@@ -164,6 +164,14 @@ enum AddressKind {
164164    Address ( RawPtrKind ) , 
165165} 
166166
167+ #[ derive( Copy ,  Clone ,  Debug ,  PartialEq ,  Eq ,  Hash ) ]  
168+ enum  AddressBase  { 
169+     /// This address is based on this local. 
170+ Local ( Local ) , 
171+     /// This address is based on the deref of this pointer. 
172+ Deref ( VnIndex ) , 
173+ } 
174+ 
167175#[ derive( Copy ,  Clone ,  Debug ,  PartialEq ,  Eq ,  Hash ) ]  
168176enum  Value < ' a ,  ' tcx >  { 
169177    // Root values. 
@@ -192,7 +200,10 @@ enum Value<'a, 'tcx> {
192200Repeat ( VnIndex ,  ty:: Const < ' tcx > ) , 
193201    /// The address of a place. 
194202Address  { 
195-         place :  Place < ' tcx > , 
203+         base :  AddressBase , 
204+         // We do not use a plain `Place` as we want to be able to reason about indices. 
205+         // This does not contain any `Deref` projection. 
206+         projection :  & ' a  [ ProjectionElem < VnIndex ,  Ty < ' tcx > > ] , 
196207        kind :  AddressKind , 
197208        /// Give each borrow and pointer a different provenance, so we don't merge them. 
198209provenance :  usize , 
@@ -309,16 +320,38 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
309320
310321    /// Create a new `Value::Address` distinct from all the others. 
311322#[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
312-     fn  new_pointer ( & mut  self ,  place :  Place < ' tcx > ,  kind :  AddressKind )  -> VnIndex  { 
323+     fn  new_pointer ( 
324+         & mut  self , 
325+         place :  Place < ' tcx > , 
326+         kind :  AddressKind , 
327+         location :  Location , 
328+     )  -> Option < VnIndex >  { 
313329        let  pty = place. ty ( self . local_decls ,  self . tcx ) . ty ; 
314330        let  ty = match  kind { 
315331            AddressKind :: Ref ( bk)  => { 
316332                Ty :: new_ref ( self . tcx ,  self . tcx . lifetimes . re_erased ,  pty,  bk. to_mutbl_lossy ( ) ) 
317333            } 
318334            AddressKind :: Address ( mutbl)  => Ty :: new_ptr ( self . tcx ,  pty,  mutbl. to_mutbl_lossy ( ) ) , 
319335        } ; 
320-         let  value = Value :: Address  {  place,  kind,  provenance :  self . next_opaque ( )  } ; 
321-         self . insert ( ty,  value) 
336+ 
337+         let  mut  projection = place. projection . iter ( ) ; 
338+         let  base = if  place. is_indirect_first_projection ( )  { 
339+             let  base = self . locals [ place. local ] ?; 
340+             // Skip the initial `Deref`. 
341+             projection. next ( ) ; 
342+             AddressBase :: Deref ( base) 
343+         }  else  { 
344+             AddressBase :: Local ( place. local ) 
345+         } ; 
346+         // Do not try evaluating inside `Index`, this has been done by `simplify_place_value`. 
347+         let  projection = self 
348+             . arena 
349+             . try_alloc_from_iter ( 
350+                 projection. map ( |proj| proj. try_map ( |value| self . locals [ value] ,  |ty| ty) . ok_or ( ( ) ) ) , 
351+             ) 
352+             . ok ( ) ?; 
353+         let  value = Value :: Address  {  base,  projection,  kind,  provenance :  self . next_opaque ( )  } ; 
354+         Some ( self . insert ( ty,  value) ) 
322355    } 
323356
324357    #[ inline]  
@@ -459,14 +492,15 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
459492                let  elem = elem. try_map ( |_| None ,  |( ) | ty. ty ) ?; 
460493                self . ecx . project ( base,  elem) . discard_err ( ) ?
461494            } 
462-             Address  {  place,  kind :  _,  provenance :  _ }  => { 
463-                 if  !place. is_indirect_first_projection ( )  { 
464-                     return  None ; 
465-                 } 
466-                 let  local = self . locals [ place. local ] ?; 
467-                 let  pointer = self . evaluated [ local] . as_ref ( ) ?; 
495+             Address  {  base,  projection,  .. }  => { 
496+                 debug_assert ! ( !projection. contains( & ProjectionElem :: Deref ) ) ; 
497+                 let  pointer = match  base { 
498+                     AddressBase :: Deref ( pointer)  => self . evaluated [ pointer] . as_ref ( ) ?, 
499+                     // We have no stack to point to. 
500+                     AddressBase :: Local ( _)  => return  None , 
501+                 } ; 
468502                let  mut  mplace = self . ecx . deref_pointer ( pointer) . discard_err ( ) ?; 
469-                 for  elem in  place . projection . iter ( ) . skip ( 1 )  { 
503+                 for  elem in  projection { 
470504                    // `Index` by constants should have been replaced by `ConstantIndex` by 
471505                    // `simplify_place_projection`. 
472506                    let  elem = elem. try_map ( |_| None ,  |ty| ty) ?; 
@@ -590,19 +624,51 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
590624        Some ( op) 
591625    } 
592626
627+     /// Represent the *value* we obtain by dereferencing an `Address` value. 
628+ #[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
629+     fn  dereference_address ( 
630+         & mut  self , 
631+         base :  AddressBase , 
632+         projection :  & [ ProjectionElem < VnIndex ,  Ty < ' tcx > > ] , 
633+     )  -> Option < VnIndex >  { 
634+         let  ( mut  place_ty,  mut  value)  = match  base { 
635+             // The base is a local, so we take the local's value and project from it. 
636+             AddressBase :: Local ( local)  => { 
637+                 let  local = self . locals [ local] ?; 
638+                 let  place_ty = PlaceTy :: from_ty ( self . ty ( local) ) ; 
639+                 ( place_ty,  local) 
640+             } 
641+             // The base is a pointer's deref, so we introduce the implicit deref. 
642+             AddressBase :: Deref ( reborrow)  => { 
643+                 let  place_ty = PlaceTy :: from_ty ( self . ty ( reborrow) ) ; 
644+                 self . project ( place_ty,  reborrow,  ProjectionElem :: Deref ) ?
645+             } 
646+         } ; 
647+         for  & proj in  projection { 
648+             ( place_ty,  value)  = self . project ( place_ty,  value,  proj) ?; 
649+         } 
650+         Some ( value) 
651+     } 
652+ 
653+     #[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
593654    fn  project ( 
594655        & mut  self , 
595656        place_ty :  PlaceTy < ' tcx > , 
596657        value :  VnIndex , 
597-         proj :  PlaceElem < ' tcx > , 
598-         from_non_ssa_index :  & mut  bool , 
658+         proj :  ProjectionElem < VnIndex ,  Ty < ' tcx > > , 
599659    )  -> Option < ( PlaceTy < ' tcx > ,  VnIndex ) >  { 
600660        let  projection_ty = place_ty. projection_ty ( self . tcx ,  proj) ; 
601661        let  proj = match  proj { 
602662            ProjectionElem :: Deref  => { 
603663                if  let  Some ( Mutability :: Not )  = place_ty. ty . ref_mutability ( ) 
604664                    && projection_ty. ty . is_freeze ( self . tcx ,  self . typing_env ( ) ) 
605665                { 
666+                     if  let  Value :: Address  {  base,  projection,  .. }  = self . get ( value) 
667+                         && let  Some ( value)  = self . dereference_address ( base,  projection) 
668+                     { 
669+                         return  Some ( ( projection_ty,  value) ) ; 
670+                     } 
671+ 
606672                    // An immutable borrow `_x` always points to the same value for the 
607673                    // lifetime of the borrow, so we can merge all instances of `*_x`. 
608674                    return  Some ( ( projection_ty,  self . insert_deref ( projection_ty. ty ,  value) ) ) ; 
@@ -639,10 +705,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
639705            } 
640706            ProjectionElem :: Index ( idx)  => { 
641707                if  let  Value :: Repeat ( inner,  _)  = self . get ( value)  { 
642-                     * from_non_ssa_index |= self . locals [ idx] . is_none ( ) ; 
643708                    return  Some ( ( projection_ty,  inner) ) ; 
644709                } 
645-                 let  idx = self . locals [ idx] ?; 
646710                ProjectionElem :: Index ( idx) 
647711            } 
648712            ProjectionElem :: ConstantIndex  {  offset,  min_length,  from_end }  => { 
@@ -721,74 +785,71 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
721785    /// Represent the *value* which would be read from `place`, and point `place` to a preexisting 
722786/// place with the same value (if that already exists). 
723787#[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
724-     fn  simplify_place_value ( 
788+     fn  compute_place_value ( 
725789        & mut  self , 
726-         place :  & mut   Place < ' tcx > , 
790+         place :  Place < ' tcx > , 
727791        location :  Location , 
728-     )  -> Option < VnIndex >  { 
729-         self . simplify_place_projection ( place,  location) ; 
730- 
792+     )  -> Result < VnIndex ,  PlaceRef < ' tcx > >  { 
731793        // Invariant: `place` and `place_ref` point to the same value, even if they point to 
732794        // different memory locations. 
733795        let  mut  place_ref = place. as_ref ( ) ; 
734796
735797        // Invariant: `value` holds the value up-to the `index`th projection excluded. 
736-         let  mut  value = self . locals [ place. local ] ? ; 
798+         let  Some ( mut  value)  = self . locals [ place. local ]   else   {   return   Err ( place_ref )   } ; 
737799        // Invariant: `value` has type `place_ty`, with optional downcast variant if needed. 
738800        let  mut  place_ty = PlaceTy :: from_ty ( self . local_decls [ place. local ] . ty ) ; 
739-         let  mut  from_non_ssa_index = false ; 
740801        for  ( index,  proj)  in  place. projection . iter ( ) . enumerate ( )  { 
741-             if  let  Value :: Projection ( pointer,  ProjectionElem :: Deref )  = self . get ( value) 
742-                 && let  Value :: Address  {  place :  mut  pointee,  kind,  .. }  = self . get ( pointer) 
743-                 && let  AddressKind :: Ref ( BorrowKind :: Shared )  = kind
744-                 && let  Some ( v)  = self . simplify_place_value ( & mut  pointee,  location) 
745-             { 
746-                 value = v; 
747-                 // `pointee` holds a `Place`, so `ProjectionElem::Index` holds a `Local`. 
748-                 // That local is SSA, but we otherwise have no guarantee on that local's value at 
749-                 // the current location compared to its value where `pointee` was borrowed. 
750-                 if  pointee. projection . iter ( ) . all ( |elem| !matches ! ( elem,  ProjectionElem :: Index ( _) ) )  { 
751-                     place_ref =
752-                         pointee. project_deeper ( & place. projection [ index..] ,  self . tcx ) . as_ref ( ) ; 
753-                 } 
754-             } 
755802            if  let  Some ( local)  = self . try_as_local ( value,  location)  { 
756803                // Both `local` and `Place { local: place.local, projection: projection[..index] }` 
757804                // hold the same value. Therefore, following place holds the value in the original 
758805                // `place`. 
759806                place_ref = PlaceRef  {  local,  projection :  & place. projection [ index..]  } ; 
760807            } 
761808
762-             ( place_ty,  value)  = self . project ( place_ty,  value,  proj,  & mut  from_non_ssa_index) ?; 
809+             let  Some ( proj)  = proj. try_map ( |value| self . locals [ value] ,  |ty| ty)  else  { 
810+                 return  Err ( place_ref) ; 
811+             } ; 
812+             let  Some ( ty_and_value)  = self . project ( place_ty,  value,  proj)  else  { 
813+                 return  Err ( place_ref) ; 
814+             } ; 
815+             ( place_ty,  value)  = ty_and_value; 
763816        } 
764817
765-         if  let  Value :: Projection ( pointer,  ProjectionElem :: Deref )  = self . get ( value) 
766-             && let  Value :: Address  {  place :  mut  pointee,  kind,  .. }  = self . get ( pointer) 
767-             && let  AddressKind :: Ref ( BorrowKind :: Shared )  = kind
768-             && let  Some ( v)  = self . simplify_place_value ( & mut  pointee,  location) 
769-         { 
770-             value = v; 
771-             // `pointee` holds a `Place`, so `ProjectionElem::Index` holds a `Local`. 
772-             // That local is SSA, but we otherwise have no guarantee on that local's value at 
773-             // the current location compared to its value where `pointee` was borrowed. 
774-             if  pointee. projection . iter ( ) . all ( |elem| !matches ! ( elem,  ProjectionElem :: Index ( _) ) )  { 
775-                 place_ref = pointee. project_deeper ( & [ ] ,  self . tcx ) . as_ref ( ) ; 
776-             } 
777-         } 
778-         if  let  Some ( new_local)  = self . try_as_local ( value,  location)  { 
779-             place_ref = PlaceRef  {  local :  new_local,  projection :  & [ ]  } ; 
780-         }  else  if  from_non_ssa_index { 
781-             // If access to non-SSA locals is unavoidable, bail out. 
782-             return  None ; 
783-         } 
818+         Ok ( value) 
819+     } 
784820
785-         if  place_ref. local  != place. local  || place_ref. projection . len ( )  < place. projection . len ( )  { 
786-             // By the invariant on `place_ref`. 
787-             * place = place_ref. project_deeper ( & [ ] ,  self . tcx ) ; 
788-             self . reused_locals . insert ( place_ref. local ) ; 
789-         } 
821+     /// Represent the *value* which would be read from `place`, and point `place` to a preexisting 
822+ /// place with the same value (if that already exists). 
823+ #[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
824+     fn  simplify_place_value ( 
825+         & mut  self , 
826+         place :  & mut  Place < ' tcx > , 
827+         location :  Location , 
828+     )  -> Option < VnIndex >  { 
829+         self . simplify_place_projection ( place,  location) ; 
790830
791-         Some ( value) 
831+         match  self . compute_place_value ( * place,  location)  { 
832+             Ok ( value)  => { 
833+                 if  let  Some ( new_place)  = self . try_as_place ( value,  location,  true ) 
834+                     && ( new_place. local  != place. local 
835+                         || new_place. projection . len ( )  < place. projection . len ( ) ) 
836+                 { 
837+                     * place = new_place; 
838+                     self . reused_locals . insert ( new_place. local ) ; 
839+                 } 
840+                 Some ( value) 
841+             } 
842+             Err ( place_ref)  => { 
843+                 if  place_ref. local  != place. local 
844+                     || place_ref. projection . len ( )  < place. projection . len ( ) 
845+                 { 
846+                     // By the invariant on `place_ref`. 
847+                     * place = place_ref. project_deeper ( & [ ] ,  self . tcx ) ; 
848+                     self . reused_locals . insert ( place_ref. local ) ; 
849+                 } 
850+                 None 
851+             } 
852+         } 
792853    } 
793854
794855    #[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
@@ -835,11 +896,11 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
835896            Rvalue :: Aggregate ( ..)  => return  self . simplify_aggregate ( lhs,  rvalue,  location) , 
836897            Rvalue :: Ref ( _,  borrow_kind,  ref  mut  place)  => { 
837898                self . simplify_place_projection ( place,  location) ; 
838-                 return  Some ( self . new_pointer ( * place,  AddressKind :: Ref ( borrow_kind) ) ) ; 
899+                 return  self . new_pointer ( * place,  AddressKind :: Ref ( borrow_kind) ,  location ) ; 
839900            } 
840901            Rvalue :: RawPtr ( mutbl,  ref  mut  place)  => { 
841902                self . simplify_place_projection ( place,  location) ; 
842-                 return  Some ( self . new_pointer ( * place,  AddressKind :: Address ( mutbl) ) ) ; 
903+                 return  self . new_pointer ( * place,  AddressKind :: Address ( mutbl) ,  location ) ; 
843904            } 
844905            Rvalue :: WrapUnsafeBinder ( ref  mut  op,  _)  => { 
845906                let  value = self . simplify_operand ( op,  location) ?; 
@@ -1070,12 +1131,10 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
10701131                    } 
10711132
10721133                    // `&mut *p`, `&raw *p`, etc don't change metadata. 
1073-                     Value :: Address  {  place,  kind :  _,  provenance :  _ } 
1074-                         if  let  PlaceRef  {  local,  projection :  [ PlaceElem :: Deref ]  }  =
1075-                             place. as_ref ( ) 
1076-                             && let  Some ( local_index)  = self . locals [ local]  =>
1134+                     Value :: Address  {  base :  AddressBase :: Deref ( reborrowed) ,  projection,  .. } 
1135+                         if  projection. is_empty ( )  =>
10771136                    { 
1078-                         arg_index = local_index ; 
1137+                         arg_index = reborrowed ; 
10791138                        was_updated = true ; 
10801139                        continue ; 
10811140                    } 
@@ -1421,9 +1480,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
14211480
14221481        // The length information is stored in the wide pointer. 
14231482        // Reborrowing copies length information from one pointer to the other. 
1424-         while  let  Value :: Address  {  place :   borrowed,   .. }  =  self . get ( inner ) 
1425-             &&  let   [ PlaceElem :: Deref ]  = borrowed . projection [ .. ] 
1426-             && let   Some ( borrowed )  =  self . locals [ borrowed . local ] 
1483+         while  let  Value :: Address  {  base :   AddressBase :: Deref ( borrowed) ,  projection ,   .. }  =
1484+             self . get ( inner ) 
1485+             && projection . is_empty ( ) 
14271486        { 
14281487            inner = borrowed; 
14291488        } 
0 commit comments