@@ -66,6 +66,7 @@ use rustc_middle::ty::layout::LayoutOf;
66
66
use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeAndMut } ;
67
67
use rustc_span:: DUMMY_SP ;
68
68
use rustc_target:: abi:: { self , Abi , Size , VariantIdx , FIRST_VARIANT } ;
69
+ use std:: borrow:: Cow ;
69
70
70
71
use crate :: dataflow_const_prop:: DummyMachine ;
71
72
use crate :: ssa:: { AssignedValue , SsaLocals } ;
@@ -461,6 +462,87 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
461
462
Some ( op)
462
463
}
463
464
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
+
464
546
/// Represent the *value* which would be read from `place`, and point `place` to a preexisting
465
547
/// place with the same value (if that already exists).
466
548
#[ instrument( level = "trace" , skip( self ) , ret) ]
@@ -469,6 +551,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
469
551
place : & mut Place < ' tcx > ,
470
552
location : Location ,
471
553
) -> Option < VnIndex > {
554
+ self . simplify_place_projection ( place, location) ;
555
+
472
556
// Invariant: `place` and `place_ref` point to the same value, even if they point to
473
557
// different memory locations.
474
558
let mut place_ref = place. as_ref ( ) ;
@@ -483,52 +567,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
483
567
place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
484
568
}
485
569
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) ?;
522
572
}
523
573
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 ( ) {
532
579
// By the invariant on `place_ref`.
533
580
* place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
534
581
self . reused_locals . insert ( place_ref. local ) ;
@@ -544,7 +591,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
544
591
location : Location ,
545
592
) -> Option < VnIndex > {
546
593
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
+ }
548
598
Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
549
599
let value = self . simplify_place_value ( place, location) ?;
550
600
if let Some ( const_) = self . try_as_constant ( value) {
@@ -594,11 +644,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
594
644
let ty = rvalue. ty ( self . local_decls , self . tcx ) ;
595
645
Value :: Aggregate ( ty, variant_index, fields?)
596
646
}
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) ) ;
599
650
}
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) ) ;
602
654
}
603
655
604
656
// Operations.
@@ -756,6 +808,10 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
756
808
self . tcx
757
809
}
758
810
811
+ fn visit_place ( & mut self , place : & mut Place < ' tcx > , _: PlaceContext , location : Location ) {
812
+ self . simplify_place_projection ( place, location) ;
813
+ }
814
+
759
815
fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
760
816
self . simplify_operand ( operand, location) ;
761
817
}
0 commit comments