@@ -262,7 +262,7 @@ struct ConstPropagator<'mir, 'tcx> {
262262 ecx : InterpCx < ' mir , ' tcx , ConstPropMachine > ,
263263 tcx : TyCtxt < ' tcx > ,
264264 source : MirSource < ' tcx > ,
265- can_const_prop : IndexVec < Local , bool > ,
265+ can_const_prop : IndexVec < Local , ConstPropMode > ,
266266 param_env : ParamEnv < ' tcx > ,
267267 // FIXME(eddyb) avoid cloning these two fields more than once,
268268 // by accessing them through `ecx` instead.
@@ -636,19 +636,45 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
636636 ScalarMaybeUndef :: Scalar ( one) ,
637637 ScalarMaybeUndef :: Scalar ( two)
638638 ) => {
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.
639642 let ty = & value. layout . ty . kind ;
643+ // Only do it for tuples
640644 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+ }
652678 }
653679 } ,
654680 _ => { }
@@ -682,17 +708,28 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
682708 }
683709}
684710
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+
685722struct CanConstProp {
686- can_const_prop : IndexVec < Local , bool > ,
723+ can_const_prop : IndexVec < Local , ConstPropMode > ,
687724 // false at the beginning, once set, there are not allowed to be any more assignments
688725 found_assignment : IndexVec < Local , bool > ,
689726}
690727
691728impl CanConstProp {
692729 /// returns true if `local` can be propagated
693- fn check ( body : ReadOnlyBodyCache < ' _ , ' _ > ) -> IndexVec < Local , bool > {
730+ fn check ( body : ReadOnlyBodyCache < ' _ , ' _ > ) -> IndexVec < Local , ConstPropMode > {
694731 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 ) ,
696733 found_assignment : IndexVec :: from_elem ( false , & body. local_decls ) ,
697734 } ;
698735 for ( local, val) in cpv. can_const_prop . iter_enumerated_mut ( ) {
@@ -702,10 +739,10 @@ impl CanConstProp {
702739 // FIXME(oli-obk): lint variables until they are used in a condition
703740 // FIXME(oli-obk): lint if return value is constant
704741 let local_kind = body. local_kind ( local) ;
705- * val = local_kind == LocalKind :: Temp || local_kind == LocalKind :: ReturnPointer ;
706742
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) ;
709746 }
710747 }
711748 cpv. visit_body ( body) ;
@@ -727,7 +764,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
727764 // only occur in independent execution paths
728765 MutatingUse ( MutatingUseContext :: Store ) => if self . found_assignment [ local] {
729766 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 ;
731768 } else {
732769 self . found_assignment [ local] = true
733770 } ,
@@ -740,7 +777,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
740777 NonUse ( _) => { } ,
741778 _ => {
742779 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 ;
744781 } ,
745782 }
746783 }
@@ -774,10 +811,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
774811 if let Ok ( place_layout) = self . tcx . layout_of ( self . param_env . and ( place_ty) ) {
775812 if let Some ( local) = place. as_local ( ) {
776813 let source = statement. source_info ;
814+ let can_const_prop = self . can_const_prop [ local] ;
777815 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 {
781818 if let Some ( value) = self . get_const ( local) {
782819 if self . should_const_prop ( value) {
783820 trace ! ( "replacing {:?} with {:?}" , rval, value) ;
@@ -786,21 +823,26 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
786823 value,
787824 statement. source_info ,
788825 ) ;
826+
827+ if can_const_prop == ConstPropMode :: FullConstProp {
828+ trace ! ( "propagated into {:?}" , local) ;
829+ }
789830 }
790831 }
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) ;
796838 }
797839 }
798840 }
799841 }
800842 } else {
801843 match statement. kind {
802844 StatementKind :: StorageLive ( local) |
803- StatementKind :: StorageDead ( local) if self . can_const_prop [ local ] => {
845+ StatementKind :: StorageDead ( local) => {
804846 let frame = self . ecx . frame_mut ( ) ;
805847 frame. locals [ local] . value =
806848 if let StatementKind :: StorageLive ( _) = statement. kind {
0 commit comments