]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::attributes; |
6a06907d | 2 | use crate::back::write::to_llvm_code_model; |
ba9703b0 | 3 | use crate::callee::get_fn; |
f035d41b | 4 | use crate::coverageinfo; |
dfeec247 | 5 | use crate::debuginfo; |
9fa01778 | 6 | use crate::llvm; |
416331ca | 7 | use crate::llvm_util; |
9fa01778 | 8 | use crate::type_::Type; |
ba9703b0 | 9 | use crate::value::Value; |
ff7c6d11 | 10 | |
6a06907d | 11 | use cstr::cstr; |
a1dfa0c6 | 12 | use rustc_codegen_ssa::base::wants_msvc_seh; |
ba9703b0 | 13 | use rustc_codegen_ssa::traits::*; |
dfeec247 | 14 | use rustc_data_structures::base_n; |
dfeec247 XL |
15 | use rustc_data_structures::fx::FxHashMap; |
16 | use rustc_data_structures::small_c_str::SmallCStr; | |
ba9703b0 XL |
17 | use rustc_middle::bug; |
18 | use rustc_middle::mir::mono::CodegenUnit; | |
19 | use rustc_middle::ty::layout::{HasParamEnv, LayoutError, TyAndLayout}; | |
20 | use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; | |
f9f354fc | 21 | use rustc_session::config::{CFGuard, CrateType, DebugInfo}; |
ba9703b0 | 22 | use rustc_session::Session; |
dfeec247 XL |
23 | use rustc_span::source_map::{Span, DUMMY_SP}; |
24 | use rustc_span::symbol::Symbol; | |
ba9703b0 | 25 | use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx}; |
f9f354fc | 26 | use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; |
ba9703b0 | 27 | |
1a4d82fc | 28 | use std::cell::{Cell, RefCell}; |
dfeec247 | 29 | use std::ffi::CStr; |
54a0048b | 30 | use std::str; |
1a4d82fc | 31 | |
2c00a5a8 | 32 | /// There is one `CodegenCx` per compilation unit. Each one has its own LLVM |
b7449926 XL |
33 | /// `llvm::Context` so that several compilation units may be optimized in parallel. |
34 | /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`. | |
dc9dc135 XL |
35 | pub struct CodegenCx<'ll, 'tcx> { |
36 | pub tcx: TyCtxt<'tcx>, | |
2c00a5a8 XL |
37 | pub check_overflow: bool, |
38 | pub use_dll_storage_attrs: bool, | |
39 | pub tls_model: llvm::ThreadLocalMode, | |
1a4d82fc | 40 | |
a1dfa0c6 XL |
41 | pub llmod: &'ll llvm::Module, |
42 | pub llcx: &'ll llvm::Context, | |
ba9703b0 | 43 | pub codegen_unit: &'tcx CodegenUnit<'tcx>, |
3b2f2976 | 44 | |
54a0048b | 45 | /// Cache instances of monomorphic and polymorphic items |
a1dfa0c6 | 46 | pub instances: RefCell<FxHashMap<Instance<'tcx>, &'ll Value>>, |
1a4d82fc | 47 | /// Cache generated vtables |
dc9dc135 XL |
48 | pub vtables: |
49 | RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>, | |
1a4d82fc | 50 | /// Cache of constant strings, |
e1599b0c | 51 | pub const_cstr_cache: RefCell<FxHashMap<Symbol, &'ll Value>>, |
1a4d82fc JJ |
52 | |
53 | /// Reverse-direction for const ptrs cast from globals. | |
f9f354fc XL |
54 | /// |
55 | /// Key is a Value holding a `*T`, | |
56 | /// Val is a Value holding a `*[T]`. | |
1a4d82fc JJ |
57 | /// |
58 | /// Needed because LLVM loses pointer->pointee association | |
94b46f34 | 59 | /// when we ptrcast, and we have to ptrcast during codegen |
f9f354fc | 60 | /// of a `[T]` const because we form a slice, a `(*T,usize)` pair, not |
85aaf69f | 61 | /// a pointer to an LLVM array type. Similar for trait objects. |
a1dfa0c6 | 62 | pub const_unsized: RefCell<FxHashMap<&'ll Value, &'ll Value>>, |
85aaf69f SL |
63 | |
64 | /// Cache of emitted const globals (value -> global) | |
a1dfa0c6 | 65 | pub const_globals: RefCell<FxHashMap<&'ll Value, &'ll Value>>, |
a7813a04 | 66 | |
c1a9b12d | 67 | /// List of globals for static variables which need to be passed to the |
94b46f34 | 68 | /// LLVM function ReplaceAllUsesWith (RAUW) when codegen is complete. |
b7449926 | 69 | /// (We have to make sure we don't invalidate any Values referring |
c1a9b12d | 70 | /// to constants.) |
a1dfa0c6 | 71 | pub statics_to_rauw: RefCell<Vec<(&'ll Value, &'ll Value)>>, |
c1a9b12d | 72 | |
cc61c64b | 73 | /// Statics that will be placed in the llvm.used variable |
9fa01778 | 74 | /// See <http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable> for details |
a1dfa0c6 | 75 | pub used_statics: RefCell<Vec<&'ll Value>>, |
cc61c64b | 76 | |
a1dfa0c6 XL |
77 | pub lltypes: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), &'ll Type>>, |
78 | pub scalar_lltypes: RefCell<FxHashMap<Ty<'tcx>, &'ll Type>>, | |
2c00a5a8 | 79 | pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>, |
a1dfa0c6 | 80 | pub isize_ty: &'ll Type, |
1a4d82fc | 81 | |
cdc7bbd5 | 82 | pub coverage_cx: Option<coverageinfo::CrateCoverageContext<'ll, 'tcx>>, |
a1dfa0c6 | 83 | pub dbg_cx: Option<debuginfo::CrateDebugContext<'ll, 'tcx>>, |
1a4d82fc | 84 | |
a1dfa0c6 | 85 | eh_personality: Cell<Option<&'ll Value>>, |
1b1a35ee | 86 | eh_catch_typeinfo: Cell<Option<&'ll Value>>, |
a1dfa0c6 | 87 | pub rust_try_fn: Cell<Option<&'ll Value>>, |
1a4d82fc | 88 | |
a1dfa0c6 | 89 | intrinsics: RefCell<FxHashMap<&'static str, &'ll Value>>, |
1a4d82fc | 90 | |
c30ab7b3 SL |
91 | /// A counter that is used for generating local symbol names |
92 | local_gen_sym_counter: Cell<usize>, | |
ea8adc8c XL |
93 | } |
94 | ||
f9f354fc XL |
95 | fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode { |
96 | match tls_model { | |
97 | TlsModel::GeneralDynamic => llvm::ThreadLocalMode::GeneralDynamic, | |
98 | TlsModel::LocalDynamic => llvm::ThreadLocalMode::LocalDynamic, | |
99 | TlsModel::InitialExec => llvm::ThreadLocalMode::InitialExec, | |
100 | TlsModel::LocalExec => llvm::ThreadLocalMode::LocalExec, | |
abe05a73 XL |
101 | } |
102 | } | |
103 | ||
6a06907d XL |
104 | fn strip_powerpc64_vectors(data_layout: String) -> String { |
105 | data_layout.replace("-v256:256:256-v512:512:512", "") | |
106 | } | |
107 | ||
b7449926 | 108 | pub unsafe fn create_module( |
dc9dc135 | 109 | tcx: TyCtxt<'_>, |
b7449926 XL |
110 | llcx: &'ll llvm::Context, |
111 | mod_name: &str, | |
112 | ) -> &'ll llvm::Module { | |
9fa01778 | 113 | let sess = tcx.sess; |
b7449926 | 114 | let mod_name = SmallCStr::new(mod_name); |
1a4d82fc JJ |
115 | let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); |
116 | ||
29967ef6 | 117 | let mut target_data_layout = sess.target.data_layout.clone(); |
6a06907d XL |
118 | if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" { |
119 | target_data_layout = strip_powerpc64_vectors(target_data_layout); | |
120 | } | |
416331ca | 121 | |
54a0048b | 122 | // Ensure the data-layout values hardcoded remain the defaults. |
29967ef6 | 123 | if sess.target.is_builtin { |
f9f354fc | 124 | let tm = crate::back::write::create_informational_target_machine(tcx.sess); |
c1a9b12d SL |
125 | llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm); |
126 | llvm::LLVMRustDisposeTargetMachine(tm); | |
54a0048b | 127 | |
ba9703b0 | 128 | let llvm_data_layout = llvm::LLVMGetDataLayoutStr(llmod); |
416331ca | 129 | let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes()) |
dfeec247 | 130 | .expect("got a non-UTF8 data-layout from LLVM"); |
54a0048b | 131 | |
5bcae85e SL |
132 | // Unfortunately LLVM target specs change over time, and right now we |
133 | // don't have proper support to work with any more than one | |
134 | // `data_layout` than the one that is in the rust-lang/rust repo. If | |
135 | // this compiler is configured against a custom LLVM, we may have a | |
136 | // differing data layout, even though we should update our own to use | |
137 | // that one. | |
138 | // | |
139 | // As an interim hack, if CFG_LLVM_ROOT is not an empty string then we | |
140 | // disable this check entirely as we may be configured with something | |
141 | // that has a different target layout. | |
142 | // | |
143 | // Unsure if this will actually cause breakage when rustc is configured | |
144 | // as such. | |
145 | // | |
146 | // FIXME(#34960) | |
147 | let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); | |
148 | let custom_llvm_used = cfg_llvm_root.trim() != ""; | |
149 | ||
416331ca | 150 | if !custom_llvm_used && target_data_layout != llvm_data_layout { |
dfeec247 XL |
151 | bug!( |
152 | "data-layout for builtin `{}` target, `{}`, \ | |
54a0048b | 153 | differs from LLVM default, `{}`", |
29967ef6 | 154 | sess.target.llvm_target, |
dfeec247 XL |
155 | target_data_layout, |
156 | llvm_data_layout | |
157 | ); | |
54a0048b | 158 | } |
c1a9b12d | 159 | } |
1a4d82fc | 160 | |
416331ca | 161 | let data_layout = SmallCStr::new(&target_data_layout); |
54a0048b SL |
162 | llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); |
163 | ||
29967ef6 | 164 | let llvm_target = SmallCStr::new(&sess.target.llvm_target); |
1a4d82fc | 165 | llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); |
5bcae85e | 166 | |
f9f354fc | 167 | if sess.relocation_model() == RelocModel::Pic { |
60c5eb7d | 168 | llvm::LLVMRustSetModulePICLevel(llmod); |
f9f354fc XL |
169 | // PIE is potentially more effective than PIC, but can only be used in executables. |
170 | // If all our outputs are executables, then we can relax PIC to PIE. | |
171 | if sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) { | |
172 | llvm::LLVMRustSetModulePIELevel(llmod); | |
173 | } | |
5bcae85e SL |
174 | } |
175 | ||
6a06907d XL |
176 | // Linking object files with different code models is undefined behavior |
177 | // because the compiler would have to generate additional code (to span | |
178 | // longer jumps) if a larger code model is used with a smaller one. | |
179 | // | |
180 | // See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323. | |
181 | llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model())); | |
182 | ||
0bf4aa26 XL |
183 | // If skipping the PLT is enabled, we need to add some module metadata |
184 | // to ensure intrinsic calls don't use it. | |
185 | if !sess.needs_plt() { | |
e74abb32 | 186 | let avoid_plt = "RtLibUseGOT\0".as_ptr().cast(); |
0bf4aa26 XL |
187 | llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1); |
188 | } | |
189 | ||
f035d41b | 190 | // Control Flow Guard is currently only supported by the MSVC linker on Windows. |
29967ef6 | 191 | if sess.target.is_like_msvc { |
3dfed10e | 192 | match sess.opts.cg.control_flow_guard { |
f035d41b XL |
193 | CFGuard::Disabled => {} |
194 | CFGuard::NoChecks => { | |
195 | // Set `cfguard=1` module flag to emit metadata only. | |
196 | llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 1) | |
197 | } | |
198 | CFGuard::Checks => { | |
199 | // Set `cfguard=2` module flag to emit metadata and checks. | |
200 | llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 2) | |
201 | } | |
74b04a01 | 202 | } |
74b04a01 XL |
203 | } |
204 | ||
b7449926 | 205 | llmod |
1a4d82fc JJ |
206 | } |
207 | ||
a1dfa0c6 | 208 | impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { |
dc9dc135 XL |
209 | crate fn new( |
210 | tcx: TyCtxt<'tcx>, | |
ba9703b0 | 211 | codegen_unit: &'tcx CodegenUnit<'tcx>, |
dc9dc135 XL |
212 | llvm_module: &'ll crate::ModuleLlvm, |
213 | ) -> Self { | |
62682a34 SL |
214 | // An interesting part of Windows which MSVC forces our hand on (and |
215 | // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` | |
216 | // attributes in LLVM IR as well as native dependencies (in C these | |
217 | // correspond to `__declspec(dllimport)`). | |
218 | // | |
3dfed10e XL |
219 | // LD (BFD) in MinGW mode can often correctly guess `dllexport` but |
220 | // relying on that can result in issues like #50176. | |
221 | // LLD won't support that and expects symbols with proper attributes. | |
222 | // Because of that we make MinGW target emit dllexport just like MSVC. | |
223 | // When it comes to dllimport we use it for constants but for functions | |
224 | // rely on the linker to do the right thing. Opposed to dllexport this | |
225 | // task is easy for them (both LD and LLD) and allows us to easily use | |
226 | // symbols from static libraries in shared libraries. | |
227 | // | |
228 | // Whenever a dynamic library is built on Windows it must have its public | |
62682a34 SL |
229 | // interface specified by functions tagged with `dllexport` or otherwise |
230 | // they're not available to be linked against. This poses a few problems | |
231 | // for the compiler, some of which are somewhat fundamental, but we use | |
232 | // the `use_dll_storage_attrs` variable below to attach the `dllexport` | |
0731742a | 233 | // attribute to all LLVM functions that are exported e.g., they're |
62682a34 SL |
234 | // already tagged with external linkage). This is suboptimal for a few |
235 | // reasons: | |
236 | // | |
237 | // * If an object file will never be included in a dynamic library, | |
238 | // there's no need to attach the dllexport attribute. Most object | |
239 | // files in Rust are not destined to become part of a dll as binaries | |
240 | // are statically linked by default. | |
241 | // * If the compiler is emitting both an rlib and a dylib, the same | |
242 | // source object file is currently used but with MSVC this may be less | |
243 | // feasible. The compiler may be able to get around this, but it may | |
244 | // involve some invasive changes to deal with this. | |
245 | // | |
246 | // The flipside of this situation is that whenever you link to a dll and | |
247 | // you import a function from it, the import should be tagged with | |
248 | // `dllimport`. At this time, however, the compiler does not emit | |
249 | // `dllimport` for any declarations other than constants (where it is | |
250 | // required), which is again suboptimal for even more reasons! | |
251 | // | |
252 | // * Calling a function imported from another dll without using | |
253 | // `dllimport` causes the linker/compiler to have extra overhead (one | |
254 | // `jmp` instruction on x86) when calling the function. | |
255 | // * The same object file may be used in different circumstances, so a | |
256 | // function may be imported from a dll if the object is linked into a | |
257 | // dll, but it may be just linked against if linked into an rlib. | |
258 | // * The compiler has no knowledge about whether native functions should | |
259 | // be tagged dllimport or not. | |
260 | // | |
261 | // For now the compiler takes the perf hit (I do not have any numbers to | |
262 | // this effect) by marking very little as `dllimport` and praying the | |
263 | // linker will take care of everything. Fixing this problem will likely | |
264 | // require adding a few attributes to Rust itself (feature gated at the | |
3dfed10e | 265 | // start) and then strongly recommending static linkage on Windows! |
29967ef6 | 266 | let use_dll_storage_attrs = tcx.sess.target.is_like_windows; |
62682a34 | 267 | |
ea8adc8c XL |
268 | let check_overflow = tcx.sess.overflow_checks(); |
269 | ||
f9f354fc | 270 | let tls_model = to_llvm_tls_model(tcx.sess.tls_model()); |
abe05a73 | 271 | |
b7449926 | 272 | let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod()); |
cc61c64b | 273 | |
cdc7bbd5 | 274 | let coverage_cx = if tcx.sess.instrument_coverage() { |
f035d41b XL |
275 | let covctx = coverageinfo::CrateCoverageContext::new(); |
276 | Some(covctx) | |
277 | } else { | |
278 | None | |
279 | }; | |
280 | ||
b7449926 XL |
281 | let dbg_cx = if tcx.sess.opts.debuginfo != DebugInfo::None { |
282 | let dctx = debuginfo::CrateDebugContext::new(llmod); | |
dfeec247 | 283 | debuginfo::metadata::compile_unit_metadata(tcx, &codegen_unit.name().as_str(), &dctx); |
b7449926 XL |
284 | Some(dctx) |
285 | } else { | |
286 | None | |
287 | }; | |
288 | ||
289 | let isize_ty = Type::ix_llcx(llcx, tcx.data_layout.pointer_size.bits()); | |
290 | ||
291 | CodegenCx { | |
292 | tcx, | |
293 | check_overflow, | |
294 | use_dll_storage_attrs, | |
295 | tls_model, | |
296 | llmod, | |
297 | llcx, | |
b7449926 | 298 | codegen_unit, |
0bf4aa26 XL |
299 | instances: Default::default(), |
300 | vtables: Default::default(), | |
301 | const_cstr_cache: Default::default(), | |
302 | const_unsized: Default::default(), | |
303 | const_globals: Default::default(), | |
b7449926 XL |
304 | statics_to_rauw: RefCell::new(Vec::new()), |
305 | used_statics: RefCell::new(Vec::new()), | |
0bf4aa26 XL |
306 | lltypes: Default::default(), |
307 | scalar_lltypes: Default::default(), | |
308 | pointee_infos: Default::default(), | |
b7449926 | 309 | isize_ty, |
f035d41b | 310 | coverage_cx, |
b7449926 XL |
311 | dbg_cx, |
312 | eh_personality: Cell::new(None), | |
1b1a35ee | 313 | eh_catch_typeinfo: Cell::new(None), |
b7449926 | 314 | rust_try_fn: Cell::new(None), |
0bf4aa26 | 315 | intrinsics: Default::default(), |
b7449926 XL |
316 | local_gen_sym_counter: Cell::new(0), |
317 | } | |
cc61c64b | 318 | } |
a1dfa0c6 XL |
319 | |
320 | crate fn statics_to_rauw(&self) -> &RefCell<Vec<(&'ll Value, &'ll Value)>> { | |
321 | &self.statics_to_rauw | |
322 | } | |
f035d41b XL |
323 | |
324 | #[inline] | |
cdc7bbd5 | 325 | pub fn coverage_context(&'a self) -> Option<&'a coverageinfo::CrateCoverageContext<'ll, 'tcx>> { |
29967ef6 | 326 | self.coverage_cx.as_ref() |
f035d41b | 327 | } |
1a4d82fc JJ |
328 | } |
329 | ||
a1dfa0c6 | 330 | impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { |
dfeec247 XL |
331 | fn vtables( |
332 | &self, | |
333 | ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>> | |
a1dfa0c6 XL |
334 | { |
335 | &self.vtables | |
1a4d82fc JJ |
336 | } |
337 | ||
e74abb32 XL |
338 | fn get_fn(&self, instance: Instance<'tcx>) -> &'ll Value { |
339 | get_fn(self, instance) | |
a1dfa0c6 | 340 | } |
0bf4aa26 | 341 | |
e74abb32 | 342 | fn get_fn_addr(&self, instance: Instance<'tcx>) -> &'ll Value { |
a1dfa0c6 | 343 | get_fn(self, instance) |
1a4d82fc JJ |
344 | } |
345 | ||
a1dfa0c6 | 346 | fn eh_personality(&self) -> &'ll Value { |
32a655c1 SL |
347 | // The exception handling personality function. |
348 | // | |
349 | // If our compilation unit has the `eh_personality` lang item somewhere | |
94b46f34 | 350 | // within it, then we just need to codegen that. Otherwise, we're |
32a655c1 SL |
351 | // building an rlib which will depend on some upstream implementation of |
352 | // this function, so we just codegen a generic reference to it. We don't | |
353 | // specify any of the types for the function, we just make it a symbol | |
354 | // that LLVM can later use. | |
355 | // | |
356 | // Note that MSVC is a little special here in that we don't use the | |
357 | // `eh_personality` lang item at all. Currently LLVM has support for | |
358 | // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the | |
359 | // *name of the personality function* to decide what kind of unwind side | |
360 | // tables/landing pads to emit. It looks like Dwarf is used by default, | |
361 | // injecting a dependency on the `_Unwind_Resume` symbol for resuming | |
362 | // an "exception", but for MSVC we want to force SEH. This means that we | |
363 | // can't actually have the personality function be our standard | |
364 | // `rust_eh_personality` function, but rather we wired it up to the | |
365 | // CRT's custom personality function, which forces LLVM to consider | |
366 | // landing pads as "landing pads for SEH". | |
2c00a5a8 | 367 | if let Some(llpersonality) = self.eh_personality.get() { |
dfeec247 | 368 | return llpersonality; |
32a655c1 | 369 | } |
2c00a5a8 | 370 | let tcx = self.tcx; |
ea8adc8c | 371 | let llfn = match tcx.lang_items().eh_personality() { |
dfeec247 XL |
372 | Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr( |
373 | ty::Instance::resolve( | |
374 | tcx, | |
375 | ty::ParamEnv::reveal_all(), | |
376 | def_id, | |
377 | tcx.intern_substs(&[]), | |
e74abb32 | 378 | ) |
f9f354fc | 379 | .unwrap() |
dfeec247 XL |
380 | .unwrap(), |
381 | ), | |
32a655c1 | 382 | _ => { |
a1dfa0c6 | 383 | let name = if wants_msvc_seh(self.sess()) { |
32a655c1 SL |
384 | "__CxxFrameHandler3" |
385 | } else { | |
386 | "rust_eh_personality" | |
387 | }; | |
a1dfa0c6 | 388 | let fty = self.type_variadic_func(&[], self.type_i32()); |
6a06907d | 389 | self.declare_cfn(name, llvm::UnnamedAddr::Global, fty) |
32a655c1 SL |
390 | } |
391 | }; | |
b7449926 | 392 | attributes::apply_target_cpu_attr(self, llfn); |
2c00a5a8 | 393 | self.eh_personality.set(Some(llfn)); |
32a655c1 SL |
394 | llfn |
395 | } | |
396 | ||
a1dfa0c6 XL |
397 | fn sess(&self) -> &Session { |
398 | &self.tcx.sess | |
399 | } | |
400 | ||
401 | fn check_overflow(&self) -> bool { | |
402 | self.check_overflow | |
403 | } | |
404 | ||
ba9703b0 XL |
405 | fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { |
406 | self.codegen_unit | |
a1dfa0c6 XL |
407 | } |
408 | ||
409 | fn used_statics(&self) -> &RefCell<Vec<&'ll Value>> { | |
410 | &self.used_statics | |
411 | } | |
412 | ||
413 | fn set_frame_pointer_elimination(&self, llfn: &'ll Value) { | |
414 | attributes::set_frame_pointer_elimination(self, llfn) | |
415 | } | |
416 | ||
417 | fn apply_target_cpu_attr(&self, llfn: &'ll Value) { | |
29967ef6 XL |
418 | attributes::apply_target_cpu_attr(self, llfn); |
419 | attributes::apply_tune_cpu_attr(self, llfn); | |
a1dfa0c6 XL |
420 | } |
421 | ||
a1dfa0c6 | 422 | fn create_used_variable(&self) { |
6a06907d XL |
423 | let name = cstr!("llvm.used"); |
424 | let section = cstr!("llvm.metadata"); | |
dfeec247 XL |
425 | let array = |
426 | self.const_array(&self.type_ptr_to(self.type_i8()), &*self.used_statics.borrow()); | |
a1dfa0c6 XL |
427 | |
428 | unsafe { | |
dfeec247 | 429 | let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr()); |
a1dfa0c6 XL |
430 | llvm::LLVMSetInitializer(g, array); |
431 | llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); | |
432 | llvm::LLVMSetSection(g, section.as_ptr()); | |
433 | } | |
2c00a5a8 | 434 | } |
1b1a35ee XL |
435 | |
436 | fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> { | |
437 | if self.get_declared_value("main").is_none() { | |
6a06907d | 438 | Some(self.declare_cfn("main", llvm::UnnamedAddr::Global, fn_type)) |
1b1a35ee XL |
439 | } else { |
440 | // If the symbol already exists, it is an error: for example, the user wrote | |
441 | // #[no_mangle] extern "C" fn main(..) {..} | |
442 | // instead of #[start] | |
443 | None | |
444 | } | |
445 | } | |
a1dfa0c6 XL |
446 | } |
447 | ||
448 | impl CodegenCx<'b, 'tcx> { | |
449 | crate fn get_intrinsic(&self, key: &str) -> &'b Value { | |
450 | if let Some(v) = self.intrinsics.borrow().get(key).cloned() { | |
451 | return v; | |
452 | } | |
2c00a5a8 | 453 | |
a1dfa0c6 | 454 | self.declare_intrinsic(key).unwrap_or_else(|| bug!("unknown intrinsic '{}'", key)) |
2c00a5a8 XL |
455 | } |
456 | ||
9fa01778 | 457 | fn insert_intrinsic( |
dfeec247 XL |
458 | &self, |
459 | name: &'static str, | |
460 | args: Option<&[&'b llvm::Type]>, | |
461 | ret: &'b llvm::Type, | |
9fa01778 XL |
462 | ) -> &'b llvm::Value { |
463 | let fn_ty = if let Some(args) = args { | |
464 | self.type_func(args, ret) | |
465 | } else { | |
466 | self.type_variadic_func(&[], ret) | |
467 | }; | |
6a06907d | 468 | let f = self.declare_cfn(name, llvm::UnnamedAddr::No, fn_ty); |
dc9dc135 | 469 | self.intrinsics.borrow_mut().insert(name, f); |
9fa01778 XL |
470 | f |
471 | } | |
472 | ||
dfeec247 | 473 | fn declare_intrinsic(&self, key: &str) -> Option<&'b Value> { |
a1dfa0c6 XL |
474 | macro_rules! ifn { |
475 | ($name:expr, fn() -> $ret:expr) => ( | |
476 | if key == $name { | |
9fa01778 | 477 | return Some(self.insert_intrinsic($name, Some(&[]), $ret)); |
a1dfa0c6 XL |
478 | } |
479 | ); | |
480 | ($name:expr, fn(...) -> $ret:expr) => ( | |
481 | if key == $name { | |
9fa01778 | 482 | return Some(self.insert_intrinsic($name, None, $ret)); |
a1dfa0c6 XL |
483 | } |
484 | ); | |
485 | ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( | |
486 | if key == $name { | |
9fa01778 | 487 | return Some(self.insert_intrinsic($name, Some(&[$($arg),*]), $ret)); |
a1dfa0c6 XL |
488 | } |
489 | ); | |
490 | } | |
491 | macro_rules! mk_struct { | |
492 | ($($field_ty:expr),*) => (self.type_struct( &[$($field_ty),*], false)) | |
2c00a5a8 XL |
493 | } |
494 | ||
a1dfa0c6 XL |
495 | let i8p = self.type_i8p(); |
496 | let void = self.type_void(); | |
497 | let i1 = self.type_i1(); | |
498 | let t_i8 = self.type_i8(); | |
499 | let t_i16 = self.type_i16(); | |
500 | let t_i32 = self.type_i32(); | |
501 | let t_i64 = self.type_i64(); | |
502 | let t_i128 = self.type_i128(); | |
503 | let t_f32 = self.type_f32(); | |
504 | let t_f64 = self.type_f64(); | |
505 | ||
3dfed10e XL |
506 | ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32); |
507 | ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32); | |
508 | ifn!("llvm.wasm.trunc.unsigned.i64.f32", fn(t_f32) -> t_i64); | |
509 | ifn!("llvm.wasm.trunc.unsigned.i64.f64", fn(t_f64) -> t_i64); | |
510 | ifn!("llvm.wasm.trunc.signed.i32.f32", fn(t_f32) -> t_i32); | |
511 | ifn!("llvm.wasm.trunc.signed.i32.f64", fn(t_f64) -> t_i32); | |
512 | ifn!("llvm.wasm.trunc.signed.i64.f32", fn(t_f32) -> t_i64); | |
513 | ifn!("llvm.wasm.trunc.signed.i64.f64", fn(t_f64) -> t_i64); | |
f035d41b | 514 | |
cdc7bbd5 XL |
515 | ifn!("llvm.fptosi.sat.i8.f32", fn(t_f32) -> t_i8); |
516 | ifn!("llvm.fptosi.sat.i16.f32", fn(t_f32) -> t_i16); | |
517 | ifn!("llvm.fptosi.sat.i32.f32", fn(t_f32) -> t_i32); | |
518 | ifn!("llvm.fptosi.sat.i64.f32", fn(t_f32) -> t_i64); | |
519 | ifn!("llvm.fptosi.sat.i128.f32", fn(t_f32) -> t_i128); | |
520 | ifn!("llvm.fptosi.sat.i8.f64", fn(t_f64) -> t_i8); | |
521 | ifn!("llvm.fptosi.sat.i16.f64", fn(t_f64) -> t_i16); | |
522 | ifn!("llvm.fptosi.sat.i32.f64", fn(t_f64) -> t_i32); | |
523 | ifn!("llvm.fptosi.sat.i64.f64", fn(t_f64) -> t_i64); | |
524 | ifn!("llvm.fptosi.sat.i128.f64", fn(t_f64) -> t_i128); | |
525 | ||
526 | ifn!("llvm.fptoui.sat.i8.f32", fn(t_f32) -> t_i8); | |
527 | ifn!("llvm.fptoui.sat.i16.f32", fn(t_f32) -> t_i16); | |
528 | ifn!("llvm.fptoui.sat.i32.f32", fn(t_f32) -> t_i32); | |
529 | ifn!("llvm.fptoui.sat.i64.f32", fn(t_f32) -> t_i64); | |
530 | ifn!("llvm.fptoui.sat.i128.f32", fn(t_f32) -> t_i128); | |
531 | ifn!("llvm.fptoui.sat.i8.f64", fn(t_f64) -> t_i8); | |
532 | ifn!("llvm.fptoui.sat.i16.f64", fn(t_f64) -> t_i16); | |
533 | ifn!("llvm.fptoui.sat.i32.f64", fn(t_f64) -> t_i32); | |
534 | ifn!("llvm.fptoui.sat.i64.f64", fn(t_f64) -> t_i64); | |
535 | ifn!("llvm.fptoui.sat.i128.f64", fn(t_f64) -> t_i128); | |
536 | ||
a1dfa0c6 XL |
537 | ifn!("llvm.trap", fn() -> void); |
538 | ifn!("llvm.debugtrap", fn() -> void); | |
539 | ifn!("llvm.frameaddress", fn(t_i32) -> i8p); | |
e74abb32 | 540 | ifn!("llvm.sideeffect", fn() -> void); |
a1dfa0c6 XL |
541 | |
542 | ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); | |
a1dfa0c6 | 543 | ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); |
a1dfa0c6 XL |
544 | |
545 | ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32); | |
a1dfa0c6 | 546 | ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64); |
a1dfa0c6 XL |
547 | |
548 | ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32); | |
a1dfa0c6 | 549 | ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 XL |
550 | |
551 | ifn!("llvm.sin.f32", fn(t_f32) -> t_f32); | |
a1dfa0c6 | 552 | ifn!("llvm.sin.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 XL |
553 | |
554 | ifn!("llvm.cos.f32", fn(t_f32) -> t_f32); | |
a1dfa0c6 | 555 | ifn!("llvm.cos.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 XL |
556 | |
557 | ifn!("llvm.exp.f32", fn(t_f32) -> t_f32); | |
a1dfa0c6 | 558 | ifn!("llvm.exp.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 XL |
559 | |
560 | ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32); | |
a1dfa0c6 | 561 | ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 XL |
562 | |
563 | ifn!("llvm.log.f32", fn(t_f32) -> t_f32); | |
a1dfa0c6 | 564 | ifn!("llvm.log.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 XL |
565 | |
566 | ifn!("llvm.log10.f32", fn(t_f32) -> t_f32); | |
a1dfa0c6 | 567 | ifn!("llvm.log10.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 XL |
568 | |
569 | ifn!("llvm.log2.f32", fn(t_f32) -> t_f32); | |
a1dfa0c6 | 570 | ifn!("llvm.log2.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 XL |
571 | |
572 | ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32); | |
a1dfa0c6 | 573 | ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64); |
a1dfa0c6 XL |
574 | |
575 | ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32); | |
a1dfa0c6 | 576 | ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 | 577 | |
dc9dc135 XL |
578 | ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32); |
579 | ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64); | |
580 | ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32); | |
581 | ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64); | |
582 | ||
a1dfa0c6 | 583 | ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); |
a1dfa0c6 | 584 | ifn!("llvm.floor.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 XL |
585 | |
586 | ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32); | |
a1dfa0c6 | 587 | ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64); |
a1dfa0c6 XL |
588 | |
589 | ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32); | |
590 | ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64); | |
591 | ||
592 | ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32); | |
593 | ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64); | |
594 | ifn!("llvm.round.f32", fn(t_f32) -> t_f32); | |
595 | ifn!("llvm.round.f64", fn(t_f64) -> t_f64); | |
596 | ||
597 | ifn!("llvm.rint.f32", fn(t_f32) -> t_f32); | |
598 | ifn!("llvm.rint.f64", fn(t_f64) -> t_f64); | |
599 | ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32); | |
600 | ifn!("llvm.nearbyint.f64", fn(t_f64) -> t_f64); | |
601 | ||
602 | ifn!("llvm.ctpop.i8", fn(t_i8) -> t_i8); | |
603 | ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16); | |
604 | ifn!("llvm.ctpop.i32", fn(t_i32) -> t_i32); | |
605 | ifn!("llvm.ctpop.i64", fn(t_i64) -> t_i64); | |
606 | ifn!("llvm.ctpop.i128", fn(t_i128) -> t_i128); | |
607 | ||
dfeec247 | 608 | ifn!("llvm.ctlz.i8", fn(t_i8, i1) -> t_i8); |
a1dfa0c6 XL |
609 | ifn!("llvm.ctlz.i16", fn(t_i16, i1) -> t_i16); |
610 | ifn!("llvm.ctlz.i32", fn(t_i32, i1) -> t_i32); | |
611 | ifn!("llvm.ctlz.i64", fn(t_i64, i1) -> t_i64); | |
612 | ifn!("llvm.ctlz.i128", fn(t_i128, i1) -> t_i128); | |
613 | ||
dfeec247 | 614 | ifn!("llvm.cttz.i8", fn(t_i8, i1) -> t_i8); |
a1dfa0c6 XL |
615 | ifn!("llvm.cttz.i16", fn(t_i16, i1) -> t_i16); |
616 | ifn!("llvm.cttz.i32", fn(t_i32, i1) -> t_i32); | |
617 | ifn!("llvm.cttz.i64", fn(t_i64, i1) -> t_i64); | |
618 | ifn!("llvm.cttz.i128", fn(t_i128, i1) -> t_i128); | |
619 | ||
620 | ifn!("llvm.bswap.i16", fn(t_i16) -> t_i16); | |
621 | ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32); | |
622 | ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); | |
623 | ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128); | |
624 | ||
625 | ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8); | |
626 | ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16); | |
627 | ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32); | |
628 | ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64); | |
629 | ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128); | |
630 | ||
631 | ifn!("llvm.fshl.i8", fn(t_i8, t_i8, t_i8) -> t_i8); | |
632 | ifn!("llvm.fshl.i16", fn(t_i16, t_i16, t_i16) -> t_i16); | |
633 | ifn!("llvm.fshl.i32", fn(t_i32, t_i32, t_i32) -> t_i32); | |
634 | ifn!("llvm.fshl.i64", fn(t_i64, t_i64, t_i64) -> t_i64); | |
635 | ifn!("llvm.fshl.i128", fn(t_i128, t_i128, t_i128) -> t_i128); | |
636 | ||
637 | ifn!("llvm.fshr.i8", fn(t_i8, t_i8, t_i8) -> t_i8); | |
638 | ifn!("llvm.fshr.i16", fn(t_i16, t_i16, t_i16) -> t_i16); | |
639 | ifn!("llvm.fshr.i32", fn(t_i32, t_i32, t_i32) -> t_i32); | |
640 | ifn!("llvm.fshr.i64", fn(t_i64, t_i64, t_i64) -> t_i64); | |
641 | ifn!("llvm.fshr.i128", fn(t_i128, t_i128, t_i128) -> t_i128); | |
642 | ||
dfeec247 XL |
643 | ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); |
644 | ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); | |
645 | ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); | |
646 | ifn!("llvm.sadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); | |
647 | ifn!("llvm.sadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); | |
648 | ||
649 | ifn!("llvm.uadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); | |
650 | ifn!("llvm.uadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); | |
651 | ifn!("llvm.uadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); | |
652 | ifn!("llvm.uadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); | |
653 | ifn!("llvm.uadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); | |
654 | ||
655 | ifn!("llvm.ssub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); | |
656 | ifn!("llvm.ssub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); | |
657 | ifn!("llvm.ssub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); | |
658 | ifn!("llvm.ssub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); | |
659 | ifn!("llvm.ssub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); | |
660 | ||
661 | ifn!("llvm.usub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); | |
662 | ifn!("llvm.usub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); | |
663 | ifn!("llvm.usub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); | |
664 | ifn!("llvm.usub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); | |
665 | ifn!("llvm.usub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); | |
666 | ||
667 | ifn!("llvm.smul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); | |
668 | ifn!("llvm.smul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); | |
669 | ifn!("llvm.smul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); | |
670 | ifn!("llvm.smul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); | |
671 | ifn!("llvm.smul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); | |
672 | ||
673 | ifn!("llvm.umul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1}); | |
674 | ifn!("llvm.umul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1}); | |
675 | ifn!("llvm.umul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1}); | |
676 | ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1}); | |
677 | ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1}); | |
a1dfa0c6 | 678 | |
9fa01778 XL |
679 | ifn!("llvm.sadd.sat.i8", fn(t_i8, t_i8) -> t_i8); |
680 | ifn!("llvm.sadd.sat.i16", fn(t_i16, t_i16) -> t_i16); | |
681 | ifn!("llvm.sadd.sat.i32", fn(t_i32, t_i32) -> t_i32); | |
682 | ifn!("llvm.sadd.sat.i64", fn(t_i64, t_i64) -> t_i64); | |
683 | ifn!("llvm.sadd.sat.i128", fn(t_i128, t_i128) -> t_i128); | |
684 | ||
685 | ifn!("llvm.uadd.sat.i8", fn(t_i8, t_i8) -> t_i8); | |
686 | ifn!("llvm.uadd.sat.i16", fn(t_i16, t_i16) -> t_i16); | |
687 | ifn!("llvm.uadd.sat.i32", fn(t_i32, t_i32) -> t_i32); | |
688 | ifn!("llvm.uadd.sat.i64", fn(t_i64, t_i64) -> t_i64); | |
689 | ifn!("llvm.uadd.sat.i128", fn(t_i128, t_i128) -> t_i128); | |
690 | ||
691 | ifn!("llvm.ssub.sat.i8", fn(t_i8, t_i8) -> t_i8); | |
692 | ifn!("llvm.ssub.sat.i16", fn(t_i16, t_i16) -> t_i16); | |
693 | ifn!("llvm.ssub.sat.i32", fn(t_i32, t_i32) -> t_i32); | |
694 | ifn!("llvm.ssub.sat.i64", fn(t_i64, t_i64) -> t_i64); | |
695 | ifn!("llvm.ssub.sat.i128", fn(t_i128, t_i128) -> t_i128); | |
696 | ||
697 | ifn!("llvm.usub.sat.i8", fn(t_i8, t_i8) -> t_i8); | |
698 | ifn!("llvm.usub.sat.i16", fn(t_i16, t_i16) -> t_i16); | |
699 | ifn!("llvm.usub.sat.i32", fn(t_i32, t_i32) -> t_i32); | |
700 | ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64); | |
701 | ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128); | |
702 | ||
74b04a01 XL |
703 | ifn!("llvm.lifetime.start.p0i8", fn(t_i64, i8p) -> void); |
704 | ifn!("llvm.lifetime.end.p0i8", fn(t_i64, i8p) -> void); | |
a1dfa0c6 XL |
705 | |
706 | ifn!("llvm.expect.i1", fn(i1, i1) -> i1); | |
707 | ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32); | |
708 | ifn!("llvm.localescape", fn(...) -> void); | |
709 | ifn!("llvm.localrecover", fn(i8p, i8p, t_i32) -> i8p); | |
710 | ifn!("llvm.x86.seh.recoverfp", fn(i8p, i8p) -> i8p); | |
711 | ||
712 | ifn!("llvm.assume", fn(i1) -> void); | |
713 | ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void); | |
714 | ||
715 | // variadic intrinsics | |
716 | ifn!("llvm.va_start", fn(i8p) -> void); | |
717 | ifn!("llvm.va_end", fn(i8p) -> void); | |
718 | ifn!("llvm.va_copy", fn(i8p, i8p) -> void); | |
719 | ||
cdc7bbd5 | 720 | if self.sess().instrument_coverage() { |
f035d41b XL |
721 | ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void); |
722 | } | |
723 | ||
a1dfa0c6 XL |
724 | if self.sess().opts.debuginfo != DebugInfo::None { |
725 | ifn!("llvm.dbg.declare", fn(self.type_metadata(), self.type_metadata()) -> void); | |
726 | ifn!("llvm.dbg.value", fn(self.type_metadata(), t_i64, self.type_metadata()) -> void); | |
2c00a5a8 | 727 | } |
ba9703b0 | 728 | None |
a1dfa0c6 | 729 | } |
1b1a35ee XL |
730 | |
731 | crate fn eh_catch_typeinfo(&self) -> &'b Value { | |
732 | if let Some(eh_catch_typeinfo) = self.eh_catch_typeinfo.get() { | |
733 | return eh_catch_typeinfo; | |
734 | } | |
735 | let tcx = self.tcx; | |
29967ef6 | 736 | assert!(self.sess().target.is_like_emscripten); |
1b1a35ee XL |
737 | let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() { |
738 | Some(def_id) => self.get_static(def_id), | |
739 | _ => { | |
740 | let ty = self | |
741 | .type_struct(&[self.type_ptr_to(self.type_isize()), self.type_i8p()], false); | |
742 | self.declare_global("rust_eh_catch_typeinfo", ty) | |
743 | } | |
744 | }; | |
745 | let eh_catch_typeinfo = self.const_bitcast(eh_catch_typeinfo, self.type_i8p()); | |
746 | self.eh_catch_typeinfo.set(Some(eh_catch_typeinfo)); | |
747 | eh_catch_typeinfo | |
748 | } | |
a1dfa0c6 XL |
749 | } |
750 | ||
751 | impl<'b, 'tcx> CodegenCx<'b, 'tcx> { | |
9fa01778 | 752 | /// Generates a new symbol name with the given prefix. This symbol name must |
a1dfa0c6 XL |
753 | /// only be used for definitions with `internal` or `private` linkage. |
754 | pub fn generate_local_symbol_name(&self, prefix: &str) -> String { | |
755 | let idx = self.local_gen_sym_counter.get(); | |
756 | self.local_gen_sym_counter.set(idx + 1); | |
757 | // Include a '.' character, so there can be no accidental conflicts with | |
758 | // user defined names | |
759 | let mut name = String::with_capacity(prefix.len() + 6); | |
760 | name.push_str(prefix); | |
29967ef6 | 761 | name.push('.'); |
a1dfa0c6 XL |
762 | base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name); |
763 | name | |
ff7c6d11 XL |
764 | } |
765 | } | |
766 | ||
ba9703b0 XL |
767 | impl HasDataLayout for CodegenCx<'ll, 'tcx> { |
768 | fn data_layout(&self) -> &TargetDataLayout { | |
2c00a5a8 | 769 | &self.tcx.data_layout |
cc61c64b XL |
770 | } |
771 | } | |
772 | ||
a1dfa0c6 | 773 | impl HasTargetSpec for CodegenCx<'ll, 'tcx> { |
83c7162d | 774 | fn target_spec(&self) -> &Target { |
29967ef6 | 775 | &self.tcx.sess.target |
83c7162d XL |
776 | } |
777 | } | |
778 | ||
a1dfa0c6 | 779 | impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> { |
dc9dc135 | 780 | fn tcx(&self) -> TyCtxt<'tcx> { |
2c00a5a8 | 781 | self.tcx |
7cac9316 | 782 | } |
ff7c6d11 XL |
783 | } |
784 | ||
a1dfa0c6 | 785 | impl LayoutOf for CodegenCx<'ll, 'tcx> { |
83c7162d | 786 | type Ty = Ty<'tcx>; |
ba9703b0 | 787 | type TyAndLayout = TyAndLayout<'tcx>; |
cc61c64b | 788 | |
ba9703b0 | 789 | fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { |
416331ca XL |
790 | self.spanned_layout_of(ty, DUMMY_SP) |
791 | } | |
792 | ||
ba9703b0 | 793 | fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::TyAndLayout { |
dfeec247 XL |
794 | self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap_or_else(|e| { |
795 | if let LayoutError::SizeOverflow(_) = e { | |
416331ca | 796 | self.sess().span_fatal(span, &e.to_string()) |
0bf4aa26 XL |
797 | } else { |
798 | bug!("failed to get layout for `{}`: {}", ty, e) | |
dfeec247 XL |
799 | } |
800 | }) | |
cc61c64b | 801 | } |
cc61c64b | 802 | } |
48663c56 XL |
803 | |
804 | impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> { | |
805 | fn param_env(&self) -> ty::ParamEnv<'tcx> { | |
806 | ty::ParamEnv::reveal_all() | |
807 | } | |
808 | } |