@@ -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 }
@@ -206,6 +200,7 @@ enum Value<'a, 'tcx> {
206200 /// Used to represent values we know nothing about.
207201 /// The `usize` is a counter incremented by `new_opaque`.
208202 Opaque ( VnOpaque ) ,
203+ Argument ( VnOpaque ) ,
209204 /// Evaluated or unevaluated constant value.
210205 Constant {
211206 value : Const < ' tcx > ,
@@ -243,7 +238,10 @@ enum Value<'a, 'tcx> {
243238
244239 // Extractions.
245240 /// This is the *value* obtained by projecting another value.
246- Projection ( VnIndex , ProjectionElem < VnIndex , ( ) > ) ,
241+ Projection {
242+ base : VnIndex ,
243+ elem : ProjectionElem < VnIndex , ( ) > ,
244+ } ,
247245 /// Discriminant of the given value.
248246 Discriminant ( VnIndex ) ,
249247
@@ -290,7 +288,7 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> {
290288 let value = value ( VnOpaque ) ;
291289
292290 debug_assert ! ( match value {
293- Value :: Opaque ( _) | Value :: Address { .. } => true ,
291+ Value :: Opaque ( _) | Value :: Argument ( _ ) | Value :: Address { .. } => true ,
294292 Value :: Constant { disambiguator, .. } => disambiguator. is_some( ) ,
295293 _ => false ,
296294 } ) ;
@@ -350,12 +348,6 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> {
350348 fn ty ( & self , index : VnIndex ) -> Ty < ' tcx > {
351349 self . types [ index]
352350 }
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- }
359351}
360352
361353struct VnState < ' body , ' a , ' tcx > {
@@ -374,8 +366,6 @@ struct VnState<'body, 'a, 'tcx> {
374366 /// - `Some(None)` are values for which computation has failed;
375367 /// - `Some(Some(op))` are successful computations.
376368 evaluated : IndexVec < VnIndex , Option < Option < & ' a OpTy < ' tcx > > > > ,
377- /// Cache the deref values.
378- derefs : Vec < VnIndex > ,
379369 ssa : & ' body SsaLocals ,
380370 dominators : Dominators < BasicBlock > ,
381371 reused_locals : DenseBitSet < Local > ,
@@ -408,7 +398,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
408398 rev_locals : IndexVec :: with_capacity ( num_values) ,
409399 values : ValueSet :: new ( num_values) ,
410400 evaluated : IndexVec :: with_capacity ( num_values) ,
411- derefs : Vec :: new ( ) ,
412401 ssa,
413402 dominators,
414403 reused_locals : DenseBitSet :: new_empty ( local_decls. len ( ) ) ,
@@ -455,6 +444,13 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
455444 index
456445 }
457446
447+ #[ instrument( level = "trace" , skip( self ) , ret) ]
448+ fn new_argument ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
449+ let index = self . insert_unique ( ty, Value :: Argument ) ;
450+ self . evaluated [ index] = Some ( None ) ;
451+ index
452+ }
453+
458454 /// Create a new `Value::Address` distinct from all the others.
459455 #[ instrument( level = "trace" , skip( self ) , ret) ]
460456 fn new_pointer ( & mut self , place : Place < ' tcx > , kind : AddressKind ) -> Option < VnIndex > {
@@ -473,6 +469,10 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
473469 projection. next ( ) ;
474470 AddressBase :: Deref ( base)
475471 } else {
472+ // Only propagate the pointer of the SSA local.
473+ if !self . ssa . is_ssa ( place. local ) {
474+ return None ;
475+ }
476476 AddressBase :: Local ( place. local )
477477 } ;
478478 // Do not try evaluating inside `Index`, this has been done by `simplify_place_projection`.
@@ -541,18 +541,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
541541 self . insert ( ty, Value :: Aggregate ( VariantIdx :: ZERO , self . arena . alloc_slice ( values) ) )
542542 }
543543
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-
556544 #[ instrument( level = "trace" , skip( self ) , ret) ]
557545 fn eval_to_const_inner ( & mut self , value : VnIndex ) -> Option < OpTy < ' tcx > > {
558546 use Value :: * ;
@@ -566,7 +554,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
566554 let op = match self . get ( value) {
567555 _ if ty. is_zst ( ) => ImmTy :: uninit ( ty) . into ( ) ,
568556
569- Opaque ( _) => return None ,
557+ Opaque ( _) | Argument ( _ ) => return None ,
570558 // Keep runtime check constants as symbolic.
571559 RuntimeChecks ( ..) => return None ,
572560
@@ -648,7 +636,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
648636 ImmTy :: from_immediate ( ptr_imm, ty) . into ( )
649637 }
650638
651- Projection ( base, elem) => {
639+ Projection { base, elem, .. } => {
652640 let base = self . eval_to_const ( base) ?;
653641 // `Index` by constants should have been replaced by `ConstantIndex` by
654642 // `simplify_place_projection`.
@@ -818,7 +806,13 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
818806
819807 // An immutable borrow `_x` always points to the same value for the
820808 // lifetime of the borrow, so we can merge all instances of `*_x`.
821- return Some ( ( projection_ty, self . insert_deref ( projection_ty. ty , value) ) ) ;
809+ return Some ( (
810+ projection_ty,
811+ self . insert (
812+ projection_ty. ty ,
813+ Value :: Projection { base : value, elem : ProjectionElem :: Deref } ,
814+ ) ,
815+ ) ) ;
822816 } else {
823817 return None ;
824818 }
@@ -827,8 +821,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
827821 ProjectionElem :: Field ( f, _) => match self . get ( value) {
828822 Value :: Aggregate ( _, fields) => return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ,
829823 Value :: Union ( active, field) if active == f => return Some ( ( projection_ty, field) ) ,
830- Value :: Projection ( outer_value , ProjectionElem :: Downcast ( _, read_variant) )
831- if let Value :: Aggregate ( written_variant, fields) = self . get ( outer_value )
824+ Value :: Projection { base , elem : ProjectionElem :: Downcast ( _, read_variant) }
825+ if let Value :: Aggregate ( written_variant, fields) = self . get ( base )
832826 // This pass is not aware of control-flow, so we do not know whether the
833827 // replacement we are doing is actually reachable. We could be in any arm of
834828 // ```
@@ -881,7 +875,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
881875 ProjectionElem :: UnwrapUnsafeBinder ( _) => ProjectionElem :: UnwrapUnsafeBinder ( ( ) ) ,
882876 } ;
883877
884- let value = self . insert ( projection_ty. ty , Value :: Projection ( value, proj) ) ;
878+ let value = self . insert ( projection_ty. ty , Value :: Projection { base : value, elem : proj } ) ;
885879 Some ( ( projection_ty, value) )
886880 }
887881
@@ -1114,11 +1108,14 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
11141108 fields : & [ VnIndex ] ,
11151109 ) -> Option < VnIndex > {
11161110 let Some ( & first_field) = fields. first ( ) else { return None } ;
1117- let Value :: Projection ( copy_from_value, _) = self . get ( first_field) else { return None } ;
1111+ let Value :: Projection { base : copy_from_value, .. } = self . get ( first_field) else {
1112+ return None ;
1113+ } ;
11181114
11191115 // All fields must correspond one-to-one and come from the same aggregate value.
11201116 if fields. iter ( ) . enumerate ( ) . any ( |( index, & v) | {
1121- if let Value :: Projection ( pointer, ProjectionElem :: Field ( from_index, _) ) = self . get ( v)
1117+ if let Value :: Projection { base : pointer, elem : ProjectionElem :: Field ( from_index, _) } =
1118+ self . get ( v)
11221119 && copy_from_value == pointer
11231120 && from_index. index ( ) == index
11241121 {
@@ -1130,7 +1127,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
11301127 }
11311128
11321129 let mut copy_from_local_value = copy_from_value;
1133- if let Value :: Projection ( pointer, proj) = self . get ( copy_from_value)
1130+ if let Value :: Projection { base : pointer, elem : proj } = self . get ( copy_from_value)
11341131 && let ProjectionElem :: Downcast ( _, read_variant) = proj
11351132 {
11361133 if variant_index == read_variant {
@@ -1142,6 +1139,45 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
11421139 }
11431140 }
11441141
1142+ // We can introduce a new dereference if the source value cannot be changed in the body.
1143+ let mut copy_root = copy_from_local_value;
1144+ loop {
1145+ match self . get ( copy_root) {
1146+ Value :: Projection { base, .. } => {
1147+ copy_root = base;
1148+ }
1149+ Value :: Address {
1150+ base,
1151+ projection,
1152+ kind : AddressKind :: Ref ( BorrowKind :: Shared ) ,
1153+ ..
1154+ } if projection. iter ( ) . all ( ProjectionElem :: is_stable_offset) => match base {
1155+ AddressBase :: Local ( local) => {
1156+ if !self . ssa . is_ssa ( local) {
1157+ return None ;
1158+ }
1159+ break ;
1160+ }
1161+ AddressBase :: Deref ( index) => {
1162+ copy_root = index;
1163+ }
1164+ } ,
1165+ Value :: Argument ( _) if !self . ty ( copy_root) . is_mutable_ptr ( ) => {
1166+ break ;
1167+ }
1168+ Value :: Opaque ( _) => {
1169+ let ty = self . ty ( copy_root) ;
1170+ if ty. is_fn ( ) || !ty. is_any_ptr ( ) {
1171+ break ;
1172+ }
1173+ return None ;
1174+ }
1175+ _ => {
1176+ return None ;
1177+ }
1178+ }
1179+ }
1180+
11451181 // Both must be variants of the same type.
11461182 if self . ty ( copy_from_local_value) == ty { Some ( copy_from_local_value) } else { None }
11471183 }
@@ -1843,7 +1879,7 @@ impl<'tcx> VnState<'_, '_, 'tcx> {
18431879 // If we are here, we failed to find a local, and we already have a `Deref`.
18441880 // Trying to add projections will only result in an ill-formed place.
18451881 return None ;
1846- } else if let Value :: Projection ( pointer, proj) = self . get ( index)
1882+ } else if let Value :: Projection { base : pointer, elem : proj } = self . get ( index)
18471883 && ( allow_complex_projection || proj. is_stable_offset ( ) )
18481884 && let Some ( proj) = self . try_as_place_elem ( self . ty ( index) , proj, loc)
18491885 {
@@ -1873,10 +1909,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
18731909
18741910 fn visit_place ( & mut self , place : & mut Place < ' tcx > , context : PlaceContext , location : Location ) {
18751911 self . simplify_place_projection ( place, location) ;
1876- if context. is_mutating_use ( ) && place. is_indirect ( ) {
1877- // Non-local mutation maybe invalidate deref.
1878- self . invalidate_derefs ( ) ;
1879- }
18801912 self . super_place ( place, context, location) ;
18811913 }
18821914
@@ -1893,7 +1925,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
18931925 ) {
18941926 self . simplify_place_projection ( lhs, location) ;
18951927
1896- let value = self . simplify_rvalue ( lhs, rvalue, location) ;
1928+ let mut value = self . simplify_rvalue ( lhs, rvalue, location) ;
18971929 if let Some ( value) = value {
18981930 if let Some ( const_) = self . try_as_constant ( value) {
18991931 * rvalue = Rvalue :: Use ( Operand :: Constant ( Box :: new ( const_) ) ) ;
@@ -1906,14 +1938,30 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
19061938 }
19071939 }
19081940
1909- if lhs. is_indirect ( ) {
1910- // Non-local mutation maybe invalidate deref.
1911- self . invalidate_derefs ( ) ;
1941+ let rvalue_ty = rvalue. ty ( self . local_decls , self . tcx ) ;
1942+ // DO NOT reason the pointer value if it may point to a non-SSA local.
1943+ // For instance, we cannot unify two pointers that dereference same local, because they may
1944+ // have different lifetimes.
1945+ if rvalue_ty. is_ref ( )
1946+ && let Some ( index) = value
1947+ {
1948+ match self . get ( index) {
1949+ Value :: Opaque ( _) | Value :: Projection { .. } => {
1950+ value = None ;
1951+ }
1952+ Value :: Constant { .. } | Value :: Address { .. } | Value :: Argument ( _) => { }
1953+ Value :: RawPtr { .. } | Value :: BinaryOp ( ..) | Value :: Cast { .. } => { }
1954+ Value :: Aggregate ( ..)
1955+ | Value :: Union ( ..)
1956+ | Value :: Repeat ( ..)
1957+ | Value :: Discriminant ( ..)
1958+ | Value :: RuntimeChecks ( ..)
1959+ | Value :: UnaryOp ( ..) => unreachable ! ( ) ,
1960+ }
19121961 }
19131962
19141963 if let Some ( local) = lhs. as_local ( )
19151964 && self . ssa . is_ssa ( local)
1916- && let rvalue_ty = rvalue. ty ( self . local_decls , self . tcx )
19171965 // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
19181966 // `local` as reusable if we have an exact type match.
19191967 && self . local_decls [ local] . ty == rvalue_ty
@@ -1933,10 +1981,6 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
19331981 self . assign ( local, opaque) ;
19341982 }
19351983 }
1936- // Terminators that can write to memory may invalidate (nested) derefs.
1937- if terminator. kind . can_write_to_memory ( ) {
1938- self . invalidate_derefs ( ) ;
1939- }
19401984 self . super_terminator ( terminator, location) ;
19411985 }
19421986}
0 commit comments