1212//! which do not.
1313
1414use rustc_data_structures:: bitvec:: BitVector ;
15+ use rustc_data_structures:: control_flow_graph:: dominators:: Dominators ;
1516use rustc_data_structures:: indexed_vec:: { Idx , IndexVec } ;
1617use rustc:: mir:: { self , Location , TerminatorKind } ;
1718use rustc:: mir:: visit:: { Visitor , PlaceContext } ;
@@ -21,7 +22,7 @@ use rustc::ty::layout::LayoutOf;
2122use type_of:: LayoutLlvmExt ;
2223use 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
5354struct 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
5963impl < ' 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 }
0 commit comments