]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/mir/mod.rs
address nits from dotdash
[rust.git] / src / librustc_trans / trans / mir / mod.rs
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.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use libc::c_uint;
12 use llvm::{self, ValueRef};
13 use rustc_mir::repr as mir;
14 use rustc_mir::tcx::LvalueTy;
15 use trans::base;
16 use trans::build;
17 use trans::common::{self, Block};
18 use trans::debuginfo::DebugLoc;
19 use trans::expr;
20 use trans::type_of;
21
22 use self::lvalue::LvalueRef;
23 use self::operand::OperandRef;
24
25 // FIXME DebugLoc is always None right now
26
27 /// Master context for translating MIR.
28 pub struct MirContext<'bcx, 'tcx:'bcx> {
29     mir: &'bcx mir::Mir<'tcx>,
30
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>,
39
40     /// A `Block` for each MIR `BasicBlock`
41     blocks: Vec<Block<'bcx, 'tcx>>,
42
43     /// An LLVM alloca for each MIR `VarDecl`
44     vars: Vec<LvalueRef<'tcx>>,
45
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:
51     ///
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
57     ///   values
58     ///
59     /// Avoiding allocs can also be important for certain intrinsics,
60     /// notably `expect`.
61     temps: Vec<TempRef<'tcx>>,
62
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>>,
67 }
68
69 enum TempRef<'tcx> {
70     Lvalue(LvalueRef<'tcx>),
71     Operand(Option<OperandRef<'tcx>>),
72 }
73
74 ///////////////////////////////////////////////////////////////////////////
75
76 pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
77     let fcx = bcx.fcx;
78     let mir = bcx.mir();
79
80     let mir_blocks = bcx.mir().all_basic_blocks();
81
82     // Analyze the temps to determine which must be lvalues
83     // FIXME
84     let lvalue_temps = analyze::lvalue_temps(bcx, mir);
85
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()))
90                             .collect();
91     let temps = mir.temp_decls.iter()
92                               .map(|decl| bcx.monomorphize(&decl.ty))
93                               .enumerate()
94                               .map(|(i, mty)| if lvalue_temps.contains(&i) {
95                                   TempRef::Lvalue(LvalueRef::alloca(bcx,
96                                                                     mty,
97                                                                     &format!("temp{:?}", i)))
98                               } else {
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)
103                               })
104                               .collect();
105     let args = arg_value_refs(bcx, mir);
106
107     // Allocate a `Block` for every basic block
108     let block_bcxs: Vec<Block<'bcx,'tcx>> =
109         mir_blocks.iter()
110                   .map(|&bb| fcx.new_block(false, &format!("{:?}", bb), None))
111                   .collect();
112
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);
116
117     let mut mircx = MirContext {
118         mir: mir,
119         llpersonalityslot: None,
120         blocks: block_bcxs,
121         vars: vars,
122         temps: temps,
123         args: args,
124     };
125
126     // Translate the body of each block
127     for &bb in &mir_blocks {
128         if bb != mir::DIVERGE_BLOCK {
129             mircx.trans_block(bb);
130         }
131     }
132
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);
138 }
139
140 /// Produce, for each argument, a `ValueRef` pointing at the
141 /// argument's value. As arguments are lvalues, these are always
142 /// indirect.
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
147     let fcx = bcx.fcx;
148     let tcx = bcx.tcx();
149     let mut idx = fcx.arg_offset() as c_uint;
150     mir.arg_decls
151        .iter()
152        .enumerate()
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);
161                idx += 1;
162                llarg
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);
169                idx += 2;
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));
173                lltemp
174            } else {
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);
178                idx += 1;
179                let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index));
180                build::Store(bcx, llarg, lltemp);
181                lltemp
182            };
183            LvalueRef::new(llval, LvalueTy::from_ty(arg_ty))
184        })
185        .collect()
186 }
187
188 mod analyze;
189 mod block;
190 mod constant;
191 mod lvalue;
192 mod rvalue;
193 mod operand;
194 mod statement;
195