Skip to content

Commit 7279af8

Browse files
committed
trans: generalize immediate temporaries to all MIR locals.
1 parent bec32eb commit 7279af8

File tree

12 files changed

+422
-307
lines changed

12 files changed

+422
-307
lines changed

src/librustc/mir/repr.rs

+35
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,40 @@ impl<'tcx> Mir<'tcx> {
144144
pub fn predecessors_for(&self, bb: BasicBlock) -> Ref<Vec<BasicBlock>> {
145145
Ref::map(self.predecessors(), |p| &p[bb])
146146
}
147+
148+
/// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
149+
/// to their index in the whole list of locals. This is useful if you
150+
/// want to treat all locals the same instead of repeating yourself.
151+
pub fn local_index(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> {
152+
let idx = match *lvalue {
153+
Lvalue::Arg(arg) => arg.index(),
154+
Lvalue::Var(var) => {
155+
self.arg_decls.len() +
156+
var.index()
157+
}
158+
Lvalue::Temp(temp) => {
159+
self.arg_decls.len() +
160+
self.var_decls.len() +
161+
temp.index()
162+
}
163+
Lvalue::ReturnPointer => {
164+
self.arg_decls.len() +
165+
self.var_decls.len() +
166+
self.temp_decls.len()
167+
}
168+
Lvalue::Static(_) |
169+
Lvalue::Projection(_) => return None
170+
};
171+
Some(Local::new(idx))
172+
}
173+
174+
/// Counts the number of locals, such that that local_index
175+
/// will always return an index smaller than this count.
176+
pub fn count_locals(&self) -> usize {
177+
self.arg_decls.len() +
178+
self.var_decls.len() +
179+
self.temp_decls.len() + 1
180+
}
147181
}
148182

149183
impl<'tcx> Index<BasicBlock> for Mir<'tcx> {
@@ -663,6 +697,7 @@ impl<'tcx> Debug for Statement<'tcx> {
663697
newtype_index!(Var, "var");
664698
newtype_index!(Temp, "tmp");
665699
newtype_index!(Arg, "arg");
700+
newtype_index!(Local, "local");
666701

667702
/// A path to a value; something that can be evaluated without
668703
/// changing or disturbing program state.

src/librustc/ty/sty.rs

+7
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,13 @@ impl<'tcx> FnOutput<'tcx> {
492492
ty::FnDiverging => def
493493
}
494494
}
495+
496+
pub fn maybe_converging(self) -> Option<Ty<'tcx>> {
497+
match self {
498+
ty::FnConverging(t) => Some(t),
499+
ty::FnDiverging => None
500+
}
501+
}
495502
}
496503

497504
pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;

src/librustc_trans/mir/analyze.rs

+81-60
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! An analysis to determine which temporaries require allocas and
11+
//! An analysis to determine which locals require allocas and
1212
//! which do not.
1313
1414
use rustc_data_structures::bitvec::BitVector;
@@ -21,16 +21,20 @@ use common::{self, Block, BlockAndBuilder};
2121
use glue;
2222
use super::rvalue;
2323

24-
pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
25-
mir: &mir::Mir<'tcx>) -> BitVector {
24+
pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
25+
mir: &mir::Mir<'tcx>) -> BitVector {
2626
let bcx = bcx.build();
27-
let mut analyzer = TempAnalyzer::new(mir, &bcx, mir.temp_decls.len());
27+
let mut analyzer = LocalAnalyzer::new(mir, &bcx);
2828

2929
analyzer.visit_mir(mir);
3030

