Skip to content

Commit e84829d

Browse files
committed
Plumbing to omit allocas for temps when possible (currently unused)
1 parent 02017b3 commit e84829d

File tree

5 files changed

+166
-44
lines changed

5 files changed

+166
-44
lines changed

src/librustc_trans/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ extern crate graphviz;
5151
extern crate libc;
5252
extern crate rustc;
5353
extern crate rustc_back;
54+
extern crate rustc_data_structures;
5455
extern crate rustc_front;
5556
extern crate rustc_llvm as llvm;
5657
extern crate rustc_mir;

src/librustc_trans/trans/mir/lvalue.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use trans::debuginfo::DebugLoc;
2020
use trans::machine;
2121
use trans::tvec;
2222

23-
use super::MirContext;
23+
use super::{MirContext, TempRef};
2424

2525
#[derive(Copy, Clone)]
2626
pub struct LvalueRef<'tcx> {
@@ -58,7 +58,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
5858
let tcx = bcx.tcx();
5959
match *lvalue {
6060
mir::Lvalue::Var(index) => self.vars[index as usize],
61-
mir::Lvalue::Temp(index) => self.temps[index as usize],
61+
mir::Lvalue::Temp(index) => match self.temps[index as usize] {
62+
TempRef::Lvalue(lvalue) =>
63+
lvalue,
64+
TempRef::Operand(..) =>
65+
tcx.sess.bug(&format!("using operand temp {:?} as lvalue", lvalue)),
66+
},
6267
mir::Lvalue::Arg(index) => self.args[index as usize],
6368
mir::Lvalue::Static(_def_id) => unimplemented!(),
6469
mir::Lvalue::ReturnPointer => {

src/librustc_trans/trans/mir/mod.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010

1111
use libc::c_uint;
1212
use llvm::{self, ValueRef};
13+
use rustc_data_structures::fnv::FnvHashSet;
1314
use rustc_mir::repr as mir;
1415
use rustc_mir::tcx::LvalueTy;
15-
use std::cell::Cell;
1616
use trans::base;
1717
use trans::build;
1818
use trans::common::{self, Block};
@@ -21,6 +21,7 @@ use trans::expr;
2121
use trans::type_of;
2222

2323
use self::lvalue::LvalueRef;
24+
use self::operand::OperandRef;
2425

2526
// FIXME DebugLoc is always None right now
2627

@@ -43,15 +44,31 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
4344
/// An LLVM alloca for each MIR `VarDecl`
4445
vars: Vec<LvalueRef<'tcx>>,
4546

46-
/// An LLVM alloca for each MIR `TempDecl`
47-
temps: Vec<LvalueRef<'tcx>>,
47+
/// The location where each MIR `TempDecl` is stored. This is
48+
/// usually an `LvalueRef` representing an alloca, but not always:
49+
/// sometimes we can skip the alloca and just store the value
50+
/// directly using an `OperandRef`, which makes for tighter LLVM
51+
/// IR. The conditions for using an `OperandRef` are as follows:
52+
///
53+
/// - the type of the temporary must be judged "immediate" by `type_is_immediate`
54+
/// - the operand must never be referenced indirectly
55+
/// - we should not take its address using the `&` operator
56+
/// - nor should it appear in an lvalue path like `tmp.a`
57+
/// - the operand must be defined by an rvalue that can generate immediate
58+
/// values
59+
temps: Vec<TempRef<'tcx>>,
4860

4961
/// The arguments to the function; as args are lvalues, these are
5062
/// always indirect, though we try to avoid creating an alloca
5163
/// when we can (and just reuse the pointer the caller provided).
5264
args: Vec<LvalueRef<'tcx>>,
5365
}
5466

67+
enum TempRef<'tcx> {
68+
Lvalue(LvalueRef<'tcx>),
69+
Operand(Option<OperandRef<'tcx>>),
70+
}
71+
5572
///////////////////////////////////////////////////////////////////////////
5673

5774
pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
@@ -60,6 +77,10 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
6077

6178
let mir_blocks = bcx.mir().all_basic_blocks();
6279

80+
// Analyze the temps to determine which must be lvalues
81+
// FIXME
82+
let lvalue_temps: FnvHashSet<usize> = (0..mir.temp_decls.len()).collect();
83+
6384
// Allocate variable and temp allocas
6485
let vars = mir.var_decls.iter()
6586
.map(|decl| (bcx.monomorphize(&decl.ty), decl.name))
@@ -68,7 +89,16 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
6889
let temps = mir.temp_decls.iter()
6990
.map(|decl| bcx.monomorphize(&decl.ty))
7091
.enumerate()
71-
.map(|(i, mty)| LvalueRef::alloca(bcx, mty, &format!("temp{:?}", i)))
92+
.map(|(i, mty)| if lvalue_temps.contains(&i) {
93+
TempRef::Lvalue(LvalueRef::alloca(bcx,
94+
mty,
95+
&format!("temp{:?}", i)))
96+
} else {
97+
// If this is an immediate temp, we do not create an
98+
// alloca in advance. Instead we wait until we see the
99+
// definition and update the operand there.
100+
TempRef::Operand(None)
101+
})
72102
.collect();
73103
let args = arg_value_refs(bcx, mir);
74104

src/librustc_trans/trans/mir/rvalue.rs

Lines changed: 99 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,98 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
5353
unimplemented!()
5454
}
5555

56+
mir::Rvalue::Aggregate(_, ref operands) => {
57+
for (i, operand) in operands.iter().enumerate() {
58+
let lldest_i = build::GEPi(bcx, lldest, &[0, i]);
59+
self.trans_operand_into(bcx, lldest_i, operand);
60+
}
61+
bcx
62+
}
63+
64+
mir::Rvalue::Slice { ref input, from_start, from_end } => {
65+
let ccx = bcx.ccx();
66+
let input = self.trans_lvalue(bcx, input);
67+
let (llbase, lllen) = tvec::get_base_and_len(bcx,
68+
input.llval,
69+
input.ty.to_ty(bcx.tcx()));
70+
let llbase1 = build::GEPi(bcx, llbase, &[from_start]);
71+
let adj = common::C_uint(ccx, from_start + from_end);
72+
let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None);
73+
build::Store(bcx, llbase1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR]));
74+
build::Store(bcx, lllen1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA]));
75+
bcx
76+
}
77+
78+
mir::Rvalue::InlineAsm(inline_asm) => {
79+
asm::trans_inline_asm(bcx, inline_asm)
80+
}
81+
82+
_ => {
83+
assert!(self.rvalue_creates_operand(rvalue));
84+
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
85+
build::Store(bcx, temp.llval, lldest);
86+
bcx
87+
}
88+
}
89+
}
90+
91+
pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool {
92+
match *rvalue {
93+
mir::Rvalue::Use(..) | // (*)
94+
mir::Rvalue::Ref(..) |
95+
mir::Rvalue::Len(..) |
96+
mir::Rvalue::Cast(..) | // (*)
97+
mir::Rvalue::BinaryOp(..) |
98+
mir::Rvalue::UnaryOp(..) |
99+
mir::Rvalue::Box(..) =>
100+
true,
101+
mir::Rvalue::Repeat(..) |
102+
mir::Rvalue::Aggregate(..) |
103+
mir::Rvalue::Slice { .. } |
104+
mir::Rvalue::InlineAsm(..) =>
105+
false,
106+
}
107+
108+
// (*) this is only true if the type is suitable
109+
}
110+
111+
pub fn trans_rvalue_operand(&mut self,
112+
bcx: Block<'bcx, 'tcx>,
113+
rvalue: &mir::Rvalue<'tcx>)
114+
-> (Block<'bcx, 'tcx>, OperandRef<'tcx>)
115+
{
116+
assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
117+
118+
match *rvalue {
119+
mir::Rvalue::Use(ref operand) => {
120+
let operand = self.trans_operand(bcx, operand);
121+
(bcx, operand)
122+
}
123+
124+
mir::Rvalue::Cast(..) => {
125+
unimplemented!()
126+
}
127+
56128
mir::Rvalue::Ref(_, _, ref lvalue) => {
57129
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
130+
58131
// Note: lvalues are indirect, so storing the `llval` into the
59132
// destination effectively creates a reference.
60-
build::Store(bcx, tr_lvalue.llval, lldest);
61-
bcx
133+
(bcx, OperandRef {
134+
llval: tr_lvalue.llval,
135+
ty: tr_lvalue.ty.to_ty(bcx.tcx()),
136+
})
62137
}
63138

64139
mir::Rvalue::Len(ref lvalue) => {
65140
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
66141
let (_, lllen) = tvec::get_base_and_len(bcx,
67142
tr_lvalue.llval,
68143
tr_lvalue.ty.to_ty(bcx.tcx()));
69-
build::Store(bcx, lllen, lldest);
70-
bcx
144+
(bcx, OperandRef {
145+
llval: lllen,
146+
ty: bcx.tcx().types.usize,
147+
})
71148
}
72149

73150
mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
@@ -170,8 +247,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
170247
mir::BinOp::Gt => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
171248
hir::BiGt, binop_debug_loc),
172249
};
173-
build::Store(bcx, llval, lldest);
174-
bcx
250+
(bcx, OperandRef {
251+
llval: llval,
252+
ty: lhs.ty,
253+
})
175254
}
176255

177256
mir::Rvalue::UnaryOp(op, ref operand) => {
@@ -186,12 +265,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
186265
build::Neg(bcx, operand.llval, debug_loc)
187266
}
188267
};
189-
build::Store(bcx, llval, lldest);
190-
bcx
268+
(bcx, OperandRef {
269+
llval: llval,
270+
ty: operand.ty,
271+
})
191272
}
192273

