@@ -49,9 +49,13 @@ impl SmallDominators<'_> {
4949 let assign_dominates = match * set {
5050 Set1 :: Empty | Set1 :: Many => false ,
5151 Set1 :: One ( LocationExtended :: Arg ) => true ,
52- Set1 :: One ( LocationExtended :: Plain ( assign) ) => {
52+ Set1 :: One ( LocationExtended :: Assign ( assign) ) => {
5353 self . dominates ( assign. successor_within_block ( ) , loc)
5454 }
55+ Set1 :: One ( LocationExtended :: Terminator ( _, effect_bb) ) => {
56+ let effect_loc = Location { block : effect_bb, statement_index : 0 } ;
57+ self . dominates ( effect_loc, loc)
58+ }
5559 } ;
5660 // We are visiting a use that is not dominated by an assignment.
5761 // Either there is a cycle involved, or we are reading for uninitialized local.
@@ -62,6 +66,12 @@ impl SmallDominators<'_> {
6266 }
6367}
6468
69+ pub enum AssignedValue < ' a , ' tcx > {
70+ Arg ,
71+ Rvalue ( & ' a mut Rvalue < ' tcx > ) ,
72+ Terminator ( & ' a mut TerminatorKind < ' tcx > ) ,
73+ }
74+
6575impl SsaLocals {
6676 pub fn new < ' tcx > ( body : & Body < ' tcx > ) -> SsaLocals {
6777 let assignment_order = Vec :: with_capacity ( body. local_decls . len ( ) ) ;
@@ -72,10 +82,12 @@ impl SsaLocals {
7282 let dominators = SmallDominators { inner : dominators } ;
7383
7484 let direct_uses = IndexVec :: from_elem ( 0 , & body. local_decls ) ;
75- let mut visitor = SsaVisitor { assignments, assignment_order, dominators, direct_uses } ;
85+ let mut visitor =
86+ SsaVisitor { body, assignments, assignment_order, dominators, direct_uses } ;
7687
7788 for local in body. args_iter ( ) {
7889 visitor. assignments [ local] = Set1 :: One ( LocationExtended :: Arg ) ;
90+ visitor. assignment_order . push ( local) ;
7991 }
8092
8193 if body. basic_blocks . len ( ) > 2 {
@@ -136,13 +148,16 @@ impl SsaLocals {
136148 ) -> bool {
137149 match self . assignments [ local] {
138150 Set1 :: One ( LocationExtended :: Arg ) => true ,
139- Set1 :: One ( LocationExtended :: Plain ( ass) ) => {
151+ Set1 :: One ( LocationExtended :: Assign ( ass) ) => {
140152 if ass. block == location. block {
141153 ass. statement_index < location. statement_index
142154 } else {
143155 dominators. dominates ( ass. block , location. block )
144156 }
145157 }
158+ Set1 :: One ( LocationExtended :: Terminator ( _, effect_bb) ) => {
159+ dominators. dominates ( effect_bb, location. block )
160+ }
146161 _ => false ,
147162 }
148163 }
@@ -152,7 +167,7 @@ impl SsaLocals {
152167 body : & ' a Body < ' tcx > ,
153168 ) -> impl Iterator < Item = ( Local , & ' a Rvalue < ' tcx > , Location ) > + ' a {
154169 self . assignment_order . iter ( ) . filter_map ( |& local| {
155- if let Set1 :: One ( LocationExtended :: Plain ( loc) ) = self . assignments [ local] {
170+ if let Set1 :: One ( LocationExtended :: Assign ( loc) ) = self . assignments [ local] {
156171 // `loc` must point to a direct assignment to `local`.
157172 let Either :: Left ( stmt) = body. stmt_at ( loc) else { bug ! ( ) } ;
158173 let Some ( ( target, rvalue) ) = stmt. kind . as_assign ( ) else { bug ! ( ) } ;
@@ -166,18 +181,33 @@ impl SsaLocals {
166181
167182 pub fn for_each_assignment_mut < ' tcx > (
168183 & self ,
169- basic_blocks : & mut BasicBlocks < ' tcx > ,
170- mut f : impl FnMut ( Local , & mut Rvalue < ' tcx > , Location ) ,
184+ basic_blocks : & mut IndexSlice < BasicBlock , BasicBlockData < ' tcx > > ,
185+ mut f : impl FnMut ( Local , AssignedValue < ' _ , ' tcx > , Location ) ,
171186 ) {
172187 for & local in & self . assignment_order {
173- if let Set1 :: One ( LocationExtended :: Plain ( loc) ) = self . assignments [ local] {
174- // `loc` must point to a direct assignment to `local`.
175- let bbs = basic_blocks. as_mut_preserves_cfg ( ) ;
176- let bb = & mut bbs[ loc. block ] ;
177- let stmt = & mut bb. statements [ loc. statement_index ] ;
178- let StatementKind :: Assign ( box ( target, ref mut rvalue) ) = stmt. kind else { bug ! ( ) } ;
179- assert_eq ! ( target. as_local( ) , Some ( local) ) ;
180- f ( local, rvalue, loc)
188+ match self . assignments [ local] {
189+ Set1 :: One ( LocationExtended :: Arg ) => f (
190+ local,
191+ AssignedValue :: Arg ,
192+ Location { block : START_BLOCK , statement_index : 0 } ,
193+ ) ,
194+ Set1 :: One ( LocationExtended :: Assign ( loc) ) => {
195+ // `loc` must point to a direct assignment to `local`.
196+ let bb = & mut basic_blocks[ loc. block ] ;
197+ let stmt = & mut bb. statements [ loc. statement_index ] ;
198+ let StatementKind :: Assign ( box ( target, ref mut rvalue) ) = stmt. kind else {
199+ bug ! ( )
200+ } ;
201+ assert_eq ! ( target. as_local( ) , Some ( local) ) ;
202+ f ( local, AssignedValue :: Rvalue ( rvalue) , loc)
203+ }
204+ Set1 :: One ( LocationExtended :: Terminator ( block, _) ) => {
205+ let loc =
206+ Location { block, statement_index : basic_blocks[ block] . statements . len ( ) } ;
207+ let term = basic_blocks[ block] . terminator_mut ( ) ;
208+ f ( local, AssignedValue :: Terminator ( & mut term. kind ) , loc)
209+ }
210+ _ => { }
181211 }
182212 }
183213 }
@@ -230,18 +260,24 @@ impl SsaLocals {
230260
231261#[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
232262enum LocationExtended {
233- Plain ( Location ) ,
263+ /// This local was assigned as a function parameter, before any execution.
234264 Arg ,
265+ /// `Location` points to the `Assign` statement.
266+ Assign ( Location ) ,
267+ /// The blocks are respectively the bb which contains the assignment,
268+ /// and the bb in which the assignment effect is complete.
269+ Terminator ( BasicBlock , BasicBlock ) ,
235270}
236271
237- struct SsaVisitor < ' a > {
272+ struct SsaVisitor < ' a , ' tcx > {
273+ body : & ' a Body < ' tcx > ,
238274 dominators : SmallDominators < ' a > ,
239275 assignments : IndexVec < Local , Set1 < LocationExtended > > ,
240276 assignment_order : Vec < Local > ,
241277 direct_uses : IndexVec < Local , u32 > ,
242278}
243279
244- impl < ' tcx > Visitor < ' tcx > for SsaVisitor < ' _ > {
280+ impl < ' tcx > Visitor < ' tcx > for SsaVisitor < ' _ , ' tcx > {
245281 fn visit_local ( & mut self , local : Local , ctxt : PlaceContext , loc : Location ) {
246282 match ctxt {
247283 PlaceContext :: MutatingUse ( MutatingUseContext :: Projection )
@@ -266,34 +302,46 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> {
266302 }
267303
268304 fn visit_place ( & mut self , place : & Place < ' tcx > , ctxt : PlaceContext , loc : Location ) {
269- if place. projection . first ( ) == Some ( & PlaceElem :: Deref ) {
270- // Do not do anything for storage statements and debuginfo.
305+ let location = match ctxt {
306+ PlaceContext :: MutatingUse ( MutatingUseContext :: Store ) => {
307+ Some ( LocationExtended :: Assign ( loc) )
308+ }
309+ PlaceContext :: MutatingUse ( MutatingUseContext :: Call | MutatingUseContext :: Yield ) => {
310+ // The assignment happens on the `loc -> target` edge. We need to ensure that
311+ // this *edge* dominates all uses of the local. This is true if
312+ // `loc` dominates `target` *and* `target` dominates all uses.
313+ if let Some ( target) = self . body . basic_blocks [ loc. block ] . terminator ( ) . successors ( ) . next ( )
314+ && self . dominators . dominates ( loc, Location { block : target, statement_index : 0 } )
315+ {
316+ Some ( LocationExtended :: Terminator ( loc. block , target) )
317+ } else {
318+ None
319+ }
320+ }
321+ _ => None ,
322+ } ;
323+ if let Some ( location) = location
324+ && let Some ( local) = place. as_local ( )
325+ {
326+ self . assignments [ local] . insert ( location) ;
327+ if let Set1 :: One ( _) = self . assignments [ local] {
328+ // Only record if SSA-like, to avoid growing the vector needlessly.
329+ self . assignment_order . push ( local) ;
330+ }
331+ } else if place. projection . first ( ) == Some ( & PlaceElem :: Deref ) {
332+ // Do not do anything for debuginfo.
271333 if ctxt. is_use ( ) {
272334 // Only change the context if it is a real use, not a "use" in debuginfo.
273335 let new_ctxt = PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: Copy ) ;
274336
275337 self . visit_projection ( place. as_ref ( ) , new_ctxt, loc) ;
276338 self . dominators . check_dominates ( & mut self . assignments [ place. local ] , loc) ;
277339 }
278- return ;
279340 } else {
280341 self . visit_projection ( place. as_ref ( ) , ctxt, loc) ;
281342 self . visit_local ( place. local , ctxt, loc) ;
282343 }
283344 }
284-
285- fn visit_assign ( & mut self , place : & Place < ' tcx > , rvalue : & Rvalue < ' tcx > , loc : Location ) {
286- if let Some ( local) = place. as_local ( ) {
287- self . assignments [ local] . insert ( LocationExtended :: Plain ( loc) ) ;
288- if let Set1 :: One ( _) = self . assignments [ local] {
289- // Only record if SSA-like, to avoid growing the vector needlessly.
290- self . assignment_order . push ( local) ;
291- }
292- } else {
293- self . visit_place ( place, PlaceContext :: MutatingUse ( MutatingUseContext :: Store ) , loc) ;
294- }
295- self . visit_rvalue ( rvalue, loc) ;
296- }
297345}
298346
299347#[ instrument( level = "trace" , skip( ssa, body) ) ]
@@ -376,7 +424,7 @@ impl StorageLiveLocals {
376424 for ( statement_index, statement) in bbdata. statements . iter ( ) . enumerate ( ) {
377425 if let StatementKind :: StorageLive ( local) = statement. kind {
378426 storage_live[ local]
379- . insert ( LocationExtended :: Plain ( Location { block, statement_index } ) ) ;
427+ . insert ( LocationExtended :: Assign ( Location { block, statement_index } ) ) ;
380428 }
381429 }
382430 }
0 commit comments