1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
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.
11 // trans.rs: Translate the completed AST to the LLVM IR.
13 // Some functions here, such as trans_block and trans_expr, return a value --
14 // the result of the translation to LLVM -- while others, such as trans_fn,
15 // trans_impl, and trans_item, are called only for the side effect of adding a
16 // particular definition to the LLVM IR output we're producing.
18 // Hopefully useful general knowledge about trans:
20 // * There's no way to find out the Ty type of a ValueRef. Doing so
21 // would be "trying to get the eggs out of an omelette" (credit:
22 // pcwalton). You can, instead, find out its TypeRef by calling val_ty,
23 // but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int,
24 // int) and rec(x=int, y=int, z=int) will have the same TypeRef.
26 #![allow(non_camel_case_types)]
28 pub use self::ValueOrigin
::*;
29 pub use self::scalar_type
::*;
31 use super::CrateTranslation
;
32 use super::ModuleTranslation
;
34 use back
::link
::{mangle_exported_name}
;
35 use back
::{link, abi}
;
37 use llvm
::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}
;
39 use metadata
::{csearch, encoder, loader}
;
40 use middle
::astencode
;
42 use middle
::lang_items
::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}
;
44 use middle
::weak_lang_items
;
45 use middle
::subst
::{Subst, Substs}
;
46 use middle
::ty
::{self, Ty, UnboxedClosureTyper}
;
47 use session
::config
::{self, NoDebugInfo, FullDebugInfo}
;
52 use trans
::builder
::{Builder, noname}
;
54 use trans
::cleanup
::CleanupMethods
;
57 use trans
::common
::{Block, C_bool, C_bytes_in_context, C_i32, C_integral}
;
58 use trans
::common
::{C_null, C_struct_in_context, C_u64, C_u8, C_undef}
;
59 use trans
::common
::{CrateContext, ExternMap, FunctionContext}
;
60 use trans
::common
::{NodeInfo, Result}
;
61 use trans
::common
::{node_id_type, return_type_is_void}
;
62 use trans
::common
::{tydesc_info, type_is_immediate}
;
63 use trans
::common
::{type_is_zero_size, val_ty}
;
66 use trans
::context
::SharedCrateContext
;
67 use trans
::controlflow
;
76 use trans
::machine
::{llsize_of, llsize_of_real}
;
78 use trans
::monomorphize
;
80 use trans
::type_
::Type
;
82 use trans
::type_of
::*;
83 use trans
::value
::Value
;
84 use util
::common
::indenter
;
85 use util
::ppaux
::{Repr, ty_to_string}
;
86 use util
::sha2
::Sha256
;
87 use util
::nodemap
::NodeMap
;
89 use arena
::TypedArena
;
90 use libc
::{c_uint, uint64_t}
;
91 use std
::ffi
::{self, CString}
;
92 use std
::cell
::{Cell, RefCell}
;
93 use std
::collections
::HashSet
;
97 use std
::{i8, i16, i32, i64}
;
98 use syntax
::abi
::{Rust, RustCall, RustIntrinsic, Abi}
;
99 use syntax
::ast_util
::local_def
;
100 use syntax
::attr
::AttrMetaMethods
;
102 use syntax
::codemap
::Span
;
103 use syntax
::parse
::token
::InternedString
;
104 use syntax
::visit
::Visitor
;
106 use syntax
::{ast, ast_util, ast_map}
;
109 static TASK_LOCAL_INSN_KEY
: RefCell
<Option
<Vec
<&'
static str>>> = {
114 pub fn with_insn_ctxt
<F
>(blk
: F
) where
115 F
: FnOnce(&[&'
static str]),
117 TASK_LOCAL_INSN_KEY
.with(move |slot
| {
118 slot
.borrow().as_ref().map(move |s
| blk(s
.as_slice()));
122 pub fn init_insn_ctxt() {
123 TASK_LOCAL_INSN_KEY
.with(|slot
| {
124 *slot
.borrow_mut() = Some(Vec
::new());
128 pub struct _InsnCtxt
{
129 _cannot_construct_outside_of_this_module
: ()
133 impl Drop
for _InsnCtxt
{
135 TASK_LOCAL_INSN_KEY
.with(|slot
| {
136 match slot
.borrow_mut().as_mut() {
137 Some(ctx
) => { ctx.pop(); }
144 pub fn push_ctxt(s
: &'
static str) -> _InsnCtxt
{
145 debug
!("new InsnCtxt: {}", s
);
146 TASK_LOCAL_INSN_KEY
.with(|slot
| {
147 match slot
.borrow_mut().as_mut() {
148 Some(ctx
) => ctx
.push(s
),
152 _InsnCtxt { _cannot_construct_outside_of_this_module: () }
155 pub struct StatRecorder
<'a
, 'tcx
: 'a
> {
156 ccx
: &'a CrateContext
<'a
, 'tcx
>,
157 name
: Option
<String
>,
161 impl<'a
, 'tcx
> StatRecorder
<'a
, 'tcx
> {
162 pub fn new(ccx
: &'a CrateContext
<'a
, 'tcx
>, name
: String
)
163 -> StatRecorder
<'a
, 'tcx
> {
164 let istart
= ccx
.stats().n_llvm_insns
.get();
174 impl<'a
, 'tcx
> Drop
for StatRecorder
<'a
, 'tcx
> {
176 if self.ccx
.sess().trans_stats() {
177 let iend
= self.ccx
.stats().n_llvm_insns
.get();
178 self.ccx
.stats().fn_stats
.borrow_mut().push((self.name
.take().unwrap(),
179 iend
- self.istart
));
180 self.ccx
.stats().n_fns
.set(self.ccx
.stats().n_fns
.get() + 1);
181 // Reset LLVM insn count to avoid compound costs.
182 self.ccx
.stats().n_llvm_insns
.set(self.istart
);
187 // only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
188 pub fn decl_fn(ccx
: &CrateContext
, name
: &str, cc
: llvm
::CallConv
,
189 ty
: Type
, output
: ty
::FnOutput
) -> ValueRef
{
191 let buf
= CString
::from_slice(name
.as_bytes());
192 let llfn
: ValueRef
= unsafe {
193 llvm
::LLVMGetOrInsertFunction(ccx
.llmod(), buf
.as_ptr(), ty
.to_ref())
196 // diverging functions may unwind, but can never return normally
197 if output
== ty
::FnDiverging
{
198 llvm
::SetFunctionAttribute(llfn
, llvm
::NoReturnAttribute
);
201 if ccx
.tcx().sess
.opts
.cg
.no_redzone
202 .unwrap_or(ccx
.tcx().sess
.target
.target
.options
.disable_redzone
) {
203 llvm
::SetFunctionAttribute(llfn
, llvm
::NoRedZoneAttribute
)
206 llvm
::SetFunctionCallConv(llfn
, cc
);
207 // Function addresses in Rust are never significant, allowing functions to be merged.
208 llvm
::SetUnnamedAddr(llfn
, true);
210 if ccx
.is_split_stack_supported() && !ccx
.sess().opts
.cg
.no_stack_check
{
211 set_split_stack(llfn
);
217 // only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
218 pub fn decl_cdecl_fn(ccx
: &CrateContext
,
221 output
: Ty
) -> ValueRef
{
222 decl_fn(ccx
, name
, llvm
::CCallConv
, ty
, ty
::FnConverging(output
))
225 // only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
226 pub fn get_extern_fn(ccx
: &CrateContext
,
227 externs
: &mut ExternMap
,
233 match externs
.get(name
) {
234 Some(n
) => return *n
,
237 let f
= decl_fn(ccx
, name
, cc
, ty
, ty
::FnConverging(output
));
238 externs
.insert(name
.to_string(), f
);
242 fn get_extern_rust_fn
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>, fn_ty
: Ty
<'tcx
>,
243 name
: &str, did
: ast
::DefId
) -> ValueRef
{
244 match ccx
.externs().borrow().get(name
) {
245 Some(n
) => return *n
,
249 let f
= decl_rust_fn(ccx
, fn_ty
, name
);
251 csearch
::get_item_attrs(&ccx
.sess().cstore
, did
, |attrs
| {
252 set_llvm_fn_attrs(ccx
, &attrs
[], f
)
255 ccx
.externs().borrow_mut().insert(name
.to_string(), f
);
259 pub fn self_type_for_unboxed_closure
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
260 closure_id
: ast
::DefId
,
264 let unboxed_closure_kind
= ccx
.tcx().unboxed_closure_kind(closure_id
);
265 match unboxed_closure_kind
{
266 ty
::FnUnboxedClosureKind
=> {
267 ty
::mk_imm_rptr(ccx
.tcx(), ccx
.tcx().mk_region(ty
::ReStatic
), fn_ty
)
269 ty
::FnMutUnboxedClosureKind
=> {
270 ty
::mk_mut_rptr(ccx
.tcx(), ccx
.tcx().mk_region(ty
::ReStatic
), fn_ty
)
272 ty
::FnOnceUnboxedClosureKind
=> fn_ty
276 pub fn kind_for_unboxed_closure(ccx
: &CrateContext
, closure_id
: ast
::DefId
)
277 -> ty
::UnboxedClosureKind
{
278 let unboxed_closures
= ccx
.tcx().unboxed_closures
.borrow();
279 (*unboxed_closures
)[closure_id
].kind
282 pub fn decl_rust_fn
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
283 fn_ty
: Ty
<'tcx
>, name
: &str) -> ValueRef
{
284 debug
!("decl_rust_fn(fn_ty={}, name={:?})",
285 fn_ty
.repr(ccx
.tcx()),
288 let fn_ty
= monomorphize
::normalize_associated_type(ccx
.tcx(), &fn_ty
);
290 debug
!("decl_rust_fn: fn_ty={} (after normalized associated types)",
291 fn_ty
.repr(ccx
.tcx()));
293 let function_type
; // placeholder so that the memory ownership works out ok
295 let (sig
, abi
, env
) = match fn_ty
.sty
{
296 ty
::ty_bare_fn(_
, ref f
) => {
297 (&f
.sig
, f
.abi
, None
)
299 ty
::ty_unboxed_closure(closure_did
, _
, substs
) => {
300 let typer
= common
::NormalizingUnboxedClosureTyper
::new(ccx
.tcx());
301 function_type
= typer
.unboxed_closure_type(closure_did
, substs
);
302 let self_type
= self_type_for_unboxed_closure(ccx
, closure_did
, fn_ty
);
303 let llenvironment_type
= type_of_explicit_arg(ccx
, self_type
);
304 debug
!("decl_rust_fn: function_type={} self_type={}",
305 function_type
.repr(ccx
.tcx()),
306 self_type
.repr(ccx
.tcx()));
307 (&function_type
.sig
, RustCall
, Some(llenvironment_type
))
309 _
=> panic
!("expected closure or fn")
312 let sig
= ty
::erase_late_bound_regions(ccx
.tcx(), sig
);
313 let sig
= ty
::Binder(sig
);
315 debug
!("decl_rust_fn: sig={} (after erasing regions)",
316 sig
.repr(ccx
.tcx()));
318 let llfty
= type_of_rust_fn(ccx
, env
, &sig
, abi
);
320 debug
!("decl_rust_fn: llfty={}",
321 ccx
.tn().type_to_string(llfty
));
323 let llfn
= decl_fn(ccx
, name
, llvm
::CCallConv
, llfty
, sig
.0.output
/* (1) */);
324 let attrs
= get_fn_llvm_attributes(ccx
, fn_ty
);
325 attrs
.apply_llfn(llfn
);
327 // (1) it's ok to directly access sig.0.output because we erased all late-bound-regions above
332 pub fn decl_internal_rust_fn
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
333 fn_ty
: Ty
<'tcx
>, name
: &str) -> ValueRef
{
334 let llfn
= decl_rust_fn(ccx
, fn_ty
, name
);
335 llvm
::SetLinkage(llfn
, llvm
::InternalLinkage
);
339 pub fn get_extern_const
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>, did
: ast
::DefId
,
340 t
: Ty
<'tcx
>) -> ValueRef
{
341 let name
= csearch
::get_symbol(&ccx
.sess().cstore
, did
);
342 let ty
= type_of(ccx
, t
);
343 match ccx
.externs().borrow_mut().get(&name
) {
344 Some(n
) => return *n
,
348 let buf
= CString
::from_slice(name
.as_bytes());
349 let c
= llvm
::LLVMAddGlobal(ccx
.llmod(), ty
.to_ref(), buf
.as_ptr());
350 // Thread-local statics in some other crate need to *always* be linked
351 // against in a thread-local fashion, so we need to be sure to apply the
352 // thread-local attribute locally if it was present remotely. If we
353 // don't do this then linker errors can be generated where the linker
354 // complains that one object files has a thread local version of the
355 // symbol and another one doesn't.
356 ty
::each_attr(ccx
.tcx(), did
, |attr
| {
357 if attr
.check_name("thread_local") {
358 llvm
::set_thread_local(c
, true);
362 ccx
.externs().borrow_mut().insert(name
.to_string(), c
);
367 // Returns a pointer to the body for the box. The box may be an opaque
368 // box. The result will be casted to the type of body_t, if it is statically
370 pub fn at_box_body
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
371 body_t
: Ty
<'tcx
>, boxptr
: ValueRef
) -> ValueRef
{
372 let _icx
= push_ctxt("at_box_body");
374 let ty
= Type
::at_box(ccx
, type_of(ccx
, body_t
));
375 let boxptr
= PointerCast(bcx
, boxptr
, ty
.ptr_to());
376 GEPi(bcx
, boxptr
, &[0u, abi
::BOX_FIELD_BODY
])
379 fn require_alloc_fn
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
380 info_ty
: Ty
<'tcx
>, it
: LangItem
) -> ast
::DefId
{
381 match bcx
.tcx().lang_items
.require(it
) {
384 bcx
.sess().fatal(&format
!("allocation of `{}` {}",
385 bcx
.ty_to_string(info_ty
),
391 // The following malloc_raw_dyn* functions allocate a box to contain
392 // a given type, but with a potentially dynamic size.
394 pub fn malloc_raw_dyn
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
399 -> Result
<'blk
, 'tcx
> {
400 let _icx
= push_ctxt("malloc_raw_exchange");
403 let r
= callee
::trans_lang_call(bcx
,
404 require_alloc_fn(bcx
, info_ty
, ExchangeMallocFnLangItem
),
408 Result
::new(r
.bcx
, PointerCast(r
.bcx
, r
.val
, llty_ptr
))
411 // Type descriptor and type glue stuff
413 pub fn get_tydesc
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
414 t
: Ty
<'tcx
>) -> Rc
<tydesc_info
<'tcx
>> {
415 match ccx
.tydescs().borrow().get(&t
) {
416 Some(inf
) => return inf
.clone(),
420 ccx
.stats().n_static_tydescs
.set(ccx
.stats().n_static_tydescs
.get() + 1u);
421 let inf
= Rc
::new(glue
::declare_tydesc(ccx
, t
));
423 ccx
.tydescs().borrow_mut().insert(t
, inf
.clone());
427 #[allow(dead_code)] // useful
428 pub fn set_optimize_for_size(f
: ValueRef
) {
429 llvm
::SetFunctionAttribute(f
, llvm
::OptimizeForSizeAttribute
)
432 pub fn set_no_inline(f
: ValueRef
) {
433 llvm
::SetFunctionAttribute(f
, llvm
::NoInlineAttribute
)
436 #[allow(dead_code)] // useful
437 pub fn set_no_unwind(f
: ValueRef
) {
438 llvm
::SetFunctionAttribute(f
, llvm
::NoUnwindAttribute
)
441 // Tell LLVM to emit the information necessary to unwind the stack for the
443 pub fn set_uwtable(f
: ValueRef
) {
444 llvm
::SetFunctionAttribute(f
, llvm
::UWTableAttribute
)
447 pub fn set_inline_hint(f
: ValueRef
) {
448 llvm
::SetFunctionAttribute(f
, llvm
::InlineHintAttribute
)
451 pub fn set_llvm_fn_attrs(ccx
: &CrateContext
, attrs
: &[ast
::Attribute
], llfn
: ValueRef
) {
453 // Set the inline hint if there is one
454 match find_inline_attr(attrs
) {
455 InlineHint
=> set_inline_hint(llfn
),
456 InlineAlways
=> set_always_inline(llfn
),
457 InlineNever
=> set_no_inline(llfn
),
458 InlineNone
=> { /* fallthrough */ }
461 for attr
in attrs
.iter() {
463 match attr
.name().get() {
464 "no_stack_check" => unset_split_stack(llfn
),
465 "no_split_stack" => {
466 unset_split_stack(llfn
);
467 ccx
.sess().span_warn(attr
.span
,
468 "no_split_stack is a deprecated synonym for no_stack_check");
471 llvm
::LLVMAddFunctionAttribute(llfn
,
472 llvm
::FunctionIndex
as c_uint
,
473 llvm
::ColdAttribute
as uint64_t
)
478 attr
::mark_used(attr
);
483 pub fn set_always_inline(f
: ValueRef
) {
484 llvm
::SetFunctionAttribute(f
, llvm
::AlwaysInlineAttribute
)
487 pub fn set_split_stack(f
: ValueRef
) {
489 llvm
::LLVMAddFunctionAttrString(f
, llvm
::FunctionIndex
as c_uint
,
490 "split-stack\0".as_ptr() as *const _
);
494 pub fn unset_split_stack(f
: ValueRef
) {
496 llvm
::LLVMRemoveFunctionAttrString(f
, llvm
::FunctionIndex
as c_uint
,
497 "split-stack\0".as_ptr() as *const _
);
501 // Double-check that we never ask LLVM to declare the same symbol twice. It
502 // silently mangles such symbols, breaking our linkage model.
503 pub fn note_unique_llvm_symbol(ccx
: &CrateContext
, sym
: String
) {
504 if ccx
.all_llvm_symbols().borrow().contains(&sym
) {
505 ccx
.sess().bug(&format
!("duplicate LLVM symbol: {}", sym
)[]);
507 ccx
.all_llvm_symbols().borrow_mut().insert(sym
);
511 pub fn get_res_dtor
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
514 parent_id
: ast
::DefId
,
515 substs
: &subst
::Substs
<'tcx
>)
517 let _icx
= push_ctxt("trans_res_dtor");
518 let did
= inline
::maybe_instantiate_inline(ccx
, did
);
520 if !substs
.types
.is_empty() {
521 assert_eq
!(did
.krate
, ast
::LOCAL_CRATE
);
523 // Since we're in trans we don't care for any region parameters
524 let substs
= subst
::Substs
::erased(substs
.types
.clone());
526 let (val
, _
, _
) = monomorphize
::monomorphic_fn(ccx
, did
, &substs
, None
);
529 } else if did
.krate
== ast
::LOCAL_CRATE
{
530 get_item_val(ccx
, did
.node
)
533 let name
= csearch
::get_symbol(&ccx
.sess().cstore
, did
);
534 let class_ty
= ty
::lookup_item_type(tcx
, parent_id
).ty
.subst(tcx
, substs
);
535 let llty
= type_of_dtor(ccx
, class_ty
);
536 let dtor_ty
= ty
::mk_ctor_fn(ccx
.tcx(),
538 &[glue
::get_drop_glue_type(ccx
, t
)],
539 ty
::mk_nil(ccx
.tcx()));
541 &mut *ccx
.externs().borrow_mut(),
549 // Structural comparison: a rather involved form of glue.
550 pub fn maybe_name_value(cx
: &CrateContext
, v
: ValueRef
, s
: &str) {
551 if cx
.sess().opts
.cg
.save_temps
{
552 let buf
= CString
::from_slice(s
.as_bytes());
553 unsafe { llvm::LLVMSetValueName(v, buf.as_ptr()) }
558 // Used only for creating scalar comparison glue.
560 pub enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, }
562 pub fn compare_scalar_types
<'blk
, 'tcx
>(cx
: Block
<'blk
, 'tcx
>,
567 -> Result
<'blk
, 'tcx
> {
568 let f
= |&: a
| Result
::new(cx
, compare_scalar_values(cx
, lhs
, rhs
, a
, op
));
571 ty
::ty_tup(ref tys
) if tys
.is_empty() => f(nil_type
),
572 ty
::ty_bool
| ty
::ty_uint(_
) | ty
::ty_char
=> f(unsigned_int
),
573 ty
::ty_ptr(mt
) if common
::type_is_sized(cx
.tcx(), mt
.ty
) => f(unsigned_int
),
574 ty
::ty_int(_
) => f(signed_int
),
575 ty
::ty_float(_
) => f(floating_point
),
576 // Should never get here, because t is scalar.
577 _
=> cx
.sess().bug("non-scalar type passed to compare_scalar_types")
582 // A helper function to do the actual comparison of scalar values.
583 pub fn compare_scalar_values
<'blk
, 'tcx
>(cx
: Block
<'blk
, 'tcx
>,
589 let _icx
= push_ctxt("compare_scalar_values");
590 fn die(cx
: Block
) -> ! {
591 cx
.sess().bug("compare_scalar_values: must be a comparison operator");
595 // We don't need to do actual comparisons for nil.
596 // () == () holds but () < () does not.
598 ast
::BiEq
| ast
::BiLe
| ast
::BiGe
=> return C_bool(cx
.ccx(), true),
599 ast
::BiNe
| ast
::BiLt
| ast
::BiGt
=> return C_bool(cx
.ccx(), false),
600 // refinements would be nice
606 ast
::BiEq
=> llvm
::RealOEQ
,
607 ast
::BiNe
=> llvm
::RealUNE
,
608 ast
::BiLt
=> llvm
::RealOLT
,
609 ast
::BiLe
=> llvm
::RealOLE
,
610 ast
::BiGt
=> llvm
::RealOGT
,
611 ast
::BiGe
=> llvm
::RealOGE
,
614 return FCmp(cx
, cmp
, lhs
, rhs
);
618 ast
::BiEq
=> llvm
::IntEQ
,
619 ast
::BiNe
=> llvm
::IntNE
,
620 ast
::BiLt
=> llvm
::IntSLT
,
621 ast
::BiLe
=> llvm
::IntSLE
,
622 ast
::BiGt
=> llvm
::IntSGT
,
623 ast
::BiGe
=> llvm
::IntSGE
,
626 return ICmp(cx
, cmp
, lhs
, rhs
);
630 ast
::BiEq
=> llvm
::IntEQ
,
631 ast
::BiNe
=> llvm
::IntNE
,
632 ast
::BiLt
=> llvm
::IntULT
,
633 ast
::BiLe
=> llvm
::IntULE
,
634 ast
::BiGt
=> llvm
::IntUGT
,
635 ast
::BiGe
=> llvm
::IntUGE
,
638 return ICmp(cx
, cmp
, lhs
, rhs
);
643 pub fn compare_simd_types
<'blk
, 'tcx
>(
644 cx
: Block
<'blk
, 'tcx
>,
653 // The comparison operators for floating point vectors are challenging.
654 // LLVM outputs a `< size x i1 >`, but if we perform a sign extension
655 // then bitcast to a floating point vector, the result will be `-NaN`
656 // for each truth value. Because of this they are unsupported.
657 cx
.sess().bug("compare_simd_types: comparison operators \
658 not supported for floating point SIMD types")
660 ty
::ty_uint(_
) | ty
::ty_int(_
) => {
662 ast
::BiEq
=> llvm
::IntEQ
,
663 ast
::BiNe
=> llvm
::IntNE
,
664 ast
::BiLt
=> llvm
::IntSLT
,
665 ast
::BiLe
=> llvm
::IntSLE
,
666 ast
::BiGt
=> llvm
::IntSGT
,
667 ast
::BiGe
=> llvm
::IntSGE
,
668 _
=> cx
.sess().bug("compare_simd_types: must be a comparison operator"),
670 let return_ty
= Type
::vector(&type_of(cx
.ccx(), t
), size
as u64);
671 // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
672 // to get the correctly sized type. This will compile to a single instruction
673 // once the IR is converted to assembly if the SIMD instruction is supported
674 // by the target architecture.
675 SExt(cx
, ICmp(cx
, cmp
, lhs
, rhs
), return_ty
)
677 _
=> cx
.sess().bug("compare_simd_types: invalid SIMD type"),
681 // Iterates through the elements of a structural type.
682 pub fn iter_structural_ty
<'blk
, 'tcx
, F
>(cx
: Block
<'blk
, 'tcx
>,
686 -> Block
<'blk
, 'tcx
> where
687 F
: FnMut(Block
<'blk
, 'tcx
>, ValueRef
, Ty
<'tcx
>) -> Block
<'blk
, 'tcx
>,
689 let _icx
= push_ctxt("iter_structural_ty");
691 fn iter_variant
<'blk
, 'tcx
, F
>(cx
: Block
<'blk
, 'tcx
>,
692 repr
: &adt
::Repr
<'tcx
>,
694 variant
: &ty
::VariantInfo
<'tcx
>,
695 substs
: &subst
::Substs
<'tcx
>,
697 -> Block
<'blk
, 'tcx
> where
698 F
: FnMut(Block
<'blk
, 'tcx
>, ValueRef
, Ty
<'tcx
>) -> Block
<'blk
, 'tcx
>,
700 let _icx
= push_ctxt("iter_variant");
704 for (i
, &arg
) in variant
.args
.iter().enumerate() {
706 adt
::trans_field_ptr(cx
, repr
, av
, variant
.disr_val
, i
),
707 arg
.subst(tcx
, substs
));
712 let (data_ptr
, info
) = if common
::type_is_sized(cx
.tcx(), t
) {
715 let data
= GEPi(cx
, av
, &[0, abi
::FAT_PTR_ADDR
]);
716 let info
= GEPi(cx
, av
, &[0, abi
::FAT_PTR_EXTRA
]);
717 (Load(cx
, data
), Some(Load(cx
, info
)))
722 ty
::ty_struct(..) => {
723 let repr
= adt
::represent_type(cx
.ccx(), t
);
724 expr
::with_field_tys(cx
.tcx(), t
, None
, |discr
, field_tys
| {
725 for (i
, field_ty
) in field_tys
.iter().enumerate() {
726 let field_ty
= field_ty
.mt
.ty
;
727 let llfld_a
= adt
::trans_field_ptr(cx
, &*repr
, data_ptr
, discr
, i
);
729 let val
= if common
::type_is_sized(cx
.tcx(), field_ty
) {
732 let boxed_ty
= ty
::mk_open(cx
.tcx(), field_ty
);
733 let scratch
= datum
::rvalue_scratch_datum(cx
, boxed_ty
, "__fat_ptr_iter");
734 Store(cx
, llfld_a
, GEPi(cx
, scratch
.val
, &[0, abi
::FAT_PTR_ADDR
]));
735 Store(cx
, info
.unwrap(), GEPi(cx
, scratch
.val
, &[0, abi
::FAT_PTR_EXTRA
]));
738 cx
= f(cx
, val
, field_ty
);
742 ty
::ty_unboxed_closure(def_id
, _
, substs
) => {
743 let repr
= adt
::represent_type(cx
.ccx(), t
);
744 let typer
= common
::NormalizingUnboxedClosureTyper
::new(cx
.tcx());
745 let upvars
= typer
.unboxed_closure_upvars(def_id
, substs
).unwrap();
746 for (i
, upvar
) in upvars
.iter().enumerate() {
747 let llupvar
= adt
::trans_field_ptr(cx
, &*repr
, data_ptr
, 0, i
);
748 cx
= f(cx
, llupvar
, upvar
.ty
);
751 ty
::ty_vec(_
, Some(n
)) => {
752 let (base
, len
) = tvec
::get_fixed_base_and_len(cx
, data_ptr
, n
);
753 let unit_ty
= ty
::sequence_element_type(cx
.tcx(), t
);
754 cx
= tvec
::iter_vec_raw(cx
, base
, unit_ty
, len
, f
);
756 ty
::ty_tup(ref args
) => {
757 let repr
= adt
::represent_type(cx
.ccx(), t
);
758 for (i
, arg
) in args
.iter().enumerate() {
759 let llfld_a
= adt
::trans_field_ptr(cx
, &*repr
, data_ptr
, 0, i
);
760 cx
= f(cx
, llfld_a
, *arg
);
763 ty
::ty_enum(tid
, substs
) => {
767 let repr
= adt
::represent_type(ccx
, t
);
768 let variants
= ty
::enum_variants(ccx
.tcx(), tid
);
769 let n_variants
= (*variants
).len();
771 // NB: we must hit the discriminant first so that structural
772 // comparison know not to proceed when the discriminants differ.
774 match adt
::trans_switch(cx
, &*repr
, av
) {
775 (_match
::Single
, None
) => {
776 cx
= iter_variant(cx
, &*repr
, av
, &*(*variants
)[0],
779 (_match
::Switch
, Some(lldiscrim_a
)) => {
780 cx
= f(cx
, lldiscrim_a
, cx
.tcx().types
.int
);
781 let unr_cx
= fcx
.new_temp_block("enum-iter-unr");
783 let llswitch
= Switch(cx
, lldiscrim_a
, unr_cx
.llbb
,
785 let next_cx
= fcx
.new_temp_block("enum-iter-next");
787 for variant
in (*variants
).iter() {
790 &format
!("enum-iter-variant-{}",
791 &variant
.disr_val
.to_string()[])
793 match adt
::trans_case(cx
, &*repr
, variant
.disr_val
) {
794 _match
::SingleResult(r
) => {
795 AddCase(llswitch
, r
.val
, variant_cx
.llbb
)
797 _
=> ccx
.sess().unimpl("value from adt::trans_case \
798 in iter_structural_ty")
801 iter_variant(variant_cx
,
807 Br(variant_cx
, next_cx
.llbb
);
811 _
=> ccx
.sess().unimpl("value from adt::trans_switch \
812 in iter_structural_ty")
816 cx
.sess().unimpl(&format
!("type in iter_structural_ty: {}",
817 ty_to_string(cx
.tcx(), t
))[])
823 pub fn cast_shift_expr_rhs(cx
: Block
,
828 cast_shift_rhs(op
, lhs
, rhs
,
829 |a
,b
| Trunc(cx
, a
, b
),
830 |a
,b
| ZExt(cx
, a
, b
))
833 pub fn cast_shift_const_rhs(op
: ast
::BinOp
,
834 lhs
: ValueRef
, rhs
: ValueRef
) -> ValueRef
{
835 cast_shift_rhs(op
, lhs
, rhs
,
836 |a
, b
| unsafe { llvm::LLVMConstTrunc(a, b.to_ref()) }
,
837 |a
, b
| unsafe { llvm::LLVMConstZExt(a, b.to_ref()) }
)
840 pub fn cast_shift_rhs
<F
, G
>(op
: ast
::BinOp
,
846 F
: FnOnce(ValueRef
, Type
) -> ValueRef
,
847 G
: FnOnce(ValueRef
, Type
) -> ValueRef
,
849 // Shifts may have any size int on the rhs
851 if ast_util
::is_shift_binop(op
) {
852 let mut rhs_llty
= val_ty(rhs
);
853 let mut lhs_llty
= val_ty(lhs
);
854 if rhs_llty
.kind() == Vector { rhs_llty = rhs_llty.element_type() }
855 if lhs_llty
.kind() == Vector { lhs_llty = lhs_llty.element_type() }
856 let rhs_sz
= llvm
::LLVMGetIntTypeWidth(rhs_llty
.to_ref());
857 let lhs_sz
= llvm
::LLVMGetIntTypeWidth(lhs_llty
.to_ref());
860 } else if lhs_sz
> rhs_sz
{
861 // FIXME (#1877: If shifting by negative
862 // values becomes not undefined then this is wrong.
873 pub fn fail_if_zero_or_overflows
<'blk
, 'tcx
>(
874 cx
: Block
<'blk
, 'tcx
>,
880 -> Block
<'blk
, 'tcx
> {
881 let (zero_text
, overflow_text
) = if divrem
== ast
::BiDiv
{
882 ("attempted to divide by zero",
883 "attempted to divide with overflow")
885 ("attempted remainder with a divisor of zero",
886 "attempted remainder with overflow")
888 let (is_zero
, is_signed
) = match rhs_t
.sty
{
890 let zero
= C_integral(Type
::int_from_ty(cx
.ccx(), t
), 0u64, false);
891 (ICmp(cx
, llvm
::IntEQ
, rhs
, zero
), true)
894 let zero
= C_integral(Type
::uint_from_ty(cx
.ccx(), t
), 0u64, false);
895 (ICmp(cx
, llvm
::IntEQ
, rhs
, zero
), false)
898 cx
.sess().bug(&format
!("fail-if-zero on unexpected type: {}",
899 ty_to_string(cx
.tcx(), rhs_t
))[]);
902 let bcx
= with_cond(cx
, is_zero
, |bcx
| {
903 controlflow
::trans_fail(bcx
, span
, InternedString
::new(zero_text
))
906 // To quote LLVM's documentation for the sdiv instruction:
908 // Division by zero leads to undefined behavior. Overflow also leads
909 // to undefined behavior; this is a rare case, but can occur, for
910 // example, by doing a 32-bit division of -2147483648 by -1.
912 // In order to avoid undefined behavior, we perform runtime checks for
913 // signed division/remainder which would trigger overflow. For unsigned
914 // integers, no action beyond checking for zero need be taken.
916 let (llty
, min
) = match rhs_t
.sty
{
918 let llty
= Type
::int_from_ty(cx
.ccx(), t
);
920 ast
::TyIs(_
) if llty
== Type
::i32(cx
.ccx()) => i32::MIN
as u64,
921 ast
::TyIs(_
) => i64::MIN
as u64,
922 ast
::TyI8
=> i8::MIN
as u64,
923 ast
::TyI16
=> i16::MIN
as u64,
924 ast
::TyI32
=> i32::MIN
as u64,
925 ast
::TyI64
=> i64::MIN
as u64,
931 let minus_one
= ICmp(bcx
, llvm
::IntEQ
, rhs
,
932 C_integral(llty
, -1, false));
933 with_cond(bcx
, minus_one
, |bcx
| {
934 let is_min
= ICmp(bcx
, llvm
::IntEQ
, lhs
,
935 C_integral(llty
, min
, true));
936 with_cond(bcx
, is_min
, |bcx
| {
937 controlflow
::trans_fail(bcx
, span
,
938 InternedString
::new(overflow_text
))
946 pub fn trans_external_path
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
947 did
: ast
::DefId
, t
: Ty
<'tcx
>) -> ValueRef
{
948 let name
= csearch
::get_symbol(&ccx
.sess().cstore
, did
);
950 ty
::ty_bare_fn(_
, ref fn_ty
) => {
951 match ccx
.sess().target
.target
.adjust_abi(fn_ty
.abi
) {
953 get_extern_rust_fn(ccx
, t
, &name
[], did
)
956 ccx
.sess().bug("unexpected intrinsic in trans_external_path")
959 foreign
::register_foreign_item_fn(ccx
, fn_ty
.abi
, t
,
965 get_extern_const(ccx
, did
, t
)
970 pub fn invoke
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
974 call_info
: Option
<NodeInfo
>)
975 -> (ValueRef
, Block
<'blk
, 'tcx
>) {
976 let _icx
= push_ctxt("invoke_");
977 if bcx
.unreachable
.get() {
978 return (C_null(Type
::i8(bcx
.ccx())), bcx
);
981 let attributes
= get_fn_llvm_attributes(bcx
.ccx(), fn_ty
);
983 match bcx
.opt_node_id
{
985 debug
!("invoke at ???");
988 debug
!("invoke at {}", bcx
.tcx().map
.node_to_string(id
));
992 if need_invoke(bcx
) {
993 debug
!("invoking {} at {:?}", bcx
.val_to_string(llfn
), bcx
.llbb
);
994 for &llarg
in llargs
.iter() {
995 debug
!("arg: {}", bcx
.val_to_string(llarg
));
997 let normal_bcx
= bcx
.fcx
.new_temp_block("normal-return");
998 let landing_pad
= bcx
.fcx
.get_landing_pad();
1001 Some(info
) => debuginfo
::set_source_location(bcx
.fcx
, info
.id
, info
.span
),
1002 None
=> debuginfo
::clear_source_location(bcx
.fcx
)
1005 let llresult
= Invoke(bcx
,
1011 return (llresult
, normal_bcx
);
1013 debug
!("calling {} at {:?}", bcx
.val_to_string(llfn
), bcx
.llbb
);
1014 for &llarg
in llargs
.iter() {
1015 debug
!("arg: {}", bcx
.val_to_string(llarg
));
1019 Some(info
) => debuginfo
::set_source_location(bcx
.fcx
, info
.id
, info
.span
),
1020 None
=> debuginfo
::clear_source_location(bcx
.fcx
)
1023 let llresult
= Call(bcx
, llfn
, &llargs
[], Some(attributes
));
1024 return (llresult
, bcx
);
1028 pub fn need_invoke(bcx
: Block
) -> bool
{
1029 if bcx
.sess().no_landing_pads() {
1033 // Avoid using invoke if we are already inside a landing pad.
1038 bcx
.fcx
.needs_invoke()
1041 pub fn load_if_immediate
<'blk
, 'tcx
>(cx
: Block
<'blk
, 'tcx
>,
1042 v
: ValueRef
, t
: Ty
<'tcx
>) -> ValueRef
{
1043 let _icx
= push_ctxt("load_if_immediate");
1044 if type_is_immediate(cx
.ccx(), t
) { return load_ty(cx, v, t); }
1048 /// Helper for loading values from memory. Does the necessary conversion if the in-memory type
1049 /// differs from the type used for SSA values. Also handles various special cases where the type
1050 /// gives us better information about what we are loading.
1051 pub fn load_ty
<'blk
, 'tcx
>(cx
: Block
<'blk
, 'tcx
>,
1052 ptr
: ValueRef
, t
: Ty
<'tcx
>) -> ValueRef
{
1053 if type_is_zero_size(cx
.ccx(), t
) {
1054 C_undef(type_of
::type_of(cx
.ccx(), t
))
1055 } else if ty
::type_is_bool(t
) {
1056 Trunc(cx
, LoadRangeAssert(cx
, ptr
, 0, 2, llvm
::False
), Type
::i1(cx
.ccx()))
1057 } else if ty
::type_is_char(t
) {
1058 // a char is a Unicode codepoint, and so takes values from 0
1059 // to 0x10FFFF inclusive only.
1060 LoadRangeAssert(cx
, ptr
, 0, 0x10FFFF + 1, llvm
::False
)
1066 /// Helper for storing values in memory. Does the necessary conversion if the in-memory type
1067 /// differs from the type used for SSA values.
1068 pub fn store_ty(cx
: Block
, v
: ValueRef
, dst
: ValueRef
, t
: Ty
) {
1069 if ty
::type_is_bool(t
) {
1070 Store(cx
, ZExt(cx
, v
, Type
::i8(cx
.ccx())), dst
);
1076 pub fn init_local
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, local
: &ast
::Local
)
1077 -> Block
<'blk
, 'tcx
> {
1078 debug
!("init_local(bcx={}, local.id={})", bcx
.to_str(), local
.id
);
1079 let _indenter
= indenter();
1080 let _icx
= push_ctxt("init_local");
1081 _match
::store_local(bcx
, local
)
1084 pub fn raw_block
<'blk
, 'tcx
>(fcx
: &'blk FunctionContext
<'blk
, 'tcx
>,
1086 llbb
: BasicBlockRef
)
1087 -> Block
<'blk
, 'tcx
> {
1088 common
::BlockS
::new(llbb
, is_lpad
, None
, fcx
)
1091 pub fn with_cond
<'blk
, 'tcx
, F
>(bcx
: Block
<'blk
, 'tcx
>,
1094 -> Block
<'blk
, 'tcx
> where
1095 F
: FnOnce(Block
<'blk
, 'tcx
>) -> Block
<'blk
, 'tcx
>,
1097 let _icx
= push_ctxt("with_cond");
1099 let next_cx
= fcx
.new_temp_block("next");
1100 let cond_cx
= fcx
.new_temp_block("cond");
1101 CondBr(bcx
, val
, cond_cx
.llbb
, next_cx
.llbb
);
1102 let after_cx
= f(cond_cx
);
1103 if !after_cx
.terminated
.get() {
1104 Br(after_cx
, next_cx
.llbb
);
1109 pub fn call_lifetime_start(cx
: Block
, ptr
: ValueRef
) {
1110 if cx
.sess().opts
.optimize
== config
::No
{
1114 let _icx
= push_ctxt("lifetime_start");
1117 let llsize
= C_u64(ccx
, machine
::llsize_of_alloc(ccx
, val_ty(ptr
).element_type()));
1118 let ptr
= PointerCast(cx
, ptr
, Type
::i8p(ccx
));
1119 let lifetime_start
= ccx
.get_intrinsic(&"llvm.lifetime.start");
1120 Call(cx
, lifetime_start
, &[llsize
, ptr
], None
);
1123 pub fn call_lifetime_end(cx
: Block
, ptr
: ValueRef
) {
1124 if cx
.sess().opts
.optimize
== config
::No
{
1128 let _icx
= push_ctxt("lifetime_end");
1131 let llsize
= C_u64(ccx
, machine
::llsize_of_alloc(ccx
, val_ty(ptr
).element_type()));
1132 let ptr
= PointerCast(cx
, ptr
, Type
::i8p(ccx
));
1133 let lifetime_end
= ccx
.get_intrinsic(&"llvm.lifetime.end");
1134 Call(cx
, lifetime_end
, &[llsize
, ptr
], None
);
1137 pub fn call_memcpy(cx
: Block
, dst
: ValueRef
, src
: ValueRef
, n_bytes
: ValueRef
, align
: u32) {
1138 let _icx
= push_ctxt("call_memcpy");
1140 let key
= match &ccx
.sess().target
.target
.target_pointer_width
[] {
1141 "32" => "llvm.memcpy.p0i8.p0i8.i32",
1142 "64" => "llvm.memcpy.p0i8.p0i8.i64",
1143 tws
=> panic
!("Unsupported target word size for memcpy: {}", tws
),
1145 let memcpy
= ccx
.get_intrinsic(&key
);
1146 let src_ptr
= PointerCast(cx
, src
, Type
::i8p(ccx
));
1147 let dst_ptr
= PointerCast(cx
, dst
, Type
::i8p(ccx
));
1148 let size
= IntCast(cx
, n_bytes
, ccx
.int_type());
1149 let align
= C_i32(ccx
, align
as i32);
1150 let volatile
= C_bool(ccx
, false);
1151 Call(cx
, memcpy
, &[dst_ptr
, src_ptr
, size
, align
, volatile
], None
);
1154 pub fn memcpy_ty
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
1155 dst
: ValueRef
, src
: ValueRef
,
1157 let _icx
= push_ctxt("memcpy_ty");
1158 let ccx
= bcx
.ccx();
1159 if ty
::type_is_structural(t
) {
1160 let llty
= type_of
::type_of(ccx
, t
);
1161 let llsz
= llsize_of(ccx
, llty
);
1162 let llalign
= type_of
::align_of(ccx
, t
);
1163 call_memcpy(bcx
, dst
, src
, llsz
, llalign
as u32);
1165 store_ty(bcx
, Load(bcx
, src
), dst
, t
);
1169 pub fn zero_mem
<'blk
, 'tcx
>(cx
: Block
<'blk
, 'tcx
>, llptr
: ValueRef
, t
: Ty
<'tcx
>) {
1170 if cx
.unreachable
.get() { return; }
1171 let _icx
= push_ctxt("zero_mem");
1173 memzero(&B(bcx
), llptr
, t
);
1176 // Always use this function instead of storing a zero constant to the memory
1177 // in question. If you store a zero constant, LLVM will drown in vreg
1178 // allocation for large data structures, and the generated code will be
1179 // awful. (A telltale sign of this is large quantities of
1180 // `mov [byte ptr foo],0` in the generated code.)
1181 fn memzero
<'a
, 'tcx
>(b
: &Builder
<'a
, 'tcx
>, llptr
: ValueRef
, ty
: Ty
<'tcx
>) {
1182 let _icx
= push_ctxt("memzero");
1185 let llty
= type_of
::type_of(ccx
, ty
);
1187 let intrinsic_key
= match &ccx
.sess().target
.target
.target_pointer_width
[] {
1188 "32" => "llvm.memset.p0i8.i32",
1189 "64" => "llvm.memset.p0i8.i64",
1190 tws
=> panic
!("Unsupported target word size for memset: {}", tws
),
1193 let llintrinsicfn
= ccx
.get_intrinsic(&intrinsic_key
);
1194 let llptr
= b
.pointercast(llptr
, Type
::i8(ccx
).ptr_to());
1195 let llzeroval
= C_u8(ccx
, 0);
1196 let size
= machine
::llsize_of(ccx
, llty
);
1197 let align
= C_i32(ccx
, type_of
::align_of(ccx
, ty
) as i32);
1198 let volatile
= C_bool(ccx
, false);
1199 b
.call(llintrinsicfn
, &[llptr
, llzeroval
, size
, align
, volatile
], None
);
1202 pub fn alloc_ty
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>, t
: Ty
<'tcx
>, name
: &str) -> ValueRef
{
1203 let _icx
= push_ctxt("alloc_ty");
1204 let ccx
= bcx
.ccx();
1205 let ty
= type_of
::type_of(ccx
, t
);
1206 assert
!(!ty
::type_has_params(t
));
1207 let val
= alloca(bcx
, ty
, name
);
1211 pub fn alloca(cx
: Block
, ty
: Type
, name
: &str) -> ValueRef
{
1212 let p
= alloca_no_lifetime(cx
, ty
, name
);
1213 call_lifetime_start(cx
, p
);
1217 pub fn alloca_no_lifetime(cx
: Block
, ty
: Type
, name
: &str) -> ValueRef
{
1218 let _icx
= push_ctxt("alloca");
1219 if cx
.unreachable
.get() {
1221 return llvm
::LLVMGetUndef(ty
.ptr_to().to_ref());
1224 debuginfo
::clear_source_location(cx
.fcx
);
1225 Alloca(cx
, ty
, name
)
1228 pub fn alloca_zeroed
<'blk
, 'tcx
>(cx
: Block
<'blk
, 'tcx
>, ty
: Ty
<'tcx
>,
1229 name
: &str) -> ValueRef
{
1230 let llty
= type_of
::type_of(cx
.ccx(), ty
);
1231 if cx
.unreachable
.get() {
1233 return llvm
::LLVMGetUndef(llty
.ptr_to().to_ref());
1236 let p
= alloca_no_lifetime(cx
, llty
, name
);
1237 let b
= cx
.fcx
.ccx
.builder();
1238 b
.position_before(cx
.fcx
.alloca_insert_pt
.get().unwrap());
1243 pub fn arrayalloca(cx
: Block
, ty
: Type
, v
: ValueRef
) -> ValueRef
{
1244 let _icx
= push_ctxt("arrayalloca");
1245 if cx
.unreachable
.get() {
1247 return llvm
::LLVMGetUndef(ty
.to_ref());
1250 debuginfo
::clear_source_location(cx
.fcx
);
1251 let p
= ArrayAlloca(cx
, ty
, v
);
1252 call_lifetime_start(cx
, p
);
1256 // Creates the alloca slot which holds the pointer to the slot for the final return value
1257 pub fn make_return_slot_pointer
<'a
, 'tcx
>(fcx
: &FunctionContext
<'a
, 'tcx
>,
1258 output_type
: Ty
<'tcx
>) -> ValueRef
{
1259 let lloutputtype
= type_of
::type_of(fcx
.ccx
, output_type
);
1261 // We create an alloca to hold a pointer of type `output_type`
1262 // which will hold the pointer to the right alloca which has the
1264 if fcx
.needs_ret_allocas
{
1265 // Let's create the stack slot
1266 let slot
= AllocaFcx(fcx
, lloutputtype
.ptr_to(), "llretslotptr");
1268 // and if we're using an out pointer, then store that in our newly made slot
1269 if type_of
::return_uses_outptr(fcx
.ccx
, output_type
) {
1270 let outptr
= get_param(fcx
.llfn
, 0);
1272 let b
= fcx
.ccx
.builder();
1273 b
.position_before(fcx
.alloca_insert_pt
.get().unwrap());
1274 b
.store(outptr
, slot
);
1279 // But if there are no nested returns, we skip the indirection and have a single
1282 if type_of
::return_uses_outptr(fcx
.ccx
, output_type
) {
1283 get_param(fcx
.llfn
, 0)
1285 AllocaFcx(fcx
, lloutputtype
, "sret_slot")
1290 struct FindNestedReturn
{
1294 impl FindNestedReturn
{
1295 fn new() -> FindNestedReturn
{
1296 FindNestedReturn { found: false }
1300 impl<'v
> Visitor
<'v
> for FindNestedReturn
{
1301 fn visit_expr(&mut self, e
: &ast
::Expr
) {
1303 ast
::ExprRet(..) => {
1306 _
=> visit
::walk_expr(self, e
)
1311 fn build_cfg(tcx
: &ty
::ctxt
, id
: ast
::NodeId
) -> (ast
::NodeId
, Option
<cfg
::CFG
>) {
1312 let blk
= match tcx
.map
.find(id
) {
1313 Some(ast_map
::NodeItem(i
)) => {
1315 ast
::ItemFn(_
, _
, _
, _
, ref blk
) => {
1318 _
=> tcx
.sess
.bug("unexpected item variant in has_nested_returns")
1321 Some(ast_map
::NodeTraitItem(trait_method
)) => {
1322 match *trait_method
{
1323 ast
::ProvidedMethod(ref m
) => {
1325 ast
::MethDecl(_
, _
, _
, _
, _
, _
, ref blk
, _
) => {
1328 ast
::MethMac(_
) => tcx
.sess
.bug("unexpanded macro")
1331 ast
::RequiredMethod(_
) => {
1332 tcx
.sess
.bug("unexpected variant: required trait method \
1333 in has_nested_returns")
1335 ast
::TypeTraitItem(_
) => {
1336 tcx
.sess
.bug("unexpected variant: type trait item in \
1337 has_nested_returns")
1341 Some(ast_map
::NodeImplItem(ii
)) => {
1343 ast
::MethodImplItem(ref m
) => {
1345 ast
::MethDecl(_
, _
, _
, _
, _
, _
, ref blk
, _
) => {
1348 ast
::MethMac(_
) => tcx
.sess
.bug("unexpanded macro")
1351 ast
::TypeImplItem(_
) => {
1352 tcx
.sess
.bug("unexpected variant: type impl item in \
1353 has_nested_returns")
1357 Some(ast_map
::NodeExpr(e
)) => {
1359 ast
::ExprClosure(_
, _
, _
, ref blk
) => {
1362 _
=> tcx
.sess
.bug("unexpected expr variant in has_nested_returns")
1365 Some(ast_map
::NodeVariant(..)) |
1366 Some(ast_map
::NodeStructCtor(..)) => return (ast
::DUMMY_NODE_ID
, None
),
1369 None
if id
== ast
::DUMMY_NODE_ID
=> return (ast
::DUMMY_NODE_ID
, None
),
1371 _
=> tcx
.sess
.bug(format
!("unexpected variant in has_nested_returns: {}",
1372 tcx
.map
.path_to_string(id
)).as_slice())
1375 (blk
.id
, Some(cfg
::CFG
::new(tcx
, &**blk
)))
1378 // Checks for the presence of "nested returns" in a function.
1379 // Nested returns are when the inner expression of a return expression
1380 // (the 'expr' in 'return expr') contains a return expression. Only cases
1381 // where the outer return is actually reachable are considered. Implicit
1382 // returns from the end of blocks are considered as well.
1384 // This check is needed to handle the case where the inner expression is
1385 // part of a larger expression that may have already partially-filled the
1386 // return slot alloca. This can cause errors related to clean-up due to
1387 // the clobbering of the existing value in the return slot.
1388 fn has_nested_returns(tcx
: &ty
::ctxt
, cfg
: &cfg
::CFG
, blk_id
: ast
::NodeId
) -> bool
{
1389 for n
in cfg
.graph
.depth_traverse(cfg
.entry
) {
1390 match tcx
.map
.find(n
.id
) {
1391 Some(ast_map
::NodeExpr(ex
)) => {
1392 if let ast
::ExprRet(Some(ref ret_expr
)) = ex
.node
{
1393 let mut visitor
= FindNestedReturn
::new();
1394 visit
::walk_expr(&mut visitor
, &**ret_expr
);
1400 Some(ast_map
::NodeBlock(blk
)) if blk
.id
== blk_id
=> {
1401 let mut visitor
= FindNestedReturn
::new();
1402 visit
::walk_expr_opt(&mut visitor
, &blk
.expr
);
1414 // NB: must keep 4 fns in sync:
1417 // - create_datums_for_fn_args.
1421 // Be warned! You must call `init_function` before doing anything with the
1422 // returned function context.
1423 pub fn new_fn_ctxt
<'a
, 'tcx
>(ccx
: &'a CrateContext
<'a
, 'tcx
>,
1427 output_type
: ty
::FnOutput
<'tcx
>,
1428 param_substs
: &'a Substs
<'tcx
>,
1430 block_arena
: &'a TypedArena
<common
::BlockS
<'a
, 'tcx
>>)
1431 -> FunctionContext
<'a
, 'tcx
> {
1432 common
::validate_substs(param_substs
);
1434 debug
!("new_fn_ctxt(path={}, id={}, param_substs={})",
1438 ccx
.tcx().map
.path_to_string(id
).to_string()
1440 id
, param_substs
.repr(ccx
.tcx()));
1442 let uses_outptr
= match output_type
{
1443 ty
::FnConverging(output_type
) => {
1444 let substd_output_type
=
1445 monomorphize
::apply_param_substs(ccx
.tcx(), param_substs
, &output_type
);
1446 type_of
::return_uses_outptr(ccx
, substd_output_type
)
1448 ty
::FnDiverging
=> false
1450 let debug_context
= debuginfo
::create_function_debug_context(ccx
, id
, param_substs
, llfndecl
);
1451 let (blk_id
, cfg
) = build_cfg(ccx
.tcx(), id
);
1452 let nested_returns
= if let Some(ref cfg
) = cfg
{
1453 has_nested_returns(ccx
.tcx(), cfg
, blk_id
)
1458 let mut fcx
= FunctionContext
{
1461 llretslotptr
: Cell
::new(None
),
1462 param_env
: ty
::empty_parameter_environment(ccx
.tcx()),
1463 alloca_insert_pt
: Cell
::new(None
),
1464 llreturn
: Cell
::new(None
),
1465 needs_ret_allocas
: nested_returns
,
1466 personality
: Cell
::new(None
),
1467 caller_expects_out_pointer
: uses_outptr
,
1468 lllocals
: RefCell
::new(NodeMap
::new()),
1469 llupvars
: RefCell
::new(NodeMap
::new()),
1471 param_substs
: param_substs
,
1473 block_arena
: block_arena
,
1475 debug_context
: debug_context
,
1476 scopes
: RefCell
::new(Vec
::new()),
1481 fcx
.llenv
= Some(get_param(fcx
.llfn
, fcx
.env_arg_pos() as c_uint
))
1487 /// Performs setup on a newly created function, creating the entry scope block
1488 /// and allocating space for the return pointer.
1489 pub fn init_function
<'a
, 'tcx
>(fcx
: &'a FunctionContext
<'a
, 'tcx
>,
1491 output
: ty
::FnOutput
<'tcx
>)
1492 -> Block
<'a
, 'tcx
> {
1493 let entry_bcx
= fcx
.new_temp_block("entry-block");
1495 // Use a dummy instruction as the insertion point for all allocas.
1496 // This is later removed in FunctionContext::cleanup.
1497 fcx
.alloca_insert_pt
.set(Some(unsafe {
1498 Load(entry_bcx
, C_null(Type
::i8p(fcx
.ccx
)));
1499 llvm
::LLVMGetFirstInstruction(entry_bcx
.llbb
)
1502 if let ty
::FnConverging(output_type
) = output
{
1503 // This shouldn't need to recompute the return type,
1504 // as new_fn_ctxt did it already.
1505 let substd_output_type
= fcx
.monomorphize(&output_type
);
1506 if !return_type_is_void(fcx
.ccx
, substd_output_type
) {
1507 // If the function returns nil/bot, there is no real return
1508 // value, so do not set `llretslotptr`.
1509 if !skip_retptr
|| fcx
.caller_expects_out_pointer
{
1510 // Otherwise, we normally allocate the llretslotptr, unless we
1511 // have been instructed to skip it for immediate return
1513 fcx
.llretslotptr
.set(Some(make_return_slot_pointer(fcx
, substd_output_type
)));
1521 // NB: must keep 4 fns in sync:
1524 // - create_datums_for_fn_args.
1528 pub fn arg_kind
<'a
, 'tcx
>(cx
: &FunctionContext
<'a
, 'tcx
>, t
: Ty
<'tcx
>)
1530 use trans
::datum
::{ByRef, ByValue}
;
1533 mode
: if arg_is_indirect(cx
.ccx
, t
) { ByRef }
else { ByValue }
1537 // work around bizarre resolve errors
1538 type RvalueDatum
<'tcx
> = datum
::Datum
<'tcx
, datum
::Rvalue
>;
1540 // create_datums_for_fn_args: creates rvalue datums for each of the
1541 // incoming function arguments. These will later be stored into
1542 // appropriate lvalue datums.
1543 pub fn create_datums_for_fn_args
<'a
, 'tcx
>(fcx
: &FunctionContext
<'a
, 'tcx
>,
1544 arg_tys
: &[Ty
<'tcx
>])
1545 -> Vec
<RvalueDatum
<'tcx
>> {
1546 let _icx
= push_ctxt("create_datums_for_fn_args");
1548 // Return an array wrapping the ValueRefs that we get from `get_param` for
1549 // each argument into datums.
1550 arg_tys
.iter().enumerate().map(|(i
, &arg_ty
)| {
1551 let llarg
= get_param(fcx
.llfn
, fcx
.arg_pos(i
) as c_uint
);
1552 datum
::Datum
::new(llarg
, arg_ty
, arg_kind(fcx
, arg_ty
))
1556 /// Creates rvalue datums for each of the incoming function arguments and
1557 /// tuples the arguments. These will later be stored into appropriate lvalue
1560 /// FIXME(pcwalton): Reduce the amount of code bloat this is responsible for.
1561 fn create_datums_for_fn_args_under_call_abi
<'blk
, 'tcx
>(
1562 mut bcx
: Block
<'blk
, 'tcx
>,
1563 arg_scope
: cleanup
::CustomScopeIndex
,
1564 arg_tys
: &[Ty
<'tcx
>])
1565 -> Vec
<RvalueDatum
<'tcx
>> {
1566 let mut result
= Vec
::new();
1567 for (i
, &arg_ty
) in arg_tys
.iter().enumerate() {
1568 if i
< arg_tys
.len() - 1 {
1569 // Regular argument.
1570 let llarg
= get_param(bcx
.fcx
.llfn
, bcx
.fcx
.arg_pos(i
) as c_uint
);
1571 result
.push(datum
::Datum
::new(llarg
, arg_ty
, arg_kind(bcx
.fcx
,
1576 // This is the last argument. Tuple it.
1578 ty
::ty_tup(ref tupled_arg_tys
) => {
1579 let tuple_args_scope_id
= cleanup
::CustomScope(arg_scope
);
1582 datum
::lvalue_scratch_datum(bcx
,
1586 tuple_args_scope_id
,
1591 for (j
, &tupled_arg_ty
) in
1592 tupled_arg_tys
.iter().enumerate() {
1594 get_param(bcx
.fcx
.llfn
,
1595 bcx
.fcx
.arg_pos(i
+ j
) as c_uint
);
1596 let lldest
= GEPi(bcx
, llval
, &[0, j
]);
1597 let datum
= datum
::Datum
::new(
1600 arg_kind(bcx
.fcx
, tupled_arg_ty
));
1601 bcx
= datum
.store_to(bcx
, lldest
);
1605 let tuple
= unpack_datum
!(bcx
,
1606 tuple
.to_expr_datum()
1607 .to_rvalue_datum(bcx
,
1612 bcx
.tcx().sess
.bug("last argument of a function with \
1613 `rust-call` ABI isn't a tuple?!")
1622 fn copy_args_to_allocas
<'blk
, 'tcx
>(fcx
: &FunctionContext
<'blk
, 'tcx
>,
1623 arg_scope
: cleanup
::CustomScopeIndex
,
1624 bcx
: Block
<'blk
, 'tcx
>,
1626 arg_datums
: Vec
<RvalueDatum
<'tcx
>>)
1627 -> Block
<'blk
, 'tcx
> {
1628 debug
!("copy_args_to_allocas");
1630 let _icx
= push_ctxt("copy_args_to_allocas");
1633 let arg_scope_id
= cleanup
::CustomScope(arg_scope
);
1635 for (i
, arg_datum
) in arg_datums
.into_iter().enumerate() {
1636 // For certain mode/type combinations, the raw llarg values are passed
1637 // by value. However, within the fn body itself, we want to always
1638 // have all locals and arguments be by-ref so that we can cancel the
1639 // cleanup and for better interaction with LLVM's debug info. So, if
1640 // the argument would be passed by value, we store it into an alloca.
1641 // This alloca should be optimized away by LLVM's mem-to-reg pass in
1642 // the event it's not truly needed.
1644 bcx
= _match
::store_arg(bcx
, &*args
[i
].pat
, arg_datum
, arg_scope_id
);
1646 if fcx
.ccx
.sess().opts
.debuginfo
== FullDebugInfo
{
1647 debuginfo
::create_argument_metadata(bcx
, &args
[i
]);
1654 fn copy_unboxed_closure_args_to_allocas
<'blk
, 'tcx
>(
1655 mut bcx
: Block
<'blk
, 'tcx
>,
1656 arg_scope
: cleanup
::CustomScopeIndex
,
1658 arg_datums
: Vec
<RvalueDatum
<'tcx
>>,
1659 monomorphized_arg_types
: &[Ty
<'tcx
>])
1660 -> Block
<'blk
, 'tcx
> {
1661 let _icx
= push_ctxt("copy_unboxed_closure_args_to_allocas");
1662 let arg_scope_id
= cleanup
::CustomScope(arg_scope
);
1664 assert_eq
!(arg_datums
.len(), 1);
1666 let arg_datum
= arg_datums
.into_iter().next().unwrap();
1668 // Untuple the rest of the arguments.
1671 arg_datum
.to_lvalue_datum_in_scope(bcx
,
1674 let untupled_arg_types
= match monomorphized_arg_types
[0].sty
{
1675 ty
::ty_tup(ref types
) => &types
[],
1677 bcx
.tcx().sess
.span_bug(args
[0].pat
.span
,
1678 "first arg to `rust-call` ABI function \
1682 for j
in range(0, args
.len()) {
1683 let tuple_element_type
= untupled_arg_types
[j
];
1684 let tuple_element_datum
=
1685 tuple_datum
.get_element(bcx
,
1687 |llval
| GEPi(bcx
, llval
, &[0, j
]));
1688 let tuple_element_datum
= tuple_element_datum
.to_expr_datum();
1689 let tuple_element_datum
=
1691 tuple_element_datum
.to_rvalue_datum(bcx
,
1693 bcx
= _match
::store_arg(bcx
,
1695 tuple_element_datum
,
1698 if bcx
.fcx
.ccx
.sess().opts
.debuginfo
== FullDebugInfo
{
1699 debuginfo
::create_argument_metadata(bcx
, &args
[j
]);
1706 // Ties up the llstaticallocas -> llloadenv -> lltop edges,
1707 // and builds the return block.
1708 pub fn finish_fn
<'blk
, 'tcx
>(fcx
: &'blk FunctionContext
<'blk
, 'tcx
>,
1709 last_bcx
: Block
<'blk
, 'tcx
>,
1710 retty
: ty
::FnOutput
<'tcx
>) {
1711 let _icx
= push_ctxt("finish_fn");
1713 let ret_cx
= match fcx
.llreturn
.get() {
1715 if !last_bcx
.terminated
.get() {
1716 Br(last_bcx
, llreturn
);
1718 raw_block(fcx
, false, llreturn
)
1723 // This shouldn't need to recompute the return type,
1724 // as new_fn_ctxt did it already.
1725 let substd_retty
= fcx
.monomorphize(&retty
);
1726 build_return_block(fcx
, ret_cx
, substd_retty
);
1728 debuginfo
::clear_source_location(fcx
);
1732 // Builds the return block for a function.
1733 pub fn build_return_block
<'blk
, 'tcx
>(fcx
: &FunctionContext
<'blk
, 'tcx
>,
1734 ret_cx
: Block
<'blk
, 'tcx
>,
1735 retty
: ty
::FnOutput
<'tcx
>) {
1736 if fcx
.llretslotptr
.get().is_none() ||
1737 (!fcx
.needs_ret_allocas
&& fcx
.caller_expects_out_pointer
) {
1738 return RetVoid(ret_cx
);
1741 let retslot
= if fcx
.needs_ret_allocas
{
1742 Load(ret_cx
, fcx
.llretslotptr
.get().unwrap())
1744 fcx
.llretslotptr
.get().unwrap()
1746 let retptr
= Value(retslot
);
1747 match retptr
.get_dominating_store(ret_cx
) {
1748 // If there's only a single store to the ret slot, we can directly return
1749 // the value that was stored and omit the store and the alloca
1751 let retval
= s
.get_operand(0).unwrap().get();
1752 s
.erase_from_parent();
1754 if retptr
.has_no_uses() {
1755 retptr
.erase_from_parent();
1758 let retval
= if retty
== ty
::FnConverging(fcx
.ccx
.tcx().types
.bool
) {
1759 Trunc(ret_cx
, retval
, Type
::i1(fcx
.ccx
))
1764 if fcx
.caller_expects_out_pointer
{
1765 if let ty
::FnConverging(retty
) = retty
{
1766 store_ty(ret_cx
, retval
, get_param(fcx
.llfn
, 0), retty
);
1773 // Otherwise, copy the return value to the ret slot
1774 None
=> match retty
{
1775 ty
::FnConverging(retty
) => {
1776 if fcx
.caller_expects_out_pointer
{
1777 memcpy_ty(ret_cx
, get_param(fcx
.llfn
, 0), retslot
, retty
);
1780 Ret(ret_cx
, load_ty(ret_cx
, retslot
, retty
))
1783 ty
::FnDiverging
=> {
1784 if fcx
.caller_expects_out_pointer
{
1787 Ret(ret_cx
, C_undef(Type
::nil(fcx
.ccx
)))
1794 #[derive(Clone, Copy, Eq, PartialEq)]
1795 pub enum IsUnboxedClosureFlag
{
1800 // trans_closure: Builds an LLVM function out of a source function.
1801 // If the function closes over its environment a closure will be
1803 pub fn trans_closure
<'a
, 'b
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
1807 param_substs
: &Substs
<'tcx
>,
1808 fn_ast_id
: ast
::NodeId
,
1809 _attributes
: &[ast
::Attribute
],
1810 output_type
: ty
::FnOutput
<'tcx
>,
1812 closure_env
: closure
::ClosureEnv
<'b
, 'tcx
>) {
1813 ccx
.stats().n_closures
.set(ccx
.stats().n_closures
.get() + 1);
1815 let _icx
= push_ctxt("trans_closure");
1816 set_uwtable(llfndecl
);
1818 debug
!("trans_closure(..., param_substs={})",
1819 param_substs
.repr(ccx
.tcx()));
1821 let arena
= TypedArena
::new();
1822 let fcx
= new_fn_ctxt(ccx
,
1825 closure_env
.kind
!= closure
::NotClosure
,
1830 let mut bcx
= init_function(&fcx
, false, output_type
);
1832 // cleanup scope for the incoming arguments
1833 let fn_cleanup_debug_loc
=
1834 debuginfo
::get_cleanup_debug_loc_for_ast_node(ccx
, fn_ast_id
, body
.span
, true);
1835 let arg_scope
= fcx
.push_custom_cleanup_scope_with_debug_loc(fn_cleanup_debug_loc
);
1837 let block_ty
= node_id_type(bcx
, body
.id
);
1839 // Set up arguments to the function.
1840 let monomorphized_arg_types
=
1842 .map(|arg
| node_id_type(bcx
, arg
.id
))
1843 .collect
::<Vec
<_
>>();
1844 let monomorphized_arg_types
= match closure_env
.kind
{
1845 closure
::NotClosure
| closure
::BoxedClosure(..) => {
1846 monomorphized_arg_types
1849 // Tuple up closure argument types for the "rust-call" ABI.
1850 closure
::UnboxedClosure(..) => {
1851 vec
![ty
::mk_tup(ccx
.tcx(), monomorphized_arg_types
)]
1854 for monomorphized_arg_type
in monomorphized_arg_types
.iter() {
1855 debug
!("trans_closure: monomorphized_arg_type: {}",
1856 ty_to_string(ccx
.tcx(), *monomorphized_arg_type
));
1858 debug
!("trans_closure: function lltype: {}",
1859 bcx
.fcx
.ccx
.tn().val_to_string(bcx
.fcx
.llfn
));
1861 let arg_datums
= if abi
!= RustCall
{
1862 create_datums_for_fn_args(&fcx
,
1863 &monomorphized_arg_types
[])
1865 create_datums_for_fn_args_under_call_abi(
1868 &monomorphized_arg_types
[])
1871 bcx
= match closure_env
.kind
{
1872 closure
::NotClosure
| closure
::BoxedClosure(..) => {
1873 copy_args_to_allocas(&fcx
,
1879 closure
::UnboxedClosure(..) => {
1880 copy_unboxed_closure_args_to_allocas(
1885 &monomorphized_arg_types
[])
1889 bcx
= closure_env
.load(bcx
, cleanup
::CustomScope(arg_scope
));
1891 // Up until here, IR instructions for this function have explicitly not been annotated with
1892 // source code location, so we don't step into call setup code. From here on, source location
1893 // emitting should be enabled.
1894 debuginfo
::start_emitting_source_locations(&fcx
);
1896 let dest
= match fcx
.llretslotptr
.get() {
1897 Some(_
) => expr
::SaveIn(fcx
.get_ret_slot(bcx
, ty
::FnConverging(block_ty
), "iret_slot")),
1899 assert
!(type_is_zero_size(bcx
.ccx(), block_ty
));
1904 // This call to trans_block is the place where we bridge between
1905 // translation calls that don't have a return value (trans_crate,
1906 // trans_mod, trans_item, et cetera) and those that do
1907 // (trans_block, trans_expr, et cetera).
1908 bcx
= controlflow
::trans_block(bcx
, body
, dest
);
1911 expr
::SaveIn(slot
) if fcx
.needs_ret_allocas
=> {
1912 Store(bcx
, slot
, fcx
.llretslotptr
.get().unwrap());
1917 match fcx
.llreturn
.get() {
1919 Br(bcx
, fcx
.return_exit_block());
1920 fcx
.pop_custom_cleanup_scope(arg_scope
);
1923 // Microoptimization writ large: avoid creating a separate
1924 // llreturn basic block
1925 bcx
= fcx
.pop_and_trans_custom_cleanup_scope(bcx
, arg_scope
);
1929 // Put return block after all other blocks.
1930 // This somewhat improves single-stepping experience in debugger.
1932 let llreturn
= fcx
.llreturn
.get();
1933 for &llreturn
in llreturn
.iter() {
1934 llvm
::LLVMMoveBasicBlockAfter(llreturn
, bcx
.llbb
);
1938 // Insert the mandatory first few basic blocks before lltop.
1939 finish_fn(&fcx
, bcx
, output_type
);
1942 // trans_fn: creates an LLVM function corresponding to a source language
1944 pub fn trans_fn
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
1948 param_substs
: &Substs
<'tcx
>,
1950 attrs
: &[ast
::Attribute
]) {
1951 let _s
= StatRecorder
::new(ccx
, ccx
.tcx().map
.path_to_string(id
).to_string());
1952 debug
!("trans_fn(param_substs={})", param_substs
.repr(ccx
.tcx()));
1953 let _icx
= push_ctxt("trans_fn");
1954 let fn_ty
= ty
::node_id_to_type(ccx
.tcx(), id
);
1955 let output_type
= ty
::erase_late_bound_regions(ccx
.tcx(), &ty
::ty_fn_ret(fn_ty
));
1956 let abi
= ty
::ty_fn_abi(fn_ty
);
1966 closure
::ClosureEnv
::new(&[], closure
::NotClosure
));
1969 pub fn trans_enum_variant
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
1970 _enum_id
: ast
::NodeId
,
1971 variant
: &ast
::Variant
,
1972 _args
: &[ast
::VariantArg
],
1974 param_substs
: &Substs
<'tcx
>,
1975 llfndecl
: ValueRef
) {
1976 let _icx
= push_ctxt("trans_enum_variant");
1978 trans_enum_variant_or_tuple_like_struct(
1986 pub fn trans_named_tuple_constructor
<'blk
, 'tcx
>(mut bcx
: Block
<'blk
, 'tcx
>,
1989 args
: callee
::CallArgs
,
1991 call_info
: Option
<NodeInfo
>)
1992 -> Result
<'blk
, 'tcx
> {
1994 let ccx
= bcx
.fcx
.ccx
;
1995 let tcx
= ccx
.tcx();
1997 let result_ty
= match ctor_ty
.sty
{
1998 ty
::ty_bare_fn(_
, ref bft
) => {
1999 ty
::erase_late_bound_regions(bcx
.tcx(), &bft
.sig
.output()).unwrap()
2001 _
=> ccx
.sess().bug(
2002 &format
!("trans_enum_variant_constructor: \
2003 unexpected ctor return type {}",
2004 ctor_ty
.repr(tcx
))[])
2007 // Get location to store the result. If the user does not care about
2008 // the result, just make a stack slot
2009 let llresult
= match dest
{
2010 expr
::SaveIn(d
) => d
,
2012 if !type_is_zero_size(ccx
, result_ty
) {
2013 alloc_ty(bcx
, result_ty
, "constructor_result")
2015 C_undef(type_of
::type_of(ccx
, result_ty
))
2020 if !type_is_zero_size(ccx
, result_ty
) {
2022 callee
::ArgExprs(exprs
) => {
2023 let fields
= exprs
.iter().map(|x
| &**x
).enumerate().collect
::<Vec
<_
>>();
2024 bcx
= expr
::trans_adt(bcx
,
2029 expr
::SaveIn(llresult
),
2032 _
=> ccx
.sess().bug("expected expr as arguments for variant/struct tuple constructor")
2036 // If the caller doesn't care about the result
2037 // drop the temporary we made
2038 let bcx
= match dest
{
2039 expr
::SaveIn(_
) => bcx
,
2041 glue
::drop_ty(bcx
, llresult
, result_ty
, call_info
)
2045 Result
::new(bcx
, llresult
)
2048 pub fn trans_tuple_struct
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
2049 _fields
: &[ast
::StructField
],
2050 ctor_id
: ast
::NodeId
,
2051 param_substs
: &Substs
<'tcx
>,
2052 llfndecl
: ValueRef
) {
2053 let _icx
= push_ctxt("trans_tuple_struct");
2055 trans_enum_variant_or_tuple_like_struct(
2063 fn trans_enum_variant_or_tuple_like_struct
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
2064 ctor_id
: ast
::NodeId
,
2066 param_substs
: &Substs
<'tcx
>,
2067 llfndecl
: ValueRef
) {
2068 let ctor_ty
= ty
::node_id_to_type(ccx
.tcx(), ctor_id
);
2069 let ctor_ty
= monomorphize
::apply_param_substs(ccx
.tcx(), param_substs
, &ctor_ty
);
2071 let result_ty
= match ctor_ty
.sty
{
2072 ty
::ty_bare_fn(_
, ref bft
) => {
2073 ty
::erase_late_bound_regions(ccx
.tcx(), &bft
.sig
.output())
2075 _
=> ccx
.sess().bug(
2076 &format
!("trans_enum_variant_or_tuple_like_struct: \
2077 unexpected ctor return type {}",
2078 ty_to_string(ccx
.tcx(), ctor_ty
))[])
2081 let arena
= TypedArena
::new();
2082 let fcx
= new_fn_ctxt(ccx
, llfndecl
, ctor_id
, false, result_ty
,
2083 param_substs
, None
, &arena
);
2084 let bcx
= init_function(&fcx
, false, result_ty
);
2086 assert
!(!fcx
.needs_ret_allocas
);
2089 ty
::erase_late_bound_regions(
2090 ccx
.tcx(), &ty
::ty_fn_args(ctor_ty
));
2092 let arg_datums
= create_datums_for_fn_args(&fcx
, &arg_tys
[]);
2094 if !type_is_zero_size(fcx
.ccx
, result_ty
.unwrap()) {
2095 let dest
= fcx
.get_ret_slot(bcx
, result_ty
, "eret_slot");
2096 let repr
= adt
::represent_type(ccx
, result_ty
.unwrap());
2097 for (i
, arg_datum
) in arg_datums
.into_iter().enumerate() {
2098 let lldestptr
= adt
::trans_field_ptr(bcx
,
2103 arg_datum
.store_to(bcx
, lldestptr
);
2105 adt
::trans_set_discr(bcx
, &*repr
, dest
, disr
);
2108 finish_fn(&fcx
, bcx
, result_ty
);
2111 fn enum_variant_size_lint(ccx
: &CrateContext
, enum_def
: &ast
::EnumDef
, sp
: Span
, id
: ast
::NodeId
) {
2112 let mut sizes
= Vec
::new(); // does no allocation if no pushes, thankfully
2114 let print_info
= ccx
.sess().print_enum_sizes();
2116 let levels
= ccx
.tcx().node_lint_levels
.borrow();
2117 let lint_id
= lint
::LintId
::of(lint
::builtin
::VARIANT_SIZE_DIFFERENCES
);
2118 let lvlsrc
= levels
.get(&(id
, lint_id
));
2119 let is_allow
= lvlsrc
.map_or(true, |&(lvl
, _
)| lvl
== lint
::Allow
);
2121 if is_allow
&& !print_info
{
2122 // we're not interested in anything here
2126 let ty
= ty
::node_id_to_type(ccx
.tcx(), id
);
2127 let avar
= adt
::represent_type(ccx
, ty
);
2129 adt
::General(_
, ref variants
, _
) => {
2130 for var
in variants
.iter() {
2132 for field
in var
.fields
.iter().skip(1) {
2133 // skip the discriminant
2134 size
+= llsize_of_real(ccx
, sizing_type_of(ccx
, *field
));
2139 _
=> { /* its size is either constant or unimportant */ }
2142 let (largest
, slargest
, largest_index
) = sizes
.iter().enumerate().fold((0, 0, 0),
2143 |(l
, s
, li
), (idx
, &size
)|
2146 } else if size
> s
{
2154 let llty
= type_of
::sizing_type_of(ccx
, ty
);
2156 let sess
= &ccx
.tcx().sess
;
2157 sess
.span_note(sp
, &*format
!("total size: {} bytes", llsize_of_real(ccx
, llty
)));
2159 adt
::General(..) => {
2160 for (i
, var
) in enum_def
.variants
.iter().enumerate() {
2161 ccx
.tcx().sess
.span_note(var
.span
,
2162 &*format
!("variant data: {} bytes", sizes
[i
]));
2169 // we only warn if the largest variant is at least thrice as large as
2170 // the second-largest.
2171 if !is_allow
&& largest
> slargest
* 3 && slargest
> 0 {
2172 // Use lint::raw_emit_lint rather than sess.add_lint because the lint-printing
2173 // pass for the latter already ran.
2174 lint
::raw_emit_lint(&ccx
.tcx().sess
, lint
::builtin
::VARIANT_SIZE_DIFFERENCES
,
2175 *lvlsrc
.unwrap(), Some(sp
),
2176 &format
!("enum variant is more than three times larger \
2177 ({} bytes) than the next largest (ignoring padding)",
2180 ccx
.sess().span_note(enum_def
.variants
[largest_index
].span
,
2181 "this variant is the largest");
2185 pub struct TransItemVisitor
<'a
, 'tcx
: 'a
> {
2186 pub ccx
: &'a CrateContext
<'a
, 'tcx
>,
2189 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for TransItemVisitor
<'a
, 'tcx
> {
2190 fn visit_item(&mut self, i
: &ast
::Item
) {
2191 trans_item(self.ccx
, i
);
2195 pub fn llvm_linkage_by_name(name
: &str) -> Option
<Linkage
> {
2196 // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
2197 // applicable to variable declarations and may not really make sense for
2198 // Rust code in the first place but whitelist them anyway and trust that
2199 // the user knows what s/he's doing. Who knows, unanticipated use cases
2200 // may pop up in the future.
2202 // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
2203 // and don't have to be, LLVM treats them as no-ops.
2205 "appending" => Some(llvm
::AppendingLinkage
),
2206 "available_externally" => Some(llvm
::AvailableExternallyLinkage
),
2207 "common" => Some(llvm
::CommonLinkage
),
2208 "extern_weak" => Some(llvm
::ExternalWeakLinkage
),
2209 "external" => Some(llvm
::ExternalLinkage
),
2210 "internal" => Some(llvm
::InternalLinkage
),
2211 "linkonce" => Some(llvm
::LinkOnceAnyLinkage
),
2212 "linkonce_odr" => Some(llvm
::LinkOnceODRLinkage
),
2213 "private" => Some(llvm
::PrivateLinkage
),
2214 "weak" => Some(llvm
::WeakAnyLinkage
),
2215 "weak_odr" => Some(llvm
::WeakODRLinkage
),
2221 /// Enum describing the origin of an LLVM `Value`, for linkage purposes.
2223 pub enum ValueOrigin
{
2224 /// The LLVM `Value` is in this context because the corresponding item was
2225 /// assigned to the current compilation unit.
2226 OriginalTranslation
,
2227 /// The `Value`'s corresponding item was assigned to some other compilation
2228 /// unit, but the `Value` was translated in this context anyway because the
2229 /// item is marked `#[inline]`.
2233 /// Set the appropriate linkage for an LLVM `ValueRef` (function or global).
2234 /// If the `llval` is the direct translation of a specific Rust item, `id`
2235 /// should be set to the `NodeId` of that item. (This mapping should be
2236 /// 1-to-1, so monomorphizations and drop/visit glue should have `id` set to
2237 /// `None`.) `llval_origin` indicates whether `llval` is the translation of an
2238 /// item assigned to `ccx`'s compilation unit or an inlined copy of an item
2239 /// assigned to a different compilation unit.
2240 pub fn update_linkage(ccx
: &CrateContext
,
2242 id
: Option
<ast
::NodeId
>,
2243 llval_origin
: ValueOrigin
) {
2244 match llval_origin
{
2246 // `llval` is a translation of an item defined in a separate
2247 // compilation unit. This only makes sense if there are at least
2248 // two compilation units.
2249 assert
!(ccx
.sess().opts
.cg
.codegen_units
> 1);
2250 // `llval` is a copy of something defined elsewhere, so use
2251 // `AvailableExternallyLinkage` to avoid duplicating code in the
2253 llvm
::SetLinkage(llval
, llvm
::AvailableExternallyLinkage
);
2256 OriginalTranslation
=> {}
,
2259 if let Some(id
) = id
{
2260 let item
= ccx
.tcx().map
.get(id
);
2261 if let ast_map
::NodeItem(i
) = item
{
2262 if let Some(name
) = attr
::first_attr_value_str_by_name(i
.attrs
.as_slice(), "linkage") {
2263 if let Some(linkage
) = llvm_linkage_by_name(name
.get()) {
2264 llvm
::SetLinkage(llval
, linkage
);
2266 ccx
.sess().span_fatal(i
.span
, "invalid linkage specified");
2274 Some(id
) if ccx
.reachable().contains(&id
) => {
2275 llvm
::SetLinkage(llval
, llvm
::ExternalLinkage
);
2278 // `id` does not refer to an item in `ccx.reachable`.
2279 if ccx
.sess().opts
.cg
.codegen_units
> 1 {
2280 llvm
::SetLinkage(llval
, llvm
::ExternalLinkage
);
2282 llvm
::SetLinkage(llval
, llvm
::InternalLinkage
);
2288 pub fn trans_item(ccx
: &CrateContext
, item
: &ast
::Item
) {
2289 let _icx
= push_ctxt("trans_item");
2291 let from_external
= ccx
.external_srcs().borrow().contains_key(&item
.id
);
2294 ast
::ItemFn(ref decl
, _fn_style
, abi
, ref generics
, ref body
) => {
2295 if !generics
.is_type_parameterized() {
2296 let trans_everywhere
= attr
::requests_inline(&item
.attrs
[]);
2297 // Ignore `trans_everywhere` for cross-crate inlined items
2298 // (`from_external`). `trans_item` will be called once for each
2299 // compilation unit that references the item, so it will still get
2300 // translated everywhere it's needed.
2301 for (ref ccx
, is_origin
) in ccx
.maybe_iter(!from_external
&& trans_everywhere
) {
2302 let llfn
= get_item_val(ccx
, item
.id
);
2304 foreign
::trans_rust_fn_with_foreign_abi(ccx
,
2309 &Substs
::trans_empty(),
2317 &Substs
::trans_empty(),
2324 if is_origin { OriginalTranslation }
else { InlinedCopy }
);
2328 // Be sure to travel more than just one layer deep to catch nested
2329 // items in blocks and such.
2330 let mut v
= TransItemVisitor{ ccx: ccx }
;
2331 v
.visit_block(&**body
);
2333 ast
::ItemImpl(_
, _
, ref generics
, _
, _
, ref impl_items
) => {
2334 meth
::trans_impl(ccx
,
2340 ast
::ItemMod(ref m
) => {
2341 trans_mod(&ccx
.rotate(), m
);
2343 ast
::ItemEnum(ref enum_definition
, ref gens
) => {
2344 if gens
.ty_params
.is_empty() {
2345 // sizes only make sense for non-generic types
2347 enum_variant_size_lint(ccx
, enum_definition
, item
.span
, item
.id
);
2350 ast
::ItemConst(_
, ref expr
) => {
2351 // Recurse on the expression to catch items in blocks
2352 let mut v
= TransItemVisitor{ ccx: ccx }
;
2353 v
.visit_expr(&**expr
);
2355 ast
::ItemStatic(_
, m
, ref expr
) => {
2356 // Recurse on the expression to catch items in blocks
2357 let mut v
= TransItemVisitor{ ccx: ccx }
;
2358 v
.visit_expr(&**expr
);
2360 consts
::trans_static(ccx
, m
, item
.id
);
2361 let g
= get_item_val(ccx
, item
.id
);
2362 update_linkage(ccx
, g
, Some(item
.id
), OriginalTranslation
);
2364 // Do static_assert checking. It can't really be done much earlier
2365 // because we need to get the value of the bool out of LLVM
2366 if attr
::contains_name(&item
.attrs
[], "static_assert") {
2367 if m
== ast
::MutMutable
{
2368 ccx
.sess().span_fatal(expr
.span
,
2369 "cannot have static_assert on a mutable \
2373 let v
= ccx
.static_values().borrow()[item
.id
].clone();
2375 if !(llvm
::LLVMConstIntGetZExtValue(v
) != 0) {
2376 ccx
.sess().span_fatal(expr
.span
, "static assertion failed");
2381 ast
::ItemForeignMod(ref foreign_mod
) => {
2382 foreign
::trans_foreign_mod(ccx
, foreign_mod
);
2384 ast
::ItemTrait(..) => {
2385 // Inside of this trait definition, we won't be actually translating any
2386 // functions, but the trait still needs to be walked. Otherwise default
2387 // methods with items will not get translated and will cause ICE's when
2388 // metadata time comes around.
2389 let mut v
= TransItemVisitor{ ccx: ccx }
;
2390 visit
::walk_item(&mut v
, item
);
2392 _
=> {/* fall through */ }
2396 // Translate a module. Doing this amounts to translating the items in the
2397 // module; there ends up being no artifact (aside from linkage names) of
2398 // separate modules in the compiled program. That's because modules exist
2399 // only as a convenience for humans working with the code, to organize names
2400 // and control visibility.
2401 pub fn trans_mod(ccx
: &CrateContext
, m
: &ast
::Mod
) {
2402 let _icx
= push_ctxt("trans_mod");
2403 for item
in m
.items
.iter() {
2404 trans_item(ccx
, &**item
);
2408 fn finish_register_fn(ccx
: &CrateContext
, sp
: Span
, sym
: String
, node_id
: ast
::NodeId
,
2410 ccx
.item_symbols().borrow_mut().insert(node_id
, sym
);
2412 // The stack exhaustion lang item shouldn't have a split stack because
2413 // otherwise it would continue to be exhausted (bad), and both it and the
2414 // eh_personality functions need to be externally linkable.
2415 let def
= ast_util
::local_def(node_id
);
2416 if ccx
.tcx().lang_items
.stack_exhausted() == Some(def
) {
2417 unset_split_stack(llfn
);
2418 llvm
::SetLinkage(llfn
, llvm
::ExternalLinkage
);
2420 if ccx
.tcx().lang_items
.eh_personality() == Some(def
) {
2421 llvm
::SetLinkage(llfn
, llvm
::ExternalLinkage
);
2425 if is_entry_fn(ccx
.sess(), node_id
) {
2426 create_entry_wrapper(ccx
, sp
, llfn
);
2430 fn register_fn
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>,
2433 node_id
: ast
::NodeId
,
2434 node_type
: Ty
<'tcx
>)
2436 match node_type
.sty
{
2437 ty
::ty_bare_fn(_
, ref f
) => {
2438 assert
!(f
.abi
== Rust
|| f
.abi
== RustCall
);
2440 _
=> panic
!("expected bare rust fn")
2443 let llfn
= decl_rust_fn(ccx
, node_type
, &sym
[]);
2444 finish_register_fn(ccx
, sp
, sym
, node_id
, llfn
);
2448 pub fn get_fn_llvm_attributes
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>, fn_ty
: Ty
<'tcx
>)
2449 -> llvm
::AttrBuilder
2451 use middle
::ty
::{BrAnon, ReLateBound}
;
2454 let (fn_sig
, abi
, has_env
) = match fn_ty
.sty
{
2455 ty
::ty_bare_fn(_
, ref f
) => (&f
.sig
, f
.abi
, false),
2456 ty
::ty_unboxed_closure(closure_did
, _
, substs
) => {
2457 let typer
= common
::NormalizingUnboxedClosureTyper
::new(ccx
.tcx());
2458 function_type
= typer
.unboxed_closure_type(closure_did
, substs
);
2459 (&function_type
.sig
, RustCall
, true)
2461 _
=> ccx
.sess().bug("expected closure or function.")
2464 let fn_sig
= ty
::erase_late_bound_regions(ccx
.tcx(), fn_sig
);
2466 // Since index 0 is the return value of the llvm func, we start
2467 // at either 1 or 2 depending on whether there's an env slot or not
2468 let mut first_arg_offset
= if has_env { 2 }
else { 1 }
;
2469 let mut attrs
= llvm
::AttrBuilder
::new();
2470 let ret_ty
= fn_sig
.output
;
2472 // These have an odd calling convention, so we need to manually
2473 // unpack the input ty's
2474 let input_tys
= match fn_ty
.sty
{
2475 ty
::ty_unboxed_closure(_
, _
, _
) => {
2476 assert
!(abi
== RustCall
);
2478 match fn_sig
.inputs
[0].sty
{
2479 ty
::ty_tup(ref inputs
) => inputs
.clone(),
2480 _
=> ccx
.sess().bug("expected tuple'd inputs")
2483 ty
::ty_bare_fn(..) if abi
== RustCall
=> {
2484 let mut inputs
= vec
![fn_sig
.inputs
[0]];
2486 match fn_sig
.inputs
[1].sty
{
2487 ty
::ty_tup(ref t_in
) => {
2488 inputs
.push_all(&t_in
[]);
2491 _
=> ccx
.sess().bug("expected tuple'd inputs")
2494 _
=> fn_sig
.inputs
.clone()
2497 if let ty
::FnConverging(ret_ty
) = ret_ty
{
2498 // A function pointer is called without the declaration
2499 // available, so we have to apply any attributes with ABI
2500 // implications directly to the call instruction. Right now,
2501 // the only attribute we need to worry about is `sret`.
2502 if type_of
::return_uses_outptr(ccx
, ret_ty
) {
2503 let llret_sz
= llsize_of_real(ccx
, type_of
::type_of(ccx
, ret_ty
));
2505 // The outptr can be noalias and nocapture because it's entirely
2506 // invisible to the program. We also know it's nonnull as well
2507 // as how many bytes we can dereference
2508 attrs
.arg(1, llvm
::StructRetAttribute
)
2509 .arg(1, llvm
::NoAliasAttribute
)
2510 .arg(1, llvm
::NoCaptureAttribute
)
2511 .arg(1, llvm
::DereferenceableAttribute(llret_sz
));
2513 // Add one more since there's an outptr
2514 first_arg_offset
+= 1;
2516 // The `noalias` attribute on the return value is useful to a
2517 // function ptr caller.
2519 // `~` pointer return values never alias because ownership
2521 ty
::ty_uniq(it
) if !common
::type_is_sized(ccx
.tcx(), it
) => {}
2523 attrs
.ret(llvm
::NoAliasAttribute
);
2528 // We can also mark the return value as `dereferenceable` in certain cases
2530 // These are not really pointers but pairs, (pointer, len)
2532 ty
::ty_rptr(_
, ty
::mt { ty: it, .. }
) if !common
::type_is_sized(ccx
.tcx(), it
) => {}
2533 ty
::ty_uniq(inner
) | ty
::ty_rptr(_
, ty
::mt { ty: inner, .. }
) => {
2534 let llret_sz
= llsize_of_real(ccx
, type_of
::type_of(ccx
, inner
));
2535 attrs
.ret(llvm
::DereferenceableAttribute(llret_sz
));
2540 if let ty
::ty_bool
= ret_ty
.sty
{
2541 attrs
.ret(llvm
::ZExtAttribute
);
2546 for (idx
, &t
) in input_tys
.iter().enumerate().map(|(i
, v
)| (i
+ first_arg_offset
, v
)) {
2548 // this needs to be first to prevent fat pointers from falling through
2549 _
if !type_is_immediate(ccx
, t
) => {
2550 let llarg_sz
= llsize_of_real(ccx
, type_of
::type_of(ccx
, t
));
2552 // For non-immediate arguments the callee gets its own copy of
2553 // the value on the stack, so there are no aliases. It's also
2554 // program-invisible so can't possibly capture
2555 attrs
.arg(idx
, llvm
::NoAliasAttribute
)
2556 .arg(idx
, llvm
::NoCaptureAttribute
)
2557 .arg(idx
, llvm
::DereferenceableAttribute(llarg_sz
));
2561 attrs
.arg(idx
, llvm
::ZExtAttribute
);
2564 // `~` pointer parameters never alias because ownership is transferred
2565 ty
::ty_uniq(inner
) => {
2566 let llsz
= llsize_of_real(ccx
, type_of
::type_of(ccx
, inner
));
2568 attrs
.arg(idx
, llvm
::NoAliasAttribute
)
2569 .arg(idx
, llvm
::DereferenceableAttribute(llsz
));
2572 // `&mut` pointer parameters never alias other parameters, or mutable global data
2574 // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
2575 // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on
2576 // memory dependencies rather than pointer equality
2577 ty
::ty_rptr(b
, mt
) if mt
.mutbl
== ast
::MutMutable
||
2578 !ty
::type_contents(ccx
.tcx(), mt
.ty
).interior_unsafe() => {
2580 let llsz
= llsize_of_real(ccx
, type_of
::type_of(ccx
, mt
.ty
));
2581 attrs
.arg(idx
, llvm
::NoAliasAttribute
)
2582 .arg(idx
, llvm
::DereferenceableAttribute(llsz
));
2584 if mt
.mutbl
== ast
::MutImmutable
{
2585 attrs
.arg(idx
, llvm
::ReadOnlyAttribute
);
2588 if let ReLateBound(_
, BrAnon(_
)) = *b
{
2589 attrs
.arg(idx
, llvm
::NoCaptureAttribute
);
2593 // When a reference in an argument has no named lifetime, it's impossible for that
2594 // reference to escape this function (returned or stored beyond the call by a closure).
2595 ty
::ty_rptr(&ReLateBound(_
, BrAnon(_
)), mt
) => {
2596 let llsz
= llsize_of_real(ccx
, type_of
::type_of(ccx
, mt
.ty
));
2597 attrs
.arg(idx
, llvm
::NoCaptureAttribute
)
2598 .arg(idx
, llvm
::DereferenceableAttribute(llsz
));
2601 // & pointer parameters are also never null and we know exactly how
2602 // many bytes we can dereference
2603 ty
::ty_rptr(_
, mt
) => {
2604 let llsz
= llsize_of_real(ccx
, type_of
::type_of(ccx
, mt
.ty
));
2605 attrs
.arg(idx
, llvm
::DereferenceableAttribute(llsz
));
2614 // only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
2615 pub fn register_fn_llvmty(ccx
: &CrateContext
,
2618 node_id
: ast
::NodeId
,
2620 llfty
: Type
) -> ValueRef
{
2621 debug
!("register_fn_llvmty id={} sym={}", node_id
, sym
);
2623 let llfn
= decl_fn(ccx
,
2627 ty
::FnConverging(ty
::mk_nil(ccx
.tcx())));
2628 finish_register_fn(ccx
, sp
, sym
, node_id
, llfn
);
2632 pub fn is_entry_fn(sess
: &Session
, node_id
: ast
::NodeId
) -> bool
{
2633 match *sess
.entry_fn
.borrow() {
2634 Some((entry_id
, _
)) => node_id
== entry_id
,
2639 // Create a _rust_main(args: ~[str]) function which will be called from the
2640 // runtime rust_start function
2641 pub fn create_entry_wrapper(ccx
: &CrateContext
,
2643 main_llfn
: ValueRef
) {
2644 let et
= ccx
.sess().entry_type
.get().unwrap();
2646 config
::EntryMain
=> {
2647 create_entry_fn(ccx
, main_llfn
, true);
2649 config
::EntryStart
=> create_entry_fn(ccx
, main_llfn
, false),
2650 config
::EntryNone
=> {}
// Do nothing.
2653 fn create_entry_fn(ccx
: &CrateContext
,
2654 rust_main
: ValueRef
,
2655 use_start_lang_item
: bool
) {
2656 let llfty
= Type
::func(&[ccx
.int_type(), Type
::i8p(ccx
).ptr_to()],
2659 let llfn
= decl_cdecl_fn(ccx
, "main", llfty
, ty
::mk_nil(ccx
.tcx()));
2661 // FIXME: #16581: Marking a symbol in the executable with `dllexport`
2662 // linkage forces MinGW's linker to output a `.reloc` section for ASLR
2663 if ccx
.sess().target
.target
.options
.is_like_windows
{
2664 unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) }
2668 llvm
::LLVMAppendBasicBlockInContext(ccx
.llcx(), llfn
,
2669 "top\0".as_ptr() as *const _
)
2671 let bld
= ccx
.raw_builder();
2673 llvm
::LLVMPositionBuilderAtEnd(bld
, llbb
);
2675 debuginfo
::insert_reference_to_gdb_debug_scripts_section_global(ccx
);
2677 let (start_fn
, args
) = if use_start_lang_item
{
2678 let start_def_id
= match ccx
.tcx().lang_items
.require(StartFnLangItem
) {
2680 Err(s
) => { ccx.sess().fatal(&s[]); }
2682 let start_fn
= if start_def_id
.krate
== ast
::LOCAL_CRATE
{
2683 get_item_val(ccx
, start_def_id
.node
)
2685 let start_fn_type
= csearch
::get_type(ccx
.tcx(),
2687 trans_external_path(ccx
, start_def_id
, start_fn_type
)
2691 let opaque_rust_main
= llvm
::LLVMBuildPointerCast(bld
,
2692 rust_main
, Type
::i8p(ccx
).to_ref(),
2693 "rust_main\0".as_ptr() as *const _
);
2703 debug
!("using user-defined start fn");
2705 get_param(llfn
, 0 as c_uint
),
2706 get_param(llfn
, 1 as c_uint
)
2712 let result
= llvm
::LLVMBuildCall(bld
,
2715 args
.len() as c_uint
,
2718 llvm
::LLVMBuildRet(bld
, result
);
2723 fn exported_name
<'a
, 'tcx
>(ccx
: &CrateContext
<'a
, 'tcx
>, id
: ast
::NodeId
,
2724 ty
: Ty
<'tcx
>, attrs
: &[ast
::Attribute
]) -> String
{
2725 match ccx
.external_srcs().borrow().get(&id
) {
2727 let sym
= csearch
::get_symbol(&ccx
.sess().cstore
, did
);
2728 debug
!("found item {} in other crate...", sym
);
2734 match attr
::first_attr_value_str_by_name(attrs
, "export_name") {
2735 // Use provided name
2736 Some(name
) => name
.get().to_string(),
2738 _
=> ccx
.tcx().map
.with_path(id
, |path
| {
2739 if attr
::contains_name(attrs
, "no_mangle") {
2741 path
.last().unwrap().to_string()
2743 match weak_lang_items
::link_name(attrs
) {
2744 Some(name
) => name
.get().to_string(),
2746 // Usual name mangling
2747 mangle_exported_name(ccx
, path
, ty
, id
)
2755 fn contains_null(s
: &str) -> bool
{
2756 s
.bytes().any(|b
| b
== 0)
2759 pub fn get_item_val(ccx
: &CrateContext
, id
: ast
::NodeId
) -> ValueRef
{
2760 debug
!("get_item_val(id=`{}`)", id
);
2762 match ccx
.item_vals().borrow().get(&id
).cloned() {
2763 Some(v
) => return v
,
2767 let item
= ccx
.tcx().map
.get(id
);
2768 debug
!("get_item_val: id={} item={:?}", id
, item
);
2769 let val
= match item
{
2770 ast_map
::NodeItem(i
) => {
2771 let ty
= ty
::node_id_to_type(ccx
.tcx(), i
.id
);
2772 let sym
= |&:| exported_name(ccx
, id
, ty
, &i
.attrs
[]);
2774 let v
= match i
.node
{
2775 ast
::ItemStatic(_
, _
, ref expr
) => {
2776 // If this static came from an external crate, then
2777 // we need to get the symbol from csearch instead of
2778 // using the current crate's name/version
2779 // information in the hash of the symbol
2781 debug
!("making {}", sym
);
2783 // We need the translated value here, because for enums the
2784 // LLVM type is not fully determined by the Rust type.
2785 let (v
, ty
) = consts
::const_expr(ccx
, &**expr
);
2786 ccx
.static_values().borrow_mut().insert(id
, v
);
2788 // boolean SSA values are i1, but they have to be stored in i8 slots,
2789 // otherwise some LLVM optimization passes don't work as expected
2790 let llty
= if ty
::type_is_bool(ty
) {
2791 llvm
::LLVMInt8TypeInContext(ccx
.llcx())
2795 if contains_null(&sym
[]) {
2797 &format
!("Illegal null byte in export_name \
2798 value: `{}`", sym
)[]);
2800 let buf
= CString
::from_slice(sym
.as_bytes());
2801 let g
= llvm
::LLVMAddGlobal(ccx
.llmod(), llty
,
2804 if attr
::contains_name(&i
.attrs
[],
2806 llvm
::set_thread_local(g
, true);
2808 ccx
.item_symbols().borrow_mut().insert(i
.id
, sym
);
2813 ast
::ItemConst(_
, ref expr
) => {
2814 let (v
, _
) = consts
::const_expr(ccx
, &**expr
);
2815 ccx
.const_values().borrow_mut().insert(id
, v
);
2819 ast
::ItemFn(_
, _
, abi
, _
, _
) => {
2821 let llfn
= if abi
== Rust
{
2822 register_fn(ccx
, i
.span
, sym
, i
.id
, ty
)
2824 foreign
::register_rust_fn_with_foreign_abi(ccx
,
2829 set_llvm_fn_attrs(ccx
, &i
.attrs
[], llfn
);
2833 _
=> panic
!("get_item_val: weird result in table")
2836 match attr
::first_attr_value_str_by_name(&i
.attrs
[],
2839 if contains_null(sect
.get()) {
2840 ccx
.sess().fatal(&format
!("Illegal null byte in link_section value: `{}`",
2844 let buf
= CString
::from_slice(sect
.get().as_bytes());
2845 llvm
::LLVMSetSection(v
, buf
.as_ptr());
2854 ast_map
::NodeTraitItem(trait_method
) => {
2855 debug
!("get_item_val(): processing a NodeTraitItem");
2856 match *trait_method
{
2857 ast
::RequiredMethod(_
) | ast
::TypeTraitItem(_
) => {
2858 ccx
.sess().bug("unexpected variant: required trait \
2859 method in get_item_val()");
2861 ast
::ProvidedMethod(ref m
) => {
2862 register_method(ccx
, id
, &**m
)
2867 ast_map
::NodeImplItem(ii
) => {
2869 ast
::MethodImplItem(ref m
) => register_method(ccx
, id
, &**m
),
2870 ast
::TypeImplItem(ref typedef
) => {
2871 ccx
.sess().span_bug(typedef
.span
,
2872 "unexpected variant: required impl \
2873 method in get_item_val()")
2878 ast_map
::NodeForeignItem(ni
) => {
2880 ast
::ForeignItemFn(..) => {
2881 let abi
= ccx
.tcx().map
.get_foreign_abi(id
);
2882 let ty
= ty
::node_id_to_type(ccx
.tcx(), ni
.id
);
2883 let name
= foreign
::link_name(&*ni
);
2884 foreign
::register_foreign_item_fn(ccx
, abi
, ty
, &name
.get()[])
2886 ast
::ForeignItemStatic(..) => {
2887 foreign
::register_static(ccx
, &*ni
)
2892 ast_map
::NodeVariant(ref v
) => {
2894 let args
= match v
.node
.kind
{
2895 ast
::TupleVariantKind(ref args
) => args
,
2896 ast
::StructVariantKind(_
) => {
2897 panic
!("struct variant kind unexpected in get_item_val")
2900 assert
!(args
.len() != 0u);
2901 let ty
= ty
::node_id_to_type(ccx
.tcx(), id
);
2902 let parent
= ccx
.tcx().map
.get_parent(id
);
2903 let enm
= ccx
.tcx().map
.expect_item(parent
);
2904 let sym
= exported_name(ccx
,
2909 llfn
= match enm
.node
{
2910 ast
::ItemEnum(_
, _
) => {
2911 register_fn(ccx
, (*v
).span
, sym
, id
, ty
)
2913 _
=> panic
!("NodeVariant, shouldn't happen")
2915 set_inline_hint(llfn
);
2919 ast_map
::NodeStructCtor(struct_def
) => {
2920 // Only register the constructor if this is a tuple-like struct.
2921 let ctor_id
= match struct_def
.ctor_id
{
2923 ccx
.sess().bug("attempt to register a constructor of \
2924 a non-tuple-like struct")
2926 Some(ctor_id
) => ctor_id
,
2928 let parent
= ccx
.tcx().map
.get_parent(id
);
2929 let struct_item
= ccx
.tcx().map
.expect_item(parent
);
2930 let ty
= ty
::node_id_to_type(ccx
.tcx(), ctor_id
);
2931 let sym
= exported_name(ccx
,
2934 &struct_item
.attrs
[]);
2935 let llfn
= register_fn(ccx
, struct_item
.span
,
2937 set_inline_hint(llfn
);
2942 ccx
.sess().bug(&format
!("get_item_val(): unexpected variant: {:?}",
2947 // All LLVM globals and functions are initially created as external-linkage
2948 // declarations. If `trans_item`/`trans_fn` later turns the declaration
2949 // into a definition, it adjusts the linkage then (using `update_linkage`).
2951 // The exception is foreign items, which have their linkage set inside the
2952 // call to `foreign::register_*` above. We don't touch the linkage after
2953 // that (`foreign::trans_foreign_mod` doesn't adjust the linkage like the
2954 // other item translation functions do).
2956 ccx
.item_vals().borrow_mut().insert(id
, val
);
2960 fn register_method(ccx
: &CrateContext
, id
: ast
::NodeId
,
2961 m
: &ast
::Method
) -> ValueRef
{
2962 let mty
= ty
::node_id_to_type(ccx
.tcx(), id
);
2964 let sym
= exported_name(ccx
, id
, mty
, &m
.attrs
[]);
2966 let llfn
= register_fn(ccx
, m
.span
, sym
, id
, mty
);
2967 set_llvm_fn_attrs(ccx
, &m
.attrs
[], llfn
);
2971 pub fn crate_ctxt_to_encode_parms
<'a
, 'tcx
>(cx
: &'a SharedCrateContext
<'tcx
>,
2972 ie
: encoder
::EncodeInlinedItem
<'a
>)
2973 -> encoder
::EncodeParams
<'a
, 'tcx
> {
2974 encoder
::EncodeParams
{
2975 diag
: cx
.sess().diagnostic(),
2977 reexports
: cx
.export_map(),
2978 item_symbols
: cx
.item_symbols(),
2979 link_meta
: cx
.link_meta(),
2980 cstore
: &cx
.sess().cstore
,
2981 encode_inlined_item
: ie
,
2982 reachable
: cx
.reachable(),
2986 pub fn write_metadata(cx
: &SharedCrateContext
, krate
: &ast
::Crate
) -> Vec
<u8> {
2989 let any_library
= cx
.sess().crate_types
.borrow().iter().any(|ty
| {
2990 *ty
!= config
::CrateTypeExecutable
2996 let encode_inlined_item
: encoder
::EncodeInlinedItem
=
2997 box |ecx
, rbml_w
, ii
| astencode
::encode_inlined_item(ecx
, rbml_w
, ii
);
2999 let encode_parms
= crate_ctxt_to_encode_parms(cx
, encode_inlined_item
);
3000 let metadata
= encoder
::encode_metadata(encode_parms
, krate
);
3001 let mut compressed
= encoder
::metadata_encoding_version
.to_vec();
3002 compressed
.push_all(match flate
::deflate_bytes(metadata
.as_slice()) {
3003 Some(compressed
) => compressed
,
3004 None
=> cx
.sess().fatal("failed to compress metadata"),
3006 let llmeta
= C_bytes_in_context(cx
.metadata_llcx(), &compressed
[]);
3007 let llconst
= C_struct_in_context(cx
.metadata_llcx(), &[llmeta
], false);
3008 let name
= format
!("rust_metadata_{}_{}",
3009 cx
.link_meta().crate_name
,
3010 cx
.link_meta().crate_hash
);
3011 let buf
= CString
::from_vec(name
.into_bytes());
3012 let llglobal
= unsafe {
3013 llvm
::LLVMAddGlobal(cx
.metadata_llmod(), val_ty(llconst
).to_ref(),
3017 llvm
::LLVMSetInitializer(llglobal
, llconst
);
3018 let name
= loader
::meta_section_name(cx
.sess().target
.target
.options
.is_like_osx
);
3019 let name
= CString
::from_slice(name
.as_bytes());
3020 llvm
::LLVMSetSection(llglobal
, name
.as_ptr())
3025 /// Find any symbols that are defined in one compilation unit, but not declared
3026 /// in any other compilation unit. Give these symbols internal linkage.
3027 fn internalize_symbols(cx
: &SharedCrateContext
, reachable
: &HashSet
<String
>) {
3029 let mut declared
= HashSet
::new();
3031 let iter_globals
= |&: llmod
| {
3033 cur
: llvm
::LLVMGetFirstGlobal(llmod
),
3034 step
: llvm
::LLVMGetNextGlobal
,
3038 let iter_functions
= |&: llmod
| {
3040 cur
: llvm
::LLVMGetFirstFunction(llmod
),
3041 step
: llvm
::LLVMGetNextFunction
,
3045 // Collect all external declarations in all compilation units.
3046 for ccx
in cx
.iter() {
3047 for val
in iter_globals(ccx
.llmod()).chain(iter_functions(ccx
.llmod())) {
3048 let linkage
= llvm
::LLVMGetLinkage(val
);
3049 // We only care about external declarations (not definitions)
3050 // and available_externally definitions.
3051 if !(linkage
== llvm
::ExternalLinkage
as c_uint
&&
3052 llvm
::LLVMIsDeclaration(val
) != 0) &&
3053 !(linkage
== llvm
::AvailableExternallyLinkage
as c_uint
) {
3057 let name
= ffi
::c_str_to_bytes(&llvm
::LLVMGetValueName(val
))
3059 declared
.insert(name
);
3063 // Examine each external definition. If the definition is not used in
3064 // any other compilation unit, and is not reachable from other crates,
3065 // then give it internal linkage.
3066 for ccx
in cx
.iter() {
3067 for val
in iter_globals(ccx
.llmod()).chain(iter_functions(ccx
.llmod())) {
3068 // We only care about external definitions.
3069 if !(llvm
::LLVMGetLinkage(val
) == llvm
::ExternalLinkage
as c_uint
&&
3070 llvm
::LLVMIsDeclaration(val
) == 0) {
3074 let name
= ffi
::c_str_to_bytes(&llvm
::LLVMGetValueName(val
))
3076 if !declared
.contains(&name
) &&
3077 !reachable
.contains(str::from_utf8(name
.as_slice()).unwrap()) {
3078 llvm
::SetLinkage(val
, llvm
::InternalLinkage
);
3087 step
: unsafe extern "C" fn(ValueRef
) -> ValueRef
,
3090 impl Iterator
for ValueIter
{
3091 type Item
= ValueRef
;
3093 fn next(&mut self) -> Option
<ValueRef
> {
3097 let step
: unsafe extern "C" fn(ValueRef
) -> ValueRef
=
3098 mem
::transmute_copy(&self.step
);
3109 pub fn trans_crate
<'tcx
>(analysis
: ty
::CrateAnalysis
<'tcx
>)
3110 -> (ty
::ctxt
<'tcx
>, CrateTranslation
) {
3111 let ty
::CrateAnalysis { ty_cx: tcx, export_map, reachable, name, .. }
= analysis
;
3112 let krate
= tcx
.map
.krate();
3114 // Before we touch LLVM, make sure that multithreading is enabled.
3116 use std
::sync
::{Once, ONCE_INIT}
;
3117 static INIT
: Once
= ONCE_INIT
;
3118 static mut POISONED
: bool
= false;
3120 if llvm
::LLVMStartMultithreaded() != 1 {
3121 // use an extra bool to make sure that all future usage of LLVM
3122 // cannot proceed despite the Once not running more than once.
3128 tcx
.sess
.bug("couldn't enable multi-threaded LLVM");
3132 let link_meta
= link
::build_link_meta(&tcx
.sess
, krate
, name
);
3134 let codegen_units
= tcx
.sess
.opts
.cg
.codegen_units
;
3135 let shared_ccx
= SharedCrateContext
::new(&link_meta
.crate_name
[],
3144 let ccx
= shared_ccx
.get_ccx(0);
3146 // First, verify intrinsics.
3147 intrinsic
::check_intrinsics(&ccx
);
3149 // Next, translate the module.
3151 let _icx
= push_ctxt("text");
3152 trans_mod(&ccx
, &krate
.module
);
3156 for ccx
in shared_ccx
.iter() {
3157 glue
::emit_tydescs(&ccx
);
3158 if ccx
.sess().opts
.debuginfo
!= NoDebugInfo
{
3159 debuginfo
::finalize(&ccx
);
3163 // Translate the metadata.
3164 let metadata
= write_metadata(&shared_ccx
, krate
);
3166 if shared_ccx
.sess().trans_stats() {
3167 let stats
= shared_ccx
.stats();
3168 println
!("--- trans stats ---");
3169 println
!("n_static_tydescs: {}", stats
.n_static_tydescs
.get());
3170 println
!("n_glues_created: {}", stats
.n_glues_created
.get());
3171 println
!("n_null_glues: {}", stats
.n_null_glues
.get());
3172 println
!("n_real_glues: {}", stats
.n_real_glues
.get());
3174 println
!("n_fns: {}", stats
.n_fns
.get());
3175 println
!("n_monos: {}", stats
.n_monos
.get());
3176 println
!("n_inlines: {}", stats
.n_inlines
.get());
3177 println
!("n_closures: {}", stats
.n_closures
.get());
3178 println
!("fn stats:");
3179 stats
.fn_stats
.borrow_mut().sort_by(|&(_
, insns_a
), &(_
, insns_b
)| {
3180 insns_b
.cmp(&insns_a
)
3182 for tuple
in stats
.fn_stats
.borrow().iter() {
3184 (ref name
, insns
) => {
3185 println
!("{} insns, {}", insns
, *name
);
3190 if shared_ccx
.sess().count_llvm_insns() {
3191 for (k
, v
) in shared_ccx
.stats().llvm_insns
.borrow().iter() {
3192 println
!("{:7} {}", *v
, *k
);
3196 let modules
= shared_ccx
.iter()
3197 .map(|ccx
| ModuleTranslation { llcx: ccx.llcx(), llmod: ccx.llmod() }
)
3200 let mut reachable
: Vec
<String
> = shared_ccx
.reachable().iter().filter_map(|id
| {
3201 shared_ccx
.item_symbols().borrow().get(id
).map(|s
| s
.to_string())
3204 // For the purposes of LTO, we add to the reachable set all of the upstream
3205 // reachable extern fns. These functions are all part of the public ABI of
3206 // the final product, so LTO needs to preserve them.
3207 shared_ccx
.sess().cstore
.iter_crate_data(|cnum
, _
| {
3208 let syms
= csearch
::get_reachable_extern_fns(&shared_ccx
.sess().cstore
, cnum
);
3209 reachable
.extend(syms
.into_iter().map(|did
| {
3210 csearch
::get_symbol(&shared_ccx
.sess().cstore
, did
)
3214 // Make sure that some other crucial symbols are not eliminated from the
3215 // module. This includes the main function, the crate map (used for debug
3216 // log settings and I/O), and finally the curious rust_stack_exhausted
3217 // symbol. This symbol is required for use by the libmorestack library that
3218 // we link in, so we must ensure that this symbol is not internalized (if
3219 // defined in the crate).
3220 reachable
.push("main".to_string());
3221 reachable
.push("rust_stack_exhausted".to_string());
3223 // referenced from .eh_frame section on some platforms
3224 reachable
.push("rust_eh_personality".to_string());
3225 // referenced from rt/rust_try.ll
3226 reachable
.push("rust_eh_personality_catch".to_string());
3228 if codegen_units
> 1 {
3229 internalize_symbols(&shared_ccx
, &reachable
.iter().map(|x
| x
.clone()).collect());
3232 let metadata_module
= ModuleTranslation
{
3233 llcx
: shared_ccx
.metadata_llcx(),
3234 llmod
: shared_ccx
.metadata_llmod(),
3236 let formats
= shared_ccx
.tcx().dependency_formats
.borrow().clone();
3237 let no_builtins
= attr
::contains_name(&krate
.attrs
[], "no_builtins");
3239 let translation
= CrateTranslation
{
3241 metadata_module
: metadata_module
,
3244 reachable
: reachable
,
3245 crate_formats
: formats
,
3246 no_builtins
: no_builtins
,
3249 (shared_ccx
.take_tcx(), translation
)