]>
Commit | Line | Data |
---|---|---|
9346a6ac | 1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
1a4d82fc JJ |
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. | |
9346a6ac AL |
10 | //! Translate the completed AST to the LLVM IR. |
11 | //! | |
12 | //! Some functions here, such as trans_block and trans_expr, return a value -- | |
13 | //! the result of the translation to LLVM -- while others, such as trans_fn, | |
14 | //! trans_impl, and trans_item, are called only for the side effect of adding a | |
15 | //! particular definition to the LLVM IR output we're producing. | |
16 | //! | |
17 | //! Hopefully useful general knowledge about trans: | |
18 | //! | |
19 | //! * There's no way to find out the Ty type of a ValueRef. Doing so | |
20 | //! would be "trying to get the eggs out of an omelette" (credit: | |
21 | //! pcwalton). You can, instead, find out its TypeRef by calling val_ty, | |
22 | //! but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, | |
23 | //! int) and rec(x=int, y=int, z=int) will have the same TypeRef. | |
1a4d82fc JJ |
24 | |
25 | #![allow(non_camel_case_types)] | |
26 | ||
27 | pub use self::ValueOrigin::*; | |
1a4d82fc JJ |
28 | |
29 | use super::CrateTranslation; | |
30 | use super::ModuleTranslation; | |
31 | ||
c34b1796 | 32 | use back::link::mangle_exported_name; |
1a4d82fc JJ |
33 | use back::{link, abi}; |
34 | use lint; | |
9346a6ac | 35 | use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; |
1a4d82fc | 36 | use llvm; |
1a4d82fc | 37 | use middle::cfg; |
92a42be0 | 38 | use middle::cstore::CrateStore; |
b039eaaf | 39 | use middle::def_id::DefId; |
92a42be0 | 40 | use middle::infer; |
1a4d82fc | 41 | use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; |
1a4d82fc | 42 | use middle::weak_lang_items; |
b039eaaf | 43 | use middle::pat_util::simple_name; |
7453a54e SL |
44 | use middle::subst::{self, Substs}; |
45 | use middle::traits; | |
9cc50fc6 | 46 | use middle::ty::{self, Ty, TypeFoldable}; |
7453a54e | 47 | use middle::ty::adjustment::CustomCoerceUnsized; |
9cc50fc6 | 48 | use rustc::dep_graph::DepNode; |
e9174d1e | 49 | use rustc::front::map as hir_map; |
9cc50fc6 | 50 | use rustc::util::common::time; |
7453a54e | 51 | use rustc::mir::mir_map::MirMap; |
c1a9b12d | 52 | use session::config::{self, NoDebugInfo, FullDebugInfo}; |
1a4d82fc JJ |
53 | use session::Session; |
54 | use trans::_match; | |
55 | use trans::adt; | |
9cc50fc6 | 56 | use trans::assert_dep_graph; |
9346a6ac | 57 | use trans::attributes; |
1a4d82fc JJ |
58 | use trans::build::*; |
59 | use trans::builder::{Builder, noname}; | |
60 | use trans::callee; | |
c1a9b12d | 61 | use trans::cleanup::{self, CleanupMethods, DropHint}; |
1a4d82fc | 62 | use trans::closure; |
92a42be0 | 63 | use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_uint, C_integral}; |
7453a54e | 64 | use trans::collector::{self, TransItem, TransItemState, TransItemCollectionMode}; |
1a4d82fc | 65 | use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef}; |
e9174d1e SL |
66 | use trans::common::{CrateContext, DropFlagHintsMap, Field, FunctionContext}; |
67 | use trans::common::{Result, NodeIdAndSpan, VariantInfo}; | |
7453a54e | 68 | use trans::common::{node_id_type, return_type_is_void, fulfill_obligation}; |
c34b1796 | 69 | use trans::common::{type_is_immediate, type_is_zero_size, val_ty}; |
1a4d82fc JJ |
70 | use trans::common; |
71 | use trans::consts; | |
72 | use trans::context::SharedCrateContext; | |
73 | use trans::controlflow; | |
74 | use trans::datum; | |
85aaf69f | 75 | use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; |
9346a6ac | 76 | use trans::declare; |
1a4d82fc JJ |
77 | use trans::expr; |
78 | use trans::foreign; | |
79 | use trans::glue; | |
1a4d82fc JJ |
80 | use trans::intrinsic; |
81 | use trans::machine; | |
82 | use trans::machine::{llsize_of, llsize_of_real}; | |
83 | use trans::meth; | |
92a42be0 | 84 | use trans::mir; |
1a4d82fc JJ |
85 | use trans::monomorphize; |
86 | use trans::tvec; | |
87 | use trans::type_::Type; | |
88 | use trans::type_of; | |
89 | use trans::type_of::*; | |
90 | use trans::value::Value; | |
9cc50fc6 | 91 | use trans::Disr; |
1a4d82fc | 92 | use util::common::indenter; |
1a4d82fc | 93 | use util::sha2::Sha256; |
e9174d1e | 94 | use util::nodemap::{NodeMap, NodeSet}; |
1a4d82fc JJ |
95 | |
96 | use arena::TypedArena; | |
9346a6ac | 97 | use libc::c_uint; |
85aaf69f | 98 | use std::ffi::{CStr, CString}; |
1a4d82fc | 99 | use std::cell::{Cell, RefCell}; |
c1a9b12d | 100 | use std::collections::{HashMap, HashSet}; |
1a4d82fc JJ |
101 | use std::str; |
102 | use std::{i8, i16, i32, i64}; | |
7453a54e SL |
103 | use syntax::abi::Abi; |
104 | use syntax::codemap::{Span, DUMMY_SP}; | |
1a4d82fc | 105 | use syntax::parse::token::InternedString; |
b039eaaf SL |
106 | use syntax::attr::AttrMetaMethods; |
107 | use syntax::attr; | |
e9174d1e | 108 | use rustc_front; |
92a42be0 | 109 | use rustc_front::intravisit::{self, Visitor}; |
e9174d1e SL |
110 | use rustc_front::hir; |
111 | use syntax::ast; | |
1a4d82fc JJ |
112 | |
113 | thread_local! { | |
114 | static TASK_LOCAL_INSN_KEY: RefCell<Option<Vec<&'static str>>> = { | |
115 | RefCell::new(None) | |
116 | } | |
117 | } | |
118 | ||
92a42be0 SL |
119 | pub fn with_insn_ctxt<F>(blk: F) |
120 | where F: FnOnce(&[&'static str]) | |
1a4d82fc JJ |
121 | { |
122 | TASK_LOCAL_INSN_KEY.with(move |slot| { | |
85aaf69f | 123 | slot.borrow().as_ref().map(move |s| blk(s)); |
1a4d82fc JJ |
124 | }) |
125 | } | |
126 | ||
127 | pub fn init_insn_ctxt() { | |
128 | TASK_LOCAL_INSN_KEY.with(|slot| { | |
129 | *slot.borrow_mut() = Some(Vec::new()); | |
130 | }); | |
131 | } | |
132 | ||
133 | pub struct _InsnCtxt { | |
92a42be0 | 134 | _cannot_construct_outside_of_this_module: (), |
1a4d82fc JJ |
135 | } |
136 | ||
1a4d82fc JJ |
137 | impl Drop for _InsnCtxt { |
138 | fn drop(&mut self) { | |
139 | TASK_LOCAL_INSN_KEY.with(|slot| { | |
140 | match slot.borrow_mut().as_mut() { | |
92a42be0 SL |
141 | Some(ctx) => { |
142 | ctx.pop(); | |
143 | } | |
1a4d82fc JJ |
144 | None => {} |
145 | } | |
146 | }) | |
147 | } | |
148 | } | |
149 | ||
150 | pub fn push_ctxt(s: &'static str) -> _InsnCtxt { | |
151 | debug!("new InsnCtxt: {}", s); | |
152 | TASK_LOCAL_INSN_KEY.with(|slot| { | |
7453a54e SL |
153 | if let Some(ctx) = slot.borrow_mut().as_mut() { |
154 | ctx.push(s) | |
1a4d82fc JJ |
155 | } |
156 | }); | |
92a42be0 SL |
157 | _InsnCtxt { |
158 | _cannot_construct_outside_of_this_module: (), | |
159 | } | |
1a4d82fc JJ |
160 | } |
161 | ||
162 | pub struct StatRecorder<'a, 'tcx: 'a> { | |
163 | ccx: &'a CrateContext<'a, 'tcx>, | |
164 | name: Option<String>, | |
c34b1796 | 165 | istart: usize, |
1a4d82fc JJ |
166 | } |
167 | ||
168 | impl<'a, 'tcx> StatRecorder<'a, 'tcx> { | |
92a42be0 | 169 | pub fn new(ccx: &'a CrateContext<'a, 'tcx>, name: String) -> StatRecorder<'a, 'tcx> { |
1a4d82fc JJ |
170 | let istart = ccx.stats().n_llvm_insns.get(); |
171 | StatRecorder { | |
172 | ccx: ccx, | |
173 | name: Some(name), | |
174 | istart: istart, | |
175 | } | |
176 | } | |
177 | } | |
178 | ||
1a4d82fc JJ |
179 | impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { |
180 | fn drop(&mut self) { | |
181 | if self.ccx.sess().trans_stats() { | |
182 | let iend = self.ccx.stats().n_llvm_insns.get(); | |
92a42be0 SL |
183 | self.ccx |
184 | .stats() | |
185 | .fn_stats | |
186 | .borrow_mut() | |
187 | .push((self.name.take().unwrap(), iend - self.istart)); | |
1a4d82fc JJ |
188 | self.ccx.stats().n_fns.set(self.ccx.stats().n_fns.get() + 1); |
189 | // Reset LLVM insn count to avoid compound costs. | |
190 | self.ccx.stats().n_llvm_insns.set(self.istart); | |
191 | } | |
192 | } | |
193 | } | |
194 | ||
92a42be0 SL |
195 | fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
196 | fn_ty: Ty<'tcx>, | |
197 | name: &str, | |
198 | did: DefId) | |
199 | -> ValueRef { | |
7453a54e SL |
200 | if let Some(n) = ccx.externs().borrow().get(name) { |
201 | return *n; | |
1a4d82fc JJ |
202 | } |
203 | ||
9346a6ac | 204 | let f = declare::declare_rust_fn(ccx, name, fn_ty); |
1a4d82fc | 205 | |
92a42be0 | 206 | let attrs = ccx.sess().cstore.item_attrs(did); |
9346a6ac | 207 | attributes::from_fn_attrs(ccx, &attrs[..], f); |
1a4d82fc JJ |
208 | |
209 | ccx.externs().borrow_mut().insert(name.to_string(), f); | |
210 | f | |
211 | } | |
212 | ||
85aaf69f | 213 | pub fn self_type_for_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
e9174d1e | 214 | closure_id: DefId, |
85aaf69f | 215 | fn_ty: Ty<'tcx>) |
92a42be0 | 216 | -> Ty<'tcx> { |
85aaf69f SL |
217 | let closure_kind = ccx.tcx().closure_kind(closure_id); |
218 | match closure_kind { | |
219 | ty::FnClosureKind => { | |
c1a9b12d | 220 | ccx.tcx().mk_imm_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty) |
1a4d82fc | 221 | } |
85aaf69f | 222 | ty::FnMutClosureKind => { |
c1a9b12d | 223 | ccx.tcx().mk_mut_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty) |
1a4d82fc | 224 | } |
92a42be0 | 225 | ty::FnOnceClosureKind => fn_ty, |
1a4d82fc JJ |
226 | } |
227 | } | |
228 | ||
e9174d1e | 229 | pub fn kind_for_closure(ccx: &CrateContext, closure_id: DefId) -> ty::ClosureKind { |
c1a9b12d | 230 | *ccx.tcx().tables.borrow().closure_kinds.get(&closure_id).unwrap() |
1a4d82fc JJ |
231 | } |
232 | ||
92a42be0 SL |
233 | pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
234 | did: DefId, | |
235 | t: Ty<'tcx>) | |
236 | -> ValueRef { | |
237 | let name = ccx.sess().cstore.item_symbol(did); | |
1a4d82fc | 238 | let ty = type_of(ccx, t); |
7453a54e SL |
239 | if let Some(n) = ccx.externs().borrow_mut().get(&name) { |
240 | return *n; | |
1a4d82fc | 241 | } |
9346a6ac AL |
242 | // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? |
243 | // FIXME(nagisa): investigate whether it can be changed into define_global | |
244 | let c = declare::declare_global(ccx, &name[..], ty); | |
245 | // Thread-local statics in some other crate need to *always* be linked | |
246 | // against in a thread-local fashion, so we need to be sure to apply the | |
247 | // thread-local attribute locally if it was present remotely. If we | |
248 | // don't do this then linker errors can be generated where the linker | |
249 | // complains that one object files has a thread local version of the | |
250 | // symbol and another one doesn't. | |
c1a9b12d | 251 | for attr in ccx.tcx().get_attrs(did).iter() { |
9346a6ac AL |
252 | if attr.check_name("thread_local") { |
253 | llvm::set_thread_local(c, true); | |
85aaf69f | 254 | } |
1a4d82fc | 255 | } |
62682a34 SL |
256 | if ccx.use_dll_storage_attrs() { |
257 | llvm::SetDLLStorageClass(c, llvm::DLLImportStorageClass); | |
258 | } | |
9346a6ac AL |
259 | ccx.externs().borrow_mut().insert(name.to_string(), c); |
260 | return c; | |
1a4d82fc JJ |
261 | } |
262 | ||
92a42be0 | 263 | fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, info_ty: Ty<'tcx>, it: LangItem) -> DefId { |
1a4d82fc JJ |
264 | match bcx.tcx().lang_items.require(it) { |
265 | Ok(id) => id, | |
266 | Err(s) => { | |
62682a34 | 267 | bcx.sess().fatal(&format!("allocation of `{}` {}", info_ty, s)); |
1a4d82fc JJ |
268 | } |
269 | } | |
270 | } | |
271 | ||
272 | // The following malloc_raw_dyn* functions allocate a box to contain | |
273 | // a given type, but with a potentially dynamic size. | |
274 | ||
275 | pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
276 | llty_ptr: Type, | |
277 | info_ty: Ty<'tcx>, | |
278 | size: ValueRef, | |
85aaf69f SL |
279 | align: ValueRef, |
280 | debug_loc: DebugLoc) | |
1a4d82fc JJ |
281 | -> Result<'blk, 'tcx> { |
282 | let _icx = push_ctxt("malloc_raw_exchange"); | |
283 | ||
284 | // Allocate space: | |
285 | let r = callee::trans_lang_call(bcx, | |
92a42be0 SL |
286 | require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem), |
287 | &[size, align], | |
288 | None, | |
289 | debug_loc); | |
1a4d82fc JJ |
290 | |
291 | Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) | |
292 | } | |
293 | ||
1a4d82fc | 294 | |
92a42be0 SL |
295 | pub fn bin_op_to_icmp_predicate(ccx: &CrateContext, |
296 | op: hir::BinOp_, | |
297 | signed: bool) | |
85aaf69f SL |
298 | -> llvm::IntPredicate { |
299 | match op { | |
e9174d1e SL |
300 | hir::BiEq => llvm::IntEQ, |
301 | hir::BiNe => llvm::IntNE, | |
302 | hir::BiLt => if signed { llvm::IntSLT } else { llvm::IntULT }, | |
303 | hir::BiLe => if signed { llvm::IntSLE } else { llvm::IntULE }, | |
304 | hir::BiGt => if signed { llvm::IntSGT } else { llvm::IntUGT }, | |
305 | hir::BiGe => if signed { llvm::IntSGE } else { llvm::IntUGE }, | |
85aaf69f | 306 | op => { |
92a42be0 SL |
307 | ccx.sess() |
308 | .bug(&format!("comparison_op_to_icmp_predicate: expected comparison operator, \ | |
309 | found {:?}", | |
310 | op)); | |
85aaf69f | 311 | } |
1a4d82fc JJ |
312 | } |
313 | } | |
314 | ||
92a42be0 | 315 | pub fn bin_op_to_fcmp_predicate(ccx: &CrateContext, op: hir::BinOp_) -> llvm::RealPredicate { |
85aaf69f | 316 | match op { |
e9174d1e SL |
317 | hir::BiEq => llvm::RealOEQ, |
318 | hir::BiNe => llvm::RealUNE, | |
319 | hir::BiLt => llvm::RealOLT, | |
320 | hir::BiLe => llvm::RealOLE, | |
321 | hir::BiGt => llvm::RealOGT, | |
322 | hir::BiGe => llvm::RealOGE, | |
85aaf69f | 323 | op => { |
92a42be0 SL |
324 | ccx.sess() |
325 | .bug(&format!("comparison_op_to_fcmp_predicate: expected comparison operator, \ | |
326 | found {:?}", | |
327 | op)); | |
328 | } | |
329 | } | |
330 | } | |
331 | ||
332 | pub fn compare_fat_ptrs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
333 | lhs_addr: ValueRef, | |
334 | lhs_extra: ValueRef, | |
335 | rhs_addr: ValueRef, | |
336 | rhs_extra: ValueRef, | |
337 | _t: Ty<'tcx>, | |
338 | op: hir::BinOp_, | |
339 | debug_loc: DebugLoc) | |
340 | -> ValueRef { | |
341 | match op { | |
342 | hir::BiEq => { | |
343 | let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc); | |
344 | let extra_eq = ICmp(bcx, llvm::IntEQ, lhs_extra, rhs_extra, debug_loc); | |
345 | And(bcx, addr_eq, extra_eq, debug_loc) | |
346 | } | |
347 | hir::BiNe => { | |
348 | let addr_eq = ICmp(bcx, llvm::IntNE, lhs_addr, rhs_addr, debug_loc); | |
349 | let extra_eq = ICmp(bcx, llvm::IntNE, lhs_extra, rhs_extra, debug_loc); | |
350 | Or(bcx, addr_eq, extra_eq, debug_loc) | |
351 | } | |
352 | hir::BiLe | hir::BiLt | hir::BiGe | hir::BiGt => { | |
353 | // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1) | |
354 | let (op, strict_op) = match op { | |
355 | hir::BiLt => (llvm::IntULT, llvm::IntULT), | |
356 | hir::BiLe => (llvm::IntULE, llvm::IntULT), | |
357 | hir::BiGt => (llvm::IntUGT, llvm::IntUGT), | |
358 | hir::BiGe => (llvm::IntUGE, llvm::IntUGT), | |
359 | _ => unreachable!(), | |
360 | }; | |
361 | ||
362 | let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc); | |
363 | let extra_op = ICmp(bcx, op, lhs_extra, rhs_extra, debug_loc); | |
364 | let addr_eq_extra_op = And(bcx, addr_eq, extra_op, debug_loc); | |
365 | ||
366 | let addr_strict = ICmp(bcx, strict_op, lhs_addr, rhs_addr, debug_loc); | |
367 | Or(bcx, addr_strict, addr_eq_extra_op, debug_loc) | |
368 | } | |
369 | _ => { | |
370 | bcx.tcx().sess.bug("unexpected fat ptr binop"); | |
85aaf69f SL |
371 | } |
372 | } | |
373 | } | |
1a4d82fc | 374 | |
85aaf69f | 375 | pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, |
1a4d82fc JJ |
376 | lhs: ValueRef, |
377 | rhs: ValueRef, | |
378 | t: Ty<'tcx>, | |
e9174d1e | 379 | op: hir::BinOp_, |
85aaf69f SL |
380 | debug_loc: DebugLoc) |
381 | -> ValueRef { | |
1a4d82fc | 382 | match t.sty { |
62682a34 | 383 | ty::TyTuple(ref tys) if tys.is_empty() => { |
85aaf69f SL |
384 | // We don't need to do actual comparisons for nil. |
385 | // () == () holds but () < () does not. | |
386 | match op { | |
e9174d1e SL |
387 | hir::BiEq | hir::BiLe | hir::BiGe => return C_bool(bcx.ccx(), true), |
388 | hir::BiNe | hir::BiLt | hir::BiGt => return C_bool(bcx.ccx(), false), | |
85aaf69f | 389 | // refinements would be nice |
92a42be0 | 390 | _ => bcx.sess().bug("compare_scalar_types: must be a comparison operator"), |
85aaf69f | 391 | } |
1a4d82fc | 392 | } |
62682a34 | 393 | ty::TyBareFn(..) | ty::TyBool | ty::TyUint(_) | ty::TyChar => { |
92a42be0 SL |
394 | ICmp(bcx, |
395 | bin_op_to_icmp_predicate(bcx.ccx(), op, false), | |
396 | lhs, | |
397 | rhs, | |
398 | debug_loc) | |
85aaf69f | 399 | } |
62682a34 | 400 | ty::TyRawPtr(mt) if common::type_is_sized(bcx.tcx(), mt.ty) => { |
92a42be0 SL |
401 | ICmp(bcx, |
402 | bin_op_to_icmp_predicate(bcx.ccx(), op, false), | |
403 | lhs, | |
404 | rhs, | |
405 | debug_loc) | |
406 | } | |
407 | ty::TyRawPtr(_) => { | |
408 | let lhs_addr = Load(bcx, GEPi(bcx, lhs, &[0, abi::FAT_PTR_ADDR])); | |
409 | let lhs_extra = Load(bcx, GEPi(bcx, lhs, &[0, abi::FAT_PTR_EXTRA])); | |
410 | ||
411 | let rhs_addr = Load(bcx, GEPi(bcx, rhs, &[0, abi::FAT_PTR_ADDR])); | |
412 | let rhs_extra = Load(bcx, GEPi(bcx, rhs, &[0, abi::FAT_PTR_EXTRA])); | |
413 | compare_fat_ptrs(bcx, | |
414 | lhs_addr, | |
415 | lhs_extra, | |
416 | rhs_addr, | |
417 | rhs_extra, | |
418 | t, | |
419 | op, | |
420 | debug_loc) | |
85aaf69f | 421 | } |
62682a34 | 422 | ty::TyInt(_) => { |
92a42be0 SL |
423 | ICmp(bcx, |
424 | bin_op_to_icmp_predicate(bcx.ccx(), op, true), | |
425 | lhs, | |
426 | rhs, | |
427 | debug_loc) | |
85aaf69f | 428 | } |
62682a34 | 429 | ty::TyFloat(_) => { |
92a42be0 SL |
430 | FCmp(bcx, |
431 | bin_op_to_fcmp_predicate(bcx.ccx(), op), | |
432 | lhs, | |
433 | rhs, | |
434 | debug_loc) | |
85aaf69f SL |
435 | } |
436 | // Should never get here, because t is scalar. | |
92a42be0 | 437 | _ => bcx.sess().bug("non-scalar type passed to compare_scalar_types"), |
1a4d82fc JJ |
438 | } |
439 | } | |
440 | ||
85aaf69f SL |
441 | pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, |
442 | lhs: ValueRef, | |
443 | rhs: ValueRef, | |
444 | t: Ty<'tcx>, | |
e9174d1e SL |
445 | ret_ty: Type, |
446 | op: hir::BinOp_, | |
85aaf69f SL |
447 | debug_loc: DebugLoc) |
448 | -> ValueRef { | |
449 | let signed = match t.sty { | |
62682a34 | 450 | ty::TyFloat(_) => { |
e9174d1e SL |
451 | let cmp = bin_op_to_fcmp_predicate(bcx.ccx(), op); |
452 | return SExt(bcx, FCmp(bcx, cmp, lhs, rhs, debug_loc), ret_ty); | |
1a4d82fc | 453 | }, |
62682a34 SL |
454 | ty::TyUint(_) => false, |
455 | ty::TyInt(_) => true, | |
85aaf69f SL |
456 | _ => bcx.sess().bug("compare_simd_types: invalid SIMD type"), |
457 | }; | |
458 | ||
459 | let cmp = bin_op_to_icmp_predicate(bcx.ccx(), op, signed); | |
460 | // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension | |
461 | // to get the correctly sized type. This will compile to a single instruction | |
462 | // once the IR is converted to assembly if the SIMD instruction is supported | |
463 | // by the target architecture. | |
e9174d1e | 464 | SExt(bcx, ICmp(bcx, cmp, lhs, rhs, debug_loc), ret_ty) |
1a4d82fc JJ |
465 | } |
466 | ||
467 | // Iterates through the elements of a structural type. | |
468 | pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, | |
469 | av: ValueRef, | |
470 | t: Ty<'tcx>, | |
471 | mut f: F) | |
92a42be0 SL |
472 | -> Block<'blk, 'tcx> |
473 | where F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx> | |
1a4d82fc JJ |
474 | { |
475 | let _icx = push_ctxt("iter_structural_ty"); | |
476 | ||
477 | fn iter_variant<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, | |
478 | repr: &adt::Repr<'tcx>, | |
92a42be0 | 479 | av: adt::MaybeSizedValue, |
e9174d1e | 480 | variant: ty::VariantDef<'tcx>, |
85aaf69f | 481 | substs: &Substs<'tcx>, |
1a4d82fc | 482 | f: &mut F) |
92a42be0 SL |
483 | -> Block<'blk, 'tcx> |
484 | where F: FnMut(Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx> | |
1a4d82fc JJ |
485 | { |
486 | let _icx = push_ctxt("iter_variant"); | |
487 | let tcx = cx.tcx(); | |
488 | let mut cx = cx; | |
489 | ||
e9174d1e SL |
490 | for (i, field) in variant.fields.iter().enumerate() { |
491 | let arg = monomorphize::field_ty(tcx, substs, field); | |
92a42be0 | 492 | cx = f(cx, |
9cc50fc6 | 493 | adt::trans_field_ptr(cx, repr, av, Disr::from(variant.disr_val), i), |
92a42be0 | 494 | arg); |
1a4d82fc JJ |
495 | } |
496 | return cx; | |
497 | } | |
498 | ||
92a42be0 SL |
499 | let value = if common::type_is_sized(cx.tcx(), t) { |
500 | adt::MaybeSizedValue::sized(av) | |
1a4d82fc | 501 | } else { |
92a42be0 SL |
502 | let data = Load(cx, expr::get_dataptr(cx, av)); |
503 | let info = Load(cx, expr::get_meta(cx, av)); | |
504 | adt::MaybeSizedValue::unsized_(data, info) | |
1a4d82fc JJ |
505 | }; |
506 | ||
507 | let mut cx = cx; | |
508 | match t.sty { | |
92a42be0 SL |
509 | ty::TyStruct(..) => { |
510 | let repr = adt::represent_type(cx.ccx(), t); | |
511 | let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None); | |
512 | for (i, &Field(_, field_ty)) in fields.iter().enumerate() { | |
7453a54e | 513 | let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i); |
92a42be0 SL |
514 | |
515 | let val = if common::type_is_sized(cx.tcx(), field_ty) { | |
516 | llfld_a | |
517 | } else { | |
518 | let scratch = datum::rvalue_scratch_datum(cx, field_ty, "__fat_ptr_iter"); | |
519 | Store(cx, llfld_a, expr::get_dataptr(cx, scratch.val)); | |
520 | Store(cx, value.meta, expr::get_meta(cx, scratch.val)); | |
521 | scratch.val | |
522 | }; | |
523 | cx = f(cx, val, field_ty); | |
524 | } | |
525 | } | |
526 | ty::TyClosure(_, ref substs) => { | |
527 | let repr = adt::represent_type(cx.ccx(), t); | |
528 | for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() { | |
7453a54e | 529 | let llupvar = adt::trans_field_ptr(cx, &repr, value, Disr(0), i); |
92a42be0 SL |
530 | cx = f(cx, llupvar, upvar_ty); |
531 | } | |
532 | } | |
533 | ty::TyArray(_, n) => { | |
534 | let (base, len) = tvec::get_fixed_base_and_len(cx, value.value, n); | |
535 | let unit_ty = t.sequence_element_type(cx.tcx()); | |
536 | cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f); | |
537 | } | |
538 | ty::TySlice(_) | ty::TyStr => { | |
539 | let unit_ty = t.sequence_element_type(cx.tcx()); | |
540 | cx = tvec::iter_vec_raw(cx, value.value, unit_ty, value.meta, f); | |
541 | } | |
542 | ty::TyTuple(ref args) => { | |
543 | let repr = adt::represent_type(cx.ccx(), t); | |
544 | for (i, arg) in args.iter().enumerate() { | |
7453a54e | 545 | let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr(0), i); |
92a42be0 SL |
546 | cx = f(cx, llfld_a, *arg); |
547 | } | |
548 | } | |
549 | ty::TyEnum(en, substs) => { | |
550 | let fcx = cx.fcx; | |
551 | let ccx = fcx.ccx; | |
552 | ||
553 | let repr = adt::represent_type(ccx, t); | |
554 | let n_variants = en.variants.len(); | |
555 | ||
556 | // NB: we must hit the discriminant first so that structural | |
557 | // comparison know not to proceed when the discriminants differ. | |
558 | ||
7453a54e | 559 | match adt::trans_switch(cx, &repr, av, false) { |
92a42be0 SL |
560 | (_match::Single, None) => { |
561 | if n_variants != 0 { | |
562 | assert!(n_variants == 1); | |
7453a54e | 563 | cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av), |
92a42be0 SL |
564 | &en.variants[0], substs, &mut f); |
565 | } | |
566 | } | |
567 | (_match::Switch, Some(lldiscrim_a)) => { | |
568 | cx = f(cx, lldiscrim_a, cx.tcx().types.isize); | |
569 | ||
570 | // Create a fall-through basic block for the "else" case of | |
571 | // the switch instruction we're about to generate. Note that | |
572 | // we do **not** use an Unreachable instruction here, even | |
573 | // though most of the time this basic block will never be hit. | |
574 | // | |
575 | // When an enum is dropped it's contents are currently | |
576 | // overwritten to DTOR_DONE, which means the discriminant | |
577 | // could have changed value to something not within the actual | |
578 | // range of the discriminant. Currently this function is only | |
579 | // used for drop glue so in this case we just return quickly | |
580 | // from the outer function, and any other use case will only | |
581 | // call this for an already-valid enum in which case the `ret | |
582 | // void` will never be hit. | |
583 | let ret_void_cx = fcx.new_temp_block("enum-iter-ret-void"); | |
584 | RetVoid(ret_void_cx, DebugLoc::None); | |
585 | let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); | |
586 | let next_cx = fcx.new_temp_block("enum-iter-next"); | |
587 | ||
588 | for variant in &en.variants { | |
589 | let variant_cx = fcx.new_temp_block(&format!("enum-iter-variant-{}", | |
590 | &variant.disr_val | |
591 | .to_string())); | |
7453a54e | 592 | let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val)); |
92a42be0 SL |
593 | AddCase(llswitch, case_val, variant_cx.llbb); |
594 | let variant_cx = iter_variant(variant_cx, | |
7453a54e | 595 | &repr, |
92a42be0 SL |
596 | value, |
597 | variant, | |
598 | substs, | |
599 | &mut f); | |
600 | Br(variant_cx, next_cx.llbb, DebugLoc::None); | |
601 | } | |
602 | cx = next_cx; | |
603 | } | |
604 | _ => ccx.sess().unimpl("value from adt::trans_switch in iter_structural_ty"), | |
605 | } | |
606 | } | |
607 | _ => { | |
608 | cx.sess().unimpl(&format!("type in iter_structural_ty: {}", t)) | |
609 | } | |
1a4d82fc JJ |
610 | } |
611 | return cx; | |
612 | } | |
613 | ||
92a42be0 SL |
614 | |
615 | /// Retrieve the information we are losing (making dynamic) in an unsizing | |
616 | /// adjustment. | |
617 | /// | |
618 | /// The `old_info` argument is a bit funny. It is intended for use | |
619 | /// in an upcast, where the new vtable for an object will be drived | |
620 | /// from the old one. | |
621 | pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, | |
622 | source: Ty<'tcx>, | |
623 | target: Ty<'tcx>, | |
624 | old_info: Option<ValueRef>, | |
625 | param_substs: &'tcx Substs<'tcx>) | |
626 | -> ValueRef { | |
627 | let (source, target) = ccx.tcx().struct_lockstep_tails(source, target); | |
628 | match (&source.sty, &target.sty) { | |
629 | (&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len), | |
630 | (&ty::TyTrait(_), &ty::TyTrait(_)) => { | |
631 | // For now, upcasts are limited to changes in marker | |
632 | // traits, and hence never actually require an actual | |
633 | // change to the vtable. | |
634 | old_info.expect("unsized_info: missing old info for trait upcast") | |
635 | } | |
636 | (_, &ty::TyTrait(box ty::TraitTy { ref principal, .. })) => { | |
637 | // Note that we preserve binding levels here: | |
638 | let substs = principal.0.substs.with_self_ty(source).erase_regions(); | |
639 | let substs = ccx.tcx().mk_substs(substs); | |
640 | let trait_ref = ty::Binder(ty::TraitRef { | |
641 | def_id: principal.def_id(), | |
642 | substs: substs, | |
643 | }); | |
644 | consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs), | |
645 | Type::vtable_ptr(ccx)) | |
646 | } | |
647 | _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {:?} -> {:?}", | |
648 | source, | |
649 | target)), | |
650 | } | |
651 | } | |
652 | ||
653 | /// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer. | |
654 | pub fn unsize_thin_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
655 | src: ValueRef, | |
656 | src_ty: Ty<'tcx>, | |
657 | dst_ty: Ty<'tcx>) | |
658 | -> (ValueRef, ValueRef) { | |
659 | debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); | |
660 | match (&src_ty.sty, &dst_ty.sty) { | |
661 | (&ty::TyBox(a), &ty::TyBox(b)) | | |
662 | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), | |
663 | &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) | | |
664 | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), | |
665 | &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) | | |
666 | (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }), | |
667 | &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => { | |
668 | assert!(common::type_is_sized(bcx.tcx(), a)); | |
669 | let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), b).ptr_to(); | |
670 | (PointerCast(bcx, src, ptr_ty), | |
671 | unsized_info(bcx.ccx(), a, b, None, bcx.fcx.param_substs)) | |
672 | } | |
673 | _ => bcx.sess().bug("unsize_thin_ptr: called on bad types"), | |
674 | } | |
675 | } | |
676 | ||
677 | /// Coerce `src`, which is a reference to a value of type `src_ty`, | |
678 | /// to a value of type `dst_ty` and store the result in `dst` | |
679 | pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
680 | src: ValueRef, | |
681 | src_ty: Ty<'tcx>, | |
682 | dst: ValueRef, | |
683 | dst_ty: Ty<'tcx>) { | |
684 | match (&src_ty.sty, &dst_ty.sty) { | |
685 | (&ty::TyBox(..), &ty::TyBox(..)) | | |
686 | (&ty::TyRef(..), &ty::TyRef(..)) | | |
687 | (&ty::TyRef(..), &ty::TyRawPtr(..)) | | |
688 | (&ty::TyRawPtr(..), &ty::TyRawPtr(..)) => { | |
689 | let (base, info) = if common::type_is_fat_ptr(bcx.tcx(), src_ty) { | |
690 | // fat-ptr to fat-ptr unsize preserves the vtable | |
691 | load_fat_ptr(bcx, src, src_ty) | |
692 | } else { | |
693 | let base = load_ty(bcx, src, src_ty); | |
694 | unsize_thin_ptr(bcx, base, src_ty, dst_ty) | |
695 | }; | |
696 | store_fat_ptr(bcx, base, info, dst, dst_ty); | |
697 | } | |
698 | ||
699 | // This can be extended to enums and tuples in the future. | |
700 | // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) | | |
701 | (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) => { | |
702 | assert_eq!(def_a, def_b); | |
703 | ||
704 | let src_repr = adt::represent_type(bcx.ccx(), src_ty); | |
705 | let src_fields = match &*src_repr { | |
706 | &adt::Repr::Univariant(ref s, _) => &s.fields, | |
707 | _ => bcx.sess().bug("struct has non-univariant repr"), | |
708 | }; | |
709 | let dst_repr = adt::represent_type(bcx.ccx(), dst_ty); | |
710 | let dst_fields = match &*dst_repr { | |
711 | &adt::Repr::Univariant(ref s, _) => &s.fields, | |
712 | _ => bcx.sess().bug("struct has non-univariant repr"), | |
713 | }; | |
714 | ||
715 | let src = adt::MaybeSizedValue::sized(src); | |
716 | let dst = adt::MaybeSizedValue::sized(dst); | |
717 | ||
718 | let iter = src_fields.iter().zip(dst_fields).enumerate(); | |
719 | for (i, (src_fty, dst_fty)) in iter { | |
720 | if type_is_zero_size(bcx.ccx(), dst_fty) { | |
721 | continue; | |
722 | } | |
723 | ||
9cc50fc6 SL |
724 | let src_f = adt::trans_field_ptr(bcx, &src_repr, src, Disr(0), i); |
725 | let dst_f = adt::trans_field_ptr(bcx, &dst_repr, dst, Disr(0), i); | |
92a42be0 SL |
726 | if src_fty == dst_fty { |
727 | memcpy_ty(bcx, dst_f, src_f, src_fty); | |
728 | } else { | |
729 | coerce_unsized_into(bcx, src_f, src_fty, dst_f, dst_fty); | |
730 | } | |
731 | } | |
732 | } | |
733 | _ => bcx.sess().bug(&format!("coerce_unsized_into: invalid coercion {:?} -> {:?}", | |
734 | src_ty, | |
735 | dst_ty)), | |
736 | } | |
1a4d82fc JJ |
737 | } |
738 | ||
7453a54e SL |
739 | pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, |
740 | source_ty: Ty<'tcx>, | |
741 | target_ty: Ty<'tcx>) | |
742 | -> CustomCoerceUnsized { | |
743 | let trait_substs = Substs::erased(subst::VecPerParamSpace::new(vec![target_ty], | |
744 | vec![source_ty], | |
745 | Vec::new())); | |
746 | let trait_ref = ty::Binder(ty::TraitRef { | |
747 | def_id: ccx.tcx().lang_items.coerce_unsized_trait().unwrap(), | |
748 | substs: ccx.tcx().mk_substs(trait_substs) | |
749 | }); | |
750 | ||
751 | match fulfill_obligation(ccx, DUMMY_SP, trait_ref) { | |
752 | traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { | |
753 | ccx.tcx().custom_coerce_unsized_kind(impl_def_id) | |
754 | } | |
755 | vtable => { | |
756 | ccx.sess().bug(&format!("invalid CoerceUnsized vtable: {:?}", | |
757 | vtable)); | |
758 | } | |
759 | } | |
760 | } | |
761 | ||
92a42be0 SL |
762 | pub fn cast_shift_expr_rhs(cx: Block, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef) -> ValueRef { |
763 | cast_shift_rhs(op, lhs, rhs, |a, b| Trunc(cx, a, b), |a, b| ZExt(cx, a, b)) | |
764 | } | |
765 | ||
766 | pub fn cast_shift_const_rhs(op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef) -> ValueRef { | |
767 | cast_shift_rhs(op, | |
768 | lhs, | |
769 | rhs, | |
1a4d82fc JJ |
770 | |a, b| unsafe { llvm::LLVMConstTrunc(a, b.to_ref()) }, |
771 | |a, b| unsafe { llvm::LLVMConstZExt(a, b.to_ref()) }) | |
772 | } | |
773 | ||
e9174d1e | 774 | fn cast_shift_rhs<F, G>(op: hir::BinOp_, |
c34b1796 AL |
775 | lhs: ValueRef, |
776 | rhs: ValueRef, | |
777 | trunc: F, | |
778 | zext: G) | |
92a42be0 SL |
779 | -> ValueRef |
780 | where F: FnOnce(ValueRef, Type) -> ValueRef, | |
781 | G: FnOnce(ValueRef, Type) -> ValueRef | |
1a4d82fc JJ |
782 | { |
783 | // Shifts may have any size int on the rhs | |
e9174d1e | 784 | if rustc_front::util::is_shift_binop(op) { |
85aaf69f SL |
785 | let mut rhs_llty = val_ty(rhs); |
786 | let mut lhs_llty = val_ty(lhs); | |
92a42be0 SL |
787 | if rhs_llty.kind() == Vector { |
788 | rhs_llty = rhs_llty.element_type() | |
789 | } | |
790 | if lhs_llty.kind() == Vector { | |
791 | lhs_llty = lhs_llty.element_type() | |
792 | } | |
85aaf69f SL |
793 | let rhs_sz = rhs_llty.int_width(); |
794 | let lhs_sz = lhs_llty.int_width(); | |
795 | if lhs_sz < rhs_sz { | |
796 | trunc(rhs, lhs_llty) | |
797 | } else if lhs_sz > rhs_sz { | |
798 | // FIXME (#1877: If shifting by negative | |
799 | // values becomes not undefined then this is wrong. | |
800 | zext(rhs, lhs_llty) | |
1a4d82fc JJ |
801 | } else { |
802 | rhs | |
803 | } | |
85aaf69f SL |
804 | } else { |
805 | rhs | |
1a4d82fc JJ |
806 | } |
807 | } | |
808 | ||
9346a6ac | 809 | pub fn llty_and_min_for_signed_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, |
92a42be0 SL |
810 | val_t: Ty<'tcx>) |
811 | -> (Type, u64) { | |
9346a6ac | 812 | match val_t.sty { |
62682a34 | 813 | ty::TyInt(t) => { |
9346a6ac AL |
814 | let llty = Type::int_from_ty(cx.ccx(), t); |
815 | let min = match t { | |
7453a54e SL |
816 | ast::IntTy::Is if llty == Type::i32(cx.ccx()) => i32::MIN as u64, |
817 | ast::IntTy::Is => i64::MIN as u64, | |
818 | ast::IntTy::I8 => i8::MIN as u64, | |
819 | ast::IntTy::I16 => i16::MIN as u64, | |
820 | ast::IntTy::I32 => i32::MIN as u64, | |
821 | ast::IntTy::I64 => i64::MIN as u64, | |
9346a6ac AL |
822 | }; |
823 | (llty, min) | |
824 | } | |
825 | _ => unreachable!(), | |
826 | } | |
827 | } | |
828 | ||
92a42be0 SL |
829 | pub fn fail_if_zero_or_overflows<'blk, 'tcx>(cx: Block<'blk, 'tcx>, |
830 | call_info: NodeIdAndSpan, | |
831 | divrem: hir::BinOp, | |
832 | lhs: ValueRef, | |
833 | rhs: ValueRef, | |
834 | rhs_t: Ty<'tcx>) | |
835 | -> Block<'blk, 'tcx> { | |
e9174d1e | 836 | let (zero_text, overflow_text) = if divrem.node == hir::BiDiv { |
1a4d82fc JJ |
837 | ("attempted to divide by zero", |
838 | "attempted to divide with overflow") | |
839 | } else { | |
840 | ("attempted remainder with a divisor of zero", | |
841 | "attempted remainder with overflow") | |
842 | }; | |
85aaf69f SL |
843 | let debug_loc = call_info.debug_loc(); |
844 | ||
1a4d82fc | 845 | let (is_zero, is_signed) = match rhs_t.sty { |
62682a34 | 846 | ty::TyInt(t) => { |
c34b1796 | 847 | let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0, false); |
85aaf69f | 848 | (ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), true) |
1a4d82fc | 849 | } |
62682a34 | 850 | ty::TyUint(t) => { |
c34b1796 | 851 | let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0, false); |
85aaf69f | 852 | (ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), false) |
1a4d82fc | 853 | } |
e9174d1e | 854 | ty::TyStruct(def, _) if def.is_simd() => { |
c34b1796 | 855 | let mut res = C_bool(cx.ccx(), false); |
92a42be0 SL |
856 | for i in 0..rhs_t.simd_size(cx.tcx()) { |
857 | res = Or(cx, | |
858 | res, | |
859 | IsNull(cx, ExtractElement(cx, rhs, C_int(cx.ccx(), i as i64))), | |
860 | debug_loc); | |
c34b1796 AL |
861 | } |
862 | (res, false) | |
863 | } | |
1a4d82fc | 864 | _ => { |
62682a34 | 865 | cx.sess().bug(&format!("fail-if-zero on unexpected type: {}", rhs_t)); |
1a4d82fc JJ |
866 | } |
867 | }; | |
868 | let bcx = with_cond(cx, is_zero, |bcx| { | |
85aaf69f | 869 | controlflow::trans_fail(bcx, call_info, InternedString::new(zero_text)) |
1a4d82fc JJ |
870 | }); |
871 | ||
872 | // To quote LLVM's documentation for the sdiv instruction: | |
873 | // | |
874 | // Division by zero leads to undefined behavior. Overflow also leads | |
875 | // to undefined behavior; this is a rare case, but can occur, for | |
876 | // example, by doing a 32-bit division of -2147483648 by -1. | |
877 | // | |
878 | // In order to avoid undefined behavior, we perform runtime checks for | |
879 | // signed division/remainder which would trigger overflow. For unsigned | |
880 | // integers, no action beyond checking for zero need be taken. | |
881 | if is_signed { | |
9346a6ac | 882 | let (llty, min) = llty_and_min_for_signed_ty(cx, rhs_t); |
92a42be0 SL |
883 | let minus_one = ICmp(bcx, |
884 | llvm::IntEQ, | |
885 | rhs, | |
886 | C_integral(llty, !0, false), | |
887 | debug_loc); | |
1a4d82fc | 888 | with_cond(bcx, minus_one, |bcx| { |
92a42be0 SL |
889 | let is_min = ICmp(bcx, |
890 | llvm::IntEQ, | |
891 | lhs, | |
892 | C_integral(llty, min, true), | |
893 | debug_loc); | |
1a4d82fc | 894 | with_cond(bcx, is_min, |bcx| { |
92a42be0 | 895 | controlflow::trans_fail(bcx, call_info, InternedString::new(overflow_text)) |
1a4d82fc JJ |
896 | }) |
897 | }) | |
898 | } else { | |
899 | bcx | |
900 | } | |
901 | } | |
902 | ||
903 | pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
92a42be0 SL |
904 | did: DefId, |
905 | t: Ty<'tcx>) | |
906 | -> ValueRef { | |
907 | let name = ccx.sess().cstore.item_symbol(did); | |
1a4d82fc | 908 | match t.sty { |
62682a34 | 909 | ty::TyBareFn(_, ref fn_ty) => { |
1a4d82fc | 910 | match ccx.sess().target.target.adjust_abi(fn_ty.abi) { |
7453a54e | 911 | Abi::Rust | Abi::RustCall => { |
85aaf69f | 912 | get_extern_rust_fn(ccx, t, &name[..], did) |
1a4d82fc | 913 | } |
7453a54e | 914 | Abi::RustIntrinsic | Abi::PlatformIntrinsic => { |
1a4d82fc JJ |
915 | ccx.sess().bug("unexpected intrinsic in trans_external_path") |
916 | } | |
917 | _ => { | |
92a42be0 | 918 | let attrs = ccx.sess().cstore.item_attrs(did); |
e9174d1e | 919 | foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name, &attrs) |
1a4d82fc JJ |
920 | } |
921 | } | |
922 | } | |
923 | _ => { | |
924 | get_extern_const(ccx, did, t) | |
925 | } | |
926 | } | |
927 | } | |
928 | ||
929 | pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
930 | llfn: ValueRef, | |
931 | llargs: &[ValueRef], | |
932 | fn_ty: Ty<'tcx>, | |
85aaf69f | 933 | debug_loc: DebugLoc) |
1a4d82fc JJ |
934 | -> (ValueRef, Block<'blk, 'tcx>) { |
935 | let _icx = push_ctxt("invoke_"); | |
936 | if bcx.unreachable.get() { | |
937 | return (C_null(Type::i8(bcx.ccx())), bcx); | |
938 | } | |
939 | ||
9346a6ac | 940 | let attributes = attributes::from_fn_type(bcx.ccx(), fn_ty); |
1a4d82fc JJ |
941 | |
942 | match bcx.opt_node_id { | |
943 | None => { | |
944 | debug!("invoke at ???"); | |
945 | } | |
946 | Some(id) => { | |
947 | debug!("invoke at {}", bcx.tcx().map.node_to_string(id)); | |
948 | } | |
949 | } | |
950 | ||
951 | if need_invoke(bcx) { | |
952 | debug!("invoking {} at {:?}", bcx.val_to_string(llfn), bcx.llbb); | |
85aaf69f | 953 | for &llarg in llargs { |
1a4d82fc JJ |
954 | debug!("arg: {}", bcx.val_to_string(llarg)); |
955 | } | |
956 | let normal_bcx = bcx.fcx.new_temp_block("normal-return"); | |
957 | let landing_pad = bcx.fcx.get_landing_pad(); | |
958 | ||
1a4d82fc JJ |
959 | let llresult = Invoke(bcx, |
960 | llfn, | |
85aaf69f | 961 | &llargs[..], |
1a4d82fc JJ |
962 | normal_bcx.llbb, |
963 | landing_pad, | |
85aaf69f SL |
964 | Some(attributes), |
965 | debug_loc); | |
1a4d82fc JJ |
966 | return (llresult, normal_bcx); |
967 | } else { | |
968 | debug!("calling {} at {:?}", bcx.val_to_string(llfn), bcx.llbb); | |
85aaf69f | 969 | for &llarg in llargs { |
1a4d82fc JJ |
970 | debug!("arg: {}", bcx.val_to_string(llarg)); |
971 | } | |
972 | ||
92a42be0 | 973 | let llresult = Call(bcx, llfn, &llargs[..], Some(attributes), debug_loc); |
1a4d82fc JJ |
974 | return (llresult, bcx); |
975 | } | |
976 | } | |
977 | ||
e9174d1e SL |
978 | /// Returns whether this session's target will use SEH-based unwinding. |
979 | /// | |
980 | /// This is only true for MSVC targets, and even then the 64-bit MSVC target | |
981 | /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as | |
982 | /// 64-bit MinGW) instead of "full SEH". | |
983 | pub fn wants_msvc_seh(sess: &Session) -> bool { | |
7453a54e | 984 | sess.target.target.options.is_like_msvc |
e9174d1e SL |
985 | } |
986 | ||
9cc50fc6 | 987 | pub fn avoid_invoke(bcx: Block) -> bool { |
7453a54e | 988 | bcx.sess().no_landing_pads() || bcx.lpad().is_some() |
9cc50fc6 | 989 | } |
1a4d82fc | 990 | |
9cc50fc6 SL |
991 | pub fn need_invoke(bcx: Block) -> bool { |
992 | if avoid_invoke(bcx) { | |
993 | false | |
994 | } else { | |
995 | bcx.fcx.needs_invoke() | |
1a4d82fc | 996 | } |
1a4d82fc JJ |
997 | } |
998 | ||
92a42be0 | 999 | pub fn load_if_immediate<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>) -> ValueRef { |
1a4d82fc | 1000 | let _icx = push_ctxt("load_if_immediate"); |
92a42be0 SL |
1001 | if type_is_immediate(cx.ccx(), t) { |
1002 | return load_ty(cx, v, t); | |
1003 | } | |
1a4d82fc JJ |
1004 | return v; |
1005 | } | |
1006 | ||
1007 | /// Helper for loading values from memory. Does the necessary conversion if the in-memory type | |
1008 | /// differs from the type used for SSA values. Also handles various special cases where the type | |
1009 | /// gives us better information about what we are loading. | |
92a42be0 | 1010 | pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> ValueRef { |
c34b1796 AL |
1011 | if cx.unreachable.get() || type_is_zero_size(cx.ccx(), t) { |
1012 | return C_undef(type_of::type_of(cx.ccx(), t)); | |
1013 | } | |
1014 | ||
1015 | let ptr = to_arg_ty_ptr(cx, ptr, t); | |
d9579d0f | 1016 | let align = type_of::align_of(cx.ccx(), t); |
c34b1796 AL |
1017 | |
1018 | if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() { | |
d9579d0f AL |
1019 | let load = Load(cx, ptr); |
1020 | unsafe { | |
1021 | llvm::LLVMSetAlignment(load, align); | |
1022 | } | |
1023 | return load; | |
c34b1796 AL |
1024 | } |
1025 | ||
1026 | unsafe { | |
1027 | let global = llvm::LLVMIsAGlobalVariable(ptr); | |
1028 | if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True { | |
1029 | let val = llvm::LLVMGetInitializer(global); | |
1030 | if !val.is_null() { | |
62682a34 | 1031 | return to_arg_ty(cx, val, t); |
85aaf69f SL |
1032 | } |
1033 | } | |
1a4d82fc | 1034 | } |
c34b1796 | 1035 | |
92a42be0 | 1036 | let val = if t.is_bool() { |
c34b1796 | 1037 | LoadRangeAssert(cx, ptr, 0, 2, llvm::False) |
c1a9b12d | 1038 | } else if t.is_char() { |
c34b1796 AL |
1039 | // a char is a Unicode codepoint, and so takes values from 0 |
1040 | // to 0x10FFFF inclusive only. | |
1041 | LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False) | |
92a42be0 SL |
1042 | } else if (t.is_region_ptr() || t.is_unique()) && !common::type_is_fat_ptr(cx.tcx(), t) { |
1043 | LoadNonNull(cx, ptr) | |
c34b1796 AL |
1044 | } else { |
1045 | Load(cx, ptr) | |
1046 | }; | |
1047 | ||
d9579d0f AL |
1048 | unsafe { |
1049 | llvm::LLVMSetAlignment(val, align); | |
1050 | } | |
1051 | ||
62682a34 | 1052 | to_arg_ty(cx, val, t) |
1a4d82fc JJ |
1053 | } |
1054 | ||
1055 | /// Helper for storing values in memory. Does the necessary conversion if the in-memory type | |
1056 | /// differs from the type used for SSA values. | |
85aaf69f | 1057 | pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) { |
d9579d0f AL |
1058 | if cx.unreachable.get() { |
1059 | return; | |
1060 | } | |
1061 | ||
92a42be0 SL |
1062 | debug!("store_ty: {} : {:?} <- {}", |
1063 | cx.val_to_string(dst), | |
1064 | t, | |
1065 | cx.val_to_string(v)); | |
1066 | ||
c1a9b12d | 1067 | if common::type_is_fat_ptr(cx.tcx(), t) { |
92a42be0 SL |
1068 | Store(cx, |
1069 | ExtractValue(cx, v, abi::FAT_PTR_ADDR), | |
1070 | expr::get_dataptr(cx, dst)); | |
1071 | Store(cx, | |
1072 | ExtractValue(cx, v, abi::FAT_PTR_EXTRA), | |
1073 | expr::get_meta(cx, dst)); | |
c1a9b12d SL |
1074 | } else { |
1075 | let store = Store(cx, from_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t)); | |
1076 | unsafe { | |
1077 | llvm::LLVMSetAlignment(store, type_of::align_of(cx.ccx(), t)); | |
1078 | } | |
d9579d0f | 1079 | } |
c34b1796 AL |
1080 | } |
1081 | ||
92a42be0 SL |
1082 | pub fn store_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>, |
1083 | data: ValueRef, | |
1084 | extra: ValueRef, | |
1085 | dst: ValueRef, | |
1086 | _ty: Ty<'tcx>) { | |
1087 | // FIXME: emit metadata | |
1088 | Store(cx, data, expr::get_dataptr(cx, dst)); | |
1089 | Store(cx, extra, expr::get_meta(cx, dst)); | |
1090 | } | |
1091 | ||
1092 | pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>, | |
1093 | src: ValueRef, | |
1094 | _ty: Ty<'tcx>) | |
1095 | -> (ValueRef, ValueRef) { | |
1096 | // FIXME: emit metadata | |
1097 | (Load(cx, expr::get_dataptr(cx, src)), | |
1098 | Load(cx, expr::get_meta(cx, src))) | |
1099 | } | |
1100 | ||
62682a34 | 1101 | pub fn from_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef { |
c1a9b12d | 1102 | if ty.is_bool() { |
c34b1796 AL |
1103 | ZExt(bcx, val, Type::i8(bcx.ccx())) |
1104 | } else { | |
1105 | val | |
1106 | } | |
1107 | } | |
1108 | ||
62682a34 | 1109 | pub fn to_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef { |
c1a9b12d | 1110 | if ty.is_bool() { |
c34b1796 AL |
1111 | Trunc(bcx, val, Type::i1(bcx.ccx())) |
1112 | } else { | |
1113 | val | |
1114 | } | |
1115 | } | |
1116 | ||
1117 | pub fn to_arg_ty_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef, ty: Ty<'tcx>) -> ValueRef { | |
1118 | if type_is_immediate(bcx.ccx(), ty) && type_of::type_of(bcx.ccx(), ty).is_aggregate() { | |
85aaf69f SL |
1119 | // We want to pass small aggregates as immediate values, but using an aggregate LLVM type |
1120 | // for this leads to bad optimizations, so its arg type is an appropriately sized integer | |
1121 | // and we have to convert it | |
c34b1796 | 1122 | BitCast(bcx, ptr, type_of::arg_type_of(bcx.ccx(), ty).ptr_to()) |
1a4d82fc | 1123 | } else { |
c34b1796 | 1124 | ptr |
85aaf69f | 1125 | } |
1a4d82fc JJ |
1126 | } |
1127 | ||
92a42be0 | 1128 | pub fn init_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, local: &hir::Local) -> Block<'blk, 'tcx> { |
1a4d82fc JJ |
1129 | debug!("init_local(bcx={}, local.id={})", bcx.to_str(), local.id); |
1130 | let _indenter = indenter(); | |
1131 | let _icx = push_ctxt("init_local"); | |
1132 | _match::store_local(bcx, local) | |
1133 | } | |
1134 | ||
1135 | pub fn raw_block<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>, | |
1a4d82fc JJ |
1136 | llbb: BasicBlockRef) |
1137 | -> Block<'blk, 'tcx> { | |
7453a54e | 1138 | common::BlockS::new(llbb, None, fcx) |
1a4d82fc JJ |
1139 | } |
1140 | ||
92a42be0 SL |
1141 | pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) -> Block<'blk, 'tcx> |
1142 | where F: FnOnce(Block<'blk, 'tcx>) -> Block<'blk, 'tcx> | |
1a4d82fc JJ |
1143 | { |
1144 | let _icx = push_ctxt("with_cond"); | |
85aaf69f | 1145 | |
62682a34 | 1146 | if bcx.unreachable.get() || common::const_to_opt_uint(val) == Some(0) { |
85aaf69f SL |
1147 | return bcx; |
1148 | } | |
1149 | ||
1a4d82fc JJ |
1150 | let fcx = bcx.fcx; |
1151 | let next_cx = fcx.new_temp_block("next"); | |
1152 | let cond_cx = fcx.new_temp_block("cond"); | |
85aaf69f | 1153 | CondBr(bcx, val, cond_cx.llbb, next_cx.llbb, DebugLoc::None); |
1a4d82fc JJ |
1154 | let after_cx = f(cond_cx); |
1155 | if !after_cx.terminated.get() { | |
85aaf69f | 1156 | Br(after_cx, next_cx.llbb, DebugLoc::None); |
1a4d82fc JJ |
1157 | } |
1158 | next_cx | |
1159 | } | |
1160 | ||
9cc50fc6 SL |
1161 | enum Lifetime { Start, End } |
1162 | ||
1163 | // If LLVM lifetime intrinsic support is enabled (i.e. optimizations | |
1164 | // on), and `ptr` is nonzero-sized, then extracts the size of `ptr` | |
1165 | // and the intrinsic for `lt` and passes them to `emit`, which is in | |
1166 | // charge of generating code to call the passed intrinsic on whatever | |
1167 | // block of generated code is targetted for the intrinsic. | |
1168 | // | |
1169 | // If LLVM lifetime intrinsic support is disabled (i.e. optimizations | |
1170 | // off) or `ptr` is zero-sized, then no-op (does not call `emit`). | |
1171 | fn core_lifetime_emit<'blk, 'tcx, F>(ccx: &'blk CrateContext<'blk, 'tcx>, | |
1172 | ptr: ValueRef, | |
1173 | lt: Lifetime, | |
1174 | emit: F) | |
1175 | where F: FnOnce(&'blk CrateContext<'blk, 'tcx>, machine::llsize, ValueRef) | |
1176 | { | |
1177 | if ccx.sess().opts.optimize == config::OptLevel::No { | |
1a4d82fc JJ |
1178 | return; |
1179 | } | |
1180 | ||
9cc50fc6 SL |
1181 | let _icx = push_ctxt(match lt { |
1182 | Lifetime::Start => "lifetime_start", | |
1183 | Lifetime::End => "lifetime_end" | |
1184 | }); | |
1a4d82fc | 1185 | |
e9174d1e SL |
1186 | let size = machine::llsize_of_alloc(ccx, val_ty(ptr).element_type()); |
1187 | if size == 0 { | |
1188 | return; | |
1189 | } | |
1190 | ||
9cc50fc6 SL |
1191 | let lifetime_intrinsic = ccx.get_intrinsic(match lt { |
1192 | Lifetime::Start => "llvm.lifetime.start", | |
1193 | Lifetime::End => "llvm.lifetime.end" | |
1194 | }); | |
1195 | emit(ccx, size, lifetime_intrinsic) | |
1a4d82fc JJ |
1196 | } |
1197 | ||
9cc50fc6 SL |
1198 | pub fn call_lifetime_start(cx: Block, ptr: ValueRef) { |
1199 | core_lifetime_emit(cx.ccx(), ptr, Lifetime::Start, |ccx, size, lifetime_start| { | |
1200 | let ptr = PointerCast(cx, ptr, Type::i8p(ccx)); | |
1201 | Call(cx, | |
1202 | lifetime_start, | |
1203 | &[C_u64(ccx, size), ptr], | |
1204 | None, | |
1205 | DebugLoc::None); | |
1206 | }) | |
1207 | } | |
e9174d1e | 1208 | |
9cc50fc6 SL |
1209 | pub fn call_lifetime_end(cx: Block, ptr: ValueRef) { |
1210 | core_lifetime_emit(cx.ccx(), ptr, Lifetime::End, |ccx, size, lifetime_end| { | |
1211 | let ptr = PointerCast(cx, ptr, Type::i8p(ccx)); | |
1212 | Call(cx, | |
1213 | lifetime_end, | |
1214 | &[C_u64(ccx, size), ptr], | |
1215 | None, | |
1216 | DebugLoc::None); | |
1217 | }) | |
1a4d82fc JJ |
1218 | } |
1219 | ||
92a42be0 SL |
1220 | // Generates code for resumption of unwind at the end of a landing pad. |
1221 | pub fn trans_unwind_resume(bcx: Block, lpval: ValueRef) { | |
1222 | if !bcx.sess().target.target.options.custom_unwind_resume { | |
1223 | Resume(bcx, lpval); | |
1224 | } else { | |
1225 | let exc_ptr = ExtractValue(bcx, lpval, 0); | |
1226 | let llunwresume = bcx.fcx.eh_unwind_resume(); | |
1227 | Call(bcx, llunwresume, &[exc_ptr], None, DebugLoc::None); | |
1228 | Unreachable(bcx); | |
1229 | } | |
1230 | } | |
1231 | ||
1232 | ||
1a4d82fc JJ |
1233 | pub fn call_memcpy(cx: Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) { |
1234 | let _icx = push_ctxt("call_memcpy"); | |
1235 | let ccx = cx.ccx(); | |
e9174d1e SL |
1236 | let ptr_width = &ccx.sess().target.target.target_pointer_width[..]; |
1237 | let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); | |
1a4d82fc JJ |
1238 | let memcpy = ccx.get_intrinsic(&key); |
1239 | let src_ptr = PointerCast(cx, src, Type::i8p(ccx)); | |
1240 | let dst_ptr = PointerCast(cx, dst, Type::i8p(ccx)); | |
1241 | let size = IntCast(cx, n_bytes, ccx.int_type()); | |
1242 | let align = C_i32(ccx, align as i32); | |
1243 | let volatile = C_bool(ccx, false); | |
92a42be0 SL |
1244 | Call(cx, |
1245 | memcpy, | |
1246 | &[dst_ptr, src_ptr, size, align, volatile], | |
1247 | None, | |
1248 | DebugLoc::None); | |
1a4d82fc JJ |
1249 | } |
1250 | ||
92a42be0 | 1251 | pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dst: ValueRef, src: ValueRef, t: Ty<'tcx>) { |
1a4d82fc JJ |
1252 | let _icx = push_ctxt("memcpy_ty"); |
1253 | let ccx = bcx.ccx(); | |
e9174d1e SL |
1254 | |
1255 | if type_is_zero_size(ccx, t) { | |
1256 | return; | |
1257 | } | |
1258 | ||
c1a9b12d | 1259 | if t.is_structural() { |
1a4d82fc JJ |
1260 | let llty = type_of::type_of(ccx, t); |
1261 | let llsz = llsize_of(ccx, llty); | |
1262 | let llalign = type_of::align_of(ccx, t); | |
1263 | call_memcpy(bcx, dst, src, llsz, llalign as u32); | |
92a42be0 SL |
1264 | } else if common::type_is_fat_ptr(bcx.tcx(), t) { |
1265 | let (data, extra) = load_fat_ptr(bcx, src, t); | |
1266 | store_fat_ptr(bcx, data, extra, dst, t); | |
1a4d82fc | 1267 | } else { |
85aaf69f | 1268 | store_ty(bcx, load_ty(bcx, src, t), dst, t); |
1a4d82fc JJ |
1269 | } |
1270 | } | |
1271 | ||
c34b1796 | 1272 | pub fn drop_done_fill_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) { |
92a42be0 SL |
1273 | if cx.unreachable.get() { |
1274 | return; | |
1275 | } | |
c34b1796 AL |
1276 | let _icx = push_ctxt("drop_done_fill_mem"); |
1277 | let bcx = cx; | |
1278 | memfill(&B(bcx), llptr, t, adt::DTOR_DONE); | |
1279 | } | |
1280 | ||
1281 | pub fn init_zero_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) { | |
92a42be0 SL |
1282 | if cx.unreachable.get() { |
1283 | return; | |
1284 | } | |
c34b1796 | 1285 | let _icx = push_ctxt("init_zero_mem"); |
1a4d82fc | 1286 | let bcx = cx; |
c34b1796 | 1287 | memfill(&B(bcx), llptr, t, 0); |
1a4d82fc JJ |
1288 | } |
1289 | ||
c34b1796 AL |
1290 | // Always use this function instead of storing a constant byte to the memory |
1291 | // in question. e.g. if you store a zero constant, LLVM will drown in vreg | |
1a4d82fc JJ |
1292 | // allocation for large data structures, and the generated code will be |
1293 | // awful. (A telltale sign of this is large quantities of | |
1294 | // `mov [byte ptr foo],0` in the generated code.) | |
c34b1796 AL |
1295 | fn memfill<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>, byte: u8) { |
1296 | let _icx = push_ctxt("memfill"); | |
1a4d82fc JJ |
1297 | let ccx = b.ccx; |
1298 | ||
1299 | let llty = type_of::type_of(ccx, ty); | |
e9174d1e SL |
1300 | let ptr_width = &ccx.sess().target.target.target_pointer_width[..]; |
1301 | let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width); | |
1a4d82fc JJ |
1302 | |
1303 | let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key); | |
1304 | let llptr = b.pointercast(llptr, Type::i8(ccx).ptr_to()); | |
e9174d1e | 1305 | let llzeroval = C_u8(ccx, byte); |
1a4d82fc JJ |
1306 | let size = machine::llsize_of(ccx, llty); |
1307 | let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32); | |
1308 | let volatile = C_bool(ccx, false); | |
92a42be0 SL |
1309 | b.call(llintrinsicfn, |
1310 | &[llptr, llzeroval, size, align, volatile], | |
7453a54e | 1311 | None, None); |
1a4d82fc JJ |
1312 | } |
1313 | ||
9cc50fc6 SL |
1314 | /// In general, when we create an scratch value in an alloca, the |
1315 | /// creator may not know if the block (that initializes the scratch | |
1316 | /// with the desired value) actually dominates the cleanup associated | |
1317 | /// with the scratch value. | |
1318 | /// | |
1319 | /// To deal with this, when we do an alloca (at the *start* of whole | |
1320 | /// function body), we optionally can also set the associated | |
1321 | /// dropped-flag state of the alloca to "dropped." | |
1322 | #[derive(Copy, Clone, Debug)] | |
1323 | pub enum InitAlloca { | |
1324 | /// Indicates that the state should have its associated drop flag | |
1325 | /// set to "dropped" at the point of allocation. | |
1326 | Dropped, | |
1327 | /// Indicates the value of the associated drop flag is irrelevant. | |
1328 | /// The embedded string literal is a programmer provided argument | |
1329 | /// for why. This is a safeguard forcing compiler devs to | |
1330 | /// document; it might be a good idea to also emit this as a | |
1331 | /// comment with the alloca itself when emitting LLVM output.ll. | |
1332 | Uninit(&'static str), | |
1333 | } | |
1334 | ||
1335 | ||
1336 | pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
1337 | t: Ty<'tcx>, | |
1338 | name: &str) -> ValueRef { | |
1339 | // pnkfelix: I do not know why alloc_ty meets the assumptions for | |
1340 | // passing Uninit, but it was never needed (even back when we had | |
1341 | // the original boolean `zero` flag on `lvalue_scratch_datum`). | |
1342 | alloc_ty_init(bcx, t, InitAlloca::Uninit("all alloc_ty are uninit"), name) | |
1343 | } | |
1344 | ||
1345 | /// This variant of `fn alloc_ty` does not necessarily assume that the | |
1346 | /// alloca should be created with no initial value. Instead the caller | |
1347 | /// controls that assumption via the `init` flag. | |
1348 | /// | |
1349 | /// Note that if the alloca *is* initialized via `init`, then we will | |
1350 | /// also inject an `llvm.lifetime.start` before that initialization | |
1351 | /// occurs, and thus callers should not call_lifetime_start | |
1352 | /// themselves. But if `init` says "uninitialized", then callers are | |
1353 | /// in charge of choosing where to call_lifetime_start and | |
1354 | /// subsequently populate the alloca. | |
1355 | /// | |
1356 | /// (See related discussion on PR #30823.) | |
1357 | pub fn alloc_ty_init<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
1358 | t: Ty<'tcx>, | |
1359 | init: InitAlloca, | |
1360 | name: &str) -> ValueRef { | |
1a4d82fc JJ |
1361 | let _icx = push_ctxt("alloc_ty"); |
1362 | let ccx = bcx.ccx(); | |
1363 | let ty = type_of::type_of(ccx, t); | |
c1a9b12d | 1364 | assert!(!t.has_param_types()); |
9cc50fc6 SL |
1365 | match init { |
1366 | InitAlloca::Dropped => alloca_dropped(bcx, t, name), | |
1367 | InitAlloca::Uninit(_) => alloca(bcx, ty, name), | |
1368 | } | |
1369 | } | |
1370 | ||
1371 | pub fn alloca_dropped<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty: Ty<'tcx>, name: &str) -> ValueRef { | |
1372 | let _icx = push_ctxt("alloca_dropped"); | |
1373 | let llty = type_of::type_of(cx.ccx(), ty); | |
1374 | if cx.unreachable.get() { | |
1375 | unsafe { return llvm::LLVMGetUndef(llty.ptr_to().to_ref()); } | |
1376 | } | |
1377 | let p = alloca(cx, llty, name); | |
1378 | let b = cx.fcx.ccx.builder(); | |
1379 | b.position_before(cx.fcx.alloca_insert_pt.get().unwrap()); | |
1380 | ||
1381 | // This is just like `call_lifetime_start` (but latter expects a | |
1382 | // Block, which we do not have for `alloca_insert_pt`). | |
1383 | core_lifetime_emit(cx.ccx(), p, Lifetime::Start, |ccx, size, lifetime_start| { | |
1384 | let ptr = b.pointercast(p, Type::i8p(ccx)); | |
7453a54e | 1385 | b.call(lifetime_start, &[C_u64(ccx, size), ptr], None, None); |
9cc50fc6 SL |
1386 | }); |
1387 | memfill(&b, p, ty, adt::DTOR_DONE); | |
1388 | p | |
1a4d82fc JJ |
1389 | } |
1390 | ||
1391 | pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef { | |
1a4d82fc JJ |
1392 | let _icx = push_ctxt("alloca"); |
1393 | if cx.unreachable.get() { | |
1394 | unsafe { | |
1395 | return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); | |
1396 | } | |
1397 | } | |
1398 | debuginfo::clear_source_location(cx.fcx); | |
1399 | Alloca(cx, ty, name) | |
1400 | } | |
1401 | ||
c1a9b12d SL |
1402 | pub fn set_value_name(val: ValueRef, name: &str) { |
1403 | unsafe { | |
1404 | let name = CString::new(name).unwrap(); | |
1405 | llvm::LLVMSetValueName(val, name.as_ptr()); | |
1406 | } | |
1407 | } | |
1408 | ||
1a4d82fc JJ |
1409 | // Creates the alloca slot which holds the pointer to the slot for the final return value |
1410 | pub fn make_return_slot_pointer<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, | |
92a42be0 SL |
1411 | output_type: Ty<'tcx>) |
1412 | -> ValueRef { | |
1a4d82fc JJ |
1413 | let lloutputtype = type_of::type_of(fcx.ccx, output_type); |
1414 | ||
1415 | // We create an alloca to hold a pointer of type `output_type` | |
1416 | // which will hold the pointer to the right alloca which has the | |
1417 | // final ret value | |
1418 | if fcx.needs_ret_allocas { | |
1419 | // Let's create the stack slot | |
1420 | let slot = AllocaFcx(fcx, lloutputtype.ptr_to(), "llretslotptr"); | |
1421 | ||
1422 | // and if we're using an out pointer, then store that in our newly made slot | |
1423 | if type_of::return_uses_outptr(fcx.ccx, output_type) { | |
1424 | let outptr = get_param(fcx.llfn, 0); | |
1425 | ||
1426 | let b = fcx.ccx.builder(); | |
1427 | b.position_before(fcx.alloca_insert_pt.get().unwrap()); | |
1428 | b.store(outptr, slot); | |
1429 | } | |
1430 | ||
1431 | slot | |
1432 | ||
1433 | // But if there are no nested returns, we skip the indirection and have a single | |
1434 | // retslot | |
1435 | } else { | |
1436 | if type_of::return_uses_outptr(fcx.ccx, output_type) { | |
1437 | get_param(fcx.llfn, 0) | |
1438 | } else { | |
1439 | AllocaFcx(fcx, lloutputtype, "sret_slot") | |
1440 | } | |
1441 | } | |
1442 | } | |
1443 | ||
1444 | struct FindNestedReturn { | |
1445 | found: bool, | |
1446 | } | |
1447 | ||
1448 | impl FindNestedReturn { | |
1449 | fn new() -> FindNestedReturn { | |
92a42be0 SL |
1450 | FindNestedReturn { |
1451 | found: false, | |
1452 | } | |
1a4d82fc JJ |
1453 | } |
1454 | } | |
1455 | ||
1456 | impl<'v> Visitor<'v> for FindNestedReturn { | |
e9174d1e | 1457 | fn visit_expr(&mut self, e: &hir::Expr) { |
1a4d82fc | 1458 | match e.node { |
e9174d1e | 1459 | hir::ExprRet(..) => { |
1a4d82fc JJ |
1460 | self.found = true; |
1461 | } | |
92a42be0 | 1462 | _ => intravisit::walk_expr(self, e), |
1a4d82fc JJ |
1463 | } |
1464 | } | |
1465 | } | |
1466 | ||
1467 | fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>) { | |
1468 | let blk = match tcx.map.find(id) { | |
e9174d1e | 1469 | Some(hir_map::NodeItem(i)) => { |
1a4d82fc | 1470 | match i.node { |
e9174d1e | 1471 | hir::ItemFn(_, _, _, _, _, ref blk) => { |
1a4d82fc JJ |
1472 | blk |
1473 | } | |
92a42be0 | 1474 | _ => tcx.sess.bug("unexpected item variant in has_nested_returns"), |
1a4d82fc JJ |
1475 | } |
1476 | } | |
e9174d1e | 1477 | Some(hir_map::NodeTraitItem(trait_item)) => { |
c34b1796 | 1478 | match trait_item.node { |
e9174d1e | 1479 | hir::MethodTraitItem(_, Some(ref body)) => body, |
d9579d0f | 1480 | _ => { |
92a42be0 SL |
1481 | tcx.sess.bug("unexpected variant: trait item other than a provided method in \ |
1482 | has_nested_returns") | |
1a4d82fc JJ |
1483 | } |
1484 | } | |
1485 | } | |
e9174d1e | 1486 | Some(hir_map::NodeImplItem(impl_item)) => { |
c34b1796 | 1487 | match impl_item.node { |
92a42be0 | 1488 | hir::ImplItemKind::Method(_, ref body) => body, |
d9579d0f | 1489 | _ => { |
92a42be0 | 1490 | tcx.sess.bug("unexpected variant: non-method impl item in has_nested_returns") |
1a4d82fc JJ |
1491 | } |
1492 | } | |
1493 | } | |
e9174d1e | 1494 | Some(hir_map::NodeExpr(e)) => { |
1a4d82fc | 1495 | match e.node { |
e9174d1e | 1496 | hir::ExprClosure(_, _, ref blk) => blk, |
92a42be0 | 1497 | _ => tcx.sess.bug("unexpected expr variant in has_nested_returns"), |
1a4d82fc JJ |
1498 | } |
1499 | } | |
e9174d1e SL |
1500 | Some(hir_map::NodeVariant(..)) | |
1501 | Some(hir_map::NodeStructCtor(..)) => return (ast::DUMMY_NODE_ID, None), | |
1a4d82fc JJ |
1502 | |
1503 | // glue, shims, etc | |
1504 | None if id == ast::DUMMY_NODE_ID => return (ast::DUMMY_NODE_ID, None), | |
1505 | ||
85aaf69f | 1506 | _ => tcx.sess.bug(&format!("unexpected variant in has_nested_returns: {}", |
92a42be0 | 1507 | tcx.map.path_to_string(id))), |
1a4d82fc JJ |
1508 | }; |
1509 | ||
c34b1796 | 1510 | (blk.id, Some(cfg::CFG::new(tcx, blk))) |
1a4d82fc JJ |
1511 | } |
1512 | ||
1513 | // Checks for the presence of "nested returns" in a function. | |
1514 | // Nested returns are when the inner expression of a return expression | |
1515 | // (the 'expr' in 'return expr') contains a return expression. Only cases | |
1516 | // where the outer return is actually reachable are considered. Implicit | |
1517 | // returns from the end of blocks are considered as well. | |
1518 | // | |
1519 | // This check is needed to handle the case where the inner expression is | |
1520 | // part of a larger expression that may have already partially-filled the | |
1521 | // return slot alloca. This can cause errors related to clean-up due to | |
1522 | // the clobbering of the existing value in the return slot. | |
1523 | fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool { | |
62682a34 SL |
1524 | for index in cfg.graph.depth_traverse(cfg.entry) { |
1525 | let n = cfg.graph.node_data(index); | |
c34b1796 | 1526 | match tcx.map.find(n.id()) { |
e9174d1e SL |
1527 | Some(hir_map::NodeExpr(ex)) => { |
1528 | if let hir::ExprRet(Some(ref ret_expr)) = ex.node { | |
1a4d82fc | 1529 | let mut visitor = FindNestedReturn::new(); |
7453a54e | 1530 | intravisit::walk_expr(&mut visitor, &ret_expr); |
1a4d82fc JJ |
1531 | if visitor.found { |
1532 | return true; | |
1533 | } | |
1534 | } | |
1535 | } | |
e9174d1e | 1536 | Some(hir_map::NodeBlock(blk)) if blk.id == blk_id => { |
1a4d82fc | 1537 | let mut visitor = FindNestedReturn::new(); |
b039eaaf | 1538 | walk_list!(&mut visitor, visit_expr, &blk.expr); |
1a4d82fc JJ |
1539 | if visitor.found { |
1540 | return true; | |
1541 | } | |
1542 | } | |
1543 | _ => {} | |
1544 | } | |
1545 | } | |
1546 | ||
1547 | return false; | |
1548 | } | |
1549 | ||
1550 | // NB: must keep 4 fns in sync: | |
1551 | // | |
1552 | // - type_of_fn | |
1553 | // - create_datums_for_fn_args. | |
1554 | // - new_fn_ctxt | |
1555 | // - trans_args | |
1556 | // | |
1557 | // Be warned! You must call `init_function` before doing anything with the | |
1558 | // returned function context. | |
1559 | pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, | |
1560 | llfndecl: ValueRef, | |
1561 | id: ast::NodeId, | |
1562 | has_env: bool, | |
1563 | output_type: ty::FnOutput<'tcx>, | |
85aaf69f | 1564 | param_substs: &'tcx Substs<'tcx>, |
1a4d82fc JJ |
1565 | sp: Option<Span>, |
1566 | block_arena: &'a TypedArena<common::BlockS<'a, 'tcx>>) | |
1567 | -> FunctionContext<'a, 'tcx> { | |
1568 | common::validate_substs(param_substs); | |
1569 | ||
62682a34 | 1570 | debug!("new_fn_ctxt(path={}, id={}, param_substs={:?})", |
c34b1796 | 1571 | if id == !0 { |
1a4d82fc JJ |
1572 | "".to_string() |
1573 | } else { | |
1574 | ccx.tcx().map.path_to_string(id).to_string() | |
1575 | }, | |
92a42be0 SL |
1576 | id, |
1577 | param_substs); | |
1a4d82fc JJ |
1578 | |
1579 | let uses_outptr = match output_type { | |
1580 | ty::FnConverging(output_type) => { | |
92a42be0 SL |
1581 | let substd_output_type = monomorphize::apply_param_substs(ccx.tcx(), |
1582 | param_substs, | |
1583 | &output_type); | |
1a4d82fc JJ |
1584 | type_of::return_uses_outptr(ccx, substd_output_type) |
1585 | } | |
92a42be0 | 1586 | ty::FnDiverging => false, |
1a4d82fc JJ |
1587 | }; |
1588 | let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl); | |
1589 | let (blk_id, cfg) = build_cfg(ccx.tcx(), id); | |
1590 | let nested_returns = if let Some(ref cfg) = cfg { | |
1591 | has_nested_returns(ccx.tcx(), cfg, blk_id) | |
1592 | } else { | |
1593 | false | |
1594 | }; | |
1595 | ||
7453a54e | 1596 | let mir = ccx.mir_map().map.get(&id); |
92a42be0 | 1597 | |
1a4d82fc | 1598 | let mut fcx = FunctionContext { |
92a42be0 SL |
1599 | mir: mir, |
1600 | llfn: llfndecl, | |
1601 | llenv: None, | |
1602 | llretslotptr: Cell::new(None), | |
1603 | param_env: ccx.tcx().empty_parameter_environment(), | |
1604 | alloca_insert_pt: Cell::new(None), | |
1605 | llreturn: Cell::new(None), | |
1606 | needs_ret_allocas: nested_returns, | |
7453a54e | 1607 | landingpad_alloca: Cell::new(None), |
92a42be0 SL |
1608 | caller_expects_out_pointer: uses_outptr, |
1609 | lllocals: RefCell::new(NodeMap()), | |
1610 | llupvars: RefCell::new(NodeMap()), | |
1611 | lldropflag_hints: RefCell::new(DropFlagHintsMap::new()), | |
1612 | id: id, | |
1613 | param_substs: param_substs, | |
1614 | span: sp, | |
1615 | block_arena: block_arena, | |
7453a54e | 1616 | lpad_arena: TypedArena::new(), |
92a42be0 SL |
1617 | ccx: ccx, |
1618 | debug_context: debug_context, | |
1619 | scopes: RefCell::new(Vec::new()), | |
1620 | cfg: cfg, | |
1a4d82fc JJ |
1621 | }; |
1622 | ||
1623 | if has_env { | |
1624 | fcx.llenv = Some(get_param(fcx.llfn, fcx.env_arg_pos() as c_uint)) | |
1625 | } | |
1626 | ||
1627 | fcx | |
1628 | } | |
1629 | ||
1630 | /// Performs setup on a newly created function, creating the entry scope block | |
1631 | /// and allocating space for the return pointer. | |
1632 | pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>, | |
1633 | skip_retptr: bool, | |
1634 | output: ty::FnOutput<'tcx>) | |
1635 | -> Block<'a, 'tcx> { | |
1636 | let entry_bcx = fcx.new_temp_block("entry-block"); | |
1637 | ||
1638 | // Use a dummy instruction as the insertion point for all allocas. | |
1639 | // This is later removed in FunctionContext::cleanup. | |
1640 | fcx.alloca_insert_pt.set(Some(unsafe { | |
1641 | Load(entry_bcx, C_null(Type::i8p(fcx.ccx))); | |
1642 | llvm::LLVMGetFirstInstruction(entry_bcx.llbb) | |
1643 | })); | |
1644 | ||
1645 | if let ty::FnConverging(output_type) = output { | |
1646 | // This shouldn't need to recompute the return type, | |
1647 | // as new_fn_ctxt did it already. | |
1648 | let substd_output_type = fcx.monomorphize(&output_type); | |
1649 | if !return_type_is_void(fcx.ccx, substd_output_type) { | |
1650 | // If the function returns nil/bot, there is no real return | |
1651 | // value, so do not set `llretslotptr`. | |
1652 | if !skip_retptr || fcx.caller_expects_out_pointer { | |
1653 | // Otherwise, we normally allocate the llretslotptr, unless we | |
1654 | // have been instructed to skip it for immediate return | |
1655 | // values. | |
1656 | fcx.llretslotptr.set(Some(make_return_slot_pointer(fcx, substd_output_type))); | |
1657 | } | |
1658 | } | |
1659 | } | |
1660 | ||
c1a9b12d SL |
1661 | // Create the drop-flag hints for every unfragmented path in the function. |
1662 | let tcx = fcx.ccx.tcx(); | |
b039eaaf | 1663 | let fn_did = tcx.map.local_def_id(fcx.id); |
9cc50fc6 | 1664 | let tables = tcx.tables.borrow(); |
c1a9b12d SL |
1665 | let mut hints = fcx.lldropflag_hints.borrow_mut(); |
1666 | let fragment_infos = tcx.fragment_infos.borrow(); | |
1667 | ||
1668 | // Intern table for drop-flag hint datums. | |
1669 | let mut seen = HashMap::new(); | |
1670 | ||
1671 | if let Some(fragment_infos) = fragment_infos.get(&fn_did) { | |
1672 | for &info in fragment_infos { | |
1673 | ||
1674 | let make_datum = |id| { | |
e9174d1e | 1675 | let init_val = C_u8(fcx.ccx, adt::DTOR_NEEDED_HINT); |
c1a9b12d SL |
1676 | let llname = &format!("dropflag_hint_{}", id); |
1677 | debug!("adding hint {}", llname); | |
e9174d1e SL |
1678 | let ty = tcx.types.u8; |
1679 | let ptr = alloc_ty(entry_bcx, ty, llname); | |
c1a9b12d | 1680 | Store(entry_bcx, init_val, ptr); |
c1a9b12d | 1681 | let flag = datum::Lvalue::new_dropflag_hint("base::init_function"); |
e9174d1e | 1682 | datum::Datum::new(ptr, ty, flag) |
c1a9b12d SL |
1683 | }; |
1684 | ||
1685 | let (var, datum) = match info { | |
1686 | ty::FragmentInfo::Moved { var, .. } | | |
1687 | ty::FragmentInfo::Assigned { var, .. } => { | |
9cc50fc6 SL |
1688 | let opt_datum = seen.get(&var).cloned().unwrap_or_else(|| { |
1689 | let ty = tables.node_types[&var]; | |
1690 | if fcx.type_needs_drop(ty) { | |
1691 | let datum = make_datum(var); | |
1692 | seen.insert(var, Some(datum.clone())); | |
1693 | Some(datum) | |
1694 | } else { | |
1695 | // No drop call needed, so we don't need a dropflag hint | |
1696 | None | |
1697 | } | |
c1a9b12d | 1698 | }); |
9cc50fc6 SL |
1699 | if let Some(datum) = opt_datum { |
1700 | (var, datum) | |
1701 | } else { | |
1702 | continue | |
1703 | } | |
c1a9b12d SL |
1704 | } |
1705 | }; | |
1706 | match info { | |
1707 | ty::FragmentInfo::Moved { move_expr: expr_id, .. } => { | |
1708 | debug!("FragmentInfo::Moved insert drop hint for {}", expr_id); | |
1709 | hints.insert(expr_id, DropHint::new(var, datum)); | |
1710 | } | |
1711 | ty::FragmentInfo::Assigned { assignee_id: expr_id, .. } => { | |
1712 | debug!("FragmentInfo::Assigned insert drop hint for {}", expr_id); | |
1713 | hints.insert(expr_id, DropHint::new(var, datum)); | |
1714 | } | |
1715 | } | |
1716 | } | |
1717 | } | |
1718 | ||
1a4d82fc JJ |
1719 | entry_bcx |
1720 | } | |
1721 | ||
1722 | // NB: must keep 4 fns in sync: | |
1723 | // | |
1724 | // - type_of_fn | |
1725 | // - create_datums_for_fn_args. | |
1726 | // - new_fn_ctxt | |
1727 | // - trans_args | |
1728 | ||
92a42be0 | 1729 | pub fn arg_kind<'a, 'tcx>(cx: &FunctionContext<'a, 'tcx>, t: Ty<'tcx>) -> datum::Rvalue { |
1a4d82fc JJ |
1730 | use trans::datum::{ByRef, ByValue}; |
1731 | ||
1732 | datum::Rvalue { | |
1733 | mode: if arg_is_indirect(cx.ccx, t) { ByRef } else { ByValue } | |
1734 | } | |
1735 | } | |
1736 | ||
c1a9b12d SL |
1737 | // create_datums_for_fn_args: creates lvalue datums for each of the |
1738 | // incoming function arguments. | |
1739 | pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>, | |
e9174d1e | 1740 | args: &[hir::Arg], |
c1a9b12d SL |
1741 | arg_tys: &[Ty<'tcx>], |
1742 | has_tupled_arg: bool, | |
1743 | arg_scope: cleanup::CustomScopeIndex) | |
1744 | -> Block<'a, 'tcx> { | |
1a4d82fc | 1745 | let _icx = push_ctxt("create_datums_for_fn_args"); |
62682a34 | 1746 | let fcx = bcx.fcx; |
c1a9b12d | 1747 | let arg_scope_id = cleanup::CustomScope(arg_scope); |
1a4d82fc | 1748 | |
9cc50fc6 SL |
1749 | debug!("create_datums_for_fn_args"); |
1750 | ||
1a4d82fc JJ |
1751 | // Return an array wrapping the ValueRefs that we get from `get_param` for |
1752 | // each argument into datums. | |
c1a9b12d SL |
1753 | // |
1754 | // For certain mode/type combinations, the raw llarg values are passed | |
1755 | // by value. However, within the fn body itself, we want to always | |
1756 | // have all locals and arguments be by-ref so that we can cancel the | |
1757 | // cleanup and for better interaction with LLVM's debug info. So, if | |
1758 | // the argument would be passed by value, we store it into an alloca. | |
1759 | // This alloca should be optimized away by LLVM's mem-to-reg pass in | |
1760 | // the event it's not truly needed. | |
1761 | let mut idx = fcx.arg_offset() as c_uint; | |
9cc50fc6 | 1762 | let uninit_reason = InitAlloca::Uninit("fn_arg populate dominates dtor"); |
1a4d82fc | 1763 | for (i, &arg_ty) in arg_tys.iter().enumerate() { |
c1a9b12d | 1764 | let arg_datum = if !has_tupled_arg || i < arg_tys.len() - 1 { |
92a42be0 SL |
1765 | if type_of::arg_is_indirect(bcx.ccx(), arg_ty) && |
1766 | bcx.sess().opts.debuginfo != FullDebugInfo { | |
c1a9b12d SL |
1767 | // Don't copy an indirect argument to an alloca, the caller |
1768 | // already put it in a temporary alloca and gave it up, unless | |
1769 | // we emit extra-debug-info, which requires local allocas :(. | |
1770 | let llarg = get_param(fcx.llfn, idx); | |
1771 | idx += 1; | |
1772 | bcx.fcx.schedule_lifetime_end(arg_scope_id, llarg); | |
1773 | bcx.fcx.schedule_drop_mem(arg_scope_id, llarg, arg_ty, None); | |
1774 | ||
92a42be0 SL |
1775 | datum::Datum::new(llarg, |
1776 | arg_ty, | |
1777 | datum::Lvalue::new("create_datum_for_fn_args")) | |
c1a9b12d SL |
1778 | } else if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { |
1779 | let data = get_param(fcx.llfn, idx); | |
1780 | let extra = get_param(fcx.llfn, idx + 1); | |
62682a34 | 1781 | idx += 2; |
9cc50fc6 | 1782 | unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", uninit_reason, |
c1a9b12d SL |
1783 | arg_scope_id, (data, extra), |
1784 | |(data, extra), bcx, dst| { | |
9cc50fc6 SL |
1785 | debug!("populate call for create_datum_for_fn_args \ |
1786 | early fat arg, on arg[{}] ty={:?}", i, arg_ty); | |
1787 | ||
c1a9b12d | 1788 | Store(bcx, data, expr::get_dataptr(bcx, dst)); |
e9174d1e | 1789 | Store(bcx, extra, expr::get_meta(bcx, dst)); |
c1a9b12d SL |
1790 | bcx |
1791 | })) | |
62682a34 | 1792 | } else { |
c1a9b12d | 1793 | let llarg = get_param(fcx.llfn, idx); |
62682a34 | 1794 | idx += 1; |
c1a9b12d | 1795 | let tmp = datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty)); |
92a42be0 SL |
1796 | unpack_datum!(bcx, |
1797 | datum::lvalue_scratch_datum(bcx, | |
1798 | arg_ty, | |
1799 | "", | |
9cc50fc6 | 1800 | uninit_reason, |
92a42be0 SL |
1801 | arg_scope_id, |
1802 | tmp, | |
9cc50fc6 SL |
1803 | |tmp, bcx, dst| { |
1804 | ||
1805 | debug!("populate call for create_datum_for_fn_args \ | |
1806 | early thin arg, on arg[{}] ty={:?}", i, arg_ty); | |
1807 | ||
1808 | tmp.store_to(bcx, dst) | |
1809 | })) | |
c1a9b12d SL |
1810 | } |
1811 | } else { | |
1812 | // FIXME(pcwalton): Reduce the amount of code bloat this is responsible for. | |
1813 | match arg_ty.sty { | |
1814 | ty::TyTuple(ref tupled_arg_tys) => { | |
1a4d82fc JJ |
1815 | unpack_datum!(bcx, |
1816 | datum::lvalue_scratch_datum(bcx, | |
1817 | arg_ty, | |
1818 | "tupled_args", | |
9cc50fc6 | 1819 | uninit_reason, |
c1a9b12d | 1820 | arg_scope_id, |
1a4d82fc JJ |
1821 | (), |
1822 | |(), | |
1823 | mut bcx, | |
9cc50fc6 SL |
1824 | llval| { |
1825 | debug!("populate call for create_datum_for_fn_args \ | |
1826 | tupled_args, on arg[{}] ty={:?}", i, arg_ty); | |
1a4d82fc JJ |
1827 | for (j, &tupled_arg_ty) in |
1828 | tupled_arg_tys.iter().enumerate() { | |
e9174d1e | 1829 | let lldest = StructGEP(bcx, llval, j); |
62682a34 SL |
1830 | if common::type_is_fat_ptr(bcx.tcx(), tupled_arg_ty) { |
1831 | let data = get_param(bcx.fcx.llfn, idx); | |
1832 | let extra = get_param(bcx.fcx.llfn, idx + 1); | |
1833 | Store(bcx, data, expr::get_dataptr(bcx, lldest)); | |
e9174d1e | 1834 | Store(bcx, extra, expr::get_meta(bcx, lldest)); |
62682a34 SL |
1835 | idx += 2; |
1836 | } else { | |
1837 | let datum = datum::Datum::new( | |
1838 | get_param(bcx.fcx.llfn, idx), | |
1839 | tupled_arg_ty, | |
1840 | arg_kind(bcx.fcx, tupled_arg_ty)); | |
1841 | idx += 1; | |
1842 | bcx = datum.store_to(bcx, lldest); | |
1843 | }; | |
1a4d82fc JJ |
1844 | } |
1845 | bcx | |
c1a9b12d SL |
1846 | })) |
1847 | } | |
1848 | _ => { | |
92a42be0 SL |
1849 | bcx.tcx() |
1850 | .sess | |
1851 | .bug("last argument of a function with `rust-call` ABI isn't a tuple?!") | |
c1a9b12d | 1852 | } |
1a4d82fc JJ |
1853 | } |
1854 | }; | |
1855 | ||
c1a9b12d | 1856 | let pat = &*args[i].pat; |
b039eaaf | 1857 | bcx = if let Some(name) = simple_name(pat) { |
c1a9b12d SL |
1858 | // Generate nicer LLVM for the common case of fn a pattern |
1859 | // like `x: T` | |
b039eaaf | 1860 | set_value_name(arg_datum.val, &bcx.name(name)); |
c1a9b12d SL |
1861 | bcx.fcx.lllocals.borrow_mut().insert(pat.id, arg_datum); |
1862 | bcx | |
1863 | } else { | |
1864 | // General path. Copy out the values that are used in the | |
1865 | // pattern. | |
1866 | _match::bind_irrefutable_pat(bcx, pat, arg_datum.match_input(), arg_scope_id) | |
1867 | }; | |
85aaf69f | 1868 | debuginfo::create_argument_metadata(bcx, &args[i]); |
1a4d82fc JJ |
1869 | } |
1870 | ||
1871 | bcx | |
1872 | } | |
1873 | ||
1a4d82fc JJ |
1874 | // Ties up the llstaticallocas -> llloadenv -> lltop edges, |
1875 | // and builds the return block. | |
1876 | pub fn finish_fn<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>, | |
1877 | last_bcx: Block<'blk, 'tcx>, | |
85aaf69f SL |
1878 | retty: ty::FnOutput<'tcx>, |
1879 | ret_debug_loc: DebugLoc) { | |
1a4d82fc JJ |
1880 | let _icx = push_ctxt("finish_fn"); |
1881 | ||
1882 | let ret_cx = match fcx.llreturn.get() { | |
1883 | Some(llreturn) => { | |
1884 | if !last_bcx.terminated.get() { | |
85aaf69f | 1885 | Br(last_bcx, llreturn, DebugLoc::None); |
1a4d82fc | 1886 | } |
7453a54e | 1887 | raw_block(fcx, llreturn) |
1a4d82fc | 1888 | } |
92a42be0 | 1889 | None => last_bcx, |
1a4d82fc JJ |
1890 | }; |
1891 | ||
1892 | // This shouldn't need to recompute the return type, | |
1893 | // as new_fn_ctxt did it already. | |
1894 | let substd_retty = fcx.monomorphize(&retty); | |
85aaf69f | 1895 | build_return_block(fcx, ret_cx, substd_retty, ret_debug_loc); |
1a4d82fc JJ |
1896 | |
1897 | debuginfo::clear_source_location(fcx); | |
1898 | fcx.cleanup(); | |
1899 | } | |
1900 | ||
1901 | // Builds the return block for a function. | |
1902 | pub fn build_return_block<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>, | |
1903 | ret_cx: Block<'blk, 'tcx>, | |
85aaf69f SL |
1904 | retty: ty::FnOutput<'tcx>, |
1905 | ret_debug_location: DebugLoc) { | |
1a4d82fc JJ |
1906 | if fcx.llretslotptr.get().is_none() || |
1907 | (!fcx.needs_ret_allocas && fcx.caller_expects_out_pointer) { | |
85aaf69f | 1908 | return RetVoid(ret_cx, ret_debug_location); |
1a4d82fc JJ |
1909 | } |
1910 | ||
1911 | let retslot = if fcx.needs_ret_allocas { | |
1912 | Load(ret_cx, fcx.llretslotptr.get().unwrap()) | |
1913 | } else { | |
1914 | fcx.llretslotptr.get().unwrap() | |
1915 | }; | |
1916 | let retptr = Value(retslot); | |
1917 | match retptr.get_dominating_store(ret_cx) { | |
1918 | // If there's only a single store to the ret slot, we can directly return | |
1919 | // the value that was stored and omit the store and the alloca | |
1920 | Some(s) => { | |
1921 | let retval = s.get_operand(0).unwrap().get(); | |
1922 | s.erase_from_parent(); | |
1923 | ||
1924 | if retptr.has_no_uses() { | |
1925 | retptr.erase_from_parent(); | |
1926 | } | |
1927 | ||
1928 | let retval = if retty == ty::FnConverging(fcx.ccx.tcx().types.bool) { | |
1929 | Trunc(ret_cx, retval, Type::i1(fcx.ccx)) | |
1930 | } else { | |
1931 | retval | |
1932 | }; | |
1933 | ||
1934 | if fcx.caller_expects_out_pointer { | |
1935 | if let ty::FnConverging(retty) = retty { | |
1936 | store_ty(ret_cx, retval, get_param(fcx.llfn, 0), retty); | |
1937 | } | |
85aaf69f | 1938 | RetVoid(ret_cx, ret_debug_location) |
1a4d82fc | 1939 | } else { |
85aaf69f | 1940 | Ret(ret_cx, retval, ret_debug_location) |
1a4d82fc JJ |
1941 | } |
1942 | } | |
1943 | // Otherwise, copy the return value to the ret slot | |
1944 | None => match retty { | |
1945 | ty::FnConverging(retty) => { | |
1946 | if fcx.caller_expects_out_pointer { | |
1947 | memcpy_ty(ret_cx, get_param(fcx.llfn, 0), retslot, retty); | |
85aaf69f | 1948 | RetVoid(ret_cx, ret_debug_location) |
1a4d82fc | 1949 | } else { |
85aaf69f | 1950 | Ret(ret_cx, load_ty(ret_cx, retslot, retty), ret_debug_location) |
1a4d82fc JJ |
1951 | } |
1952 | } | |
1953 | ty::FnDiverging => { | |
1954 | if fcx.caller_expects_out_pointer { | |
85aaf69f | 1955 | RetVoid(ret_cx, ret_debug_location) |
1a4d82fc | 1956 | } else { |
85aaf69f | 1957 | Ret(ret_cx, C_undef(Type::nil(fcx.ccx)), ret_debug_location) |
1a4d82fc JJ |
1958 | } |
1959 | } | |
92a42be0 | 1960 | }, |
1a4d82fc JJ |
1961 | } |
1962 | } | |
1963 | ||
9346a6ac AL |
1964 | /// Builds an LLVM function out of a source function. |
1965 | /// | |
1966 | /// If the function closes over its environment a closure will be returned. | |
1a4d82fc | 1967 | pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
e9174d1e SL |
1968 | decl: &hir::FnDecl, |
1969 | body: &hir::Block, | |
1a4d82fc | 1970 | llfndecl: ValueRef, |
85aaf69f | 1971 | param_substs: &'tcx Substs<'tcx>, |
1a4d82fc | 1972 | fn_ast_id: ast::NodeId, |
92a42be0 | 1973 | attributes: &[ast::Attribute], |
1a4d82fc JJ |
1974 | output_type: ty::FnOutput<'tcx>, |
1975 | abi: Abi, | |
85aaf69f | 1976 | closure_env: closure::ClosureEnv<'b>) { |
1a4d82fc JJ |
1977 | ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); |
1978 | ||
7453a54e SL |
1979 | record_translation_item_as_generated(ccx, fn_ast_id, param_substs); |
1980 | ||
1a4d82fc | 1981 | let _icx = push_ctxt("trans_closure"); |
9346a6ac | 1982 | attributes::emit_uwtable(llfndecl, true); |
1a4d82fc | 1983 | |
92a42be0 | 1984 | debug!("trans_closure(..., param_substs={:?})", param_substs); |
1a4d82fc | 1985 | |
85aaf69f | 1986 | let has_env = match closure_env { |
b039eaaf | 1987 | closure::ClosureEnv::Closure(..) => true, |
85aaf69f SL |
1988 | closure::ClosureEnv::NotClosure => false, |
1989 | }; | |
1990 | ||
1991 | let (arena, fcx): (TypedArena<_>, FunctionContext); | |
1992 | arena = TypedArena::new(); | |
1993 | fcx = new_fn_ctxt(ccx, | |
1994 | llfndecl, | |
1995 | fn_ast_id, | |
1996 | has_env, | |
1997 | output_type, | |
1998 | param_substs, | |
1999 | Some(body.span), | |
2000 | &arena); | |
1a4d82fc JJ |
2001 | let mut bcx = init_function(&fcx, false, output_type); |
2002 | ||
92a42be0 | 2003 | if attributes.iter().any(|item| item.check_name("rustc_mir")) { |
7453a54e | 2004 | mir::trans_mir(bcx.build()); |
92a42be0 SL |
2005 | fcx.cleanup(); |
2006 | return; | |
2007 | } | |
2008 | ||
1a4d82fc | 2009 | // cleanup scope for the incoming arguments |
92a42be0 SL |
2010 | let fn_cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(ccx, |
2011 | fn_ast_id, | |
2012 | body.span, | |
2013 | true); | |
1a4d82fc JJ |
2014 | let arg_scope = fcx.push_custom_cleanup_scope_with_debug_loc(fn_cleanup_debug_loc); |
2015 | ||
2016 | let block_ty = node_id_type(bcx, body.id); | |
2017 | ||
2018 | // Set up arguments to the function. | |
92a42be0 SL |
2019 | let monomorphized_arg_types = decl.inputs |
2020 | .iter() | |
2021 | .map(|arg| node_id_type(bcx, arg.id)) | |
2022 | .collect::<Vec<_>>(); | |
85aaf69f | 2023 | for monomorphized_arg_type in &monomorphized_arg_types { |
62682a34 SL |
2024 | debug!("trans_closure: monomorphized_arg_type: {:?}", |
2025 | monomorphized_arg_type); | |
1a4d82fc JJ |
2026 | } |
2027 | debug!("trans_closure: function lltype: {}", | |
2028 | bcx.fcx.ccx.tn().val_to_string(bcx.fcx.llfn)); | |
2029 | ||
c1a9b12d | 2030 | let has_tupled_arg = match closure_env { |
7453a54e | 2031 | closure::ClosureEnv::NotClosure => abi == Abi::RustCall, |
92a42be0 | 2032 | _ => false, |
1a4d82fc JJ |
2033 | }; |
2034 | ||
92a42be0 SL |
2035 | bcx = create_datums_for_fn_args(bcx, |
2036 | &decl.inputs, | |
2037 | &monomorphized_arg_types, | |
2038 | has_tupled_arg, | |
2039 | arg_scope); | |
c34b1796 | 2040 | |
1a4d82fc JJ |
2041 | bcx = closure_env.load(bcx, cleanup::CustomScope(arg_scope)); |
2042 | ||
2043 | // Up until here, IR instructions for this function have explicitly not been annotated with | |
2044 | // source code location, so we don't step into call setup code. From here on, source location | |
2045 | // emitting should be enabled. | |
2046 | debuginfo::start_emitting_source_locations(&fcx); | |
2047 | ||
2048 | let dest = match fcx.llretslotptr.get() { | |
2049 | Some(_) => expr::SaveIn(fcx.get_ret_slot(bcx, ty::FnConverging(block_ty), "iret_slot")), | |
2050 | None => { | |
2051 | assert!(type_is_zero_size(bcx.ccx(), block_ty)); | |
2052 | expr::Ignore | |
2053 | } | |
2054 | }; | |
2055 | ||
2056 | // This call to trans_block is the place where we bridge between | |
2057 | // translation calls that don't have a return value (trans_crate, | |
2058 | // trans_mod, trans_item, et cetera) and those that do | |
2059 | // (trans_block, trans_expr, et cetera). | |
2060 | bcx = controlflow::trans_block(bcx, body, dest); | |
2061 | ||
2062 | match dest { | |
2063 | expr::SaveIn(slot) if fcx.needs_ret_allocas => { | |
2064 | Store(bcx, slot, fcx.llretslotptr.get().unwrap()); | |
2065 | } | |
2066 | _ => {} | |
2067 | } | |
2068 | ||
2069 | match fcx.llreturn.get() { | |
2070 | Some(_) => { | |
85aaf69f | 2071 | Br(bcx, fcx.return_exit_block(), DebugLoc::None); |
1a4d82fc JJ |
2072 | fcx.pop_custom_cleanup_scope(arg_scope); |
2073 | } | |
2074 | None => { | |
2075 | // Microoptimization writ large: avoid creating a separate | |
2076 | // llreturn basic block | |
2077 | bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope); | |
2078 | } | |
2079 | }; | |
2080 | ||
2081 | // Put return block after all other blocks. | |
2082 | // This somewhat improves single-stepping experience in debugger. | |
2083 | unsafe { | |
2084 | let llreturn = fcx.llreturn.get(); | |
85aaf69f | 2085 | if let Some(llreturn) = llreturn { |
1a4d82fc JJ |
2086 | llvm::LLVMMoveBasicBlockAfter(llreturn, bcx.llbb); |
2087 | } | |
2088 | } | |
2089 | ||
92a42be0 | 2090 | let ret_debug_loc = DebugLoc::At(fn_cleanup_debug_loc.id, fn_cleanup_debug_loc.span); |
85aaf69f | 2091 | |
1a4d82fc | 2092 | // Insert the mandatory first few basic blocks before lltop. |
85aaf69f | 2093 | finish_fn(&fcx, bcx, output_type, ret_debug_loc); |
7453a54e SL |
2094 | |
2095 | fn record_translation_item_as_generated<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
2096 | node_id: ast::NodeId, | |
2097 | param_substs: &'tcx Substs<'tcx>) { | |
2098 | if !collector::collecting_debug_information(ccx) { | |
2099 | return; | |
2100 | } | |
2101 | ||
2102 | let def_id = match ccx.tcx().node_id_to_type(node_id).sty { | |
2103 | ty::TyClosure(def_id, _) => def_id, | |
2104 | _ => ccx.external_srcs() | |
2105 | .borrow() | |
2106 | .get(&node_id) | |
2107 | .map(|did| *did) | |
2108 | .unwrap_or_else(|| ccx.tcx().map.local_def_id(node_id)), | |
2109 | }; | |
2110 | ||
2111 | ccx.record_translation_item_as_generated(TransItem::Fn{ | |
2112 | def_id: def_id, | |
2113 | substs: ccx.tcx().mk_substs(ccx.tcx().erase_regions(param_substs)), | |
2114 | }); | |
2115 | } | |
1a4d82fc JJ |
2116 | } |
2117 | ||
9346a6ac | 2118 | /// Creates an LLVM function corresponding to a source language function. |
1a4d82fc | 2119 | pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
e9174d1e SL |
2120 | decl: &hir::FnDecl, |
2121 | body: &hir::Block, | |
1a4d82fc | 2122 | llfndecl: ValueRef, |
85aaf69f | 2123 | param_substs: &'tcx Substs<'tcx>, |
1a4d82fc | 2124 | id: ast::NodeId, |
b039eaaf | 2125 | attrs: &[ast::Attribute]) { |
1a4d82fc | 2126 | let _s = StatRecorder::new(ccx, ccx.tcx().map.path_to_string(id).to_string()); |
62682a34 | 2127 | debug!("trans_fn(param_substs={:?})", param_substs); |
1a4d82fc | 2128 | let _icx = push_ctxt("trans_fn"); |
c1a9b12d | 2129 | let fn_ty = ccx.tcx().node_id_to_type(id); |
92a42be0 SL |
2130 | let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fn_ty); |
2131 | let sig = fn_ty.fn_sig(); | |
2132 | let sig = ccx.tcx().erase_late_bound_regions(&sig); | |
2133 | let sig = infer::normalize_associated_type(ccx.tcx(), &sig); | |
2134 | let output_type = sig.output; | |
c1a9b12d | 2135 | let abi = fn_ty.fn_abi(); |
92a42be0 SL |
2136 | trans_closure(ccx, |
2137 | decl, | |
2138 | body, | |
2139 | llfndecl, | |
2140 | param_substs, | |
2141 | id, | |
2142 | attrs, | |
2143 | output_type, | |
2144 | abi, | |
85aaf69f | 2145 | closure::ClosureEnv::NotClosure); |
1a4d82fc JJ |
2146 | } |
2147 | ||
2148 | pub fn trans_enum_variant<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
e9174d1e | 2149 | ctor_id: ast::NodeId, |
9cc50fc6 | 2150 | disr: Disr, |
85aaf69f | 2151 | param_substs: &'tcx Substs<'tcx>, |
1a4d82fc JJ |
2152 | llfndecl: ValueRef) { |
2153 | let _icx = push_ctxt("trans_enum_variant"); | |
2154 | ||
92a42be0 | 2155 | trans_enum_variant_or_tuple_like_struct(ccx, ctor_id, disr, param_substs, llfndecl); |
1a4d82fc JJ |
2156 | } |
2157 | ||
2158 | pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, | |
2159 | ctor_ty: Ty<'tcx>, | |
9cc50fc6 | 2160 | disr: Disr, |
1a4d82fc JJ |
2161 | args: callee::CallArgs, |
2162 | dest: expr::Dest, | |
85aaf69f | 2163 | debug_loc: DebugLoc) |
1a4d82fc JJ |
2164 | -> Result<'blk, 'tcx> { |
2165 | ||
2166 | let ccx = bcx.fcx.ccx; | |
1a4d82fc | 2167 | |
92a42be0 SL |
2168 | let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig()); |
2169 | let sig = infer::normalize_associated_type(ccx.tcx(), &sig); | |
2170 | let result_ty = sig.output.unwrap(); | |
1a4d82fc JJ |
2171 | |
2172 | // Get location to store the result. If the user does not care about | |
2173 | // the result, just make a stack slot | |
2174 | let llresult = match dest { | |
2175 | expr::SaveIn(d) => d, | |
2176 | expr::Ignore => { | |
2177 | if !type_is_zero_size(ccx, result_ty) { | |
e9174d1e SL |
2178 | let llresult = alloc_ty(bcx, result_ty, "constructor_result"); |
2179 | call_lifetime_start(bcx, llresult); | |
2180 | llresult | |
1a4d82fc | 2181 | } else { |
62682a34 | 2182 | C_undef(type_of::type_of(ccx, result_ty).ptr_to()) |
1a4d82fc JJ |
2183 | } |
2184 | } | |
2185 | }; | |
2186 | ||
2187 | if !type_is_zero_size(ccx, result_ty) { | |
2188 | match args { | |
2189 | callee::ArgExprs(exprs) => { | |
2190 | let fields = exprs.iter().map(|x| &**x).enumerate().collect::<Vec<_>>(); | |
2191 | bcx = expr::trans_adt(bcx, | |
2192 | result_ty, | |
2193 | disr, | |
85aaf69f | 2194 | &fields[..], |
1a4d82fc JJ |
2195 | None, |
2196 | expr::SaveIn(llresult), | |
85aaf69f | 2197 | debug_loc); |
1a4d82fc | 2198 | } |
92a42be0 | 2199 | _ => ccx.sess().bug("expected expr as arguments for variant/struct tuple constructor"), |
1a4d82fc | 2200 | } |
e9174d1e SL |
2201 | } else { |
2202 | // Just eval all the expressions (if any). Since expressions in Rust can have arbitrary | |
2203 | // contents, there could be side-effects we need from them. | |
2204 | match args { | |
2205 | callee::ArgExprs(exprs) => { | |
2206 | for expr in exprs { | |
2207 | bcx = expr::trans_into(bcx, expr, expr::Ignore); | |
2208 | } | |
2209 | } | |
92a42be0 | 2210 | _ => (), |
e9174d1e | 2211 | } |
1a4d82fc JJ |
2212 | } |
2213 | ||
2214 | // If the caller doesn't care about the result | |
2215 | // drop the temporary we made | |
2216 | let bcx = match dest { | |
2217 | expr::SaveIn(_) => bcx, | |
2218 | expr::Ignore => { | |
85aaf69f SL |
2219 | let bcx = glue::drop_ty(bcx, llresult, result_ty, debug_loc); |
2220 | if !type_is_zero_size(ccx, result_ty) { | |
2221 | call_lifetime_end(bcx, llresult); | |
2222 | } | |
2223 | bcx | |
1a4d82fc JJ |
2224 | } |
2225 | }; | |
2226 | ||
2227 | Result::new(bcx, llresult) | |
2228 | } | |
2229 | ||
2230 | pub fn trans_tuple_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
1a4d82fc | 2231 | ctor_id: ast::NodeId, |
85aaf69f | 2232 | param_substs: &'tcx Substs<'tcx>, |
1a4d82fc JJ |
2233 | llfndecl: ValueRef) { |
2234 | let _icx = push_ctxt("trans_tuple_struct"); | |
2235 | ||
9cc50fc6 | 2236 | trans_enum_variant_or_tuple_like_struct(ccx, ctor_id, Disr(0), param_substs, llfndecl); |
1a4d82fc JJ |
2237 | } |
2238 | ||
2239 | fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
2240 | ctor_id: ast::NodeId, | |
9cc50fc6 | 2241 | disr: Disr, |
85aaf69f | 2242 | param_substs: &'tcx Substs<'tcx>, |
1a4d82fc | 2243 | llfndecl: ValueRef) { |
c1a9b12d | 2244 | let ctor_ty = ccx.tcx().node_id_to_type(ctor_id); |
1a4d82fc JJ |
2245 | let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty); |
2246 | ||
92a42be0 SL |
2247 | let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig()); |
2248 | let sig = infer::normalize_associated_type(ccx.tcx(), &sig); | |
2249 | let arg_tys = sig.inputs; | |
2250 | let result_ty = sig.output; | |
1a4d82fc | 2251 | |
85aaf69f SL |
2252 | let (arena, fcx): (TypedArena<_>, FunctionContext); |
2253 | arena = TypedArena::new(); | |
92a42be0 SL |
2254 | fcx = new_fn_ctxt(ccx, |
2255 | llfndecl, | |
2256 | ctor_id, | |
2257 | false, | |
2258 | result_ty, | |
2259 | param_substs, | |
2260 | None, | |
2261 | &arena); | |
1a4d82fc JJ |
2262 | let bcx = init_function(&fcx, false, result_ty); |
2263 | ||
2264 | assert!(!fcx.needs_ret_allocas); | |
2265 | ||
1a4d82fc JJ |
2266 | if !type_is_zero_size(fcx.ccx, result_ty.unwrap()) { |
2267 | let dest = fcx.get_ret_slot(bcx, result_ty, "eret_slot"); | |
92a42be0 | 2268 | let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value |
1a4d82fc | 2269 | let repr = adt::represent_type(ccx, result_ty.unwrap()); |
c1a9b12d SL |
2270 | let mut llarg_idx = fcx.arg_offset() as c_uint; |
2271 | for (i, arg_ty) in arg_tys.into_iter().enumerate() { | |
7453a54e | 2272 | let lldestptr = adt::trans_field_ptr(bcx, &repr, dest_val, Disr::from(disr), i); |
c1a9b12d | 2273 | if common::type_is_fat_ptr(bcx.tcx(), arg_ty) { |
92a42be0 SL |
2274 | Store(bcx, |
2275 | get_param(fcx.llfn, llarg_idx), | |
2276 | expr::get_dataptr(bcx, lldestptr)); | |
2277 | Store(bcx, | |
2278 | get_param(fcx.llfn, llarg_idx + 1), | |
2279 | expr::get_meta(bcx, lldestptr)); | |
c1a9b12d SL |
2280 | llarg_idx += 2; |
2281 | } else { | |
2282 | let arg = get_param(fcx.llfn, llarg_idx); | |
2283 | llarg_idx += 1; | |
2284 | ||
2285 | if arg_is_indirect(ccx, arg_ty) { | |
2286 | memcpy_ty(bcx, lldestptr, arg, arg_ty); | |
2287 | } else { | |
2288 | store_ty(bcx, arg, lldestptr, arg_ty); | |
2289 | } | |
2290 | } | |
1a4d82fc | 2291 | } |
7453a54e | 2292 | adt::trans_set_discr(bcx, &repr, dest, disr); |
1a4d82fc JJ |
2293 | } |
2294 | ||
85aaf69f | 2295 | finish_fn(&fcx, bcx, result_ty, DebugLoc::None); |
1a4d82fc JJ |
2296 | } |
2297 | ||
e9174d1e | 2298 | fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &hir::EnumDef, sp: Span, id: ast::NodeId) { |
1a4d82fc JJ |
2299 | let mut sizes = Vec::new(); // does no allocation if no pushes, thankfully |
2300 | ||
2301 | let print_info = ccx.sess().print_enum_sizes(); | |
2302 | ||
2303 | let levels = ccx.tcx().node_lint_levels.borrow(); | |
2304 | let lint_id = lint::LintId::of(lint::builtin::VARIANT_SIZE_DIFFERENCES); | |
2305 | let lvlsrc = levels.get(&(id, lint_id)); | |
2306 | let is_allow = lvlsrc.map_or(true, |&(lvl, _)| lvl == lint::Allow); | |
2307 | ||
2308 | if is_allow && !print_info { | |
2309 | // we're not interested in anything here | |
92a42be0 | 2310 | return; |
1a4d82fc JJ |
2311 | } |
2312 | ||
c1a9b12d | 2313 | let ty = ccx.tcx().node_id_to_type(id); |
1a4d82fc JJ |
2314 | let avar = adt::represent_type(ccx, ty); |
2315 | match *avar { | |
2316 | adt::General(_, ref variants, _) => { | |
85aaf69f | 2317 | for var in variants { |
1a4d82fc JJ |
2318 | let mut size = 0; |
2319 | for field in var.fields.iter().skip(1) { | |
2320 | // skip the discriminant | |
2321 | size += llsize_of_real(ccx, sizing_type_of(ccx, *field)); | |
2322 | } | |
2323 | sizes.push(size); | |
2324 | } | |
2325 | }, | |
2326 | _ => { /* its size is either constant or unimportant */ } | |
2327 | } | |
2328 | ||
2329 | let (largest, slargest, largest_index) = sizes.iter().enumerate().fold((0, 0, 0), | |
2330 | |(l, s, li), (idx, &size)| | |
2331 | if size > l { | |
2332 | (size, l, idx) | |
2333 | } else if size > s { | |
2334 | (l, size, li) | |
2335 | } else { | |
2336 | (l, s, li) | |
2337 | } | |
2338 | ); | |
2339 | ||
9cc50fc6 | 2340 | // FIXME(#30505) Should use logging for this. |
1a4d82fc JJ |
2341 | if print_info { |
2342 | let llty = type_of::sizing_type_of(ccx, ty); | |
2343 | ||
2344 | let sess = &ccx.tcx().sess; | |
9cc50fc6 | 2345 | sess.span_note_without_error(sp, |
7453a54e | 2346 | &format!("total size: {} bytes", llsize_of_real(ccx, llty))); |
1a4d82fc JJ |
2347 | match *avar { |
2348 | adt::General(..) => { | |
2349 | for (i, var) in enum_def.variants.iter().enumerate() { | |
92a42be0 SL |
2350 | ccx.tcx() |
2351 | .sess | |
9cc50fc6 | 2352 | .span_note_without_error(var.span, |
7453a54e | 2353 | &format!("variant data: {} bytes", sizes[i])); |
1a4d82fc JJ |
2354 | } |
2355 | } | |
2356 | _ => {} | |
2357 | } | |
2358 | } | |
2359 | ||
2360 | // we only warn if the largest variant is at least thrice as large as | |
2361 | // the second-largest. | |
2362 | if !is_allow && largest > slargest * 3 && slargest > 0 { | |
2363 | // Use lint::raw_emit_lint rather than sess.add_lint because the lint-printing | |
2364 | // pass for the latter already ran. | |
9cc50fc6 SL |
2365 | lint::raw_struct_lint(&ccx.tcx().sess, |
2366 | &ccx.tcx().sess.lint_store.borrow(), | |
2367 | lint::builtin::VARIANT_SIZE_DIFFERENCES, | |
2368 | *lvlsrc.unwrap(), | |
2369 | Some(sp), | |
2370 | &format!("enum variant is more than three times larger ({} bytes) \ | |
2371 | than the next largest (ignoring padding)", | |
2372 | largest)) | |
2373 | .span_note(enum_def.variants[largest_index].span, | |
2374 | "this variant is the largest") | |
2375 | .emit(); | |
1a4d82fc JJ |
2376 | } |
2377 | } | |
2378 | ||
1a4d82fc JJ |
2379 | pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> { |
2380 | // Use the names from src/llvm/docs/LangRef.rst here. Most types are only | |
2381 | // applicable to variable declarations and may not really make sense for | |
2382 | // Rust code in the first place but whitelist them anyway and trust that | |
2383 | // the user knows what s/he's doing. Who knows, unanticipated use cases | |
2384 | // may pop up in the future. | |
2385 | // | |
2386 | // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported | |
2387 | // and don't have to be, LLVM treats them as no-ops. | |
2388 | match name { | |
2389 | "appending" => Some(llvm::AppendingLinkage), | |
2390 | "available_externally" => Some(llvm::AvailableExternallyLinkage), | |
2391 | "common" => Some(llvm::CommonLinkage), | |
2392 | "extern_weak" => Some(llvm::ExternalWeakLinkage), | |
2393 | "external" => Some(llvm::ExternalLinkage), | |
2394 | "internal" => Some(llvm::InternalLinkage), | |
2395 | "linkonce" => Some(llvm::LinkOnceAnyLinkage), | |
2396 | "linkonce_odr" => Some(llvm::LinkOnceODRLinkage), | |
2397 | "private" => Some(llvm::PrivateLinkage), | |
2398 | "weak" => Some(llvm::WeakAnyLinkage), | |
2399 | "weak_odr" => Some(llvm::WeakODRLinkage), | |
2400 | _ => None, | |
2401 | } | |
2402 | } | |
2403 | ||
2404 | ||
2405 | /// Enum describing the origin of an LLVM `Value`, for linkage purposes. | |
c34b1796 | 2406 | #[derive(Copy, Clone)] |
1a4d82fc JJ |
2407 | pub enum ValueOrigin { |
2408 | /// The LLVM `Value` is in this context because the corresponding item was | |
2409 | /// assigned to the current compilation unit. | |
2410 | OriginalTranslation, | |
2411 | /// The `Value`'s corresponding item was assigned to some other compilation | |
2412 | /// unit, but the `Value` was translated in this context anyway because the | |
2413 | /// item is marked `#[inline]`. | |
2414 | InlinedCopy, | |
2415 | } | |
2416 | ||
2417 | /// Set the appropriate linkage for an LLVM `ValueRef` (function or global). | |
2418 | /// If the `llval` is the direct translation of a specific Rust item, `id` | |
2419 | /// should be set to the `NodeId` of that item. (This mapping should be | |
2420 | /// 1-to-1, so monomorphizations and drop/visit glue should have `id` set to | |
2421 | /// `None`.) `llval_origin` indicates whether `llval` is the translation of an | |
2422 | /// item assigned to `ccx`'s compilation unit or an inlined copy of an item | |
2423 | /// assigned to a different compilation unit. | |
2424 | pub fn update_linkage(ccx: &CrateContext, | |
2425 | llval: ValueRef, | |
2426 | id: Option<ast::NodeId>, | |
2427 | llval_origin: ValueOrigin) { | |
2428 | match llval_origin { | |
2429 | InlinedCopy => { | |
2430 | // `llval` is a translation of an item defined in a separate | |
2431 | // compilation unit. This only makes sense if there are at least | |
2432 | // two compilation units. | |
2433 | assert!(ccx.sess().opts.cg.codegen_units > 1); | |
2434 | // `llval` is a copy of something defined elsewhere, so use | |
2435 | // `AvailableExternallyLinkage` to avoid duplicating code in the | |
2436 | // output. | |
2437 | llvm::SetLinkage(llval, llvm::AvailableExternallyLinkage); | |
2438 | return; | |
2439 | }, | |
2440 | OriginalTranslation => {}, | |
2441 | } | |
2442 | ||
2443 | if let Some(id) = id { | |
2444 | let item = ccx.tcx().map.get(id); | |
e9174d1e | 2445 | if let hir_map::NodeItem(i) = item { |
85aaf69f SL |
2446 | if let Some(name) = attr::first_attr_value_str_by_name(&i.attrs, "linkage") { |
2447 | if let Some(linkage) = llvm_linkage_by_name(&name) { | |
1a4d82fc JJ |
2448 | llvm::SetLinkage(llval, linkage); |
2449 | } else { | |
2450 | ccx.sess().span_fatal(i.span, "invalid linkage specified"); | |
2451 | } | |
2452 | return; | |
2453 | } | |
2454 | } | |
2455 | } | |
2456 | ||
2457 | match id { | |
2458 | Some(id) if ccx.reachable().contains(&id) => { | |
2459 | llvm::SetLinkage(llval, llvm::ExternalLinkage); | |
2460 | }, | |
2461 | _ => { | |
2462 | // `id` does not refer to an item in `ccx.reachable`. | |
2463 | if ccx.sess().opts.cg.codegen_units > 1 { | |
2464 | llvm::SetLinkage(llval, llvm::ExternalLinkage); | |
2465 | } else { | |
2466 | llvm::SetLinkage(llval, llvm::InternalLinkage); | |
2467 | } | |
2468 | }, | |
2469 | } | |
2470 | } | |
2471 | ||
e9174d1e | 2472 | fn set_global_section(ccx: &CrateContext, llval: ValueRef, i: &hir::Item) { |
92a42be0 | 2473 | match attr::first_attr_value_str_by_name(&i.attrs, "link_section") { |
c1a9b12d SL |
2474 | Some(sect) => { |
2475 | if contains_null(§) { | |
92a42be0 | 2476 | ccx.sess().fatal(&format!("Illegal null byte in link_section value: `{}`", §)); |
c1a9b12d SL |
2477 | } |
2478 | unsafe { | |
2479 | let buf = CString::new(sect.as_bytes()).unwrap(); | |
2480 | llvm::LLVMSetSection(llval, buf.as_ptr()); | |
2481 | } | |
2482 | }, | |
2483 | None => () | |
2484 | } | |
2485 | } | |
2486 | ||
e9174d1e | 2487 | pub fn trans_item(ccx: &CrateContext, item: &hir::Item) { |
1a4d82fc JJ |
2488 | let _icx = push_ctxt("trans_item"); |
2489 | ||
2490 | let from_external = ccx.external_srcs().borrow().contains_key(&item.id); | |
2491 | ||
2492 | match item.node { | |
92a42be0 SL |
2493 | hir::ItemFn(ref decl, _, _, abi, ref generics, ref body) => { |
2494 | if !generics.is_type_parameterized() { | |
2495 | let trans_everywhere = attr::requests_inline(&item.attrs); | |
2496 | // Ignore `trans_everywhere` for cross-crate inlined items | |
2497 | // (`from_external`). `trans_item` will be called once for each | |
2498 | // compilation unit that references the item, so it will still get | |
2499 | // translated everywhere it's needed. | |
2500 | for (ref ccx, is_origin) in ccx.maybe_iter(!from_external && trans_everywhere) { | |
2501 | let llfn = get_item_val(ccx, item.id); | |
2502 | let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); | |
7453a54e | 2503 | if abi != Abi::Rust { |
92a42be0 | 2504 | foreign::trans_rust_fn_with_foreign_abi(ccx, |
7453a54e SL |
2505 | &decl, |
2506 | &body, | |
92a42be0 SL |
2507 | &item.attrs, |
2508 | llfn, | |
2509 | empty_substs, | |
2510 | item.id, | |
2511 | None); | |
2512 | } else { | |
2513 | trans_fn(ccx, | |
7453a54e SL |
2514 | &decl, |
2515 | &body, | |
92a42be0 SL |
2516 | llfn, |
2517 | empty_substs, | |
2518 | item.id, | |
2519 | &item.attrs); | |
2520 | } | |
2521 | set_global_section(ccx, llfn, item); | |
2522 | update_linkage(ccx, | |
2523 | llfn, | |
2524 | Some(item.id), | |
2525 | if is_origin { | |
2526 | OriginalTranslation | |
2527 | } else { | |
2528 | InlinedCopy | |
2529 | }); | |
2530 | ||
2531 | if is_entry_fn(ccx.sess(), item.id) { | |
2532 | create_entry_wrapper(ccx, item.span, llfn); | |
2533 | // check for the #[rustc_error] annotation, which forces an | |
2534 | // error in trans. This is used to write compile-fail tests | |
2535 | // that actually test that compilation succeeds without | |
2536 | // reporting an error. | |
2537 | let item_def_id = ccx.tcx().map.local_def_id(item.id); | |
2538 | if ccx.tcx().has_attr(item_def_id, "rustc_error") { | |
2539 | ccx.tcx().sess.span_fatal(item.span, "compilation successful"); | |
2540 | } | |
9346a6ac AL |
2541 | } |
2542 | } | |
1a4d82fc JJ |
2543 | } |
2544 | } | |
92a42be0 SL |
2545 | hir::ItemImpl(_, _, ref generics, _, _, ref impl_items) => { |
2546 | meth::trans_impl(ccx, item.name, impl_items, generics, item.id); | |
2547 | } | |
2548 | hir::ItemMod(_) => { | |
2549 | // modules have no equivalent at runtime, they just affect | |
2550 | // the mangled names of things contained within | |
2551 | } | |
2552 | hir::ItemEnum(ref enum_definition, ref gens) => { | |
2553 | if gens.ty_params.is_empty() { | |
2554 | // sizes only make sense for non-generic types | |
1a4d82fc | 2555 | |
92a42be0 SL |
2556 | enum_variant_size_lint(ccx, enum_definition, item.span, item.id); |
2557 | } | |
2558 | } | |
2559 | hir::ItemConst(..) => {} | |
2560 | hir::ItemStatic(_, m, ref expr) => { | |
2561 | let g = match consts::trans_static(ccx, m, expr, item.id, &item.attrs) { | |
2562 | Ok(g) => g, | |
2563 | Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()), | |
2564 | }; | |
2565 | set_global_section(ccx, g, item); | |
2566 | update_linkage(ccx, g, Some(item.id), OriginalTranslation); | |
2567 | } | |
2568 | hir::ItemForeignMod(ref foreign_mod) => { | |
2569 | foreign::trans_foreign_mod(ccx, foreign_mod); | |
2570 | } | |
2571 | hir::ItemTrait(..) => {} | |
2572 | _ => { | |
2573 | // fall through | |
2574 | } | |
1a4d82fc JJ |
2575 | } |
2576 | } | |
2577 | ||
9346a6ac AL |
2578 | // only use this for foreign function ABIs and glue, use `register_fn` for Rust functions |
2579 | pub fn register_fn_llvmty(ccx: &CrateContext, | |
2580 | sp: Span, | |
2581 | sym: String, | |
2582 | node_id: ast::NodeId, | |
92a42be0 SL |
2583 | cc: llvm::CallConv, |
2584 | llfty: Type) | |
2585 | -> ValueRef { | |
9346a6ac AL |
2586 | debug!("register_fn_llvmty id={} sym={}", node_id, sym); |
2587 | ||
2588 | let llfn = declare::define_fn(ccx, &sym[..], cc, llfty, | |
c1a9b12d | 2589 | ty::FnConverging(ccx.tcx().mk_nil())).unwrap_or_else(||{ |
9346a6ac AL |
2590 | ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym)); |
2591 | }); | |
e9174d1e | 2592 | finish_register_fn(ccx, sym, node_id); |
9346a6ac AL |
2593 | llfn |
2594 | } | |
2595 | ||
e9174d1e | 2596 | fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId) { |
1a4d82fc | 2597 | ccx.item_symbols().borrow_mut().insert(node_id, sym); |
1a4d82fc JJ |
2598 | } |
2599 | ||
2600 | fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
2601 | sp: Span, | |
2602 | sym: String, | |
2603 | node_id: ast::NodeId, | |
2604 | node_type: Ty<'tcx>) | |
2605 | -> ValueRef { | |
62682a34 | 2606 | if let ty::TyBareFn(_, ref f) = node_type.sty { |
7453a54e | 2607 | if f.abi != Abi::Rust && f.abi != Abi::RustCall { |
92a42be0 SL |
2608 | ccx.sess().span_bug(sp, |
2609 | &format!("only the `{}` or `{}` calling conventions are valid \ | |
2610 | for this function; `{}` was specified", | |
7453a54e SL |
2611 | Abi::Rust.name(), |
2612 | Abi::RustCall.name(), | |
92a42be0 | 2613 | f.abi.name())); |
1a4d82fc | 2614 | } |
c34b1796 AL |
2615 | } else { |
2616 | ccx.sess().span_bug(sp, "expected bare rust function") | |
2617 | } | |
1a4d82fc | 2618 | |
92a42be0 | 2619 | let llfn = declare::define_rust_fn(ccx, &sym[..], node_type).unwrap_or_else(|| { |
9346a6ac AL |
2620 | ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym)); |
2621 | }); | |
e9174d1e | 2622 | finish_register_fn(ccx, sym, node_id); |
1a4d82fc JJ |
2623 | llfn |
2624 | } | |
2625 | ||
2626 | pub fn is_entry_fn(sess: &Session, node_id: ast::NodeId) -> bool { | |
2627 | match *sess.entry_fn.borrow() { | |
2628 | Some((entry_id, _)) => node_id == entry_id, | |
92a42be0 | 2629 | None => false, |
1a4d82fc JJ |
2630 | } |
2631 | } | |
2632 | ||
9346a6ac AL |
2633 | /// Create the `main` function which will initialise the rust runtime and call users’ main |
2634 | /// function. | |
92a42be0 | 2635 | pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) { |
1a4d82fc JJ |
2636 | let et = ccx.sess().entry_type.get().unwrap(); |
2637 | match et { | |
2638 | config::EntryMain => { | |
9346a6ac | 2639 | create_entry_fn(ccx, sp, main_llfn, true); |
1a4d82fc | 2640 | } |
9346a6ac | 2641 | config::EntryStart => create_entry_fn(ccx, sp, main_llfn, false), |
1a4d82fc JJ |
2642 | config::EntryNone => {} // Do nothing. |
2643 | } | |
2644 | ||
2645 | fn create_entry_fn(ccx: &CrateContext, | |
9346a6ac | 2646 | sp: Span, |
1a4d82fc JJ |
2647 | rust_main: ValueRef, |
2648 | use_start_lang_item: bool) { | |
92a42be0 | 2649 | let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], &ccx.int_type()); |
1a4d82fc | 2650 | |
92a42be0 | 2651 | let llfn = declare::define_cfn(ccx, "main", llfty, ccx.tcx().mk_nil()).unwrap_or_else(|| { |
9346a6ac | 2652 | // FIXME: We should be smart and show a better diagnostic here. |
9cc50fc6 SL |
2653 | ccx.sess().struct_span_err(sp, "entry symbol `main` defined multiple times") |
2654 | .help("did you use #[no_mangle] on `fn main`? Use #[start] instead") | |
2655 | .emit(); | |
9346a6ac AL |
2656 | ccx.sess().abort_if_errors(); |
2657 | panic!(); | |
2658 | }); | |
1a4d82fc | 2659 | |
1a4d82fc | 2660 | let llbb = unsafe { |
92a42be0 | 2661 | llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, "top\0".as_ptr() as *const _) |
1a4d82fc JJ |
2662 | }; |
2663 | let bld = ccx.raw_builder(); | |
2664 | unsafe { | |
2665 | llvm::LLVMPositionBuilderAtEnd(bld, llbb); | |
2666 | ||
d9579d0f | 2667 | debuginfo::gdb::insert_reference_to_gdb_debug_scripts_section_global(ccx); |
1a4d82fc JJ |
2668 | |
2669 | let (start_fn, args) = if use_start_lang_item { | |
2670 | let start_def_id = match ccx.tcx().lang_items.require(StartFnLangItem) { | |
2671 | Ok(id) => id, | |
92a42be0 SL |
2672 | Err(s) => { |
2673 | ccx.sess().fatal(&s[..]); | |
2674 | } | |
2675 | }; | |
2676 | let start_fn = if let Some(start_node_id) = ccx.tcx() | |
2677 | .map | |
2678 | .as_local_node_id(start_def_id) { | |
2679 | get_item_val(ccx, start_node_id) | |
2680 | } else { | |
2681 | let start_fn_type = ccx.tcx().lookup_item_type(start_def_id).ty; | |
2682 | trans_external_path(ccx, start_def_id, start_fn_type) | |
1a4d82fc | 2683 | }; |
1a4d82fc | 2684 | let args = { |
92a42be0 SL |
2685 | let opaque_rust_main = |
2686 | llvm::LLVMBuildPointerCast(bld, | |
2687 | rust_main, | |
2688 | Type::i8p(ccx).to_ref(), | |
2689 | "rust_main\0".as_ptr() as *const _); | |
2690 | ||
2691 | vec![opaque_rust_main, get_param(llfn, 0), get_param(llfn, 1)] | |
1a4d82fc JJ |
2692 | }; |
2693 | (start_fn, args) | |
2694 | } else { | |
2695 | debug!("using user-defined start fn"); | |
92a42be0 | 2696 | let args = vec![get_param(llfn, 0 as c_uint), get_param(llfn, 1 as c_uint)]; |
1a4d82fc JJ |
2697 | |
2698 | (rust_main, args) | |
2699 | }; | |
2700 | ||
7453a54e SL |
2701 | let result = llvm::LLVMRustBuildCall(bld, |
2702 | start_fn, | |
2703 | args.as_ptr(), | |
2704 | args.len() as c_uint, | |
2705 | 0 as *mut _, | |
2706 | noname()); | |
1a4d82fc JJ |
2707 | |
2708 | llvm::LLVMBuildRet(bld, result); | |
2709 | } | |
2710 | } | |
2711 | } | |
2712 | ||
92a42be0 SL |
2713 | fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
2714 | id: ast::NodeId, | |
2715 | ty: Ty<'tcx>, | |
2716 | attrs: &[ast::Attribute]) | |
2717 | -> String { | |
1a4d82fc JJ |
2718 | match ccx.external_srcs().borrow().get(&id) { |
2719 | Some(&did) => { | |
92a42be0 | 2720 | let sym = ccx.sess().cstore.item_symbol(did); |
1a4d82fc JJ |
2721 | debug!("found item {} in other crate...", sym); |
2722 | return sym; | |
2723 | } | |
2724 | None => {} | |
2725 | } | |
2726 | ||
9346a6ac | 2727 | match attr::find_export_name_attr(ccx.sess().diagnostic(), attrs) { |
1a4d82fc | 2728 | // Use provided name |
85aaf69f | 2729 | Some(name) => name.to_string(), |
b039eaaf SL |
2730 | _ => { |
2731 | let path = ccx.tcx().map.def_path_from_id(id); | |
1a4d82fc JJ |
2732 | if attr::contains_name(attrs, "no_mangle") { |
2733 | // Don't mangle | |
b039eaaf | 2734 | path.last().unwrap().data.to_string() |
1a4d82fc JJ |
2735 | } else { |
2736 | match weak_lang_items::link_name(attrs) { | |
85aaf69f | 2737 | Some(name) => name.to_string(), |
1a4d82fc JJ |
2738 | None => { |
2739 | // Usual name mangling | |
2740 | mangle_exported_name(ccx, path, ty, id) | |
2741 | } | |
2742 | } | |
2743 | } | |
b039eaaf | 2744 | } |
1a4d82fc JJ |
2745 | } |
2746 | } | |
2747 | ||
2748 | fn contains_null(s: &str) -> bool { | |
2749 | s.bytes().any(|b| b == 0) | |
2750 | } | |
2751 | ||
2752 | pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { | |
2753 | debug!("get_item_val(id=`{}`)", id); | |
2754 | ||
7453a54e SL |
2755 | if let Some(v) = ccx.item_vals().borrow().get(&id).cloned() { |
2756 | return v; | |
1a4d82fc JJ |
2757 | } |
2758 | ||
2759 | let item = ccx.tcx().map.get(id); | |
2760 | debug!("get_item_val: id={} item={:?}", id, item); | |
2761 | let val = match item { | |
e9174d1e | 2762 | hir_map::NodeItem(i) => { |
c1a9b12d | 2763 | let ty = ccx.tcx().node_id_to_type(i.id); |
c34b1796 | 2764 | let sym = || exported_name(ccx, id, ty, &i.attrs); |
1a4d82fc JJ |
2765 | |
2766 | let v = match i.node { | |
e9174d1e | 2767 | hir::ItemStatic(..) => { |
1a4d82fc | 2768 | // If this static came from an external crate, then |
92a42be0 | 2769 | // we need to get the symbol from metadata instead of |
1a4d82fc JJ |
2770 | // using the current crate's name/version |
2771 | // information in the hash of the symbol | |
2772 | let sym = sym(); | |
2773 | debug!("making {}", sym); | |
2774 | ||
c1a9b12d SL |
2775 | // Create the global before evaluating the initializer; |
2776 | // this is necessary to allow recursive statics. | |
2777 | let llty = type_of(ccx, ty); | |
92a42be0 SL |
2778 | let g = declare::define_global(ccx, &sym[..], llty).unwrap_or_else(|| { |
2779 | ccx.sess() | |
2780 | .span_fatal(i.span, &format!("symbol `{}` is already defined", sym)) | |
c1a9b12d SL |
2781 | }); |
2782 | ||
2783 | ccx.item_symbols().borrow_mut().insert(i.id, sym); | |
2784 | g | |
1a4d82fc JJ |
2785 | } |
2786 | ||
e9174d1e | 2787 | hir::ItemFn(_, _, _, abi, _, _) => { |
1a4d82fc | 2788 | let sym = sym(); |
7453a54e | 2789 | let llfn = if abi == Abi::Rust { |
1a4d82fc JJ |
2790 | register_fn(ccx, i.span, sym, i.id, ty) |
2791 | } else { | |
9346a6ac | 2792 | foreign::register_rust_fn_with_foreign_abi(ccx, i.span, sym, i.id) |
1a4d82fc | 2793 | }; |
9346a6ac | 2794 | attributes::from_fn_attrs(ccx, &i.attrs, llfn); |
1a4d82fc JJ |
2795 | llfn |
2796 | } | |
2797 | ||
92a42be0 | 2798 | _ => ccx.sess().bug("get_item_val: weird result in table"), |
1a4d82fc JJ |
2799 | }; |
2800 | ||
1a4d82fc JJ |
2801 | v |
2802 | } | |
2803 | ||
e9174d1e | 2804 | hir_map::NodeTraitItem(trait_item) => { |
1a4d82fc | 2805 | debug!("get_item_val(): processing a NodeTraitItem"); |
c34b1796 | 2806 | match trait_item.node { |
e9174d1e | 2807 | hir::MethodTraitItem(_, Some(_)) => { |
c34b1796 | 2808 | register_method(ccx, id, &trait_item.attrs, trait_item.span) |
1a4d82fc | 2809 | } |
d9579d0f AL |
2810 | _ => { |
2811 | ccx.sess().span_bug(trait_item.span, | |
92a42be0 SL |
2812 | "unexpected variant: trait item other than a provided \ |
2813 | method in get_item_val()"); | |
d9579d0f | 2814 | } |
1a4d82fc JJ |
2815 | } |
2816 | } | |
2817 | ||
e9174d1e | 2818 | hir_map::NodeImplItem(impl_item) => { |
c34b1796 | 2819 | match impl_item.node { |
92a42be0 | 2820 | hir::ImplItemKind::Method(..) => { |
c34b1796 AL |
2821 | register_method(ccx, id, &impl_item.attrs, impl_item.span) |
2822 | } | |
d9579d0f | 2823 | _ => { |
c34b1796 | 2824 | ccx.sess().span_bug(impl_item.span, |
92a42be0 SL |
2825 | "unexpected variant: non-method impl item in \ |
2826 | get_item_val()"); | |
1a4d82fc JJ |
2827 | } |
2828 | } | |
2829 | } | |
2830 | ||
e9174d1e | 2831 | hir_map::NodeForeignItem(ni) => { |
1a4d82fc | 2832 | match ni.node { |
e9174d1e | 2833 | hir::ForeignItemFn(..) => { |
1a4d82fc | 2834 | let abi = ccx.tcx().map.get_foreign_abi(id); |
c1a9b12d | 2835 | let ty = ccx.tcx().node_id_to_type(ni.id); |
7453a54e | 2836 | let name = foreign::link_name(&ni); |
e9174d1e | 2837 | foreign::register_foreign_item_fn(ccx, abi, ty, &name, &ni.attrs) |
1a4d82fc | 2838 | } |
e9174d1e | 2839 | hir::ForeignItemStatic(..) => { |
7453a54e | 2840 | foreign::register_static(ccx, &ni) |
1a4d82fc JJ |
2841 | } |
2842 | } | |
2843 | } | |
2844 | ||
e9174d1e | 2845 | hir_map::NodeVariant(ref v) => { |
1a4d82fc | 2846 | let llfn; |
b039eaaf SL |
2847 | let fields = if v.node.data.is_struct() { |
2848 | ccx.sess().bug("struct variant kind unexpected in get_item_val") | |
2849 | } else { | |
2850 | v.node.data.fields() | |
1a4d82fc | 2851 | }; |
b039eaaf | 2852 | assert!(!fields.is_empty()); |
c1a9b12d | 2853 | let ty = ccx.tcx().node_id_to_type(id); |
1a4d82fc JJ |
2854 | let parent = ccx.tcx().map.get_parent(id); |
2855 | let enm = ccx.tcx().map.expect_item(parent); | |
92a42be0 | 2856 | let sym = exported_name(ccx, id, ty, &enm.attrs); |
1a4d82fc JJ |
2857 | |
2858 | llfn = match enm.node { | |
e9174d1e | 2859 | hir::ItemEnum(_, _) => { |
1a4d82fc JJ |
2860 | register_fn(ccx, (*v).span, sym, id, ty) |
2861 | } | |
92a42be0 | 2862 | _ => ccx.sess().bug("NodeVariant, shouldn't happen"), |
1a4d82fc | 2863 | }; |
9346a6ac | 2864 | attributes::inline(llfn, attributes::InlineAttr::Hint); |
1a4d82fc JJ |
2865 | llfn |
2866 | } | |
2867 | ||
e9174d1e | 2868 | hir_map::NodeStructCtor(struct_def) => { |
1a4d82fc | 2869 | // Only register the constructor if this is a tuple-like struct. |
b039eaaf | 2870 | let ctor_id = if struct_def.is_struct() { |
92a42be0 | 2871 | ccx.sess().bug("attempt to register a constructor of a non-tuple-like struct") |
b039eaaf SL |
2872 | } else { |
2873 | struct_def.id() | |
1a4d82fc JJ |
2874 | }; |
2875 | let parent = ccx.tcx().map.get_parent(id); | |
2876 | let struct_item = ccx.tcx().map.expect_item(parent); | |
c1a9b12d | 2877 | let ty = ccx.tcx().node_id_to_type(ctor_id); |
92a42be0 SL |
2878 | let sym = exported_name(ccx, id, ty, &struct_item.attrs); |
2879 | let llfn = register_fn(ccx, struct_item.span, sym, ctor_id, ty); | |
9346a6ac | 2880 | attributes::inline(llfn, attributes::InlineAttr::Hint); |
1a4d82fc JJ |
2881 | llfn |
2882 | } | |
2883 | ||
2884 | ref variant => { | |
92a42be0 | 2885 | ccx.sess().bug(&format!("get_item_val(): unexpected variant: {:?}", variant)) |
1a4d82fc JJ |
2886 | } |
2887 | }; | |
2888 | ||
2889 | // All LLVM globals and functions are initially created as external-linkage | |
2890 | // declarations. If `trans_item`/`trans_fn` later turns the declaration | |
2891 | // into a definition, it adjusts the linkage then (using `update_linkage`). | |
2892 | // | |
2893 | // The exception is foreign items, which have their linkage set inside the | |
2894 | // call to `foreign::register_*` above. We don't touch the linkage after | |
2895 | // that (`foreign::trans_foreign_mod` doesn't adjust the linkage like the | |
2896 | // other item translation functions do). | |
2897 | ||
2898 | ccx.item_vals().borrow_mut().insert(id, val); | |
2899 | val | |
2900 | } | |
2901 | ||
92a42be0 SL |
2902 | fn register_method(ccx: &CrateContext, |
2903 | id: ast::NodeId, | |
2904 | attrs: &[ast::Attribute], | |
2905 | span: Span) | |
2906 | -> ValueRef { | |
c1a9b12d | 2907 | let mty = ccx.tcx().node_id_to_type(id); |
1a4d82fc | 2908 | |
c34b1796 | 2909 | let sym = exported_name(ccx, id, mty, &attrs); |
1a4d82fc | 2910 | |
62682a34 | 2911 | if let ty::TyBareFn(_, ref f) = mty.sty { |
7453a54e | 2912 | let llfn = if f.abi == Abi::Rust || f.abi == Abi::RustCall { |
c34b1796 AL |
2913 | register_fn(ccx, span, sym, id, mty) |
2914 | } else { | |
2915 | foreign::register_rust_fn_with_foreign_abi(ccx, span, sym, id) | |
2916 | }; | |
9346a6ac | 2917 | attributes::from_fn_attrs(ccx, &attrs, llfn); |
c34b1796 AL |
2918 | return llfn; |
2919 | } else { | |
2920 | ccx.sess().span_bug(span, "expected bare rust function"); | |
2921 | } | |
1a4d82fc JJ |
2922 | } |
2923 | ||
9cc50fc6 SL |
2924 | pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>, |
2925 | krate: &hir::Crate, | |
2926 | reachable: &NodeSet, | |
2927 | mir_map: &MirMap<'tcx>) | |
2928 | -> Vec<u8> { | |
1a4d82fc JJ |
2929 | use flate; |
2930 | ||
92a42be0 SL |
2931 | let any_library = cx.sess() |
2932 | .crate_types | |
2933 | .borrow() | |
2934 | .iter() | |
2935 | .any(|ty| *ty != config::CrateTypeExecutable); | |
1a4d82fc | 2936 | if !any_library { |
92a42be0 | 2937 | return Vec::new(); |
1a4d82fc JJ |
2938 | } |
2939 | ||
92a42be0 | 2940 | let cstore = &cx.tcx().sess.cstore; |
9cc50fc6 SL |
2941 | let metadata = cstore.encode_metadata(cx.tcx(), |
2942 | cx.export_map(), | |
2943 | cx.item_symbols(), | |
2944 | cx.link_meta(), | |
2945 | reachable, | |
2946 | mir_map, | |
2947 | krate); | |
92a42be0 SL |
2948 | let mut compressed = cstore.metadata_encoding_version().to_vec(); |
2949 | compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); | |
1a4d82fc | 2950 | |
85aaf69f | 2951 | let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed[..]); |
1a4d82fc JJ |
2952 | let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); |
2953 | let name = format!("rust_metadata_{}_{}", | |
2954 | cx.link_meta().crate_name, | |
2955 | cx.link_meta().crate_hash); | |
85aaf69f | 2956 | let buf = CString::new(name).unwrap(); |
1a4d82fc | 2957 | let llglobal = unsafe { |
92a42be0 | 2958 | llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf.as_ptr()) |
1a4d82fc JJ |
2959 | }; |
2960 | unsafe { | |
2961 | llvm::LLVMSetInitializer(llglobal, llconst); | |
92a42be0 SL |
2962 | let name = |
2963 | cx.tcx().sess.cstore.metadata_section_name(&cx.sess().target.target); | |
85aaf69f | 2964 | let name = CString::new(name).unwrap(); |
1a4d82fc JJ |
2965 | llvm::LLVMSetSection(llglobal, name.as_ptr()) |
2966 | } | |
2967 | return metadata; | |
2968 | } | |
2969 | ||
2970 | /// Find any symbols that are defined in one compilation unit, but not declared | |
2971 | /// in any other compilation unit. Give these symbols internal linkage. | |
e9174d1e | 2972 | fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { |
1a4d82fc JJ |
2973 | unsafe { |
2974 | let mut declared = HashSet::new(); | |
2975 | ||
1a4d82fc JJ |
2976 | // Collect all external declarations in all compilation units. |
2977 | for ccx in cx.iter() { | |
2978 | for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { | |
2979 | let linkage = llvm::LLVMGetLinkage(val); | |
2980 | // We only care about external declarations (not definitions) | |
2981 | // and available_externally definitions. | |
2982 | if !(linkage == llvm::ExternalLinkage as c_uint && | |
2983 | llvm::LLVMIsDeclaration(val) != 0) && | |
2984 | !(linkage == llvm::AvailableExternallyLinkage as c_uint) { | |
92a42be0 | 2985 | continue; |
1a4d82fc JJ |
2986 | } |
2987 | ||
85aaf69f | 2988 | let name = CStr::from_ptr(llvm::LLVMGetValueName(val)) |
92a42be0 SL |
2989 | .to_bytes() |
2990 | .to_vec(); | |
1a4d82fc JJ |
2991 | declared.insert(name); |
2992 | } | |
2993 | } | |
2994 | ||
2995 | // Examine each external definition. If the definition is not used in | |
2996 | // any other compilation unit, and is not reachable from other crates, | |
2997 | // then give it internal linkage. | |
2998 | for ccx in cx.iter() { | |
2999 | for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { | |
3000 | // We only care about external definitions. | |
3001 | if !(llvm::LLVMGetLinkage(val) == llvm::ExternalLinkage as c_uint && | |
3002 | llvm::LLVMIsDeclaration(val) == 0) { | |
92a42be0 | 3003 | continue; |
1a4d82fc JJ |
3004 | } |
3005 | ||
85aaf69f | 3006 | let name = CStr::from_ptr(llvm::LLVMGetValueName(val)) |
92a42be0 SL |
3007 | .to_bytes() |
3008 | .to_vec(); | |
1a4d82fc | 3009 | if !declared.contains(&name) && |
85aaf69f | 3010 | !reachable.contains(str::from_utf8(&name).unwrap()) { |
1a4d82fc | 3011 | llvm::SetLinkage(val, llvm::InternalLinkage); |
62682a34 | 3012 | llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass); |
1a4d82fc JJ |
3013 | } |
3014 | } | |
3015 | } | |
3016 | } | |
e9174d1e SL |
3017 | } |
3018 | ||
3019 | // Create a `__imp_<symbol> = &symbol` global for every public static `symbol`. | |
3020 | // This is required to satisfy `dllimport` references to static data in .rlibs | |
3021 | // when using MSVC linker. We do this only for data, as linker can fix up | |
3022 | // code references on its own. | |
3023 | // See #26591, #27438 | |
3024 | fn create_imps(cx: &SharedCrateContext) { | |
3025 | // The x86 ABI seems to require that leading underscores are added to symbol | |
3026 | // names, so we need an extra underscore on 32-bit. There's also a leading | |
3027 | // '\x01' here which disables LLVM's symbol mangling (e.g. no extra | |
3028 | // underscores added in front). | |
3029 | let prefix = if cx.sess().target.target.target_pointer_width == "32" { | |
3030 | "\x01__imp__" | |
3031 | } else { | |
3032 | "\x01__imp_" | |
3033 | }; | |
3034 | unsafe { | |
3035 | for ccx in cx.iter() { | |
3036 | let exported: Vec<_> = iter_globals(ccx.llmod()) | |
92a42be0 SL |
3037 | .filter(|&val| { |
3038 | llvm::LLVMGetLinkage(val) == | |
3039 | llvm::ExternalLinkage as c_uint && | |
3040 | llvm::LLVMIsDeclaration(val) == 0 | |
3041 | }) | |
3042 | .collect(); | |
e9174d1e SL |
3043 | |
3044 | let i8p_ty = Type::i8p(&ccx); | |
3045 | for val in exported { | |
3046 | let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); | |
3047 | let mut imp_name = prefix.as_bytes().to_vec(); | |
3048 | imp_name.extend(name.to_bytes()); | |
3049 | let imp_name = CString::new(imp_name).unwrap(); | |
92a42be0 SL |
3050 | let imp = llvm::LLVMAddGlobal(ccx.llmod(), |
3051 | i8p_ty.to_ref(), | |
e9174d1e SL |
3052 | imp_name.as_ptr() as *const _); |
3053 | let init = llvm::LLVMConstBitCast(val, i8p_ty.to_ref()); | |
3054 | llvm::LLVMSetInitializer(imp, init); | |
3055 | llvm::SetLinkage(imp, llvm::ExternalLinkage); | |
3056 | } | |
3057 | } | |
3058 | } | |
3059 | } | |
1a4d82fc | 3060 | |
e9174d1e SL |
3061 | struct ValueIter { |
3062 | cur: ValueRef, | |
3063 | step: unsafe extern "C" fn(ValueRef) -> ValueRef, | |
3064 | } | |
3065 | ||
3066 | impl Iterator for ValueIter { | |
3067 | type Item = ValueRef; | |
1a4d82fc | 3068 | |
e9174d1e SL |
3069 | fn next(&mut self) -> Option<ValueRef> { |
3070 | let old = self.cur; | |
3071 | if !old.is_null() { | |
b039eaaf | 3072 | self.cur = unsafe { (self.step)(old) }; |
e9174d1e SL |
3073 | Some(old) |
3074 | } else { | |
3075 | None | |
3076 | } | |
1a4d82fc | 3077 | } |
e9174d1e | 3078 | } |
1a4d82fc | 3079 | |
e9174d1e SL |
3080 | fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter { |
3081 | unsafe { | |
3082 | ValueIter { | |
3083 | cur: llvm::LLVMGetFirstGlobal(llmod), | |
3084 | step: llvm::LLVMGetNextGlobal, | |
3085 | } | |
3086 | } | |
3087 | } | |
1a4d82fc | 3088 | |
e9174d1e SL |
3089 | fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { |
3090 | unsafe { | |
3091 | ValueIter { | |
3092 | cur: llvm::LLVMGetFirstFunction(llmod), | |
3093 | step: llvm::LLVMGetNextFunction, | |
1a4d82fc JJ |
3094 | } |
3095 | } | |
3096 | } | |
3097 | ||
e9174d1e SL |
3098 | /// The context provided lists a set of reachable ids as calculated by |
3099 | /// middle::reachable, but this contains far more ids and symbols than we're | |
3100 | /// actually exposing from the object file. This function will filter the set in | |
3101 | /// the context to the set of ids which correspond to symbols that are exposed | |
3102 | /// from the object file being generated. | |
3103 | /// | |
3104 | /// This list is later used by linkers to determine the set of symbols needed to | |
3105 | /// be exposed from a dynamic library and it's also encoded into the metadata. | |
3106 | pub fn filter_reachable_ids(ccx: &SharedCrateContext) -> NodeSet { | |
3107 | ccx.reachable().iter().map(|x| *x).filter(|id| { | |
3108 | // First, only worry about nodes which have a symbol name | |
3109 | ccx.item_symbols().borrow().contains_key(id) | |
3110 | }).filter(|&id| { | |
3111 | // Next, we want to ignore some FFI functions that are not exposed from | |
3112 | // this crate. Reachable FFI functions can be lumped into two | |
3113 | // categories: | |
3114 | // | |
3115 | // 1. Those that are included statically via a static library | |
3116 | // 2. Those included otherwise (e.g. dynamically or via a framework) | |
3117 | // | |
3118 | // Although our LLVM module is not literally emitting code for the | |
3119 | // statically included symbols, it's an export of our library which | |
3120 | // needs to be passed on to the linker and encoded in the metadata. | |
3121 | // | |
3122 | // As a result, if this id is an FFI item (foreign item) then we only | |
3123 | // let it through if it's included statically. | |
3124 | match ccx.tcx().map.get(id) { | |
3125 | hir_map::NodeForeignItem(..) => { | |
3126 | ccx.sess().cstore.is_statically_included_foreign_item(id) | |
3127 | } | |
3128 | _ => true, | |
3129 | } | |
3130 | }).collect() | |
3131 | } | |
3132 | ||
92a42be0 SL |
3133 | pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>, |
3134 | mir_map: &MirMap<'tcx>, | |
3135 | analysis: ty::CrateAnalysis) | |
3136 | -> CrateTranslation { | |
9cc50fc6 SL |
3137 | let _task = tcx.dep_graph.in_task(DepNode::TransCrate); |
3138 | ||
3139 | // Be careful with this krate: obviously it gives access to the | |
3140 | // entire contents of the krate. So if you push any subtasks of | |
3141 | // `TransCrate`, you need to be careful to register "reads" of the | |
3142 | // particular items that will be processed. | |
1a4d82fc JJ |
3143 | let krate = tcx.map.krate(); |
3144 | ||
9cc50fc6 SL |
3145 | let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis; |
3146 | ||
c34b1796 AL |
3147 | let check_overflow = if let Some(v) = tcx.sess.opts.debugging_opts.force_overflow_checks { |
3148 | v | |
3149 | } else { | |
3150 | tcx.sess.opts.debug_assertions | |
3151 | }; | |
3152 | ||
3153 | let check_dropflag = if let Some(v) = tcx.sess.opts.debugging_opts.force_dropflag_checks { | |
3154 | v | |
3155 | } else { | |
3156 | tcx.sess.opts.debug_assertions | |
3157 | }; | |
3158 | ||
1a4d82fc JJ |
3159 | // Before we touch LLVM, make sure that multithreading is enabled. |
3160 | unsafe { | |
62682a34 SL |
3161 | use std::sync::Once; |
3162 | static INIT: Once = Once::new(); | |
1a4d82fc JJ |
3163 | static mut POISONED: bool = false; |
3164 | INIT.call_once(|| { | |
3165 | if llvm::LLVMStartMultithreaded() != 1 { | |
3166 | // use an extra bool to make sure that all future usage of LLVM | |
3167 | // cannot proceed despite the Once not running more than once. | |
3168 | POISONED = true; | |
3169 | } | |
c1a9b12d SL |
3170 | |
3171 | ::back::write::configure_llvm(&tcx.sess); | |
1a4d82fc JJ |
3172 | }); |
3173 | ||
3174 | if POISONED { | |
3175 | tcx.sess.bug("couldn't enable multi-threaded LLVM"); | |
3176 | } | |
3177 | } | |
3178 | ||
3179 | let link_meta = link::build_link_meta(&tcx.sess, krate, name); | |
3180 | ||
3181 | let codegen_units = tcx.sess.opts.cg.codegen_units; | |
c34b1796 | 3182 | let shared_ccx = SharedCrateContext::new(&link_meta.crate_name, |
1a4d82fc JJ |
3183 | codegen_units, |
3184 | tcx, | |
92a42be0 | 3185 | &mir_map, |
1a4d82fc JJ |
3186 | export_map, |
3187 | Sha256::new(), | |
3188 | link_meta.clone(), | |
c34b1796 AL |
3189 | reachable, |
3190 | check_overflow, | |
3191 | check_dropflag); | |
1a4d82fc JJ |
3192 | |
3193 | { | |
3194 | let ccx = shared_ccx.get_ccx(0); | |
3195 | ||
3196 | // First, verify intrinsics. | |
3197 | intrinsic::check_intrinsics(&ccx); | |
3198 | ||
7453a54e SL |
3199 | collect_translation_items(&ccx); |
3200 | ||
92a42be0 SL |
3201 | // Next, translate all items. See `TransModVisitor` for |
3202 | // details on why we walk in this particular way. | |
1a4d82fc JJ |
3203 | { |
3204 | let _icx = push_ctxt("text"); | |
92a42be0 SL |
3205 | intravisit::walk_mod(&mut TransItemsWithinModVisitor { ccx: &ccx }, &krate.module); |
3206 | krate.visit_all_items(&mut TransModVisitor { ccx: &ccx }); | |
1a4d82fc | 3207 | } |
7453a54e SL |
3208 | |
3209 | collector::print_collection_results(&ccx); | |
1a4d82fc JJ |
3210 | } |
3211 | ||
3212 | for ccx in shared_ccx.iter() { | |
1a4d82fc JJ |
3213 | if ccx.sess().opts.debuginfo != NoDebugInfo { |
3214 | debuginfo::finalize(&ccx); | |
3215 | } | |
c1a9b12d SL |
3216 | for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() { |
3217 | unsafe { | |
3218 | let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g)); | |
3219 | llvm::LLVMReplaceAllUsesWith(old_g, bitcast); | |
3220 | llvm::LLVMDeleteGlobal(old_g); | |
3221 | } | |
3222 | } | |
1a4d82fc JJ |
3223 | } |
3224 | ||
e9174d1e SL |
3225 | let reachable_symbol_ids = filter_reachable_ids(&shared_ccx); |
3226 | ||
1a4d82fc | 3227 | // Translate the metadata. |
9cc50fc6 SL |
3228 | let metadata = time(tcx.sess.time_passes(), "write metadata", || { |
3229 | write_metadata(&shared_ccx, krate, &reachable_symbol_ids, mir_map) | |
3230 | }); | |
1a4d82fc JJ |
3231 | |
3232 | if shared_ccx.sess().trans_stats() { | |
3233 | let stats = shared_ccx.stats(); | |
3234 | println!("--- trans stats ---"); | |
1a4d82fc JJ |
3235 | println!("n_glues_created: {}", stats.n_glues_created.get()); |
3236 | println!("n_null_glues: {}", stats.n_null_glues.get()); | |
3237 | println!("n_real_glues: {}", stats.n_real_glues.get()); | |
3238 | ||
3239 | println!("n_fns: {}", stats.n_fns.get()); | |
3240 | println!("n_monos: {}", stats.n_monos.get()); | |
3241 | println!("n_inlines: {}", stats.n_inlines.get()); | |
3242 | println!("n_closures: {}", stats.n_closures.get()); | |
3243 | println!("fn stats:"); | |
3244 | stats.fn_stats.borrow_mut().sort_by(|&(_, insns_a), &(_, insns_b)| { | |
3245 | insns_b.cmp(&insns_a) | |
3246 | }); | |
62682a34 | 3247 | for tuple in stats.fn_stats.borrow().iter() { |
1a4d82fc JJ |
3248 | match *tuple { |
3249 | (ref name, insns) => { | |
3250 | println!("{} insns, {}", insns, *name); | |
3251 | } | |
3252 | } | |
3253 | } | |
3254 | } | |
3255 | if shared_ccx.sess().count_llvm_insns() { | |
62682a34 | 3256 | for (k, v) in shared_ccx.stats().llvm_insns.borrow().iter() { |
1a4d82fc JJ |
3257 | println!("{:7} {}", *v, *k); |
3258 | } | |
3259 | } | |
3260 | ||
3261 | let modules = shared_ccx.iter() | |
3262 | .map(|ccx| ModuleTranslation { llcx: ccx.llcx(), llmod: ccx.llmod() }) | |
3263 | .collect(); | |
3264 | ||
e9174d1e SL |
3265 | let sess = shared_ccx.sess(); |
3266 | let mut reachable_symbols = reachable_symbol_ids.iter().map(|id| { | |
3267 | shared_ccx.item_symbols().borrow()[id].to_string() | |
3268 | }).collect::<Vec<_>>(); | |
3269 | if sess.entry_fn.borrow().is_some() { | |
3270 | reachable_symbols.push("main".to_string()); | |
3271 | } | |
1a4d82fc JJ |
3272 | |
3273 | // For the purposes of LTO, we add to the reachable set all of the upstream | |
3274 | // reachable extern fns. These functions are all part of the public ABI of | |
3275 | // the final product, so LTO needs to preserve them. | |
e9174d1e | 3276 | if sess.lto() { |
92a42be0 SL |
3277 | for cnum in sess.cstore.crates() { |
3278 | let syms = sess.cstore.reachable_ids(cnum); | |
e9174d1e | 3279 | reachable_symbols.extend(syms.into_iter().filter(|did| { |
7453a54e | 3280 | sess.cstore.is_extern_item(shared_ccx.tcx(), *did) |
e9174d1e | 3281 | }).map(|did| { |
92a42be0 | 3282 | sess.cstore.item_symbol(did) |
e9174d1e | 3283 | })); |
92a42be0 | 3284 | } |
e9174d1e | 3285 | } |
1a4d82fc JJ |
3286 | |
3287 | if codegen_units > 1 { | |
e9174d1e SL |
3288 | internalize_symbols(&shared_ccx, |
3289 | &reachable_symbols.iter().map(|x| &x[..]).collect()); | |
3290 | } | |
3291 | ||
3292 | if sess.target.target.options.is_like_msvc && | |
3293 | sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { | |
3294 | create_imps(&shared_ccx); | |
1a4d82fc JJ |
3295 | } |
3296 | ||
3297 | let metadata_module = ModuleTranslation { | |
3298 | llcx: shared_ccx.metadata_llcx(), | |
3299 | llmod: shared_ccx.metadata_llmod(), | |
3300 | }; | |
c34b1796 | 3301 | let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); |
1a4d82fc | 3302 | |
9cc50fc6 SL |
3303 | assert_dep_graph::assert_dep_graph(tcx); |
3304 | ||
62682a34 | 3305 | CrateTranslation { |
1a4d82fc JJ |
3306 | modules: modules, |
3307 | metadata_module: metadata_module, | |
3308 | link: link_meta, | |
3309 | metadata: metadata, | |
e9174d1e | 3310 | reachable: reachable_symbols, |
1a4d82fc | 3311 | no_builtins: no_builtins, |
62682a34 | 3312 | } |
1a4d82fc | 3313 | } |
92a42be0 SL |
3314 | |
3315 | /// We visit all the items in the krate and translate them. We do | |
3316 | /// this in two walks. The first walk just finds module items. It then | |
3317 | /// walks the full contents of those module items and translates all | |
3318 | /// the items within. Note that this entire process is O(n). The | |
3319 | /// reason for this two phased walk is that each module is | |
3320 | /// (potentially) placed into a distinct codegen-unit. This walk also | |
3321 | /// ensures that the immediate contents of each module is processed | |
3322 | /// entirely before we proceed to find more modules, helping to ensure | |
3323 | /// an equitable distribution amongst codegen-units. | |
3324 | pub struct TransModVisitor<'a, 'tcx: 'a> { | |
3325 | pub ccx: &'a CrateContext<'a, 'tcx>, | |
3326 | } | |
3327 | ||
3328 | impl<'a, 'tcx, 'v> Visitor<'v> for TransModVisitor<'a, 'tcx> { | |
3329 | fn visit_item(&mut self, i: &hir::Item) { | |
3330 | match i.node { | |
3331 | hir::ItemMod(_) => { | |
3332 | let item_ccx = self.ccx.rotate(); | |
3333 | intravisit::walk_item(&mut TransItemsWithinModVisitor { ccx: &item_ccx }, i); | |
3334 | } | |
3335 | _ => { } | |
3336 | } | |
3337 | } | |
3338 | } | |
3339 | ||
3340 | /// Translates all the items within a given module. Expects owner to | |
3341 | /// invoke `walk_item` on a module item. Ignores nested modules. | |
3342 | pub struct TransItemsWithinModVisitor<'a, 'tcx: 'a> { | |
3343 | pub ccx: &'a CrateContext<'a, 'tcx>, | |
3344 | } | |
3345 | ||
3346 | impl<'a, 'tcx, 'v> Visitor<'v> for TransItemsWithinModVisitor<'a, 'tcx> { | |
3347 | fn visit_nested_item(&mut self, item_id: hir::ItemId) { | |
3348 | self.visit_item(self.ccx.tcx().map.expect_item(item_id.id)); | |
3349 | } | |
3350 | ||
3351 | fn visit_item(&mut self, i: &hir::Item) { | |
3352 | match i.node { | |
3353 | hir::ItemMod(..) => { | |
3354 | // skip modules, they will be uncovered by the TransModVisitor | |
3355 | } | |
3356 | _ => { | |
9cc50fc6 SL |
3357 | let def_id = self.ccx.tcx().map.local_def_id(i.id); |
3358 | let tcx = self.ccx.tcx(); | |
3359 | ||
3360 | // Create a subtask for trans'ing a particular item. We are | |
3361 | // giving `trans_item` access to this item, so also record a read. | |
3362 | tcx.dep_graph.with_task(DepNode::TransCrateItem(def_id), || { | |
3363 | tcx.dep_graph.read(DepNode::Hir(def_id)); | |
7453a54e SL |
3364 | |
3365 | // We are going to be accessing various tables | |
3366 | // generated by TypeckItemBody; we also assume | |
3367 | // that the body passes type check. These tables | |
3368 | // are not individually tracked, so just register | |
3369 | // a read here. | |
3370 | tcx.dep_graph.read(DepNode::TypeckItemBody(def_id)); | |
3371 | ||
9cc50fc6 SL |
3372 | trans_item(self.ccx, i); |
3373 | }); | |
3374 | ||
92a42be0 SL |
3375 | intravisit::walk_item(self, i); |
3376 | } | |
3377 | } | |
3378 | } | |
3379 | } | |
7453a54e SL |
3380 | |
3381 | fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) { | |
3382 | let time_passes = ccx.sess().time_passes(); | |
3383 | ||
3384 | let collection_mode = match ccx.sess().opts.debugging_opts.print_trans_items { | |
3385 | Some(ref s) => { | |
3386 | let mode_string = s.to_lowercase(); | |
3387 | let mode_string = mode_string.trim(); | |
3388 | if mode_string == "eager" { | |
3389 | TransItemCollectionMode::Eager | |
3390 | } else { | |
3391 | if mode_string != "lazy" { | |
3392 | let message = format!("Unknown codegen-item collection mode '{}'. \ | |
3393 | Falling back to 'lazy' mode.", | |
3394 | mode_string); | |
3395 | ccx.sess().warn(&message); | |
3396 | } | |
3397 | ||
3398 | TransItemCollectionMode::Lazy | |
3399 | } | |
3400 | } | |
3401 | None => TransItemCollectionMode::Lazy | |
3402 | }; | |
3403 | ||
3404 | let items = time(time_passes, "translation item collection", || { | |
3405 | collector::collect_crate_translation_items(&ccx, collection_mode) | |
3406 | }); | |
3407 | ||
3408 | if ccx.sess().opts.debugging_opts.print_trans_items.is_some() { | |
3409 | let mut item_keys: Vec<_> = items.iter() | |
3410 | .map(|i| i.to_string(ccx)) | |
3411 | .collect(); | |
3412 | item_keys.sort(); | |
3413 | ||
3414 | for item in item_keys { | |
3415 | println!("TRANS_ITEM {}", item); | |
3416 | } | |
3417 | ||
3418 | let mut ccx_map = ccx.translation_items().borrow_mut(); | |
3419 | ||
3420 | for cgi in items { | |
3421 | ccx_map.insert(cgi, TransItemState::PredictedButNotGenerated); | |
3422 | } | |
3423 | } | |
3424 | } |