rustc_codegen_llvm/llvm/
mod.rs

1#![allow(non_snake_case)]
2
3use std::ffi::{CStr, CString};
4use std::ops::Deref;
5use std::ptr;
6use std::str::FromStr;
7use std::string::FromUtf8Error;
8
9use libc::c_uint;
10use rustc_abi::{Align, Size, WrappingRange};
11use rustc_llvm::RustString;
12
13pub use self::CallConv::*;
14pub use self::CodeGenOptSize::*;
15pub use self::MetadataType::*;
16pub use self::ffi::*;
17use crate::common::AsCCharPtr;
18
19pub mod archive_ro;
20pub mod diagnostic;
21pub mod enzyme_ffi;
22mod ffi;
23
24pub use self::enzyme_ffi::*;
25
26impl LLVMRustResult {
27    pub(crate) fn into_result(self) -> Result<(), ()> {
28        match self {
29            LLVMRustResult::Success => Ok(()),
30            LLVMRustResult::Failure => Err(()),
31        }
32    }
33}
34
35pub(crate) fn AddFunctionAttributes<'ll>(
36    llfn: &'ll Value,
37    idx: AttributePlace,
38    attrs: &[&'ll Attribute],
39) {
40    unsafe {
41        LLVMRustAddFunctionAttributes(llfn, idx.as_uint(), attrs.as_ptr(), attrs.len());
42    }
43}
44
45pub(crate) fn AddCallSiteAttributes<'ll>(
46    callsite: &'ll Value,
47    idx: AttributePlace,
48    attrs: &[&'ll Attribute],
49) {
50    unsafe {
51        LLVMRustAddCallSiteAttributes(callsite, idx.as_uint(), attrs.as_ptr(), attrs.len());
52    }
53}
54
55pub(crate) fn CreateAttrStringValue<'ll>(
56    llcx: &'ll Context,
57    attr: &str,
58    value: &str,
59) -> &'ll Attribute {
60    unsafe {
61        LLVMCreateStringAttribute(
62            llcx,
63            attr.as_c_char_ptr(),
64            attr.len().try_into().unwrap(),
65            value.as_c_char_ptr(),
66            value.len().try_into().unwrap(),
67        )
68    }
69}
70
71pub(crate) fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute {
72    unsafe {
73        LLVMCreateStringAttribute(
74            llcx,
75            attr.as_c_char_ptr(),
76            attr.len().try_into().unwrap(),
77            std::ptr::null(),
78            0,
79        )
80    }
81}
82
83pub(crate) fn CreateAlignmentAttr(llcx: &Context, bytes: u64) -> &Attribute {
84    unsafe { LLVMRustCreateAlignmentAttr(llcx, bytes) }
85}
86
87pub(crate) fn CreateDereferenceableAttr(llcx: &Context, bytes: u64) -> &Attribute {
88    unsafe { LLVMRustCreateDereferenceableAttr(llcx, bytes) }
89}
90
91pub(crate) fn CreateDereferenceableOrNullAttr(llcx: &Context, bytes: u64) -> &Attribute {
92    unsafe { LLVMRustCreateDereferenceableOrNullAttr(llcx, bytes) }
93}
94
95pub(crate) fn CreateByValAttr<'ll>(llcx: &'ll Context, ty: &'ll Type) -> &'ll Attribute {
96    unsafe { LLVMRustCreateByValAttr(llcx, ty) }
97}
98
99pub(crate) fn CreateStructRetAttr<'ll>(llcx: &'ll Context, ty: &'ll Type) -> &'ll Attribute {
100    unsafe { LLVMRustCreateStructRetAttr(llcx, ty) }
101}
102
103pub(crate) fn CreateUWTableAttr(llcx: &Context, async_: bool) -> &Attribute {
104    unsafe { LLVMRustCreateUWTableAttr(llcx, async_) }
105}
106
107pub(crate) fn CreateAllocSizeAttr(llcx: &Context, size_arg: u32) -> &Attribute {
108    unsafe { LLVMRustCreateAllocSizeAttr(llcx, size_arg) }
109}
110
111pub(crate) fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> &Attribute {
112    unsafe { LLVMRustCreateAllocKindAttr(llcx, kind_arg.bits()) }
113}
114
115pub(crate) fn CreateRangeAttr(llcx: &Context, size: Size, range: WrappingRange) -> &Attribute {
116    let lower = range.start;
117    let upper = range.end.wrapping_add(1);
118    let lower_words = [lower as u64, (lower >> 64) as u64];
119    let upper_words = [upper as u64, (upper >> 64) as u64];
120    unsafe {
121        LLVMRustCreateRangeAttribute(
122            llcx,
123            size.bits().try_into().unwrap(),
124            lower_words.as_ptr(),
125            upper_words.as_ptr(),
126        )
127    }
128}
129
130#[derive(Copy, Clone)]
131pub enum AttributePlace {
132    ReturnValue,
133    Argument(u32),
134    Function,
135}
136
137impl AttributePlace {
138    pub(crate) fn as_uint(self) -> c_uint {
139        match self {
140            AttributePlace::ReturnValue => 0,
141            AttributePlace::Argument(i) => 1 + i,
142            AttributePlace::Function => !0,
143        }
144    }
145}
146
147#[derive(Copy, Clone, PartialEq)]
148#[repr(C)]
149pub enum CodeGenOptSize {
150    CodeGenOptSizeNone = 0,
151    CodeGenOptSizeDefault = 1,
152    CodeGenOptSizeAggressive = 2,
153}
154
155impl FromStr for ArchiveKind {
156    type Err = ();
157
158    fn from_str(s: &str) -> Result<Self, Self::Err> {
159        match s {
160            "gnu" => Ok(ArchiveKind::K_GNU),
161            "bsd" => Ok(ArchiveKind::K_BSD),
162            "darwin" => Ok(ArchiveKind::K_DARWIN),
163            "coff" => Ok(ArchiveKind::K_COFF),
164            "aix_big" => Ok(ArchiveKind::K_AIXBIG),
165            _ => Err(()),
166        }
167    }
168}
169
170pub(crate) fn SetInstructionCallConv(instr: &Value, cc: CallConv) {
171    unsafe {
172        LLVMSetInstructionCallConv(instr, cc as c_uint);
173    }
174}
175pub(crate) fn SetFunctionCallConv(fn_: &Value, cc: CallConv) {
176    unsafe {
177        LLVMSetFunctionCallConv(fn_, cc as c_uint);
178    }
179}
180
181// Externally visible symbols that might appear in multiple codegen units need to appear in
182// their own comdat section so that the duplicates can be discarded at link time. This can for
183// example happen for generics when using multiple codegen units. This function simply uses the
184// value's name as the comdat value to make sure that it is in a 1-to-1 relationship to the
185// function.
186// For more details on COMDAT sections see e.g., https://www.airs.com/blog/archives/52
187pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) {
188    let name_buf = get_value_name(val).to_vec();
189    let name =
190        CString::from_vec_with_nul(name_buf).or_else(|buf| CString::new(buf.into_bytes())).unwrap();
191    set_comdat(llmod, val, &name);
192}
193
194pub(crate) fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) {
195    unsafe {
196        LLVMSetUnnamedAddress(global, unnamed);
197    }
198}
199
200pub(crate) fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) {
201    unsafe {
202        LLVMSetThreadLocalMode(global, mode);
203    }
204}
205
206impl AttributeKind {
207    /// Create an LLVM Attribute with no associated value.
208    pub(crate) fn create_attr(self, llcx: &Context) -> &Attribute {
209        unsafe { LLVMRustCreateAttrNoValue(llcx, self) }
210    }
211}
212
213impl MemoryEffects {
214    /// Create an LLVM Attribute with these memory effects.
215    pub(crate) fn create_attr(self, llcx: &Context) -> &Attribute {
216        unsafe { LLVMRustCreateMemoryEffectsAttr(llcx, self) }
217    }
218}
219
220pub(crate) fn set_section(llglobal: &Value, section_name: &CStr) {
221    unsafe {
222        LLVMSetSection(llglobal, section_name.as_ptr());
223    }
224}
225
226pub(crate) fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name_cstr: &CStr) -> &'a Value {
227    unsafe { LLVMAddGlobal(llmod, ty, name_cstr.as_ptr()) }
228}
229
230pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) {
231    unsafe {
232        LLVMSetInitializer(llglobal, constant_val);
233    }
234}
235
236pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) {
237    unsafe {
238        LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False });
239    }
240}
241
242pub(crate) fn get_linkage(llglobal: &Value) -> Linkage {
243    unsafe { LLVMGetLinkage(llglobal) }.to_rust()
244}
245
246pub(crate) fn set_linkage(llglobal: &Value, linkage: Linkage) {
247    unsafe {
248        LLVMSetLinkage(llglobal, linkage);
249    }
250}
251
252pub(crate) fn is_declaration(llglobal: &Value) -> bool {
253    unsafe { LLVMIsDeclaration(llglobal) == ffi::True }
254}
255
256pub(crate) fn get_visibility(llglobal: &Value) -> Visibility {
257    unsafe { LLVMGetVisibility(llglobal) }.to_rust()
258}
259
260pub(crate) fn set_visibility(llglobal: &Value, visibility: Visibility) {
261    unsafe {
262        LLVMSetVisibility(llglobal, visibility);
263    }
264}
265
266pub(crate) fn set_alignment(llglobal: &Value, align: Align) {
267    unsafe {
268        ffi::LLVMSetAlignment(llglobal, align.bytes() as c_uint);
269    }
270}
271
272/// Get the `name`d comdat from `llmod` and assign it to `llglobal`.
273///
274/// Inserts the comdat into `llmod` if it does not exist.
275/// It is an error to call this if the target does not support comdat.
276pub(crate) fn set_comdat(llmod: &Module, llglobal: &Value, name: &CStr) {
277    unsafe {
278        let comdat = LLVMGetOrInsertComdat(llmod, name.as_ptr());
279        LLVMSetComdat(llglobal, comdat);
280    }
281}
282
283/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
284pub(crate) fn get_param(llfn: &Value, index: c_uint) -> &Value {
285    unsafe {
286        assert!(
287            index < LLVMCountParams(llfn),
288            "out of bounds argument access: {} out of {} arguments",
289            index,
290            LLVMCountParams(llfn)
291        );
292        LLVMGetParam(llfn, index)
293    }
294}
295
296/// Safe wrapper for `LLVMGetValueName2` into a byte slice
297pub(crate) fn get_value_name(value: &Value) -> &[u8] {
298    unsafe {
299        let mut len = 0;
300        let data = LLVMGetValueName2(value, &mut len);
301        std::slice::from_raw_parts(data.cast(), len)
302    }
303}
304
305/// Safe wrapper for `LLVMSetValueName2` from a byte slice
306pub(crate) fn set_value_name(value: &Value, name: &[u8]) {
307    unsafe {
308        let data = name.as_c_char_ptr();
309        LLVMSetValueName2(value, data, name.len());
310    }
311}
312
313pub(crate) fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
314    String::from_utf8(RustString::build_byte_buffer(f))
315}
316
317pub(crate) fn build_byte_buffer(f: impl FnOnce(&RustString)) -> Vec<u8> {
318    RustString::build_byte_buffer(f)
319}
320
321pub(crate) fn twine_to_string(tr: &Twine) -> String {
322    unsafe {
323        build_string(|s| LLVMRustWriteTwineToString(tr, s)).expect("got a non-UTF8 Twine from LLVM")
324    }
325}
326
327pub(crate) fn last_error() -> Option<String> {
328    unsafe {
329        let cstr = LLVMRustGetLastError();
330        if cstr.is_null() {
331            None
332        } else {
333            let err = CStr::from_ptr(cstr).to_bytes();
334            let err = String::from_utf8_lossy(err).to_string();
335            libc::free(cstr as *mut _);
336            Some(err)
337        }
338    }
339}
340
341/// Owns an [`OperandBundle`], and will dispose of it when dropped.
342pub(crate) struct OperandBundleOwned<'a> {
343    raw: ptr::NonNull<OperandBundle<'a>>,
344}
345
346impl<'a> OperandBundleOwned<'a> {
347    pub(crate) fn new(name: &str, vals: &[&'a Value]) -> Self {
348        let raw = unsafe {
349            LLVMCreateOperandBundle(
350                name.as_c_char_ptr(),
351                name.len(),
352                vals.as_ptr(),
353                vals.len() as c_uint,
354            )
355        };
356        OperandBundleOwned { raw: ptr::NonNull::new(raw).unwrap() }
357    }
358}
359
360impl Drop for OperandBundleOwned<'_> {
361    fn drop(&mut self) {
362        unsafe {
363            LLVMDisposeOperandBundle(self.raw);
364        }
365    }
366}
367
368impl<'a> Deref for OperandBundleOwned<'a> {
369    type Target = OperandBundle<'a>;
370
371    fn deref(&self) -> &Self::Target {
372        // SAFETY: The returned reference is opaque and can only used for FFI.
373        // It is valid for as long as `&self` is.
374        unsafe { self.raw.as_ref() }
375    }
376}
377
378pub(crate) fn add_module_flag_u32(
379    module: &Module,
380    merge_behavior: ModuleFlagMergeBehavior,
381    key: &str,
382    value: u32,
383) {
384    unsafe {
385        LLVMRustAddModuleFlagU32(module, merge_behavior, key.as_c_char_ptr(), key.len(), value);
386    }
387}
388
389pub(crate) fn add_module_flag_str(
390    module: &Module,
391    merge_behavior: ModuleFlagMergeBehavior,
392    key: &str,
393    value: &str,
394) {
395    unsafe {
396        LLVMRustAddModuleFlagString(
397            module,
398            merge_behavior,
399            key.as_c_char_ptr(),
400            key.len(),
401            value.as_c_char_ptr(),
402            value.len(),
403        );
404    }
405}