rustc_codegen_llvm/llvm/
mod.rs

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    // LLVM treats the upper bound as exclusive, but allows wrapping.
119    let upper = range.end.wrapping_add(1);
120
121    // Pass each `u128` endpoint value as a `[u64; 2]` array, least-significant part first.
122    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    // To ensure that LLVM doesn't try to read beyond the `[u64; 2]` arrays,
127    // we must explicitly check that `size_bits` does not exceed 128.
128    let size_bits = size.bits();
129    assert!(size_bits <= 128);
130    // More robust assertions that are redundant with `size_bits <= 128` and
131    // should be optimized away.
132    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
177// Externally visible symbols that might appear in multiple codegen units need to appear in
178// their own comdat section so that the duplicates can be discarded at link time. This can for
179// example happen for generics when using multiple codegen units. This function simply uses the
180// value's name as the comdat value to make sure that it is in a 1-to-1 relationship to the
181// function.
182// For more details on COMDAT sections see e.g., https://www.airs.com/blog/archives/52
183pub(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    /// Create an LLVM Attribute with no associated value.
202    pub(crate) fn create_attr(self, llcx: &Context) -> &Attribute {
203        unsafe { LLVMRustCreateAttrNoValue(llcx, self) }
204    }
205}
206
207impl MemoryEffects {
208    /// Create an LLVM Attribute with these memory effects.
209    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
268/// Get the `name`d comdat from `llmod` and assign it to `llglobal`.
269///
270/// Inserts the comdat into `llmod` if it does not exist.
271/// It is an error to call this if the target does not support comdat.
272pub(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
279/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
280pub(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
292/// Safe wrapper for `LLVMGetValueName2`
293/// Needs to allocate the value, because `set_value_name` will invalidate
294/// the pointer.
295pub(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
325/// Safe wrapper for `LLVMSetValueName2` from a byte slice
326pub(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
361/// Owning pointer to an [`OperandBundle`] that will dispose of the bundle
362/// when dropped.
363pub(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    /// Dereferences to the underlying `&OperandBundle`.
381    ///
382    /// This can't be a `Deref` implementation because `OperandBundle` transitively
383    /// contains an extern type, which is incompatible with `Deref::Target: ?Sized`.
384    pub(crate) fn as_ref(&self) -> &OperandBundle<'a> {
385        // SAFETY: The returned reference is opaque and can only used for FFI.
386        // It is valid for as long as `&self` is.
387        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
440/// Safe wrapper for `LLVMAppendModuleInlineAsm`, which delegates to
441/// `Module::appendModuleInlineAsm`.
442pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) {
443    unsafe {
444        LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len());
445    }
446}