@@ -227,12 +227,13 @@ struct VnState<'body, 'a, 'tcx> {
227
227
local_decls : & ' body LocalDecls < ' tcx > ,
228
228
is_coroutine : bool ,
229
229
/// Value stored in each local.
230
- locals : IndexVec < Local , VnIndex > ,
230
+ locals : IndexVec < Local , Option < VnIndex > > ,
231
231
/// Locals that are assigned that value.
232
232
// 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 ] > > ,
236
237
values : FxIndexSet < ( Value < ' a , ' tcx > , Ty < ' tcx > ) > ,
237
238
/// Values evaluated as constants if possible.
238
239
evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
@@ -268,7 +269,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
268
269
ecx : InterpCx :: new ( tcx, DUMMY_SP , typing_env, DummyMachine ) ,
269
270
local_decls,
270
271
is_coroutine : body. coroutine . is_some ( ) ,
271
- locals : IndexVec :: with_capacity ( body. local_decls . len ( ) ) ,
272
+ locals : IndexVec :: from_elem ( None , & body. local_decls ) ,
272
273
rev_locals_ssa : IndexVec :: with_capacity ( num_values) ,
273
274
rev_locals_non_ssa : FxHashMap :: default ( ) ,
274
275
values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
@@ -280,14 +281,12 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
280
281
reused_locals : DenseBitSet :: new_empty ( local_decls. len ( ) ) ,
281
282
arena,
282
283
} ;
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 ( ) {
287
285
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) ;
291
290
}
292
291
}
293
292
this
@@ -344,7 +343,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
344
343
345
344
let mut projection = place. projection . iter ( ) ;
346
345
let base = if place. is_indirect_first_projection ( ) {
347
- let base = self . locals [ place. local ] ;
346
+ let base = self . local ( place. local ) ;
348
347
// Skip the initial `Deref`.
349
348
projection. next ( ) ;
350
349
AddressBase :: Deref ( base)
@@ -356,7 +355,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
356
355
. arena
357
356
. try_alloc_from_iter (
358
357
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 ( ( ) ) ) ,
360
359
)
361
360
. ok ( ) ?;
362
361
let value = Value :: Address { base, projection, kind, provenance : self . next_opaque ( ) } ;
@@ -376,12 +375,24 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
376
375
/// Record that `local` is assigned `value`.
377
376
#[ instrument( level = "trace" , skip( self ) ) ]
378
377
fn assign ( & mut self , local : Local , value : VnIndex , loc : Location ) {
379
- self . locals [ local] = value;
378
+ self . locals [ local] = Some ( value) ;
380
379
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 ) ) ;
382
381
} 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;
384
391
}
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
385
396
}
386
397
387
398
#[ instrument( level = "trace" , skip( self ) ) ]
@@ -390,9 +401,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
390
401
if this. ssa . is_ssa ( local) {
391
402
return ;
392
403
}
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
+ }
396
407
} ;
397
408
if place. is_indirect_first_projection ( ) {
398
409
// Non-local mutation maybe invalidate deref.
@@ -668,7 +679,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
668
679
let ( mut place_ty, mut value) = match base {
669
680
// The base is a local, so we take the local's value and project from it.
670
681
AddressBase :: Local ( local) => {
671
- let local = self . locals [ local] ;
682
+ let local = self . local ( local ) ;
672
683
let place_ty = PlaceTy :: from_ty ( self . ty ( local) ) ;
673
684
( place_ty, local)
674
685
}
@@ -774,7 +785,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
774
785
// If the projection is indirect, we treat the local as a value, so can replace it with
775
786
// another local.
776
787
if place. is_indirect_first_projection ( )
777
- && let base = self . locals [ place. local ]
788
+ && let base = self . local ( place. local )
778
789
&& let Some ( new_local) = self . try_as_local ( base, location)
779
790
&& place. local != new_local
780
791
{
@@ -787,7 +798,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
787
798
for i in 0 ..projection. len ( ) {
788
799
let elem = projection[ i] ;
789
800
if let ProjectionElem :: Index ( idx_local) = elem {
790
- let idx = self . locals [ idx_local] ;
801
+ let idx = self . local ( idx_local) ;
791
802
if let Some ( offset) = self . evaluated [ idx] . as_ref ( )
792
803
&& let Some ( offset) = self . ecx . read_target_usize ( offset) . discard_err ( )
793
804
&& let Some ( min_length) = offset. checked_add ( 1 )
@@ -823,7 +834,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
823
834
let mut place_ref = place. as_ref ( ) ;
824
835
825
836
// 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 ) ;
827
838
// Invariant: `value` has type `place_ty`, with optional downcast variant if needed.
828
839
let mut place_ty = PlaceTy :: from_ty ( self . local_decls [ place. local ] . ty ) ;
829
840
for ( index, proj) in place. projection . iter ( ) . enumerate ( ) {
@@ -834,7 +845,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
834
845
place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
835
846
}
836
847
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 {
838
849
return Err ( place_ref) ;
839
850
} ;
840
851
let Some ( ty_and_value) = self . project ( place_ty, value, proj) else {
@@ -1770,15 +1781,15 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
1770
1781
#[ instrument( level = "trace" , skip( self ) , ret) ]
1771
1782
fn try_as_local ( & mut self , index : VnIndex , loc : Location ) -> Option < Local > {
1772
1783
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
+ }
1782
1793
}
1783
1794
}
1784
1795
@@ -1791,13 +1802,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
1791
1802
self . rev_locals_non_ssa . clear ( ) ;
1792
1803
for local in self . locals . indices ( ) {
1793
1804
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 ;
1801
1806
}
1802
1807
}
1803
1808
self . super_basic_block_data ( block, bbdata) ;
0 commit comments