]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/mir/mod.rs
correct typos
[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     temps: Vec<TempRef<'tcx>>,
59
60     /// The arguments to the function; as args are lvalues, these are
61     /// always indirect, though we try to avoid creating an alloca
62     /// when we can (and just reuse the pointer the caller provided).
63     args: Vec<LvalueRef<'tcx>>,
64 }
65
66 enum TempRef<'tcx> {
67     Lvalue(LvalueRef<'tcx>),
68     Operand(Option<OperandRef<'tcx>>),
69 }
70
71 ///////////////////////////////////////////////////////////////////////////
72
73 pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
74     let fcx = bcx.fcx;
75     let mir = bcx.mir();
76
77     let mir_blocks = bcx.mir().all_basic_blocks();
78
79     // Analyze the temps to determine which must be lvalues
80     // FIXME
81     let lvalue_temps = analyze::lvalue_temps(bcx, mir);
82
83     // Allocate variable and temp allocas
84     let vars = mir.var_decls.iter()
85                             .map(|decl| (bcx.monomorphize(&decl.ty), decl.name))
86                             .map(|(mty, name)| LvalueRef::alloca(bcx, mty, &name.as_str()))
87                             .collect();
88     let temps = mir.temp_decls.iter()
89                               .map(|decl| bcx.monomorphize(&decl.ty))
90                               .enumerate()
91                               .map(|(i, mty)| if lvalue_temps.contains(&i) {
92                                   TempRef::Lvalue(LvalueRef::alloca(bcx,
93                                                                     mty,
94                                                                     &format!("temp{:?}", i)))
95                               } else {
96                                   // If this is an immediate temp, we do not create an
97                                   // alloca in advance. Instead we wait until we see the
98                                   // definition and update the operand there.
99                                   TempRef::Operand(None)
100                               })
101                               .collect();
102     let args = arg_value_refs(bcx, mir);
103
104     // Allocate a `Block` for every basic block
105     let block_bcxs: Vec<Block<'bcx,'tcx>> =
106         mir_blocks.iter()
107                   .map(|&bb| fcx.new_block(false, &format!("{:?}", bb), None))
108                   .collect();
109
110     // Branch to the START block
111     let start_bcx = block_bcxs[mir::START_BLOCK.index()];
112     build::Br(bcx, start_bcx.llbb, DebugLoc::None);
113
114     let mut mircx = MirContext {
115         mir: mir,
116         llpersonalityslot: None,
117         blocks: block_bcxs,
118         vars: vars,
119         temps: temps,
120         args: args,
121     };
122
123     // Translate the body of each block
124     for &bb in &mir_blocks {
125         if bb != mir::DIVERGE_BLOCK {
126             mircx.trans_block(bb);
127         }
128     }
129
130     // Total hack: translate DIVERGE_BLOCK last. This is so that any
131     // panics which the fn may do can initialize the
132     // `llpersonalityslot` cell. We don't do this up front because the
133     // LLVM type of it is (frankly) annoying to compute.
134     mircx.trans_block(mir::DIVERGE_BLOCK);
135 }
136
137 /// Produce, for each argument, a `ValueRef` pointing at the
138 /// argument's value. As arguments are lvalues, these are always
139 /// indirect.
140 fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>,
141                               mir: &mir::Mir<'tcx>)
142                               -> Vec<LvalueRef<'tcx>> {
143     // FIXME tupled_args? I think I'd rather that mapping is done in MIR land though
144     let fcx = bcx.fcx;
145     let tcx = bcx.tcx();
146     let mut idx = fcx.arg_offset() as c_uint;
147     mir.arg_decls
148        .iter()
149        .enumerate()
150        .map(|(arg_index, arg_decl)| {
151            let arg_ty = bcx.monomorphize(&arg_decl.ty);
152            let llval = if type_of::arg_is_indirect(bcx.ccx(), arg_ty) {
153                // Don't copy an indirect argument to an alloca, the caller
154                // already put it in a temporary alloca and gave it up, unless
155                // we emit extra-debug-info, which requires local allocas :(.
156                // FIXME: lifetimes, debug info
157                let llarg = llvm::get_param(fcx.llfn, idx);
158                idx += 1;
159                llarg
160            } else if common::type_is_fat_ptr(tcx, arg_ty) {
161                // we pass fat pointers as two words, but we want to
162                // represent them internally as a pointer to two words,
163                // so make an alloca to store them in.
164                let lldata = llvm::get_param(fcx.llfn, idx);
165                let llextra = llvm::get_param(fcx.llfn, idx + 1);
166                idx += 2;
167                let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index));
168                build::Store(bcx, lldata, expr::get_dataptr(bcx, lltemp));
169                build::Store(bcx, llextra, expr::get_dataptr(bcx, lltemp));
170                lltemp
171            } else {
172                // otherwise, arg is passed by value, so make a
173                // temporary and store it there
174                let llarg = llvm::get_param(fcx.llfn, idx);
175                idx += 1;
176                let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index));
177                build::Store(bcx, llarg, lltemp);
178                lltemp
179            };
180            LvalueRef::new(llval, LvalueTy::from_ty(arg_ty))
181        })
182        .collect()
183 }
184
185 mod analyze;
186 mod block;
187 mod constant;
188 mod lvalue;
189 mod rvalue;
190 mod operand;
191 mod statement;
192