193274
mir::Rvalue::Box(content_ty) => {
194-
let content_ty: Ty<'tcx> = content_ty;
275+
let content_ty: Ty<'tcx> = bcx.monomorphize(&content_ty);
195276
let llty = type_of::type_of(bcx.ccx(), content_ty);
196277
let llsize = machine::llsize_of(bcx.ccx(), llty);
197278
let align = type_of::align_of(bcx.ccx(), content_ty);
@@ -204,34 +285,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
204285
llsize,
205286
llalign,
206287
DebugLoc::None);
207-
build::Store(bcx, llval, lldest);
208-
bcx
209-
}
210-
211-
mir::Rvalue::Aggregate(_, ref operands) => {
212-
for (i, operand) in operands.iter().enumerate() {
213-
let lldest_i = build::GEPi(bcx, lldest, &[0, i]);
214-
self.trans_operand_into(bcx, lldest_i, operand);
215-
}
216-
bcx
288+
(bcx, OperandRef {
289+
llval: llval,
290+
ty: box_ty,
291+
})
217292
}
218293

219-
mir::Rvalue::Slice { ref input, from_start, from_end } => {
220-
let ccx = bcx.ccx();
221-
let input = self.trans_lvalue(bcx, input);
222-
let (llbase, lllen) = tvec::get_base_and_len(bcx,
223-
input.llval,
224-
input.ty.to_ty(bcx.tcx()));
225-
let llbase1 = build::GEPi(bcx, llbase, &[from_start]);
226-
let adj = common::C_uint(ccx, from_start + from_end);
227-
let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None);
228-
build::Store(bcx, llbase1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR]));
229-
build::Store(bcx, lllen1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA]));
230-
bcx
231-
}
232-
233-
mir::Rvalue::InlineAsm(inline_asm) => {
234-
asm::trans_inline_asm(bcx, inline_asm)
294+
mir::Rvalue::Repeat(..) |
295+
mir::Rvalue::Aggregate(..) |
296+
mir::Rvalue::Slice { .. } |
297+
mir::Rvalue::InlineAsm(..) => {
298+
bcx.tcx().sess.bug(&format!("cannot generate operand from rvalue {:?}", rvalue));
235299
}
236300
}
237301
}

