1use 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
31pub(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
55pub(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 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 pub(crate) fn declare_cfn(
101 &self,
102 name: &str,
103 unnamed: llvm::UnnamedAddr,
104 fn_type: &'ll Type,
105 ) -> &'ll Value {
106 declare_raw_fn(self, name, llvm::CCallConv, unnamed, Visibility::Default, fn_type)
109 }
110
111 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 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 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 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 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 pub(crate) fn define_private_global(&self, ty: &'ll Type) -> &'ll Value {
225 unsafe { llvm::LLVMRustInsertPrivateGlobal(self.llmod, ty) }
226 }
227
228 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 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}