31-
for (index, temp_decl) in mir.temp_decls.iter().enumerate() {
32-
let ty = bcx.monomorphize(&temp_decl.ty);
33-
debug!("temp {:?} has type {:?}", index, ty);
31+
let local_types = mir.arg_decls.iter().map(|a| a.ty)
32+
.chain(mir.var_decls.iter().map(|v| v.ty))
33+
.chain(mir.temp_decls.iter().map(|t| t.ty))
34+
.chain(mir.return_ty.maybe_converging());
35+
for (index, ty) in local_types.enumerate() {
36+
let ty = bcx.monomorphize(&ty);
37+
debug!("local {} has type {:?}", index, ty);
3438
if ty.is_scalar() ||
3539
ty.is_unique() ||
3640
ty.is_region_ptr() ||
@@ -50,76 +54,97 @@ pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
5054
// (e.g. structs) into an alloca unconditionally, just so
5155
// that we don't have to deal with having two pathways
5256
// (gep vs extractvalue etc).
53-
analyzer.mark_as_lvalue(index);
57+
analyzer.mark_as_lvalue(mir::Local::new(index));
5458
}
5559
}
5660

57-
analyzer.lvalue_temps
61+
analyzer.lvalue_locals
5862
}
5963

60-
struct TempAnalyzer<'mir, 'bcx: 'mir, 'tcx: 'bcx> {
64+
struct LocalAnalyzer<'mir, 'bcx: 'mir, 'tcx: 'bcx> {
6165
mir: &'mir mir::Mir<'tcx>,
6266
bcx: &'mir BlockAndBuilder<'bcx, 'tcx>,
63-
lvalue_temps: BitVector,
67+
lvalue_locals: BitVector,
6468
seen_assigned: BitVector
6569
}
6670

