84
84
85
85
use rustc_const_eval:: interpret:: { intern_const_alloc_for_constprop, MemoryKind } ;
86
86
use rustc_const_eval:: interpret:: { ImmTy , InterpCx , OpTy , Projectable , Scalar } ;
87
- use rustc_data_structures:: fx:: { FxHashMap , FxIndexSet } ;
87
+ use rustc_data_structures:: fx:: FxIndexSet ;
88
88
use rustc_data_structures:: graph:: dominators:: Dominators ;
89
89
use rustc_hir:: def:: DefKind ;
90
90
use rustc_index:: bit_set:: BitSet ;
@@ -99,6 +99,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut};
99
99
use rustc_span:: def_id:: DefId ;
100
100
use rustc_span:: DUMMY_SP ;
101
101
use rustc_target:: abi:: { self , Abi , Size , VariantIdx , FIRST_VARIANT } ;
102
+ use smallvec:: SmallVec ;
102
103
use std:: borrow:: Cow ;
103
104
104
105
use crate :: dataflow_const_prop:: DummyMachine ;
@@ -238,14 +239,18 @@ struct VnState<'body, 'tcx> {
238
239
local_decls : & ' body LocalDecls < ' tcx > ,
239
240
/// Value stored in each local.
240
241
locals : IndexVec < Local , Option < VnIndex > > ,
241
- /// First local to be assigned that value.
242
- rev_locals : FxHashMap < VnIndex , Vec < Local > > ,
242
+ /// Locals that are assigned that value.
243
+ // This vector does not hold all the values of `VnIndex` that we create.
244
+ // It stops at the largest value created in the first phase of collecting assignments.
245
+ rev_locals : IndexVec < VnIndex , SmallVec < [ Local ; 1 ] > > ,
243
246
values : FxIndexSet < Value < ' tcx > > ,
244
247
/// Values evaluated as constants if possible.
245
248
evaluated : IndexVec < VnIndex , Option < OpTy < ' tcx > > > ,
246
249
/// Counter to generate different values.
247
250
/// This is an option to stop creating opaques during replacement.
248
251
next_opaque : Option < usize > ,
252
+ /// Cache the value of the `unsized_locals` features, to avoid fetching it repeatedly in a loop.
253
+ feature_unsized_locals : bool ,
249
254
ssa : & ' body SsaLocals ,
250
255
dominators : & ' body Dominators < BasicBlock > ,
251
256
reused_locals : BitSet < Local > ,
@@ -265,10 +270,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
265
270
param_env,
266
271
local_decls,
267
272
locals : IndexVec :: from_elem ( None , local_decls) ,
268
- rev_locals : FxHashMap :: default ( ) ,
273
+ rev_locals : IndexVec :: default ( ) ,
269
274
values : FxIndexSet :: default ( ) ,
270
275
evaluated : IndexVec :: new ( ) ,
271
276
next_opaque : Some ( 0 ) ,
277
+ feature_unsized_locals : tcx. features ( ) . unsized_locals ,
272
278
ssa,
273
279
dominators,
274
280
reused_locals : BitSet :: new_empty ( local_decls. len ( ) ) ,
@@ -316,10 +322,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
316
322
self . locals [ local] = Some ( value) ;
317
323
318
324
// Only register the value if its type is `Sized`, as we will emit copies of it.
319
- let is_sized = !self . tcx . features ( ) . unsized_locals
325
+ let is_sized = !self . feature_unsized_locals
320
326
|| self . local_decls [ local] . ty . is_sized ( self . tcx , self . param_env ) ;
321
327
if is_sized {
322
- self . rev_locals . entry ( value) . or_default ( ) . push ( local) ;
328
+ self . rev_locals . ensure_contains_elem ( value, SmallVec :: new) ;
329
+ self . rev_locals [ value] . push ( local) ;
323
330
}
324
331
}
325
332
@@ -630,6 +637,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
630
637
if place. is_indirect ( )
631
638
&& let Some ( base) = self . locals [ place. local ]
632
639
&& let Some ( new_local) = self . try_as_local ( base, location)
640
+ && place. local != new_local
633
641
{
634
642
place. local = new_local;
635
643
self . reused_locals . insert ( new_local) ;
@@ -639,18 +647,20 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
639
647
640
648
for i in 0 ..projection. len ( ) {
641
649
let elem = projection[ i] ;
642
- if let ProjectionElem :: Index ( idx ) = elem
643
- && let Some ( idx) = self . locals [ idx ]
650
+ if let ProjectionElem :: Index ( idx_local ) = elem
651
+ && let Some ( idx) = self . locals [ idx_local ]
644
652
{
645
653
if let Some ( offset) = self . evaluated [ idx] . as_ref ( )
646
654
&& let Ok ( offset) = self . ecx . read_target_usize ( offset)
647
655
&& let Some ( min_length) = offset. checked_add ( 1 )
648
656
{
649
657
projection. to_mut ( ) [ i] =
650
658
ProjectionElem :: ConstantIndex { offset, min_length, from_end : false } ;
651
- } else if let Some ( new_idx) = self . try_as_local ( idx, location) {
652
- projection. to_mut ( ) [ i] = ProjectionElem :: Index ( new_idx) ;
653
- self . reused_locals . insert ( new_idx) ;
659
+ } else if let Some ( new_idx_local) = self . try_as_local ( idx, location)
660
+ && idx_local != new_idx_local
661
+ {
662
+ projection. to_mut ( ) [ i] = ProjectionElem :: Index ( new_idx_local) ;
663
+ self . reused_locals . insert ( new_idx_local) ;
654
664
}
655
665
}
656
666
}
@@ -986,11 +996,11 @@ impl<'tcx> VnState<'_, 'tcx> {
986
996
/// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`,
987
997
/// return it.
988
998
fn try_as_local ( & mut self , index : VnIndex , loc : Location ) -> Option < Local > {
989
- let other = self . rev_locals . get ( & index) ?;
999
+ let other = self . rev_locals . get ( index) ?;
990
1000
other
991
1001
. iter ( )
1002
+ . find ( |& & other| self . ssa . assignment_dominates ( self . dominators , other, loc) )
992
1003
. copied ( )
993
- . find ( |& other| self . ssa . assignment_dominates ( self . dominators , other, loc) )
994
1004
}
995
1005
}
996
1006
@@ -1008,23 +1018,32 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
1008
1018
}
1009
1019
1010
1020
fn visit_statement ( & mut self , stmt : & mut Statement < ' tcx > , location : Location ) {
1011
- if let StatementKind :: Assign ( box ( _, ref mut rvalue) ) = stmt. kind
1021
+ if let StatementKind :: Assign ( box ( ref mut lhs, ref mut rvalue) ) = stmt. kind {
1022
+ self . simplify_place_projection ( lhs, location) ;
1023
+
1012
1024
// Do not try to simplify a constant, it's already in canonical shape.
1013
- && !matches ! ( rvalue, Rvalue :: Use ( Operand :: Constant ( _) ) )
1014
- {
1015
- if let Some ( value) = self . simplify_rvalue ( rvalue, location) {
1016
- if let Some ( const_) = self . try_as_constant ( value) {
1017
- * rvalue = Rvalue :: Use ( Operand :: Constant ( Box :: new ( const_) ) ) ;
1018
- } else if let Some ( local) = self . try_as_local ( value, location)
1019
- && * rvalue != Rvalue :: Use ( Operand :: Move ( local. into ( ) ) )
1020
- {
1021
- * rvalue = Rvalue :: Use ( Operand :: Copy ( local. into ( ) ) ) ;
1022
- self . reused_locals . insert ( local) ;
1023
- }
1025
+ if matches ! ( rvalue, Rvalue :: Use ( Operand :: Constant ( _) ) ) {
1026
+ return ;
1024
1027
}
1025
- } else {
1026
- self . super_statement ( stmt, location) ;
1028
+
1029
+ let value = lhs
1030
+ . as_local ( )
1031
+ . and_then ( |local| self . locals [ local] )
1032
+ . or_else ( || self . simplify_rvalue ( rvalue, location) ) ;
1033
+ let Some ( value) = value else { return } ;
1034
+
1035
+ if let Some ( const_) = self . try_as_constant ( value) {
1036
+ * rvalue = Rvalue :: Use ( Operand :: Constant ( Box :: new ( const_) ) ) ;
1037
+ } else if let Some ( local) = self . try_as_local ( value, location)
1038
+ && * rvalue != Rvalue :: Use ( Operand :: Move ( local. into ( ) ) )
1039
+ {
1040
+ * rvalue = Rvalue :: Use ( Operand :: Copy ( local. into ( ) ) ) ;
1041
+ self . reused_locals . insert ( local) ;
1042
+ }
1043
+
1044
+ return ;
1027
1045
}
1046
+ self . super_statement ( stmt, location) ;
1028
1047
}
1029
1048
}
1030
1049
0 commit comments