rustc_codegen_llvm/
declare.rs

1//! Declare various LLVM values.
2//!
3//! Prefer using functions and methods from this module rather than calling LLVM
4//! functions directly. These functions do some additional work to ensure we do
5//! the right thing given the preconceptions of codegen.
6//!
7//! Some useful guidelines:
8//!
9//! * Use declare_* family of methods if you are declaring, but are not
10//!   interested in defining the Value they return.
11//! * Use define_* family of methods when you might be defining the Value.
12//! * When in doubt, define.
13
14use itertools::Itertools;
15use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods;
16use rustc_data_structures::fx::FxIndexSet;
17use rustc_middle::ty::{Instance, Ty};
18use rustc_sanitizers::{cfi, kcfi};
19use smallvec::SmallVec;
20use tracing::debug;
21
22use crate::abi::{FnAbi, FnAbiLlvmExt};
23use crate::common::AsCCharPtr;
24use crate::context::{CodegenCx, SimpleCx};
25use crate::llvm::AttributePlace::Function;
26use crate::llvm::Visibility;
27use crate::type_::Type;
28use crate::value::Value;
29use crate::{attributes, llvm};
30
31/// Declare a function with a SimpleCx.
32///
33/// If there’s a value with the same name already declared, the function will
34/// update the declaration and return existing Value instead.
35pub(crate) fn declare_simple_fn<'ll>(
36    cx: &SimpleCx<'ll>,
37    name: &str,
38    callconv: llvm::CallConv,
39    unnamed: llvm::UnnamedAddr,
40    visibility: llvm::Visibility,
41    ty: &'ll Type,
42) -> &'ll Value {
43    debug!("declare_simple_fn(name={:?}, ty={:?})", name, ty);
44    let llfn = unsafe {
45        llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty)
46    };
47
48    llvm::SetFunctionCallConv(llfn, callconv);
49    llvm::SetUnnamedAddress(llfn, unnamed);
50    llvm::set_visibility(llfn, visibility);
51
52    llfn
53}
54
55/// Declare a function.
56///
57/// If there’s a value with the same name already declared, the function will
58/// update the declaration and return existing Value instead.
59pub(crate) fn declare_raw_fn<'ll, 'tcx>(
60    cx: &CodegenCx<'ll, 'tcx>,
61    name: &str,
62    callconv: llvm::CallConv,
63    unnamed: llvm::UnnamedAddr,
64    visibility: llvm::Visibility,
65    ty: &'ll Type,
66) -> &'ll Value {
67    debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
68    let llfn = declare_simple_fn(cx, name, callconv, unnamed, visibility, ty);
69
70    let mut attrs = SmallVec::<[_; 4]>::new();
71
72    if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {
73        attrs.push(llvm::AttributeKind::NoRedZone.create_attr(cx.llcx));
74    }
75
76    attrs.extend(attributes::non_lazy_bind_attr(cx));
77
78    attributes::apply_to_llfn(llfn, Function, &attrs);
79
80    llfn
81}
82
83impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
84    /// Declare a global value.
85    ///
86    /// If there’s a value with the same name already declared, the function will
87    /// return its Value instead.
88    pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value {
89        debug!("declare_global(name={:?})", name);
90        unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) }
91    }
92
93    /// Declare a C ABI function.
94    ///
95    /// Only use this for foreign function ABIs and glue. For Rust functions use
96    /// `declare_fn` instead.
97    ///
98    /// If there’s a value with the same name already declared, the function will
99    /// update the declaration and return existing Value instead.
100    pub(crate) fn declare_cfn(
101        &self,
102        name: &str,
103        unnamed: llvm::UnnamedAddr,
104        fn_type: &'ll Type,
105    ) -> &'ll Value {
106        // Visibility should always be default for declarations, otherwise the linker may report an
107        // error.
108        declare_raw_fn(self, name, llvm::CCallConv, unnamed, Visibility::Default, fn_type)
109    }
110
111    /// Declare an entry Function
112    ///
113    /// The ABI of this function can change depending on the target (although for now the same as
114    /// `declare_cfn`)
115    ///
116    /// If there’s a value with the same name already declared, the function will
117    /// update the declaration and return existing Value instead.
118    pub(crate) fn declare_entry_fn(
119        &self,
120        name: &str,
121        callconv: llvm::CallConv,
122        unnamed: llvm::UnnamedAddr,
123        fn_type: &'ll Type,
124    ) -> &'ll Value {
125        let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
126        declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type)
127    }
128
129    /// Declare a Rust function.
130    ///
131    /// If there’s a value with the same name already declared, the function will
132    /// update the declaration and return existing Value instead.
133    pub(crate) fn declare_fn(
134        &self,
135        name: &str,
136        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
137        instance: Option<Instance<'tcx>>,
138    ) -> &'ll Value {
139        debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
140
141        // Function addresses in Rust are never significant, allowing functions to
142        // be merged.
143        let llfn = declare_raw_fn(
144            self,
145            name,
146            fn_abi.llvm_cconv(self),
147            llvm::UnnamedAddr::Global,
148            llvm::Visibility::Default,
149            fn_abi.llvm_type(self),
150        );
151        fn_abi.apply_attrs_llfn(self, llfn, instance);
152
153        if self.tcx.sess.is_sanitizer_cfi_enabled() {
154            if let Some(instance) = instance {
155                let mut typeids = FxIndexSet::default();
156                for options in [
157                    cfi::TypeIdOptions::GENERALIZE_POINTERS,
158                    cfi::TypeIdOptions::NORMALIZE_INTEGERS,
159                    cfi::TypeIdOptions::USE_CONCRETE_SELF,
160                ]
161                .into_iter()
162                .powerset()
163                .map(cfi::TypeIdOptions::from_iter)
164                {
165                    let typeid = cfi::typeid_for_instance(self.tcx, instance, options);
166                    if typeids.insert(typeid.clone()) {
167                        self.add_type_metadata(llfn, typeid);
168                    }
169                }
170            } else {
171                for options in [
172                    cfi::TypeIdOptions::GENERALIZE_POINTERS,
173                    cfi::TypeIdOptions::NORMALIZE_INTEGERS,
174                ]
175                .into_iter()
176                .powerset()
177                .map(cfi::TypeIdOptions::from_iter)
178                {
179                    let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options);
180                    self.add_type_metadata(llfn, typeid);
181                }
182            }
183        }
184
185        if self.tcx.sess.is_sanitizer_kcfi_enabled() {
186            // LLVM KCFI does not support multiple !kcfi_type attachments
187            let mut options = kcfi::TypeIdOptions::empty();
188            if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
189                options.insert(kcfi::TypeIdOptions::GENERALIZE_POINTERS);
190            }
191            if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
192                options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS);
193            }
194
195            if let Some(instance) = instance {
196                let kcfi_typeid = kcfi::typeid_for_instance(self.tcx, instance, options);
197                self.set_kcfi_type_metadata(llfn, kcfi_typeid);
198            } else {
199                let kcfi_typeid = kcfi::typeid_for_fnabi(self.tcx, fn_abi, options);
200                self.set_kcfi_type_metadata(llfn, kcfi_typeid);
201            }
202        }
203
204        llfn
205    }
206
207    /// Declare a global with an intention to define it.
208    ///
209    /// Use this function when you intend to define a global. This function will
210    /// return `None` if the name already has a definition associated with it. In that
211    /// case an error should be reported to the user, because it usually happens due
212    /// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes).
213    pub(crate) fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> {
214        if self.get_defined_value(name).is_some() {
215            None
216        } else {
217            Some(self.declare_global(name, ty))
218        }
219    }
220
221    /// Declare a private global
222    ///
223    /// Use this function when you intend to define a global without a name.
224    pub(crate) fn define_private_global(&self, ty: &'ll Type) -> &'ll Value {
225        unsafe { llvm::LLVMRustInsertPrivateGlobal(self.llmod, ty) }
226    }
227
228    /// Gets declared value by name.
229    pub(crate) fn get_declared_value(&self, name: &str) -> Option<&'ll Value> {
230        debug!("get_declared_value(name={:?})", name);
231        unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_c_char_ptr(), name.len()) }
232    }
233
234    /// Gets defined or externally defined (AvailableExternally linkage) value by
235    /// name.
236    pub(crate) fn get_defined_value(&self, name: &str) -> Option<&'ll Value> {
237        self.get_declared_value(name).and_then(|val| {
238            let declaration = llvm::is_declaration(val);
239            if !declaration { Some(val) } else { None }
240        })
241    }
242}