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}
;
14 use rustc
::mir
::repr
as mir
;
15 use rustc
::mir
::tcx
::LvalueTy
;
17 use common
::{self, Block, BlockAndBuilder, FunctionContext}
;
22 use basic_block
::BasicBlock
;
24 use rustc_data_structures
::bitvec
::BitVector
;
26 use self::lvalue
::{LvalueRef, get_dataptr, get_meta}
;
27 use rustc_mir
::traversal
;
29 use self::operand
::OperandRef
;
32 pub enum CachedMir
<'mir
, 'tcx
: 'mir
> {
33 Ref(&'mir mir
::Mir
<'tcx
>),
34 Owned(Rc
<mir
::Mir
<'tcx
>>)
37 impl<'mir
, 'tcx
: 'mir
> Deref
for CachedMir
<'mir
, 'tcx
> {
38 type Target
= mir
::Mir
<'tcx
>;
39 fn deref(&self) -> &mir
::Mir
<'tcx
> {
41 CachedMir
::Ref(r
) => r
,
42 CachedMir
::Owned(ref rc
) => rc
47 // FIXME DebugLoc is always None right now
49 /// Master context for translating MIR.
50 pub struct MirContext
<'bcx
, 'tcx
:'bcx
> {
51 mir
: CachedMir
<'bcx
, 'tcx
>,
54 fcx
: &'bcx common
::FunctionContext
<'bcx
, 'tcx
>,
56 /// When unwinding is initiated, we have to store this personality
57 /// value somewhere so that we can load it and re-use it in the
58 /// resume instruction. The personality is (afaik) some kind of
59 /// value used for C++ unwinding, which must filter by type: we
60 /// don't really care about it very much. Anyway, this value
61 /// contains an alloca into which the personality is stored and
62 /// then later loaded when generating the DIVERGE_BLOCK.
63 llpersonalityslot
: Option
<ValueRef
>,
65 /// A `Block` for each MIR `BasicBlock`
66 blocks
: Vec
<Block
<'bcx
, 'tcx
>>,
68 /// Cached unreachable block
69 unreachable_block
: Option
<Block
<'bcx
, 'tcx
>>,
71 /// An LLVM alloca for each MIR `VarDecl`
72 vars
: Vec
<LvalueRef
<'tcx
>>,
74 /// The location where each MIR `TempDecl` is stored. This is
75 /// usually an `LvalueRef` representing an alloca, but not always:
76 /// sometimes we can skip the alloca and just store the value
77 /// directly using an `OperandRef`, which makes for tighter LLVM
78 /// IR. The conditions for using an `OperandRef` are as follows:
80 /// - the type of the temporary must be judged "immediate" by `type_is_immediate`
81 /// - the operand must never be referenced indirectly
82 /// - we should not take its address using the `&` operator
83 /// - nor should it appear in an lvalue path like `tmp.a`
84 /// - the operand must be defined by an rvalue that can generate immediate
87 /// Avoiding allocs can also be important for certain intrinsics,
89 temps
: Vec
<TempRef
<'tcx
>>,
91 /// The arguments to the function; as args are lvalues, these are
92 /// always indirect, though we try to avoid creating an alloca
93 /// when we can (and just reuse the pointer the caller provided).
94 args
: Vec
<LvalueRef
<'tcx
>>,
98 Lvalue(LvalueRef
<'tcx
>),
99 Operand(Option
<OperandRef
<'tcx
>>),
102 ///////////////////////////////////////////////////////////////////////////
104 pub fn trans_mir
<'blk
, 'tcx
: 'blk
>(fcx
: &'blk FunctionContext
<'blk
, 'tcx
>) {
105 let bcx
= fcx
.init(false, None
).build();
108 let mir_blocks
= mir
.all_basic_blocks();
110 // Analyze the temps to determine which must be lvalues
112 let lvalue_temps
= bcx
.with_block(|bcx
| {
113 analyze
::lvalue_temps(bcx
, &mir
)
116 // Allocate variable and temp allocas
117 let vars
= mir
.var_decls
.iter()
118 .map(|decl
| (bcx
.monomorphize(&decl
.ty
), decl
.name
))
119 .map(|(mty
, name
)| LvalueRef
::alloca(&bcx
, mty
, &name
.as_str()))
121 let temps
= mir
.temp_decls
.iter()
122 .map(|decl
| bcx
.monomorphize(&decl
.ty
))
124 .map(|(i
, mty
)| if lvalue_temps
.contains(i
) {
125 TempRef
::Lvalue(LvalueRef
::alloca(&bcx
,
127 &format
!("temp{:?}", i
)))
129 // If this is an immediate temp, we do not create an
130 // alloca in advance. Instead we wait until we see the
131 // definition and update the operand there.
132 TempRef
::Operand(None
)
135 let args
= arg_value_refs(&bcx
, &mir
);
137 // Allocate a `Block` for every basic block
138 let block_bcxs
: Vec
<Block
<'blk
,'tcx
>> =
141 if bb
== mir
::START_BLOCK
{
142 fcx
.new_block("start", None
)
143 } else if bb
== mir
::END_BLOCK
{
144 fcx
.new_block("end", None
)
146 fcx
.new_block(&format
!("{:?}", bb
), None
)
151 // Branch to the START block
152 let start_bcx
= block_bcxs
[mir
::START_BLOCK
.index()];
153 bcx
.br(start_bcx
.llbb
);
155 let mut mircx
= MirContext
{
158 llpersonalityslot
: None
,
160 unreachable_block
: None
,
166 let mut visited
= BitVector
::new(mir_blocks
.len());
168 let rpo
= traversal
::reverse_postorder(&mir
);
169 // Translate the body of each block using reverse postorder
171 visited
.insert(bb
.index());
172 mircx
.trans_block(bb
);
175 // Remove blocks that haven't been visited, or have no
177 for &bb
in &mir_blocks
{
178 let block
= mircx
.blocks
[bb
.index()];
179 let block
= BasicBlock(block
.llbb
);
181 if !visited
.contains(bb
.index()) {
183 } else if block
.pred_iter().count() == 0 {
191 /// Produce, for each argument, a `ValueRef` pointing at the
192 /// argument's value. As arguments are lvalues, these are always
194 fn arg_value_refs
<'bcx
, 'tcx
>(bcx
: &BlockAndBuilder
<'bcx
, 'tcx
>,
195 mir
: &mir
::Mir
<'tcx
>)
196 -> Vec
<LvalueRef
<'tcx
>> {
200 let mut llarg_idx
= fcx
.fn_ty
.ret
.is_indirect() as usize;
201 mir
.arg_decls
.iter().enumerate().map(|(arg_index
, arg_decl
)| {
202 let arg_ty
= bcx
.monomorphize(&arg_decl
.ty
);
204 // This argument (e.g. the last argument in the "rust-call" ABI)
205 // is a tuple that was spread at the ABI level and now we have
206 // to reconstruct it into a tuple local variable, from multiple
207 // individual LLVM function arguments.
209 let tupled_arg_tys
= match arg_ty
.sty
{
210 ty
::TyTuple(ref tys
) => tys
,
211 _
=> bug
!("spread argument isn't a tuple?!")
214 let lltemp
= bcx
.with_block(|bcx
| {
215 base
::alloc_ty(bcx
, arg_ty
, &format
!("arg{}", arg_index
))
217 for (i
, &tupled_arg_ty
) in tupled_arg_tys
.iter().enumerate() {
218 let dst
= bcx
.struct_gep(lltemp
, i
);
219 let arg
= &fcx
.fn_ty
.args
[idx
];
221 if common
::type_is_fat_ptr(tcx
, tupled_arg_ty
) {
222 // We pass fat pointers as two words, but inside the tuple
223 // they are the two sub-fields of a single aggregate field.
224 let meta
= &fcx
.fn_ty
.args
[idx
];
226 arg
.store_fn_arg(bcx
, &mut llarg_idx
, get_dataptr(bcx
, dst
));
227 meta
.store_fn_arg(bcx
, &mut llarg_idx
, get_meta(bcx
, dst
));
229 arg
.store_fn_arg(bcx
, &mut llarg_idx
, dst
);
232 return LvalueRef
::new_sized(lltemp
, LvalueTy
::from_ty(arg_ty
));
235 let arg
= &fcx
.fn_ty
.args
[idx
];
237 let llval
= if arg
.is_indirect() {
238 // Don't copy an indirect argument to an alloca, the caller
239 // already put it in a temporary alloca and gave it up, unless
240 // we emit extra-debug-info, which requires local allocas :(.
241 // FIXME: lifetimes, debug info
242 let llarg
= llvm
::get_param(fcx
.llfn
, llarg_idx
as c_uint
);
246 let lltemp
= bcx
.with_block(|bcx
| {
247 base
::alloc_ty(bcx
, arg_ty
, &format
!("arg{}", arg_index
))
249 if common
::type_is_fat_ptr(tcx
, arg_ty
) {
250 // we pass fat pointers as two words, but we want to
251 // represent them internally as a pointer to two words,
252 // so make an alloca to store them in.
253 let meta
= &fcx
.fn_ty
.args
[idx
];
255 arg
.store_fn_arg(bcx
, &mut llarg_idx
, get_dataptr(bcx
, lltemp
));
256 meta
.store_fn_arg(bcx
, &mut llarg_idx
, get_meta(bcx
, lltemp
));
258 // otherwise, arg is passed by value, so make a
259 // temporary and store it there
260 arg
.store_fn_arg(bcx
, &mut llarg_idx
, lltemp
);
264 LvalueRef
::new_sized(llval
, LvalueTy
::from_ty(arg_ty
))