Auto merge of #86107 - Smittyvb:peephole-optim-eq-bool, r=wesleywiser

Peephole optimize `x == false` and `x != true`

This adds peephole optimizations to make `x == false`, `false == x`, `x != true`, and `true != x` get optimized to `!x` in the `instcombine` MIR pass. That pass currently handles `x == true` -> `x` already.
This commit is contained in:
bors 2021-06-09 06:06:06 +00:00
commit d45d205d59
6 changed files with 180 additions and 7 deletions

View File

@ -4,7 +4,7 @@ use crate::transform::MirPass;
use rustc_hir::Mutability;
use rustc_middle::mir::{
BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
StatementKind,
StatementKind, UnOp,
};
use rustc_middle::ty::{self, TyCtxt};
@ -47,28 +47,35 @@ impl<'tcx, 'a> InstCombineContext<'tcx, 'a> {
Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) => {
let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) {
// Transform "Eq(a, true)" ==> "a"
(BinOp::Eq, _, Some(true)) => Some(a.clone()),
(BinOp::Eq, _, Some(true)) => Some(Rvalue::Use(a.clone())),
// Transform "Ne(a, false)" ==> "a"
(BinOp::Ne, _, Some(false)) => Some(a.clone()),
(BinOp::Ne, _, Some(false)) => Some(Rvalue::Use(a.clone())),
// Transform "Eq(true, b)" ==> "b"
(BinOp::Eq, Some(true), _) => Some(b.clone()),
(BinOp::Eq, Some(true), _) => Some(Rvalue::Use(b.clone())),
// Transform "Ne(false, b)" ==> "b"
(BinOp::Ne, Some(false), _) => Some(b.clone()),
(BinOp::Ne, Some(false), _) => Some(Rvalue::Use(b.clone())),
// FIXME: Consider combining remaining comparisons into logical operations:
// Transform "Eq(false, b)" ==> "Not(b)"
(BinOp::Eq, Some(false), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())),
// Transform "Ne(true, b)" ==> "Not(b)"
(BinOp::Ne, Some(true), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())),
// Transform "Eq(a, false)" ==> "Not(a)"
(BinOp::Eq, _, Some(false)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())),
// Transform "Ne(a, true)" ==> "Not(a)"
(BinOp::Ne, _, Some(true)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())),
_ => None,
};
if let Some(new) = new {
if self.should_combine(source_info, rvalue) {
*rvalue = Rvalue::Use(new);
*rvalue = new;
}
}
}

View File

@ -0,0 +1,35 @@
- // MIR for `opt1` before InstCombine
+ // MIR for `opt1` after InstCombine
fn opt1(_1: bool) -> u32 {
debug x => _1; // in scope 0 at $DIR/bool_compare.rs:2:9: 2:10
let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:2:21: 2:24
let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:3:8: 3:17
let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:3:8: 3:9
bb0: {
StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17
StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:3:8: 3:9
_3 = _1; // scope 0 at $DIR/bool_compare.rs:3:8: 3:9
- _2 = Ne(move _3, const true); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17
+ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17
StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:3:16: 3:17
switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34
}
bb1: {
_0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:3:20: 3:21
goto -> bb3; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34
}
bb2: {
_0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:3:31: 3:32
goto -> bb3; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34
}
bb3: {
StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:3:33: 3:34
return; // scope 0 at $DIR/bool_compare.rs:4:2: 4:2
}
}

View File

@ -0,0 +1,35 @@
- // MIR for `opt2` before InstCombine
+ // MIR for `opt2` after InstCombine
fn opt2(_1: bool) -> u32 {
debug x => _1; // in scope 0 at $DIR/bool_compare.rs:7:9: 7:10
let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:7:21: 7:24
let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:8:8: 8:17
let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:8:16: 8:17
bb0: {
StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17
StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:8:16: 8:17
_3 = _1; // scope 0 at $DIR/bool_compare.rs:8:16: 8:17
- _2 = Ne(const true, move _3); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17
+ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17
StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:8:16: 8:17
switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34
}
bb1: {
_0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:8:20: 8:21
goto -> bb3; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34
}
bb2: {
_0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:8:31: 8:32
goto -> bb3; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34
}
bb3: {
StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:8:33: 8:34
return; // scope 0 at $DIR/bool_compare.rs:9:2: 9:2
}
}

View File

@ -0,0 +1,35 @@
- // MIR for `opt3` before InstCombine
+ // MIR for `opt3` after InstCombine
fn opt3(_1: bool) -> u32 {
debug x => _1; // in scope 0 at $DIR/bool_compare.rs:12:9: 12:10
let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:12:21: 12:24
let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:13:8: 13:18
let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:13:8: 13:9
bb0: {
StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18
StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:13:8: 13:9
_3 = _1; // scope 0 at $DIR/bool_compare.rs:13:8: 13:9
- _2 = Eq(move _3, const false); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18
+ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18
StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:13:17: 13:18
switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35
}
bb1: {
_0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:13:21: 13:22
goto -> bb3; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35
}
bb2: {
_0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:13:32: 13:33
goto -> bb3; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35
}
bb3: {
StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:13:34: 13:35
return; // scope 0 at $DIR/bool_compare.rs:14:2: 14:2
}
}

View File

@ -0,0 +1,35 @@
- // MIR for `opt4` before InstCombine
+ // MIR for `opt4` after InstCombine
fn opt4(_1: bool) -> u32 {
debug x => _1; // in scope 0 at $DIR/bool_compare.rs:17:9: 17:10
let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:17:21: 17:24
let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:18:8: 18:18
let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:18:17: 18:18
bb0: {
StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18
StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:18:17: 18:18
_3 = _1; // scope 0 at $DIR/bool_compare.rs:18:17: 18:18
- _2 = Eq(const false, move _3); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18
+ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18
StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:18:17: 18:18
switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35
}
bb1: {
_0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:18:21: 18:22
goto -> bb3; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35
}
bb2: {
_0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:18:32: 18:33
goto -> bb3; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35
}
bb3: {
StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:18:34: 18:35
return; // scope 0 at $DIR/bool_compare.rs:19:2: 19:2
}
}

View File

@ -0,0 +1,26 @@
// EMIT_MIR bool_compare.opt1.InstCombine.diff
fn opt1(x: bool) -> u32 {
if x != true { 0 } else { 1 }
}
// EMIT_MIR bool_compare.opt2.InstCombine.diff
fn opt2(x: bool) -> u32 {
if true != x { 0 } else { 1 }
}
// EMIT_MIR bool_compare.opt3.InstCombine.diff
fn opt3(x: bool) -> u32 {
if x == false { 0 } else { 1 }
}
// EMIT_MIR bool_compare.opt4.InstCombine.diff
fn opt4(x: bool) -> u32 {
if false == x { 0 } else { 1 }
}
fn main() {
opt1(false);
opt2(false);
opt3(false);
opt4(false);
}