@@ -14,8 +14,7 @@ use rustc_middle::mir::visit::{
14
14
} ;
15
15
use rustc_middle:: mir:: * ;
16
16
use rustc_middle:: ty:: layout:: { LayoutError , LayoutOf , LayoutOfHelpers , TyAndLayout } ;
17
- use rustc_middle:: ty:: GenericArgs ;
18
- use rustc_middle:: ty:: { self , ConstKind , Instance , ParamEnv , Ty , TyCtxt , TypeVisitableExt } ;
17
+ use rustc_middle:: ty:: { self , GenericArgs , Instance , ParamEnv , Ty , TyCtxt , TypeVisitableExt } ;
19
18
use rustc_span:: { def_id:: DefId , Span , DUMMY_SP } ;
20
19
use rustc_target:: abi:: { self , Align , HasDataLayout , Size , TargetDataLayout } ;
21
20
use rustc_target:: spec:: abi:: Abi as CallAbi ;
@@ -434,24 +433,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
434
433
}
435
434
436
435
fn propagate_operand ( & mut self , operand : & mut Operand < ' tcx > ) {
437
- match * operand {
438
- Operand :: Copy ( l) | Operand :: Move ( l) => {
439
- if let Some ( value) = self . get_const ( l) && self . should_const_prop ( & value) {
440
- // FIXME(felix91gr): this code only handles `Scalar` cases.
441
- // For now, we're not handling `ScalarPair` cases because
442
- // doing so here would require a lot of code duplication.
443
- // We should hopefully generalize `Operand` handling into a fn,
444
- // and use it to do const-prop here and everywhere else
445
- // where it makes sense.
446
- if let interpret:: Operand :: Immediate ( interpret:: Immediate :: Scalar (
447
- scalar,
448
- ) ) = * value
449
- {
450
- * operand = self . operand_from_scalar ( scalar, value. layout . ty ) ;
451
- }
452
- }
453
- }
454
- Operand :: Constant ( _) => ( ) ,
436
+ if let Some ( place) = operand. place ( ) && let Some ( op) = self . replace_with_const ( place) {
437
+ * operand = op;
455
438
}
456
439
}
457
440
@@ -579,78 +562,63 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
579
562
} ) )
580
563
}
581
564
582
- fn replace_with_const ( & mut self , place : Place < ' tcx > , rval : & mut Rvalue < ' tcx > ) {
565
+ fn replace_with_const ( & mut self , place : Place < ' tcx > ) -> Option < Operand < ' tcx > > {
583
566
// This will return None if the above `const_prop` invocation only "wrote" a
584
567
// type whose creation requires no write. E.g. a generator whose initial state
585
568
// consists solely of uninitialized memory (so it doesn't capture any locals).
586
- let Some ( ref value) = self . get_const ( place) else { return } ;
587
- if !self . should_const_prop ( value) {
588
- return ;
589
- }
590
- trace ! ( "replacing {:?}={:?} with {:?}" , place, rval, value) ;
591
-
592
- if let Rvalue :: Use ( Operand :: Constant ( c) ) = rval {
593
- match c. literal {
594
- ConstantKind :: Ty ( c) if matches ! ( c. kind( ) , ConstKind :: Unevaluated ( ..) ) => { }
595
- _ => {
596
- trace ! ( "skipping replace of Rvalue::Use({:?} because it is already a const" , c) ;
597
- return ;
598
- }
599
- }
569
+ let value = self . get_const ( place) ?;
570
+ if !self . should_const_prop ( & value) {
571
+ return None ;
600
572
}
573
+ trace ! ( "replacing {:?} with {:?}" , place, value) ;
601
574
602
- trace ! ( "attempting to replace {:?} with {:?}" , rval, value) ;
603
575
// FIXME> figure out what to do when read_immediate_raw fails
604
- let imm = self . ecx . read_immediate_raw ( value) . ok ( ) ;
576
+ let imm = self . ecx . read_immediate_raw ( & value) . ok ( ) ? ;
605
577
606
- if let Some ( Right ( imm) ) = imm {
607
- match * imm {
608
- interpret:: Immediate :: Scalar ( scalar) => {
609
- * rval = Rvalue :: Use ( self . operand_from_scalar ( scalar, value. layout . ty ) ) ;
610
- }
611
- Immediate :: ScalarPair ( ..) => {
612
- // Found a value represented as a pair. For now only do const-prop if the type
613
- // of `rvalue` is also a tuple with two scalars.
614
- // FIXME: enable the general case stated above ^.
615
- let ty = value. layout . ty ;
616
- // Only do it for tuples
617
- if let ty:: Tuple ( types) = ty. kind ( ) {
618
- // Only do it if tuple is also a pair with two scalars
619
- if let [ ty1, ty2] = types[ ..] {
620
- let ty_is_scalar = |ty| {
621
- self . ecx . layout_of ( ty) . ok ( ) . map ( |layout| layout. abi . is_scalar ( ) )
622
- == Some ( true )
623
- } ;
624
- let alloc = if ty_is_scalar ( ty1) && ty_is_scalar ( ty2) {
625
- let alloc = self
626
- . ecx
627
- . intern_with_temp_alloc ( value. layout , |ecx, dest| {
628
- ecx. write_immediate ( * imm, dest)
629
- } )
630
- . unwrap ( ) ;
631
- Some ( alloc)
632
- } else {
633
- None
634
- } ;
635
-
636
- if let Some ( alloc) = alloc {
637
- // Assign entire constant in a single statement.
638
- // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
639
- let const_val = ConstValue :: ByRef { alloc, offset : Size :: ZERO } ;
640
- let literal = ConstantKind :: Val ( const_val, ty) ;
641
- * rval = Rvalue :: Use ( Operand :: Constant ( Box :: new ( Constant {
642
- span : DUMMY_SP ,
643
- user_ty : None ,
644
- literal,
645
- } ) ) ) ;
646
- }
647
- }
648
- }
578
+ let Right ( imm) = imm else { return None } ;
579
+ match * imm {
580
+ interpret:: Immediate :: Scalar ( scalar) => {
581
+ Some ( self . operand_from_scalar ( scalar, value. layout . ty ) )
582
+ }
583
+ Immediate :: ScalarPair ( ..) => {
584
+ // Found a value represented as a pair. For now only do const-prop if the type
585
+ // of `rvalue` is also a tuple with two scalars.
586
+ // FIXME: enable the general case stated above ^.
587
+ let ty = value. layout . ty ;
588
+ // Only do it for tuples
589
+ let ty:: Tuple ( types) = ty. kind ( ) else { return None } ;
590
+ // Only do it if tuple is also a pair with two scalars
591
+ if let [ ty1, ty2] = types[ ..] {
592
+ let ty_is_scalar = |ty| {
593
+ self . ecx . layout_of ( ty) . ok ( ) . map ( |layout| layout. abi . is_scalar ( ) )
594
+ == Some ( true )
595
+ } ;
596
+ let alloc = if ty_is_scalar ( ty1) && ty_is_scalar ( ty2) {
597
+ self . ecx
598
+ . intern_with_temp_alloc ( value. layout , |ecx, dest| {
599
+ ecx. write_immediate ( * imm, dest)
600
+ } )
601
+ . unwrap ( )
602
+ } else {
603
+ return None ;
604
+ } ;
605
+
606
+ // Assign entire constant in a single statement.
607
+ // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
608
+ let const_val = ConstValue :: ByRef { alloc, offset : Size :: ZERO } ;
609
+ let literal = ConstantKind :: Val ( const_val, ty) ;
610
+ Some ( Operand :: Constant ( Box :: new ( Constant {
611
+ span : DUMMY_SP ,
612
+ user_ty : None ,
613
+ literal,
614
+ } ) ) )
615
+ } else {
616
+ None
649
617
}
650
- // Scalars or scalar pairs that contain undef values are assumed to not have
651
- // successfully evaluated and are thus not propagated.
652
- _ => { }
653
618
}
619
+ // Scalars or scalar pairs that contain undef values are assumed to not have
620
+ // successfully evaluated and are thus not propagated.
621
+ _ => None ,
654
622
}
655
623
}
656
624
@@ -847,7 +815,14 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
847
815
ConstPropMode :: NoPropagation => self . ensure_not_propagated ( place. local ) ,
848
816
ConstPropMode :: OnlyInsideOwnBlock | ConstPropMode :: FullConstProp => {
849
817
if let Some ( ( ) ) = self . eval_rvalue_with_identities ( rvalue, * place) {
850
- self . replace_with_const ( * place, rvalue) ;
818
+ // If this was already an evaluated constant, keep it.
819
+ if let Rvalue :: Use ( Operand :: Constant ( c) ) = rvalue
820
+ && let ConstantKind :: Val ( ..) = c. literal
821
+ {
822
+ trace ! ( "skipping replace of Rvalue::Use({:?} because it is already a const" , c) ;
823
+ } else if let Some ( operand) = self . replace_with_const ( * place) {
824
+ * rvalue = Rvalue :: Use ( operand) ;
825
+ }
851
826
} else {
852
827
// Const prop failed, so erase the destination, ensuring that whatever happens
853
828
// from here on, does not know about the previous value.
0 commit comments