Skip to content

Commit b5903b3

Browse files
committed
mir-opt: Simplify trivial constants in SimplifyConstCondition
1 parent 2f7620a commit b5903b3

File tree

7 files changed

+278
-2
lines changed

7 files changed

+278
-2
lines changed

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ declare_passes! {
189189
Final
190190
};
191191
mod simplify_branches : SimplifyConstCondition {
192+
AfterInstSimplify,
192193
AfterConstProp,
193194
Final
194195
};
@@ -708,6 +709,7 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'
708709
// optimizations. This invalidates CFG caches, so avoid putting between
709710
// `ReferencePropagation` and `GVN` which both use the dominator tree.
710711
&instsimplify::InstSimplify::AfterSimplifyCfg,
712+
&o1(simplify_branches::SimplifyConstCondition::AfterInstSimplify),
711713
&ref_prop::ReferencePropagation,
712714
&sroa::ScalarReplacementOfAggregates,
713715
&simplify::SimplifyLocals::BeforeConstProp,

compiler/rustc_mir_transform/src/simplify_branches.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use tracing::trace;
55
use crate::patch::MirPatch;
66

77
pub(super) enum SimplifyConstCondition {
8+
AfterInstSimplify,
89
AfterConstProp,
910
Final,
1011
}
@@ -13,6 +14,9 @@ pub(super) enum SimplifyConstCondition {
1314
impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
1415
fn name(&self) -> &'static str {
1516
match self {
17+
SimplifyConstCondition::AfterInstSimplify => {
18+
"SimplifyConstCondition-after-inst-simplify"
19+
}
1620
SimplifyConstCondition::AfterConstProp => "SimplifyConstCondition-after-const-prop",
1721
SimplifyConstCondition::Final => "SimplifyConstCondition-final",
1822
}
@@ -24,19 +28,39 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
2428
let mut patch = MirPatch::new(body);
2529

2630
'blocks: for (bb, block) in body.basic_blocks.iter_enumerated() {
31+
let mut pre_local_const: Option<(Local, &'_ ConstOperand<'_>)> = None;
32+
2733
for (statement_index, stmt) in block.statements.iter().enumerate() {
34+
let has_local_const = pre_local_const.take();
2835
// Simplify `assume` of a known value: either a NOP or unreachable.
2936
if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind
3037
&& let NonDivergingIntrinsic::Assume(discr) = intrinsic
31-
&& let Operand::Constant(c) = discr
32-
&& let Some(constant) = c.const_.try_eval_bool(tcx, typing_env)
3338
{
39+
let c = if let Operand::Constant(c) = discr {
40+
c
41+
} else if let Some((local, c)) = has_local_const
42+
&& let Some(assume_local) = discr.place().and_then(|p| p.as_local())
43+
&& local == assume_local
44+
{
45+
c
46+
} else {
47+
continue;
48+
};
49+
let Some(constant) = c.const_.try_eval_bool(tcx, typing_env) else {
50+
continue;
51+
};
3452
if constant {
3553
patch.nop_statement(Location { block: bb, statement_index });
3654
} else {
3755
patch.patch_terminator(bb, TerminatorKind::Unreachable);
3856
continue 'blocks;
3957
}
58+
} else if let StatementKind::Assign(box (ref lhs, ref rvalue)) = stmt.kind
59+
&& let Some(local) = lhs.as_local()
60+
&& let Rvalue::Use(Operand::Constant(c)) = rvalue
61+
&& c.const_.ty().is_bool()
62+
{
63+
pre_local_const = Some((local, c));
4064
}
4165
}
4266

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ test-mir-pass: SimplifyConstCondition-after-inst-simplify
2+
//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg -Zub_checks=false -Zinline-mir
3+
4+
#![crate_type = "lib"]
5+
6+
// EMIT_MIR trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff
7+
pub fn unwrap_unchecked(v: &Option<i32>) -> i32 {
8+
// CHECK-LABEL: fn unwrap_unchecked(
9+
// CHECK: bb0: {
10+
// CHECK: switchInt({{.*}}) -> [0: [[AssumeFalseBB:bb.*]], 1:
11+
// CHECK: [[AssumeFalseBB]]: {
12+
// CHECK-NEXT: unreachable;
13+
let v = unsafe { v.unwrap_unchecked() };
14+
v
15+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
- // MIR for `unwrap_unchecked` before SimplifyConstCondition-after-inst-simplify
2+
+ // MIR for `unwrap_unchecked` after SimplifyConstCondition-after-inst-simplify
3+
4+
fn unwrap_unchecked(_1: &Option<i32>) -> i32 {
5+
debug v => _1;
6+
let mut _0: i32;
7+
let _2: i32;
8+
let mut _3: std::option::Option<i32>;
9+
scope 1 {
10+
debug v => _2;
11+
}
12+
scope 2 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
13+
let mut _4: isize;
14+
scope 3 {
15+
}
16+
scope 4 (inlined #[track_caller] unreachable_unchecked) {
17+
let _5: ();
18+
scope 5 (inlined core::ub_checks::check_language_ub) {
19+
let mut _6: bool;
20+
scope 6 (inlined core::ub_checks::check_language_ub::runtime) {
21+
}
22+
}
23+
}
24+
}
25+
26+
bb0: {
27+
StorageLive(_2);
28+
StorageLive(_3);
29+
_3 = copy (*_1);
30+
StorageLive(_4);
31+
StorageLive(_5);
32+
_4 = discriminant(_3);
33+
switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb1];
34+
}
35+
36+
bb1: {
37+
unreachable;
38+
}
39+
40+
bb2: {
41+
- StorageLive(_6);
42+
- _6 = const false;
43+
- assume(copy _6);
44+
- _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable];
45+
+ unreachable;
46+
}
47+
48+
bb3: {
49+
_2 = move ((_3 as Some).0: i32);
50+
StorageDead(_5);
51+
StorageDead(_4);
52+
StorageDead(_3);
53+
_0 = copy _2;
54+
StorageDead(_2);
55+
return;
56+
}
57+
}
58+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// skip-filecheck
2+
//@ compile-flags: -O
3+
4+
#![crate_type = "lib"]
5+
6+
// EMIT_MIR two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff
7+
// EMIT_MIR two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir
8+
pub fn two_unwrap_unchecked(v: &Option<i32>) -> i32 {
9+
let v1 = unsafe { v.unwrap_unchecked() };
10+
let v2 = unsafe { v.unwrap_unchecked() };
11+
v1 + v2
12+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
- // MIR for `two_unwrap_unchecked` before GVN
2+
+ // MIR for `two_unwrap_unchecked` after GVN
3+
4+
fn two_unwrap_unchecked(_1: &Option<i32>) -> i32 {
5+
debug v => _1;
6+
let mut _0: i32;
7+
let _2: i32;
8+
let mut _3: std::option::Option<i32>;
9+
let mut _5: std::option::Option<i32>;
10+
let mut _6: i32;
11+
let mut _7: i32;
12+
scope 1 {
13+
debug v1 => _2;
14+
let _4: i32;
15+
scope 2 {
16+
debug v2 => _4;
17+
}
18+
scope 8 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
19+
let mut _9: isize;
20+
scope 9 {
21+
}
22+
scope 10 (inlined #[track_caller] unreachable_unchecked) {
23+
scope 11 (inlined core::ub_checks::check_language_ub) {
24+
scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
25+
}
26+
}
27+
}
28+
}
29+
}
30+
scope 3 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
31+
let mut _8: isize;
32+
scope 4 {
33+
}
34+
scope 5 (inlined #[track_caller] unreachable_unchecked) {
35+
scope 6 (inlined core::ub_checks::check_language_ub) {
36+
scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
37+
}
38+
}
39+
}
40+
}
41+
42+
bb0: {
43+
- StorageLive(_2);
44+
+ nop;
45+
StorageLive(_3);
46+
_3 = copy (*_1);
47+
StorageLive(_8);
48+
_8 = discriminant(_3);
49+
switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1];
50+
}
51+
52+
bb1: {
53+
unreachable;
54+
}
55+
56+
bb2: {
57+
unreachable;
58+
}
59+
60+
bb3: {
61+
_2 = move ((_3 as Some).0: i32);
62+
StorageDead(_8);
63+
StorageDead(_3);
64+
- StorageLive(_4);
65+
+ nop;
66+
StorageLive(_5);
67+
_5 = copy (*_1);
68+
StorageLive(_9);
69+
_9 = discriminant(_5);
70+
switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb1];
71+
}
72+
73+
bb4: {
74+
unreachable;
75+
}
76+
77+
bb5: {
78+
_4 = move ((_5 as Some).0: i32);
79+
StorageDead(_9);
80+
StorageDead(_5);
81+
StorageLive(_6);
82+
_6 = copy _2;
83+
StorageLive(_7);
84+
_7 = copy _4;
85+
- _0 = Add(move _6, move _7);
86+
+ _0 = Add(copy _2, copy _4);
87+
StorageDead(_7);
88+
StorageDead(_6);
89+
- StorageDead(_4);
90+
- StorageDead(_2);
91+
+ nop;
92+
+ nop;
93+
return;
94+
}
95+
}
96+
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// MIR for `two_unwrap_unchecked` after PreCodegen
2+
3+
fn two_unwrap_unchecked(_1: &Option<i32>) -> i32 {
4+
debug v => _1;
5+
let mut _0: i32;
6+
let mut _2: std::option::Option<i32>;
7+
let _4: i32;
8+
let mut _5: std::option::Option<i32>;
9+
scope 1 {
10+
debug v1 => _4;
11+
let _7: i32;
12+
scope 2 {
13+
debug v2 => _7;
14+
}
15+
scope 8 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
16+
let mut _6: isize;
17+
scope 9 {
18+
}
19+
scope 10 (inlined #[track_caller] unreachable_unchecked) {
20+
scope 11 (inlined core::ub_checks::check_language_ub) {
21+
scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
22+
}
23+
}
24+
}
25+
}
26+
}
27+
scope 3 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
28+
let mut _3: isize;
29+
scope 4 {
30+
}
31+
scope 5 (inlined #[track_caller] unreachable_unchecked) {
32+
scope 6 (inlined core::ub_checks::check_language_ub) {
33+
scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
34+
}
35+
}
36+
}
37+
}
38+
39+
bb0: {
40+
StorageLive(_2);
41+
_2 = copy (*_1);
42+
StorageLive(_3);
43+
_3 = discriminant(_2);
44+
switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb3];
45+
}
46+
47+
bb1: {
48+
_4 = move ((_2 as Some).0: i32);
49+
StorageDead(_3);
50+
StorageDead(_2);
51+
StorageLive(_5);
52+
_5 = copy (*_1);
53+
StorageLive(_6);
54+
_6 = discriminant(_5);
55+
switchInt(move _6) -> [0: bb3, 1: bb2, otherwise: bb3];
56+
}
57+
58+
bb2: {
59+
_7 = move ((_5 as Some).0: i32);
60+
StorageDead(_6);
61+
StorageDead(_5);
62+
_0 = Add(copy _4, copy _7);
63+
return;
64+
}
65+
66+
bb3: {
67+
unreachable;
68+
}
69+
}

0 commit comments

Comments
 (0)