3
3
4
4
use rustc:: hir:: def:: DefKind ;
5
5
use rustc:: mir:: {
6
- Constant , Location , Place , PlaceBase , Mir , Operand , Rvalue , Local ,
6
+ AggregateKind , Constant , Location , Place , PlaceBase , Mir , Operand , Rvalue , Local ,
7
7
NullOp , UnOp , StatementKind , Statement , LocalKind , Static , StaticKind ,
8
8
TerminatorKind , Terminator , ClearCrossCrate , SourceInfo , BinOp , ProjectionElem ,
9
9
SourceScope , SourceScopeLocalData , LocalDecl , Promoted ,
10
10
} ;
11
- use rustc:: mir:: visit:: { Visitor , PlaceContext , MutatingUseContext , NonMutatingUseContext } ;
11
+ use rustc:: mir:: visit:: {
12
+ Visitor , PlaceContext , MutatingUseContext , MutVisitor , NonMutatingUseContext ,
13
+ } ;
12
14
use rustc:: mir:: interpret:: { InterpError , Scalar , GlobalId , EvalResult } ;
13
15
use rustc:: ty:: { self , Instance , ParamEnv , Ty , TyCtxt } ;
14
16
use syntax:: source_map:: DUMMY_SP ;
@@ -19,7 +21,7 @@ use rustc::ty::layout::{
19
21
HasTyCtxt , TargetDataLayout , HasDataLayout ,
20
22
} ;
21
23
22
- use crate :: interpret:: { InterpretCx , ScalarMaybeUndef , Immediate , OpTy , ImmTy , MemoryKind } ;
24
+ use crate :: interpret:: { self , InterpretCx , ScalarMaybeUndef , Immediate , OpTy , ImmTy , MemoryKind } ;
23
25
use crate :: const_eval:: {
24
26
CompileTimeInterpreter , error_to_const_error, eval_promoted, mk_eval_cx,
25
27
} ;
@@ -497,6 +499,50 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
497
499
} ,
498
500
}
499
501
}
502
+
503
+ fn operand_from_scalar ( & self , scalar : Scalar , ty : Ty < ' tcx > ) -> Operand < ' tcx > {
504
+ Operand :: Constant ( Box :: new (
505
+ Constant {
506
+ span : DUMMY_SP ,
507
+ ty,
508
+ user_ty : None ,
509
+ literal : self . tcx . mk_const ( ty:: Const :: from_scalar (
510
+ scalar,
511
+ ty,
512
+ ) )
513
+ }
514
+ ) )
515
+ }
516
+
517
+ fn replace_with_const ( & self , rval : & mut Rvalue < ' tcx > , value : Const < ' tcx > ) {
518
+ if let interpret:: Operand :: Immediate ( im) = * value {
519
+ match im {
520
+ interpret:: Immediate :: Scalar ( ScalarMaybeUndef :: Scalar ( scalar) ) => {
521
+ * rval = Rvalue :: Use ( self . operand_from_scalar ( scalar, value. layout . ty ) ) ;
522
+ } ,
523
+ Immediate :: ScalarPair (
524
+ ScalarMaybeUndef :: Scalar ( one) ,
525
+ ScalarMaybeUndef :: Scalar ( two)
526
+ ) => {
527
+ let ty = & value. layout . ty . sty ;
528
+ if let ty:: Tuple ( substs) = ty {
529
+ * rval = Rvalue :: Aggregate (
530
+ Box :: new ( AggregateKind :: Tuple ) ,
531
+ vec ! [
532
+ self . operand_from_scalar( one, substs[ 0 ] . expect_ty( ) ) ,
533
+ self . operand_from_scalar( two, substs[ 1 ] . expect_ty( ) ) ,
534
+ ] ,
535
+ ) ;
536
+ }
537
+ } ,
538
+ _ => { }
539
+ }
540
+ }
541
+ }
542
+
543
+ fn should_const_prop ( & self ) -> bool {
544
+ true
545
+ }
500
546
}
501
547
502
548
fn type_size_of < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
@@ -560,10 +606,10 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
560
606
}
561
607
}
562
608
563
- impl < ' b , ' a , ' tcx > Visitor < ' tcx > for ConstPropagator < ' b , ' a , ' tcx > {
609
+ impl < ' b , ' a , ' tcx > MutVisitor < ' tcx > for ConstPropagator < ' b , ' a , ' tcx > {
564
610
fn visit_constant (
565
611
& mut self ,
566
- constant : & Constant < ' tcx > ,
612
+ constant : & mut Constant < ' tcx > ,
567
613
location : Location ,
568
614
) {
569
615
trace ! ( "visit_constant: {:?}" , constant) ;
@@ -573,11 +619,11 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
573
619
574
620
fn visit_statement (
575
621
& mut self ,
576
- statement : & Statement < ' tcx > ,
622
+ statement : & mut Statement < ' tcx > ,
577
623
location : Location ,
578
624
) {
579
625
trace ! ( "visit_statement: {:?}" , statement) ;
580
- if let StatementKind :: Assign ( ref place, ref rval) = statement. kind {
626
+ if let StatementKind :: Assign ( ref place, ref mut rval) = statement. kind {
581
627
let place_ty: Ty < ' tcx > = place
582
628
. ty ( & self . local_decls , self . tcx )
583
629
. ty ;
@@ -589,6 +635,10 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
589
635
trace ! ( "storing {:?} to {:?}" , value, local) ;
590
636
assert ! ( self . places[ local] . is_none( ) ) ;
591
637
self . places [ local] = Some ( value) ;
638
+
639
+ if self . should_const_prop ( ) {
640
+ self . replace_with_const ( rval, value) ;
641
+ }
592
642
}
593
643
}
594
644
}
@@ -599,79 +649,111 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
599
649
600
650
fn visit_terminator (
601
651
& mut self ,
602
- terminator : & Terminator < ' tcx > ,
652
+ terminator : & mut Terminator < ' tcx > ,
603
653
location : Location ,
604
654
) {
605
655
self . super_terminator ( terminator, location) ;
606
- let source_info = terminator. source_info ; ;
607
- if let TerminatorKind :: Assert { expected, msg, cond, .. } = & terminator. kind {
608
- if let Some ( value) = self . eval_operand ( & cond, source_info) {
609
- trace ! ( "assertion on {:?} should be {:?}" , value, expected) ;
610
- let expected = ScalarMaybeUndef :: from ( Scalar :: from_bool ( * expected) ) ;
611
- if expected != self . ecx . read_scalar ( value) . unwrap ( ) {
612
- // poison all places this operand references so that further code
613
- // doesn't use the invalid value
614
- match cond {
615
- Operand :: Move ( ref place) | Operand :: Copy ( ref place) => {
616
- let mut place = place;
617
- while let Place :: Projection ( ref proj) = * place {
618
- place = & proj. base ;
619
- }
620
- if let Place :: Base ( PlaceBase :: Local ( local) ) = * place {
621
- self . places [ local] = None ;
656
+ let source_info = terminator. source_info ;
657
+ match & mut terminator. kind {
658
+ TerminatorKind :: Assert { expected, msg, ref mut cond, .. } => {
659
+ if let Some ( value) = self . eval_operand ( & cond, source_info) {
660
+ trace ! ( "assertion on {:?} should be {:?}" , value, expected) ;
661
+ let expected = ScalarMaybeUndef :: from ( Scalar :: from_bool ( * expected) ) ;
662
+ let value_const = self . ecx . read_scalar ( value) . unwrap ( ) ;
663
+ if expected != value_const {
664
+ // poison all places this operand references so that further code
665
+ // doesn't use the invalid value
666
+ match cond {
667
+ Operand :: Move ( ref place) | Operand :: Copy ( ref place) => {
668
+ let mut place = place;
669
+ while let Place :: Projection ( ref proj) = * place {
670
+ place = & proj. base ;
671
+ }
672
+ if let Place :: Base ( PlaceBase :: Local ( local) ) = * place {
673
+ self . places [ local] = None ;
674
+ }
675
+ } ,
676
+ Operand :: Constant ( _) => { }
677
+ }
678
+ let span = terminator. source_info . span ;
679
+ let hir_id = self
680
+ . tcx
681
+ . hir ( )
682
+ . as_local_hir_id ( self . source . def_id ( ) )
683
+ . expect ( "some part of a failing const eval must be local" ) ;
684
+ use rustc:: mir:: interpret:: InterpError :: * ;
685
+ let msg = match msg {
686
+ Overflow ( _) |
687
+ OverflowNeg |
688
+ DivisionByZero |
689
+ RemainderByZero => msg. description ( ) . to_owned ( ) ,
690
+ BoundsCheck { ref len, ref index } => {
691
+ let len = self
692
+ . eval_operand ( len, source_info)
693
+ . expect ( "len must be const" ) ;
694
+ let len = match self . ecx . read_scalar ( len) {
695
+ Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
696
+ bits, ..
697
+ } ) ) => bits,
698
+ other => bug ! ( "const len not primitive: {:?}" , other) ,
699
+ } ;
700
+ let index = self
701
+ . eval_operand ( index, source_info)
702
+ . expect ( "index must be const" ) ;
703
+ let index = match self . ecx . read_scalar ( index) {
704
+ Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
705
+ bits, ..
706
+ } ) ) => bits,
707
+ other => bug ! ( "const index not primitive: {:?}" , other) ,
708
+ } ;
709
+ format ! (
710
+ "index out of bounds: \
711
+ the len is {} but the index is {}",
712
+ len,
713
+ index,
714
+ )
715
+ } ,
716
+ // Need proper const propagator for these
717
+ _ => return ,
718
+ } ;
719
+ self . tcx . lint_hir (
720
+ :: rustc:: lint:: builtin:: CONST_ERR ,
721
+ hir_id,
722
+ span,
723
+ & msg,
724
+ ) ;
725
+ } else {
726
+ if self . should_const_prop ( ) {
727
+ if let ScalarMaybeUndef :: Scalar ( scalar) = value_const {
728
+ * cond = self . operand_from_scalar ( scalar, self . tcx . types . bool ) ;
622
729
}
623
- } ,
624
- Operand :: Constant ( _) => { }
730
+ }
625
731
}
626
- let span = terminator. source_info . span ;
627
- let hir_id = self
628
- . tcx
629
- . hir ( )
630
- . as_local_hir_id ( self . source . def_id ( ) )
631
- . expect ( "some part of a failing const eval must be local" ) ;
632
- use rustc:: mir:: interpret:: InterpError :: * ;
633
- let msg = match msg {
634
- Overflow ( _) |
635
- OverflowNeg |
636
- DivisionByZero |
637
- RemainderByZero => msg. description ( ) . to_owned ( ) ,
638
- BoundsCheck { ref len, ref index } => {
639
- let len = self
640
- . eval_operand ( len, source_info)
641
- . expect ( "len must be const" ) ;
642
- let len = match self . ecx . read_scalar ( len) {
643
- Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
644
- bits, ..
645
- } ) ) => bits,
646
- other => bug ! ( "const len not primitive: {:?}" , other) ,
647
- } ;
648
- let index = self
649
- . eval_operand ( index, source_info)
650
- . expect ( "index must be const" ) ;
651
- let index = match self . ecx . read_scalar ( index) {
652
- Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
653
- bits, ..
654
- } ) ) => bits,
655
- other => bug ! ( "const index not primitive: {:?}" , other) ,
656
- } ;
657
- format ! (
658
- "index out of bounds: \
659
- the len is {} but the index is {}",
660
- len,
661
- index,
662
- )
663
- } ,
664
- // Need proper const propagator for these
665
- _ => return ,
666
- } ;
667
- self . tcx . lint_hir (
668
- :: rustc:: lint:: builtin:: CONST_ERR ,
669
- hir_id,
670
- span,
671
- & msg,
672
- ) ;
673
732
}
674
- }
733
+ } ,
734
+ TerminatorKind :: SwitchInt { ref mut discr, switch_ty, .. } => {
735
+ if self . should_const_prop ( ) {
736
+ if let Some ( value) = self . eval_operand ( & discr, source_info) {
737
+ if let Ok ( ScalarMaybeUndef :: Scalar ( scalar) ) = self . ecx . read_scalar ( value) {
738
+ * discr = self . operand_from_scalar ( scalar, switch_ty) ;
739
+ }
740
+ }
741
+ }
742
+ } ,
743
+ //none of these have Operands to const-propagate
744
+ TerminatorKind :: Goto { .. } |
745
+ TerminatorKind :: Resume |
746
+ TerminatorKind :: Abort |
747
+ TerminatorKind :: Return |
748
+ TerminatorKind :: Unreachable |
749
+ TerminatorKind :: Drop { .. } |
750
+ TerminatorKind :: DropAndReplace { .. } |
751
+ TerminatorKind :: Yield { .. } |
752
+ TerminatorKind :: GeneratorDrop |
753
+ TerminatorKind :: FalseEdges { .. } |
754
+ TerminatorKind :: FalseUnwind { .. } => { }
755
+ //FIXME(wesleywiser) Call does have Operands that could be const-propagated
756
+ TerminatorKind :: Call { .. } => { }
675
757
}
676
758
}
677
759
}
0 commit comments