src/librustc_trans/trans/mir/statement.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use trans::debuginfo::DebugLoc;
1515
use trans::glue;
1616

1717
use super::MirContext;
18+
use super::TempRef;
1819

1920
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
2021
pub fn trans_statement(&mut self,
@@ -25,9 +26,30 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
2526

2627
match statement.kind {
2728
mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
28-
let tr_dest = self.trans_lvalue(bcx, lvalue);
29-
self.trans_rvalue(bcx, tr_dest.llval, rvalue);
30-
bcx
29+
match *lvalue {
30+
mir::Lvalue::Temp(index) => {
31+
let index = index as usize;
32+
match self.temps[index as usize] {
33+
TempRef::Lvalue(tr_dest) => {
34+
self.trans_rvalue(bcx, tr_dest.llval, rvalue)
35+
}
36+
TempRef::Operand(None) => {
37+
let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue);
38+
self.temps[index] = TempRef::Operand(Some(operand));
39+
bcx
40+
}
41+
TempRef::Operand(Some(_)) => {
42+
bcx.tcx().sess.span_bug(
43+
statement.span,
44+
&format!("operand {:?} already assigned", rvalue));
45+
}
46+
}
47+
}
48+
_ => {
49+
let tr_dest = self.trans_lvalue(bcx, lvalue);
50+
self.trans_rvalue(bcx, tr_dest.llval, rvalue)
51+
}
52+
}
3153
}
3254

3355
mir::StatementKind::Drop(mir::DropKind::Deep, ref lvalue) => {

0 commit comments

Comments
 (0)