Skip to main content

rustc_codegen_llvm/llvm/
enzyme_ffi.rs

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