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