Skip to content

Commit 0d804b9

Browse files
committed
Move constants into the SwitchInt to be easier to see
1 parent a1e3451 commit 0d804b9

File tree

3 files changed

+60
-3
lines changed

3 files changed

+60
-3
lines changed

compiler/rustc_mir_transform/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ mod simplify_branches;
108108
mod simplify_comparison_integral;
109109
mod single_use_consts;
110110
mod sroa;
111+
mod switch_const;
111112
mod unreachable_enum_branching;
112113
mod unreachable_prop;
113114
mod validate;
@@ -598,6 +599,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
598599
&simplify::SimplifyLocals::AfterGVN,
599600
&dataflow_const_prop::DataflowConstProp,
600601
&single_use_consts::SingleUseConsts,
602+
// GVN & ConstProp often don't fixup unevaluatable constants
603+
&switch_const::SwitchConst,
601604
&o1(simplify_branches::SimplifyConstCondition::AfterConstProp),
602605
&jump_threading::JumpThreading,
603606
&early_otherwise_branch::EarlyOtherwiseBranch,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//! A pass that makes `SwitchInt`-on-`const` more obvious to later code.
2+
3+
use rustc_middle::bug;
4+
use rustc_middle::mir::*;
5+
use rustc_middle::ty::TyCtxt;
6+
7+
/// A `MirPass` for simplifying `if T::CONST`.
8+
///
9+
/// Today, MIR building for things like `if T::IS_ZST` introduce a constant
10+
/// for the copy of the bool, so it ends up in MIR as
11+
/// `_1 = CONST; switchInt (move _1)` or `_2 = CONST; switchInt (_2)`.
12+
///
13+
/// This pass is very specifically targeted at *exactly* those patterns.
14+
/// It can absolutely be replaced with a more general pass should we get one that
15+
/// we can run in low optimization levels, but at the time of writing even in
16+
/// optimized builds this wasn't simplified.
17+
#[derive(Default)]
18+
pub struct SwitchConst;
19+
20+
impl<'tcx> MirPass<'tcx> for SwitchConst {
21+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
22+
for block in body.basic_blocks.as_mut_preserves_cfg() {
23+
let switch_local = if let TerminatorKind::SwitchInt { discr, .. } =
24+
&block.terminator().kind
25+
&& let Some(place) = discr.place()
26+
&& let Some(local) = place.as_local()
27+
{
28+
local
29+
} else {
30+
continue;
31+
};
32+
33+
let new_operand = if let Some(statement) = block.statements.last()
34+
&& let StatementKind::Assign(place_and_rvalue) = &statement.kind
35+
&& let Some(local) = place_and_rvalue.0.as_local()
36+
&& local == switch_local
37+
&& let Rvalue::Use(operand) = &place_and_rvalue.1
38+
&& let Operand::Constant(_) = operand
39+
{
40+
operand.clone()
41+
} else {
42+
continue;
43+
};
44+
45+
if !tcx.consider_optimizing(|| format!("SwitchConst: switchInt(move {switch_local:?}"))
46+
{
47+
break;
48+
}
49+
50+
let TerminatorKind::SwitchInt { discr, .. } = &mut block.terminator_mut().kind else {
51+
bug!("Somehow wasn't a switchInt any more?")
52+
};
53+
*discr = new_operand;
54+
}
55+
}
56+
}

tests/mir-opt/single_use_consts.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ fn match_const<T: MyTrait>() -> &'static str {
2929
fn if_const_debug<T: MyTrait>() -> i32 {
3030
// CHECK-LABEL: fn if_const_debug(
3131
// CHECK: my_bool => const <T as MyTrait>::ASSOC_BOOL;
32-
// FIXME: `if` forces a temporary (unlike `match`), so the const isn't direct
33-
// CHECK: _3 = const <T as MyTrait>::ASSOC_BOOL;
34-
// CHECK: switchInt(move _3)
32+
// CHECK: switchInt(const <T as MyTrait>::ASSOC_BOOL)
3533
let my_bool = T::ASSOC_BOOL;
3634
do_whatever();
3735
if my_bool { 7 } else { 42 }

0 commit comments

Comments
 (0)