@@ -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:: SsaLocals ;
@@ -453,6 +454,86 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
453454 Some ( op)
454455 }
455456
457+ fn project (
458+ & mut self ,
459+ place : PlaceRef < ' tcx > ,
460+ value : VnIndex ,
461+ proj : PlaceElem < ' tcx > ,
462+ ) -> Option < VnIndex > {
463+ let proj = match proj {
464+ ProjectionElem :: Deref => {
465+ let ty = place. ty ( self . local_decls , self . tcx ) . ty ;
466+ if let Some ( Mutability :: Not ) = ty. ref_mutability ( )
467+ && let Some ( pointee_ty) = ty. builtin_deref ( true )
468+ && pointee_ty. ty . is_freeze ( self . tcx , self . param_env )
469+ {
470+ // An immutable borrow `_x` always points to the same value for the
471+ // lifetime of the borrow, so we can merge all instances of `*_x`.
472+ ProjectionElem :: Deref
473+ } else {
474+ return None ;
475+ }
476+ }
477+ ProjectionElem :: Downcast ( name, index) => ProjectionElem :: Downcast ( name, index) ,
478+ ProjectionElem :: Field ( f, ty) => ProjectionElem :: Field ( f, ty) ,
479+ ProjectionElem :: Index ( idx) => {
480+ let idx = self . locals [ idx] ?;
481+ ProjectionElem :: Index ( idx)
482+ }
483+ ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
484+ ProjectionElem :: ConstantIndex { offset, min_length, from_end }
485+ }
486+ ProjectionElem :: Subslice { from, to, from_end } => {
487+ ProjectionElem :: Subslice { from, to, from_end }
488+ }
489+ ProjectionElem :: OpaqueCast ( ty) => ProjectionElem :: OpaqueCast ( ty) ,
490+ } ;
491+
492+ Some ( self . insert ( Value :: Projection ( value, proj) ) )
493+ }
494+
495+ /// Simplify the projection chain if we know better.
496+ #[ instrument( level = "trace" , skip( self ) ) ]
497+ fn simplify_place_projection ( & mut self , place : & mut Place < ' tcx > , location : Location ) {
498+ // If the projection is indirect, we treat the local as a value, so can replace it with
499+ // another local.
500+ if place. is_indirect ( )
501+ && let Some ( base) = self . locals [ place. local ]
502+ && let Some ( new_local) = self . try_as_local ( base, location)
503+ {
504+ place. local = new_local;
505+ self . reused_locals . insert ( new_local) ;
506+ }
507+
508+ let mut projection = Cow :: Borrowed ( & place. projection [ ..] ) ;
509+
510+ for i in 0 ..projection. len ( ) {
511+ let elem = projection[ i] ;
512+ if let ProjectionElem :: Index ( idx) = elem
513+ && let Some ( idx) = self . locals [ idx]
514+ {
515+ if let Some ( offset) = self . evaluated [ idx] . as_ref ( )
516+ && let Ok ( offset) = self . ecx . read_target_usize ( offset)
517+ {
518+ projection. to_mut ( ) [ i] = ProjectionElem :: ConstantIndex {
519+ offset,
520+ min_length : offset + 1 ,
521+ from_end : false ,
522+ } ;
523+ } else if let Some ( new_idx) = self . try_as_local ( idx, location) {
524+ projection. to_mut ( ) [ i] = ProjectionElem :: Index ( new_idx) ;
525+ self . reused_locals . insert ( new_idx) ;
526+ }
527+ }
528+ }
529+
530+ if projection. is_owned ( ) {
531+ place. projection = self . tcx . mk_place_elems ( & projection) ;
532+ }
533+
534+ trace ! ( ?place) ;
535+ }
536+
456537 /// Represent the *value* which would be read from `place`, and point `place` to a preexisting
457538 /// place with the same value (if that already exists).
458539 #[ instrument( level = "trace" , skip( self ) , ret) ]
@@ -461,6 +542,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
461542 place : & mut Place < ' tcx > ,
462543 location : Location ,
463544 ) -> Option < VnIndex > {
545+ self . simplify_place_projection ( place, location) ;
546+
464547 // Invariant: `place` and `place_ref` point to the same value, even if they point to
465548 // different memory locations.
466549 let mut place_ref = place. as_ref ( ) ;
@@ -475,51 +558,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
475558 place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
476559 }
477560
478- let proj = match proj {
479- ProjectionElem :: Deref => {
480- let ty = Place :: ty_from (
481- place. local ,
482- & place. projection [ ..index] ,
483- self . local_decls ,
484- self . tcx ,
485- )
486- . ty ;
487- if let Some ( Mutability :: Not ) = ty. ref_mutability ( )
488- && let Some ( pointee_ty) = ty. builtin_deref ( true )
489- && pointee_ty. ty . is_freeze ( self . tcx , self . param_env )
490- {
491- // An immutable borrow `_x` always points to the same value for the
492- // lifetime of the borrow, so we can merge all instances of `*_x`.
493- ProjectionElem :: Deref
494- } else {
495- return None ;
496- }
497- }
498- ProjectionElem :: Field ( f, ty) => ProjectionElem :: Field ( f, ty) ,
499- ProjectionElem :: Index ( idx) => {
500- let idx = self . locals [ idx] ?;
501- ProjectionElem :: Index ( idx)
502- }
503- ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
504- ProjectionElem :: ConstantIndex { offset, min_length, from_end }
505- }
506- ProjectionElem :: Subslice { from, to, from_end } => {
507- ProjectionElem :: Subslice { from, to, from_end }
508- }
509- ProjectionElem :: Downcast ( name, index) => ProjectionElem :: Downcast ( name, index) ,
510- ProjectionElem :: OpaqueCast ( ty) => ProjectionElem :: OpaqueCast ( ty) ,
511- } ;
512- value = self . insert ( Value :: Projection ( value, proj) ) ;
561+ let base = PlaceRef { local : place. local , projection : & place. projection [ ..index] } ;
562+ value = self . project ( base, value, proj) ?;
513563 }
514564
515- if let Some ( local) = self . try_as_local ( value, location)
516- && local != place. local // in case we had no projection to begin with.
517- {
518- * place = local. into ( ) ;
519- self . reused_locals . insert ( local) ;
520- } else if place_ref. local != place. local
521- || place_ref. projection . len ( ) < place. projection . len ( )
522- {
565+ if let Some ( new_local) = self . try_as_local ( value, location) {
566+ place_ref = PlaceRef { local : new_local, projection : & [ ] } ;
567+ }
568+
569+ if place_ref. local != place. local || place_ref. projection . len ( ) < place. projection . len ( ) {
523570 // By the invariant on `place_ref`.
524571 * place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
525572 self . reused_locals . insert ( place_ref. local ) ;
@@ -535,7 +582,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
535582 location : Location ,
536583 ) -> Option < VnIndex > {
537584 match * operand {
538- Operand :: Constant ( ref constant) => Some ( self . insert ( Value :: Constant ( constant. const_ ) ) ) ,
585+ Operand :: Constant ( ref mut constant) => {
586+ let const_ = constant. const_ . normalize ( self . tcx , self . param_env ) ;
587+ Some ( self . insert ( Value :: Constant ( const_) ) )
588+ }
539589 Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
540590 let value = self . simplify_place_value ( place, location) ?;
541591 if let Some ( const_) = self . try_as_constant ( value) {
@@ -585,11 +635,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
585635 let ty = rvalue. ty ( self . local_decls , self . tcx ) ;
586636 Value :: Aggregate ( ty, variant_index, fields?)
587637 }
588- Rvalue :: Ref ( _, borrow_kind, place) => {
589- return self . new_pointer ( place, AddressKind :: Ref ( borrow_kind) ) ;
638+ Rvalue :: Ref ( _, borrow_kind, ref mut place) => {
639+ self . simplify_place_projection ( place, location) ;
640+ return self . new_pointer ( * place, AddressKind :: Ref ( borrow_kind) ) ;
590641 }
591- Rvalue :: AddressOf ( mutbl, place) => {
592- return self . new_pointer ( place, AddressKind :: Address ( mutbl) ) ;
642+ Rvalue :: AddressOf ( mutbl, ref mut place) => {
643+ self . simplify_place_projection ( place, location) ;
644+ return self . new_pointer ( * place, AddressKind :: Address ( mutbl) ) ;
593645 }
594646
595647 // Operations.
@@ -747,6 +799,10 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
747799 self . tcx
748800 }
749801
802+ fn visit_place ( & mut self , place : & mut Place < ' tcx > , _: PlaceContext , location : Location ) {
803+ self . simplify_place_projection ( place, location) ;
804+ }
805+
750806 fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
751807 self . simplify_operand ( operand, location) ;
752808 }
0 commit comments