diff --git a/src/librustc_middle/mir/interpret/value.rs b/src/librustc_middle/mir/interpret/value.rs index 4c47f25105d..7d6ff3eb5c1 100644 --- a/src/librustc_middle/mir/interpret/value.rs +++ b/src/librustc_middle/mir/interpret/value.rs @@ -503,6 +503,11 @@ impl<'tcx, Tag> Scalar { 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 { 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)?; diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 7ac7d9b23f1..785a7f0c51a 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -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( diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 0db5bd662ca..c3a34756122 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -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, diff --git a/src/librustc_mir/transform/simplify_comparison_integral.rs b/src/librustc_mir/transform/simplify_comparison_integral.rs new file mode 100644 index 00000000000..a450a75d091 --- /dev/null +++ b/src/librustc_mir/transform/simplify_comparison_integral.rs @@ -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> { + 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, + /// Current targets used in the switch + targets: Vec, +} diff --git a/src/test/mir-opt/if-condition-int.rs b/src/test/mir-opt/if-condition-int.rs new file mode 100644 index 00000000000..b34389a0ab5 --- /dev/null +++ b/src/test/mir-opt/if-condition-int.rs @@ -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); +} diff --git a/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff new file mode 100644 index 00000000000..993ff660caa --- /dev/null +++ b/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff @@ -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 + } + } + diff --git a/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff new file mode 100644 index 00000000000..8ae9168c950 --- /dev/null +++ b/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff @@ -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 + } + } + diff --git a/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff new file mode 100644 index 00000000000..b590be5370f --- /dev/null +++ b/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff @@ -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 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff new file mode 100644 index 00000000000..ae0960028a8 --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff @@ -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 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff new file mode 100644 index 00000000000..8d59e51ac2b --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff @@ -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 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff new file mode 100644 index 00000000000..c4975661efe --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff @@ -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 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff new file mode 100644 index 00000000000..d7f544e44c0 --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff @@ -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 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff new file mode 100644 index 00000000000..51e00e680c2 --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff @@ -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 + } + } +