1#![expect(dead_code)]
2
3use libc::{c_char, c_uchar, c_uint};
4
5use super::MetadataKindId;
6use super::ffi::{AttributeKind, BasicBlock, Context, Metadata, Module, Type, Value};
7use crate::llvm::{Bool, Builder};
8
9pub(crate) type CTypeTreeRef = *mut EnzymeTypeTree;
11
12#[repr(C)]
13#[derive(#[automatically_derived]
impl ::core::fmt::Debug for EnzymeTypeTree {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"EnzymeTypeTree", "_unused", &&self._unused)
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for EnzymeTypeTree { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for EnzymeTypeTree { }
#[automatically_derived]
impl ::core::clone::Clone for EnzymeTypeTree {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<[u8; 0]>;
*self
}
}Clone)]
14pub(crate) struct EnzymeTypeTree {
15 _unused: [u8; 0],
16}
17
18#[repr(u32)]
19#[derive(#[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::fmt::Debug for CConcreteType {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_c_like_enum_write_str(f,
"DT_Anything DT_Integer DT_Pointer DT_Half DT_Float DT_Double DT_Unknown DT_FP128",
match self {
CConcreteType::DT_Anything => 0usize,
CConcreteType::DT_Integer => 12usize,
CConcreteType::DT_Pointer => 23usize,
CConcreteType::DT_Half => 34usize,
CConcreteType::DT_Float => 42usize,
CConcreteType::DT_Double => 51usize,
CConcreteType::DT_Unknown => 61usize,
CConcreteType::DT_FP128 => 72usize,
})
}
}Debug, #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::marker::Copy for CConcreteType { }Copy, #[automatically_derived]
#[doc(hidden)]
#[allow(non_camel_case_types)]
unsafe impl ::core::clone::TrivialClone for CConcreteType { }
#[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::clone::Clone for CConcreteType {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::hash::Hash for CConcreteType {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
state)
}
}Hash, #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::marker::StructuralPartialEq for CConcreteType { }
#[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::cmp::PartialEq for CConcreteType {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
#[allow(non_camel_case_types)]
impl ::core::cmp::Eq for CConcreteType { }Eq)]
20#[allow(non_camel_case_types)]
21pub(crate) enum CConcreteType {
22 DT_Anything = 0,
23 DT_Integer = 1,
24 DT_Pointer = 2,
25 DT_Half = 3,
26 DT_Float = 4,
27 DT_Double = 5,
28 DT_Unknown = 6,
29 DT_FP128 = 9,
30}
31
32pub(crate) struct TypeTree {
33 pub(crate) inner: CTypeTreeRef,
34}
35
36#[link(name = "llvm-wrapper", kind = "static")]
37unsafe extern "C" {
38 pub(crate) safe fn LLVMRustHasMetadata(I: &Value, KindID: MetadataKindId) -> bool;
40 pub(crate) fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value);
41 pub(crate) fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>;
42 pub(crate) fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
43 pub(crate) fn LLVMRustEraseInstFromParent(V: &Value);
44 pub(crate) fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value;
45 pub(crate) fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
46 pub(crate) fn LLVMRustHasAttributeAtIndex(V: &Value, i: c_uint, Kind: AttributeKind) -> bool;
47 pub(crate) fn LLVMRustGetArrayNumElements(Ty: &Type) -> u64;
48 pub(crate) fn LLVMRustHasFnAttribute(
49 F: &Value,
50 Name: *const c_uchar, NameLen: libc::size_t,
52 ) -> bool;
53 pub(crate) fn LLVMRustRemoveFnAttribute(
54 F: &Value,
55 Name: *const c_uchar, NameLen: libc::size_t,
57 );
58 pub(crate) fn LLVMGetFirstFunction(M: &Module) -> Option<&Value>;
59 pub(crate) fn LLVMGetNextFunction(Fn: &Value) -> Option<&Value>;
60 pub(crate) fn LLVMRustRemoveEnumAttributeAtIndex(
61 Fn: &Value,
62 index: c_uint,
63 kind: AttributeKind,
64 );
65 pub(crate) fn LLVMRustPositionBefore<'a>(B: &'a Builder<'_>, I: &'a Value);
66 pub(crate) fn LLVMRustPositionAfter<'a>(B: &'a Builder<'_>, I: &'a Value);
67 pub(crate) fn LLVMRustGetFunctionCall(
68 F: &Value,
69 name: *const c_char,
70 NameLen: libc::size_t,
71 ) -> Option<&Value>;
72
73 pub(crate) safe fn LLVMRustIsCall(V: &Value) -> bool;
74}
75
76unsafe extern "C" {
77 pub(crate) fn LLVMDumpModule(M: &Module);
79 pub(crate) fn LLVMDumpValue(V: &Value);
80 pub(crate) fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
81 pub(crate) fn LLVMGetParams(Fnc: &Value, params: *mut &Value);
82 pub(crate) fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>;
83}
84
85#[repr(C)]
86#[derive(#[automatically_derived]
impl ::core::marker::Copy for LLVMRustVerifierFailureAction { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for LLVMRustVerifierFailureAction { }
#[automatically_derived]
impl ::core::clone::Clone for LLVMRustVerifierFailureAction {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for LLVMRustVerifierFailureAction { }
#[automatically_derived]
impl ::core::cmp::PartialEq for LLVMRustVerifierFailureAction {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq)]
87pub(crate) enum LLVMRustVerifierFailureAction {
88 LLVMAbortProcessAction = 0,
89 LLVMPrintMessageAction = 1,
90 LLVMReturnStatusAction = 2,
91}
92
93pub(crate) use self::Enzyme_AD::*;
94
95pub(crate) mod Enzyme_AD {
96 use std::ffi::{c_char, c_void};
97 use std::path::PathBuf;
98 use std::sync::{Mutex, MutexGuard, OnceLock};
99
100 use rustc_session::config::{Sysroot, host_tuple};
101 use rustc_session::filesearch;
102 use rustc_span::bug;
103
104 use super::{CConcreteType, CTypeTreeRef, Context};
105 use crate::llvm::{self, EnzymeTypeTree};
106
107 type EnzymeSetCLBoolFn = unsafe extern "C" fn(*mut c_void, u8);
108 type EnzymeSetCLStringFn = unsafe extern "C" fn(*mut c_void, *const c_char);
109
110 type EnzymeNewTypeTreeFn = unsafe extern "C" fn() -> CTypeTreeRef;
111 type EnzymeNewTypeTreeCTFn = unsafe extern "C" fn(CConcreteType, &Context) -> CTypeTreeRef;
112 type EnzymeNewTypeTreeTRFn = unsafe extern "C" fn(CTypeTreeRef) -> CTypeTreeRef;
113 type EnzymeFreeTypeTreeFn = unsafe extern "C" fn(CTypeTreeRef);
114 type EnzymeMergeTypeTreeFn = unsafe extern "C" fn(CTypeTreeRef, CTypeTreeRef) -> bool;
115 type EnzymeTypeTreeOnlyEqFn = unsafe extern "C" fn(CTypeTreeRef, i64);
116 type EnzymeTypeTreeData0EqFn = unsafe extern "C" fn(CTypeTreeRef);
117 type EnzymeTypeTreeShiftIndiciesEqFn =
118 unsafe extern "C" fn(CTypeTreeRef, *const c_char, i64, i64, u64);
119 type EnzymeTypeTreeInsertEqFn =
120 unsafe extern "C" fn(CTypeTreeRef, *const i64, usize, CConcreteType, &Context);
121 type EnzymeTypeTreeToStringFn = unsafe extern "C" fn(CTypeTreeRef) -> *const c_char;
122 type EnzymeTypeTreeToStringFreeFn = unsafe extern "C" fn(*const c_char);
123
124 #[allow(non_snake_case)]
125 pub(crate) struct EnzymeWrapper {
126 EnzymeNewTypeTree: EnzymeNewTypeTreeFn,
127 EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn,
128 EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn,
129 EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn,
130 EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn,
131 EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn,
132 EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn,
133 EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn,
134 EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn,
135 EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn,
136 EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn,
137
138 EnzymePrintPerf: *mut c_void,
139 EnzymePrintActivity: *mut c_void,
140 EnzymePrintType: *mut c_void,
141 EnzymeFunctionToAnalyze: *mut c_void,
142 EnzymePrint: *mut c_void,
143 EnzymeStrictAliasing: *mut c_void,
144 EnzymeInline: *mut c_void,
145 EnzymeMaxTypeDepth: *mut c_void,
146 RustTypeRules: *mut c_void,
147 looseTypeAnalysis: *mut c_void,
148
149 EnzymeSetCLBool: EnzymeSetCLBoolFn,
150 EnzymeSetCLString: EnzymeSetCLStringFn,
151 pub registerEnzymeAndPassPipeline: *const c_void,
152 lib: libloading::Library,
153 }
154
155 unsafe impl Sync for EnzymeWrapper {}
156 unsafe impl Send for EnzymeWrapper {}
157
158 fn load_ptr_by_symbol_mut_void(
159 lib: &libloading::Library,
160 bytes: &[u8],
161 ) -> Result<*mut c_void, libloading::Error> {
162 unsafe {
163 let s: libloading::Symbol<'_, *mut c_void> = lib.get(bytes)?;
164 let s = s.try_as_raw_ptr().unwrap();
166 Ok(s)
167 }
168 }
169
170 macro_rules! load_ptrs_by_symbols_mut_void {
176 ($lib:expr, $($name:ident),* $(,)?) => {
177 $(
178 #[allow(non_snake_case)]
179 let $name = load_ptr_by_symbol_mut_void(&$lib, stringify!($name).as_bytes())?;
180 )*
181 };
182 }
183
184 macro_rules! load_ptrs_by_symbols_fn {
190 ($lib:expr, $($name:ident : $ty:ty),* $(,)?) => {
191 $(
192 #[allow(non_snake_case)]
193 let $name: $ty = *unsafe { $lib.get::<$ty>(stringify!($name).as_bytes())? };
194 )*
195 };
196 }
197
198 static ENZYME_INSTANCE: OnceLock<Mutex<EnzymeWrapper>> = OnceLock::new();
199
200 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for EnzymeLibraryError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::NotFound { err: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"NotFound", "err", &__self_0),
Self::LoadFailed { err: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"LoadFailed", "err", &__self_0),
}
}
}Debug)]
201 pub(crate) enum EnzymeLibraryError {
202 NotFound { err: String },
203 LoadFailed { err: String },
204 }
205
206 impl From<libloading::Error> for EnzymeLibraryError {
207 fn from(err: libloading::Error) -> Self {
208 Self::LoadFailed { err: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", err))
})format!("{err:?}") }
209 }
210 }
211
212 impl EnzymeWrapper {
213 pub(crate) fn get_or_init(
216 sysroot: &rustc_session::config::Sysroot,
217 ) -> Result<MutexGuard<'static, Self>, EnzymeLibraryError> {
218 let mtx: &'static Mutex<EnzymeWrapper> = ENZYME_INSTANCE.get_or_try_init(|| {
219 let w = Self::call_dynamic(sysroot)?;
220 Ok::<_, EnzymeLibraryError>(Mutex::new(w))
221 })?;
222
223 Ok(mtx.lock().unwrap())
224 }
225
226 pub(crate) fn get_instance() -> MutexGuard<'static, Self> {
228 ENZYME_INSTANCE
229 .get()
230 .expect("EnzymeWrapper not initialized. Call get_or_init with sysroot first.")
231 .lock()
232 .unwrap()
233 }
234
235 pub(crate) fn new_type_tree(&self) -> CTypeTreeRef {
236 unsafe { (self.EnzymeNewTypeTree)() }
237 }
238
239 pub(crate) fn new_type_tree_ct(
240 &self,
241 t: CConcreteType,
242 ctx: &Context,
243 ) -> *mut EnzymeTypeTree {
244 unsafe { (self.EnzymeNewTypeTreeCT)(t, ctx) }
245 }
246
247 pub(crate) fn new_type_tree_tr(&self, tree: CTypeTreeRef) -> CTypeTreeRef {
248 unsafe { (self.EnzymeNewTypeTreeTR)(tree) }
249 }
250
251 pub(crate) fn free_type_tree(&self, tree: CTypeTreeRef) {
252 unsafe { (self.EnzymeFreeTypeTree)(tree) }
253 }
254
255 pub(crate) fn merge_type_tree(&self, tree1: CTypeTreeRef, tree2: CTypeTreeRef) -> bool {
256 unsafe { (self.EnzymeMergeTypeTree)(tree1, tree2) }
257 }
258
259 pub(crate) fn tree_only_eq(&self, tree: CTypeTreeRef, num: i64) {
260 unsafe { (self.EnzymeTypeTreeOnlyEq)(tree, num) }
261 }
262
263 pub(crate) fn tree_data0_eq(&self, tree: CTypeTreeRef) {
264 unsafe { (self.EnzymeTypeTreeData0Eq)(tree) }
265 }
266
267 pub(crate) fn shift_indicies_eq(
268 &self,
269 tree: CTypeTreeRef,
270 data_layout: *const c_char,
271 offset: i64,
272 max_size: i64,
273 add_offset: u64,
274 ) {
275 unsafe {
276 (self.EnzymeTypeTreeShiftIndiciesEq)(
277 tree,
278 data_layout,
279 offset,
280 max_size,
281 add_offset,
282 )
283 }
284 }
285
286 pub(crate) fn tree_insert_eq(
287 &self,
288 tree: CTypeTreeRef,
289 indices: *const i64,
290 len: usize,
291 ct: CConcreteType,
292 ctx: &Context,
293 ) {
294 unsafe { (self.EnzymeTypeTreeInsertEq)(tree, indices, len, ct, ctx) }
295 }
296
297 pub(crate) fn tree_to_string(&self, tree: *mut EnzymeTypeTree) -> *const c_char {
298 unsafe { (self.EnzymeTypeTreeToString)(tree) }
299 }
300
301 pub(crate) fn tree_to_cstr(&self, tree: *mut EnzymeTypeTree) -> &std::ffi::CStr {
302 let c_str = self.tree_to_string(tree);
303 unsafe { std::ffi::CStr::from_ptr(c_str) }
304 }
305
306 pub(crate) fn tree_to_string_free(&self, ch: *const c_char) {
307 unsafe { (self.EnzymeTypeTreeToStringFree)(ch) }
308 }
309
310 pub(crate) fn get_max_type_depth(&self) -> usize {
311 unsafe { std::ptr::read::<u32>(self.EnzymeMaxTypeDepth as *const u32) as usize }
312 }
313
314 pub(crate) fn set_print_perf(&mut self, print: bool) {
315 unsafe {
316 (self.EnzymeSetCLBool)(self.EnzymePrintPerf, print as u8);
317 }
318 }
319
320 pub(crate) fn set_print_activity(&mut self, print: bool) {
321 unsafe {
322 (self.EnzymeSetCLBool)(self.EnzymePrintActivity, print as u8);
323 }
324 }
325
326 pub(crate) fn set_print_type(&mut self, print: bool) {
327 unsafe {
328 (self.EnzymeSetCLBool)(self.EnzymePrintType, print as u8);
329 }
330 }
331
332 pub(crate) fn set_print_type_fun(&mut self, fun_name: &str) {
333 let c_fun_name = std::ffi::CString::new(fun_name)
334 .unwrap_or_else(|err| ::rustc_span::macros::bug_impl(None,
format_args!("failed to set_print_type_fun: {0}", err),
Location::caller())bug!("failed to set_print_type_fun: {err}"));
335 unsafe {
336 (self.EnzymeSetCLString)(self.EnzymeFunctionToAnalyze, c_fun_name.as_ptr());
337 }
338 }
339
340 pub(crate) fn set_print(&mut self, print: bool) {
341 unsafe {
342 (self.EnzymeSetCLBool)(self.EnzymePrint, print as u8);
343 }
344 }
345
346 pub(crate) fn set_strict_aliasing(&mut self, strict: bool) {
347 unsafe {
348 (self.EnzymeSetCLBool)(self.EnzymeStrictAliasing, strict as u8);
349 }
350 }
351
352 pub(crate) fn set_loose_types(&mut self, loose: bool) {
353 unsafe {
354 (self.EnzymeSetCLBool)(self.looseTypeAnalysis, loose as u8);
355 }
356 }
357
358 pub(crate) fn set_inline(&mut self, val: bool) {
359 unsafe {
360 (self.EnzymeSetCLBool)(self.EnzymeInline, val as u8);
361 }
362 }
363
364 pub(crate) fn set_rust_rules(&mut self, val: bool) {
365 unsafe {
366 (self.EnzymeSetCLBool)(self.RustTypeRules, val as u8);
367 }
368 }
369
370 #[allow(non_snake_case)]
371 fn call_dynamic(
372 sysroot: &rustc_session::config::Sysroot,
373 ) -> Result<Self, EnzymeLibraryError> {
374 let enzyme_path = Self::get_enzyme_path(sysroot)?;
375 let lib = unsafe { libloading::Library::new(enzyme_path)? };
376
377 #[allow(non_snake_case)]
let EnzymeNewTypeTree: EnzymeNewTypeTreeFn =
*unsafe {
lib.get::<EnzymeNewTypeTreeFn>("EnzymeNewTypeTree".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn =
*unsafe {
lib.get::<EnzymeNewTypeTreeCTFn>("EnzymeNewTypeTreeCT".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn =
*unsafe {
lib.get::<EnzymeNewTypeTreeTRFn>("EnzymeNewTypeTreeTR".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn =
*unsafe {
lib.get::<EnzymeFreeTypeTreeFn>("EnzymeFreeTypeTree".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn =
*unsafe {
lib.get::<EnzymeMergeTypeTreeFn>("EnzymeMergeTypeTree".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn =
*unsafe {
lib.get::<EnzymeTypeTreeOnlyEqFn>("EnzymeTypeTreeOnlyEq".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn =
*unsafe {
lib.get::<EnzymeTypeTreeData0EqFn>("EnzymeTypeTreeData0Eq".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn =
*unsafe {
lib.get::<EnzymeTypeTreeShiftIndiciesEqFn>("EnzymeTypeTreeShiftIndiciesEq".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn =
*unsafe {
lib.get::<EnzymeTypeTreeInsertEqFn>("EnzymeTypeTreeInsertEq".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn =
*unsafe {
lib.get::<EnzymeTypeTreeToStringFn>("EnzymeTypeTreeToString".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn =
*unsafe {
lib.get::<EnzymeTypeTreeToStringFreeFn>("EnzymeTypeTreeToStringFree".as_bytes())?
};
#[allow(non_snake_case)]
let EnzymeSetCLBool: EnzymeSetCLBoolFn =
*unsafe { lib.get::<EnzymeSetCLBoolFn>("EnzymeSetCLBool".as_bytes())? };
#[allow(non_snake_case)]
let EnzymeSetCLString: EnzymeSetCLStringFn =
*unsafe {
lib.get::<EnzymeSetCLStringFn>("EnzymeSetCLString".as_bytes())?
};load_ptrs_by_symbols_fn!(
378 lib,
379 EnzymeNewTypeTree: EnzymeNewTypeTreeFn,
380 EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn,
381 EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn,
382 EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn,
383 EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn,
384 EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn,
385 EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn,
386 EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn,
387 EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn,
388 EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn,
389 EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn,
390 EnzymeSetCLBool: EnzymeSetCLBoolFn,
391 EnzymeSetCLString: EnzymeSetCLStringFn,
392 );
393
394 #[allow(non_snake_case)]
let registerEnzymeAndPassPipeline =
load_ptr_by_symbol_mut_void(&lib,
"registerEnzymeAndPassPipeline".as_bytes())?;
#[allow(non_snake_case)]
let EnzymePrintPerf =
load_ptr_by_symbol_mut_void(&lib, "EnzymePrintPerf".as_bytes())?;
#[allow(non_snake_case)]
let EnzymePrintActivity =
load_ptr_by_symbol_mut_void(&lib, "EnzymePrintActivity".as_bytes())?;
#[allow(non_snake_case)]
let EnzymePrintType =
load_ptr_by_symbol_mut_void(&lib, "EnzymePrintType".as_bytes())?;
#[allow(non_snake_case)]
let EnzymeFunctionToAnalyze =
load_ptr_by_symbol_mut_void(&lib, "EnzymeFunctionToAnalyze".as_bytes())?;
#[allow(non_snake_case)]
let EnzymePrint =
load_ptr_by_symbol_mut_void(&lib, "EnzymePrint".as_bytes())?;
#[allow(non_snake_case)]
let EnzymeStrictAliasing =
load_ptr_by_symbol_mut_void(&lib, "EnzymeStrictAliasing".as_bytes())?;
#[allow(non_snake_case)]
let EnzymeInline =
load_ptr_by_symbol_mut_void(&lib, "EnzymeInline".as_bytes())?;
#[allow(non_snake_case)]
let EnzymeMaxTypeDepth =
load_ptr_by_symbol_mut_void(&lib, "EnzymeMaxTypeDepth".as_bytes())?;
#[allow(non_snake_case)]
let RustTypeRules =
load_ptr_by_symbol_mut_void(&lib, "RustTypeRules".as_bytes())?;
#[allow(non_snake_case)]
let looseTypeAnalysis =
load_ptr_by_symbol_mut_void(&lib, "looseTypeAnalysis".as_bytes())?;load_ptrs_by_symbols_mut_void!(
395 lib,
396 registerEnzymeAndPassPipeline,
397 EnzymePrintPerf,
398 EnzymePrintActivity,
399 EnzymePrintType,
400 EnzymeFunctionToAnalyze,
401 EnzymePrint,
402 EnzymeStrictAliasing,
403 EnzymeInline,
404 EnzymeMaxTypeDepth,
405 RustTypeRules,
406 looseTypeAnalysis,
407 );
408
409 Ok(Self {
410 EnzymeNewTypeTree,
411 EnzymeNewTypeTreeCT,
412 EnzymeNewTypeTreeTR,
413 EnzymeFreeTypeTree,
414 EnzymeMergeTypeTree,
415 EnzymeTypeTreeOnlyEq,
416 EnzymeTypeTreeData0Eq,
417 EnzymeTypeTreeShiftIndiciesEq,
418 EnzymeTypeTreeInsertEq,
419 EnzymeTypeTreeToString,
420 EnzymeTypeTreeToStringFree,
421 EnzymePrintPerf,
422 EnzymePrintActivity,
423 EnzymePrintType,
424 EnzymeFunctionToAnalyze,
425 EnzymePrint,
426 EnzymeStrictAliasing,
427 EnzymeInline,
428 EnzymeMaxTypeDepth,
429 RustTypeRules,
430 looseTypeAnalysis,
431 EnzymeSetCLBool,
432 EnzymeSetCLString,
433 registerEnzymeAndPassPipeline,
434 lib,
435 })
436 }
437
438 fn get_enzyme_path(sysroot: &Sysroot) -> Result<PathBuf, EnzymeLibraryError> {
439 let llvm_version_major = llvm::LLVMRustVersionMajor();
440 let mut searched = Vec::new();
441
442 for p in sysroot.all_paths() {
443 let libdir = filesearch::make_target_lib_path(p, host_tuple());
444
445 let enzyme_path = libdir
446 .join(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("libEnzyme-{0}",
llvm_version_major))
})format!("libEnzyme-{llvm_version_major}"))
447 .with_extension(std::env::consts::DLL_EXTENSION);
448
449 if enzyme_path.exists() {
450 return Ok(enzyme_path);
451 }
452
453 searched.push(libdir);
454 }
455
456 Err(EnzymeLibraryError::NotFound {
457 err: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("failed to find a `libEnzyme-{2}.{0}` in the sysroot candidates:\n* {1}",
std::env::consts::DLL_EXTENSION,
searched.iter().map(|p|
p.display().to_string()).collect::<Vec<_>>().join("\n* "),
llvm_version_major))
})format!(
458 "failed to find a `libEnzyme-{llvm_version_major}.{}` \
459 in the sysroot candidates:\n* {}",
460 std::env::consts::DLL_EXTENSION,
461 searched
462 .iter()
463 .map(|p| p.display().to_string())
464 .collect::<Vec<_>>()
465 .join("\n* ")
466 ),
467 })
468 }
469 }
470}
471
472impl TypeTree {
473 pub(crate) fn new() -> TypeTree {
474 let wrapper = EnzymeWrapper::get_instance();
475 let inner = wrapper.new_type_tree();
476 TypeTree { inner }
477 }
478
479 pub(crate) fn from_type(t: CConcreteType, ctx: &Context) -> TypeTree {
480 let wrapper = EnzymeWrapper::get_instance();
481 let inner = wrapper.new_type_tree_ct(t, ctx);
482 TypeTree { inner }
483 }
484
485 pub(crate) fn merge(self, other: Self) -> Self {
486 let wrapper = EnzymeWrapper::get_instance();
487 wrapper.merge_type_tree(self.inner, other.inner);
488 drop(other);
489 self
490 }
491
492 #[must_use]
493 pub(crate) fn shift(
494 self,
495 layout: &str,
496 offset: isize,
497 max_size: isize,
498 add_offset: usize,
499 ) -> Self {
500 let layout = std::ffi::CString::new(layout).unwrap();
501 let wrapper = EnzymeWrapper::get_instance();
502 wrapper.shift_indicies_eq(
503 self.inner,
504 layout.as_ptr(),
505 offset as i64,
506 max_size as i64,
507 add_offset as u64,
508 );
509
510 self
511 }
512
513 pub(crate) fn insert(&mut self, indices: &[i64], ct: CConcreteType, ctx: &Context) {
514 let wrapper = EnzymeWrapper::get_instance();
515 wrapper.tree_insert_eq(self.inner, indices.as_ptr(), indices.len(), ct, ctx);
516 }
517}
518
519impl Clone for TypeTree {
520 fn clone(&self) -> Self {
521 let wrapper = EnzymeWrapper::get_instance();
522 let inner = wrapper.new_type_tree_tr(self.inner);
523 TypeTree { inner }
524 }
525}
526
527impl std::fmt::Display for TypeTree {
528 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
529 let wrapper = EnzymeWrapper::get_instance();
530 let ptr = wrapper.tree_to_string(self.inner);
531 let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) };
532 match cstr.to_str() {
533 Ok(x) => f.write_fmt(format_args!("{0}", x))write!(f, "{}", x)?,
534 Err(err) => f.write_fmt(format_args!("could not parse: {0}", err))write!(f, "could not parse: {}", err)?,
535 }
536
537 wrapper.tree_to_string_free(ptr);
539
540 Ok(())
541 }
542}
543
544impl std::fmt::Debug for TypeTree {
545 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
546 <Self as std::fmt::Display>::fmt(self, f)
547 }
548}
549
550impl Drop for TypeTree {
551 fn drop(&mut self) {
552 let wrapper = EnzymeWrapper::get_instance();
553 wrapper.free_type_tree(self.inner)
554 }
555}