@@ -582,6 +582,34 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
582582 Some ( ( ) )
583583 }
584584
585+ fn propagate_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
586+ match * operand {
587+ Operand :: Copy ( l) | Operand :: Move ( l) => {
588+ if let Some ( value) = self . get_const ( l) {
589+ if self . should_const_prop ( value) {
590+ // FIXME(felix91gr): this code only handles `Scalar` cases.
591+ // For now, we're not handling `ScalarPair` cases because
592+ // doing so here would require a lot of code duplication.
593+ // We should hopefully generalize `Operand` handling into a fn,
594+ // and use it to do const-prop here and everywhere else
595+ // where it makes sense.
596+ if let interpret:: Operand :: Immediate ( interpret:: Immediate :: Scalar (
597+ ScalarMaybeUninit :: Scalar ( scalar) ,
598+ ) ) = * value
599+ {
600+ * operand = self . operand_from_scalar (
601+ scalar,
602+ value. layout . ty ,
603+ self . source_info . unwrap ( ) . span ,
604+ ) ;
605+ }
606+ }
607+ }
608+ }
609+ Operand :: Constant ( ref mut ct) => self . visit_constant ( ct, location) ,
610+ }
611+ }
612+
585613 fn const_prop (
586614 & mut self ,
587615 rvalue : & Rvalue < ' tcx > ,
@@ -905,6 +933,16 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
905933 }
906934 }
907935
936+ fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
937+ // Only const prop copies and moves on `mir_opt_level=3` as doing so
938+ // currently increases compile time.
939+ if self . tcx . sess . opts . debugging_opts . mir_opt_level < 3 {
940+ self . super_operand ( operand, location)
941+ } else {
942+ self . propagate_operand ( operand, location)
943+ }
944+ }
945+
908946 fn visit_constant ( & mut self , constant : & mut Constant < ' tcx > , location : Location ) {
909947 trace ! ( "visit_constant: {:?}" , constant) ;
910948 self . super_constant ( constant, location) ;
@@ -1072,18 +1110,13 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
10721110 }
10731111 }
10741112 }
1075- TerminatorKind :: SwitchInt { ref mut discr, switch_ty, .. } => {
1076- if let Some ( value) = self . eval_operand ( & discr, source_info) {
1077- if self . should_const_prop ( value) {
1078- if let ScalarMaybeUninit :: Scalar ( scalar) =
1079- self . ecx . read_scalar ( value) . unwrap ( )
1080- {
1081- * discr = self . operand_from_scalar ( scalar, switch_ty, source_info. span ) ;
1082- }
1083- }
1084- }
1113+ TerminatorKind :: SwitchInt { ref mut discr, .. } => {
1114+ // FIXME: This is currently redundant with `visit_operand`, but sadly
1115+ // always visiting operands currently causes a perf regression, so
1116+ // `visit_operand` currently only runs for propagates places for `mir_opt_level=3`.
1117+ self . propagate_operand ( discr, location)
10851118 }
1086- // None of these have Operands to const-propagate
1119+ // None of these have Operands to const-propagate.
10871120 TerminatorKind :: Goto { .. }
10881121 | TerminatorKind :: Resume
10891122 | TerminatorKind :: Abort
@@ -1096,61 +1129,16 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
10961129 | TerminatorKind :: FalseEdge { .. }
10971130 | TerminatorKind :: FalseUnwind { .. }
10981131 | TerminatorKind :: InlineAsm { .. } => { }
1099- // Every argument in our function calls can be const propagated.
1100- TerminatorKind :: Call { ref mut args, .. } => {
1101- let mir_opt_level = self . tcx . sess . opts . debugging_opts . mir_opt_level ;
1102- // Constant Propagation into function call arguments is gated
1103- // under mir-opt-level 2, because LLVM codegen gives performance
1104- // regressions with it.
1105- if mir_opt_level >= 2 {
1106- for opr in args {
1107- /*
1108- The following code would appear to be incomplete, because
1109- the function `Operand::place()` returns `None` if the
1110- `Operand` is of the variant `Operand::Constant`. In this
1111- context however, that variant will never appear. This is why:
1112-
1113- When constructing the MIR, all function call arguments are
1114- copied into `Locals` of `LocalKind::Temp`. At least, all arguments
1115- that are not unsized (Less than 0.1% are unsized. See #71170
1116- to learn more about those).
1117-
1118- This means that, conversely, all `Operands` found as function call
1119- arguments are of the variant `Operand::Copy`. This allows us to
1120- simplify our handling of `Operands` in this case.
1121- */
1122- if let Some ( l) = opr. place ( ) {
1123- if let Some ( value) = self . get_const ( l) {
1124- if self . should_const_prop ( value) {
1125- // FIXME(felix91gr): this code only handles `Scalar` cases.
1126- // For now, we're not handling `ScalarPair` cases because
1127- // doing so here would require a lot of code duplication.
1128- // We should hopefully generalize `Operand` handling into a fn,
1129- // and use it to do const-prop here and everywhere else
1130- // where it makes sense.
1131- if let interpret:: Operand :: Immediate (
1132- interpret:: Immediate :: Scalar ( ScalarMaybeUninit :: Scalar (
1133- scalar,
1134- ) ) ,
1135- ) = * value
1136- {
1137- * opr = self . operand_from_scalar (
1138- scalar,
1139- value. layout . ty ,
1140- source_info. span ,
1141- ) ;
1142- }
1143- }
1144- }
1145- }
1146- }
1147- }
1148- }
1132+ // Every argument in our function calls have already been propagated in `visit_operand`.
1133+ //
1134+ // NOTE: because LLVM codegen gives performance regressions with it, so this is gated
1135+ // on `mir_opt_level=3`.
1136+ TerminatorKind :: Call { .. } => { }
11491137 }
11501138
11511139 // We remove all Locals which are restricted in propagation to their containing blocks and
11521140 // which were modified in the current block.
1153- // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`
1141+ // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`.
11541142 let mut locals = std:: mem:: take ( & mut self . ecx . machine . written_only_inside_own_block_locals ) ;
11551143 for & local in locals. iter ( ) {
11561144 Self :: remove_const ( & mut self . ecx , local) ;
0 commit comments