@@ -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 ;
@@ -453,6 +454,86 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
453
454
Some ( op)
454
455
}
455
456
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
+
456
537
/// Represent the *value* which would be read from `place`, and point `place` to a preexisting
457
538
/// place with the same value (if that already exists).
458
539
#[ instrument( level = "trace" , skip( self ) , ret) ]
@@ -461,6 +542,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
461
542
place : & mut Place < ' tcx > ,
462
543
location : Location ,
463
544
) -> Option < VnIndex > {
545
+ self . simplify_place_projection ( place, location) ;
546
+
464
547
// Invariant: `place` and `place_ref` point to the same value, even if they point to
465
548
// different memory locations.
466
549
let mut place_ref = place. as_ref ( ) ;
@@ -475,51 +558,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
475
558
place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
476
559
}
477
560
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) ?;
513
563
}
514
564
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 ( ) {
523
570
// By the invariant on `place_ref`.
524
571
* place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
525
572
self . reused_locals . insert ( place_ref. local ) ;
@@ -535,7 +582,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
535
582
location : Location ,
536
583
) -> Option < VnIndex > {
537
584
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
+ }
539
589
Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
540
590
let value = self . simplify_place_value ( place, location) ?;
541
591
if let Some ( const_) = self . try_as_constant ( value) {
@@ -585,11 +635,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
585
635
let ty = rvalue. ty ( self . local_decls , self . tcx ) ;
586
636
Value :: Aggregate ( ty, variant_index, fields?)
587
637
}
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) ) ;
590
641
}
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) ) ;
593
645
}
594
646
595
647
// Operations.
@@ -747,6 +799,10 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
747
799
self . tcx
748
800
}
749
801
802
+ fn visit_place ( & mut self , place : & mut Place < ' tcx > , _: PlaceContext , location : Location ) {
803
+ self . simplify_place_projection ( place, location) ;
804
+ }
805
+
750
806
fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
751
807
self . simplify_operand ( operand, location) ;
752
808
}
0 commit comments