@@ -13,11 +13,7 @@ use rustc_index::vec::IndexVec;
13
13
use rustc_middle:: mir:: visit:: {
14
14
MutVisitor , MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor ,
15
15
} ;
16
- use rustc_middle:: mir:: {
17
- BasicBlock , BinOp , Body , Constant , ConstantKind , Local , LocalDecl , LocalKind , Location ,
18
- Operand , Place , Rvalue , SourceInfo , Statement , StatementKind , Terminator , TerminatorKind ,
19
- RETURN_PLACE ,
20
- } ;
16
+ use rustc_middle:: mir:: * ;
21
17
use rustc_middle:: ty:: layout:: { LayoutError , LayoutOf , LayoutOfHelpers , TyAndLayout } ;
22
18
use rustc_middle:: ty:: InternalSubsts ;
23
19
use rustc_middle:: ty:: { self , ConstKind , Instance , ParamEnv , Ty , TyCtxt , TypeVisitable } ;
@@ -456,27 +452,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
456
452
} ;
457
453
}
458
454
459
- fn use_ecx < F , T > ( & mut self , f : F ) -> Option < T >
460
- where
461
- F : FnOnce ( & mut Self ) -> InterpResult < ' tcx , T > ,
462
- {
463
- match f ( self ) {
464
- Ok ( val) => Some ( val) ,
465
- Err ( error) => {
466
- trace ! ( "InterpCx operation failed: {:?}" , error) ;
467
- // Some errors shouldn't come up because creating them causes
468
- // an allocation, which we should avoid. When that happens,
469
- // dedicated error variants should be introduced instead.
470
- assert ! (
471
- !error. kind( ) . formatted_string( ) ,
472
- "const-prop encountered formatting error: {}" ,
473
- error
474
- ) ;
475
- None
476
- }
477
- }
478
- }
479
-
480
455
/// Returns the value, if any, of evaluating `c`.
481
456
fn eval_constant ( & mut self , c : & Constant < ' tcx > ) -> Option < OpTy < ' tcx > > {
482
457
// FIXME we need to revisit this for #67176
@@ -491,7 +466,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
491
466
/// Returns the value, if any, of evaluating `place`.
492
467
fn eval_place ( & mut self , place : Place < ' tcx > ) -> Option < OpTy < ' tcx > > {
493
468
trace ! ( "eval_place(place={:?})" , place) ;
494
- self . use_ecx ( |this| this . ecx . eval_place_to_op ( place, None ) )
469
+ self . ecx . eval_place_to_op ( place, None ) . ok ( )
495
470
}
496
471
497
472
/// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant`
@@ -595,52 +570,54 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
595
570
rvalue : & Rvalue < ' tcx > ,
596
571
place : Place < ' tcx > ,
597
572
) -> Option < ( ) > {
598
- self . use_ecx ( |this| match rvalue {
573
+ match rvalue {
599
574
Rvalue :: BinaryOp ( op, box ( left, right) )
600
575
| Rvalue :: CheckedBinaryOp ( op, box ( left, right) ) => {
601
- let l = this . ecx . eval_operand ( left, None ) . and_then ( |x| this . ecx . read_immediate ( & x) ) ;
576
+ let l = self . ecx . eval_operand ( left, None ) . and_then ( |x| self . ecx . read_immediate ( & x) ) ;
602
577
let r =
603
- this . ecx . eval_operand ( right, None ) . and_then ( |x| this . ecx . read_immediate ( & x) ) ;
578
+ self . ecx . eval_operand ( right, None ) . and_then ( |x| self . ecx . read_immediate ( & x) ) ;
604
579
605
580
let const_arg = match ( l, r) {
606
581
( Ok ( x) , Err ( _) ) | ( Err ( _) , Ok ( x) ) => x, // exactly one side is known
607
- ( Err ( e ) , Err ( _) ) => return Err ( e ) , // neither side is known
608
- ( Ok ( _) , Ok ( _) ) => return this . ecx . eval_rvalue_into_place ( rvalue, place) , // both sides are known
582
+ ( Err ( _ ) , Err ( _) ) => return None , // neither side is known
583
+ ( Ok ( _) , Ok ( _) ) => return self . ecx . eval_rvalue_into_place ( rvalue, place) . ok ( ) , // both sides are known
609
584
} ;
610
585
611
586
if !matches ! ( const_arg. layout. abi, abi:: Abi :: Scalar ( ..) ) {
612
587
// We cannot handle Scalar Pair stuff.
613
588
// No point in calling `eval_rvalue_into_place`, since only one side is known
614
- throw_machine_stop_str ! ( "cannot optimize this" )
589
+ return None ;
615
590
}
616
591
617
- let arg_value = const_arg. to_scalar ( ) . to_bits ( const_arg. layout . size ) ?;
618
- let dest = this . ecx . eval_place ( place) ?;
592
+ let arg_value = const_arg. to_scalar ( ) . to_bits ( const_arg. layout . size ) . ok ( ) ?;
593
+ let dest = self . ecx . eval_place ( place) . ok ( ) ?;
619
594
620
595
match op {
621
- BinOp :: BitAnd if arg_value == 0 => this. ecx . write_immediate ( * const_arg, & dest) ,
596
+ BinOp :: BitAnd if arg_value == 0 => {
597
+ self . ecx . write_immediate ( * const_arg, & dest) . ok ( )
598
+ }
622
599
BinOp :: BitOr
623
600
if arg_value == const_arg. layout . size . truncate ( u128:: MAX )
624
601
|| ( const_arg. layout . ty . is_bool ( ) && arg_value == 1 ) =>
625
602
{
626
- this . ecx . write_immediate ( * const_arg, & dest)
603
+ self . ecx . write_immediate ( * const_arg, & dest) . ok ( )
627
604
}
628
605
BinOp :: Mul if const_arg. layout . ty . is_integral ( ) && arg_value == 0 => {
629
606
if let Rvalue :: CheckedBinaryOp ( _, _) = rvalue {
630
607
let val = Immediate :: ScalarPair (
631
608
const_arg. to_scalar ( ) ,
632
609
Scalar :: from_bool ( false ) ,
633
610
) ;
634
- this . ecx . write_immediate ( val, & dest)
611
+ self . ecx . write_immediate ( val, & dest) . ok ( )
635
612
} else {
636
- this . ecx . write_immediate ( * const_arg, & dest)
613
+ self . ecx . write_immediate ( * const_arg, & dest) . ok ( )
637
614
}
638
615
}
639
- _ => throw_machine_stop_str ! ( "cannot optimize this" ) ,
616
+ _ => None ,
640
617
}
641
618
}
642
- _ => this . ecx . eval_rvalue_into_place ( rvalue, place) ,
643
- } )
619
+ _ => self . ecx . eval_rvalue_into_place ( rvalue, place) . ok ( ) ,
620
+ }
644
621
}
645
622
646
623
/// Creates a new `Operand::Constant` from a `Scalar` value
@@ -682,7 +659,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
682
659
}
683
660
684
661
// FIXME> figure out what to do when read_immediate_raw fails
685
- let imm = self . use_ecx ( |this| this . ecx . read_immediate_raw ( value) ) ;
662
+ let imm = self . ecx . read_immediate_raw ( value) . ok ( ) ;
686
663
687
664
if let Some ( Right ( imm) ) = imm {
688
665
match * imm {
@@ -702,25 +679,23 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
702
679
if let ty:: Tuple ( types) = ty. kind ( ) {
703
680
// Only do it if tuple is also a pair with two scalars
704
681
if let [ ty1, ty2] = types[ ..] {
705
- let alloc = self . use_ecx ( |this| {
706
- let ty_is_scalar = |ty| {
707
- this. ecx . layout_of ( ty) . ok ( ) . map ( |layout| layout. abi . is_scalar ( ) )
708
- == Some ( true )
709
- } ;
710
- if ty_is_scalar ( ty1) && ty_is_scalar ( ty2) {
711
- let alloc = this
712
- . ecx
713
- . intern_with_temp_alloc ( value. layout , |ecx, dest| {
714
- ecx. write_immediate ( * imm, dest)
715
- } )
716
- . unwrap ( ) ;
717
- Ok ( Some ( alloc) )
718
- } else {
719
- Ok ( None )
720
- }
721
- } ) ;
722
-
723
- if let Some ( Some ( alloc) ) = alloc {
682
+ let ty_is_scalar = |ty| {
683
+ self . ecx . layout_of ( ty) . ok ( ) . map ( |layout| layout. abi . is_scalar ( ) )
684
+ == Some ( true )
685
+ } ;
686
+ let alloc = if ty_is_scalar ( ty1) && ty_is_scalar ( ty2) {
687
+ let alloc = self
688
+ . ecx
689
+ . intern_with_temp_alloc ( value. layout , |ecx, dest| {
690
+ ecx. write_immediate ( * imm, dest)
691
+ } )
692
+ . unwrap ( ) ;
693
+ Some ( alloc)
694
+ } else {
695
+ None
696
+ } ;
697
+
698
+ if let Some ( alloc) = alloc {
724
699
// Assign entire constant in a single statement.
725
700
// We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
726
701
let const_val = ConstValue :: ByRef { alloc, offset : Size :: ZERO } ;
@@ -921,84 +896,80 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
921
896
trace ! ( "visit_statement: {:?}" , statement) ;
922
897
let source_info = statement. source_info ;
923
898
self . source_info = Some ( source_info) ;
924
- if let StatementKind :: Assign ( box ( place, ref mut rval) ) = statement. kind {
925
- let can_const_prop = self . ecx . machine . can_const_prop [ place. local ] ;
926
- if let Some ( ( ) ) = self . const_prop ( rval, place) {
927
- // This will return None if the above `const_prop` invocation only "wrote" a
928
- // type whose creation requires no write. E.g. a generator whose initial state
929
- // consists solely of uninitialized memory (so it doesn't capture any locals).
930
- if let Some ( ref value) = self . get_const ( place) && self . should_const_prop ( value) {
931
- trace ! ( "replacing {:?} with {:?}" , rval, value) ;
932
- self . replace_with_const ( rval, value, source_info) ;
933
- if can_const_prop == ConstPropMode :: FullConstProp
934
- || can_const_prop == ConstPropMode :: OnlyInsideOwnBlock
935
- {
936
- trace ! ( "propagated into {:?}" , place) ;
899
+ match statement. kind {
900
+ StatementKind :: Assign ( box ( place, ref mut rval) ) => {
901
+ let can_const_prop = self . ecx . machine . can_const_prop [ place. local ] ;
902
+ if let Some ( ( ) ) = self . const_prop ( rval, place) {
903
+ // This will return None if the above `const_prop` invocation only "wrote" a
904
+ // type whose creation requires no write. E.g. a generator whose initial state
905
+ // consists solely of uninitialized memory (so it doesn't capture any locals).
906
+ if let Some ( ref value) = self . get_const ( place) && self . should_const_prop ( value) {
907
+ trace ! ( "replacing {:?} with {:?}" , rval, value) ;
908
+ self . replace_with_const ( rval, value, source_info) ;
909
+ if can_const_prop == ConstPropMode :: FullConstProp
910
+ || can_const_prop == ConstPropMode :: OnlyInsideOwnBlock
911
+ {
912
+ trace ! ( "propagated into {:?}" , place) ;
913
+ }
937
914
}
938
- }
939
- match can_const_prop {
940
- ConstPropMode :: OnlyInsideOwnBlock => {
941
- trace ! (
942
- "found local restricted to its block. \
915
+ match can_const_prop {
916
+ ConstPropMode :: OnlyInsideOwnBlock => {
917
+ trace ! (
918
+ "found local restricted to its block. \
943
919
Will remove it from const-prop after block is finished. Local: {:?}",
944
- place. local
945
- ) ;
946
- }
947
- ConstPropMode :: OnlyPropagateInto | ConstPropMode :: NoPropagation => {
948
- trace ! ( "can't propagate into {:?}" , place) ;
949
- if place. local != RETURN_PLACE {
950
- Self :: remove_const ( & mut self . ecx , place. local ) ;
920
+ place. local
921
+ ) ;
951
922
}
952
- }
953
- ConstPropMode :: FullConstProp => { }
954
- }
955
- } else {
956
- // Const prop failed, so erase the destination, ensuring that whatever happens
957
- // from here on, does not know about the previous value.
958
- // This is important in case we have
959
- // ```rust
960
- // let mut x = 42;
961
- // x = SOME_MUTABLE_STATIC;
962
- // // x must now be uninit
963
- // ```
964
- // FIXME: we overzealously erase the entire local, because that's easier to
965
- // implement.
966
- trace ! (
967
- "propagation into {:?} failed.
968
- Nuking the entire site from orbit, it's the only way to be sure" ,
969
- place,
970
- ) ;
971
- Self :: remove_const ( & mut self . ecx , place. local ) ;
972
- }
973
- } else {
974
- match statement. kind {
975
- StatementKind :: SetDiscriminant { ref place, .. } => {
976
- match self . ecx . machine . can_const_prop [ place. local ] {
977
- ConstPropMode :: FullConstProp | ConstPropMode :: OnlyInsideOwnBlock => {
978
- if self . use_ecx ( |this| this. ecx . statement ( statement) ) . is_some ( ) {
979
- trace ! ( "propped discriminant into {:?}" , place) ;
980
- } else {
923
+ ConstPropMode :: OnlyPropagateInto | ConstPropMode :: NoPropagation => {
924
+ trace ! ( "can't propagate into {:?}" , place) ;
925
+ if place. local != RETURN_PLACE {
981
926
Self :: remove_const ( & mut self . ecx , place. local ) ;
982
927
}
983
928
}
984
- ConstPropMode :: OnlyPropagateInto | ConstPropMode :: NoPropagation => {
985
- Self :: remove_const ( & mut self . ecx , place. local ) ;
986
- }
929
+ ConstPropMode :: FullConstProp => { }
987
930
}
931
+ } else {
932
+ // Const prop failed, so erase the destination, ensuring that whatever happens
933
+ // from here on, does not know about the previous value.
934
+ // This is important in case we have
935
+ // ```rust
936
+ // let mut x = 42;
937
+ // x = SOME_MUTABLE_STATIC;
938
+ // // x must now be uninit
939
+ // ```
940
+ // FIXME: we overzealously erase the entire local, because that's easier to
941
+ // implement.
942
+ trace ! (
943
+ "propagation into {:?} failed.
944
+ Nuking the entire site from orbit, it's the only way to be sure" ,
945
+ place,
946
+ ) ;
947
+ Self :: remove_const ( & mut self . ecx , place. local ) ;
988
948
}
989
- StatementKind :: StorageLive ( local) | StatementKind :: StorageDead ( local) => {
990
- let frame = self . ecx . frame_mut ( ) ;
991
- frame. locals [ local] . value =
992
- if let StatementKind :: StorageLive ( _) = statement. kind {
993
- LocalValue :: Live ( interpret:: Operand :: Immediate (
994
- interpret:: Immediate :: Uninit ,
995
- ) )
949
+ }
950
+ StatementKind :: SetDiscriminant { ref place, .. } => {
951
+ match self . ecx . machine . can_const_prop [ place. local ] {
952
+ ConstPropMode :: FullConstProp | ConstPropMode :: OnlyInsideOwnBlock => {
953
+ if self . ecx . statement ( statement) . is_ok ( ) {
954
+ trace ! ( "propped discriminant into {:?}" , place) ;
996
955
} else {
997
- LocalValue :: Dead
998
- } ;
956
+ Self :: remove_const ( & mut self . ecx , place. local ) ;
957
+ }
958
+ }
959
+ ConstPropMode :: OnlyPropagateInto | ConstPropMode :: NoPropagation => {
960
+ Self :: remove_const ( & mut self . ecx , place. local ) ;
961
+ }
999
962
}
1000
- _ => { }
1001
963
}
964
+ StatementKind :: StorageLive ( local) | StatementKind :: StorageDead ( local) => {
965
+ let frame = self . ecx . frame_mut ( ) ;
966
+ frame. locals [ local] . value = if let StatementKind :: StorageLive ( _) = statement. kind {
967
+ LocalValue :: Live ( interpret:: Operand :: Immediate ( interpret:: Immediate :: Uninit ) )
968
+ } else {
969
+ LocalValue :: Dead
970
+ } ;
971
+ }
972
+ _ => { }
1002
973
}
1003
974
1004
975
self . super_statement ( statement, location) ;
@@ -1008,12 +979,10 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
1008
979
let source_info = terminator. source_info ;
1009
980
self . source_info = Some ( source_info) ;
1010
981
self . super_terminator ( terminator, location) ;
1011
- // Do NOT early return in this function, it does some crucial fixup of the state at the end!
982
+
1012
983
match & mut terminator. kind {
1013
984
TerminatorKind :: Assert { expected, ref mut cond, .. } => {
1014
985
if let Some ( ref value) = self . eval_operand ( & cond)
1015
- // FIXME should be used use_ecx rather than a local match... but we have
1016
- // quite a few of these read_scalar/read_immediate that need fixing.
1017
986
&& let Ok ( value_const) = self . ecx . read_scalar ( & value)
1018
987
&& self . should_const_prop ( value)
1019
988
{
@@ -1050,6 +1019,10 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
1050
1019
// gated on `mir_opt_level=3`.
1051
1020
TerminatorKind :: Call { .. } => { }
1052
1021
}
1022
+ }
1023
+
1024
+ fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & mut BasicBlockData < ' tcx > ) {
1025
+ self . super_basic_block_data ( block, data) ;
1053
1026
1054
1027
// We remove all Locals which are restricted in propagation to their containing blocks and
1055
1028
// which were modified in the current block.
0 commit comments