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