@@ -129,24 +129,18 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
129129 let ssa = SsaLocals :: new ( tcx, body, typing_env) ;
130130 // Clone dominators because we need them while mutating the body.
131131 let dominators = body. basic_blocks . dominators ( ) . clone ( ) ;
132- let maybe_loop_headers = loops:: maybe_loop_headers ( body) ;
133132
134133 let arena = DroplessArena :: default ( ) ;
135134 let mut state =
136135 VnState :: new ( tcx, body, typing_env, & ssa, dominators, & body. local_decls , & arena) ;
137136
138137 for local in body. args_iter ( ) . filter ( |& local| ssa. is_ssa ( local) ) {
139- let opaque = state. new_opaque ( body. local_decls [ local] . ty ) ;
138+ let opaque = state. new_argument ( body. local_decls [ local] . ty ) ;
140139 state. assign ( local, opaque) ;
141140 }
142141
143142 let reverse_postorder = body. basic_blocks . reverse_postorder ( ) . to_vec ( ) ;
144143 for bb in reverse_postorder {
145- // N.B. With loops, reverse postorder cannot produce a valid topological order.
146- // A statement or terminator from inside the loop, that is not processed yet, may have performed an indirect write.
147- if maybe_loop_headers. contains ( bb) {
148- state. invalidate_derefs ( ) ;
149- }
150144 let data = & mut body. basic_blocks . as_mut_preserves_cfg ( ) [ bb] ;
151145 state. visit_basic_block_data ( bb, data) ;
152146 }
@@ -204,8 +198,9 @@ enum AddressBase {
204198enum Value < ' a , ' tcx > {
205199 // Root values.
206200 /// Used to represent values we know nothing about.
207- /// The `usize` is a counter incremented by `new_opaque`.
208201 Opaque ( VnOpaque ) ,
202+ /// The value is a argument.
203+ Argument ( VnOpaque ) ,
209204 /// Evaluated or unevaluated constant value.
210205 Constant {
211206 value : Const < ' tcx > ,
@@ -290,7 +285,7 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> {
290285 let value = value ( VnOpaque ) ;
291286
292287 debug_assert ! ( match value {
293- Value :: Opaque ( _) | Value :: Address { .. } => true ,
288+ Value :: Opaque ( _) | Value :: Argument ( _ ) | Value :: Address { .. } => true ,
294289 Value :: Constant { disambiguator, .. } => disambiguator. is_some( ) ,
295290 _ => false ,
296291 } ) ;
@@ -350,12 +345,6 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> {
350345 fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
351346 self . types [ index]
352347 }
353-
354- /// Replace the value associated with `index` with an opaque value.
355- #[ inline]
356- fn forget ( & mut self , index : VnIndex ) {
357- self . values [ index] = Value :: Opaque ( VnOpaque ) ;
358- }
359348}
360349
361350struct VnState < ' body , ' a , ' tcx > {
@@ -374,8 +363,6 @@ struct VnState<'body, 'a, 'tcx> {
374363 /// - `Some(None)` are values for which computation has failed;
375364 /// - `Some(Some(op))` are successful computations.
376365 evaluated : IndexVec < VnIndex , Option < Option < & ' a OpTy < ' tcx > > > > ,
377- /// Cache the deref values.
378- derefs : Vec < VnIndex > ,
379366 ssa : & ' body SsaLocals ,
380367 dominators : Dominators < BasicBlock > ,
381368 reused_locals : DenseBitSet < Local > ,
@@ -408,7 +395,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
408395 rev_locals : IndexVec :: with_capacity ( num_values) ,
409396 values : ValueSet :: new ( num_values) ,
410397 evaluated : IndexVec :: with_capacity ( num_values) ,
411- derefs : Vec :: new ( ) ,
412398 ssa,
413399 dominators,
414400 reused_locals : DenseBitSet :: new_empty ( local_decls. len ( ) ) ,
@@ -455,6 +441,13 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
455441 index
456442 }
457443
444+ #[ instrument( level = "trace" , skip( self ) , ret) ]
445+ fn new_argument ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
446+ let index = self . insert_unique ( ty, Value :: Argument ) ;
447+ self . evaluated [ index] = Some ( None ) ;
448+ index
449+ }
450+
458451 /// Create a new `Value::Address` distinct from all the others.
459452 #[ instrument( level = "trace" , skip( self ) , ret) ]
460453 fn new_pointer ( & mut self , place : Place < ' tcx > , kind : AddressKind ) -> Option < VnIndex > {
@@ -472,8 +465,11 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
472465 // Skip the initial `Deref`.
473466 projection. next ( ) ;
474467 AddressBase :: Deref ( base)
475- } else {
468+ } else if self . ssa . is_ssa ( place. local ) {
469+ // Only propagate the pointer of the SSA local.
476470 AddressBase :: Local ( place. local )
471+ } else {
472+ return None ;
477473 } ;
478474 // Do not try evaluating inside `Index`, this has been done by `simplify_place_projection`.
479475 let projection =
@@ -541,18 +537,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
541537 self . insert ( ty, Value :: Aggregate ( VariantIdx :: ZERO , self . arena . alloc_slice ( values) ) )
542538 }
543539
544- fn insert_deref ( & mut self , ty : Ty < ' tcx > , value : VnIndex ) -> VnIndex {
545- let value = self . insert ( ty, Value :: Projection ( value, ProjectionElem :: Deref ) ) ;
546- self . derefs . push ( value) ;
547- value
548- }
549-
550- fn invalidate_derefs ( & mut self ) {
551- for deref in std:: mem:: take ( & mut self . derefs ) {
552- self . values . forget ( deref) ;
553- }
554- }
555-
556540 #[ instrument( level = "trace" , skip( self ) , ret) ]
557541 fn eval_to_const_inner ( & mut self , value : VnIndex ) -> Option < OpTy < ' tcx > > {
558542 use Value :: * ;
@@ -566,7 +550,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
566550 let op = match self . get ( value) {
567551 _ if ty. is_zst ( ) => ImmTy :: uninit ( ty) . into ( ) ,
568552
569- Opaque ( _) => return None ,
553+ Opaque ( _) | Argument ( _ ) => return None ,
570554 // Keep runtime check constants as symbolic.
571555 RuntimeChecks ( ..) => return None ,
572556
@@ -815,10 +799,24 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
815799 {
816800 return Some ( ( projection_ty, value) ) ;
817801 }
802+ // DO NOT reason the pointer value.
803+ // We cannot unify two pointers that dereference same local, because they may
804+ // have different lifetimes.
805+ // ```
806+ // let b: &T = *a;
807+ // ... `a` is allowed to be modified. `c` and `b` have different borrowing lifetime.
808+ // Unifying them will extend the lifetime of `b`.
809+ // let c: &T = *a;
810+ // ```
811+ if projection_ty. ty . is_ref ( ) {
812+ return None ;
813+ }
818814
819815 // An immutable borrow `_x` always points to the same value for the
820816 // lifetime of the borrow, so we can merge all instances of `*_x`.
821- return Some ( ( projection_ty, self . insert_deref ( projection_ty. ty , value) ) ) ;
817+ let deref = self
818+ . insert ( projection_ty. ty , Value :: Projection ( value, ProjectionElem :: Deref ) ) ;
819+ return Some ( ( projection_ty, deref) ) ;
822820 } else {
823821 return None ;
824822 }
@@ -1037,7 +1035,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
10371035 let op = self . simplify_operand ( op, location) ?;
10381036 Value :: Repeat ( op, amount)
10391037 }
1040- Rvalue :: Aggregate ( ..) => return self . simplify_aggregate ( lhs , rvalue, location) ,
1038+ Rvalue :: Aggregate ( ..) => return self . simplify_aggregate ( rvalue, location) ,
10411039 Rvalue :: Ref ( _, borrow_kind, ref mut place) => {
10421040 self . simplify_place_projection ( place, location) ;
10431041 return self . new_pointer ( * place, AddressKind :: Ref ( borrow_kind) ) ;
@@ -1148,7 +1146,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
11481146
11491147 fn simplify_aggregate (
11501148 & mut self ,
1151- lhs : & Place < ' tcx > ,
11521149 rvalue : & mut Rvalue < ' tcx > ,
11531150 location : Location ,
11541151 ) -> Option < VnIndex > {
@@ -1231,12 +1228,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
12311228 }
12321229
12331230 if let Some ( value) = self . simplify_aggregate_to_copy ( ty, variant_index, & fields) {
1234- // Allow introducing places with non-constant offsets, as those are still better than
1235- // reconstructing an aggregate. But avoid creating `*a = copy (*b)`, as they might be
1236- // aliases resulting in overlapping assignments.
1237- let allow_complex_projection =
1238- lhs. projection [ ..] . iter ( ) . all ( PlaceElem :: is_stable_offset) ;
1239- if let Some ( place) = self . try_as_place ( value, location, allow_complex_projection) {
1231+ if let Some ( place) = self . try_as_place ( value, location, true ) {
12401232 self . reused_locals . insert ( place. local ) ;
12411233 * rvalue = Rvalue :: Use ( Operand :: Copy ( place) ) ;
12421234 }
@@ -1890,6 +1882,17 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
18901882 && ( allow_complex_projection || proj. is_stable_offset ( ) )
18911883 && let Some ( proj) = self . try_as_place_elem ( self . ty ( index) , proj, loc)
18921884 {
1885+ if proj == PlaceElem :: Deref {
1886+ // We can introduce a new dereference if the source value cannot be changed in the body.
1887+ // Dereferencing an immutable argument always gives the same value in the body.
1888+ match self . get ( pointer) {
1889+ Value :: Argument ( _)
1890+ if let Some ( Mutability :: Not ) = self . ty ( pointer) . ref_mutability ( ) => { }
1891+ _ => {
1892+ return None ;
1893+ }
1894+ }
1895+ }
18931896 projection. push ( proj) ;
18941897 index = pointer;
18951898 } else {
@@ -1916,10 +1919,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
19161919
19171920 fn visit_place ( & mut self , place : & mut Place < ' tcx > , context : PlaceContext , location : Location ) {
19181921 self . simplify_place_projection ( place, location) ;
1919- if context. is_mutating_use ( ) && place. is_indirect ( ) {
1920- // Non-local mutation maybe invalidate deref.
1921- self . invalidate_derefs ( ) ;
1922- }
19231922 self . super_place ( place, context, location) ;
19241923 }
19251924
@@ -1949,11 +1948,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
19491948 }
19501949 }
19511950
1952- if lhs. is_indirect ( ) {
1953- // Non-local mutation maybe invalidate deref.
1954- self . invalidate_derefs ( ) ;
1955- }
1956-
19571951 if let Some ( local) = lhs. as_local ( )
19581952 && self . ssa . is_ssa ( local)
19591953 && let rvalue_ty = rvalue. ty ( self . local_decls , self . tcx )
@@ -1976,10 +1970,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
19761970 self . assign ( local, opaque) ;
19771971 }
19781972 }
1979- // Terminators that can write to memory may invalidate (nested) derefs.
1980- if terminator. kind . can_write_to_memory ( ) {
1981- self . invalidate_derefs ( ) ;
1982- }
19831973 self . super_terminator ( terminator, location) ;
19841974 }
19851975}
0 commit comments