Skip to main content

rustc_codegen_llvm/llvm/
enzyme_ffi.rs

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
9// TypeTree types
10pub(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    // Enzyme
39    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, // See "PTR_LEN_STR".
51        NameLen: libc::size_t,
52    ) -> bool;
53    pub(crate) fn LLVMRustRemoveFnAttribute(
54        F: &Value,
55        Name: *const c_uchar, // See "PTR_LEN_STR".
56        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    // Enzyme
78    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            // libloading = 0.9.0: try_as_raw_ptr always succeeds and returns Some
165            let s = s.try_as_raw_ptr().unwrap();
166            Ok(s)
167        }
168    }
169
170    // e.g.
171    // load_ptrs_by_symbols_mut_void(ABC, XYZ);
172    // =>
173    // let ABC = load_ptr_mut_void(&lib, b"ABC")?;
174    // let XYZ = load_ptr_mut_void(&lib, b"XYZ")?;
175    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    // e.g.
185    // load_ptrs_by_symbols_fn(ABC: ABCFn, XYZ: XYZFn);
186    // =>
187    // let ABC: libloading::Symbol<'_, ABCFn> = unsafe { lib.get(b"ABC")? };
188    // let XYZ: libloading::Symbol<'_, XYZFn> = unsafe { lib.get(b"XYZ")? };
189    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        /// Initialize EnzymeWrapper with the given sysroot if not already initialized.
214        /// Safe to call multiple times - subsequent calls are no-ops due to OnceLock.
215        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        /// Get the EnzymeWrapper instance. Panics if not initialized.
227        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        // delete C string pointer
538        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}