@@ -262,7 +262,7 @@ struct ConstPropagator<'mir, 'tcx> {
262
262
ecx : InterpCx < ' mir , ' tcx , ConstPropMachine > ,
263
263
tcx : TyCtxt < ' tcx > ,
264
264
source : MirSource < ' tcx > ,
265
- can_const_prop : IndexVec < Local , bool > ,
265
+ can_const_prop : IndexVec < Local , ConstPropMode > ,
266
266
param_env : ParamEnv < ' tcx > ,
267
267
// FIXME(eddyb) avoid cloning these two fields more than once,
268
268
// by accessing them through `ecx` instead.
@@ -636,19 +636,45 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
636
636
ScalarMaybeUndef :: Scalar ( one) ,
637
637
ScalarMaybeUndef :: Scalar ( two)
638
638
) => {
639
+ // Found a value represented as a pair. For now only do cont-prop if type of
640
+ // Rvalue is also a pair with two scalars. The more general case is more
641
+ // complicated to implement so we'll do it later.
639
642
let ty = & value. layout . ty . kind ;
643
+ // Only do it for tuples
640
644
if let ty:: Tuple ( substs) = ty {
641
- * rval = Rvalue :: Aggregate (
642
- Box :: new ( AggregateKind :: Tuple ) ,
643
- vec ! [
644
- self . operand_from_scalar(
645
- one, substs[ 0 ] . expect_ty( ) , source_info. span
646
- ) ,
647
- self . operand_from_scalar(
648
- two, substs[ 1 ] . expect_ty( ) , source_info. span
649
- ) ,
650
- ] ,
651
- ) ;
645
+ // Only do it if tuple is also a pair with two scalars
646
+ if substs. len ( ) == 2 {
647
+ let opt_ty1_ty2 = self . use_ecx ( source_info, |this| {
648
+ let ty1 = substs[ 0 ] . expect_ty ( ) ;
649
+ let ty2 = substs[ 1 ] . expect_ty ( ) ;
650
+ let ty_is_scalar = |ty| {
651
+ this. ecx
652
+ . layout_of ( ty)
653
+ . ok ( )
654
+ . map ( |ty| ty. details . abi . is_scalar ( ) )
655
+ == Some ( true )
656
+ } ;
657
+ if ty_is_scalar ( ty1) && ty_is_scalar ( ty2) {
658
+ Ok ( Some ( ( ty1, ty2) ) )
659
+ } else {
660
+ Ok ( None )
661
+ }
662
+ } ) ;
663
+
664
+ if let Some ( Some ( ( ty1, ty2) ) ) = opt_ty1_ty2 {
665
+ * rval = Rvalue :: Aggregate (
666
+ Box :: new ( AggregateKind :: Tuple ) ,
667
+ vec ! [
668
+ self . operand_from_scalar(
669
+ one, ty1, source_info. span
670
+ ) ,
671
+ self . operand_from_scalar(
672
+ two, ty2, source_info. span
673
+ ) ,
674
+ ] ,
675
+ ) ;
676
+ }
677
+ }
652
678
}
653
679
} ,
654
680
_ => { }
@@ -682,17 +708,28 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
682
708
}
683
709
}
684
710
711
+ /// The mode that `ConstProp` is allowed to run in for a given `Local`.
712
+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
713
+ enum ConstPropMode {
714
+ /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
715
+ FullConstProp ,
716
+ /// The `Local` can be propagated into but reads cannot be propagated.
717
+ OnlyPropagateInto ,
718
+ /// No propagation is allowed at all.
719
+ NoPropagation ,
720
+ }
721
+
685
722
struct CanConstProp {
686
- can_const_prop : IndexVec < Local , bool > ,
723
+ can_const_prop : IndexVec < Local , ConstPropMode > ,
687
724
// false at the beginning, once set, there are not allowed to be any more assignments
688
725
found_assignment : IndexVec < Local , bool > ,
689
726
}
690
727
691
728
impl CanConstProp {
692
729
/// returns true if `local` can be propagated
693
- fn check ( body : ReadOnlyBodyCache < ' _ , ' _ > ) -> IndexVec < Local , bool > {
730
+ fn check ( body : ReadOnlyBodyCache < ' _ , ' _ > ) -> IndexVec < Local , ConstPropMode > {
694
731
let mut cpv = CanConstProp {
695
- can_const_prop : IndexVec :: from_elem ( true , & body. local_decls ) ,
732
+ can_const_prop : IndexVec :: from_elem ( ConstPropMode :: FullConstProp , & body. local_decls ) ,
696
733
found_assignment : IndexVec :: from_elem ( false , & body. local_decls ) ,
697
734
} ;
698
735
for ( local, val) in cpv. can_const_prop . iter_enumerated_mut ( ) {
@@ -702,10 +739,10 @@ impl CanConstProp {
702
739
// FIXME(oli-obk): lint variables until they are used in a condition
703
740
// FIXME(oli-obk): lint if return value is constant
704
741
let local_kind = body. local_kind ( local) ;
705
- * val = local_kind == LocalKind :: Temp || local_kind == LocalKind :: ReturnPointer ;
706
742
707
- if !* val {
708
- trace ! ( "local {:?} can't be propagated because it's not a temporary" , local) ;
743
+ if local_kind == LocalKind :: Arg || local_kind == LocalKind :: Var {
744
+ * val = ConstPropMode :: OnlyPropagateInto ;
745
+ trace ! ( "local {:?} can't be const propagated because it's not a temporary" , local) ;
709
746
}
710
747
}
711
748
cpv. visit_body ( body) ;
@@ -727,7 +764,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
727
764
// only occur in independent execution paths
728
765
MutatingUse ( MutatingUseContext :: Store ) => if self . found_assignment [ local] {
729
766
trace ! ( "local {:?} can't be propagated because of multiple assignments" , local) ;
730
- self . can_const_prop [ local] = false ;
767
+ self . can_const_prop [ local] = ConstPropMode :: NoPropagation ;
731
768
} else {
732
769
self . found_assignment [ local] = true
733
770
} ,
@@ -740,7 +777,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
740
777
NonUse ( _) => { } ,
741
778
_ => {
742
779
trace ! ( "local {:?} can't be propagaged because it's used: {:?}" , local, context) ;
743
- self . can_const_prop [ local] = false ;
780
+ self . can_const_prop [ local] = ConstPropMode :: NoPropagation ;
744
781
} ,
745
782
}
746
783
}
@@ -774,10 +811,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
774
811
if let Ok ( place_layout) = self . tcx . layout_of ( self . param_env . and ( place_ty) ) {
775
812
if let Some ( local) = place. as_local ( ) {
776
813
let source = statement. source_info ;
814
+ let can_const_prop = self . can_const_prop [ local] ;
777
815
if let Some ( ( ) ) = self . const_prop ( rval, place_layout, source, place) {
778
- if self . can_const_prop [ local] {
779
- trace ! ( "propagated into {:?}" , local) ;
780
-
816
+ if can_const_prop == ConstPropMode :: FullConstProp ||
817
+ can_const_prop == ConstPropMode :: OnlyPropagateInto {
781
818
if let Some ( value) = self . get_const ( local) {
782
819
if self . should_const_prop ( value) {
783
820
trace ! ( "replacing {:?} with {:?}" , rval, value) ;
@@ -786,21 +823,26 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
786
823
value,
787
824
statement. source_info ,
788
825
) ;
826
+
827
+ if can_const_prop == ConstPropMode :: FullConstProp {
828
+ trace ! ( "propagated into {:?}" , local) ;
829
+ }
789
830
}
790
831
}
791
- } else {
792
- trace ! ( "can't propagate into {:?}" , local) ;
793
- if local != RETURN_PLACE {
794
- self . remove_const ( local) ;
795
- }
832
+ }
833
+ }
834
+ if self . can_const_prop [ local] != ConstPropMode :: FullConstProp {
835
+ trace ! ( "can't propagate into {:?}" , local) ;
836
+ if local != RETURN_PLACE {
837
+ self . remove_const ( local) ;
796
838
}
797
839
}
798
840
}
799
841
}
800
842
} else {
801
843
match statement. kind {
802
844
StatementKind :: StorageLive ( local) |
803
- StatementKind :: StorageDead ( local) if self . can_const_prop [ local ] => {
845
+ StatementKind :: StorageDead ( local) => {
804
846
let frame = self . ecx . frame_mut ( ) ;
805
847
frame. locals [ local] . value =
806
848
if let StatementKind :: StorageLive ( _) = statement. kind {
0 commit comments