@@ -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:: SsaLocals ;
@@ -454,6 +455,87 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
454
455
Some ( op)
455
456
}
456
457
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
+
457
539
/// Represent the *value* which would be read from `place`, and point `place` to a preexisting
458
540
/// place with the same value (if that already exists).
459
541
#[ instrument( level = "trace" , skip( self ) , ret) ]
@@ -462,6 +544,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
462
544
place : & mut Place < ' tcx > ,
463
545
location : Location ,
464
546
) -> Option < VnIndex > {
547
+ self . simplify_place_projection ( place, location) ;
548
+
465
549
// Invariant: `place` and `place_ref` point to the same value, even if they point to
466
550
// different memory locations.
467
551
let mut place_ref = place. as_ref ( ) ;
@@ -476,52 +560,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
476
560
place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
477
561
}
478
562
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) ?;
515
565
}
516
566
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 ( ) {
525
572
// By the invariant on `place_ref`.
526
573
* place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
527
574
self . reused_locals . insert ( place_ref. local ) ;
@@ -537,7 +584,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
537
584
location : Location ,
538
585
) -> Option < VnIndex > {
539
586
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
+ }
541
591
Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
542
592
let value = self . simplify_place_value ( place, location) ?;
543
593
if let Some ( const_) = self . try_as_constant ( value) {
@@ -587,11 +637,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
587
637
let ty = rvalue. ty ( self . local_decls , self . tcx ) ;
588
638
Value :: Aggregate ( ty, variant_index, fields?)
589
639
}
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) ) ;
592
643
}
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) ) ;
595
647
}
596
648
597
649
// Operations.
@@ -749,6 +801,10 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
749
801
self . tcx
750
802
}
751
803
804
+ fn visit_place ( & mut self , place : & mut Place < ' tcx > , _: PlaceContext , location : Location ) {
805
+ self . simplify_place_projection ( place, location) ;
806
+ }
807
+
752
808
fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
753
809
self . simplify_operand ( operand, location) ;
754
810
}
0 commit comments