Skip to content

Commit 4b65872

Browse files
committed
Auto merge of #76067 - simonvandel:peephole-ne, r=wesleywiser
MIR peephole optimize {Ne, Eq}(_1, false) into _1 Add peephole optimization that simplifies Ne(_1, false) and Ne(false, _1) into _1. Similarly handles Eq(_1, true) and Eq(true, _1). This was observed emitted from the MatchBranchSimplification pass.
2 parents aa81d32 + 9b0fc62 commit 4b65872

File tree

7 files changed

+187
-2
lines changed

7 files changed

+187
-2
lines changed

compiler/rustc_middle/src/mir/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1954,6 +1954,15 @@ impl<'tcx> Operand<'tcx> {
19541954
Operand::Constant(_) => None,
19551955
}
19561956
}
1957+
1958+
/// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a
1959+
/// place.
1960+
pub fn constant(&self) -> Option<&Constant<'tcx>> {
1961+
match self {
1962+
Operand::Constant(x) => Some(&**x),
1963+
Operand::Copy(_) | Operand::Move(_) => None,
1964+
}
1965+
}
19571966
}
19581967

19591968
///////////////////////////////////////////////////////////////////////////

compiler/rustc_mir/src/transform/instcombine.rs

+51-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_hir::Mutability;
66
use rustc_index::vec::Idx;
77
use rustc_middle::mir::visit::{MutVisitor, Visitor};
88
use rustc_middle::mir::{
9-
Body, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue,
9+
BinOp, Body, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue,
1010
};
1111
use rustc_middle::ty::{self, TyCtxt};
1212
use std::mem;
@@ -66,6 +66,11 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
6666
*rvalue = Rvalue::Use(Operand::Constant(box constant));
6767
}
6868

69+
if let Some(operand) = self.optimizations.unneeded_equality_comparison.remove(&location) {
70+
debug!("replacing {:?} with {:?}", rvalue, operand);
71+
*rvalue = Rvalue::Use(operand);
72+
}
73+
6974
self.super_rvalue(rvalue, location)
7075
}
7176
}
@@ -81,6 +86,48 @@ impl OptimizationFinder<'b, 'tcx> {
8186
fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'tcx>) -> OptimizationFinder<'b, 'tcx> {
8287
OptimizationFinder { body, tcx, optimizations: OptimizationList::default() }
8388
}
89+
90+
fn find_unneeded_equality_comparison(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
91+
// find Ne(_place, false) or Ne(false, _place)
92+
// or Eq(_place, true) or Eq(true, _place)
93+
if let Rvalue::BinaryOp(op, l, r) = rvalue {
94+
let const_to_find = if *op == BinOp::Ne {
95+
false
96+
} else if *op == BinOp::Eq {
97+
true
98+
} else {
99+
return;
100+
};
101+
// (const, _place)
102+
if let Some(o) = self.find_operand_in_equality_comparison_pattern(l, r, const_to_find) {
103+
self.optimizations.unneeded_equality_comparison.insert(location, o.clone());
104+
}
105+
// (_place, const)
106+
else if let Some(o) =
107+
self.find_operand_in_equality_comparison_pattern(r, l, const_to_find)
108+
{
109+
self.optimizations.unneeded_equality_comparison.insert(location, o.clone());
110+
}
111+
}
112+
}
113+
114+
fn find_operand_in_equality_comparison_pattern(
115+
&self,
116+
l: &Operand<'tcx>,
117+
r: &'a Operand<'tcx>,
118+
const_to_find: bool,
119+
) -> Option<&'a Operand<'tcx>> {
120+
let const_ = l.constant()?;
121+
if const_.literal.ty == self.tcx.types.bool
122+
&& const_.literal.val.try_to_bool() == Some(const_to_find)
123+
{
124+
if r.place().is_some() {
125+
return Some(r);
126+
}
127+
}
128+
129+
return None;
130+
}
84131
}
85132

86133
impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
@@ -106,6 +153,8 @@ impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
106153
}
107154
}
108155

156+
self.find_unneeded_equality_comparison(rvalue, location);
157+
109158
self.super_rvalue(rvalue, location)
110159
}
111160
}
@@ -114,4 +163,5 @@ impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
114163
struct OptimizationList<'tcx> {
115164
and_stars: FxHashSet<Location>,
116165
arrays_lengths: FxHashMap<Location, Constant<'tcx>>,
166+
unneeded_equality_comparison: FxHashMap<Location, Operand<'tcx>>,
117167
}

compiler/rustc_mir/src/transform/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -453,8 +453,9 @@ fn run_optimization_passes<'tcx>(
453453

