@@ -66,6 +66,7 @@ use rustc_middle::ty::layout::LayoutOf;
6666use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeAndMut } ;
6767use rustc_span:: DUMMY_SP ;
6868use rustc_target:: abi:: { self , Abi , Size , VariantIdx , FIRST_VARIANT } ;
69+ use std:: borrow:: Cow ;
6970
7071use crate :: dataflow_const_prop:: DummyMachine ;
7172use crate :: ssa:: { AssignedValue , SsaLocals } ;
@@ -461,6 +462,87 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
461462 Some ( op)
462463 }
463464
465+ fn project (
466+ & mut self ,
467+ place : PlaceRef < ' tcx > ,
468+ value : VnIndex ,
469+ proj : PlaceElem < ' tcx > ,
470+ ) -> Option < VnIndex > {
471+ let proj = match proj {
472+ ProjectionElem :: Deref => {
473+ let ty = place. ty ( self . local_decls , self . tcx ) . ty ;
474+ if let Some ( Mutability :: Not ) = ty. ref_mutability ( )
475+ && let Some ( pointee_ty) = ty. builtin_deref ( true )
476+ && pointee_ty. ty . is_freeze ( self . tcx , self . param_env )
477+ {
478+ // An immutable borrow `_x` always points to the same value for the
479+ // lifetime of the borrow, so we can merge all instances of `*_x`.
480+ ProjectionElem :: Deref
481+ } else {
482+ return None ;
483+ }
484+ }
485+ ProjectionElem :: Downcast ( name, index) => ProjectionElem :: Downcast ( name, index) ,
486+ ProjectionElem :: Field ( f, ty) => ProjectionElem :: Field ( f, ty) ,
487+ ProjectionElem :: Index ( idx) => {
488+ let idx = self . locals [ idx] ?;
489+ ProjectionElem :: Index ( idx)
490+ }
491+ ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
492+ ProjectionElem :: ConstantIndex { offset, min_length, from_end }
493+ }
494+ ProjectionElem :: Subslice { from, to, from_end } => {
495+ ProjectionElem :: Subslice { from, to, from_end }
496+ }
497+ ProjectionElem :: OpaqueCast ( ty) => ProjectionElem :: OpaqueCast ( ty) ,
498+ ProjectionElem :: Subtype ( ty) => ProjectionElem :: Subtype ( ty) ,
499+ } ;
500+
501+ Some ( self . insert ( Value :: Projection ( value, proj) ) )
502+ }
503+
504+ /// Simplify the projection chain if we know better.
505+ #[ instrument( level = "trace" , skip( self ) ) ]
506+ fn simplify_place_projection ( & mut self , place : & mut Place < ' tcx > , location : Location ) {
507+ // If the projection is indirect, we treat the local as a value, so can replace it with
508+ // another local.
509+ if place. is_indirect ( )
510+ && let Some ( base) = self . locals [ place. local ]
511+ && let Some ( new_local) = self . try_as_local ( base, location)
512+ {
513+ place. local = new_local;
514+ self . reused_locals . insert ( new_local) ;
515+ }
516+
517+ let mut projection = Cow :: Borrowed ( & place. projection [ ..] ) ;
518+
519+ for i in 0 ..projection. len ( ) {
520+ let elem = projection[ i] ;
521+ if let ProjectionElem :: Index ( idx) = elem
522+ && let Some ( idx) = self . locals [ idx]
523+ {
524+ if let Some ( offset) = self . evaluated [ idx] . as_ref ( )
525+ && let Ok ( offset) = self . ecx . read_target_usize ( offset)
526+ {
527+ projection. to_mut ( ) [ i] = ProjectionElem :: ConstantIndex {
528+ offset,
529+ min_length : offset + 1 ,
530+ from_end : false ,
531+ } ;
532+ } else if let Some ( new_idx) = self . try_as_local ( idx, location) {
533+ projection. to_mut ( ) [ i] = ProjectionElem :: Index ( new_idx) ;
534+ self . reused_locals . insert ( new_idx) ;
535+ }
536+ }
537+ }
538+
539+ if projection. is_owned ( ) {
540+ place. projection = self . tcx . mk_place_elems ( & projection) ;
541+ }
542+
543+ trace ! ( ?place) ;
544+ }
545+
464546 /// Represent the *value* which would be read from `place`, and point `place` to a preexisting
465547 /// place with the same value (if that already exists).
466548 #[ instrument( level = "trace" , skip( self ) , ret) ]
@@ -469,6 +551,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
469551 place : & mut Place < ' tcx > ,
470552 location : Location ,
471553 ) -> Option < VnIndex > {
554+ self . simplify_place_projection ( place, location) ;
555+
472556 // Invariant: `place` and `place_ref` point to the same value, even if they point to
473557 // different memory locations.
474558 let mut place_ref = place. as_ref ( ) ;
@@ -483,52 +567,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
483567 place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
484568 }
485569
486- let proj = match proj {
487- ProjectionElem :: Deref => {
488- let ty = Place :: ty_from (
489- place. local ,
490- & place. projection [ ..index] ,
491- self . local_decls ,
492- self . tcx ,
493- )
494- . ty ;
495- if let Some ( Mutability :: Not ) = ty. ref_mutability ( )
496- && let Some ( pointee_ty) = ty. builtin_deref ( true )
497- && pointee_ty. ty . is_freeze ( self . tcx , self . param_env )
498- {
499- // An immutable borrow `_x` always points to the same value for the
500- // lifetime of the borrow, so we can merge all instances of `*_x`.
501- ProjectionElem :: Deref
502- } else {
503- return None ;
504- }
505- }
506- ProjectionElem :: Field ( f, ty) => ProjectionElem :: Field ( f, ty) ,
507- ProjectionElem :: Index ( idx) => {
508- let idx = self . locals [ idx] ?;
509- ProjectionElem :: Index ( idx)
510- }
511- ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
512- ProjectionElem :: ConstantIndex { offset, min_length, from_end }
513- }
514- ProjectionElem :: Subslice { from, to, from_end } => {
515- ProjectionElem :: Subslice { from, to, from_end }
516- }
517- ProjectionElem :: Downcast ( name, index) => ProjectionElem :: Downcast ( name, index) ,
518- ProjectionElem :: OpaqueCast ( ty) => ProjectionElem :: OpaqueCast ( ty) ,
519- ProjectionElem :: Subtype ( ty) => ProjectionElem :: Subtype ( ty) ,
520- } ;
521- value = self . insert ( Value :: Projection ( value, proj) ) ;
570+ let base = PlaceRef { local : place. local , projection : & place. projection [ ..index] } ;
571+ value = self . project ( base, value, proj) ?;
522572 }
523573
524- if let Some ( local) = self . try_as_local ( value, location)
525- && local != place. local // in case we had no projection to begin with.
526- {
527- * place = local. into ( ) ;
528- self . reused_locals . insert ( local) ;
529- } else if place_ref. local != place. local
530- || place_ref. projection . len ( ) < place. projection . len ( )
531- {
574+ if let Some ( new_local) = self . try_as_local ( value, location) {
575+ place_ref = PlaceRef { local : new_local, projection : & [ ] } ;
576+ }
577+
578+ if place_ref. local != place. local || place_ref. projection . len ( ) < place. projection . len ( ) {
532579 // By the invariant on `place_ref`.
533580 * place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
534581 self . reused_locals . insert ( place_ref. local ) ;
@@ -544,7 +591,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
544591 location : Location ,
545592 ) -> Option < VnIndex > {
546593 match * operand {
547- Operand :: Constant ( ref constant) => Some ( self . insert ( Value :: Constant ( constant. const_ ) ) ) ,
594+ Operand :: Constant ( ref mut constant) => {
595+ let const_ = constant. const_ . normalize ( self . tcx , self . param_env ) ;
596+ Some ( self . insert ( Value :: Constant ( const_) ) )
597+ }
548598 Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
549599 let value = self . simplify_place_value ( place, location) ?;
550600 if let Some ( const_) = self . try_as_constant ( value) {
@@ -594,11 +644,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
594644 let ty = rvalue. ty ( self . local_decls , self . tcx ) ;
595645 Value :: Aggregate ( ty, variant_index, fields?)
596646 }
597- Rvalue :: Ref ( _, borrow_kind, place) => {
598- return self . new_pointer ( place, AddressKind :: Ref ( borrow_kind) ) ;
647+ Rvalue :: Ref ( _, borrow_kind, ref mut place) => {
648+ self . simplify_place_projection ( place, location) ;
649+ return self . new_pointer ( * place, AddressKind :: Ref ( borrow_kind) ) ;
599650 }
600- Rvalue :: AddressOf ( mutbl, place) => {
601- return self . new_pointer ( place, AddressKind :: Address ( mutbl) ) ;
651+ Rvalue :: AddressOf ( mutbl, ref mut place) => {
652+ self . simplify_place_projection ( place, location) ;
653+ return self . new_pointer ( * place, AddressKind :: Address ( mutbl) ) ;
602654 }
603655
604656 // Operations.
@@ -756,6 +808,10 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
756808 self . tcx
757809 }
758810
811+ fn visit_place ( & mut self , place : & mut Place < ' tcx > , _: PlaceContext , location : Location ) {
812+ self . simplify_place_projection ( place, location) ;
813+ }
814+
759815 fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
760816 self . simplify_operand ( operand, location) ;
761817 }
0 commit comments