]>
git.proxmox.com Git - rustc.git/blob - src/librustc_trans/trans/mir/mod.rs
75ce33da2c9b9da66eb84a77ad40fbdabb3f1eaf
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
>,
32 fcx
: &'bcx common
::FunctionContext
<'bcx
, 'tcx
>,
34 /// When unwinding is initiated, we have to store this personality
35 /// value somewhere so that we can load it and re-use it in the
36 /// resume instruction. The personality is (afaik) some kind of
37 /// value used for C++ unwinding, which must filter by type: we
38 /// don't really care about it very much. Anyway, this value
39 /// contains an alloca into which the personality is stored and
40 /// then later loaded when generating the DIVERGE_BLOCK.
41 llpersonalityslot
: Option
<ValueRef
>,
43 /// A `Block` for each MIR `BasicBlock`
44 blocks
: Vec
<Block
<'bcx
, 'tcx
>>,
46 /// Cached unreachable block
47 unreachable_block
: Option
<Block
<'bcx
, 'tcx
>>,
49 /// An LLVM alloca for each MIR `VarDecl`
50 vars
: Vec
<LvalueRef
<'tcx
>>,
52 /// The location where each MIR `TempDecl` is stored. This is
53 /// usually an `LvalueRef` representing an alloca, but not always:
54 /// sometimes we can skip the alloca and just store the value
55 /// directly using an `OperandRef`, which makes for tighter LLVM
56 /// IR. The conditions for using an `OperandRef` are as follows:
58 /// - the type of the temporary must be judged "immediate" by `type_is_immediate`
59 /// - the operand must never be referenced indirectly
60 /// - we should not take its address using the `&` operator
61 /// - nor should it appear in an lvalue path like `tmp.a`
62 /// - the operand must be defined by an rvalue that can generate immediate
65 /// Avoiding allocs can also be important for certain intrinsics,
67 temps
: Vec
<TempRef
<'tcx
>>,
69 /// The arguments to the function; as args are lvalues, these are
70 /// always indirect, though we try to avoid creating an alloca
71 /// when we can (and just reuse the pointer the caller provided).
72 args
: Vec
<LvalueRef
<'tcx
>>,
76 Lvalue(LvalueRef
<'tcx
>),
77 Operand(Option
<OperandRef
<'tcx
>>),
80 ///////////////////////////////////////////////////////////////////////////
82 pub fn trans_mir
<'bcx
, 'tcx
>(bcx
: Block
<'bcx
, 'tcx
>) {
86 let mir_blocks
= bcx
.mir().all_basic_blocks();
88 // Analyze the temps to determine which must be lvalues
90 let lvalue_temps
= analyze
::lvalue_temps(bcx
, mir
);
92 // Allocate variable and temp allocas
93 let vars
= mir
.var_decls
.iter()
94 .map(|decl
| (bcx
.monomorphize(&decl
.ty
), decl
.name
))
95 .map(|(mty
, name
)| LvalueRef
::alloca(bcx
, mty
, &name
.as_str()))
97 let temps
= mir
.temp_decls
.iter()
98 .map(|decl
| bcx
.monomorphize(&decl
.ty
))
100 .map(|(i
, mty
)| if lvalue_temps
.contains(&i
) {
101 TempRef
::Lvalue(LvalueRef
::alloca(bcx
,
103 &format
!("temp{:?}", i
)))
105 // If this is an immediate temp, we do not create an
106 // alloca in advance. Instead we wait until we see the
107 // definition and update the operand there.
108 TempRef
::Operand(None
)
111 let args
= arg_value_refs(bcx
, mir
);
113 // Allocate a `Block` for every basic block
114 let block_bcxs
: Vec
<Block
<'bcx
,'tcx
>> =
117 let is_cleanup
= mir
.basic_block_data(bb
).is_cleanup
;
118 fcx
.new_block(is_cleanup
, &format
!("{:?}", bb
), None
)
122 // Branch to the START block
123 let start_bcx
= block_bcxs
[mir
::START_BLOCK
.index()];
124 build
::Br(bcx
, start_bcx
.llbb
, DebugLoc
::None
);
126 let mut mircx
= MirContext
{
129 llpersonalityslot
: None
,
131 unreachable_block
: None
,
137 // Translate the body of each block
138 for &bb
in &mir_blocks
{
139 mircx
.trans_block(bb
);
143 /// Produce, for each argument, a `ValueRef` pointing at the
144 /// argument's value. As arguments are lvalues, these are always
146 fn arg_value_refs
<'bcx
, 'tcx
>(bcx
: Block
<'bcx
, 'tcx
>,
147 mir
: &mir
::Mir
<'tcx
>)
148 -> Vec
<LvalueRef
<'tcx
>> {
149 // FIXME tupled_args? I think I'd rather that mapping is done in MIR land though
152 let mut idx
= fcx
.arg_offset() as c_uint
;
156 .map(|(arg_index
, arg_decl
)| {
157 let arg_ty
= bcx
.monomorphize(&arg_decl
.ty
);
158 let llval
= if type_of
::arg_is_indirect(bcx
.ccx(), arg_ty
) {
159 // Don't copy an indirect argument to an alloca, the caller
160 // already put it in a temporary alloca and gave it up, unless
161 // we emit extra-debug-info, which requires local allocas :(.
162 // FIXME: lifetimes, debug info
163 let llarg
= llvm
::get_param(fcx
.llfn
, idx
);
166 } else if common
::type_is_fat_ptr(tcx
, arg_ty
) {
167 // we pass fat pointers as two words, but we want to
168 // represent them internally as a pointer to two words,
169 // so make an alloca to store them in.
170 let lldata
= llvm
::get_param(fcx
.llfn
, idx
);
171 let llextra
= llvm
::get_param(fcx
.llfn
, idx
+ 1);
173 let lltemp
= base
::alloc_ty(bcx
, arg_ty
, &format
!("arg{}", arg_index
));
174 build
::Store(bcx
, lldata
, expr
::get_dataptr(bcx
, lltemp
));
175 build
::Store(bcx
, llextra
, expr
::get_meta(bcx
, lltemp
));
178 // otherwise, arg is passed by value, so make a
179 // temporary and store it there
180 let llarg
= llvm
::get_param(fcx
.llfn
, idx
);
182 let lltemp
= base
::alloc_ty(bcx
, arg_ty
, &format
!("arg{}", arg_index
));
183 base
::store_ty(bcx
, llarg
, lltemp
, arg_ty
);
186 LvalueRef
::new_sized(llval
, LvalueTy
::from_ty(arg_ty
))