454454
// The main optimizations that we do on MIR.
455455
let optimizations: &[&dyn MirPass<'tcx>] = &[
456-
&instcombine::InstCombine,
457456
&match_branches::MatchBranchSimplification,
457+
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
458+
&instcombine::InstCombine,
458459
&const_prop::ConstProp,
459460
&simplify_branches::SimplifyBranches::new("after-const-prop"),
460461
&simplify_comparison_integral::SimplifyComparisonIntegral,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
- // MIR for `opt` before InstCombine
2+
+ // MIR for `opt` after InstCombine
3+
4+
fn opt(_1: bool) -> i32 {
5+
debug x => _1; // in scope 0 at $DIR/equal_true.rs:3:8: 3:9
6+
let mut _0: i32; // return place in scope 0 at $DIR/equal_true.rs:3:20: 3:23
7+
let mut _2: bool; // in scope 0 at $DIR/equal_true.rs:4:8: 4:17
8+
let mut _3: bool; // in scope 0 at $DIR/equal_true.rs:4:8: 4:9
9+
10+
bb0: {
11+
StorageLive(_2); // scope 0 at $DIR/equal_true.rs:4:8: 4:17
12+
StorageLive(_3); // scope 0 at $DIR/equal_true.rs:4:8: 4:9
13+
_3 = _1; // scope 0 at $DIR/equal_true.rs:4:8: 4:9
14+
- _2 = Eq(move _3, const true); // scope 0 at $DIR/equal_true.rs:4:8: 4:17
15+
+ _2 = move _3; // scope 0 at $DIR/equal_true.rs:4:8: 4:17
16+
StorageDead(_3); // scope 0 at $DIR/equal_true.rs:4:16: 4:17
17+
switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/equal_true.rs:4:5: 4:34
18+
}
19+
20+
bb1: {
21+
_0 = const 1_i32; // scope 0 at $DIR/equal_true.rs:4:31: 4:32
22+
goto -> bb3; // scope 0 at $DIR/equal_true.rs:4:5: 4:34
23+
}
24+
25+
bb2: {
26+
_0 = const 0_i32; // scope 0 at $DIR/equal_true.rs:4:20: 4:21
27+
goto -> bb3; // scope 0 at $DIR/equal_true.rs:4:5: 4:34
28+
}
29+
30+
bb3: {
31+
StorageDead(_2); // scope 0 at $DIR/equal_true.rs:5:1: 5:2
32+
return; // scope 0 at $DIR/equal_true.rs:5:2: 5:2
33+
}
34+
}
35+

src/test/mir-opt/equal_true.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// EMIT_MIR equal_true.opt.InstCombine.diff
2+
3+
fn opt(x: bool) -> i32 {
4+
if x == true { 0 } else { 1 }
5+
}
6+
7+
fn main() {
8+
opt(true);
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
- // MIR for `opt` before InstCombine
2+
+ // MIR for `opt` after InstCombine
3+
4+
fn opt(_1: Option<()>) -> bool {
5+
debug x => _1; // in scope 0 at $DIR/not_equal_false.rs:3:8: 3:9
6+
let mut _0: bool; // return place in scope 0 at $DIR/not_equal_false.rs:3:26: 3:30
7+
let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
8+
let mut _3: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
9+
let mut _4: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
10+
let mut _5: isize; // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
11+
12+
bb0: {
13+
StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
14+
_3 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
15+
_2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
16+
goto -> bb7; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21
17+
}
18+
19+
bb1: {
20+
_0 = const true; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
21+
goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
22+
}
23+
24+
bb2: {
25+
_0 = const false; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
26+
goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
27+
}
28+
29+
bb3: {
30+
StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
31+
_5 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
32+
_4 = Eq(_5, const 1_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
33+
goto -> bb10; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45
34+
}
35+
36+
bb4: {
37+
StorageDead(_4); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46
38+
StorageDead(_2); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46
39+
return; // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2
40+
}
41+
42+
bb5: {
43+
_2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
44+
goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
45+
}
46+
47+
bb6: {
48+
_2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
49+
goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
50+
}
51+
52+
bb7: {
53+
switchInt(move _2) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
54+
}
55+
56+
bb8: {
57+
_4 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
58+
goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
59+
}
60+
61+
bb9: {
62+
_4 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
63+
goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
64+
}
65+
66+
bb10: {
67+
- _0 = Ne(_4, const false); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
68+
+ _0 = _4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
69+
goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46
70+
}
71+
}
72+

src/test/mir-opt/not_equal_false.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// EMIT_MIR not_equal_false.opt.InstCombine.diff
2+
3+
fn opt(x: Option<()>) -> bool {
4+
matches!(x, None) || matches!(x, Some(_))
5+
}
6+
7+
fn main() {
8+
opt(None);
9+
}

0 commit comments

Comments
 (0)