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    pub(crate) safe fn LLVMRustIsCall(V: &Value) -> bool;
70}
71
72unsafe extern "C" {
73    // Enzyme
74    pub(crate) fn LLVMDumpModule(M: &Module);
75    pub(crate) fn LLVMDumpValue(V: &Value);
76    pub(crate) fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
77    pub(crate) fn LLVMGetParams(Fnc: &Value, params: *mut &Value);
78    pub(crate) fn LLVMGetNamedFunction(M: &Module, Name: *const c_char) -> Option<&Value>;
79}
80
81#[repr(C)]
82#[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)]
83pub(crate) enum LLVMRustVerifierFailureAction {
84    LLVMAbortProcessAction = 0,
85    LLVMPrintMessageAction = 1,
86    LLVMReturnStatusAction = 2,
87}
88
89pub(crate) use self::Enzyme_AD::*;
90
91pub(crate) mod Enzyme_AD {
92    use std::ffi::{c_char, c_void};
93    use std::sync::{Mutex, MutexGuard, OnceLock};
94
95    use rustc_middle::bug;
96    use rustc_session::config::{Sysroot, host_tuple};
97    use rustc_session::filesearch;
98
99    use super::{CConcreteType, CTypeTreeRef, Context};
100    use crate::llvm::{EnzymeTypeTree, LLVMRustVersionMajor};
101
102    type EnzymeSetCLBoolFn = unsafe extern "C" fn(*mut c_void, u8);
103    type EnzymeSetCLStringFn = unsafe extern "C" fn(*mut c_void, *const c_char);
104
105    type EnzymeNewTypeTreeFn = unsafe extern "C" fn() -> CTypeTreeRef;
106    type EnzymeNewTypeTreeCTFn = unsafe extern "C" fn(CConcreteType, &Context) -> CTypeTreeRef;
107    type EnzymeNewTypeTreeTRFn = unsafe extern "C" fn(CTypeTreeRef) -> CTypeTreeRef;
108    type EnzymeFreeTypeTreeFn = unsafe extern "C" fn(CTypeTreeRef);
109    type EnzymeMergeTypeTreeFn = unsafe extern "C" fn(CTypeTreeRef, CTypeTreeRef) -> bool;
110    type EnzymeTypeTreeOnlyEqFn = unsafe extern "C" fn(CTypeTreeRef, i64);
111    type EnzymeTypeTreeData0EqFn = unsafe extern "C" fn(CTypeTreeRef);
112    type EnzymeTypeTreeShiftIndiciesEqFn =
113        unsafe extern "C" fn(CTypeTreeRef, *const c_char, i64, i64, u64);
114    type EnzymeTypeTreeInsertEqFn =
115        unsafe extern "C" fn(CTypeTreeRef, *const i64, usize, CConcreteType, &Context);
116    type EnzymeTypeTreeToStringFn = unsafe extern "C" fn(CTypeTreeRef) -> *const c_char;
117    type EnzymeTypeTreeToStringFreeFn = unsafe extern "C" fn(*const c_char);
118
119    #[allow(non_snake_case)]
120    pub(crate) struct EnzymeWrapper {
121        EnzymeNewTypeTree: EnzymeNewTypeTreeFn,
122        EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn,
123        EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn,
124        EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn,
125        EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn,
126        EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn,
127        EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn,
128        EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn,
129        EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn,
130        EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn,
131        EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn,
132
133        EnzymePrintPerf: *mut c_void,
134        EnzymePrintActivity: *mut c_void,
135        EnzymePrintType: *mut c_void,
136        EnzymeFunctionToAnalyze: *mut c_void,
137        EnzymePrint: *mut c_void,
138        EnzymeStrictAliasing: *mut c_void,
139        EnzymeInline: *mut c_void,
140        EnzymeMaxTypeDepth: *mut c_void,
141        RustTypeRules: *mut c_void,
142        looseTypeAnalysis: *mut c_void,
143
144        EnzymeSetCLBool: EnzymeSetCLBoolFn,
145        EnzymeSetCLString: EnzymeSetCLStringFn,
146        pub registerEnzymeAndPassPipeline: *const c_void,
147        lib: libloading::Library,
148    }
149
150    unsafe impl Sync for EnzymeWrapper {}
151    unsafe impl Send for EnzymeWrapper {}
152
153    fn load_ptr_by_symbol_mut_void(
154        lib: &libloading::Library,
155        bytes: &[u8],
156    ) -> Result<*mut c_void, libloading::Error> {
157        unsafe {
158            let s: libloading::Symbol<'_, *mut c_void> = lib.get(bytes)?;
159            // libloading = 0.9.0: try_as_raw_ptr always succeeds and returns Some
160            let s = s.try_as_raw_ptr().unwrap();
161            Ok(s)
162        }
163    }
164
165    // e.g.
166    // load_ptrs_by_symbols_mut_void(ABC, XYZ);
167    // =>
168    // let ABC = load_ptr_mut_void(&lib, b"ABC")?;
169    // let XYZ = load_ptr_mut_void(&lib, b"XYZ")?;
170    macro_rules! load_ptrs_by_symbols_mut_void {
171        ($lib:expr, $($name:ident),* $(,)?) => {
172            $(
173                #[allow(non_snake_case)]
174                let $name = load_ptr_by_symbol_mut_void(&$lib, stringify!($name).as_bytes())?;
175            )*
176        };
177    }
178
179    // e.g.
180    // load_ptrs_by_symbols_fn(ABC: ABCFn, XYZ: XYZFn);
181    // =>
182    // let ABC: libloading::Symbol<'_, ABCFn> = unsafe { lib.get(b"ABC")? };
183    // let XYZ: libloading::Symbol<'_, XYZFn> = unsafe { lib.get(b"XYZ")? };
184    macro_rules! load_ptrs_by_symbols_fn {
185        ($lib:expr, $($name:ident : $ty:ty),* $(,)?) => {
186            $(
187                #[allow(non_snake_case)]
188                let $name: $ty = *unsafe { $lib.get::<$ty>(stringify!($name).as_bytes())? };
189            )*
190        };
191    }
192
193    static ENZYME_INSTANCE: OnceLock<Mutex<EnzymeWrapper>> = OnceLock::new();
194
195    #[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)]
196    pub(crate) enum EnzymeLibraryError {
197        NotFound { err: String },
198        LoadFailed { err: String },
199    }
200
201    impl From<libloading::Error> for EnzymeLibraryError {
202        fn from(err: libloading::Error) -> Self {
203            Self::LoadFailed { err: ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", err))
    })format!("{err:?}") }
204        }
205    }
206
207    impl EnzymeWrapper {
208        /// Initialize EnzymeWrapper with the given sysroot if not already initialized.
209        /// Safe to call multiple times - subsequent calls are no-ops due to OnceLock.
210        pub(crate) fn get_or_init(
211            sysroot: &rustc_session::config::Sysroot,
212        ) -> Result<MutexGuard<'static, Self>, EnzymeLibraryError> {
213            let mtx: &'static Mutex<EnzymeWrapper> = ENZYME_INSTANCE.get_or_try_init(|| {
214                let w = Self::call_dynamic(sysroot)?;
215                Ok::<_, EnzymeLibraryError>(Mutex::new(w))
216            })?;
217
218            Ok(mtx.lock().unwrap())
219        }
220
221        /// Get the EnzymeWrapper instance. Panics if not initialized.
222        pub(crate) fn get_instance() -> MutexGuard<'static, Self> {
223            ENZYME_INSTANCE
224                .get()
225                .expect("EnzymeWrapper not initialized. Call get_or_init with sysroot first.")
226                .lock()
227                .unwrap()
228        }
229
230        pub(crate) fn new_type_tree(&self) -> CTypeTreeRef {
231            unsafe { (self.EnzymeNewTypeTree)() }
232        }
233
234        pub(crate) fn new_type_tree_ct(
235            &self,
236            t: CConcreteType,
237            ctx: &Context,
238        ) -> *mut EnzymeTypeTree {
239            unsafe { (self.EnzymeNewTypeTreeCT)(t, ctx) }
240        }
241
242        pub(crate) fn new_type_tree_tr(&self, tree: CTypeTreeRef) -> CTypeTreeRef {
243            unsafe { (self.EnzymeNewTypeTreeTR)(tree) }
244        }
245
246        pub(crate) fn free_type_tree(&self, tree: CTypeTreeRef) {
247            unsafe { (self.EnzymeFreeTypeTree)(tree) }
248        }
249
250        pub(crate) fn merge_type_tree(&self, tree1: CTypeTreeRef, tree2: CTypeTreeRef) -> bool {
251            unsafe { (self.EnzymeMergeTypeTree)(tree1, tree2) }
252        }
253
254        pub(crate) fn tree_only_eq(&self, tree: CTypeTreeRef, num: i64) {
255            unsafe { (self.EnzymeTypeTreeOnlyEq)(tree, num) }
256        }
257
258        pub(crate) fn tree_data0_eq(&self, tree: CTypeTreeRef) {
259            unsafe { (self.EnzymeTypeTreeData0Eq)(tree) }
260        }
261
262        pub(crate) fn shift_indicies_eq(
263            &self,
264            tree: CTypeTreeRef,
265            data_layout: *const c_char,
266            offset: i64,
267            max_size: i64,
268            add_offset: u64,
269        ) {
270            unsafe {
271                (self.EnzymeTypeTreeShiftIndiciesEq)(
272                    tree,
273                    data_layout,
274                    offset,
275                    max_size,
276                    add_offset,
277                )
278            }
279        }
280
281        pub(crate) fn tree_insert_eq(
282            &self,
283            tree: CTypeTreeRef,
284            indices: *const i64,
285            len: usize,
286            ct: CConcreteType,
287            ctx: &Context,
288        ) {
289            unsafe { (self.EnzymeTypeTreeInsertEq)(tree, indices, len, ct, ctx) }
290        }
291
292        pub(crate) fn tree_to_string(&self, tree: *mut EnzymeTypeTree) -> *const c_char {
293            unsafe { (self.EnzymeTypeTreeToString)(tree) }
294        }
295
296        pub(crate) fn tree_to_cstr(&self, tree: *mut EnzymeTypeTree) -> &std::ffi::CStr {
297            let c_str = self.tree_to_string(tree);
298            unsafe { std::ffi::CStr::from_ptr(c_str) }
299        }
300
301        pub(crate) fn tree_to_string_free(&self, ch: *const c_char) {
302            unsafe { (self.EnzymeTypeTreeToStringFree)(ch) }
303        }
304
305        pub(crate) fn get_max_type_depth(&self) -> usize {
306            unsafe { std::ptr::read::<u32>(self.EnzymeMaxTypeDepth as *const u32) as usize }
307        }
308
309        pub(crate) fn set_print_perf(&mut self, print: bool) {
310            unsafe {
311                (self.EnzymeSetCLBool)(self.EnzymePrintPerf, print as u8);
312            }
313        }
314
315        pub(crate) fn set_print_activity(&mut self, print: bool) {
316            unsafe {
317                (self.EnzymeSetCLBool)(self.EnzymePrintActivity, print as u8);
318            }
319        }
320
321        pub(crate) fn set_print_type(&mut self, print: bool) {
322            unsafe {
323                (self.EnzymeSetCLBool)(self.EnzymePrintType, print as u8);
324            }
325        }
326
327        pub(crate) fn set_print_type_fun(&mut self, fun_name: &str) {
328            let c_fun_name = std::ffi::CString::new(fun_name)
329                .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}"));
330            unsafe {
331                (self.EnzymeSetCLString)(
332                    self.EnzymeFunctionToAnalyze,
333                    c_fun_name.as_ptr() as *const c_char,
334                );
335            }
336        }
337
338        pub(crate) fn set_print(&mut self, print: bool) {
339            unsafe {
340                (self.EnzymeSetCLBool)(self.EnzymePrint, print as u8);
341            }
342        }
343
344        pub(crate) fn set_strict_aliasing(&mut self, strict: bool) {
345            unsafe {
346                (self.EnzymeSetCLBool)(self.EnzymeStrictAliasing, strict as u8);
347            }
348        }
349
350        pub(crate) fn set_loose_types(&mut self, loose: bool) {
351            unsafe {
352                (self.EnzymeSetCLBool)(self.looseTypeAnalysis, loose as u8);
353            }
354        }
355
356        pub(crate) fn set_inline(&mut self, val: bool) {
357            unsafe {
358                (self.EnzymeSetCLBool)(self.EnzymeInline, val as u8);
359            }
360        }
361
362        pub(crate) fn set_rust_rules(&mut self, val: bool) {
363            unsafe {
364                (self.EnzymeSetCLBool)(self.RustTypeRules, val as u8);
365            }
366        }
367
368        #[allow(non_snake_case)]
369        fn call_dynamic(
370            sysroot: &rustc_session::config::Sysroot,
371        ) -> Result<Self, EnzymeLibraryError> {
372            let enzyme_path = Self::get_enzyme_path(sysroot)?;
373            let lib = unsafe { libloading::Library::new(enzyme_path)? };
374
375            #[allow(non_snake_case)]
let EnzymeSetCLString: EnzymeSetCLStringFn =
    *unsafe {
            lib.get::<EnzymeSetCLStringFn>("EnzymeSetCLString".as_bytes())?
        };load_ptrs_by_symbols_fn!(
376                lib,
377                EnzymeNewTypeTree: EnzymeNewTypeTreeFn,
378                EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn,
379                EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn,
380                EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn,
381                EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn,
382                EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn,
383                EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn,
384                EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn,
385                EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn,
386                EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn,
387                EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn,
388                EnzymeSetCLBool: EnzymeSetCLBoolFn,
389                EnzymeSetCLString: EnzymeSetCLStringFn,
390            );
391
392            #[allow(non_snake_case)]
let looseTypeAnalysis =
    load_ptr_by_symbol_mut_void(&lib, "looseTypeAnalysis".as_bytes())?;load_ptrs_by_symbols_mut_void!(
393                lib,
394                registerEnzymeAndPassPipeline,
395                EnzymePrintPerf,
396                EnzymePrintActivity,
397                EnzymePrintType,
398                EnzymeFunctionToAnalyze,
399                EnzymePrint,
400                EnzymeStrictAliasing,
401                EnzymeInline,
402                EnzymeMaxTypeDepth,
403                RustTypeRules,
404                looseTypeAnalysis,
405            );
406
407            Ok(Self {
408                EnzymeNewTypeTree,
409                EnzymeNewTypeTreeCT,
410                EnzymeNewTypeTreeTR,
411                EnzymeFreeTypeTree,
412                EnzymeMergeTypeTree,
413                EnzymeTypeTreeOnlyEq,
414                EnzymeTypeTreeData0Eq,
415                EnzymeTypeTreeShiftIndiciesEq,
416                EnzymeTypeTreeInsertEq,
417                EnzymeTypeTreeToString,
418                EnzymeTypeTreeToStringFree,
419                EnzymePrintPerf,
420                EnzymePrintActivity,
421                EnzymePrintType,
422                EnzymeFunctionToAnalyze,
423                EnzymePrint,
424                EnzymeStrictAliasing,
425                EnzymeInline,
426                EnzymeMaxTypeDepth,
427                RustTypeRules,
428                looseTypeAnalysis,
429                EnzymeSetCLBool,
430                EnzymeSetCLString,
431                registerEnzymeAndPassPipeline,
432                lib,
433            })
434        }
435
436        fn get_enzyme_path(sysroot: &Sysroot) -> Result<String, EnzymeLibraryError> {
437            let llvm_version_major = unsafe { LLVMRustVersionMajor() };
438
439            let path_buf = sysroot
440                .all_paths()
441                .map(|sysroot_path| {
442                    filesearch::make_target_lib_path(sysroot_path, host_tuple())
443                        .join("lib")
444                        .with_file_name(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("libEnzyme-{0}",
                llvm_version_major))
    })format!("libEnzyme-{llvm_version_major}"))
445                        .with_extension(std::env::consts::DLL_EXTENSION)
446                })
447                .find(|f| f.exists())
448                .ok_or_else(|| {
449                    let candidates = sysroot
450                        .all_paths()
451                        .map(|p| p.join("lib").display().to_string())
452                        .collect::<Vec<String>>()
453                        .join("\n* ");
454                    EnzymeLibraryError::NotFound {
455                        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!(
456                            "failed to find a `libEnzyme-{llvm_version_major}` folder \
457                    in the sysroot candidates:\n* {candidates}"
458                        ),
459                    }
460                })?;
461
462            Ok(path_buf
463                .to_str()
464                .ok_or_else(|| EnzymeLibraryError::LoadFailed {
465                    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()),
466                })?
467                .to_string())
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}