Skip to main content

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::{MiscCodegenMethods, 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    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/declare.rs:44",
                        "rustc_codegen_llvm::declare", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/declare.rs"),
                        ::tracing_core::__macro_support::Option::Some(44u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::declare"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("declare_simple_fn(name={0:?}, ty={1:?})",
                                                    name, ty) as &dyn Value))])
            });
    } else { ; }
};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    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/declare.rs:68",
                        "rustc_codegen_llvm::declare", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/declare.rs"),
                        ::tracing_core::__macro_support::Option::Some(68u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::declare"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("declare_raw_fn(name={0:?}, ty={1:?})",
                                                    name, ty) as &dyn Value))])
            });
    } else { ; }
};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.sess().target.is_like_gpu {
74        // Conservatively apply convergent to all functions in case they may call
75        // a convergent function. Rely on LLVM to optimize away the unnecessary
76        // convergent attributes.
77        attrs.push(llvm::AttributeKind::Convergent.create_attr(cx.llcx));
78    }
79
80    if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {
81        attrs.push(llvm::AttributeKind::NoRedZone.create_attr(cx.llcx));
82    }
83
84    attrs.extend(attributes::non_lazy_bind_attr(cx, cx.tcx.sess));
85
86    attributes::apply_to_llfn(llfn, Function, &attrs);
87
88    llfn
89}
90
91impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
92    /// Declare a global value.
93    ///
94    /// If there’s a value with the same name already declared, the function will
95    /// return its Value instead.
96    pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value {
97        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/declare.rs:97",
                        "rustc_codegen_llvm::declare", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/declare.rs"),
                        ::tracing_core::__macro_support::Option::Some(97u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::declare"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("declare_global(name={0:?})",
                                                    name) as &dyn Value))])
            });
    } else { ; }
};debug!("declare_global(name={:?})", name);
98        unsafe {
99            llvm::LLVMRustGetOrInsertGlobal(
100                (**self).borrow().llmod,
101                name.as_c_char_ptr(),
102                name.len(),
103                ty,
104            )
105        }
106    }
107}
108
109impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
110    /// Declare a C ABI function.
111    ///
112    /// Only use this for foreign function ABIs and glue. For Rust functions use
113    /// `declare_fn` instead.
114    ///
115    /// If there’s a value with the same name already declared, the function will
116    /// update the declaration and return existing Value instead.
117    pub(crate) fn declare_cfn(
118        &self,
119        name: &str,
120        unnamed: llvm::UnnamedAddr,
121        fn_type: &'ll Type,
122    ) -> &'ll Value {
123        // Visibility should always be default for declarations, otherwise the linker may report an
124        // error.
125        declare_raw_fn(self, name, llvm::CCallConv, unnamed, Visibility::Default, fn_type)
126    }
127
128    /// Declare an entry Function
129    ///
130    /// The ABI of this function can change depending on the target (although for now the same as
131    /// `declare_cfn`)
132    ///
133    /// If there’s a value with the same name already declared, the function will
134    /// update the declaration and return existing Value instead.
135    pub(crate) fn declare_entry_fn(
136        &self,
137        name: &str,
138        callconv: llvm::CallConv,
139        unnamed: llvm::UnnamedAddr,
140        fn_type: &'ll Type,
141    ) -> &'ll Value {
142        let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
143        declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type)
144    }
145
146    /// Declare a Rust function.
147    ///
148    /// If there’s a value with the same name already declared, the function will
149    /// update the declaration and return existing Value instead.
150    pub(crate) fn declare_fn(
151        &self,
152        name: &str,
153        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
154        instance: Option<Instance<'tcx>>,
155    ) -> &'ll Value {
156        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/declare.rs:156",
                        "rustc_codegen_llvm::declare", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/declare.rs"),
                        ::tracing_core::__macro_support::Option::Some(156u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::declare"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("declare_rust_fn(name={0:?}, fn_abi={1:?})",
                                                    name, fn_abi) as &dyn Value))])
            });
    } else { ; }
};debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
157
158        // Function addresses in Rust are never significant, allowing functions to
159        // be merged.
160        let llfn = declare_raw_fn(
161            self,
162            name,
163            fn_abi.llvm_cconv(self),
164            llvm::UnnamedAddr::Global,
165            llvm::Visibility::Default,
166            fn_abi.llvm_type(self),
167        );
168        fn_abi.apply_attrs_llfn(self, llfn, instance);
169
170        if self.tcx.sess.is_sanitizer_cfi_enabled() {
171            if let Some(instance) = instance {
172                let mut typeids = FxIndexSet::default();
173                for options in [
174                    cfi::TypeIdOptions::GENERALIZE_POINTERS,
175                    cfi::TypeIdOptions::NORMALIZE_INTEGERS,
176                    cfi::TypeIdOptions::USE_CONCRETE_SELF,
177                ]
178                .into_iter()
179                .powerset()
180                .map(cfi::TypeIdOptions::from_iter)
181                {
182                    let typeid = cfi::typeid_for_instance(self.tcx, instance, options);
183                    if typeids.insert(typeid.clone()) {
184                        self.add_type_metadata(llfn, typeid.as_bytes());
185                    }
186                }
187            } else {
188                for options in [
189                    cfi::TypeIdOptions::GENERALIZE_POINTERS,
190                    cfi::TypeIdOptions::NORMALIZE_INTEGERS,
191                ]
192                .into_iter()
193                .powerset()
194                .map(cfi::TypeIdOptions::from_iter)
195                {
196                    let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options);
197                    self.add_type_metadata(llfn, typeid.as_bytes());
198                }
199            }
200        }
201
202        if self.tcx.sess.is_sanitizer_kcfi_enabled() {
203            // LLVM KCFI does not support multiple !kcfi_type attachments
204            let mut options = kcfi::TypeIdOptions::empty();
205            if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
206                options.insert(kcfi::TypeIdOptions::GENERALIZE_POINTERS);
207            }
208            if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
209                options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS);
210            }
211
212            if let Some(instance) = instance {
213                let kcfi_typeid = kcfi::typeid_for_instance(self.tcx, instance, options);
214                self.set_kcfi_type_metadata(llfn, kcfi_typeid);
215            } else {
216                let kcfi_typeid = kcfi::typeid_for_fnabi(self.tcx, fn_abi, options);
217                self.set_kcfi_type_metadata(llfn, kcfi_typeid);
218            }
219        }
220
221        llfn
222    }
223}
224
225impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
226    /// Declare a global with an intention to define it.
227    ///
228    /// Use this function when you intend to define a global. This function will
229    /// return `None` if the name already has a definition associated with it. In that
230    /// case an error should be reported to the user, because it usually happens due
231    /// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes).
232    pub(crate) fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> {
233        if self.get_defined_value(name).is_some() {
234            None
235        } else {
236            Some(self.declare_global(name, ty))
237        }
238    }
239
240    /// Gets declared value by name.
241    pub(crate) fn get_declared_value(&self, name: &str) -> Option<&'ll Value> {
242        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/declare.rs:242",
                        "rustc_codegen_llvm::declare", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/declare.rs"),
                        ::tracing_core::__macro_support::Option::Some(242u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::declare"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("get_declared_value(name={0:?})",
                                                    name) as &dyn Value))])
            });
    } else { ; }
};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}