67-
impl<'mir, 'bcx, 'tcx> TempAnalyzer<'mir, 'bcx, 'tcx> {
71+
impl<'mir, 'bcx, 'tcx> LocalAnalyzer<'mir, 'bcx, 'tcx> {
6872
fn new(mir: &'mir mir::Mir<'tcx>,
69-
bcx: &'mir BlockAndBuilder<'bcx, 'tcx>,
70-
temp_count: usize) -> TempAnalyzer<'mir, 'bcx, 'tcx> {
71-
TempAnalyzer {
73+
bcx: &'mir BlockAndBuilder<'bcx, 'tcx>)
74+
-> LocalAnalyzer<'mir, 'bcx, 'tcx> {
75+
let local_count = mir.count_locals();
76+
LocalAnalyzer {
7277
mir: mir,
7378
bcx: bcx,
74-
lvalue_temps: BitVector::new(temp_count),
75-
seen_assigned: BitVector::new(temp_count)
79+
lvalue_locals: BitVector::new(local_count),
80+
seen_assigned: BitVector::new(local_count)
7681
}
7782
}
7883

79-
fn mark_as_lvalue(&mut self, temp: usize) {
80-
debug!("marking temp {} as lvalue", temp);
81-
self.lvalue_temps.insert(temp);
84+
fn mark_as_lvalue(&mut self, local: mir::Local) {
85+
debug!("marking {:?} as lvalue", local);
86+
self.lvalue_locals.insert(local.index());
8287
}
8388

84-
fn mark_assigned(&mut self, temp: usize) {
85-
if !self.seen_assigned.insert(temp) {
86-
self.mark_as_lvalue(temp);
89+
fn mark_assigned(&mut self, local: mir::Local) {
90+
if !self.seen_assigned.insert(local.index()) {
91+
self.mark_as_lvalue(local);
8792
}
8893
}
8994
}
9095

91-
impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> {
96+
impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> {
9297
fn visit_assign(&mut self,
9398
block: mir::BasicBlock,
9499
lvalue: &mir::Lvalue<'tcx>,
95100
rvalue: &mir::Rvalue<'tcx>) {
96101
debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue);
97102

98-
match *lvalue {
99-
mir::Lvalue::Temp(temp) => {
100-
self.mark_assigned(temp.index());
101-
if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) {
102-
self.mark_as_lvalue(temp.index());
103-
}
104-
}
105-
_ => {
106-
self.visit_lvalue(lvalue, LvalueContext::Store);
103+
if let Some(index) = self.mir.local_index(lvalue) {
104+
self.mark_assigned(index);
105+
if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) {
106+
self.mark_as_lvalue(index);
107107
}
108+
} else {
109+
self.visit_lvalue(lvalue, LvalueContext::Store);
108110
}
109111

110112
self.visit_rvalue(rvalue);
111113
}
112114

115+
fn visit_terminator_kind(&mut self,
116+
block: mir::BasicBlock,
117+
kind: &mir::TerminatorKind<'tcx>) {
118+
match *kind {
119+
mir::TerminatorKind::Call {
120+
func: mir::Operand::Constant(mir::Constant {
121+
literal: mir::Literal::Item { def_id, .. }, ..
122+
}),
123+
ref args, ..
124+
} if Some(def_id) == self.bcx.tcx().lang_items.box_free_fn() => {
125+
// box_free(x) shares with `drop x` the property that it
126+
// is not guaranteed to be statically dominated by the
127+
// definition of x, so x must always be in an alloca.
128+
if let mir::Operand::Consume(ref lvalue) = args[0] {
129+
self.visit_lvalue(lvalue, LvalueContext::Drop);
130+
}
131+
}
132+
_ => {}
133+
}
134+
135+
self.super_terminator_kind(block, kind);
136+
}
137+
113138
fn visit_lvalue(&mut self,
114139
lvalue: &mir::Lvalue<'tcx>,
115140
context: LvalueContext) {
116141
debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
117142

118143
// Allow uses of projections of immediate pair fields.
119144
if let mir::Lvalue::Projection(ref proj) = *lvalue {
120-
if let mir::Lvalue::Temp(temp) = proj.base {
121-
let ty = self.mir.temp_decls[temp].ty;
122-
let ty = self.bcx.monomorphize(&ty);
145+
if self.mir.local_index(&proj.base).is_some() {
146+
let ty = self.mir.lvalue_ty(self.bcx.tcx(), &proj.base);
147+
let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
123148
if common::type_is_imm_pair(self.bcx.ccx(), ty) {
124149
if let mir::ProjectionElem::Field(..) = proj.elem {
125150
if let LvalueContext::Consume = context {
@@ -130,34 +155,30 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for TempAnalyzer<'mir, 'bcx, 'tcx> {
130155
}
131156
}
132157

133-
match *lvalue {
134-
mir::Lvalue::Temp(temp) => {
135-
match context {
136-
LvalueContext::Call => {
137-
self.mark_assigned(temp.index());
138-
}
139-
LvalueContext::Consume => {
140-
}
141-
LvalueContext::Store |
142-
LvalueContext::Inspect |
143-
LvalueContext::Borrow { .. } |
144-
LvalueContext::Slice { .. } |
145-
LvalueContext::Projection => {
146-
self.mark_as_lvalue(temp.index());
147-
}
148-
LvalueContext::Drop => {
149-
let ty = self.mir.temp_decls[index as usize].ty;
150-
let ty = self.bcx.monomorphize(&ty);
158+
if let Some(index) = self.mir.local_index(lvalue) {
159+
match context {
160+
LvalueContext::Call => {
161+
self.mark_assigned(index);
162+
}
163+
LvalueContext::Consume => {
164+
}
165+
LvalueContext::Store |
166+
LvalueContext::Inspect |
167+
LvalueContext::Borrow { .. } |
168+
LvalueContext::Slice { .. } |
169+
LvalueContext::Projection => {
170+
self.mark_as_lvalue(index);
171+
}
172+
LvalueContext::Drop => {
173+
let ty = self.mir.lvalue_ty(self.bcx.tcx(), lvalue);
174+
let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
151175

152-
// Only need the lvalue if we're actually dropping it.
153-
if glue::type_needs_drop(self.bcx.tcx(), ty) {
154-
self.mark_as_lvalue(index as usize);
155-
}
176+
// Only need the lvalue if we're actually dropping it.
177+
if glue::type_needs_drop(self.bcx.tcx(), ty) {
178+
self.mark_as_lvalue(index);
156179
}
157180
}
158181
}
159-
_ => {
160-
}
161182
}
162183

163184
// A deref projection only reads the pointer, never needs the lvalue.

0 commit comments

Comments
 (0)