1#![allow(non_snake_case)]
2
3use std::ffi::{CStr, CString};
4use std::num::NonZero;
5use std::ptr;
6use std::string::FromUtf8Error;
7
8use libc::c_uint;
9use rustc_abi::{Align, Size, WrappingRange};
10use rustc_llvm::RustString;
11
12pub(crate) use self::CallConv::*;
13pub(crate) use self::CodeGenOptSize::*;
14pub(crate) use self::conversions::*;
15pub(crate) use self::ffi::*;
16pub(crate) use self::metadata_kind::*;
17use crate::common::AsCCharPtr;
18
19mod conversions;
20pub(crate) mod diagnostic;
21pub(crate) mod enzyme_ffi;
22mod ffi;
23mod metadata_kind;
24
25pub(crate) use self::enzyme_ffi::*;
26
27impl LLVMRustResult {
28 pub(crate) fn into_result(self) -> Result<(), ()> {
29 match self {
30 LLVMRustResult::Success => Ok(()),
31 LLVMRustResult::Failure => Err(()),
32 }
33 }
34}
35
36pub(crate) fn AddFunctionAttributes<'ll>(
37 llfn: &'ll Value,
38 idx: AttributePlace,
39 attrs: &[&'ll Attribute],
40) {
41 unsafe {
42 LLVMRustAddFunctionAttributes(llfn, idx.as_uint(), attrs.as_ptr(), attrs.len());
43 }
44}
45
46pub(crate) fn AddCallSiteAttributes<'ll>(
47 callsite: &'ll Value,
48 idx: AttributePlace,
49 attrs: &[&'ll Attribute],
50) {
51 unsafe {
52 LLVMRustAddCallSiteAttributes(callsite, idx.as_uint(), attrs.as_ptr(), attrs.len());
53 }
54}
55
56pub(crate) fn CreateAttrStringValue<'ll>(
57 llcx: &'ll Context,
58 attr: &str,
59 value: &str,
60) -> &'ll Attribute {
61 unsafe {
62 LLVMCreateStringAttribute(
63 llcx,
64 attr.as_c_char_ptr(),
65 attr.len().try_into().unwrap(),
66 value.as_c_char_ptr(),
67 value.len().try_into().unwrap(),
68 )
69 }
70}
71
72pub(crate) fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute {
73 unsafe {
74 LLVMCreateStringAttribute(
75 llcx,
76 attr.as_c_char_ptr(),
77 attr.len().try_into().unwrap(),
78 std::ptr::null(),
79 0,
80 )
81 }
82}
83
84pub(crate) fn CreateAlignmentAttr(llcx: &Context, bytes: u64) -> &Attribute {
85 unsafe { LLVMRustCreateAlignmentAttr(llcx, bytes) }
86}
87
88pub(crate) fn CreateDereferenceableAttr(llcx: &Context, bytes: u64) -> &Attribute {
89 unsafe { LLVMRustCreateDereferenceableAttr(llcx, bytes) }
90}
91
92pub(crate) fn CreateDereferenceableOrNullAttr(llcx: &Context, bytes: u64) -> &Attribute {
93 unsafe { LLVMRustCreateDereferenceableOrNullAttr(llcx, bytes) }
94}
95
96pub(crate) fn CreateByValAttr<'ll>(llcx: &'ll Context, ty: &'ll Type) -> &'ll Attribute {
97 unsafe { LLVMRustCreateByValAttr(llcx, ty) }
98}
99
100pub(crate) fn CreateStructRetAttr<'ll>(llcx: &'ll Context, ty: &'ll Type) -> &'ll Attribute {
101 unsafe { LLVMRustCreateStructRetAttr(llcx, ty) }
102}
103
104pub(crate) fn CreateUWTableAttr(llcx: &Context, async_: bool) -> &Attribute {
105 unsafe { LLVMRustCreateUWTableAttr(llcx, async_) }
106}
107
108pub(crate) fn CreateAllocSizeAttr(llcx: &Context, size_arg: u32) -> &Attribute {
109 unsafe { LLVMRustCreateAllocSizeAttr(llcx, size_arg) }
110}
111
112pub(crate) fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> &Attribute {
113 unsafe { LLVMRustCreateAllocKindAttr(llcx, kind_arg.bits()) }
114}
115
116pub(crate) fn CreateRangeAttr(llcx: &Context, size: Size, range: WrappingRange) -> &Attribute {
117 let lower = range.start;
118 let upper = range.end.wrapping_add(1);
120
121 let as_u64_array = |x: u128| [x as u64, (x >> 64) as u64];
123 let lower_words: [u64; 2] = as_u64_array(lower);
124 let upper_words: [u64; 2] = as_u64_array(upper);
125
126 let size_bits = size.bits();
129 assert!(size_bits <= 128);
130 assert!(size_bits.div_ceil(64) <= u64::try_from(lower_words.len()).unwrap());
133 assert!(size_bits.div_ceil(64) <= u64::try_from(upper_words.len()).unwrap());
134 let size_bits = c_uint::try_from(size_bits).unwrap();
135
136 unsafe {
137 LLVMRustCreateRangeAttribute(llcx, size_bits, lower_words.as_ptr(), upper_words.as_ptr())
138 }
139}
140
141#[derive(Copy, Clone)]
142pub(crate) enum AttributePlace {
143 ReturnValue,
144 Argument(u32),
145 Function,
146}
147
148impl AttributePlace {
149 pub(crate) fn as_uint(self) -> c_uint {
150 match self {
151 AttributePlace::ReturnValue => 0,
152 AttributePlace::Argument(i) => 1 + i,
153 AttributePlace::Function => !0,
154 }
155 }
156}
157
158#[derive(Copy, Clone, PartialEq)]
159#[repr(C)]
160pub(crate) enum CodeGenOptSize {
161 CodeGenOptSizeNone = 0,
162 CodeGenOptSizeDefault = 1,
163 CodeGenOptSizeAggressive = 2,
164}
165
166pub(crate) fn SetInstructionCallConv(instr: &Value, cc: CallConv) {
167 unsafe {
168 LLVMSetInstructionCallConv(instr, cc as c_uint);
169 }
170}
171pub(crate) fn SetFunctionCallConv(fn_: &Value, cc: CallConv) {
172 unsafe {
173 LLVMSetFunctionCallConv(fn_, cc as c_uint);
174 }
175}
176
177pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) {
184 let name_buf = get_value_name(val);
185 let name =
186 CString::from_vec_with_nul(name_buf).or_else(|buf| CString::new(buf.into_bytes())).unwrap();
187 set_comdat(llmod, val, &name);
188}
189
190pub(crate) fn set_unnamed_address(global: &Value, unnamed: UnnamedAddr) {
191 LLVMSetUnnamedAddress(global, unnamed);
192}
193
194pub(crate) fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) {
195 unsafe {
196 LLVMSetThreadLocalMode(global, mode);
197 }
198}
199
200impl AttributeKind {
201 pub(crate) fn create_attr(self, llcx: &Context) -> &Attribute {
203 unsafe { LLVMRustCreateAttrNoValue(llcx, self) }
204 }
205}
206
207impl MemoryEffects {
208 pub(crate) fn create_attr(self, llcx: &Context) -> &Attribute {
210 unsafe { LLVMRustCreateMemoryEffectsAttr(llcx, self) }
211 }
212}
213
214pub(crate) fn set_section(llglobal: &Value, section_name: &CStr) {
215 unsafe {
216 LLVMSetSection(llglobal, section_name.as_ptr());
217 }
218}
219
220pub(crate) fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name_cstr: &CStr) -> &'a Value {
221 unsafe { LLVMAddGlobal(llmod, ty, name_cstr.as_ptr()) }
222}
223
224pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) {
225 unsafe {
226 LLVMSetInitializer(llglobal, constant_val);
227 }
228}
229
230pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) {
231 LLVMSetGlobalConstant(llglobal, is_constant.to_llvm_bool());
232}
233
234pub(crate) fn get_linkage(llglobal: &Value) -> Linkage {
235 unsafe { LLVMGetLinkage(llglobal) }.to_rust()
236}
237
238pub(crate) fn set_linkage(llglobal: &Value, linkage: Linkage) {
239 unsafe {
240 LLVMSetLinkage(llglobal, linkage);
241 }
242}
243
244pub(crate) fn is_declaration(llglobal: &Value) -> bool {
245 unsafe { LLVMIsDeclaration(llglobal) }.is_true()
246}
247
248pub(crate) fn get_visibility(llglobal: &Value) -> Visibility {
249 unsafe { LLVMGetVisibility(llglobal) }.to_rust()
250}
251
252pub(crate) fn set_visibility(llglobal: &Value, visibility: Visibility) {
253 unsafe {
254 LLVMSetVisibility(llglobal, visibility);
255 }
256}
257
258pub(crate) fn set_alignment(llglobal: &Value, align: Align) {
259 unsafe {
260 ffi::LLVMSetAlignment(llglobal, align.bytes() as c_uint);
261 }
262}
263
264pub(crate) fn set_externally_initialized(llglobal: &Value, is_ext_init: bool) {
265 LLVMSetExternallyInitialized(llglobal, is_ext_init.to_llvm_bool());
266}
267
268pub(crate) fn set_comdat(llmod: &Module, llglobal: &Value, name: &CStr) {
273 unsafe {
274 let comdat = LLVMGetOrInsertComdat(llmod, name.as_ptr());
275 LLVMSetComdat(llglobal, comdat);
276 }
277}
278
279pub(crate) fn get_param(llfn: &Value, index: c_uint) -> &Value {
281 unsafe {
282 assert!(
283 index < LLVMCountParams(llfn),
284 "out of bounds argument access: {} out of {} arguments",
285 index,
286 LLVMCountParams(llfn)
287 );
288 LLVMGetParam(llfn, index)
289 }
290}
291
292pub(crate) fn get_value_name(value: &Value) -> Vec<u8> {
296 unsafe {
297 let mut len = 0;
298 let data = LLVMGetValueName2(value, &mut len);
299 std::slice::from_raw_parts(data.cast(), len).to_vec()
300 }
301}
302
303#[derive(Debug, Copy, Clone)]
304pub(crate) struct Intrinsic {
305 id: NonZero<c_uint>,
306}
307
308impl Intrinsic {
309 pub(crate) fn lookup(name: &[u8]) -> Option<Self> {
310 let id = unsafe { LLVMLookupIntrinsicID(name.as_c_char_ptr(), name.len()) };
311 NonZero::new(id).map(|id| Self { id })
312 }
313
314 pub(crate) fn get_declaration<'ll>(
315 self,
316 llmod: &'ll Module,
317 type_params: &[&'ll Type],
318 ) -> &'ll Value {
319 unsafe {
320 LLVMGetIntrinsicDeclaration(llmod, self.id, type_params.as_ptr(), type_params.len())
321 }
322 }
323}
324
325pub(crate) fn set_value_name(value: &Value, name: &[u8]) {
327 unsafe {
328 let data = name.as_c_char_ptr();
329 LLVMSetValueName2(value, data, name.len());
330 }
331}
332
333pub(crate) fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
334 String::from_utf8(RustString::build_byte_buffer(f))
335}
336
337pub(crate) fn build_byte_buffer(f: impl FnOnce(&RustString)) -> Vec<u8> {
338 RustString::build_byte_buffer(f)
339}
340
341pub(crate) fn twine_to_string(tr: &Twine) -> String {
342 unsafe {
343 build_string(|s| LLVMRustWriteTwineToString(tr, s)).expect("got a non-UTF8 Twine from LLVM")
344 }
345}
346
347pub(crate) fn last_error() -> Option<String> {
348 unsafe {
349 let cstr = LLVMRustGetLastError();
350 if cstr.is_null() {
351 None
352 } else {
353 let err = CStr::from_ptr(cstr).to_bytes();
354 let err = String::from_utf8_lossy(err).to_string();
355 libc::free(cstr as *mut _);
356 Some(err)
357 }
358 }
359}
360
361pub(crate) struct OperandBundleBox<'a> {
364 raw: ptr::NonNull<OperandBundle<'a>>,
365}
366
367impl<'a> OperandBundleBox<'a> {
368 pub(crate) fn new(name: &str, vals: &[&'a Value]) -> Self {
369 let raw = unsafe {
370 LLVMCreateOperandBundle(
371 name.as_c_char_ptr(),
372 name.len(),
373 vals.as_ptr(),
374 vals.len() as c_uint,
375 )
376 };
377 Self { raw: ptr::NonNull::new(raw).unwrap() }
378 }
379
380 pub(crate) fn as_ref(&self) -> &OperandBundle<'a> {
385 unsafe { self.raw.as_ref() }
388 }
389}
390
391impl Drop for OperandBundleBox<'_> {
392 fn drop(&mut self) {
393 unsafe {
394 LLVMDisposeOperandBundle(self.raw);
395 }
396 }
397}
398
399pub(crate) fn add_module_flag_u32(
400 module: &Module,
401 merge_behavior: ModuleFlagMergeBehavior,
402 key: &str,
403 value: u32,
404) {
405 unsafe {
406 LLVMRustAddModuleFlagU32(module, merge_behavior, key.as_c_char_ptr(), key.len(), value);
407 }
408}
409
410pub(crate) fn add_module_flag_str(
411 module: &Module,
412 merge_behavior: ModuleFlagMergeBehavior,
413 key: &str,
414 value: &str,
415) {
416 unsafe {
417 LLVMRustAddModuleFlagString(
418 module,
419 merge_behavior,
420 key.as_c_char_ptr(),
421 key.len(),
422 value.as_c_char_ptr(),
423 value.len(),
424 );
425 }
426}
427
428pub(crate) fn set_dllimport_storage_class<'ll>(v: &'ll Value) {
429 unsafe {
430 LLVMSetDLLStorageClass(v, DLLStorageClass::DllImport);
431 }
432}
433
434pub(crate) fn set_dso_local<'ll>(v: &'ll Value) {
435 unsafe {
436 LLVMRustSetDSOLocal(v, true);
437 }
438}
439
440pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) {
443 unsafe {
444 LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len());
445 }
446}