@@ -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 ;
@@ -454,6 +455,87 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
454455 Some ( op)
455456 }
456457
458+ fn project (
459+ & mut self ,
460+ place : PlaceRef < ' tcx > ,
461+ value : VnIndex ,
462+ proj : PlaceElem < ' tcx > ,
463+ ) -> Option < VnIndex > {
464+ let proj = match proj {
465+ ProjectionElem :: Deref => {
466+ let ty = place. ty ( self . local_decls , self . tcx ) . ty ;
467+ if let Some ( Mutability :: Not ) = ty. ref_mutability ( )
468+ && let Some ( pointee_ty) = ty. builtin_deref ( true )
469+ && pointee_ty. ty . is_freeze ( self . tcx , self . param_env )
470+ {
471+ // An immutable borrow `_x` always points to the same value for the
472+ // lifetime of the borrow, so we can merge all instances of `*_x`.
473+ ProjectionElem :: Deref
474+ } else {
475+ return None ;
476+ }
477+ }
478+ ProjectionElem :: Downcast ( name, index) => ProjectionElem :: Downcast ( name, index) ,
479+ ProjectionElem :: Field ( f, ty) => ProjectionElem :: Field ( f, ty) ,
480+ ProjectionElem :: Index ( idx) => {
481+ let idx = self . locals [ idx] ?;
482+ ProjectionElem :: Index ( idx)
483+ }
484+ ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
485+ ProjectionElem :: ConstantIndex { offset, min_length, from_end }
486+ }
487+ ProjectionElem :: Subslice { from, to, from_end } => {
488+ ProjectionElem :: Subslice { from, to, from_end }
489+ }
490+ ProjectionElem :: OpaqueCast ( ty) => ProjectionElem :: OpaqueCast ( ty) ,
491+ ProjectionElem :: Subtype ( ty) => ProjectionElem :: Subtype ( ty) ,
492+ } ;
493+
494+ Some ( self . insert ( Value :: Projection ( value, proj) ) )
495+ }
496+
497+ /// Simplify the projection chain if we know better.
498+ #[ instrument( level = "trace" , skip( self ) ) ]
499+ fn simplify_place_projection ( & mut self , place : & mut Place < ' tcx > , location : Location ) {
500+ // If the projection is indirect, we treat the local as a value, so can replace it with
501+ // another local.
502+ if place. is_indirect ( )
503+ && let Some ( base) = self . locals [ place. local ]
504+ && let Some ( new_local) = self . try_as_local ( base, location)
505+ {
506+ place. local = new_local;
507+ self . reused_locals . insert ( new_local) ;
508+ }
509+
510+ let mut projection = Cow :: Borrowed ( & place. projection [ ..] ) ;
511+
512+ for i in 0 ..projection. len ( ) {
513+ let elem = projection[ i] ;
514+ if let ProjectionElem :: Index ( idx) = elem
515+ && let Some ( idx) = self . locals [ idx]
516+ {
517+ if let Some ( offset) = self . evaluated [ idx] . as_ref ( )
518+ && let Ok ( offset) = self . ecx . read_target_usize ( offset)
519+ {
520+ projection. to_mut ( ) [ i] = ProjectionElem :: ConstantIndex {
521+ offset,
522+ min_length : offset + 1 ,
523+ from_end : false ,
524+ } ;
525+ } else if let Some ( new_idx) = self . try_as_local ( idx, location) {
526+ projection. to_mut ( ) [ i] = ProjectionElem :: Index ( new_idx) ;
527+ self . reused_locals . insert ( new_idx) ;
528+ }
529+ }
530+ }
531+
532+ if projection. is_owned ( ) {
533+ place. projection = self . tcx . mk_place_elems ( & projection) ;
534+ }
535+
536+ trace ! ( ?place) ;
537+ }
538+
457539 /// Represent the *value* which would be read from `place`, and point `place` to a preexisting
458540 /// place with the same value (if that already exists).
459541 #[ instrument( level = "trace" , skip( self ) , ret) ]
@@ -462,6 +544,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
462544 place : & mut Place < ' tcx > ,
463545 location : Location ,
464546 ) -> Option < VnIndex > {
547+ self . simplify_place_projection ( place, location) ;
548+
465549 // Invariant: `place` and `place_ref` point to the same value, even if they point to
466550 // different memory locations.
467551 let mut place_ref = place. as_ref ( ) ;
@@ -476,52 +560,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
476560 place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
477561 }
478562
479- let proj = match proj {
480- ProjectionElem :: Deref => {
481- let ty = Place :: ty_from (
482- place. local ,
483- & place. projection [ ..index] ,
484- self . local_decls ,
485- self . tcx ,
486- )
487- . ty ;
488- if let Some ( Mutability :: Not ) = ty. ref_mutability ( )
489- && let Some ( pointee_ty) = ty. builtin_deref ( true )
490- && pointee_ty. ty . is_freeze ( self . tcx , self . param_env )
491- {
492- // An immutable borrow `_x` always points to the same value for the
493- // lifetime of the borrow, so we can merge all instances of `*_x`.
494- ProjectionElem :: Deref
495- } else {
496- return None ;
497- }
498- }
499- ProjectionElem :: Field ( f, ty) => ProjectionElem :: Field ( f, ty) ,
500- ProjectionElem :: Index ( idx) => {
501- let idx = self . locals [ idx] ?;
502- ProjectionElem :: Index ( idx)
503- }
504- ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
505- ProjectionElem :: ConstantIndex { offset, min_length, from_end }
506- }
507- ProjectionElem :: Subslice { from, to, from_end } => {
508- ProjectionElem :: Subslice { from, to, from_end }
509- }
510- ProjectionElem :: Downcast ( name, index) => ProjectionElem :: Downcast ( name, index) ,
511- ProjectionElem :: OpaqueCast ( ty) => ProjectionElem :: OpaqueCast ( ty) ,
512- ProjectionElem :: Subtype ( ty) => ProjectionElem :: Subtype ( ty) ,
513- } ;
514- value = self . insert ( Value :: Projection ( value, proj) ) ;
563+ let base = PlaceRef { local : place. local , projection : & place. projection [ ..index] } ;
564+ value = self . project ( base, value, proj) ?;
515565 }
516566
517- if let Some ( local) = self . try_as_local ( value, location)
518- && local != place. local // in case we had no projection to begin with.
519- {
520- * place = local. into ( ) ;
521- self . reused_locals . insert ( local) ;
522- } else if place_ref. local != place. local
523- || place_ref. projection . len ( ) < place. projection . len ( )
524- {
567+ if let Some ( new_local) = self . try_as_local ( value, location) {
568+ place_ref = PlaceRef { local : new_local, projection : & [ ] } ;
569+ }
570+
571+ if place_ref. local != place. local || place_ref. projection . len ( ) < place. projection . len ( ) {
525572 // By the invariant on `place_ref`.
526573 * place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
527574 self . reused_locals . insert ( place_ref. local ) ;
@@ -537,7 +584,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
537584 location : Location ,
538585 ) -> Option < VnIndex > {
539586 match * operand {
540- Operand :: Constant ( ref constant) => Some ( self . insert ( Value :: Constant ( constant. const_ ) ) ) ,
587+ Operand :: Constant ( ref mut constant) => {
588+ let const_ = constant. const_ . normalize ( self . tcx , self . param_env ) ;
589+ Some ( self . insert ( Value :: Constant ( const_) ) )
590+ }
541591 Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
542592 let value = self . simplify_place_value ( place, location) ?;
543593 if let Some ( const_) = self . try_as_constant ( value) {
@@ -587,11 +637,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
587637 let ty = rvalue. ty ( self . local_decls , self . tcx ) ;
588638 Value :: Aggregate ( ty, variant_index, fields?)
589639 }
590- Rvalue :: Ref ( _, borrow_kind, place) => {
591- return self . new_pointer ( place, AddressKind :: Ref ( borrow_kind) ) ;
640+ Rvalue :: Ref ( _, borrow_kind, ref mut place) => {
641+ self . simplify_place_projection ( place, location) ;
642+ return self . new_pointer ( * place, AddressKind :: Ref ( borrow_kind) ) ;
592643 }
593- Rvalue :: AddressOf ( mutbl, place) => {
594- return self . new_pointer ( place, AddressKind :: Address ( mutbl) ) ;
644+ Rvalue :: AddressOf ( mutbl, ref mut place) => {
645+ self . simplify_place_projection ( place, location) ;
646+ return self . new_pointer ( * place, AddressKind :: Address ( mutbl) ) ;
595647 }
596648
597649 // Operations.
@@ -749,6 +801,10 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
749801 self . tcx
750802 }
751803
804+ fn visit_place ( & mut self , place : & mut Place < ' tcx > , _: PlaceContext , location : Location ) {
805+ self . simplify_place_projection ( place, location) ;
806+ }
807+
752808 fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
753809 self . simplify_operand ( operand, location) ;
754810 }
0 commit comments