| //! Declare various LLVM values. | 
 | //! | 
 | //! Prefer using functions and methods from this module rather than calling LLVM | 
 | //! functions directly. These functions do some additional work to ensure we do | 
 | //! the right thing given the preconceptions of codegen. | 
 | //! | 
 | //! Some useful guidelines: | 
 | //! | 
 | //! * Use declare_* family of methods if you are declaring, but are not | 
 | //!   interested in defining the Value they return. | 
 | //! * Use define_* family of methods when you might be defining the Value. | 
 | //! * When in doubt, define. | 
 |  | 
 | use std::borrow::Borrow; | 
 |  | 
 | use itertools::Itertools; | 
 | use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods; | 
 | use rustc_data_structures::fx::FxIndexSet; | 
 | use rustc_middle::ty::{Instance, Ty}; | 
 | use rustc_sanitizers::{cfi, kcfi}; | 
 | use rustc_target::callconv::FnAbi; | 
 | use smallvec::SmallVec; | 
 | use tracing::debug; | 
 |  | 
 | use crate::abi::FnAbiLlvmExt; | 
 | use crate::common::AsCCharPtr; | 
 | use crate::context::{CodegenCx, GenericCx, SCx, SimpleCx}; | 
 | use crate::llvm::AttributePlace::Function; | 
 | use crate::llvm::Visibility; | 
 | use crate::type_::Type; | 
 | use crate::value::Value; | 
 | use crate::{attributes, llvm}; | 
 |  | 
 | /// Declare a function with a SimpleCx. | 
 | /// | 
 | /// If there’s a value with the same name already declared, the function will | 
 | /// update the declaration and return existing Value instead. | 
 | pub(crate) fn declare_simple_fn<'ll>( | 
 |     cx: &SimpleCx<'ll>, | 
 |     name: &str, | 
 |     callconv: llvm::CallConv, | 
 |     unnamed: llvm::UnnamedAddr, | 
 |     visibility: llvm::Visibility, | 
 |     ty: &'ll Type, | 
 | ) -> &'ll Value { | 
 |     debug!("declare_simple_fn(name={:?}, ty={:?})", name, ty); | 
 |     let llfn = unsafe { | 
 |         llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty) | 
 |     }; | 
 |  | 
 |     llvm::SetFunctionCallConv(llfn, callconv); | 
 |     llvm::set_unnamed_address(llfn, unnamed); | 
 |     llvm::set_visibility(llfn, visibility); | 
 |  | 
 |     llfn | 
 | } | 
 |  | 
 | /// Declare a function. | 
 | /// | 
 | /// If there’s a value with the same name already declared, the function will | 
 | /// update the declaration and return existing Value instead. | 
 | pub(crate) fn declare_raw_fn<'ll, 'tcx>( | 
 |     cx: &CodegenCx<'ll, 'tcx>, | 
 |     name: &str, | 
 |     callconv: llvm::CallConv, | 
 |     unnamed: llvm::UnnamedAddr, | 
 |     visibility: llvm::Visibility, | 
 |     ty: &'ll Type, | 
 | ) -> &'ll Value { | 
 |     debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); | 
 |     let llfn = declare_simple_fn(cx, name, callconv, unnamed, visibility, ty); | 
 |  | 
 |     let mut attrs = SmallVec::<[_; 4]>::new(); | 
 |  | 
 |     if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) { | 
 |         attrs.push(llvm::AttributeKind::NoRedZone.create_attr(cx.llcx)); | 
 |     } | 
 |  | 
 |     attrs.extend(attributes::non_lazy_bind_attr(cx)); | 
 |  | 
 |     attributes::apply_to_llfn(llfn, Function, &attrs); | 
 |  | 
 |     llfn | 
 | } | 
 |  | 
 | impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { | 
 |     /// Declare a global value. | 
 |     /// | 
 |     /// If there’s a value with the same name already declared, the function will | 
 |     /// return its Value instead. | 
 |     pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { | 
 |         debug!("declare_global(name={:?})", name); | 
 |         unsafe { | 
 |             llvm::LLVMRustGetOrInsertGlobal( | 
 |                 (**self).borrow().llmod, | 
 |                 name.as_c_char_ptr(), | 
 |                 name.len(), | 
 |                 ty, | 
 |             ) | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { | 
 |     /// Declare a C ABI function. | 
 |     /// | 
 |     /// Only use this for foreign function ABIs and glue. For Rust functions use | 
 |     /// `declare_fn` instead. | 
 |     /// | 
 |     /// If there’s a value with the same name already declared, the function will | 
 |     /// update the declaration and return existing Value instead. | 
 |     pub(crate) fn declare_cfn( | 
 |         &self, | 
 |         name: &str, | 
 |         unnamed: llvm::UnnamedAddr, | 
 |         fn_type: &'ll Type, | 
 |     ) -> &'ll Value { | 
 |         // Visibility should always be default for declarations, otherwise the linker may report an | 
 |         // error. | 
 |         declare_raw_fn(self, name, llvm::CCallConv, unnamed, Visibility::Default, fn_type) | 
 |     } | 
 |  | 
 |     /// Declare an entry Function | 
 |     /// | 
 |     /// The ABI of this function can change depending on the target (although for now the same as | 
 |     /// `declare_cfn`) | 
 |     /// | 
 |     /// If there’s a value with the same name already declared, the function will | 
 |     /// update the declaration and return existing Value instead. | 
 |     pub(crate) fn declare_entry_fn( | 
 |         &self, | 
 |         name: &str, | 
 |         callconv: llvm::CallConv, | 
 |         unnamed: llvm::UnnamedAddr, | 
 |         fn_type: &'ll Type, | 
 |     ) -> &'ll Value { | 
 |         let visibility = Visibility::from_generic(self.tcx.sess.default_visibility()); | 
 |         declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type) | 
 |     } | 
 |  | 
 |     /// Declare a Rust function. | 
 |     /// | 
 |     /// If there’s a value with the same name already declared, the function will | 
 |     /// update the declaration and return existing Value instead. | 
 |     pub(crate) fn declare_fn( | 
 |         &self, | 
 |         name: &str, | 
 |         fn_abi: &FnAbi<'tcx, Ty<'tcx>>, | 
 |         instance: Option<Instance<'tcx>>, | 
 |     ) -> &'ll Value { | 
 |         debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi); | 
 |  | 
 |         // Function addresses in Rust are never significant, allowing functions to | 
 |         // be merged. | 
 |         let llfn = declare_raw_fn( | 
 |             self, | 
 |             name, | 
 |             fn_abi.llvm_cconv(self), | 
 |             llvm::UnnamedAddr::Global, | 
 |             llvm::Visibility::Default, | 
 |             fn_abi.llvm_type(self), | 
 |         ); | 
 |         fn_abi.apply_attrs_llfn(self, llfn, instance); | 
 |  | 
 |         if self.tcx.sess.is_sanitizer_cfi_enabled() { | 
 |             if let Some(instance) = instance { | 
 |                 let mut typeids = FxIndexSet::default(); | 
 |                 for options in [ | 
 |                     cfi::TypeIdOptions::GENERALIZE_POINTERS, | 
 |                     cfi::TypeIdOptions::NORMALIZE_INTEGERS, | 
 |                     cfi::TypeIdOptions::USE_CONCRETE_SELF, | 
 |                 ] | 
 |                 .into_iter() | 
 |                 .powerset() | 
 |                 .map(cfi::TypeIdOptions::from_iter) | 
 |                 { | 
 |                     let typeid = cfi::typeid_for_instance(self.tcx, instance, options); | 
 |                     if typeids.insert(typeid.clone()) { | 
 |                         self.add_type_metadata(llfn, typeid.as_bytes()); | 
 |                     } | 
 |                 } | 
 |             } else { | 
 |                 for options in [ | 
 |                     cfi::TypeIdOptions::GENERALIZE_POINTERS, | 
 |                     cfi::TypeIdOptions::NORMALIZE_INTEGERS, | 
 |                 ] | 
 |                 .into_iter() | 
 |                 .powerset() | 
 |                 .map(cfi::TypeIdOptions::from_iter) | 
 |                 { | 
 |                     let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options); | 
 |                     self.add_type_metadata(llfn, typeid.as_bytes()); | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         if self.tcx.sess.is_sanitizer_kcfi_enabled() { | 
 |             // LLVM KCFI does not support multiple !kcfi_type attachments | 
 |             let mut options = kcfi::TypeIdOptions::empty(); | 
 |             if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { | 
 |                 options.insert(kcfi::TypeIdOptions::GENERALIZE_POINTERS); | 
 |             } | 
 |             if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() { | 
 |                 options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS); | 
 |             } | 
 |  | 
 |             if let Some(instance) = instance { | 
 |                 let kcfi_typeid = kcfi::typeid_for_instance(self.tcx, instance, options); | 
 |                 self.set_kcfi_type_metadata(llfn, kcfi_typeid); | 
 |             } else { | 
 |                 let kcfi_typeid = kcfi::typeid_for_fnabi(self.tcx, fn_abi, options); | 
 |                 self.set_kcfi_type_metadata(llfn, kcfi_typeid); | 
 |             } | 
 |         } | 
 |  | 
 |         llfn | 
 |     } | 
 |  | 
 |     /// Declare a global with an intention to define it. | 
 |     /// | 
 |     /// Use this function when you intend to define a global. This function will | 
 |     /// return `None` if the name already has a definition associated with it. In that | 
 |     /// case an error should be reported to the user, because it usually happens due | 
 |     /// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes). | 
 |     pub(crate) fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> { | 
 |         if self.get_defined_value(name).is_some() { | 
 |             None | 
 |         } else { | 
 |             Some(self.declare_global(name, ty)) | 
 |         } | 
 |     } | 
 |  | 
 |     /// Declare a private global | 
 |     /// | 
 |     /// Use this function when you intend to define a global without a name. | 
 |     pub(crate) fn define_private_global(&self, ty: &'ll Type) -> &'ll Value { | 
 |         unsafe { llvm::LLVMRustInsertPrivateGlobal(self.llmod, ty) } | 
 |     } | 
 |  | 
 |     /// Gets declared value by name. | 
 |     pub(crate) fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { | 
 |         debug!("get_declared_value(name={:?})", name); | 
 |         unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_c_char_ptr(), name.len()) } | 
 |     } | 
 |  | 
 |     /// Gets defined or externally defined (AvailableExternally linkage) value by | 
 |     /// name. | 
 |     pub(crate) fn get_defined_value(&self, name: &str) -> Option<&'ll Value> { | 
 |         self.get_declared_value(name).and_then(|val| { | 
 |             let declaration = llvm::is_declaration(val); | 
 |             if !declaration { Some(val) } else { None } | 
 |         }) | 
 |     } | 
 | } |