@@ -131,11 +131,6 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
131
131
let mut state =
132
132
VnState :: new ( tcx, body, typing_env, & ssa, dominators, & body. local_decls , & arena) ;
133
133
134
- for local in body. args_iter ( ) . filter ( |& local| ssa. is_ssa ( local) ) {
135
- let opaque = state. new_opaque ( body. local_decls [ local] . ty ) ;
136
- state. assign ( local, opaque) ;
137
- }
138
-
139
134
let reverse_postorder = body. basic_blocks . reverse_postorder ( ) . to_vec ( ) ;
140
135
for bb in reverse_postorder {
141
136
let data = & mut body. basic_blocks . as_mut_preserves_cfg ( ) [ bb] ;
@@ -232,10 +227,10 @@ struct VnState<'body, 'a, 'tcx> {
232
227
local_decls : & ' body LocalDecls < ' tcx > ,
233
228
is_coroutine : bool ,
234
229
/// Value stored in each local.
235
- locals : IndexVec < Local , Option < VnIndex > > ,
230
+ locals : IndexVec < Local , VnIndex > ,
236
231
/// Locals that are assigned that value.
237
232
// This vector does not hold all the values of `VnIndex` that we create.
238
- rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
233
+ rev_locals : IndexVec < VnIndex , SmallVec < [ ( Local , Location ) ; 1 ] > > ,
239
234
values : FxIndexSet < ( Value < ' a , ' tcx > , Ty < ' tcx > ) > ,
240
235
/// Values evaluated as constants if possible.
241
236
evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
@@ -266,12 +261,12 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
266
261
let num_values =
267
262
2 * body. basic_blocks . iter ( ) . map ( |bbdata| bbdata. statements . len ( ) ) . sum :: < usize > ( )
268
263
+ 4 * body. basic_blocks . len ( ) ;
269
- VnState {
264
+ let mut this = VnState {
270
265
tcx,
271
266
ecx : InterpCx :: new ( tcx, DUMMY_SP , typing_env, DummyMachine ) ,
272
267
local_decls,
273
268
is_coroutine : body. coroutine . is_some ( ) ,
274
- locals : IndexVec :: from_elem ( None , local_decls) ,
269
+ locals : IndexVec :: with_capacity ( body . local_decls . len ( ) ) ,
275
270
rev_locals : IndexVec :: with_capacity ( num_values) ,
276
271
values : FxIndexSet :: with_capacity_and_hasher ( num_values, Default :: default ( ) ) ,
277
272
evaluated : IndexVec :: with_capacity ( num_values) ,
@@ -281,7 +276,14 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
281
276
dominators,
282
277
reused_locals : DenseBitSet :: new_empty ( local_decls. len ( ) ) ,
283
278
arena,
279
+ } ;
280
+ let init_loc = Location { block : START_BLOCK , statement_index : 0 } ;
281
+ for decl in body. local_decls . iter ( ) {
282
+ let value = this. new_opaque ( decl. ty ) ;
283
+ let local = this. locals . push ( value) ;
284
+ this. rev_locals [ value] . push ( ( local, init_loc) ) ;
284
285
}
286
+ this
285
287
}
286
288
287
289
fn typing_env ( & self ) -> ty:: TypingEnv < ' tcx > {
@@ -335,7 +337,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
335
337
336
338
let mut projection = place. projection . iter ( ) ;
337
339
let base = if place. is_indirect_first_projection ( ) {
338
- let base = self . locals [ place. local ] ? ;
340
+ let base = self . locals [ place. local ] ;
339
341
// Skip the initial `Deref`.
340
342
projection. next ( ) ;
341
343
AddressBase :: Deref ( base)
@@ -346,7 +348,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
346
348
let projection = self
347
349
. arena
348
350
. try_alloc_from_iter (
349
- projection. map ( |proj| proj. try_map ( |value| self . locals [ value] , |ty| ty) . ok_or ( ( ) ) ) ,
351
+ projection
352
+ . map ( |proj| proj. try_map ( |value| Some ( self . locals [ value] ) , |ty| ty) . ok_or ( ( ) ) ) ,
350
353
)
351
354
. ok ( ) ?;
352
355
let value = Value :: Address { base, projection, kind, provenance : self . next_opaque ( ) } ;
@@ -363,12 +366,39 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
363
366
self . values . get_index ( index. as_usize ( ) ) . unwrap ( ) . 1
364
367
}
365
368
366
- /// Record that `local` is assigned `value`. `local` must be SSA.
369
+ /// Record that `local` is assigned `value`.
367
370
#[ instrument( level = "trace" , skip( self ) ) ]
368
- fn assign ( & mut self , local : Local , value : VnIndex ) {
369
- debug_assert ! ( self . ssa. is_ssa( local) ) ;
370
- self . locals [ local] = Some ( value) ;
371
- self . rev_locals [ value] . push ( local) ;
371
+ fn assign ( & mut self , local : Local , value : VnIndex , loc : Location ) {
372
+ self . locals [ local] = value;
373
+ self . rev_locals [ value] . push ( ( local, loc) ) ;
374
+ }
375
+
376
+ #[ instrument( level = "trace" , skip( self ) ) ]
377
+ fn discard_place ( & mut self , place : Place < ' tcx > ) {
378
+ let discard_local = |this : & mut Self , local| {
379
+ if this. ssa . is_ssa ( local) {
380
+ return ;
381
+ }
382
+ let value = this. locals [ local] ;
383
+ this. rev_locals [ value] . retain ( |( l, _) | * l != local) ;
384
+ this. locals [ local] = this. new_opaque ( this. ty ( value) ) ;
385
+ #[ cfg( debug_assertions) ]
386
+ for local_vec in this. rev_locals . iter ( ) {
387
+ for ( other, _) in local_vec {
388
+ debug_assert_ne ! ( * other, local) ;
389
+ }
390
+ }
391
+ } ;
392
+ if place. is_indirect_first_projection ( ) {
393
+ // Non-local mutation maybe invalidate deref.
394
+ self . invalidate_derefs ( ) ;
395
+ // Remove stored value from borrowed locals.
396
+ for local in self . ssa . borrowed_locals ( ) . iter ( ) {
397
+ discard_local ( self , local) ;
398
+ }
399
+ } else {
400
+ discard_local ( self , place. local ) ;
401
+ }
372
402
}
373
403
374
404
fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
@@ -633,7 +663,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
633
663
let ( mut place_ty, mut value) = match base {
634
664
// The base is a local, so we take the local's value and project from it.
635
665
AddressBase :: Local ( local) => {
636
- let local = self . locals [ local] ? ;
666
+ let local = self . locals [ local] ;
637
667
let place_ty = PlaceTy :: from_ty ( self . ty ( local) ) ;
638
668
( place_ty, local)
639
669
}
@@ -744,7 +774,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
744
774
// If the projection is indirect, we treat the local as a value, so can replace it with
745
775
// another local.
746
776
if place. is_indirect_first_projection ( )
747
- && let Some ( base) = self . locals [ place. local ]
777
+ && let base = self . locals [ place. local ]
748
778
&& let Some ( new_local) = self . try_as_local ( base, location)
749
779
&& place. local != new_local
750
780
{
@@ -756,9 +786,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
756
786
757
787
for i in 0 ..projection. len ( ) {
758
788
let elem = projection[ i] ;
759
- if let ProjectionElem :: Index ( idx_local) = elem
760
- && let Some ( idx) = self . locals [ idx_local]
761
- {
789
+ if let ProjectionElem :: Index ( idx_local) = elem {
790
+ let idx = self . locals [ idx_local] ;
762
791
if let Some ( offset) = self . evaluated [ idx] . as_ref ( )
763
792
&& let Some ( offset) = self . ecx . read_target_usize ( offset) . discard_err ( )
764
793
&& let Some ( min_length) = offset. checked_add ( 1 )
@@ -794,7 +823,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
794
823
let mut place_ref = place. as_ref ( ) ;
795
824
796
825
// Invariant: `value` holds the value up-to the `index`th projection excluded.
797
- let Some ( mut value) = self . locals [ place. local ] else { return Err ( place_ref ) } ;
826
+ let mut value = self . locals [ place. local ] ;
798
827
// Invariant: `value` has type `place_ty`, with optional downcast variant if needed.
799
828
let mut place_ty = PlaceTy :: from_ty ( self . local_decls [ place. local ] . ty ) ;
800
829
for ( index, proj) in place. projection . iter ( ) . enumerate ( ) {
@@ -805,7 +834,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
805
834
place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
806
835
}
807
836
808
- let Some ( proj) = proj. try_map ( |value| self . locals [ value] , |ty| ty) else {
837
+ let Some ( proj) = proj. try_map ( |value| Some ( self . locals [ value] ) , |ty| ty) else {
809
838
return Err ( place_ref) ;
810
839
} ;
811
840
let Some ( ty_and_value) = self . project ( place_ty, value, proj) else {
@@ -1017,6 +1046,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
1017
1046
None
1018
1047
}
1019
1048
1049
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
1020
1050
fn simplify_aggregate (
1021
1051
& mut self ,
1022
1052
lhs : & Place < ' tcx > ,
@@ -1661,6 +1691,7 @@ fn op_to_prop_const<'tcx>(
1661
1691
impl < ' tcx > VnState < ' _ , ' _ , ' tcx > {
1662
1692
/// If either [`Self::try_as_constant`] as [`Self::try_as_place`] succeeds,
1663
1693
/// returns that result as an [`Operand`].
1694
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
1664
1695
fn try_as_operand ( & mut self , index : VnIndex , location : Location ) -> Option < Operand < ' tcx > > {
1665
1696
if let Some ( const_) = self . try_as_constant ( index) {
1666
1697
Some ( Operand :: Constant ( Box :: new ( const_) ) )
@@ -1673,6 +1704,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
1673
1704
}
1674
1705
1675
1706
/// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR.
1707
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
1676
1708
fn try_as_constant ( & mut self , index : VnIndex ) -> Option < ConstOperand < ' tcx > > {
1677
1709
// This was already constant in MIR, do not change it. If the constant is not
1678
1710
// deterministic, adding an additional mention of it in MIR will not give the same value as
@@ -1730,12 +1762,17 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
1730
1762
1731
1763
/// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`,
1732
1764
/// return it. If you used this local, add it to `reused_locals` to remove storage statements.
1765
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
1733
1766
fn try_as_local ( & mut self , index : VnIndex , loc : Location ) -> Option < Local > {
1734
1767
let other = self . rev_locals . get ( index) ?;
1735
1768
other
1736
1769
. iter ( )
1737
- . find ( |& & other| self . ssa . assignment_dominates ( & self . dominators , other, loc) )
1738
- . copied ( )
1770
+ . find ( |& & ( other, assign_loc) | {
1771
+ self . ssa . assignment_dominates ( & self . dominators , other, loc)
1772
+ || ( assign_loc. block == loc. block
1773
+ && assign_loc. statement_index < loc. statement_index )
1774
+ } )
1775
+ . map ( |& ( other, _) | other)
1739
1776
}
1740
1777
}
1741
1778
@@ -1744,11 +1781,25 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
1744
1781
self . tcx
1745
1782
}
1746
1783
1784
+ fn visit_basic_block_data ( & mut self , block : BasicBlock , bbdata : & mut BasicBlockData < ' tcx > ) {
1785
+ for local_set in self . rev_locals . iter_mut ( ) {
1786
+ local_set. retain ( |( local, _) | self . ssa . is_ssa ( * local) ) ;
1787
+ }
1788
+ for local in self . locals . indices ( ) {
1789
+ if !self . ssa . is_ssa ( local) {
1790
+ let current = self . locals [ local] ;
1791
+ let new = self . new_opaque ( self . ty ( current) ) ;
1792
+ self . locals [ local] = new;
1793
+ self . rev_locals [ new] . push ( ( local, Location { block, statement_index : 0 } ) ) ;
1794
+ }
1795
+ }
1796
+ self . super_basic_block_data ( block, bbdata) ;
1797
+ }
1798
+
1747
1799
fn visit_place ( & mut self , place : & mut Place < ' tcx > , context : PlaceContext , location : Location ) {
1748
1800
self . simplify_place_projection ( place, location) ;
1749
- if context. is_mutating_use ( ) && place. is_indirect ( ) {
1750
- // Non-local mutation maybe invalidate deref.
1751
- self . invalidate_derefs ( ) ;
1801
+ if context. is_mutating_use ( ) {
1802
+ self . discard_place ( * place) ;
1752
1803
}
1753
1804
self . super_place ( place, context, location) ;
1754
1805
}
@@ -1779,32 +1830,27 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
1779
1830
}
1780
1831
}
1781
1832
1782
- if lhs. is_indirect ( ) {
1783
- // Non-local mutation maybe invalidate deref.
1784
- self . invalidate_derefs ( ) ;
1785
- }
1833
+ self . discard_place ( * lhs) ;
1786
1834
1787
1835
if let Some ( local) = lhs. as_local ( )
1788
- && self . ssa . is_ssa ( local)
1789
1836
&& let rvalue_ty = rvalue. ty ( self . local_decls , self . tcx )
1790
1837
// FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
1791
1838
// `local` as reusable if we have an exact type match.
1792
1839
&& self . local_decls [ local] . ty == rvalue_ty
1793
1840
{
1794
1841
let value = value. unwrap_or_else ( || self . new_opaque ( rvalue_ty) ) ;
1795
- self . assign ( local, value) ;
1842
+ self . assign ( local, value, location ) ;
1796
1843
}
1797
1844
}
1798
1845
1799
1846
fn visit_terminator ( & mut self , terminator : & mut Terminator < ' tcx > , location : Location ) {
1800
- if let Terminator { kind : TerminatorKind :: Call { destination, .. } , .. } = terminator {
1801
- if let Some ( local) = destination. as_local ( )
1802
- && self . ssa . is_ssa ( local)
1803
- {
1804
- let ty = self . local_decls [ local] . ty ;
1805
- let opaque = self . new_opaque ( ty) ;
1806
- self . assign ( local, opaque) ;
1807
- }
1847
+ self . super_terminator ( terminator, location) ;
1848
+ if let Terminator { kind : TerminatorKind :: Call { destination, .. } , .. } = terminator
1849
+ && let Some ( local) = destination. as_local ( )
1850
+ {
1851
+ let ty = self . local_decls [ local] . ty ;
1852
+ let opaque = self . new_opaque ( ty) ;
1853
+ self . assign ( local, opaque, location) ;
1808
1854
}
1809
1855
// Function calls and ASM may invalidate (nested) derefs. We must handle them carefully.
1810
1856
// Currently, only preserving derefs for trivial terminators like SwitchInt and Goto.
@@ -1815,7 +1861,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
1815
1861
if !safe_to_preserve_derefs {
1816
1862
self . invalidate_derefs ( ) ;
1817
1863
}
1818
- self . super_terminator ( terminator, location) ;
1819
1864
}
1820
1865
}
1821
1866
0 commit comments