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