@@ -135,7 +135,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
135135 VnState :: new ( tcx, body, typing_env, & ssa, dominators, & body. local_decls , & arena) ;
136136
137137 for local in body. args_iter ( ) . filter ( |& local| ssa. is_ssa ( local) ) {
138- let opaque = state. new_opaque ( body. local_decls [ local] . ty ) ;
138+ let opaque = state. new_argument ( body. local_decls [ local] . ty ) ;
139139 state. assign ( local, opaque) ;
140140 }
141141
@@ -198,8 +198,9 @@ enum AddressBase {
198198enum Value < ' a , ' tcx > {
199199 // Root values.
200200 /// Used to represent values we know nothing about.
201- /// The `usize` is a counter incremented by `new_opaque`.
202201 Opaque ( VnOpaque ) ,
202+ /// The value is a argument.
203+ Argument ( VnOpaque ) ,
203204 /// Evaluated or unevaluated constant value.
204205 Constant {
205206 value : Const < ' tcx > ,
@@ -284,7 +285,7 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> {
284285 let value = value ( VnOpaque ) ;
285286
286287 debug_assert ! ( match value {
287- Value :: Opaque ( _) | Value :: Address { .. } => true ,
288+ Value :: Opaque ( _) | Value :: Argument ( _ ) | Value :: Address { .. } => true ,
288289 Value :: Constant { disambiguator, .. } => disambiguator. is_some( ) ,
289290 _ => false ,
290291 } ) ;
@@ -440,6 +441,13 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
440441 index
441442 }
442443
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+
443451 /// Create a new `Value::Address` distinct from all the others.
444452 #[ instrument( level = "trace" , skip( self ) , ret) ]
445453 fn new_pointer ( & mut self , place : Place < ' tcx > , kind : AddressKind ) -> Option < VnIndex > {
@@ -458,6 +466,10 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
458466 projection. next ( ) ;
459467 AddressBase :: Deref ( base)
460468 } else {
469+ // Only propagate the pointer of the SSA local.
470+ if !self . ssa . is_ssa ( place. local ) {
471+ return None ;
472+ }
461473 AddressBase :: Local ( place. local )
462474 } ;
463475 // Do not try evaluating inside `Index`, this has been done by `simplify_place_projection`.
@@ -526,10 +538,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
526538 self . insert ( ty, Value :: Aggregate ( VariantIdx :: ZERO , self . arena . alloc_slice ( values) ) )
527539 }
528540
529- fn insert_deref ( & mut self , ty : Ty < ' tcx > , value : VnIndex ) -> VnIndex {
530- self . insert ( ty, Value :: Projection ( value, ProjectionElem :: Deref ) )
531- }
532-
533541 #[ instrument( level = "trace" , skip( self ) , ret) ]
534542 fn eval_to_const_inner ( & mut self , value : VnIndex ) -> Option < OpTy < ' tcx > > {
535543 use Value :: * ;
@@ -543,7 +551,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
543551 let op = match self . get ( value) {
544552 _ if ty. is_zst ( ) => ImmTy :: uninit ( ty) . into ( ) ,
545553
546- Opaque ( _) => return None ,
554+ Opaque ( _) | Argument ( _ ) => return None ,
547555 // Keep runtime check constants as symbolic.
548556 RuntimeChecks ( ..) => return None ,
549557
@@ -795,7 +803,13 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
795803
796804 // An immutable borrow `_x` always points to the same value for the
797805 // lifetime of the borrow, so we can merge all instances of `*_x`.
798- return Some ( ( projection_ty, self . insert_deref ( projection_ty. ty , value) ) ) ;
806+ return Some ( (
807+ projection_ty,
808+ self . insert (
809+ projection_ty. ty ,
810+ Value :: Projection ( value, ProjectionElem :: Deref ) ,
811+ ) ,
812+ ) ) ;
799813 } else {
800814 return None ;
801815 }
@@ -1119,6 +1133,42 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
11191133 }
11201134 }
11211135
1136+ // We can introduce a new dereference if the source value cannot be changed in the body.
1137+ let mut copy_root = copy_from_local_value;
1138+ loop {
1139+ match self . get ( copy_root) {
1140+ Value :: Projection ( base, _) => {
1141+ copy_root = base;
1142+ }
1143+ Value :: Address {
1144+ base,
1145+ projection,
1146+ kind : AddressKind :: Ref ( BorrowKind :: Shared ) ,
1147+ ..
1148+ } if projection. iter ( ) . all ( ProjectionElem :: is_stable_offset) => match base {
1149+ AddressBase :: Local ( local) => {
1150+ break ;
1151+ }
1152+ AddressBase :: Deref ( index) => {
1153+ copy_root = index;
1154+ }
1155+ } ,
1156+ Value :: Argument ( _) if !self . ty ( copy_root) . is_mutable_ptr ( ) => {
1157+ break ;
1158+ }
1159+ Value :: Opaque ( _) => {
1160+ let ty = self . ty ( copy_root) ;
1161+ if ty. is_fn ( ) || !ty. is_any_ptr ( ) {
1162+ break ;
1163+ }
1164+ return None ;
1165+ }
1166+ _ => {
1167+ return None ;
1168+ }
1169+ }
1170+ }
1171+
11221172 // Both must be variants of the same type.
11231173 if self . ty ( copy_from_local_value) == ty { Some ( copy_from_local_value) } else { None }
11241174 }
@@ -1208,12 +1258,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
12081258 }
12091259
12101260 if let Some ( value) = self . simplify_aggregate_to_copy ( ty, variant_index, & fields) {
1211- // Allow introducing places with non-constant offsets, as those are still better than
1212- // reconstructing an aggregate. But avoid creating `*a = copy (*b)`, as they might be
1213- // aliases resulting in overlapping assignments.
1214- let allow_complex_projection =
1215- lhs. projection [ ..] . iter ( ) . all ( PlaceElem :: is_stable_offset) ;
1216- if let Some ( place) = self . try_as_place ( value, location, allow_complex_projection) {
1261+ if let Some ( place) = self . try_as_place ( value, location, true ) {
12171262 self . reused_locals . insert ( place. local ) ;
12181263 * rvalue = Rvalue :: Use ( Operand :: Copy ( place) ) ;
12191264 }
@@ -1866,7 +1911,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
18661911 ) {
18671912 self . simplify_place_projection ( lhs, location) ;
18681913
1869- let value = self . simplify_rvalue ( lhs, rvalue, location) ;
1914+ let mut value = self . simplify_rvalue ( lhs, rvalue, location) ;
18701915 if let Some ( value) = value {
18711916 if let Some ( const_) = self . try_as_constant ( value) {
18721917 * rvalue = Rvalue :: Use ( Operand :: Constant ( Box :: new ( const_) ) ) ;
@@ -1879,9 +1924,34 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, '_, 'tcx> {
18791924 }
18801925 }
18811926
1927+ let rvalue_ty = rvalue. ty ( self . local_decls , self . tcx ) ;
1928+ // DO NOT reason the pointer value if it may point to a non-SSA local.
1929+ // For instance, we cannot unify two pointers that dereference same local, because they may
1930+ // have different lifetimes.
1931+ if rvalue_ty. is_ref ( )
1932+ && let Some ( index) = value
1933+ {
1934+ match self . get ( index) {
1935+ Value :: Opaque ( _) | Value :: Projection ( ..) => {
1936+ value = None ;
1937+ }
1938+ Value :: Constant { .. }
1939+ | Value :: Address { .. }
1940+ | Value :: Argument ( _)
1941+ | Value :: RawPtr { .. }
1942+ | Value :: BinaryOp ( ..)
1943+ | Value :: Cast { .. } => { }
1944+ Value :: Aggregate ( ..)
1945+ | Value :: Union ( ..)
1946+ | Value :: Repeat ( ..)
1947+ | Value :: Discriminant ( ..)
1948+ | Value :: RuntimeChecks ( ..)
1949+ | Value :: UnaryOp ( ..) => unreachable ! ( ) ,
1950+ }
1951+ }
1952+
18821953 if let Some ( local) = lhs. as_local ( )
18831954 && self . ssa . is_ssa ( local)
1884- && let rvalue_ty = rvalue. ty ( self . local_decls , self . tcx )
18851955 // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
18861956 // `local` as reusable if we have an exact type match.
18871957 && self . local_decls [ local] . ty == rvalue_ty
0 commit comments