New pass to optimize if
conditions on integrals to switches on the integer
Fixes #75144
This commit is contained in:
parent
abb98ca10d
commit
23dda1b9c6
13 changed files with 662 additions and 0 deletions
|
@ -503,6 +503,11 @@ impl<'tcx, Tag> Scalar<Tag> {
|
|||
self.to_unsigned_with_bit_width(64).map(|v| u64::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
/// Converts the scalar to produce an `u128`. Fails if the scalar is a pointer.
|
||||
pub fn to_u128(self) -> InterpResult<'static, u128> {
|
||||
self.to_unsigned_with_bit_width(128)
|
||||
}
|
||||
|
||||
pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'static, u64> {
|
||||
let b = self.to_bits(cx.data_layout().pointer_size)?;
|
||||
Ok(u64::try_from(b).unwrap())
|
||||
|
@ -535,6 +540,11 @@ impl<'tcx, Tag> Scalar<Tag> {
|
|||
self.to_signed_with_bit_width(64).map(|v| i64::try_from(v).unwrap())
|
||||
}
|
||||
|
||||
/// Converts the scalar to produce an `i128`. Fails if the scalar is a pointer.
|
||||
pub fn to_i128(self) -> InterpResult<'static, i128> {
|
||||
self.to_signed_with_bit_width(128)
|
||||
}
|
||||
|
||||
pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> {
|
||||
let sz = cx.data_layout().pointer_size;
|
||||
let b = self.to_bits(sz)?;
|
||||
|
|
|
@ -1430,6 +1430,15 @@ pub enum StatementKind<'tcx> {
|
|||
Nop,
|
||||
}
|
||||
|
||||
impl<'tcx> StatementKind<'tcx> {
|
||||
pub fn as_assign_mut(&mut self) -> Option<&mut Box<(Place<'tcx>, Rvalue<'tcx>)>> {
|
||||
match self {
|
||||
StatementKind::Assign(x) => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes what kind of retag is to be performed.
|
||||
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, HashStable)]
|
||||
pub enum RetagKind {
|
||||
|
@ -1843,6 +1852,10 @@ impl<'tcx> Operand<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn is_move(&self) -> bool {
|
||||
matches!(self, Operand::Move(..))
|
||||
}
|
||||
|
||||
/// Convenience helper to make a literal-like constant from a given scalar value.
|
||||
/// Since this is used to synthesize MIR, assumes `user_ty` is None.
|
||||
pub fn const_from_scalar(
|
||||
|
|
|
@ -39,6 +39,7 @@ pub mod required_consts;
|
|||
pub mod rustc_peek;
|
||||
pub mod simplify;
|
||||
pub mod simplify_branches;
|
||||
pub mod simplify_comparison_integral;
|
||||
pub mod simplify_try;
|
||||
pub mod uninhabited_enum_branching;
|
||||
pub mod unreachable_prop;
|
||||
|
@ -456,6 +457,7 @@ fn run_optimization_passes<'tcx>(
|
|||
&match_branches::MatchBranchSimplification,
|
||||
&const_prop::ConstProp,
|
||||
&simplify_branches::SimplifyBranches::new("after-const-prop"),
|
||||
&simplify_comparison_integral::SimplifyComparisonIntegral,
|
||||
&simplify_try::SimplifyArmIdentity,
|
||||
&simplify_try::SimplifyBranchSame,
|
||||
©_prop::CopyPropagation,
|
||||
|
|
226
src/librustc_mir/transform/simplify_comparison_integral.rs
Normal file
226
src/librustc_mir/transform/simplify_comparison_integral.rs
Normal file
|
@ -0,0 +1,226 @@
|
|||
use super::{MirPass, MirSource};
|
||||
use rustc_middle::{
|
||||
mir::{
|
||||
interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement,
|
||||
StatementKind, TerminatorKind,
|
||||
},
|
||||
ty::{Ty, TyCtxt},
|
||||
};
|
||||
|
||||
/// Pass to convert `if` conditions on integrals into switches on the integral.
|
||||
/// For an example, it turns something like
|
||||
///
|
||||
/// ```
|
||||
/// _3 = Eq(move _4, const 43i32);
|
||||
/// StorageDead(_4);
|
||||
/// switchInt(_3) -> [false: bb2, otherwise: bb3];
|
||||
/// ```
|
||||
///
|
||||
/// into:
|
||||
///
|
||||
/// ```
|
||||
/// switchInt(_4) -> [43i32: bb3, otherwise: bb2];
|
||||
/// ```
|
||||
pub struct SimplifyComparisonIntegral;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
|
||||
fn run_pass(&self, _: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
|
||||
trace!("Running SimplifyComparisonIntegral on {:?}", source);
|
||||
|
||||
let helper = OptimizationFinder { body };
|
||||
let opts = helper.find_optimizations();
|
||||
let mut storage_deads_to_insert = vec![];
|
||||
let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![];
|
||||
for opt in opts {
|
||||
trace!("SUCCESS: Applying {:?}", opt);
|
||||
// replace terminator with a switchInt that switches on the integer directly
|
||||
let bbs = &mut body.basic_blocks_mut();
|
||||
let bb = &mut bbs[opt.bb_idx];
|
||||
// We only use the bits for the untyped, not length checked `values` field. Thus we are
|
||||
// not using any of the convenience wrappers here and directly access the bits.
|
||||
let new_value = match opt.branch_value_scalar {
|
||||
Scalar::Raw { data, .. } => data,
|
||||
Scalar::Ptr(_) => continue,
|
||||
};
|
||||
const FALSE: u128 = 0;
|
||||
let mut new_targets = opt.targets.clone();
|
||||
let first_is_false_target = opt.values[0] == FALSE;
|
||||
match opt.op {
|
||||
BinOp::Eq => {
|
||||
// if the assignment was Eq we want the true case to be first
|
||||
if first_is_false_target {
|
||||
new_targets.swap(0, 1);
|
||||
}
|
||||
}
|
||||
BinOp::Ne => {
|
||||
// if the assignment was Ne we want the false case to be first
|
||||
if !first_is_false_target {
|
||||
new_targets.swap(0, 1);
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let terminator = bb.terminator_mut();
|
||||
|
||||
// add StorageDead for the place switched on at the top of each target
|
||||
for bb_idx in new_targets.iter() {
|
||||
storage_deads_to_insert.push((
|
||||
*bb_idx,
|
||||
Statement {
|
||||
source_info: terminator.source_info,
|
||||
kind: StatementKind::StorageDead(opt.to_switch_on.local),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
terminator.kind = TerminatorKind::SwitchInt {
|
||||
discr: Operand::Move(opt.to_switch_on),
|
||||
switch_ty: opt.branch_value_ty,
|
||||
values: vec![new_value].into(),
|
||||
targets: new_targets,
|
||||
};
|
||||
|
||||
// delete comparison statement if it the value being switched on was moved, which means it can not be user later on
|
||||
if opt.can_remove_bin_op_stmt {
|
||||
bb.statements[opt.bin_op_stmt_idx].make_nop();
|
||||
} else {
|
||||
// if the integer being compared to a const integral is being moved into the comparison,
|
||||
// e.g `_2 = Eq(move _3, const 'x');`
|
||||
// we want to avoid making a double move later on in the switchInt on _3.
|
||||
// So to avoid `switchInt(move _3) -> ['x': bb2, otherwise: bb1];`,
|
||||
// we convert the move in the comparison statement to a copy.
|
||||
|
||||
// unwrap is safe as we know this statement is an assign
|
||||
let box (_, rhs) = bb.statements[opt.bin_op_stmt_idx].kind.as_assign_mut().unwrap();
|
||||
|
||||
use Operand::*;
|
||||
match rhs {
|
||||
Rvalue::BinaryOp(_, ref mut left @ Move(_), Constant(_)) => {
|
||||
*left = Copy(opt.to_switch_on);
|
||||
}
|
||||
Rvalue::BinaryOp(_, Constant(_), ref mut right @ Move(_)) => {
|
||||
*right = Copy(opt.to_switch_on);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// remove StorageDead (if it exists) being used in the assign of the comparison
|
||||
for (stmt_idx, stmt) in bb.statements.iter().enumerate() {
|
||||
if !matches!(stmt.kind, StatementKind::StorageDead(local) if local == opt.to_switch_on.local)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
storage_deads_to_remove.push((stmt_idx, opt.bb_idx))
|
||||
}
|
||||
}
|
||||
|
||||
for (idx, bb_idx) in storage_deads_to_remove {
|
||||
body.basic_blocks_mut()[bb_idx].statements[idx].make_nop();
|
||||
}
|
||||
|
||||
for (idx, stmt) in storage_deads_to_insert {
|
||||
body.basic_blocks_mut()[idx].statements.insert(0, stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct OptimizationFinder<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> {
|
||||
fn find_optimizations(&self) -> Vec<OptimizationInfo<'tcx>> {
|
||||
self.body
|
||||
.basic_blocks()
|
||||
.iter_enumerated()
|
||||
.filter_map(|(bb_idx, bb)| {
|
||||
// find switch
|
||||
let (place_switched_on, values, targets, place_switched_on_moved) = match &bb
|
||||
.terminator()
|
||||
.kind
|
||||
{
|
||||
rustc_middle::mir::TerminatorKind::SwitchInt {
|
||||
discr, values, targets, ..
|
||||
} => Some((discr.place()?, values, targets, discr.is_move())),
|
||||
_ => None,
|
||||
}?;
|
||||
|
||||
// find the statement that assigns the place being switched on
|
||||
bb.statements.iter().enumerate().rev().find_map(|(stmt_idx, stmt)| {
|
||||
match &stmt.kind {
|
||||
rustc_middle::mir::StatementKind::Assign(box (lhs, rhs))
|
||||
if *lhs == place_switched_on =>
|
||||
{
|
||||
match rhs {
|
||||
Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), left, right) => {
|
||||
let (branch_value_scalar, branch_value_ty, to_switch_on) =
|
||||
find_branch_value_info(left, right)?;
|
||||
|
||||
Some(OptimizationInfo {
|
||||
bin_op_stmt_idx: stmt_idx,
|
||||
bb_idx,
|
||||
can_remove_bin_op_stmt: place_switched_on_moved,
|
||||
to_switch_on,
|
||||
branch_value_scalar,
|
||||
branch_value_ty,
|
||||
op: *op,
|
||||
values: values.clone().into_owned(),
|
||||
targets: targets.clone(),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn find_branch_value_info<'tcx>(
|
||||
left: &Operand<'tcx>,
|
||||
right: &Operand<'tcx>,
|
||||
) -> Option<(Scalar, Ty<'tcx>, Place<'tcx>)> {
|
||||
// check that either left or right is a constant.
|
||||
// if any are, we can use the other to switch on, and the constant as a value in a switch
|
||||
use Operand::*;
|
||||
match (left, right) {
|
||||
(Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on))
|
||||
| (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => {
|
||||
let branch_value_ty = branch_value.literal.ty;
|
||||
// we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats
|
||||
if !branch_value_ty.is_integral() && !branch_value_ty.is_char() {
|
||||
return None;
|
||||
};
|
||||
let branch_value_scalar = branch_value.literal.val.try_to_scalar()?;
|
||||
Some((branch_value_scalar, branch_value_ty, *to_switch_on))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OptimizationInfo<'tcx> {
|
||||
/// Basic block to apply the optimization
|
||||
bb_idx: BasicBlock,
|
||||
/// Statement index of Eq/Ne assignment that can be removed. None if the assignment can not be removed - i.e the statement is used later on
|
||||
bin_op_stmt_idx: usize,
|
||||
/// Can remove Eq/Ne assignment
|
||||
can_remove_bin_op_stmt: bool,
|
||||
/// Place that needs to be switched on. This place is of type integral
|
||||
to_switch_on: Place<'tcx>,
|
||||
/// Constant to use in switch target value
|
||||
branch_value_scalar: Scalar,
|
||||
/// Type of the constant value
|
||||
branch_value_ty: Ty<'tcx>,
|
||||
/// Either Eq or Ne
|
||||
op: BinOp,
|
||||
/// Current values used in the switch target. This needs to be replaced with the branch_value
|
||||
values: Vec<u128>,
|
||||
/// Current targets used in the switch
|
||||
targets: Vec<BasicBlock>,
|
||||
}
|
65
src/test/mir-opt/if-condition-int.rs
Normal file
65
src/test/mir-opt/if-condition-int.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
// compile-flags: -O
|
||||
// EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
|
||||
// EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
|
||||
// EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff
|
||||
// EMIT_MIR if_condition_int.opt_i8.SimplifyComparisonIntegral.diff
|
||||
// EMIT_MIR if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff
|
||||
// EMIT_MIR if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff
|
||||
// EMIT_MIR if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff
|
||||
// EMIT_MIR if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff
|
||||
|
||||
fn opt_u32(x: u32) -> u32 {
|
||||
if x == 42 { 0 } else { 1 }
|
||||
}
|
||||
|
||||
// don't opt: it is already optimal to switch on the bool
|
||||
fn dont_opt_bool(x: bool) -> u32 {
|
||||
if x { 0 } else { 1 }
|
||||
}
|
||||
|
||||
fn opt_char(x: char) -> u32 {
|
||||
if x == 'x' { 0 } else { 1 }
|
||||
}
|
||||
|
||||
fn opt_i8(x: i8) -> u32 {
|
||||
if x == 42 { 0 } else { 1 }
|
||||
}
|
||||
|
||||
fn opt_negative(x: i32) -> u32 {
|
||||
if x == -42 { 0 } else { 1 }
|
||||
}
|
||||
|
||||
fn opt_multiple_ifs(x: u32) -> u32 {
|
||||
if x == 42 {
|
||||
0
|
||||
} else if x != 21 {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
}
|
||||
}
|
||||
|
||||
// test that we optimize, but do not remove the b statement, as that is used later on
|
||||
fn dont_remove_comparison(a: i8) -> i32 {
|
||||
let b = a == 17;
|
||||
match b {
|
||||
false => 10 + b as i32,
|
||||
true => 100 + b as i32,
|
||||
}
|
||||
}
|
||||
|
||||
// test that we do not optimize on floats
|
||||
fn dont_opt_floats(a: f32) -> i32 {
|
||||
if a == -42.0 { 0 } else { 1 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
opt_u32(0);
|
||||
opt_char('0');
|
||||
opt_i8(22);
|
||||
dont_opt_bool(false);
|
||||
opt_negative(0);
|
||||
opt_multiple_ifs(0);
|
||||
dont_remove_comparison(11);
|
||||
dont_opt_floats(1.0);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
- // MIR for `dont_opt_bool` before SimplifyComparisonIntegral
|
||||
+ // MIR for `dont_opt_bool` after SimplifyComparisonIntegral
|
||||
|
||||
fn dont_opt_bool(_1: bool) -> u32 {
|
||||
debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:16:18: 16:19
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:16:30: 16:33
|
||||
let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:17:8: 17:9
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:17:8: 17:9
|
||||
_2 = _1; // scope 0 at $DIR/if-condition-int.rs:17:8: 17:9
|
||||
switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:17:23: 17:24
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:17:12: 17:13
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:18:1: 18:2
|
||||
return; // scope 0 at $DIR/if-condition-int.rs:18:2: 18:2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
- // MIR for `dont_opt_floats` before SimplifyComparisonIntegral
|
||||
+ // MIR for `dont_opt_floats` after SimplifyComparisonIntegral
|
||||
|
||||
fn dont_opt_floats(_1: f32) -> i32 {
|
||||
debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:52:20: 52:21
|
||||
let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:52:31: 52:34
|
||||
let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:53:8: 53:18
|
||||
let mut _3: f32; // in scope 0 at $DIR/if-condition-int.rs:53:8: 53:9
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:18
|
||||
StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:9
|
||||
_3 = _1; // scope 0 at $DIR/if-condition-int.rs:53:8: 53:9
|
||||
_2 = Eq(move _3, const -42f32); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:18
|
||||
// mir::Constant
|
||||
// + span: $DIR/if-condition-int.rs:53:13: 53:18
|
||||
// + literal: Const { ty: f32, val: Value(Scalar(0xc2280000)) }
|
||||
StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:53:17: 53:18
|
||||
switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = const 1_i32; // scope 0 at $DIR/if-condition-int.rs:53:32: 53:33
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_0 = const 0_i32; // scope 0 at $DIR/if-condition-int.rs:53:21: 53:22
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:54:1: 54:2
|
||||
return; // scope 0 at $DIR/if-condition-int.rs:54:2: 54:2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
- // MIR for `dont_remove_comparison` before SimplifyComparisonIntegral
|
||||
+ // MIR for `dont_remove_comparison` after SimplifyComparisonIntegral
|
||||
|
||||
fn dont_remove_comparison(_1: i8) -> i32 {
|
||||
debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:43:27: 43:28
|
||||
let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:43:37: 43:40
|
||||
let _2: bool; // in scope 0 at $DIR/if-condition-int.rs:44:9: 44:10
|
||||
let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:44:13: 44:14
|
||||
let mut _4: i32; // in scope 0 at $DIR/if-condition-int.rs:46:23: 46:31
|
||||
let mut _5: bool; // in scope 0 at $DIR/if-condition-int.rs:46:23: 46:24
|
||||
let mut _6: i32; // in scope 0 at $DIR/if-condition-int.rs:47:23: 47:31
|
||||
let mut _7: bool; // in scope 0 at $DIR/if-condition-int.rs:47:23: 47:24
|
||||
scope 1 {
|
||||
debug b => _2; // in scope 1 at $DIR/if-condition-int.rs:44:9: 44:10
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:44:9: 44:10
|
||||
StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:14
|
||||
_3 = _1; // scope 0 at $DIR/if-condition-int.rs:44:13: 44:14
|
||||
- _2 = Eq(move _3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:20
|
||||
- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:44:19: 44:20
|
||||
- switchInt(_2) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14
|
||||
+ _2 = Eq(_3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:20
|
||||
+ nop; // scope 0 at $DIR/if-condition-int.rs:44:19: 44:20
|
||||
+ switchInt(move _3) -> [17_i8: bb1, otherwise: bb2]; // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14
|
||||
}
|
||||
|
||||
bb1: {
|
||||
+ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14
|
||||
StorageLive(_6); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:31
|
||||
StorageLive(_7); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:24
|
||||
_7 = _2; // scope 1 at $DIR/if-condition-int.rs:47:23: 47:24
|
||||
_6 = move _7 as i32 (Misc); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:31
|
||||
StorageDead(_7); // scope 1 at $DIR/if-condition-int.rs:47:30: 47:31
|
||||
_0 = Add(const 100_i32, move _6); // scope 1 at $DIR/if-condition-int.rs:47:17: 47:31
|
||||
StorageDead(_6); // scope 1 at $DIR/if-condition-int.rs:47:30: 47:31
|
||||
goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:45:5: 48:6
|
||||
}
|
||||
|
||||
bb2: {
|
||||
+ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14
|
||||
StorageLive(_4); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:31
|
||||
StorageLive(_5); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:24
|
||||
_5 = _2; // scope 1 at $DIR/if-condition-int.rs:46:23: 46:24
|
||||
_4 = move _5 as i32 (Misc); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:31
|
||||
StorageDead(_5); // scope 1 at $DIR/if-condition-int.rs:46:30: 46:31
|
||||
_0 = Add(const 10_i32, move _4); // scope 1 at $DIR/if-condition-int.rs:46:18: 46:31
|
||||
StorageDead(_4); // scope 1 at $DIR/if-condition-int.rs:46:30: 46:31
|
||||
goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:45:5: 48:6
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:49:1: 49:2
|
||||
return; // scope 0 at $DIR/if-condition-int.rs:49:2: 49:2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
- // MIR for `opt_char` before SimplifyComparisonIntegral
|
||||
+ // MIR for `opt_char` after SimplifyComparisonIntegral
|
||||
|
||||
fn opt_char(_1: char) -> u32 {
|
||||
debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:20:13: 20:14
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:20:25: 20:28
|
||||
let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:21:8: 21:16
|
||||
let mut _3: char; // in scope 0 at $DIR/if-condition-int.rs:21:8: 21:9
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16
|
||||
StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:9
|
||||
_3 = _1; // scope 0 at $DIR/if-condition-int.rs:21:8: 21:9
|
||||
- _2 = Eq(move _3, const 'x'); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16
|
||||
- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:15: 21:16
|
||||
- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33
|
||||
+ _2 = Eq(_3, const 'x'); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16
|
||||
+ nop; // scope 0 at $DIR/if-condition-int.rs:21:15: 21:16
|
||||
+ switchInt(move _3) -> ['x': bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33
|
||||
}
|
||||
|
||||
bb1: {
|
||||
+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33
|
||||
_0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:21:30: 21:31
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33
|
||||
}
|
||||
|
||||
bb2: {
|
||||
+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33
|
||||
_0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:21:19: 21:20
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:22:1: 22:2
|
||||
return; // scope 0 at $DIR/if-condition-int.rs:22:2: 22:2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
- // MIR for `opt_i8` before SimplifyComparisonIntegral
|
||||
+ // MIR for `opt_i8` after SimplifyComparisonIntegral
|
||||
|
||||
fn opt_i8(_1: i8) -> u32 {
|
||||
debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:24:11: 24:12
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:24:21: 24:24
|
||||
let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:25:8: 25:15
|
||||
let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:25:8: 25:9
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15
|
||||
StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:9
|
||||
_3 = _1; // scope 0 at $DIR/if-condition-int.rs:25:8: 25:9
|
||||
- _2 = Eq(move _3, const 42_i8); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15
|
||||
- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:14: 25:15
|
||||
- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32
|
||||
+ _2 = Eq(_3, const 42_i8); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15
|
||||
+ nop; // scope 0 at $DIR/if-condition-int.rs:25:14: 25:15
|
||||
+ switchInt(move _3) -> [42_i8: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32
|
||||
}
|
||||
|
||||
bb1: {
|
||||
+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32
|
||||
_0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:25:29: 25:30
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32
|
||||
}
|
||||
|
||||
bb2: {
|
||||
+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32
|
||||
_0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:25:18: 25:19
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:26:1: 26:2
|
||||
return; // scope 0 at $DIR/if-condition-int.rs:26:2: 26:2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
- // MIR for `opt_multiple_ifs` before SimplifyComparisonIntegral
|
||||
+ // MIR for `opt_multiple_ifs` after SimplifyComparisonIntegral
|
||||
|
||||
fn opt_multiple_ifs(_1: u32) -> u32 {
|
||||
debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:32:21: 32:22
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:32:32: 32:35
|
||||
let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:33:8: 33:15
|
||||
let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:33:8: 33:9
|
||||
let mut _4: bool; // in scope 0 at $DIR/if-condition-int.rs:35:15: 35:22
|
||||
let mut _5: u32; // in scope 0 at $DIR/if-condition-int.rs:35:15: 35:16
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15
|
||||
StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:9
|
||||
_3 = _1; // scope 0 at $DIR/if-condition-int.rs:33:8: 33:9
|
||||
- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15
|
||||
- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:14: 33:15
|
||||
- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6
|
||||
+ _2 = Eq(_3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15
|
||||
+ nop; // scope 0 at $DIR/if-condition-int.rs:33:14: 33:15
|
||||
+ switchInt(move _3) -> [42_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6
|
||||
}
|
||||
|
||||
bb1: {
|
||||
+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6
|
||||
StorageLive(_4); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22
|
||||
StorageLive(_5); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:16
|
||||
_5 = _1; // scope 0 at $DIR/if-condition-int.rs:35:15: 35:16
|
||||
- _4 = Ne(move _5, const 21_u32); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22
|
||||
- StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:21: 35:22
|
||||
- switchInt(_4) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6
|
||||
+ _4 = Ne(_5, const 21_u32); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22
|
||||
+ nop; // scope 0 at $DIR/if-condition-int.rs:35:21: 35:22
|
||||
+ switchInt(move _5) -> [21_u32: bb3, otherwise: bb4]; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6
|
||||
}
|
||||
|
||||
bb2: {
|
||||
+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6
|
||||
_0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:34:9: 34:10
|
||||
goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6
|
||||
}
|
||||
|
||||
bb3: {
|
||||
+ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6
|
||||
_0 = const 2_u32; // scope 0 at $DIR/if-condition-int.rs:38:9: 38:10
|
||||
goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6
|
||||
}
|
||||
|
||||
bb4: {
|
||||
+ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6
|
||||
_0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:36:9: 36:10
|
||||
goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_4); // scope 0 at $DIR/if-condition-int.rs:39:5: 39:6
|
||||
goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:40:1: 40:2
|
||||
return; // scope 0 at $DIR/if-condition-int.rs:40:2: 40:2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
- // MIR for `opt_negative` before SimplifyComparisonIntegral
|
||||
+ // MIR for `opt_negative` after SimplifyComparisonIntegral
|
||||
|
||||
fn opt_negative(_1: i32) -> u32 {
|
||||
debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:28:17: 28:18
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:28:28: 28:31
|
||||
let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:29:8: 29:16
|
||||
let mut _3: i32; // in scope 0 at $DIR/if-condition-int.rs:29:8: 29:9
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16
|
||||
StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:9
|
||||
_3 = _1; // scope 0 at $DIR/if-condition-int.rs:29:8: 29:9
|
||||
- _2 = Eq(move _3, const -42_i32); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16
|
||||
- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:15: 29:16
|
||||
- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33
|
||||
+ _2 = Eq(_3, const -42_i32); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16
|
||||
+ nop; // scope 0 at $DIR/if-condition-int.rs:29:15: 29:16
|
||||
+ switchInt(move _3) -> [-42_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33
|
||||
}
|
||||
|
||||
bb1: {
|
||||
+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33
|
||||
_0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:29:30: 29:31
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33
|
||||
}
|
||||
|
||||
bb2: {
|
||||
+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33
|
||||
_0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:29:19: 29:20
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:30:1: 30:2
|
||||
return; // scope 0 at $DIR/if-condition-int.rs:30:2: 30:2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
- // MIR for `opt_u32` before SimplifyComparisonIntegral
|
||||
+ // MIR for `opt_u32` after SimplifyComparisonIntegral
|
||||
|
||||
fn opt_u32(_1: u32) -> u32 {
|
||||
debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:11:12: 11:13
|
||||
let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:11:23: 11:26
|
||||
let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:12:8: 12:15
|
||||
let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:12:8: 12:9
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15
|
||||
StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:9
|
||||
_3 = _1; // scope 0 at $DIR/if-condition-int.rs:12:8: 12:9
|
||||
- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15
|
||||
- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:14: 12:15
|
||||
- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32
|
||||
+ _2 = Eq(_3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15
|
||||
+ nop; // scope 0 at $DIR/if-condition-int.rs:12:14: 12:15
|
||||
+ switchInt(move _3) -> [42_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32
|
||||
}
|
||||
|
||||
bb1: {
|
||||
+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32
|
||||
_0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:12:29: 12:30
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32
|
||||
}
|
||||
|
||||
bb2: {
|
||||
+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32
|
||||
_0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:12:18: 12:19
|
||||
goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:13:1: 13:2
|
||||
return; // scope 0 at $DIR/if-condition-int.rs:13:2: 13:2
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue