@@ -186,6 +186,14 @@ enum AddressKind {
186186    Address ( RawPtrKind ) , 
187187} 
188188
189+ #[ derive( Copy ,  Clone ,  Debug ,  PartialEq ,  Eq ,  Hash ) ]  
190+ enum  AddressBase  { 
191+     /// This address is based on this local. 
192+ Local ( Local ) , 
193+     /// This address is based on the deref of this pointer. 
194+ Deref ( VnIndex ) , 
195+ } 
196+ 
189197#[ derive( Copy ,  Clone ,  Debug ,  PartialEq ,  Eq ,  Hash ) ]  
190198enum  Value < ' a ,  ' tcx >  { 
191199    // Root values. 
@@ -216,7 +224,10 @@ enum Value<'a, 'tcx> {
216224Repeat ( VnIndex ,  ty:: Const < ' tcx > ) , 
217225    /// The address of a place. 
218226Address  { 
219-         place :  Place < ' tcx > , 
227+         base :  AddressBase , 
228+         // We do not use a plain `Place` as we want to be able to reason about indices. 
229+         // This does not contain any `Deref` projection. 
230+         projection :  & ' a  [ ProjectionElem < VnIndex ,  Ty < ' tcx > > ] , 
220231        kind :  AddressKind , 
221232        /// Give each borrow and pointer a different provenance, so we don't merge them. 
222233provenance :  VnOpaque , 
@@ -426,22 +437,42 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
426437
427438    /// Create a new `Value::Address` distinct from all the others. 
428439#[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
429-     fn  new_pointer ( & mut  self ,  place :  Place < ' tcx > ,  kind :  AddressKind )  -> VnIndex  { 
440+     fn  new_pointer ( & mut  self ,  place :  Place < ' tcx > ,  kind :  AddressKind )  -> Option < VnIndex >  { 
430441        let  pty = place. ty ( self . local_decls ,  self . tcx ) . ty ; 
431442        let  ty = match  kind { 
432443            AddressKind :: Ref ( bk)  => { 
433444                Ty :: new_ref ( self . tcx ,  self . tcx . lifetimes . re_erased ,  pty,  bk. to_mutbl_lossy ( ) ) 
434445            } 
435446            AddressKind :: Address ( mutbl)  => Ty :: new_ptr ( self . tcx ,  pty,  mutbl. to_mutbl_lossy ( ) ) , 
436447        } ; 
437-         let  index =
438-             self . values . insert_unique ( ty,  |provenance| Value :: Address  {  place,  kind,  provenance } ) ; 
448+ 
449+         let  mut  projection = place. projection . iter ( ) ; 
450+         let  base = if  place. is_indirect_first_projection ( )  { 
451+             let  base = self . locals [ place. local ] ?; 
452+             // Skip the initial `Deref`. 
453+             projection. next ( ) ; 
454+             AddressBase :: Deref ( base) 
455+         }  else  { 
456+             AddressBase :: Local ( place. local ) 
457+         } ; 
458+         // Do not try evaluating inside `Index`, this has been done by `simplify_place_projection`. 
459+         let  projection =
460+             projection. map ( |proj| proj. try_map ( |index| self . locals [ index] ,  |ty| ty) . ok_or ( ( ) ) ) ; 
461+         let  projection = self . arena . try_alloc_from_iter ( projection) . ok ( ) ?; 
462+ 
463+         let  index = self . values . insert_unique ( ty,  |provenance| Value :: Address  { 
464+             base, 
465+             projection, 
466+             kind, 
467+             provenance, 
468+         } ) ; 
439469        let  evaluated = self . eval_to_const ( index) ; 
440470        let  _index = self . evaluated . push ( evaluated) ; 
441471        debug_assert_eq ! ( index,  _index) ; 
442472        let  _index = self . rev_locals . push ( SmallVec :: new ( ) ) ; 
443473        debug_assert_eq ! ( index,  _index) ; 
444-         index
474+ 
475+         Some ( index) 
445476    } 
446477
447478    #[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
@@ -591,14 +622,15 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
591622                let  elem = elem. try_map ( |_| None ,  |( ) | ty. ty ) ?; 
592623                self . ecx . project ( base,  elem) . discard_err ( ) ?
593624            } 
594-             Address  {  place,  kind :  _,  provenance :  _ }  => { 
595-                 if  !place. is_indirect_first_projection ( )  { 
596-                     return  None ; 
597-                 } 
598-                 let  local = self . locals [ place. local ] ?; 
599-                 let  pointer = self . evaluated [ local] . as_ref ( ) ?; 
625+             Address  {  base,  projection,  .. }  => { 
626+                 debug_assert ! ( !projection. contains( & ProjectionElem :: Deref ) ) ; 
627+                 let  pointer = match  base { 
628+                     AddressBase :: Deref ( pointer)  => self . evaluated [ pointer] . as_ref ( ) ?, 
629+                     // We have no stack to point to. 
630+                     AddressBase :: Local ( _)  => return  None , 
631+                 } ; 
600632                let  mut  mplace = self . ecx . deref_pointer ( pointer) . discard_err ( ) ?; 
601-                 for  elem in  place . projection . iter ( ) . skip ( 1 )  { 
633+                 for  elem in  projection { 
602634                    // `Index` by constants should have been replaced by `ConstantIndex` by 
603635                    // `simplify_place_projection`. 
604636                    let  elem = elem. try_map ( |_| None ,  |ty| ty) ?; 
@@ -717,19 +749,51 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
717749        Some ( op) 
718750    } 
719751
752+     /// Represent the *value* we obtain by dereferencing an `Address` value. 
753+ #[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
754+     fn  dereference_address ( 
755+         & mut  self , 
756+         base :  AddressBase , 
757+         projection :  & [ ProjectionElem < VnIndex ,  Ty < ' tcx > > ] , 
758+     )  -> Option < VnIndex >  { 
759+         let  ( mut  place_ty,  mut  value)  = match  base { 
760+             // The base is a local, so we take the local's value and project from it. 
761+             AddressBase :: Local ( local)  => { 
762+                 let  local = self . locals [ local] ?; 
763+                 let  place_ty = PlaceTy :: from_ty ( self . ty ( local) ) ; 
764+                 ( place_ty,  local) 
765+             } 
766+             // The base is a pointer's deref, so we introduce the implicit deref. 
767+             AddressBase :: Deref ( reborrow)  => { 
768+                 let  place_ty = PlaceTy :: from_ty ( self . ty ( reborrow) ) ; 
769+                 self . project ( place_ty,  reborrow,  ProjectionElem :: Deref ) ?
770+             } 
771+         } ; 
772+         for  & proj in  projection { 
773+             ( place_ty,  value)  = self . project ( place_ty,  value,  proj) ?; 
774+         } 
775+         Some ( value) 
776+     } 
777+ 
778+     #[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
720779    fn  project ( 
721780        & mut  self , 
722781        place_ty :  PlaceTy < ' tcx > , 
723782        value :  VnIndex , 
724-         proj :  PlaceElem < ' tcx > , 
725-         from_non_ssa_index :  & mut  bool , 
783+         proj :  ProjectionElem < VnIndex ,  Ty < ' tcx > > , 
726784    )  -> Option < ( PlaceTy < ' tcx > ,  VnIndex ) >  { 
727785        let  projection_ty = place_ty. projection_ty ( self . tcx ,  proj) ; 
728786        let  proj = match  proj { 
729787            ProjectionElem :: Deref  => { 
730788                if  let  Some ( Mutability :: Not )  = place_ty. ty . ref_mutability ( ) 
731789                    && projection_ty. ty . is_freeze ( self . tcx ,  self . typing_env ( ) ) 
732790                { 
791+                     if  let  Value :: Address  {  base,  projection,  .. }  = self . get ( value) 
792+                         && let  Some ( value)  = self . dereference_address ( base,  projection) 
793+                     { 
794+                         return  Some ( ( projection_ty,  value) ) ; 
795+                     } 
796+ 
733797                    // An immutable borrow `_x` always points to the same value for the 
734798                    // lifetime of the borrow, so we can merge all instances of `*_x`. 
735799                    return  Some ( ( projection_ty,  self . insert_deref ( projection_ty. ty ,  value) ) ) ; 
@@ -766,10 +830,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
766830            } 
767831            ProjectionElem :: Index ( idx)  => { 
768832                if  let  Value :: Repeat ( inner,  _)  = self . get ( value)  { 
769-                     * from_non_ssa_index |= self . locals [ idx] . is_none ( ) ; 
770833                    return  Some ( ( projection_ty,  inner) ) ; 
771834                } 
772-                 let  idx = self . locals [ idx] ?; 
773835                ProjectionElem :: Index ( idx) 
774836            } 
775837            ProjectionElem :: ConstantIndex  {  offset,  min_length,  from_end }  => { 
@@ -844,77 +906,74 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
844906        trace ! ( ?place) ; 
845907    } 
846908
847-     /// Represent the *value* which would be read from `place`, and point `place` to a preexisting  
848- /// place with the same value (if  that already exists) . 
909+     /// Represent the *value* which would be read from `place`. If we succeed, return it.  
910+ /// If we fail, return a `PlaceRef`  that contains the same value . 
849911#[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
850-     fn  simplify_place_value ( 
912+     fn  compute_place_value ( 
851913        & mut  self , 
852-         place :  & mut   Place < ' tcx > , 
914+         place :  Place < ' tcx > , 
853915        location :  Location , 
854-     )  -> Option < VnIndex >  { 
855-         self . simplify_place_projection ( place,  location) ; 
856- 
916+     )  -> Result < VnIndex ,  PlaceRef < ' tcx > >  { 
857917        // Invariant: `place` and `place_ref` point to the same value, even if they point to 
858918        // different memory locations. 
859919        let  mut  place_ref = place. as_ref ( ) ; 
860920
861921        // Invariant: `value` holds the value up-to the `index`th projection excluded. 
862-         let  mut  value = self . locals [ place. local ] ? ; 
922+         let  Some ( mut  value)  = self . locals [ place. local ]   else   {   return   Err ( place_ref )   } ; 
863923        // Invariant: `value` has type `place_ty`, with optional downcast variant if needed. 
864924        let  mut  place_ty = PlaceTy :: from_ty ( self . local_decls [ place. local ] . ty ) ; 
865-         let  mut  from_non_ssa_index = false ; 
866925        for  ( index,  proj)  in  place. projection . iter ( ) . enumerate ( )  { 
867-             if  let  Value :: Projection ( pointer,  ProjectionElem :: Deref )  = self . get ( value) 
868-                 && let  Value :: Address  {  place :  mut  pointee,  kind,  .. }  = self . get ( pointer) 
869-                 && let  AddressKind :: Ref ( BorrowKind :: Shared )  = kind
870-                 && let  Some ( v)  = self . simplify_place_value ( & mut  pointee,  location) 
871-             { 
872-                 value = v; 
873-                 // `pointee` holds a `Place`, so `ProjectionElem::Index` holds a `Local`. 
874-                 // That local is SSA, but we otherwise have no guarantee on that local's value at 
875-                 // the current location compared to its value where `pointee` was borrowed. 
876-                 if  pointee. projection . iter ( ) . all ( |elem| !matches ! ( elem,  ProjectionElem :: Index ( _) ) )  { 
877-                     place_ref =
878-                         pointee. project_deeper ( & place. projection [ index..] ,  self . tcx ) . as_ref ( ) ; 
879-                 } 
880-             } 
881926            if  let  Some ( local)  = self . try_as_local ( value,  location)  { 
882927                // Both `local` and `Place { local: place.local, projection: projection[..index] }` 
883928                // hold the same value. Therefore, following place holds the value in the original 
884929                // `place`. 
885930                place_ref = PlaceRef  {  local,  projection :  & place. projection [ index..]  } ; 
886931            } 
887932
888-             ( place_ty,  value)  = self . project ( place_ty,  value,  proj,  & mut  from_non_ssa_index) ?; 
933+             let  Some ( proj)  = proj. try_map ( |value| self . locals [ value] ,  |ty| ty)  else  { 
934+                 return  Err ( place_ref) ; 
935+             } ; 
936+             let  Some ( ty_and_value)  = self . project ( place_ty,  value,  proj)  else  { 
937+                 return  Err ( place_ref) ; 
938+             } ; 
939+             ( place_ty,  value)  = ty_and_value; 
889940        } 
890941
891-         if  let  Value :: Projection ( pointer,  ProjectionElem :: Deref )  = self . get ( value) 
892-             && let  Value :: Address  {  place :  mut  pointee,  kind,  .. }  = self . get ( pointer) 
893-             && let  AddressKind :: Ref ( BorrowKind :: Shared )  = kind
894-             && let  Some ( v)  = self . simplify_place_value ( & mut  pointee,  location) 
895-         { 
896-             value = v; 
897-             // `pointee` holds a `Place`, so `ProjectionElem::Index` holds a `Local`. 
898-             // That local is SSA, but we otherwise have no guarantee on that local's value at 
899-             // the current location compared to its value where `pointee` was borrowed. 
900-             if  pointee. projection . iter ( ) . all ( |elem| !matches ! ( elem,  ProjectionElem :: Index ( _) ) )  { 
901-                 place_ref = pointee. project_deeper ( & [ ] ,  self . tcx ) . as_ref ( ) ; 
902-             } 
903-         } 
904-         if  let  Some ( new_local)  = self . try_as_local ( value,  location)  { 
905-             place_ref = PlaceRef  {  local :  new_local,  projection :  & [ ]  } ; 
906-         }  else  if  from_non_ssa_index { 
907-             // If access to non-SSA locals is unavoidable, bail out. 
908-             return  None ; 
909-         } 
942+         Ok ( value) 
943+     } 
910944
911-         if  place_ref. local  != place. local  || place_ref. projection . len ( )  < place. projection . len ( )  { 
912-             // By the invariant on `place_ref`. 
913-             * place = place_ref. project_deeper ( & [ ] ,  self . tcx ) ; 
914-             self . reused_locals . insert ( place_ref. local ) ; 
915-         } 
945+     /// Represent the *value* which would be read from `place`, and point `place` to a preexisting 
946+ /// place with the same value (if that already exists). 
947+ #[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
948+     fn  simplify_place_value ( 
949+         & mut  self , 
950+         place :  & mut  Place < ' tcx > , 
951+         location :  Location , 
952+     )  -> Option < VnIndex >  { 
953+         self . simplify_place_projection ( place,  location) ; 
916954
917-         Some ( value) 
955+         match  self . compute_place_value ( * place,  location)  { 
956+             Ok ( value)  => { 
957+                 if  let  Some ( new_place)  = self . try_as_place ( value,  location,  true ) 
958+                     && ( new_place. local  != place. local 
959+                         || new_place. projection . len ( )  < place. projection . len ( ) ) 
960+                 { 
961+                     * place = new_place; 
962+                     self . reused_locals . insert ( new_place. local ) ; 
963+                 } 
964+                 Some ( value) 
965+             } 
966+             Err ( place_ref)  => { 
967+                 if  place_ref. local  != place. local 
968+                     || place_ref. projection . len ( )  < place. projection . len ( ) 
969+                 { 
970+                     // By the invariant on `place_ref`. 
971+                     * place = place_ref. project_deeper ( & [ ] ,  self . tcx ) ; 
972+                     self . reused_locals . insert ( place_ref. local ) ; 
973+                 } 
974+                 None 
975+             } 
976+         } 
918977    } 
919978
920979    #[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
@@ -961,11 +1020,11 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
9611020            Rvalue :: Aggregate ( ..)  => return  self . simplify_aggregate ( lhs,  rvalue,  location) , 
9621021            Rvalue :: Ref ( _,  borrow_kind,  ref  mut  place)  => { 
9631022                self . simplify_place_projection ( place,  location) ; 
964-                 return  Some ( self . new_pointer ( * place,  AddressKind :: Ref ( borrow_kind) ) ) ; 
1023+                 return  self . new_pointer ( * place,  AddressKind :: Ref ( borrow_kind) ) ; 
9651024            } 
9661025            Rvalue :: RawPtr ( mutbl,  ref  mut  place)  => { 
9671026                self . simplify_place_projection ( place,  location) ; 
968-                 return  Some ( self . new_pointer ( * place,  AddressKind :: Address ( mutbl) ) ) ; 
1027+                 return  self . new_pointer ( * place,  AddressKind :: Address ( mutbl) ) ; 
9691028            } 
9701029            Rvalue :: WrapUnsafeBinder ( ref  mut  op,  _)  => { 
9711030                let  value = self . simplify_operand ( op,  location) ?; 
@@ -1205,12 +1264,10 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
12051264                    } 
12061265
12071266                    // `&mut *p`, `&raw *p`, etc don't change metadata. 
1208-                     Value :: Address  {  place,  kind :  _,  provenance :  _ } 
1209-                         if  let  PlaceRef  {  local,  projection :  [ PlaceElem :: Deref ]  }  =
1210-                             place. as_ref ( ) 
1211-                             && let  Some ( local_index)  = self . locals [ local]  =>
1267+                     Value :: Address  {  base :  AddressBase :: Deref ( reborrowed) ,  projection,  .. } 
1268+                         if  projection. is_empty ( )  =>
12121269                    { 
1213-                         local_index 
1270+                         reborrowed 
12141271                    } 
12151272
12161273                    _ => break , 
0 commit comments