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.
12 use llvm::{self, ValueRef};
13 use rustc_mir::repr as mir;
14 use rustc_mir::tcx::LvalueTy;
17 use trans::common::{self, Block};
18 use trans::debuginfo::DebugLoc;
22 use self::lvalue::LvalueRef;
23 use self::operand::OperandRef;
25 // FIXME DebugLoc is always None right now
27 /// Master context for translating MIR.
28 pub struct MirContext<'bcx, 'tcx:'bcx> {
29 mir: &'bcx mir::Mir<'tcx>,
31 /// When unwinding is initiated, we have to store this personality
32 /// value somewhere so that we can load it and re-use it in the
33 /// resume instruction. The personality is (afaik) some kind of
34 /// value used for C++ unwinding, which must filter by type: we
35 /// don't really care about it very much. Anyway, this value
36 /// contains an alloca into which the personality is stored and
37 /// then later loaded when generating the DIVERGE_BLOCK.
38 llpersonalityslot: Option<ValueRef>,
40 /// A `Block` for each MIR `BasicBlock`
41 blocks: Vec<Block<'bcx, 'tcx>>,
43 /// An LLVM alloca for each MIR `VarDecl`
44 vars: Vec<LvalueRef<'tcx>>,
46 /// The location where each MIR `TempDecl` is stored. This is
47 /// usually an `LvalueRef` representing an alloca, but not always:
48 /// sometimes we can skip the alloca and just store the value
49 /// directly using an `OperandRef`, which makes for tighter LLVM
50 /// IR. The conditions for using an `OperandRef` are as follows:
52 /// - the type of the temporary must be judged "immediate" by `type_is_immediate`
53 /// - the operand must never be referenced indirectly
54 /// - we should not take its address using the `&` operator
55 /// - nor should it appear in an lvalue path like `tmp.a`
56 /// - the operand must be defined by an rvalue that can generate immediate
59 /// Avoiding allocs can also be important for certain intrinsics,
61 temps: Vec<TempRef<'tcx>>,
63 /// The arguments to the function; as args are lvalues, these are
64 /// always indirect, though we try to avoid creating an alloca
65 /// when we can (and just reuse the pointer the caller provided).
66 args: Vec<LvalueRef<'tcx>>,
70 Lvalue(LvalueRef<'tcx>),
71 Operand(Option<OperandRef<'tcx>>),
74 ///////////////////////////////////////////////////////////////////////////
76 pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
80 let mir_blocks = bcx.mir().all_basic_blocks();
82 // Analyze the temps to determine which must be lvalues
84 let lvalue_temps = analyze::lvalue_temps(bcx, mir);
86 // Allocate variable and temp allocas
87 let vars = mir.var_decls.iter()
88 .map(|decl| (bcx.monomorphize(&decl.ty), decl.name))
89 .map(|(mty, name)| LvalueRef::alloca(bcx, mty, &name.as_str()))
91 let temps = mir.temp_decls.iter()
92 .map(|decl| bcx.monomorphize(&decl.ty))
94 .map(|(i, mty)| if lvalue_temps.contains(&i) {
95 TempRef::Lvalue(LvalueRef::alloca(bcx,
97 &format!("temp{:?}", i)))
99 // If this is an immediate temp, we do not create an
100 // alloca in advance. Instead we wait until we see the
101 // definition and update the operand there.
102 TempRef::Operand(None)
105 let args = arg_value_refs(bcx, mir);
107 // Allocate a `Block` for every basic block
108 let block_bcxs: Vec<Block<'bcx,'tcx>> =
110 .map(|&bb| fcx.new_block(false, &format!("{:?}", bb), None))
113 // Branch to the START block
114 let start_bcx = block_bcxs[mir::START_BLOCK.index()];
115 build::Br(bcx, start_bcx.llbb, DebugLoc::None);
117 let mut mircx = MirContext {
119 llpersonalityslot: None,
126 // Translate the body of each block
127 for &bb in &mir_blocks {
128 if bb != mir::DIVERGE_BLOCK {
129 mircx.trans_block(bb);
133 // Total hack: translate DIVERGE_BLOCK last. This is so that any
134 // panics which the fn may do can initialize the
135 // `llpersonalityslot` cell. We don't do this up front because the
136 // LLVM type of it is (frankly) annoying to compute.
137 mircx.trans_block(mir::DIVERGE_BLOCK);
140 /// Produce, for each argument, a `ValueRef` pointing at the
141 /// argument's value. As arguments are lvalues, these are always
143 fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>,
144 mir: &mir::Mir<'tcx>)
145 -> Vec<LvalueRef<'tcx>> {
146 // FIXME tupled_args? I think I'd rather that mapping is done in MIR land though
149 let mut idx = fcx.arg_offset() as c_uint;
153 .map(|(arg_index, arg_decl)| {
154 let arg_ty = bcx.monomorphize(&arg_decl.ty);
155 let llval = if type_of::arg_is_indirect(bcx.ccx(), arg_ty) {
156 // Don't copy an indirect argument to an alloca, the caller
157 // already put it in a temporary alloca and gave it up, unless
158 // we emit extra-debug-info, which requires local allocas :(.
159 // FIXME: lifetimes, debug info
160 let llarg = llvm::get_param(fcx.llfn, idx);
163 } else if common::type_is_fat_ptr(tcx, arg_ty) {
164 // we pass fat pointers as two words, but we want to
165 // represent them internally as a pointer to two words,
166 // so make an alloca to store them in.
167 let lldata = llvm::get_param(fcx.llfn, idx);
168 let llextra = llvm::get_param(fcx.llfn, idx + 1);
170 let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index));
171 build::Store(bcx, lldata, expr::get_dataptr(bcx, lltemp));
172 build::Store(bcx, llextra, expr::get_dataptr(bcx, lltemp));
175 // otherwise, arg is passed by value, so make a
176 // temporary and store it there
177 let llarg = llvm::get_param(fcx.llfn, idx);
179 let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index));
180 build::Store(bcx, llarg, lltemp);
183 LvalueRef::new(llval, LvalueTy::from_ty(arg_ty))