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
9pub(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 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, NameLen: libc::size_t,
59 ) -> bool;
60 pub(crate) fn LLVMRustRemoveFnAttribute<'ll>(
61 F: Value<'ll>,
62 Name: *const c_uchar, 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 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 let s = s.try_as_raw_ptr().unwrap();
177 Ok(s)
178 }
179 }
180
181 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 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 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 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 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}