@@ -227,12 +227,13 @@ struct VnState<'body, 'a, 'tcx> {
227227 local_decls : & ' body LocalDecls < ' tcx > ,
228228 is_coroutine : bool ,
229229 /// Value stored in each local.
230- locals : IndexVec < Local , VnIndex > ,
230+ locals : IndexVec < Local , Option < VnIndex > > ,
231231 /// Locals that are assigned that value.
232232 // This vector holds the locals that are SSA.
233- rev_locals_ssa : IndexVec < VnIndex , SmallVec < [ ( Local , Location ) ; 1 ] > > ,
234- // This vector holds the locals that are not SSA.
235- rev_locals_non_ssa : FxHashMap < VnIndex , SmallVec < [ ( Local , Location ) ; 1 ] > > ,
233+ rev_locals_ssa : IndexVec < VnIndex , SmallVec < [ ( Local , BasicBlock ) ; 1 ] > > ,
234+ // This map holds the locals that are not SSA. This map is cleared at the end of each block.
235+ // Therefore, we do not need a location, the local always appears before the current location.
236+ rev_locals_non_ssa : FxHashMap < VnIndex , SmallVec < [ Local ; 1 ] > > ,
236237 values : FxIndexSet < ( Value < ' a , ' tcx > , Ty < ' tcx > ) > ,
237238 /// Values evaluated as constants if possible.
238239 evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
@@ -268,7 +269,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
268269 ecx : InterpCx :: new ( tcx, DUMMY_SP , typing_env, DummyMachine ) ,
269270 local_decls,
270271 is_coroutine : body. coroutine . is_some ( ) ,
271- locals : IndexVec :: with_capacity ( body. local_decls . len ( ) ) ,
272+ locals : IndexVec :: from_elem ( None , & body. local_decls ) ,
272273 rev_locals_ssa : IndexVec :: with_capacity ( num_values) ,
273274 rev_locals_non_ssa : FxHashMap :: default ( ) ,
274275 values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
@@ -280,14 +281,12 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
280281 reused_locals : DenseBitSet :: new_empty ( local_decls. len ( ) ) ,
281282 arena,
282283 } ;
283- let init_loc = Location { block : START_BLOCK , statement_index : 0 } ;
284- for decl in body. local_decls . iter ( ) {
285- let value = this. new_opaque ( decl. ty ) ;
286- let local = this. locals . push ( value) ;
284+ for local in body. args_iter ( ) {
287285 if ssa. is_ssa ( local) {
288- this. rev_locals_ssa [ value] . push ( ( local, init_loc) ) ;
289- } else {
290- this. rev_locals_non_ssa . entry ( value) . or_default ( ) . push ( ( local, init_loc) ) ;
286+ let ty = body. local_decls [ local] . ty ;
287+ let value = this. new_opaque ( ty) ;
288+ this. rev_locals_ssa [ value] . push ( ( local, START_BLOCK ) ) ;
289+ this. locals [ local] = Some ( value) ;
291290 }
292291 }
293292 this
@@ -344,7 +343,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
344343
345344 let mut projection = place. projection . iter ( ) ;
346345 let base = if place. is_indirect_first_projection ( ) {
347- let base = self . locals [ place. local ] ;
346+ let base = self . local ( place. local ) ;
348347 // Skip the initial `Deref`.
349348 projection. next ( ) ;
350349 AddressBase :: Deref ( base)
@@ -356,7 +355,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
356355 . arena
357356 . try_alloc_from_iter (
358357 projection
359- . map ( |proj| proj. try_map ( |value| Some ( self . locals [ value] ) , |ty| ty) . ok_or ( ( ) ) ) ,
358+ . map ( |proj| proj. try_map ( |value| Some ( self . local ( value) ) , |ty| ty) . ok_or ( ( ) ) ) ,
360359 )
361360 . ok ( ) ?;
362361 let value = Value :: Address { base, projection, kind, provenance : self . next_opaque ( ) } ;
@@ -376,12 +375,24 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
376375 /// Record that `local` is assigned `value`.
377376 #[ instrument( level = "trace" , skip( self ) ) ]
378377 fn assign ( & mut self , local : Local , value : VnIndex , loc : Location ) {
379- self . locals [ local] = value;
378+ self . locals [ local] = Some ( value) ;
380379 if self . ssa . is_ssa ( local) {
381- self . rev_locals_ssa [ value] . push ( ( local, loc) ) ;
380+ self . rev_locals_ssa [ value] . push ( ( local, loc. block ) ) ;
382381 } else {
383- self . rev_locals_non_ssa . entry ( value) . or_default ( ) . push ( ( local, loc) ) ;
382+ self . rev_locals_non_ssa . entry ( value) . or_default ( ) . push ( local) ;
383+ }
384+ }
385+
386+ /// Return the value assigned to a local, or assign an opaque value and return it.
387+ #[ instrument( level = "trace" , skip( self ) , ret) ]
388+ fn local ( & mut self , local : Local ) -> VnIndex {
389+ if let Some ( value) = self . locals [ local] {
390+ return value;
384391 }
392+ let value = self . new_opaque ( self . local_decls [ local] . ty ) ;
393+ self . locals [ local] = Some ( value) ;
394+ self . rev_locals_non_ssa . entry ( value) . or_default ( ) . push ( local) ;
395+ value
385396 }
386397
387398 #[ instrument( level = "trace" , skip( self ) ) ]
@@ -390,9 +401,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
390401 if this. ssa . is_ssa ( local) {
391402 return ;
392403 }
393- let value = this. locals [ local] ;
394- this. rev_locals_non_ssa . entry ( value) . or_default ( ) . retain ( |( l , _ ) | * l != local) ;
395- this . locals [ local ] = this . new_opaque ( this . ty ( value ) ) ;
404+ if let Some ( value) = this. locals [ local] . take ( ) {
405+ this. rev_locals_non_ssa . entry ( value) . or_default ( ) . retain ( |l | * l != local) ;
406+ }
396407 } ;
397408 if place. is_indirect_first_projection ( ) {
398409 // Non-local mutation maybe invalidate deref.
@@ -668,7 +679,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
668679 let ( mut place_ty, mut value) = match base {
669680 // The base is a local, so we take the local's value and project from it.
670681 AddressBase :: Local ( local) => {
671- let local = self . locals [ local] ;
682+ let local = self . local ( local ) ;
672683 let place_ty = PlaceTy :: from_ty ( self . ty ( local) ) ;
673684 ( place_ty, local)
674685 }
@@ -774,7 +785,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
774785 // If the projection is indirect, we treat the local as a value, so can replace it with
775786 // another local.
776787 if place. is_indirect_first_projection ( )
777- && let base = self . locals [ place. local ]
788+ && let base = self . local ( place. local )
778789 && let Some ( new_local) = self . try_as_local ( base, location)
779790 && place. local != new_local
780791 {
@@ -787,7 +798,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
787798 for i in 0 ..projection. len ( ) {
788799 let elem = projection[ i] ;
789800 if let ProjectionElem :: Index ( idx_local) = elem {
790- let idx = self . locals [ idx_local] ;
801+ let idx = self . local ( idx_local) ;
791802 if let Some ( offset) = self . evaluated [ idx] . as_ref ( )
792803 && let Some ( offset) = self . ecx . read_target_usize ( offset) . discard_err ( )
793804 && let Some ( min_length) = offset. checked_add ( 1 )
@@ -823,7 +834,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
823834 let mut place_ref = place. as_ref ( ) ;
824835
825836 // Invariant: `value` holds the value up-to the `index`th projection excluded.
826- let mut value = self . locals [ place. local ] ;
837+ let mut value = self . local ( place. local ) ;
827838 // Invariant: `value` has type `place_ty`, with optional downcast variant if needed.
828839 let mut place_ty = PlaceTy :: from_ty ( self . local_decls [ place. local ] . ty ) ;
829840 for ( index, proj) in place. projection . iter ( ) . enumerate ( ) {
@@ -834,7 +845,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
834845 place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
835846 }
836847
837- let Some ( proj) = proj. try_map ( |value| Some ( self . locals [ value] ) , |ty| ty) else {
848+ let Some ( proj) = proj. try_map ( |value| Some ( self . local ( value) ) , |ty| ty) else {
838849 return Err ( place_ref) ;
839850 } ;
840851 let Some ( ty_and_value) = self . project ( place_ty, value, proj) else {
@@ -1770,15 +1781,15 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
17701781 #[ instrument( level = "trace" , skip( self ) , ret) ]
17711782 fn try_as_local ( & mut self , index : VnIndex , loc : Location ) -> Option < Local > {
17721783 let ssa = self . rev_locals_ssa . get ( index) ?;
1773- let non_ssa = self . rev_locals_non_ssa . entry ( index ) . or_default ( ) ;
1774- ssa. iter ( )
1775- . chain ( non_ssa . iter ( ) )
1776- . find ( | & & ( other, assign_loc ) | {
1777- self . ssa . assignment_dominates ( & self . dominators , other , loc )
1778- || ( assign_loc . block == loc . block
1779- && assign_loc . statement_index < loc . statement_index )
1780- } )
1781- . map ( | & ( other , _ ) | other )
1784+ if let Some ( ( other , _ ) ) = ssa . iter ( ) . find ( | & & ( other , assign_block ) | {
1785+ self . ssa . assignment_dominates ( & self . dominators , other , loc ) || assign_block == loc . block
1786+ } ) {
1787+ Some ( * other)
1788+ } else if let Some ( non_ssa ) = self . rev_locals_non_ssa . get ( & index ) {
1789+ non_ssa . first ( ) . copied ( )
1790+ } else {
1791+ None
1792+ }
17821793 }
17831794}
17841795
@@ -1791,13 +1802,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
17911802 self . rev_locals_non_ssa . clear ( ) ;
17921803 for local in self . locals . indices ( ) {
17931804 if !self . ssa . is_ssa ( local) {
1794- let current = self . locals [ local] ;
1795- let new = self . new_opaque ( self . ty ( current) ) ;
1796- self . locals [ local] = new;
1797- self . rev_locals_non_ssa
1798- . entry ( new)
1799- . or_default ( )
1800- . push ( ( local, Location { block, statement_index : 0 } ) ) ;
1805+ self . locals [ local] = None ;
18011806 }
18021807 }
18031808 self . super_basic_block_data ( block, bbdata) ;
0 commit comments