@@ -94,7 +94,7 @@ use rustc_const_eval::interpret::{
94
94
ImmTy , Immediate , InterpCx , MemPlaceMeta , MemoryKind , OpTy , Projectable , Scalar ,
95
95
intern_const_alloc_for_constprop,
96
96
} ;
97
- use rustc_data_structures:: fx:: { FxIndexSet , MutableValues } ;
97
+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexSet , MutableValues } ;
98
98
use rustc_data_structures:: graph:: dominators:: Dominators ;
99
99
use rustc_hir:: def:: DefKind ;
100
100
use rustc_index:: bit_set:: DenseBitSet ;
@@ -234,8 +234,11 @@ struct VnState<'body, 'a, 'tcx> {
234
234
/// Value stored in each local.
235
235
locals : IndexVec < Local , Option < VnIndex > > ,
236
236
/// Locals that are assigned that value.
237
- // This vector does not hold all the values of `VnIndex` that we create.
238
- rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
237
+ // This vector holds the locals that are SSA.
238
+ rev_locals_ssa : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
239
+ // This map holds the locals that are not SSA. This map is cleared at the end of each block.
240
+ // Therefore, we do not need a location, the local always appears before the current location.
241
+ rev_locals_non_ssa : FxHashMap < VnIndex , SmallVec < [ Local ; 1 ] > > ,
239
242
values : FxIndexSet < ( Value < ' a , ' tcx > , Ty < ' tcx > ) > ,
240
243
/// Values evaluated as constants if possible.
241
244
evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
@@ -271,8 +274,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
271
274
ecx : InterpCx :: new ( tcx, DUMMY_SP , typing_env, DummyMachine ) ,
272
275
local_decls,
273
276
is_coroutine : body. coroutine . is_some ( ) ,
274
- locals : IndexVec :: from_elem ( None , local_decls) ,
275
- rev_locals : IndexVec :: with_capacity ( num_values) ,
277
+ locals : IndexVec :: from_elem ( None , & body. local_decls ) ,
278
+ rev_locals_ssa : IndexVec :: with_capacity ( num_values) ,
279
+ rev_locals_non_ssa : FxHashMap :: default ( ) ,
276
280
values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
277
281
evaluated : IndexVec :: with_capacity ( num_values) ,
278
282
next_opaque : 1 ,
@@ -297,7 +301,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
297
301
let evaluated = self . eval_to_const ( index) ;
298
302
let _index = self . evaluated . push ( evaluated) ;
299
303
debug_assert_eq ! ( index, _index) ;
300
- let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
304
+ let _index = self . rev_locals_ssa . push ( Default :: default ( ) ) ;
301
305
debug_assert_eq ! ( index, _index) ;
302
306
}
303
307
index
@@ -335,7 +339,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
335
339
336
340
let mut projection = place. projection . iter ( ) ;
337
341
let base = if place. is_indirect_first_projection ( ) {
338
- let base = self . locals [ place. local ] ? ;
342
+ let base = self . local ( place. local ) ;
339
343
// Skip the initial `Deref`.
340
344
projection. next ( ) ;
341
345
AddressBase :: Deref ( base)
@@ -346,7 +350,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
346
350
let projection = self
347
351
. arena
348
352
. try_alloc_from_iter (
349
- projection. map ( |proj| proj. try_map ( |value| self . locals [ value] , |ty| ty) . ok_or ( ( ) ) ) ,
353
+ projection
354
+ . map ( |proj| proj. try_map ( |value| Some ( self . local ( value) ) , |ty| ty) . ok_or ( ( ) ) ) ,
350
355
)
351
356
. ok ( ) ?;
352
357
let value = Value :: Address { base, projection, kind, provenance : self . next_opaque ( ) } ;
@@ -363,12 +368,49 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
363
368
self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
364
369
}
365
370
366
- /// Record that `local` is assigned `value`. `local` must be SSA.
371
+ /// Record that `local` is assigned `value`.
367
372
#[ instrument( level = "trace" , skip( self ) ) ]
368
373
fn assign ( & mut self , local : Local , value : VnIndex ) {
369
- debug_assert ! ( self . ssa. is_ssa( local) ) ;
370
374
self . locals [ local] = Some ( value) ;
371
- self . rev_locals [ value] . push ( local) ;
375
+ if self . ssa . is_ssa ( local) {
376
+ self . rev_locals_ssa [ value] . push ( local) ;
377
+ } else {
378
+ self . rev_locals_non_ssa . entry ( value) . or_default ( ) . push ( local) ;
379
+ }
380
+ }
381
+
382
+ /// Return the value assigned to a local, or assign an opaque value and return it.
383
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
384
+ fn local ( & mut self , local : Local ) -> VnIndex {
385
+ if let Some ( value) = self . locals [ local] {
386
+ return value;
387
+ }
388
+ let value = self . new_opaque ( self . local_decls [ local] . ty ) ;
389
+ self . locals [ local] = Some ( value) ;
390
+ self . rev_locals_non_ssa . entry ( value) . or_default ( ) . push ( local) ;
391
+ value
392
+ }
393
+
394
+ #[ instrument( level = "trace" , skip( self ) ) ]
395
+ fn discard_place ( & mut self , place : Place < ' tcx > ) {
396
+ let discard_local = |this : & mut Self , local| {
397
+ if this. ssa . is_ssa ( local) {
398
+ return ;
399
+ }
400
+ if let Some ( value) = this. locals [ local] . take ( ) {
401
+ this. rev_locals_non_ssa . entry ( value) . or_default ( ) . retain ( |l| * l != local) ;
402
+ }
403
+ } ;
404
+ if place. is_indirect_first_projection ( ) {
405
+ // Non-local mutation maybe invalidate deref.
406
+ self . invalidate_derefs ( ) ;
407
+ // Remove stored value from borrowed locals.
408
+ for local in self . ssa . borrowed_locals ( ) . iter ( ) {
409
+ discard_local ( self , local) ;
410
+ }
411
+ } else {
412
+ discard_local ( self , place. local ) ;
413
+ }
372
414
}
373
415
374
416
fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
@@ -633,7 +675,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
633
675
let ( mut place_ty, mut value) = match base {
634
676
// The base is a local, so we take the local's value and project from it.
635
677
AddressBase :: Local ( local) => {
636
- let local = self . locals [ local] ? ;
678
+ let local = self . local ( local ) ;
637
679
let place_ty = PlaceTy :: from_ty ( self . ty ( local) ) ;
638
680
( place_ty, local)
639
681
}
@@ -739,7 +781,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
739
781
// If the projection is indirect, we treat the local as a value, so can replace it with
740
782
// another local.
741
783
if place. is_indirect_first_projection ( )
742
- && let Some ( base) = self . locals [ place. local ]
784
+ && let base = self . local ( place. local )
743
785
&& let Some ( new_local) = self . try_as_local ( base, location)
744
786
&& place. local != new_local
745
787
{
@@ -751,9 +793,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
751
793
752
794
for i in 0 ..projection. len ( ) {
753
795
let elem = projection[ i] ;
754
- if let ProjectionElem :: Index ( idx_local) = elem
755
- && let Some ( idx) = self . locals [ idx_local]
756
- {
796
+ if let ProjectionElem :: Index ( idx_local) = elem {
797
+ let idx = self . local ( idx_local) ;
757
798
if let Some ( offset) = self . evaluated [ idx] . as_ref ( )
758
799
&& let Some ( offset) = self . ecx . read_target_usize ( offset) . discard_err ( )
759
800
&& let Some ( min_length) = offset. checked_add ( 1 )
@@ -789,7 +830,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
789
830
let mut place_ref = place. as_ref ( ) ;
790
831
791
832
// Invariant: `value` holds the value up-to the `index`th projection excluded.
792
- let Some ( mut value) = self . locals [ place. local ] else { return Err ( place_ref ) } ;
833
+ let mut value = self . local ( place. local ) ;
793
834
// Invariant: `value` has type `place_ty`, with optional downcast variant if needed.
794
835
let mut place_ty = PlaceTy :: from_ty ( self . local_decls [ place. local ] . ty ) ;
795
836
for ( index, proj) in place. projection . iter ( ) . enumerate ( ) {
@@ -800,7 +841,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
800
841
place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
801
842
}
802
843
803
- let Some ( proj) = proj. try_map ( |value| self . locals [ value] , |ty| ty) else {
844
+ let Some ( proj) = proj. try_map ( |value| Some ( self . local ( value) ) , |ty| ty) else {
804
845
return Err ( place_ref) ;
805
846
} ;
806
847
let Some ( ty_and_value) = self . project ( place_ty, value, proj) else {
@@ -1709,11 +1750,17 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
1709
1750
/// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`,
1710
1751
/// return it. If you used this local, add it to `reused_locals` to remove storage statements.
1711
1752
fn try_as_local ( & mut self , index : VnIndex , loc : Location ) -> Option < Local > {
1712
- let other = self . rev_locals . get ( index) ?;
1713
- other
1714
- . iter ( )
1715
- . find ( |& & other| self . ssa . assignment_dominates ( & self . dominators , other, loc) )
1716
- . copied ( )
1753
+ if let Some ( ssa) = self . rev_locals_ssa . get ( index)
1754
+ && let Some ( other) = ssa
1755
+ . iter ( )
1756
+ . find ( |& & other| self . ssa . assignment_dominates ( & self . dominators , other, loc) )
1757
+ {
1758
+ Some ( * other)
1759
+ } else if let Some ( non_ssa) = self . rev_locals_non_ssa . get ( & index) {
1760
+ non_ssa. first ( ) . copied ( )
1761
+ } else {
1762
+ None
1763
+ }
1717
1764
}
1718
1765
}
1719
1766
@@ -1722,11 +1769,20 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
1722
1769
self . tcx
1723
1770
}
1724
1771
1772
+ fn visit_basic_block_data ( & mut self , block : BasicBlock , bbdata : & mut BasicBlockData < ' tcx > ) {
1773
+ self . rev_locals_non_ssa . clear ( ) ;
1774
+ for local in self . locals . indices ( ) {
1775
+ if !self . ssa . is_ssa ( local) {
1776
+ self . locals [ local] = None ;
1777
+ }
1778
+ }
1779
+ self . super_basic_block_data ( block, bbdata) ;
1780
+ }
1781
+
1725
1782
fn visit_place ( & mut self , place : & mut Place < ' tcx > , context : PlaceContext , location : Location ) {
1726
1783
self . simplify_place_projection ( place, location) ;
1727
- if context. is_mutating_use ( ) && place. is_indirect ( ) {
1728
- // Non-local mutation maybe invalidate deref.
1729
- self . invalidate_derefs ( ) ;
1784
+ if context. is_mutating_use ( ) {
1785
+ self . discard_place ( * place) ;
1730
1786
}
1731
1787
self . super_place ( place, context, location) ;
1732
1788
}
@@ -1765,13 +1821,9 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
1765
1821
}
1766
1822
}
1767
1823
1768
- if lhs. is_indirect ( ) {
1769
- // Non-local mutation maybe invalidate deref.
1770
- self . invalidate_derefs ( ) ;
1771
- }
1824
+ self . discard_place ( * lhs) ;
1772
1825
1773
1826
if let Some ( local) = lhs. as_local ( )
1774
- && self . ssa . is_ssa ( local)
1775
1827
&& let rvalue_ty = rvalue. ty ( self . local_decls , self . tcx )
1776
1828
// FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
1777
1829
// `local` as reusable if we have an exact type match.
@@ -1783,14 +1835,13 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
1783
1835
}
1784
1836
1785
1837
fn visit_terminator ( & mut self , terminator : & mut Terminator < ' tcx > , location : Location ) {
1786
- if let Terminator { kind : TerminatorKind :: Call { destination, .. } , .. } = terminator {
1787
- if let Some ( local) = destination. as_local ( )
1788
- && self . ssa . is_ssa ( local)
1789
- {
1790
- let ty = self . local_decls [ local] . ty ;
1791
- let opaque = self . new_opaque ( ty) ;
1792
- self . assign ( local, opaque) ;
1793
- }
1838
+ self . super_terminator ( terminator, location) ;
1839
+ if let Terminator { kind : TerminatorKind :: Call { destination, .. } , .. } = terminator
1840
+ && let Some ( local) = destination. as_local ( )
1841
+ {
1842
+ let ty = self . local_decls [ local] . ty ;
1843
+ let opaque = self . new_opaque ( ty) ;
1844
+ self . assign ( local, opaque) ;
1794
1845
}
1795
1846
// Function calls and ASM may invalidate (nested) derefs. We must handle them carefully.
1796
1847
// Currently, only preserving derefs for trivial terminators like SwitchInt and Goto.
@@ -1801,7 +1852,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
1801
1852
if !safe_to_preserve_derefs {
1802
1853
self . invalidate_derefs ( ) ;
1803
1854
}
1804
- self . super_terminator ( terminator, location) ;
1805
1855
}
1806
1856
}
1807
1857
0 commit comments