]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use llvm; | |
12 | use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef}; | |
7453a54e | 13 | use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig}; |
92a42be0 | 14 | use middle::cstore::LinkMeta; |
1a4d82fc | 15 | use middle::def::ExportMap; |
e9174d1e | 16 | use middle::def_id::DefId; |
1a4d82fc | 17 | use middle::traits; |
7453a54e | 18 | use rustc::mir::mir_map::MirMap; |
1a4d82fc JJ |
19 | use trans::adt; |
20 | use trans::base; | |
21 | use trans::builder::Builder; | |
c34b1796 | 22 | use trans::common::{ExternMap,BuilderRef_res}; |
1a4d82fc | 23 | use trans::debuginfo; |
9346a6ac | 24 | use trans::declare; |
d9579d0f | 25 | use trans::glue::DropGlueKind; |
1a4d82fc | 26 | use trans::monomorphize::MonoId; |
7453a54e | 27 | use trans::collector::{TransItem, TransItemState}; |
1a4d82fc | 28 | use trans::type_::{Type, TypeNames}; |
85aaf69f | 29 | use middle::subst::Substs; |
1a4d82fc JJ |
30 | use middle::ty::{self, Ty}; |
31 | use session::config::NoDebugInfo; | |
32 | use session::Session; | |
1a4d82fc JJ |
33 | use util::sha2::Sha256; |
34 | use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; | |
35 | ||
36 | use std::ffi::CString; | |
37 | use std::cell::{Cell, RefCell}; | |
7453a54e | 38 | use std::marker::PhantomData; |
1a4d82fc JJ |
39 | use std::ptr; |
40 | use std::rc::Rc; | |
41 | use syntax::ast; | |
42 | use syntax::parse::token::InternedString; | |
43 | ||
44 | pub struct Stats { | |
c34b1796 AL |
45 | pub n_glues_created: Cell<usize>, |
46 | pub n_null_glues: Cell<usize>, | |
47 | pub n_real_glues: Cell<usize>, | |
48 | pub n_fns: Cell<usize>, | |
49 | pub n_monos: Cell<usize>, | |
50 | pub n_inlines: Cell<usize>, | |
51 | pub n_closures: Cell<usize>, | |
52 | pub n_llvm_insns: Cell<usize>, | |
53 | pub llvm_insns: RefCell<FnvHashMap<String, usize>>, | |
1a4d82fc | 54 | // (ident, llvm-instructions) |
c34b1796 | 55 | pub fn_stats: RefCell<Vec<(String, usize)> >, |
1a4d82fc JJ |
56 | } |
57 | ||
58 | /// The shared portion of a `CrateContext`. There is one `SharedCrateContext` | |
59 | /// per crate. The data here is shared between all compilation units of the | |
60 | /// crate, so it must not contain references to any LLVM data structures | |
61 | /// (aside from metadata-related ones). | |
62682a34 | 62 | pub struct SharedCrateContext<'a, 'tcx: 'a> { |
1a4d82fc JJ |
63 | local_ccxs: Vec<LocalCrateContext<'tcx>>, |
64 | ||
65 | metadata_llmod: ModuleRef, | |
66 | metadata_llcx: ContextRef, | |
67 | ||
68 | export_map: ExportMap, | |
69 | reachable: NodeSet, | |
70 | item_symbols: RefCell<NodeMap<String>>, | |
71 | link_meta: LinkMeta, | |
72 | symbol_hasher: RefCell<Sha256>, | |
62682a34 | 73 | tcx: &'a ty::ctxt<'tcx>, |
1a4d82fc | 74 | stats: Stats, |
c34b1796 AL |
75 | check_overflow: bool, |
76 | check_drop_flag_for_sanity: bool, | |
92a42be0 | 77 | mir_map: &'a MirMap<'tcx>, |
1a4d82fc | 78 | |
d9579d0f | 79 | available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>, |
62682a34 | 80 | use_dll_storage_attrs: bool, |
7453a54e SL |
81 | |
82 | translation_items: RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>>, | |
1a4d82fc JJ |
83 | } |
84 | ||
85 | /// The local portion of a `CrateContext`. There is one `LocalCrateContext` | |
86 | /// per compilation unit. Each one has its own LLVM `ContextRef` so that | |
87 | /// several compilation units may be optimized in parallel. All other LLVM | |
88 | /// data structures in the `LocalCrateContext` are tied to that `ContextRef`. | |
89 | pub struct LocalCrateContext<'tcx> { | |
90 | llmod: ModuleRef, | |
91 | llcx: ContextRef, | |
1a4d82fc JJ |
92 | tn: TypeNames, |
93 | externs: RefCell<ExternMap>, | |
94 | item_vals: RefCell<NodeMap<ValueRef>>, | |
95 | needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>, | |
96 | fn_pointer_shims: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>, | |
d9579d0f | 97 | drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>>, |
1a4d82fc JJ |
98 | /// Track mapping of external ids to local items imported for inlining |
99 | external: RefCell<DefIdMap<Option<ast::NodeId>>>, | |
100 | /// Backwards version of the `external` map (inlined items to where they | |
101 | /// came from) | |
e9174d1e | 102 | external_srcs: RefCell<NodeMap<DefId>>, |
1a4d82fc JJ |
103 | /// Cache instances of monomorphized functions |
104 | monomorphized: RefCell<FnvHashMap<MonoId<'tcx>, ValueRef>>, | |
c34b1796 | 105 | monomorphizing: RefCell<DefIdMap<usize>>, |
62682a34 | 106 | available_monomorphizations: RefCell<FnvHashSet<String>>, |
1a4d82fc | 107 | /// Cache generated vtables |
c34b1796 | 108 | vtables: RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>, ValueRef>>, |
1a4d82fc JJ |
109 | /// Cache of constant strings, |
110 | const_cstr_cache: RefCell<FnvHashMap<InternedString, ValueRef>>, | |
111 | ||
112 | /// Reverse-direction for const ptrs cast from globals. | |
85aaf69f | 113 | /// Key is a ValueRef holding a *T, |
1a4d82fc JJ |
114 | /// Val is a ValueRef holding a *[T]. |
115 | /// | |
116 | /// Needed because LLVM loses pointer->pointee association | |
117 | /// when we ptrcast, and we have to ptrcast during translation | |
85aaf69f SL |
118 | /// of a [T] const because we form a slice, a (*T,usize) pair, not |
119 | /// a pointer to an LLVM array type. Similar for trait objects. | |
120 | const_unsized: RefCell<FnvHashMap<ValueRef, ValueRef>>, | |
121 | ||
122 | /// Cache of emitted const globals (value -> global) | |
123 | const_globals: RefCell<FnvHashMap<ValueRef, ValueRef>>, | |
1a4d82fc JJ |
124 | |
125 | /// Cache of emitted const values | |
85aaf69f | 126 | const_values: RefCell<FnvHashMap<(ast::NodeId, &'tcx Substs<'tcx>), ValueRef>>, |
1a4d82fc | 127 | |
1a4d82fc JJ |
128 | /// Cache of external const values |
129 | extern_const_values: RefCell<DefIdMap<ValueRef>>, | |
130 | ||
e9174d1e | 131 | impl_method_cache: RefCell<FnvHashMap<(DefId, ast::Name), DefId>>, |
1a4d82fc JJ |
132 | |
133 | /// Cache of closure wrappers for bare fn's. | |
134 | closure_bare_wrapper_cache: RefCell<FnvHashMap<ValueRef, ValueRef>>, | |
135 | ||
c1a9b12d SL |
136 | /// List of globals for static variables which need to be passed to the |
137 | /// LLVM function ReplaceAllUsesWith (RAUW) when translation is complete. | |
138 | /// (We have to make sure we don't invalidate any ValueRefs referring | |
139 | /// to constants.) | |
140 | statics_to_rauw: RefCell<Vec<(ValueRef, ValueRef)>>, | |
141 | ||
1a4d82fc JJ |
142 | lltypes: RefCell<FnvHashMap<Ty<'tcx>, Type>>, |
143 | llsizingtypes: RefCell<FnvHashMap<Ty<'tcx>, Type>>, | |
144 | adt_reprs: RefCell<FnvHashMap<Ty<'tcx>, Rc<adt::Repr<'tcx>>>>, | |
145 | type_hashcodes: RefCell<FnvHashMap<Ty<'tcx>, String>>, | |
1a4d82fc JJ |
146 | int_type: Type, |
147 | opaque_vec_type: Type, | |
148 | builder: BuilderRef_res, | |
149 | ||
150 | /// Holds the LLVM values for closure IDs. | |
85aaf69f | 151 | closure_vals: RefCell<FnvHashMap<MonoId<'tcx>, ValueRef>>, |
1a4d82fc JJ |
152 | |
153 | dbg_cx: Option<debuginfo::CrateDebugContext<'tcx>>, | |
154 | ||
155 | eh_personality: RefCell<Option<ValueRef>>, | |
92a42be0 | 156 | eh_unwind_resume: RefCell<Option<ValueRef>>, |
c1a9b12d | 157 | rust_try_fn: RefCell<Option<ValueRef>>, |
1a4d82fc JJ |
158 | |
159 | intrinsics: RefCell<FnvHashMap<&'static str, ValueRef>>, | |
160 | ||
161 | /// Number of LLVM instructions translated into this `LocalCrateContext`. | |
162 | /// This is used to perform some basic load-balancing to keep all LLVM | |
163 | /// contexts around the same size. | |
c34b1796 | 164 | n_llvm_insns: Cell<usize>, |
1a4d82fc | 165 | |
92a42be0 SL |
166 | /// Depth of the current type-of computation - used to bail out |
167 | type_of_depth: Cell<usize>, | |
168 | ||
7453a54e SL |
169 | trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>, |
170 | } | |
171 | ||
172 | // Implement DepTrackingMapConfig for `trait_cache` | |
173 | pub struct TraitSelectionCache<'tcx> { | |
174 | data: PhantomData<&'tcx ()> | |
175 | } | |
176 | ||
177 | impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { | |
178 | type Key = ty::PolyTraitRef<'tcx>; | |
179 | type Value = traits::Vtable<'tcx, ()>; | |
180 | fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode { | |
181 | ty::tls::with(|tcx| { | |
182 | let lifted_key = tcx.lift(key).unwrap(); | |
183 | lifted_key.to_poly_trait_predicate().dep_node() | |
184 | }) | |
185 | } | |
1a4d82fc JJ |
186 | } |
187 | ||
188 | pub struct CrateContext<'a, 'tcx: 'a> { | |
62682a34 | 189 | shared: &'a SharedCrateContext<'a, 'tcx>, |
1a4d82fc JJ |
190 | local: &'a LocalCrateContext<'tcx>, |
191 | /// The index of `local` in `shared.local_ccxs`. This is used in | |
192 | /// `maybe_iter(true)` to identify the original `LocalCrateContext`. | |
c34b1796 | 193 | index: usize, |
1a4d82fc JJ |
194 | } |
195 | ||
196 | pub struct CrateContextIterator<'a, 'tcx: 'a> { | |
62682a34 | 197 | shared: &'a SharedCrateContext<'a, 'tcx>, |
c34b1796 | 198 | index: usize, |
1a4d82fc JJ |
199 | } |
200 | ||
201 | impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> { | |
202 | type Item = CrateContext<'a, 'tcx>; | |
203 | ||
204 | fn next(&mut self) -> Option<CrateContext<'a, 'tcx>> { | |
205 | if self.index >= self.shared.local_ccxs.len() { | |
206 | return None; | |
207 | } | |
208 | ||
209 | let index = self.index; | |
210 | self.index += 1; | |
211 | ||
212 | Some(CrateContext { | |
213 | shared: self.shared, | |
214 | local: &self.shared.local_ccxs[index], | |
215 | index: index, | |
216 | }) | |
217 | } | |
218 | } | |
219 | ||
220 | /// The iterator produced by `CrateContext::maybe_iter`. | |
221 | pub struct CrateContextMaybeIterator<'a, 'tcx: 'a> { | |
62682a34 | 222 | shared: &'a SharedCrateContext<'a, 'tcx>, |
c34b1796 | 223 | index: usize, |
1a4d82fc | 224 | single: bool, |
c34b1796 | 225 | origin: usize, |
1a4d82fc JJ |
226 | } |
227 | ||
228 | impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> { | |
229 | type Item = (CrateContext<'a, 'tcx>, bool); | |
230 | ||
231 | fn next(&mut self) -> Option<(CrateContext<'a, 'tcx>, bool)> { | |
232 | if self.index >= self.shared.local_ccxs.len() { | |
233 | return None; | |
234 | } | |
235 | ||
236 | let index = self.index; | |
237 | self.index += 1; | |
238 | if self.single { | |
239 | self.index = self.shared.local_ccxs.len(); | |
240 | } | |
241 | ||
242 | let ccx = CrateContext { | |
243 | shared: self.shared, | |
244 | local: &self.shared.local_ccxs[index], | |
245 | index: index, | |
246 | }; | |
247 | Some((ccx, index == self.origin)) | |
248 | } | |
249 | } | |
250 | ||
1a4d82fc JJ |
251 | unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { |
252 | let llcx = llvm::LLVMContextCreate(); | |
85aaf69f | 253 | let mod_name = CString::new(mod_name).unwrap(); |
1a4d82fc JJ |
254 | let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); |
255 | ||
e9174d1e SL |
256 | if let Some(ref custom_data_layout) = sess.target.target.options.data_layout { |
257 | let data_layout = CString::new(&custom_data_layout[..]).unwrap(); | |
c1a9b12d SL |
258 | llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); |
259 | } else { | |
260 | let tm = ::back::write::create_target_machine(sess); | |
261 | llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm); | |
262 | llvm::LLVMRustDisposeTargetMachine(tm); | |
263 | } | |
1a4d82fc | 264 | |
85aaf69f SL |
265 | let llvm_target = sess.target.target.llvm_target.as_bytes(); |
266 | let llvm_target = CString::new(llvm_target).unwrap(); | |
1a4d82fc JJ |
267 | llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); |
268 | (llcx, llmod) | |
269 | } | |
270 | ||
62682a34 | 271 | impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { |
1a4d82fc | 272 | pub fn new(crate_name: &str, |
c34b1796 | 273 | local_count: usize, |
62682a34 | 274 | tcx: &'b ty::ctxt<'tcx>, |
92a42be0 | 275 | mir_map: &'b MirMap<'tcx>, |
1a4d82fc JJ |
276 | export_map: ExportMap, |
277 | symbol_hasher: Sha256, | |
278 | link_meta: LinkMeta, | |
c34b1796 AL |
279 | reachable: NodeSet, |
280 | check_overflow: bool, | |
281 | check_drop_flag_for_sanity: bool) | |
62682a34 | 282 | -> SharedCrateContext<'b, 'tcx> { |
1a4d82fc JJ |
283 | let (metadata_llcx, metadata_llmod) = unsafe { |
284 | create_context_and_module(&tcx.sess, "metadata") | |
285 | }; | |
286 | ||
62682a34 SL |
287 | // An interesting part of Windows which MSVC forces our hand on (and |
288 | // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` | |
289 | // attributes in LLVM IR as well as native dependencies (in C these | |
290 | // correspond to `__declspec(dllimport)`). | |
291 | // | |
292 | // Whenever a dynamic library is built by MSVC it must have its public | |
293 | // interface specified by functions tagged with `dllexport` or otherwise | |
294 | // they're not available to be linked against. This poses a few problems | |
295 | // for the compiler, some of which are somewhat fundamental, but we use | |
296 | // the `use_dll_storage_attrs` variable below to attach the `dllexport` | |
297 | // attribute to all LLVM functions that are reachable (e.g. they're | |
298 | // already tagged with external linkage). This is suboptimal for a few | |
299 | // reasons: | |
300 | // | |
301 | // * If an object file will never be included in a dynamic library, | |
302 | // there's no need to attach the dllexport attribute. Most object | |
303 | // files in Rust are not destined to become part of a dll as binaries | |
304 | // are statically linked by default. | |
305 | // * If the compiler is emitting both an rlib and a dylib, the same | |
306 | // source object file is currently used but with MSVC this may be less | |
307 | // feasible. The compiler may be able to get around this, but it may | |
308 | // involve some invasive changes to deal with this. | |
309 | // | |
310 | // The flipside of this situation is that whenever you link to a dll and | |
311 | // you import a function from it, the import should be tagged with | |
312 | // `dllimport`. At this time, however, the compiler does not emit | |
313 | // `dllimport` for any declarations other than constants (where it is | |
314 | // required), which is again suboptimal for even more reasons! | |
315 | // | |
316 | // * Calling a function imported from another dll without using | |
317 | // `dllimport` causes the linker/compiler to have extra overhead (one | |
318 | // `jmp` instruction on x86) when calling the function. | |
319 | // * The same object file may be used in different circumstances, so a | |
320 | // function may be imported from a dll if the object is linked into a | |
321 | // dll, but it may be just linked against if linked into an rlib. | |
322 | // * The compiler has no knowledge about whether native functions should | |
323 | // be tagged dllimport or not. | |
324 | // | |
325 | // For now the compiler takes the perf hit (I do not have any numbers to | |
326 | // this effect) by marking very little as `dllimport` and praying the | |
327 | // linker will take care of everything. Fixing this problem will likely | |
328 | // require adding a few attributes to Rust itself (feature gated at the | |
329 | // start) and then strongly recommending static linkage on MSVC! | |
330 | let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc; | |
331 | ||
1a4d82fc JJ |
332 | let mut shared_ccx = SharedCrateContext { |
333 | local_ccxs: Vec::with_capacity(local_count), | |
334 | metadata_llmod: metadata_llmod, | |
335 | metadata_llcx: metadata_llcx, | |
336 | export_map: export_map, | |
337 | reachable: reachable, | |
85aaf69f | 338 | item_symbols: RefCell::new(NodeMap()), |
1a4d82fc JJ |
339 | link_meta: link_meta, |
340 | symbol_hasher: RefCell::new(symbol_hasher), | |
341 | tcx: tcx, | |
92a42be0 | 342 | mir_map: mir_map, |
1a4d82fc | 343 | stats: Stats { |
85aaf69f SL |
344 | n_glues_created: Cell::new(0), |
345 | n_null_glues: Cell::new(0), | |
346 | n_real_glues: Cell::new(0), | |
347 | n_fns: Cell::new(0), | |
348 | n_monos: Cell::new(0), | |
349 | n_inlines: Cell::new(0), | |
350 | n_closures: Cell::new(0), | |
351 | n_llvm_insns: Cell::new(0), | |
352 | llvm_insns: RefCell::new(FnvHashMap()), | |
1a4d82fc JJ |
353 | fn_stats: RefCell::new(Vec::new()), |
354 | }, | |
c34b1796 AL |
355 | check_overflow: check_overflow, |
356 | check_drop_flag_for_sanity: check_drop_flag_for_sanity, | |
85aaf69f | 357 | available_drop_glues: RefCell::new(FnvHashMap()), |
62682a34 | 358 | use_dll_storage_attrs: use_dll_storage_attrs, |
7453a54e | 359 | translation_items: RefCell::new(FnvHashMap()), |
1a4d82fc JJ |
360 | }; |
361 | ||
85aaf69f | 362 | for i in 0..local_count { |
1a4d82fc JJ |
363 | // Append ".rs" to crate name as LLVM module identifier. |
364 | // | |
365 | // LLVM code generator emits a ".file filename" directive | |
366 | // for ELF backends. Value of the "filename" is set as the | |
367 | // LLVM module identifier. Due to a LLVM MC bug[1], LLVM | |
368 | // crashes if the module identifier is same as other symbols | |
369 | // such as a function name in the module. | |
370 | // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 | |
371 | let llmod_id = format!("{}.{}.rs", crate_name, i); | |
85aaf69f | 372 | let local_ccx = LocalCrateContext::new(&shared_ccx, &llmod_id[..]); |
1a4d82fc JJ |
373 | shared_ccx.local_ccxs.push(local_ccx); |
374 | } | |
375 | ||
376 | shared_ccx | |
377 | } | |
378 | ||
379 | pub fn iter<'a>(&'a self) -> CrateContextIterator<'a, 'tcx> { | |
380 | CrateContextIterator { | |
381 | shared: self, | |
382 | index: 0, | |
383 | } | |
384 | } | |
385 | ||
c34b1796 | 386 | pub fn get_ccx<'a>(&'a self, index: usize) -> CrateContext<'a, 'tcx> { |
1a4d82fc JJ |
387 | CrateContext { |
388 | shared: self, | |
389 | local: &self.local_ccxs[index], | |
390 | index: index, | |
391 | } | |
392 | } | |
393 | ||
394 | fn get_smallest_ccx<'a>(&'a self) -> CrateContext<'a, 'tcx> { | |
395 | let (local_ccx, index) = | |
396 | self.local_ccxs | |
397 | .iter() | |
85aaf69f | 398 | .zip(0..self.local_ccxs.len()) |
92a42be0 | 399 | .min_by_key(|&(local_ccx, _idx)| local_ccx.n_llvm_insns.get()) |
1a4d82fc JJ |
400 | .unwrap(); |
401 | CrateContext { | |
402 | shared: self, | |
403 | local: local_ccx, | |
404 | index: index, | |
405 | } | |
406 | } | |
407 | ||
408 | ||
409 | pub fn metadata_llmod(&self) -> ModuleRef { | |
410 | self.metadata_llmod | |
411 | } | |
412 | ||
413 | pub fn metadata_llcx(&self) -> ContextRef { | |
414 | self.metadata_llcx | |
415 | } | |
416 | ||
417 | pub fn export_map<'a>(&'a self) -> &'a ExportMap { | |
418 | &self.export_map | |
419 | } | |
420 | ||
421 | pub fn reachable<'a>(&'a self) -> &'a NodeSet { | |
422 | &self.reachable | |
423 | } | |
424 | ||
425 | pub fn item_symbols<'a>(&'a self) -> &'a RefCell<NodeMap<String>> { | |
426 | &self.item_symbols | |
427 | } | |
428 | ||
429 | pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { | |
430 | &self.link_meta | |
431 | } | |
432 | ||
433 | pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { | |
1a4d82fc JJ |
434 | self.tcx |
435 | } | |
436 | ||
437 | pub fn sess<'a>(&'a self) -> &'a Session { | |
438 | &self.tcx.sess | |
439 | } | |
440 | ||
441 | pub fn stats<'a>(&'a self) -> &'a Stats { | |
442 | &self.stats | |
443 | } | |
62682a34 SL |
444 | |
445 | pub fn use_dll_storage_attrs(&self) -> bool { | |
446 | self.use_dll_storage_attrs | |
447 | } | |
1a4d82fc JJ |
448 | } |
449 | ||
450 | impl<'tcx> LocalCrateContext<'tcx> { | |
62682a34 | 451 | fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, |
1a4d82fc JJ |
452 | name: &str) |
453 | -> LocalCrateContext<'tcx> { | |
454 | unsafe { | |
455 | let (llcx, llmod) = create_context_and_module(&shared.tcx.sess, name); | |
456 | ||
1a4d82fc JJ |
457 | let dbg_cx = if shared.tcx.sess.opts.debuginfo != NoDebugInfo { |
458 | Some(debuginfo::CrateDebugContext::new(llmod)) | |
459 | } else { | |
460 | None | |
461 | }; | |
462 | ||
463 | let mut local_ccx = LocalCrateContext { | |
464 | llmod: llmod, | |
465 | llcx: llcx, | |
1a4d82fc | 466 | tn: TypeNames::new(), |
85aaf69f SL |
467 | externs: RefCell::new(FnvHashMap()), |
468 | item_vals: RefCell::new(NodeMap()), | |
469 | needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()), | |
470 | fn_pointer_shims: RefCell::new(FnvHashMap()), | |
471 | drop_glues: RefCell::new(FnvHashMap()), | |
85aaf69f SL |
472 | external: RefCell::new(DefIdMap()), |
473 | external_srcs: RefCell::new(NodeMap()), | |
474 | monomorphized: RefCell::new(FnvHashMap()), | |
475 | monomorphizing: RefCell::new(DefIdMap()), | |
62682a34 | 476 | available_monomorphizations: RefCell::new(FnvHashSet()), |
85aaf69f SL |
477 | vtables: RefCell::new(FnvHashMap()), |
478 | const_cstr_cache: RefCell::new(FnvHashMap()), | |
479 | const_unsized: RefCell::new(FnvHashMap()), | |
480 | const_globals: RefCell::new(FnvHashMap()), | |
481 | const_values: RefCell::new(FnvHashMap()), | |
85aaf69f SL |
482 | extern_const_values: RefCell::new(DefIdMap()), |
483 | impl_method_cache: RefCell::new(FnvHashMap()), | |
484 | closure_bare_wrapper_cache: RefCell::new(FnvHashMap()), | |
c1a9b12d | 485 | statics_to_rauw: RefCell::new(Vec::new()), |
85aaf69f SL |
486 | lltypes: RefCell::new(FnvHashMap()), |
487 | llsizingtypes: RefCell::new(FnvHashMap()), | |
488 | adt_reprs: RefCell::new(FnvHashMap()), | |
489 | type_hashcodes: RefCell::new(FnvHashMap()), | |
1a4d82fc JJ |
490 | int_type: Type::from_ref(ptr::null_mut()), |
491 | opaque_vec_type: Type::from_ref(ptr::null_mut()), | |
492 | builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), | |
85aaf69f | 493 | closure_vals: RefCell::new(FnvHashMap()), |
1a4d82fc JJ |
494 | dbg_cx: dbg_cx, |
495 | eh_personality: RefCell::new(None), | |
92a42be0 | 496 | eh_unwind_resume: RefCell::new(None), |
c1a9b12d | 497 | rust_try_fn: RefCell::new(None), |
85aaf69f SL |
498 | intrinsics: RefCell::new(FnvHashMap()), |
499 | n_llvm_insns: Cell::new(0), | |
92a42be0 | 500 | type_of_depth: Cell::new(0), |
7453a54e SL |
501 | trait_cache: RefCell::new(DepTrackingMap::new(shared.tcx |
502 | .dep_graph | |
503 | .clone())), | |
1a4d82fc JJ |
504 | }; |
505 | ||
506 | local_ccx.int_type = Type::int(&local_ccx.dummy_ccx(shared)); | |
507 | local_ccx.opaque_vec_type = Type::opaque_vec(&local_ccx.dummy_ccx(shared)); | |
508 | ||
509 | // Done mutating local_ccx directly. (The rest of the | |
510 | // initialization goes through RefCell.) | |
511 | { | |
512 | let ccx = local_ccx.dummy_ccx(shared); | |
513 | ||
514 | let mut str_slice_ty = Type::named_struct(&ccx, "str_slice"); | |
515 | str_slice_ty.set_struct_body(&[Type::i8p(&ccx), ccx.int_type()], false); | |
516 | ccx.tn().associate_type("str_slice", &str_slice_ty); | |
517 | ||
1a4d82fc JJ |
518 | if ccx.sess().count_llvm_insns() { |
519 | base::init_insn_ctxt() | |
520 | } | |
521 | } | |
522 | ||
523 | local_ccx | |
524 | } | |
525 | } | |
526 | ||
527 | /// Create a dummy `CrateContext` from `self` and the provided | |
528 | /// `SharedCrateContext`. This is somewhat dangerous because `self` may | |
529 | /// not actually be an element of `shared.local_ccxs`, which can cause some | |
530 | /// operations to panic unexpectedly. | |
531 | /// | |
532 | /// This is used in the `LocalCrateContext` constructor to allow calling | |
533 | /// functions that expect a complete `CrateContext`, even before the local | |
534 | /// portion is fully initialized and attached to the `SharedCrateContext`. | |
62682a34 | 535 | fn dummy_ccx<'a>(&'a self, shared: &'a SharedCrateContext<'a, 'tcx>) |
1a4d82fc JJ |
536 | -> CrateContext<'a, 'tcx> { |
537 | CrateContext { | |
538 | shared: shared, | |
539 | local: self, | |
c34b1796 | 540 | index: !0 as usize, |
1a4d82fc JJ |
541 | } |
542 | } | |
543 | } | |
544 | ||
545 | impl<'b, 'tcx> CrateContext<'b, 'tcx> { | |
62682a34 | 546 | pub fn shared(&self) -> &'b SharedCrateContext<'b, 'tcx> { |
1a4d82fc JJ |
547 | self.shared |
548 | } | |
549 | ||
550 | pub fn local(&self) -> &'b LocalCrateContext<'tcx> { | |
551 | self.local | |
552 | } | |
553 | ||
554 | ||
555 | /// Get a (possibly) different `CrateContext` from the same | |
556 | /// `SharedCrateContext`. | |
557 | pub fn rotate(&self) -> CrateContext<'b, 'tcx> { | |
558 | self.shared.get_smallest_ccx() | |
559 | } | |
560 | ||
561 | /// Either iterate over only `self`, or iterate over all `CrateContext`s in | |
562 | /// the `SharedCrateContext`. The iterator produces `(ccx, is_origin)` | |
563 | /// pairs, where `is_origin` is `true` if `ccx` is `self` and `false` | |
564 | /// otherwise. This method is useful for avoiding code duplication in | |
565 | /// cases where it may or may not be necessary to translate code into every | |
566 | /// context. | |
567 | pub fn maybe_iter(&self, iter_all: bool) -> CrateContextMaybeIterator<'b, 'tcx> { | |
568 | CrateContextMaybeIterator { | |
569 | shared: self.shared, | |
570 | index: if iter_all { 0 } else { self.index }, | |
571 | single: !iter_all, | |
572 | origin: self.index, | |
573 | } | |
574 | } | |
575 | ||
576 | ||
577 | pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { | |
62682a34 | 578 | self.shared.tcx |
1a4d82fc JJ |
579 | } |
580 | ||
581 | pub fn sess<'a>(&'a self) -> &'a Session { | |
582 | &self.shared.tcx.sess | |
583 | } | |
584 | ||
585 | pub fn builder<'a>(&'a self) -> Builder<'a, 'tcx> { | |
586 | Builder::new(self) | |
587 | } | |
588 | ||
589 | pub fn raw_builder<'a>(&'a self) -> BuilderRef { | |
590 | self.local.builder.b | |
591 | } | |
592 | ||
e9174d1e | 593 | pub fn get_intrinsic(&self, key: &str) -> ValueRef { |
1a4d82fc JJ |
594 | if let Some(v) = self.intrinsics().borrow().get(key).cloned() { |
595 | return v; | |
596 | } | |
597 | match declare_intrinsic(self, key) { | |
598 | Some(v) => return v, | |
e9174d1e | 599 | None => panic!("unknown intrinsic '{}'", key) |
1a4d82fc JJ |
600 | } |
601 | } | |
602 | ||
1a4d82fc JJ |
603 | pub fn llmod(&self) -> ModuleRef { |
604 | self.local.llmod | |
605 | } | |
606 | ||
607 | pub fn llcx(&self) -> ContextRef { | |
608 | self.local.llcx | |
609 | } | |
610 | ||
c1a9b12d SL |
611 | pub fn td(&self) -> llvm::TargetDataRef { |
612 | unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) } | |
1a4d82fc JJ |
613 | } |
614 | ||
615 | pub fn tn<'a>(&'a self) -> &'a TypeNames { | |
616 | &self.local.tn | |
617 | } | |
618 | ||
619 | pub fn externs<'a>(&'a self) -> &'a RefCell<ExternMap> { | |
620 | &self.local.externs | |
621 | } | |
622 | ||
623 | pub fn item_vals<'a>(&'a self) -> &'a RefCell<NodeMap<ValueRef>> { | |
624 | &self.local.item_vals | |
625 | } | |
626 | ||
627 | pub fn export_map<'a>(&'a self) -> &'a ExportMap { | |
628 | &self.shared.export_map | |
629 | } | |
630 | ||
631 | pub fn reachable<'a>(&'a self) -> &'a NodeSet { | |
632 | &self.shared.reachable | |
633 | } | |
634 | ||
635 | pub fn item_symbols<'a>(&'a self) -> &'a RefCell<NodeMap<String>> { | |
636 | &self.shared.item_symbols | |
637 | } | |
638 | ||
639 | pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { | |
640 | &self.shared.link_meta | |
641 | } | |
642 | ||
643 | pub fn needs_unwind_cleanup_cache(&self) -> &RefCell<FnvHashMap<Ty<'tcx>, bool>> { | |
644 | &self.local.needs_unwind_cleanup_cache | |
645 | } | |
646 | ||
647 | pub fn fn_pointer_shims(&self) -> &RefCell<FnvHashMap<Ty<'tcx>, ValueRef>> { | |
648 | &self.local.fn_pointer_shims | |
649 | } | |
650 | ||
d9579d0f | 651 | pub fn drop_glues<'a>(&'a self) -> &'a RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>> { |
1a4d82fc JJ |
652 | &self.local.drop_glues |
653 | } | |
654 | ||
1a4d82fc JJ |
655 | pub fn external<'a>(&'a self) -> &'a RefCell<DefIdMap<Option<ast::NodeId>>> { |
656 | &self.local.external | |
657 | } | |
658 | ||
e9174d1e | 659 | pub fn external_srcs<'a>(&'a self) -> &'a RefCell<NodeMap<DefId>> { |
1a4d82fc JJ |
660 | &self.local.external_srcs |
661 | } | |
662 | ||
663 | pub fn monomorphized<'a>(&'a self) -> &'a RefCell<FnvHashMap<MonoId<'tcx>, ValueRef>> { | |
664 | &self.local.monomorphized | |
665 | } | |
666 | ||
c34b1796 | 667 | pub fn monomorphizing<'a>(&'a self) -> &'a RefCell<DefIdMap<usize>> { |
1a4d82fc JJ |
668 | &self.local.monomorphizing |
669 | } | |
670 | ||
c34b1796 | 671 | pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>, ValueRef>> { |
1a4d82fc JJ |
672 | &self.local.vtables |
673 | } | |
674 | ||
675 | pub fn const_cstr_cache<'a>(&'a self) -> &'a RefCell<FnvHashMap<InternedString, ValueRef>> { | |
676 | &self.local.const_cstr_cache | |
677 | } | |
678 | ||
85aaf69f SL |
679 | pub fn const_unsized<'a>(&'a self) -> &'a RefCell<FnvHashMap<ValueRef, ValueRef>> { |
680 | &self.local.const_unsized | |
681 | } | |
682 | ||
683 | pub fn const_globals<'a>(&'a self) -> &'a RefCell<FnvHashMap<ValueRef, ValueRef>> { | |
1a4d82fc JJ |
684 | &self.local.const_globals |
685 | } | |
686 | ||
85aaf69f SL |
687 | pub fn const_values<'a>(&'a self) -> &'a RefCell<FnvHashMap<(ast::NodeId, &'tcx Substs<'tcx>), |
688 | ValueRef>> { | |
1a4d82fc JJ |
689 | &self.local.const_values |
690 | } | |
691 | ||
1a4d82fc JJ |
692 | pub fn extern_const_values<'a>(&'a self) -> &'a RefCell<DefIdMap<ValueRef>> { |
693 | &self.local.extern_const_values | |
694 | } | |
695 | ||
696 | pub fn impl_method_cache<'a>(&'a self) | |
e9174d1e | 697 | -> &'a RefCell<FnvHashMap<(DefId, ast::Name), DefId>> { |
1a4d82fc JJ |
698 | &self.local.impl_method_cache |
699 | } | |
700 | ||
701 | pub fn closure_bare_wrapper_cache<'a>(&'a self) -> &'a RefCell<FnvHashMap<ValueRef, ValueRef>> { | |
702 | &self.local.closure_bare_wrapper_cache | |
703 | } | |
704 | ||
c1a9b12d SL |
705 | pub fn statics_to_rauw<'a>(&'a self) -> &'a RefCell<Vec<(ValueRef, ValueRef)>> { |
706 | &self.local.statics_to_rauw | |
707 | } | |
708 | ||
1a4d82fc JJ |
709 | pub fn lltypes<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, Type>> { |
710 | &self.local.lltypes | |
711 | } | |
712 | ||
713 | pub fn llsizingtypes<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, Type>> { | |
714 | &self.local.llsizingtypes | |
715 | } | |
716 | ||
717 | pub fn adt_reprs<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, Rc<adt::Repr<'tcx>>>> { | |
718 | &self.local.adt_reprs | |
719 | } | |
720 | ||
721 | pub fn symbol_hasher<'a>(&'a self) -> &'a RefCell<Sha256> { | |
722 | &self.shared.symbol_hasher | |
723 | } | |
724 | ||
725 | pub fn type_hashcodes<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, String>> { | |
726 | &self.local.type_hashcodes | |
727 | } | |
728 | ||
1a4d82fc JJ |
729 | pub fn stats<'a>(&'a self) -> &'a Stats { |
730 | &self.shared.stats | |
731 | } | |
732 | ||
733 | pub fn available_monomorphizations<'a>(&'a self) -> &'a RefCell<FnvHashSet<String>> { | |
62682a34 | 734 | &self.local.available_monomorphizations |
1a4d82fc JJ |
735 | } |
736 | ||
d9579d0f | 737 | pub fn available_drop_glues(&self) -> &RefCell<FnvHashMap<DropGlueKind<'tcx>, String>> { |
1a4d82fc JJ |
738 | &self.shared.available_drop_glues |
739 | } | |
740 | ||
741 | pub fn int_type(&self) -> Type { | |
742 | self.local.int_type | |
743 | } | |
744 | ||
745 | pub fn opaque_vec_type(&self) -> Type { | |
746 | self.local.opaque_vec_type | |
747 | } | |
748 | ||
85aaf69f SL |
749 | pub fn closure_vals<'a>(&'a self) -> &'a RefCell<FnvHashMap<MonoId<'tcx>, ValueRef>> { |
750 | &self.local.closure_vals | |
1a4d82fc JJ |
751 | } |
752 | ||
753 | pub fn dbg_cx<'a>(&'a self) -> &'a Option<debuginfo::CrateDebugContext<'tcx>> { | |
754 | &self.local.dbg_cx | |
755 | } | |
756 | ||
757 | pub fn eh_personality<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> { | |
758 | &self.local.eh_personality | |
759 | } | |
760 | ||
92a42be0 SL |
761 | pub fn eh_unwind_resume<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> { |
762 | &self.local.eh_unwind_resume | |
c1a9b12d SL |
763 | } |
764 | ||
92a42be0 SL |
765 | pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> { |
766 | &self.local.rust_try_fn | |
c1a9b12d SL |
767 | } |
768 | ||
1a4d82fc JJ |
769 | fn intrinsics<'a>(&'a self) -> &'a RefCell<FnvHashMap<&'static str, ValueRef>> { |
770 | &self.local.intrinsics | |
771 | } | |
772 | ||
773 | pub fn count_llvm_insn(&self) { | |
774 | self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1); | |
775 | } | |
776 | ||
7453a54e | 777 | pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>> { |
1a4d82fc JJ |
778 | &self.local.trait_cache |
779 | } | |
780 | ||
781 | /// Return exclusive upper bound on object size. | |
782 | /// | |
783 | /// The theoretical maximum object size is defined as the maximum positive `int` value. This | |
784 | /// ensures that the `offset` semantics remain well-defined by allowing it to correctly index | |
785 | /// every address within an object along with one byte past the end, along with allowing `int` | |
786 | /// to store the difference between any two pointers into an object. | |
787 | /// | |
788 | /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer to | |
789 | /// represent object size in bits. It would need to be 1 << 61 to account for this, but is | |
790 | /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable | |
791 | /// address space on 64-bit ARMv8 and x86_64. | |
792 | pub fn obj_size_bound(&self) -> u64 { | |
c34b1796 | 793 | match &self.sess().target.target.target_pointer_width[..] { |
1a4d82fc JJ |
794 | "32" => 1 << 31, |
795 | "64" => 1 << 47, | |
796 | _ => unreachable!() // error handled by config::build_target_config | |
797 | } | |
798 | } | |
799 | ||
800 | pub fn report_overbig_object(&self, obj: Ty<'tcx>) -> ! { | |
801 | self.sess().fatal( | |
62682a34 SL |
802 | &format!("the type `{:?}` is too big for the current architecture", |
803 | obj)) | |
c34b1796 AL |
804 | } |
805 | ||
92a42be0 SL |
806 | pub fn enter_type_of(&self, ty: Ty<'tcx>) -> TypeOfDepthLock<'b, 'tcx> { |
807 | let current_depth = self.local.type_of_depth.get(); | |
808 | debug!("enter_type_of({:?}) at depth {:?}", ty, current_depth); | |
809 | if current_depth > self.sess().recursion_limit.get() { | |
810 | self.sess().fatal( | |
811 | &format!("overflow representing the type `{}`", ty)) | |
812 | } | |
813 | self.local.type_of_depth.set(current_depth + 1); | |
814 | TypeOfDepthLock(self.local) | |
815 | } | |
816 | ||
c34b1796 AL |
817 | pub fn check_overflow(&self) -> bool { |
818 | self.shared.check_overflow | |
819 | } | |
820 | ||
821 | pub fn check_drop_flag_for_sanity(&self) -> bool { | |
822 | // This controls whether we emit a conditional llvm.debugtrap | |
823 | // guarded on whether the dropflag is one of its (two) valid | |
824 | // values. | |
825 | self.shared.check_drop_flag_for_sanity | |
1a4d82fc | 826 | } |
62682a34 SL |
827 | |
828 | pub fn use_dll_storage_attrs(&self) -> bool { | |
829 | self.shared.use_dll_storage_attrs() | |
830 | } | |
92a42be0 SL |
831 | |
832 | pub fn mir_map(&self) -> &'b MirMap<'tcx> { | |
833 | self.shared.mir_map | |
834 | } | |
7453a54e SL |
835 | |
836 | pub fn translation_items(&self) -> &RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>> { | |
837 | &self.shared.translation_items | |
838 | } | |
839 | ||
840 | pub fn record_translation_item_as_generated(&self, cgi: TransItem<'tcx>) { | |
841 | if self.sess().opts.debugging_opts.print_trans_items.is_none() { | |
842 | return; | |
843 | } | |
844 | ||
845 | let mut codegen_items = self.translation_items().borrow_mut(); | |
846 | ||
847 | if codegen_items.contains_key(&cgi) { | |
848 | codegen_items.insert(cgi, TransItemState::PredictedAndGenerated); | |
849 | } else { | |
850 | codegen_items.insert(cgi, TransItemState::NotPredictedButGenerated); | |
851 | } | |
852 | } | |
92a42be0 SL |
853 | } |
854 | ||
855 | pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>); | |
856 | ||
857 | impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> { | |
858 | fn drop(&mut self) { | |
859 | self.0.type_of_depth.set(self.0.type_of_depth.get() - 1); | |
860 | } | |
1a4d82fc JJ |
861 | } |
862 | ||
d9579d0f | 863 | /// Declare any llvm intrinsics that you might need |
e9174d1e | 864 | fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option<ValueRef> { |
1a4d82fc JJ |
865 | macro_rules! ifn { |
866 | ($name:expr, fn() -> $ret:expr) => ( | |
e9174d1e | 867 | if key == $name { |
9346a6ac | 868 | let f = declare::declare_cfn(ccx, $name, Type::func(&[], &$ret), |
c1a9b12d | 869 | ccx.tcx().mk_nil()); |
e9174d1e | 870 | llvm::SetUnnamedAddr(f, false); |
1a4d82fc JJ |
871 | ccx.intrinsics().borrow_mut().insert($name, f.clone()); |
872 | return Some(f); | |
873 | } | |
874 | ); | |
7453a54e SL |
875 | ($name:expr, fn(...) -> $ret:expr) => ( |
876 | if key == $name { | |
877 | let f = declare::declare_cfn(ccx, $name, | |
878 | Type::variadic_func(&[], &$ret), | |
879 | ccx.tcx().mk_nil()); | |
880 | llvm::SetUnnamedAddr(f, false); | |
881 | ccx.intrinsics().borrow_mut().insert($name, f.clone()); | |
882 | return Some(f); | |
883 | } | |
884 | ); | |
1a4d82fc | 885 | ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( |
e9174d1e | 886 | if key == $name { |
9346a6ac | 887 | let f = declare::declare_cfn(ccx, $name, Type::func(&[$($arg),*], &$ret), |
c1a9b12d | 888 | ccx.tcx().mk_nil()); |
e9174d1e | 889 | llvm::SetUnnamedAddr(f, false); |
1a4d82fc JJ |
890 | ccx.intrinsics().borrow_mut().insert($name, f.clone()); |
891 | return Some(f); | |
892 | } | |
7453a54e | 893 | ); |
1a4d82fc JJ |
894 | } |
895 | macro_rules! mk_struct { | |
896 | ($($field_ty:expr),*) => (Type::struct_(ccx, &[$($field_ty),*], false)) | |
897 | } | |
898 | ||
899 | let i8p = Type::i8p(ccx); | |
900 | let void = Type::void(ccx); | |
901 | let i1 = Type::i1(ccx); | |
902 | let t_i8 = Type::i8(ccx); | |
903 | let t_i16 = Type::i16(ccx); | |
904 | let t_i32 = Type::i32(ccx); | |
905 | let t_i64 = Type::i64(ccx); | |
906 | let t_f32 = Type::f32(ccx); | |
907 | let t_f64 = Type::f64(ccx); | |
908 | ||
e9174d1e | 909 | ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); |
1a4d82fc JJ |
910 | ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); |
911 | ifn!("llvm.memcpy.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); | |
e9174d1e | 912 | ifn!("llvm.memmove.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); |
1a4d82fc JJ |
913 | ifn!("llvm.memmove.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); |
914 | ifn!("llvm.memmove.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); | |
e9174d1e | 915 | ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void); |
1a4d82fc JJ |
916 | ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void); |
917 | ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void); | |
918 | ||
919 | ifn!("llvm.trap", fn() -> void); | |
920 | ifn!("llvm.debugtrap", fn() -> void); | |
7453a54e | 921 | ifn!("llvm.frameaddress", fn(t_i32) -> i8p); |
1a4d82fc JJ |
922 | |
923 | ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); | |
924 | ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); | |
925 | ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32); | |
926 | ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64); | |
927 | ||
928 | ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32); | |
929 | ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64); | |
930 | ifn!("llvm.sin.f32", fn(t_f32) -> t_f32); | |
931 | ifn!("llvm.sin.f64", fn(t_f64) -> t_f64); | |
932 | ifn!("llvm.cos.f32", fn(t_f32) -> t_f32); | |
933 | ifn!("llvm.cos.f64", fn(t_f64) -> t_f64); | |
934 | ifn!("llvm.exp.f32", fn(t_f32) -> t_f32); | |
935 | ifn!("llvm.exp.f64", fn(t_f64) -> t_f64); | |
936 | ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32); | |
937 | ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64); | |
938 | ifn!("llvm.log.f32", fn(t_f32) -> t_f32); | |
939 | ifn!("llvm.log.f64", fn(t_f64) -> t_f64); | |
940 | ifn!("llvm.log10.f32", fn(t_f32) -> t_f32); | |
941 | ifn!("llvm.log10.f64", fn(t_f64) -> t_f64); | |
942 | ifn!("llvm.log2.f32", fn(t_f32) -> t_f32); | |
943 | ifn!("llvm.log2.f64", fn(t_f64) -> t_f64); | |
944 | ||
945 | ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32); | |
946 | ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64); | |
947 | ||
948 | ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32); | |
949 | ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64); | |
950 | ||
951 | ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); | |
952 | ifn!("llvm.floor.f64", fn(t_f64) -> t_f64); | |
953 | ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32); | |
954 | ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64); | |
955 | ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32); | |
956 | ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64); | |
957 | ||
62682a34 SL |
958 | ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32); |
959 | ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64); | |
960 | ifn!("llvm.round.f32", fn(t_f32) -> t_f32); | |
961 | ifn!("llvm.round.f64", fn(t_f64) -> t_f64); | |
962 | ||
1a4d82fc JJ |
963 | ifn!("llvm.rint.f32", fn(t_f32) -> t_f32); |
964 | ifn!("llvm.rint.f64", fn(t_f64) -> t_f64); | |
965 | ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32); | |
966 | ifn!("llvm.nearbyint.f64", fn(t_f64) -> t_f64); | |
967 | ||
968 | ifn!("llvm.ctpop.i8", fn(t_i8) -> t_i8); | |
969 | ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16); | |
970 | ifn!("llvm.ctpop.i32", fn(t_i32) -> t_i32); | |
971 | ifn!("llvm.ctpop.i64", fn(t_i64) -> t_i64); | |
972 | ||
973 | ifn!("llvm.ctlz.i8", fn(t_i8 , i1) -> t_i8); | |
974 | ifn!("llvm.ctlz.i16", fn(t_i16, i1) -> t_i16); | |
975 | ifn!("llvm.ctlz.i32", fn(t_i32, i1) -> t_i32); | |
976 | ifn!("llvm.ctlz.i64", fn(t_i64, i1) -> t_i64); | |
977 | ||
978 | ifn!("llvm.cttz.i8", fn(t_i8 , i1) -> t_i8); | |
979 | ifn!("llvm.cttz.i16", fn(t_i16, i1) -> t_i16); | |
980 | ifn!("llvm.cttz.i32", fn(t_i32, i1) -> t_i32); | |
981 | ifn!("llvm.cttz.i64", fn(t_i64, i1) -> t_i64); | |
982 | ||
983 | ifn!("llvm.bswap.i16", fn(t_i16) -> t_i16); | |
984 | ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32); | |
985 | ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); | |
986 | ||
987 | ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); | |
988 | ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); | |
989 | ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); | |
990 | ifn!("llvm.sadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); | |
991 | ||
992 | ifn!("llvm.uadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); | |
993 | ifn!("llvm.uadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); | |
994 | ifn!("llvm.uadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); | |
995 | ifn!("llvm.uadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); | |
996 | ||
997 | ifn!("llvm.ssub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); | |
998 | ifn!("llvm.ssub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); | |
999 | ifn!("llvm.ssub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); | |
1000 | ifn!("llvm.ssub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); | |
1001 | ||
1002 | ifn!("llvm.usub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); | |
1003 | ifn!("llvm.usub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); | |
1004 | ifn!("llvm.usub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); | |
1005 | ifn!("llvm.usub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); | |
1006 | ||
1007 | ifn!("llvm.smul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); | |
1008 | ifn!("llvm.smul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); | |
1009 | ifn!("llvm.smul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); | |
1010 | ifn!("llvm.smul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); | |
1011 | ||
1012 | ifn!("llvm.umul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); | |
1013 | ifn!("llvm.umul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); | |
1014 | ifn!("llvm.umul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); | |
1015 | ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); | |
1016 | ||
1017 | ifn!("llvm.lifetime.start", fn(t_i64,i8p) -> void); | |
1018 | ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void); | |
1019 | ||
1020 | ifn!("llvm.expect.i1", fn(i1, i1) -> i1); | |
c1a9b12d | 1021 | ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32); |
7453a54e SL |
1022 | ifn!("llvm.localescape", fn(...) -> void); |
1023 | ifn!("llvm.localrecover", fn(i8p, i8p, t_i32) -> i8p); | |
1024 | ifn!("llvm.x86.seh.recoverfp", fn(i8p, i8p) -> i8p); | |
1a4d82fc JJ |
1025 | |
1026 | // Some intrinsics were introduced in later versions of LLVM, but they have | |
62682a34 | 1027 | // fallbacks in libc or libm and such. |
1a4d82fc | 1028 | macro_rules! compatible_ifn { |
62682a34 SL |
1029 | ($name:expr, noop($cname:ident ($($arg:expr),*) -> void), $llvm_version:expr) => ( |
1030 | if unsafe { llvm::LLVMVersionMinor() >= $llvm_version } { | |
1031 | // The `if key == $name` is already in ifn! | |
1032 | ifn!($name, fn($($arg),*) -> void); | |
e9174d1e | 1033 | } else if key == $name { |
62682a34 SL |
1034 | let f = declare::declare_cfn(ccx, stringify!($cname), |
1035 | Type::func(&[$($arg),*], &void), | |
c1a9b12d | 1036 | ccx.tcx().mk_nil()); |
62682a34 SL |
1037 | llvm::SetLinkage(f, llvm::InternalLinkage); |
1038 | ||
1039 | let bld = ccx.builder(); | |
1040 | let llbb = unsafe { | |
1041 | llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), f, | |
1042 | "entry-block\0".as_ptr() as *const _) | |
1043 | }; | |
1044 | ||
1045 | bld.position_at_end(llbb); | |
1046 | bld.ret_void(); | |
1047 | ||
1048 | ccx.intrinsics().borrow_mut().insert($name, f.clone()); | |
1049 | return Some(f); | |
1050 | } | |
1051 | ); | |
1052 | ($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr, $llvm_version:expr) => ( | |
1053 | if unsafe { llvm::LLVMVersionMinor() >= $llvm_version } { | |
1054 | // The `if key == $name` is already in ifn! | |
1055 | ifn!($name, fn($($arg),*) -> $ret); | |
e9174d1e | 1056 | } else if key == $name { |
62682a34 SL |
1057 | let f = declare::declare_cfn(ccx, stringify!($cname), |
1058 | Type::func(&[$($arg),*], &$ret), | |
c1a9b12d | 1059 | ccx.tcx().mk_nil()); |
62682a34 SL |
1060 | ccx.intrinsics().borrow_mut().insert($name, f.clone()); |
1061 | return Some(f); | |
1062 | } | |
1a4d82fc JJ |
1063 | ) |
1064 | } | |
1065 | ||
62682a34 | 1066 | compatible_ifn!("llvm.assume", noop(llvmcompat_assume(i1) -> void), 6); |
1a4d82fc JJ |
1067 | |
1068 | if ccx.sess().opts.debuginfo != NoDebugInfo { | |
1069 | ifn!("llvm.dbg.declare", fn(Type::metadata(ccx), Type::metadata(ccx)) -> void); | |
1070 | ifn!("llvm.dbg.value", fn(Type::metadata(ccx), t_i64, Type::metadata(ccx)) -> void); | |
1071 | } | |
1072 | return None; | |
1073 | } |