Skip to content

Commit 5dc896e

Browse files
committed
Auto merge of #50048 - glandium:issue50041, r=eddyb
rustc_trans: also check dominators for SSA values in mir::analyze Fixes #50041
2 parents e0f9b32 + 45fd741 commit 5dc896e

File tree

2 files changed

+60
-27
lines changed

2 files changed

+60
-27
lines changed

src/librustc_trans/mir/analyze.rs

+59-26
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! which do not.
1313
1414
use rustc_data_structures::bitvec::BitVector;
15+
use rustc_data_structures::control_flow_graph::dominators::Dominators;
1516
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
1617
use rustc::mir::{self, Location, TerminatorKind};
1718
use rustc::mir::visit::{Visitor, PlaceContext};
@@ -21,7 +22,7 @@ use rustc::ty::layout::LayoutOf;
2122
use type_of::LayoutLlvmExt;
2223
use super::FunctionCx;
2324

24-
pub fn memory_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector {
25+
pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector {
2526
let mir = fx.mir;
2627
let mut analyzer = LocalAnalyzer::new(fx);
2728

@@ -43,43 +44,60 @@ pub fn memory_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector {
4344
// (e.g. structs) into an alloca unconditionally, just so
4445
// that we don't have to deal with having two pathways
4546
// (gep vs extractvalue etc).
46-
analyzer.mark_as_memory(mir::Local::new(index));
47+
analyzer.not_ssa(mir::Local::new(index));
4748
}
4849
}
4950

50-
analyzer.memory_locals
51+
analyzer.non_ssa_locals
5152
}
5253

5354
struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> {
5455
fx: &'mir FunctionCx<'a, 'tcx>,
55-
memory_locals: BitVector,
56-
seen_assigned: BitVector
56+
dominators: Dominators<mir::BasicBlock>,
57+
non_ssa_locals: BitVector,
58+
// The location of the first visited direct assignment to each
59+
// local, or an invalid location (out of bounds `block` index).
60+
first_assignment: IndexVec<mir::Local, Location>
5761
}
5862

5963
impl<'mir, 'a, 'tcx> LocalAnalyzer<'mir, 'a, 'tcx> {
6064
fn new(fx: &'mir FunctionCx<'a, 'tcx>) -> LocalAnalyzer<'mir, 'a, 'tcx> {
65+
let invalid_location =
66+
mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location();
6167
let mut analyzer = LocalAnalyzer {
6268
fx,
63-
memory_locals: BitVector::new(fx.mir.local_decls.len()),
64-
seen_assigned: BitVector::new(fx.mir.local_decls.len())
69+
dominators: fx.mir.dominators(),
70+
non_ssa_locals: BitVector::new(fx.mir.local_decls.len()),
71+
first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls)
6572
};
6673

6774
// Arguments get assigned to by means of the function being called
68-
for idx in 0..fx.mir.arg_count {
69-
analyzer.seen_assigned.insert(idx + 1);
75+
for arg in fx.mir.args_iter() {
76+
analyzer.first_assignment[arg] = mir::START_BLOCK.start_location();
7077
}
7178

7279
analyzer
7380
}
7481

75-
fn mark_as_memory(&mut self, local: mir::Local) {
76-
debug!("marking {:?} as memory", local);
77-
self.memory_locals.insert(local.index());
82+
fn first_assignment(&self, local: mir::Local) -> Option<Location> {
83+
let location = self.first_assignment[local];
84+
if location.block.index() < self.fx.mir.basic_blocks().len() {
85+
Some(location)
86+
} else {
87+
None
88+
}
7889
}
7990

80-
fn mark_assigned(&mut self, local: mir::Local) {
81-
if !self.seen_assigned.insert(local.index()) {
82-
self.mark_as_memory(local);
91+
fn not_ssa(&mut self, local: mir::Local) {
92+
debug!("marking {:?} as non-SSA", local);
93+
self.non_ssa_locals.insert(local.index());
94+
}
95+
96+
fn assign(&mut self, local: mir::Local, location: Location) {
97+
if self.first_assignment(local).is_some() {
98+
self.not_ssa(local);
99+
} else {
100+
self.first_assignment[local] = location;
83101
}
84102
}
85103
}
@@ -93,9 +111,9 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
93111
debug!("visit_assign(block={:?}, place={:?}, rvalue={:?})", block, place, rvalue);
94112

95113
if let mir::Place::Local(index) = *place {
96-
self.mark_assigned(index);
114+
self.assign(index, location);
97115
if !self.fx.rvalue_creates_operand(rvalue) {
98-
self.mark_as_memory(index);
116+
self.not_ssa(index);
99117
}
100118
} else {
101119
self.visit_place(place, PlaceContext::Store, location);
@@ -161,7 +179,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
161179
if layout.is_llvm_immediate() || layout.is_llvm_scalar_pair() {
162180
// Recurse with the same context, instead of `Projection`,
163181
// potentially stopping at non-operand projections,
164-
// which would trigger `mark_as_memory` on locals.
182+
// which would trigger `not_ssa` on locals.
165183
self.visit_place(&proj.base, context, location);
166184
return;
167185
}
@@ -178,35 +196,50 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
178196
}
179197

180198
fn visit_local(&mut self,
181-
&index: &mir::Local,
199+
&local: &mir::Local,
182200
context: PlaceContext<'tcx>,
183-
_: Location) {
201+
location: Location) {
184202
match context {
185203
PlaceContext::Call => {
186-
self.mark_assigned(index);
204+
self.assign(local, location);
187205
}
188206

189207
PlaceContext::StorageLive |
190208
PlaceContext::StorageDead |
191-
PlaceContext::Validate |
209+
PlaceContext::Validate => {}
210+
192211
PlaceContext::Copy |
193-
PlaceContext::Move => {}
212+
PlaceContext::Move => {
213+
// Reads from uninitialized variables (e.g. in dead code, after
214+
// optimizations) require locals to be in (uninitialized) memory.
215+
// NB: there can be uninitialized reads of a local visited after
216+
// an assignment to that local, if they happen on disjoint paths.
217+
let ssa_read = match self.first_assignment(local) {
218+
Some(assignment_location) => {
219+
assignment_location.dominates(location, &self.dominators)
220+
}
221+
None => false
222+
};
223+
if !ssa_read {
224+
self.not_ssa(local);
225+
}
226+
}
194227

195228
PlaceContext::Inspect |
196229
PlaceContext::Store |
197230
PlaceContext::AsmOutput |
198231
PlaceContext::Borrow { .. } |
199232
PlaceContext::Projection(..) => {
200-
self.mark_as_memory(index);
233+
self.not_ssa(local);
201234
}
202235

203236
PlaceContext::Drop => {
204-
let ty = mir::Place::Local(index).ty(self.fx.mir, self.fx.cx.tcx);
237+
let ty = mir::Place::Local(local).ty(self.fx.mir, self.fx.cx.tcx);
205238
let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx));
206239

207240
// Only need the place if we're actually dropping it.
208241
if self.fx.cx.type_needs_drop(ty) {
209-
self.mark_as_memory(index);
242+
self.not_ssa(local);
210243
}
211244
}
212245
}

src/librustc_trans/mir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ pub fn trans_mir<'a, 'tcx: 'a>(
252252
},
253253
};
254254

255-
let memory_locals = analyze::memory_locals(&fx);
255+
let memory_locals = analyze::non_ssa_locals(&fx);
256256

257257
// Allocate variable and temp allocas
258258
fx.locals = {

0 commit comments

Comments
 (0)