From 7008cce788bc917895f36557849ffb51c92766d2 Mon Sep 17 00:00:00 2001 From: Catherine Flores Date: Sun, 30 Jul 2023 14:30:17 +0000 Subject: [PATCH 1/5] New MIR opt pass `simplify_pow_of_two` --- .../rustc_middle/src/mir/interpret/value.rs | 4 + compiler/rustc_middle/src/ty/sty.rs | 4 + compiler/rustc_mir_transform/src/lib.rs | 2 + .../src/simplify_pow_of_two.rs | 256 ++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 2 + .../simplify_pow_of_two_no_overflow_checks.rs | 50 ++++ ...ow_checks.slow_256_i.SimplifyPowOfTwo.diff | 34 +++ ...ow_checks.slow_256_u.SimplifyPowOfTwo.diff | 34 +++ ...flow_checks.slow_2_i.SimplifyPowOfTwo.diff | 34 +++ ...flow_checks.slow_2_u.SimplifyPowOfTwo.diff | 34 +++ ...flow_checks.slow_4_i.SimplifyPowOfTwo.diff | 34 +++ ...flow_checks.slow_4_u.SimplifyPowOfTwo.diff | 34 +++ .../simplify_pow_of_two_overflow_checks.rs | 50 ++++ ...ow_checks.slow_256_i.SimplifyPowOfTwo.diff | 34 +++ ...ow_checks.slow_256_u.SimplifyPowOfTwo.diff | 34 +++ ...flow_checks.slow_2_i.SimplifyPowOfTwo.diff | 34 +++ ...flow_checks.slow_2_u.SimplifyPowOfTwo.diff | 34 +++ ...flow_checks.slow_4_i.SimplifyPowOfTwo.diff | 34 +++ ...flow_checks.slow_4_u.SimplifyPowOfTwo.diff | 34 +++ tests/ui/mir/simplify-pow-of-two.rs | 44 +++ 20 files changed, 820 insertions(+) create mode 100644 compiler/rustc_mir_transform/src/simplify_pow_of_two.rs create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.rs create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff create mode 100644 tests/ui/mir/simplify-pow-of-two.rs diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 20861d5ffa405..47831d44de4e3 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -93,6 +93,10 @@ impl<'tcx> ConstValue<'tcx> { ConstValue::Scalar(Scalar::from_bool(b)) } + pub fn from_u32(i: u32) -> Self { + ConstValue::Scalar(Scalar::from_u32(i)) + } + pub fn from_u64(i: u64) -> Self { ConstValue::Scalar(Scalar::from_u64(i)) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 3e023ccdead67..0d327c332ac00 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1872,6 +1872,10 @@ impl<'tcx> Region<'tcx> { /// Constructors for `Ty` impl<'tcx> Ty<'tcx> { + pub fn new_bool(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, TyKind::Bool) + } + // Avoid this in favour of more specific `new_*` methods, where possible. #[allow(rustc::usage_of_ty_tykind)] #[inline] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 734321e97d892..a4c769be31966 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -95,6 +95,7 @@ mod required_consts; mod reveal_all; mod separate_const_switch; mod shim; +mod simplify_pow_of_two; mod ssa; // This pass is public to allow external drivers to perform MIR cleanup mod check_alignment; @@ -546,6 +547,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first &unreachable_prop::UnreachablePropagation, &uninhabited_enum_branching::UninhabitedEnumBranching, + &simplify_pow_of_two::SimplifyPowOfTwo, &o1(simplify::SimplifyCfg::AfterUninhabitedEnumBranching), &inline::Inline, &remove_storage_markers::RemoveStorageMarkers, diff --git a/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs b/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs new file mode 100644 index 0000000000000..58a3cfdda8e69 --- /dev/null +++ b/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs @@ -0,0 +1,256 @@ +//! A pass that checks for and simplifies calls to `pow` where the receiver is a power of +//! two. This can be done with `<<` instead. + +use crate::MirPass; +use rustc_const_eval::interpret::{ConstValue, Scalar}; +use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_middle::mir::patch::MirPatch; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, Ty, TyCtxt, UintTy}; +use rustc_span::sym; +use rustc_target::abi::FieldIdx; + +pub struct SimplifyPowOfTwo; + +impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut patch = MirPatch::new(body); + + for (i, bb) in body.basic_blocks.iter_enumerated() { + let term = bb.terminator(); + let source_info = term.source_info; + let span = source_info.span; + + if let TerminatorKind::Call { + func, + args, + destination, + target: Some(target), + unwind, + call_source: CallSource::Normal, + .. + } = &term.kind + && let Some(def_id) = func.const_fn_def().map(|def| def.0) + && let def_path = tcx.def_path(def_id) + && tcx.crate_name(def_path.krate) == sym::core + // FIXME(Centri3): I feel like we should do this differently... + && let [ + DisambiguatedDefPathData { data: DefPathData::TypeNs(sym::num), disambiguator: 0 }, + DisambiguatedDefPathData { data: DefPathData::Impl, .. }, + DisambiguatedDefPathData { data: DefPathData::ValueNs(sym::pow), .. }, + ] = &*def_path.data + && let [recv, exp] = args.as_slice() + && let Some(recv_const) = recv.constant() + && let ConstantKind::Val( + ConstValue::Scalar(Scalar::Int(recv_int)), + recv_ty, + ) = recv_const.literal + && let Ok(recv_val) = match recv_ty.kind() { + ty::Int(_) => { + let result = recv_int.try_to_int(recv_int.size()).unwrap_or(-1).max(0); + if result > 0 { + Ok(result as u128) + } else { + continue; + } + }, + ty::Uint(_) => recv_int.try_to_uint(recv_int.size()), + _ => continue, + } + && let power_used = f32::log2(recv_val as f32) + // Precision loss means it's not a power of two + && power_used == (power_used as u32) as f32 + // `0` would be `1.pow()`, which we shouldn't try to optimize as it's + // already entirely optimized away + && power_used != 0.0 + // Same here + && recv_val != 0 + { + let power_used = power_used as u32; + let loc = Location { block: i, statement_index: bb.statements.len() }; + let exp_ty = Ty::new(tcx, ty::Uint(UintTy::U32)); + let checked_mul = + patch.new_temp(Ty::new_tup(tcx, &[exp_ty, Ty::new_bool(tcx)]), span); + + // If this is not `2.pow(...)`, we need to multiply the number of times we + // shift the bits left by the receiver's power of two used, e.g.: + // + // > 2 -> 1 + // > 4 -> 2 + // > 16 -> 4 + // > 256 -> 8 + // + // If this is `1`, then we *could* remove this entirely but it'll be + // optimized out anyway by later passes (or perhaps LLVM) so it's entirely + // unnecessary to do so. + patch.add_assign( + loc, + checked_mul.into(), + Rvalue::CheckedBinaryOp( + BinOp::Mul, + Box::new(( + exp.clone(), + Operand::Constant(Box::new(Constant { + span, + user_ty: None, + literal: ConstantKind::Val( + ConstValue::from_u32(power_used), + exp_ty, + ), + })), + )), + ), + ); + + let num_shl = tcx.mk_place_field(checked_mul.into(), FieldIdx::from_u32(0), exp_ty); + let mul_result = + tcx.mk_place_field(checked_mul.into(), FieldIdx::from_u32(1), Ty::new_bool(tcx)); + let shl_result = patch.new_temp(Ty::new_bool(tcx), span); + + // Whether the shl will overflow, if so we return 0 + patch.add_assign( + loc, + shl_result.into(), + Rvalue::BinaryOp( + BinOp::Lt, + Box::new(( + Operand::Copy(num_shl), + Operand::Constant(Box::new(Constant { + span, + user_ty: None, + literal: ConstantKind::Val(ConstValue::from_u32(32), exp_ty), + })), + )), + ), + ); + + let should_be_zero_bool = patch.new_temp(Ty::new_bool(tcx), span); + let should_be_zero = patch.new_temp(recv_ty, span); + + patch.add_assign( + loc, + should_be_zero_bool.into(), + Rvalue::BinaryOp( + BinOp::BitOr, + Box::new(( + Operand::Copy(mul_result.into()), + Operand::Copy(shl_result.into()), + )), + ), + ); + + patch.add_assign( + loc, + should_be_zero.into(), + Rvalue::Cast( + CastKind::IntToInt, + Operand::Copy(should_be_zero_bool.into()), + recv_ty, + ), + ); + + let shl_exp_ty = patch.new_temp(exp_ty, span); + let shl = patch.new_temp(recv_ty, span); + + patch.add_assign( + loc, + shl_exp_ty.into(), + Rvalue::BinaryOp( + BinOp::Shl, + Box::new(( + Operand::Constant(Box::new(Constant { + span, + user_ty: None, + literal: ConstantKind::Val(ConstValue::from_u32(1), exp_ty), + })), + Operand::Copy(num_shl.into()), + )), + ), + ); + + patch.add_assign( + loc, + shl.into(), + Rvalue::Cast( + CastKind::IntToInt, + Operand::Copy(shl_exp_ty.into()), + recv_ty, + ), + ); + + patch.add_assign( + loc, + *destination, + Rvalue::BinaryOp( + BinOp::MulUnchecked, + Box::new((Operand::Copy(shl.into()), Operand::Copy(should_be_zero.into()))), + ), + ); + + // shl doesn't set the overflow flag on x86_64 or even in Rust, so shr to + // see if it overflowed. If it equals 1, it did not, but we also need to + // check `shl_result` to ensure that if this is a multiple of the type's + // size it won't wrap back over to 1 + // + // FIXME(Centri3): Do we use `debug_assertions` or `overflow_checks` here? + if tcx.sess.opts.debug_assertions { + let shr = patch.new_temp(recv_ty, span); + let shl_eq_shr = patch.new_temp(Ty::new_bool(tcx), span); + let overflowed = patch.new_temp(Ty::new_bool(tcx), span); + + patch.add_assign( + loc, + shr.into(), + Rvalue::BinaryOp( + BinOp::Shr, + Box::new((Operand::Copy(shl.into()), Operand::Copy(num_shl.into()))), + ), + ); + + patch.add_assign( + loc, + shl_eq_shr.into(), + Rvalue::BinaryOp( + BinOp::Eq, + Box::new((Operand::Copy(shl.into()), Operand::Copy(shr.into()))), + ), + ); + + patch.add_assign( + loc, + overflowed.into(), + Rvalue::BinaryOp( + BinOp::BitAnd, + Box::new((Operand::Copy(shl_eq_shr.into()), Operand::Copy(shl_result.into()))), + ), + ); + + patch.patch_terminator( + i, + TerminatorKind::Assert { + cond: Operand::Copy(overflowed.into()), + expected: true, + msg: Box::new(AssertMessage::Overflow( + // For consistency with the previous error message, though + // it's technically incorrect + BinOp::Mul, + Operand::Constant(Box::new(Constant { + span, + user_ty: None, + literal: ConstantKind::Val(ConstValue::Scalar(Scalar::from_u32(1)), exp_ty), + })), + Operand::Copy(num_shl.into()), + )), + target: *target, + unwind: *unwind, + }, + ); + } else { + patch.patch_terminator(i, TerminatorKind::Goto { target: *target }); + } + } + } + + patch.apply(body); + } +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d3739733c1d10..c6add72fde56c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1054,6 +1054,7 @@ symbols! { not, notable_trait, note, + num, object_safe_for_dispatch, of, offset, @@ -1121,6 +1122,7 @@ symbols! { poll, position, post_dash_lto: "post-lto", + pow, powerpc_target_feature, powf32, powf64, diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs new file mode 100644 index 0000000000000..7737b55868bb9 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs @@ -0,0 +1,50 @@ +// compile-flags: -Coverflow-checks=false + +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff +fn slow_2_u(a: u32) -> u32 { + 2u32.pow(a) +} + +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff +fn slow_2_i(a: u32) -> i32 { + 2i32.pow(a) +} + +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff +fn slow_4_u(a: u32) -> u32 { + 4u32.pow(a) +} + +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff +fn slow_4_i(a: u32) -> i32 { + 4i32.pow(a) +} + +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff +fn slow_256_u(a: u32) -> u32 { + 256u32.pow(a) +} + +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff +fn slow_256_i(a: u32) -> i32 { + 256i32.pow(a) +} + +fn main() { + slow_2_u(0); + slow_2_i(0); + slow_2_u(1); + slow_2_i(1); + slow_2_u(2); + slow_2_i(2); + slow_4_u(4); + slow_4_i(4); + slow_4_u(15); + slow_4_i(15); + slow_4_u(16); + slow_4_i(16); + slow_4_u(17); + slow_4_i(17); + slow_256_u(2); + slow_256_i(2); +} diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..b0b8fa2d7d6af --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_256_i` before SimplifyPowOfTwo ++ // MIR for `slow_256_i` after SimplifyPowOfTwo + + fn slow_256_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: i32; ++ let mut _7: u32; ++ let mut _8: i32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 8_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as i32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as i32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..a86c5ae2c3a37 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_256_u` before SimplifyPowOfTwo ++ // MIR for `slow_256_u` after SimplifyPowOfTwo + + fn slow_256_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: u32; ++ let mut _7: u32; ++ let mut _8: u32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 8_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as u32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as u32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..67e0dd7791418 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_2_i` before SimplifyPowOfTwo ++ // MIR for `slow_2_i` after SimplifyPowOfTwo + + fn slow_2_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: i32; ++ let mut _7: u32; ++ let mut _8: i32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 1_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as i32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as i32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..496b3f45e7a8f --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_2_u` before SimplifyPowOfTwo ++ // MIR for `slow_2_u` after SimplifyPowOfTwo + + fn slow_2_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: u32; ++ let mut _7: u32; ++ let mut _8: u32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 1_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as u32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as u32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..1afc4ea19f851 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_4_i` before SimplifyPowOfTwo ++ // MIR for `slow_4_i` after SimplifyPowOfTwo + + fn slow_4_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: i32; ++ let mut _7: u32; ++ let mut _8: i32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 2_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as i32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as i32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..431e5890aa888 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_4_u` before SimplifyPowOfTwo ++ // MIR for `slow_4_u` after SimplifyPowOfTwo + + fn slow_4_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: u32; ++ let mut _7: u32; ++ let mut _8: u32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 2_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as u32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as u32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs b/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs new file mode 100644 index 0000000000000..47d40bc623b0f --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs @@ -0,0 +1,50 @@ +// compile-flags: -Coverflow-checks=true + +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff +fn slow_2_u(a: u32) -> u32 { + 2u32.pow(a) +} + +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff +fn slow_2_i(a: u32) -> i32 { + 2i32.pow(a) +} + +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff +fn slow_4_u(a: u32) -> u32 { + 4u32.pow(a) +} + +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff +fn slow_4_i(a: u32) -> i32 { + 4i32.pow(a) +} + +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff +fn slow_256_u(a: u32) -> u32 { + 256u32.pow(a) +} + +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff +fn slow_256_i(a: u32) -> i32 { + 256i32.pow(a) +} + +fn main() { + slow_2_u(0); + slow_2_i(0); + slow_2_u(1); + slow_2_i(1); + slow_2_u(2); + slow_2_i(2); + slow_4_u(4); + slow_4_i(4); + slow_4_u(15); + slow_4_i(15); + slow_4_u(16); + slow_4_i(16); + slow_4_u(17); + slow_4_i(17); + slow_256_u(2); + slow_256_i(2); +} diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..b0b8fa2d7d6af --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_256_i` before SimplifyPowOfTwo ++ // MIR for `slow_256_i` after SimplifyPowOfTwo + + fn slow_256_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: i32; ++ let mut _7: u32; ++ let mut _8: i32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 8_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as i32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as i32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..a86c5ae2c3a37 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_256_u` before SimplifyPowOfTwo ++ // MIR for `slow_256_u` after SimplifyPowOfTwo + + fn slow_256_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: u32; ++ let mut _7: u32; ++ let mut _8: u32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 8_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as u32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as u32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..67e0dd7791418 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_2_i` before SimplifyPowOfTwo ++ // MIR for `slow_2_i` after SimplifyPowOfTwo + + fn slow_2_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: i32; ++ let mut _7: u32; ++ let mut _8: i32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 1_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as i32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as i32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..496b3f45e7a8f --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_2_u` before SimplifyPowOfTwo ++ // MIR for `slow_2_u` after SimplifyPowOfTwo + + fn slow_2_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: u32; ++ let mut _7: u32; ++ let mut _8: u32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 1_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as u32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as u32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..1afc4ea19f851 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_4_i` before SimplifyPowOfTwo ++ // MIR for `slow_4_i` after SimplifyPowOfTwo + + fn slow_4_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: i32; ++ let mut _7: u32; ++ let mut _8: i32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 2_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as i32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as i32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff new file mode 100644 index 0000000000000..431e5890aa888 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff @@ -0,0 +1,34 @@ +- // MIR for `slow_4_u` before SimplifyPowOfTwo ++ // MIR for `slow_4_u` after SimplifyPowOfTwo + + fn slow_4_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; ++ let mut _3: (u32, bool); ++ let mut _4: bool; ++ let mut _5: bool; ++ let mut _6: u32; ++ let mut _7: u32; ++ let mut _8: u32; + + bb0: { + StorageLive(_2); + _2 = _1; +- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind unreachable]; ++ _3 = CheckedMul(move _2, const 2_u32); ++ _4 = Lt((_3.0: u32), const 32_u32); ++ _5 = BitOr((_3.1: bool), _4); ++ _6 = _5 as u32 (IntToInt); ++ _7 = Shl(const 1_u32, (_3.0: u32)); ++ _8 = _7 as u32 (IntToInt); ++ _0 = MulUnchecked(_8, _6); ++ goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } + } + diff --git a/tests/ui/mir/simplify-pow-of-two.rs b/tests/ui/mir/simplify-pow-of-two.rs new file mode 100644 index 0000000000000..cee55ed044059 --- /dev/null +++ b/tests/ui/mir/simplify-pow-of-two.rs @@ -0,0 +1,44 @@ +// run-pass + +fn slow_2_u(a: u32) -> u32 { + 2u32.pow(a) +} + +fn slow_2_i(a: u32) -> i32 { + 2i32.pow(a) +} + +fn slow_4_u(a: u32) -> u32 { + 4u32.pow(a) +} + +fn slow_4_i(a: u32) -> i32 { + 4i32.pow(a) +} + +fn slow_256_u(a: u32) -> u32 { + 256u32.pow(a) +} + +fn slow_256_i(a: u32) -> i32 { + 256i32.pow(a) +} + +fn main() { + assert_eq!(slow_2_u(0), 1); + assert_eq!(slow_2_i(0), 1); + assert_eq!(slow_2_u(1), 2); + assert_eq!(slow_2_i(1), 2); + assert_eq!(slow_2_u(2), 4); + assert_eq!(slow_2_i(2), 4); + assert_eq!(slow_4_u(4), 256); + assert_eq!(slow_4_i(4), 256); + assert_eq!(slow_4_u(15), 1073741824); + assert_eq!(slow_4_i(15), 1073741824); + assert_eq!(slow_4_u(16), 0); + assert_eq!(slow_4_i(16), 0); + assert_eq!(slow_4_u(17), 0); + assert_eq!(slow_4_i(17), 0); + assert_eq!(slow_256_u(2), 65536); + assert_eq!(slow_256_i(2), 65536); +} From cb2b3ea2aa2e29d76ccb5267c3cdada341b68343 Mon Sep 17 00:00:00 2001 From: Catherine Flores Date: Sun, 30 Jul 2023 14:59:32 +0000 Subject: [PATCH 2/5] Use size of recv instead of constant `32` --- .../src/simplify_pow_of_two.rs | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs b/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs index 58a3cfdda8e69..264fe7054cf4f 100644 --- a/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs +++ b/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs @@ -103,8 +103,11 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { ); let num_shl = tcx.mk_place_field(checked_mul.into(), FieldIdx::from_u32(0), exp_ty); - let mul_result = - tcx.mk_place_field(checked_mul.into(), FieldIdx::from_u32(1), Ty::new_bool(tcx)); + let mul_result = tcx.mk_place_field( + checked_mul.into(), + FieldIdx::from_u32(1), + Ty::new_bool(tcx), + ); let shl_result = patch.new_temp(Ty::new_bool(tcx), span); // Whether the shl will overflow, if so we return 0 @@ -118,7 +121,10 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: ConstantKind::Val(ConstValue::from_u32(32), exp_ty), + literal: ConstantKind::Val( + ConstValue::from_u32(recv_int.size().bits() as u32), + exp_ty, + ), })), )), ), @@ -171,11 +177,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { patch.add_assign( loc, shl.into(), - Rvalue::Cast( - CastKind::IntToInt, - Operand::Copy(shl_exp_ty.into()), - recv_ty, - ), + Rvalue::Cast(CastKind::IntToInt, Operand::Copy(shl_exp_ty.into()), recv_ty), ); patch.add_assign( @@ -221,7 +223,10 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { overflowed.into(), Rvalue::BinaryOp( BinOp::BitAnd, - Box::new((Operand::Copy(shl_eq_shr.into()), Operand::Copy(shl_result.into()))), + Box::new(( + Operand::Copy(shl_eq_shr.into()), + Operand::Copy(shl_result.into()), + )), ), ); @@ -237,7 +242,10 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: ConstantKind::Val(ConstValue::Scalar(Scalar::from_u32(1)), exp_ty), + literal: ConstantKind::Val( + ConstValue::Scalar(Scalar::from_u32(1)), + exp_ty, + ), })), Operand::Copy(num_shl.into()), )), From c4b8c57e4829b95871742ad164f31c7a5cf4a8e2 Mon Sep 17 00:00:00 2001 From: Catherine Flores Date: Sun, 30 Jul 2023 15:02:09 +0000 Subject: [PATCH 3/5] Use `-Cdebug-assertions` instead of `-Coverlow-checks` in tests --- .../rustc_mir_transform/src/simplify_pow_of_two.rs | 4 ++-- .../mir-opt/simplify_pow_of_two_no_overflow_checks.rs | 2 +- ...no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff | 2 +- ...no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff | 2 +- ...o_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff | 2 +- ...o_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff | 2 +- ...o_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff | 2 +- ...o_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff | 2 +- tests/mir-opt/simplify_pow_of_two_overflow_checks.rs | 2 +- ...wo_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff | 10 ++++++++-- ...wo_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff | 10 ++++++++-- ..._two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff | 10 ++++++++-- ..._two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff | 10 ++++++++-- ..._two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff | 10 ++++++++-- ..._two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff | 10 ++++++++-- 15 files changed, 58 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs b/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs index 264fe7054cf4f..cefb2f621807f 100644 --- a/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs +++ b/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs @@ -222,7 +222,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { loc, overflowed.into(), Rvalue::BinaryOp( - BinOp::BitAnd, + BinOp::BitOr, Box::new(( Operand::Copy(shl_eq_shr.into()), Operand::Copy(shl_result.into()), @@ -234,7 +234,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { i, TerminatorKind::Assert { cond: Operand::Copy(overflowed.into()), - expected: true, + expected: false, msg: Box::new(AssertMessage::Overflow( // For consistency with the previous error message, though // it's technically incorrect diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs index 7737b55868bb9..1953276bb78c7 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs @@ -1,4 +1,4 @@ -// compile-flags: -Coverflow-checks=false +// compile-flags: -Cdebug-assertions=false // EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff fn slow_2_u(a: u32) -> u32 { diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff index b0b8fa2d7d6af..32944e0e0267d 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff @@ -15,7 +15,7 @@ bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff index a86c5ae2c3a37..a1b8deb218972 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff @@ -15,7 +15,7 @@ bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff index 67e0dd7791418..ad57ff93c82e8 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff @@ -15,7 +15,7 @@ bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff index 496b3f45e7a8f..d5f997bad3649 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff @@ -15,7 +15,7 @@ bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff index 1afc4ea19f851..ec0d2e6a10082 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff @@ -15,7 +15,7 @@ bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff index 431e5890aa888..9cf2a9b4de54c 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff @@ -15,7 +15,7 @@ bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs b/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs index 47d40bc623b0f..0dd819b5ffc9e 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs @@ -1,4 +1,4 @@ -// compile-flags: -Coverflow-checks=true +// compile-flags: -Cdebug-assertions=true // EMIT_MIR simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff fn slow_2_u(a: u32) -> u32 { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff index b0b8fa2d7d6af..c126d8a592d5b 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff @@ -11,11 +11,14 @@ + let mut _6: i32; + let mut _7: u32; + let mut _8: i32; ++ let mut _9: i32; ++ let mut _10: bool; ++ let mut _11: bool; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); @@ -23,7 +26,10 @@ + _7 = Shl(const 1_u32, (_3.0: u32)); + _8 = _7 as i32 (IntToInt); + _0 = MulUnchecked(_8, _6); -+ goto -> bb1; ++ _9 = Shr(_8, (_3.0: u32)); ++ _10 = Eq(_8, _9); ++ _11 = BitOr(_10, _4); ++ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff index a86c5ae2c3a37..92faa89c969ae 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff @@ -11,11 +11,14 @@ + let mut _6: u32; + let mut _7: u32; + let mut _8: u32; ++ let mut _9: u32; ++ let mut _10: bool; ++ let mut _11: bool; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); @@ -23,7 +26,10 @@ + _7 = Shl(const 1_u32, (_3.0: u32)); + _8 = _7 as u32 (IntToInt); + _0 = MulUnchecked(_8, _6); -+ goto -> bb1; ++ _9 = Shr(_8, (_3.0: u32)); ++ _10 = Eq(_8, _9); ++ _11 = BitOr(_10, _4); ++ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff index 67e0dd7791418..ff44fe313444c 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff @@ -11,11 +11,14 @@ + let mut _6: i32; + let mut _7: u32; + let mut _8: i32; ++ let mut _9: i32; ++ let mut _10: bool; ++ let mut _11: bool; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); @@ -23,7 +26,10 @@ + _7 = Shl(const 1_u32, (_3.0: u32)); + _8 = _7 as i32 (IntToInt); + _0 = MulUnchecked(_8, _6); -+ goto -> bb1; ++ _9 = Shr(_8, (_3.0: u32)); ++ _10 = Eq(_8, _9); ++ _11 = BitOr(_10, _4); ++ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff index 496b3f45e7a8f..32b72e5d2b0b3 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff @@ -11,11 +11,14 @@ + let mut _6: u32; + let mut _7: u32; + let mut _8: u32; ++ let mut _9: u32; ++ let mut _10: bool; ++ let mut _11: bool; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); @@ -23,7 +26,10 @@ + _7 = Shl(const 1_u32, (_3.0: u32)); + _8 = _7 as u32 (IntToInt); + _0 = MulUnchecked(_8, _6); -+ goto -> bb1; ++ _9 = Shr(_8, (_3.0: u32)); ++ _10 = Eq(_8, _9); ++ _11 = BitOr(_10, _4); ++ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff index 1afc4ea19f851..3410cf9a7d27e 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff @@ -11,11 +11,14 @@ + let mut _6: i32; + let mut _7: u32; + let mut _8: i32; ++ let mut _9: i32; ++ let mut _10: bool; ++ let mut _11: bool; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); @@ -23,7 +26,10 @@ + _7 = Shl(const 1_u32, (_3.0: u32)); + _8 = _7 as i32 (IntToInt); + _0 = MulUnchecked(_8, _6); -+ goto -> bb1; ++ _9 = Shr(_8, (_3.0: u32)); ++ _10 = Eq(_8, _9); ++ _11 = BitOr(_10, _4); ++ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff index 431e5890aa888..b54d4f4d6dedf 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff @@ -11,11 +11,14 @@ + let mut _6: u32; + let mut _7: u32; + let mut _8: u32; ++ let mut _9: u32; ++ let mut _10: bool; ++ let mut _11: bool; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind unreachable]; +- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind continue]; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); @@ -23,7 +26,10 @@ + _7 = Shl(const 1_u32, (_3.0: u32)); + _8 = _7 as u32 (IntToInt); + _0 = MulUnchecked(_8, _6); -+ goto -> bb1; ++ _9 = Shr(_8, (_3.0: u32)); ++ _10 = Eq(_8, _9); ++ _11 = BitOr(_10, _4); ++ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; } bb1: { From 9b299077a0e1ec0af1c03f2f908d4cb94f8ebc96 Mon Sep 17 00:00:00 2001 From: Catherine Flores Date: Sun, 30 Jul 2023 16:52:10 +0000 Subject: [PATCH 4/5] Maybe fix the regression? --- .../src/simplify_pow_of_two.rs | 89 ++++--------------- .../simplify-pow-of-two-debug-assertions.rs | 19 ++++ tests/codegen/simplify-pow-of-two.rs | 16 ++++ ...ow_checks.slow_256_i.SimplifyPowOfTwo.diff | 10 +-- ...ow_checks.slow_256_u.SimplifyPowOfTwo.diff | 6 +- ...flow_checks.slow_2_i.SimplifyPowOfTwo.diff | 10 +-- ...flow_checks.slow_2_u.SimplifyPowOfTwo.diff | 6 +- ...flow_checks.slow_4_i.SimplifyPowOfTwo.diff | 10 +-- ...flow_checks.slow_4_u.SimplifyPowOfTwo.diff | 6 +- ...ow_checks.slow_256_i.SimplifyPowOfTwo.diff | 18 ++-- ...ow_checks.slow_256_u.SimplifyPowOfTwo.diff | 14 +-- ...flow_checks.slow_2_i.SimplifyPowOfTwo.diff | 18 ++-- ...flow_checks.slow_2_u.SimplifyPowOfTwo.diff | 14 +-- ...flow_checks.slow_4_i.SimplifyPowOfTwo.diff | 18 ++-- ...flow_checks.slow_4_u.SimplifyPowOfTwo.diff | 14 +-- tests/ui/mir/simplify-pow-of-two.rs | 34 +++++++ 16 files changed, 130 insertions(+), 172 deletions(-) create mode 100644 tests/codegen/simplify-pow-of-two-debug-assertions.rs create mode 100644 tests/codegen/simplify-pow-of-two.rs diff --git a/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs b/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs index cefb2f621807f..20e8e19aa1193 100644 --- a/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs +++ b/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs @@ -3,7 +3,6 @@ use crate::MirPass; use rustc_const_eval::interpret::{ConstValue, Scalar}; -use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt, UintTy}; @@ -33,18 +32,14 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { && let Some(def_id) = func.const_fn_def().map(|def| def.0) && let def_path = tcx.def_path(def_id) && tcx.crate_name(def_path.krate) == sym::core - // FIXME(Centri3): I feel like we should do this differently... - && let [ - DisambiguatedDefPathData { data: DefPathData::TypeNs(sym::num), disambiguator: 0 }, - DisambiguatedDefPathData { data: DefPathData::Impl, .. }, - DisambiguatedDefPathData { data: DefPathData::ValueNs(sym::pow), .. }, - ] = &*def_path.data && let [recv, exp] = args.as_slice() && let Some(recv_const) = recv.constant() && let ConstantKind::Val( ConstValue::Scalar(Scalar::Int(recv_int)), recv_ty, ) = recv_const.literal + && recv_ty.is_integral() + && tcx.item_name(def_id) == sym::pow && let Ok(recv_val) = match recv_ty.kind() { ty::Int(_) => { let result = recv_int.try_to_int(recv_int.size()).unwrap_or(-1).max(0); @@ -63,8 +58,8 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { // `0` would be `1.pow()`, which we shouldn't try to optimize as it's // already entirely optimized away && power_used != 0.0 - // Same here - && recv_val != 0 + // `-inf` would be `0.pow()` + && power_used.is_finite() { let power_used = power_used as u32; let loc = Location { block: i, statement_index: bb.statements.len() }; @@ -110,7 +105,8 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { ); let shl_result = patch.new_temp(Ty::new_bool(tcx), span); - // Whether the shl will overflow, if so we return 0 + // Whether the shl will overflow, if so we return 0. We can do this rather + // than doing a shr because only one bit is set on any power of two patch.add_assign( loc, shl_result.into(), @@ -130,12 +126,12 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { ), ); - let should_be_zero_bool = patch.new_temp(Ty::new_bool(tcx), span); - let should_be_zero = patch.new_temp(recv_ty, span); + let fine_bool = patch.new_temp(Ty::new_bool(tcx), span); + let fine = patch.new_temp(recv_ty, span); patch.add_assign( loc, - should_be_zero_bool.into(), + fine_bool.into(), Rvalue::BinaryOp( BinOp::BitOr, Box::new(( @@ -147,94 +143,47 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { patch.add_assign( loc, - should_be_zero.into(), - Rvalue::Cast( - CastKind::IntToInt, - Operand::Copy(should_be_zero_bool.into()), - recv_ty, - ), + fine.into(), + Rvalue::Cast(CastKind::IntToInt, Operand::Copy(fine_bool.into()), recv_ty), ); - let shl_exp_ty = patch.new_temp(exp_ty, span); let shl = patch.new_temp(recv_ty, span); patch.add_assign( loc, - shl_exp_ty.into(), + shl.into(), Rvalue::BinaryOp( BinOp::Shl, Box::new(( Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: ConstantKind::Val(ConstValue::from_u32(1), exp_ty), + literal: ConstantKind::Val( + ConstValue::Scalar(Scalar::from_uint(1u128, recv_int.size())), + recv_ty, + ), })), Operand::Copy(num_shl.into()), )), ), ); - patch.add_assign( - loc, - shl.into(), - Rvalue::Cast(CastKind::IntToInt, Operand::Copy(shl_exp_ty.into()), recv_ty), - ); - patch.add_assign( loc, *destination, Rvalue::BinaryOp( BinOp::MulUnchecked, - Box::new((Operand::Copy(shl.into()), Operand::Copy(should_be_zero.into()))), + Box::new((Operand::Copy(shl.into()), Operand::Copy(fine.into()))), ), ); - // shl doesn't set the overflow flag on x86_64 or even in Rust, so shr to - // see if it overflowed. If it equals 1, it did not, but we also need to - // check `shl_result` to ensure that if this is a multiple of the type's - // size it won't wrap back over to 1 - // // FIXME(Centri3): Do we use `debug_assertions` or `overflow_checks` here? if tcx.sess.opts.debug_assertions { - let shr = patch.new_temp(recv_ty, span); - let shl_eq_shr = patch.new_temp(Ty::new_bool(tcx), span); - let overflowed = patch.new_temp(Ty::new_bool(tcx), span); - - patch.add_assign( - loc, - shr.into(), - Rvalue::BinaryOp( - BinOp::Shr, - Box::new((Operand::Copy(shl.into()), Operand::Copy(num_shl.into()))), - ), - ); - - patch.add_assign( - loc, - shl_eq_shr.into(), - Rvalue::BinaryOp( - BinOp::Eq, - Box::new((Operand::Copy(shl.into()), Operand::Copy(shr.into()))), - ), - ); - - patch.add_assign( - loc, - overflowed.into(), - Rvalue::BinaryOp( - BinOp::BitOr, - Box::new(( - Operand::Copy(shl_eq_shr.into()), - Operand::Copy(shl_result.into()), - )), - ), - ); - patch.patch_terminator( i, TerminatorKind::Assert { - cond: Operand::Copy(overflowed.into()), - expected: false, + cond: Operand::Copy(fine_bool.into()), + expected: true, msg: Box::new(AssertMessage::Overflow( // For consistency with the previous error message, though // it's technically incorrect diff --git a/tests/codegen/simplify-pow-of-two-debug-assertions.rs b/tests/codegen/simplify-pow-of-two-debug-assertions.rs new file mode 100644 index 0000000000000..c1d2a0b2acd01 --- /dev/null +++ b/tests/codegen/simplify-pow-of-two-debug-assertions.rs @@ -0,0 +1,19 @@ +// compile-flags: -Copt-level=3 -Cdebug-assertions=true + +// CHECK-LABEL: @slow_2_u( +#[no_mangle] +fn slow_2_u(a: u32) -> u32 { + // CHECK: %_3 = icmp ult i32 %a, 32 + // CHECK-NEXT: br i1 %_3, label %bb1, label %panic, !prof !{{[0-9]+}} + // CHECK-EMPTY: + // CHECK-NEXT: bb1: + // CHECK-NEXT: %_01 = shl nuw i32 1, %a + // CHECK-NEXT: ret i32 %_0 + // CHECK-EMPTY: + // CHECK-NEXT: panic: + 2u32.pow(a) +} + +fn main() { + slow_2_u(2); +} diff --git a/tests/codegen/simplify-pow-of-two.rs b/tests/codegen/simplify-pow-of-two.rs new file mode 100644 index 0000000000000..657e4af8dbc10 --- /dev/null +++ b/tests/codegen/simplify-pow-of-two.rs @@ -0,0 +1,16 @@ +// compile-flags: -Copt-level=3 + +// CHECK-LABEL: @slow_2_u( +#[no_mangle] +fn slow_2_u(a: u32) -> u32 { + // CHECK: %_3 = icmp ult i32 %a, 32 + // CHECK-NEXT: %_5 = zext i1 %_3 to i32 + // CHECK-NEXT: %0 = and i32 %a, 31 + // CHECK-NEXT: %_01 = shl nuw i32 %_5, %0 + // CHECK-NEXT: ret i32 %_01 + 2u32.pow(a) +} + +fn main() { + slow_2_u(2); +} diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff index 32944e0e0267d..a6369d4ec89d6 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff @@ -9,20 +9,18 @@ + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; -+ let mut _7: u32; -+ let mut _8: i32; ++ let mut _7: i32; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as i32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); ++ _7 = Shl(const 1_i32, (_3.0: u32)); ++ _0 = MulUnchecked(_7, _6); + goto -> bb1; } diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff index a1b8deb218972..b8f6a929ecf73 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff @@ -10,19 +10,17 @@ + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; -+ let mut _8: u32; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as u32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); ++ _0 = MulUnchecked(_7, _6); + goto -> bb1; } diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff index ad57ff93c82e8..0de879d057224 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff @@ -9,20 +9,18 @@ + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; -+ let mut _7: u32; -+ let mut _8: i32; ++ let mut _7: i32; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as i32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); ++ _7 = Shl(const 1_i32, (_3.0: u32)); ++ _0 = MulUnchecked(_7, _6); + goto -> bb1; } diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff index d5f997bad3649..2cc8f88624d63 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff @@ -10,19 +10,17 @@ + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; -+ let mut _8: u32; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as u32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); ++ _0 = MulUnchecked(_7, _6); + goto -> bb1; } diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff index ec0d2e6a10082..cf9342a14434d 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff @@ -9,20 +9,18 @@ + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; -+ let mut _7: u32; -+ let mut _8: i32; ++ let mut _7: i32; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as i32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); ++ _7 = Shl(const 1_i32, (_3.0: u32)); ++ _0 = MulUnchecked(_7, _6); + goto -> bb1; } diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff index 9cf2a9b4de54c..5037093ac900a 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff @@ -10,19 +10,17 @@ + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; -+ let mut _8: u32; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as u32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); ++ _0 = MulUnchecked(_7, _6); + goto -> bb1; } diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff index c126d8a592d5b..e9323e3deb470 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff @@ -9,27 +9,19 @@ + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; -+ let mut _7: u32; -+ let mut _8: i32; -+ let mut _9: i32; -+ let mut _10: bool; -+ let mut _11: bool; ++ let mut _7: i32; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as i32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); -+ _9 = Shr(_8, (_3.0: u32)); -+ _10 = Eq(_8, _9); -+ _11 = BitOr(_10, _4); -+ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; ++ _7 = Shl(const 1_i32, (_3.0: u32)); ++ _0 = MulUnchecked(_7, _6); ++ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff index 92faa89c969ae..c9f5c5c5568e7 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff @@ -10,26 +10,18 @@ + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; -+ let mut _8: u32; -+ let mut _9: u32; -+ let mut _10: bool; -+ let mut _11: bool; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as u32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); -+ _9 = Shr(_8, (_3.0: u32)); -+ _10 = Eq(_8, _9); -+ _11 = BitOr(_10, _4); -+ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; ++ _0 = MulUnchecked(_7, _6); ++ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff index ff44fe313444c..0ad56062a1f72 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff @@ -9,27 +9,19 @@ + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; -+ let mut _7: u32; -+ let mut _8: i32; -+ let mut _9: i32; -+ let mut _10: bool; -+ let mut _11: bool; ++ let mut _7: i32; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as i32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); -+ _9 = Shr(_8, (_3.0: u32)); -+ _10 = Eq(_8, _9); -+ _11 = BitOr(_10, _4); -+ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; ++ _7 = Shl(const 1_i32, (_3.0: u32)); ++ _0 = MulUnchecked(_7, _6); ++ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff index 32b72e5d2b0b3..f27d3a704d2c0 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff @@ -10,26 +10,18 @@ + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; -+ let mut _8: u32; -+ let mut _9: u32; -+ let mut _10: bool; -+ let mut _11: bool; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as u32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); -+ _9 = Shr(_8, (_3.0: u32)); -+ _10 = Eq(_8, _9); -+ _11 = BitOr(_10, _4); -+ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; ++ _0 = MulUnchecked(_7, _6); ++ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff index 3410cf9a7d27e..dc0c72d9c4aae 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff @@ -9,27 +9,19 @@ + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; -+ let mut _7: u32; -+ let mut _8: i32; -+ let mut _9: i32; -+ let mut _10: bool; -+ let mut _11: bool; ++ let mut _7: i32; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as i32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); -+ _9 = Shr(_8, (_3.0: u32)); -+ _10 = Eq(_8, _9); -+ _11 = BitOr(_10, _4); -+ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; ++ _7 = Shl(const 1_i32, (_3.0: u32)); ++ _0 = MulUnchecked(_7, _6); ++ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff index b54d4f4d6dedf..39bd3ea438600 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff @@ -10,26 +10,18 @@ + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; -+ let mut _8: u32; -+ let mut _9: u32; -+ let mut _10: bool; -+ let mut _11: bool; bb0: { StorageLive(_2); _2 = _1; -- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind continue]; +- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind unreachable]; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); -+ _8 = _7 as u32 (IntToInt); -+ _0 = MulUnchecked(_8, _6); -+ _9 = Shr(_8, (_3.0: u32)); -+ _10 = Eq(_8, _9); -+ _11 = BitOr(_10, _4); -+ assert(!_11, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; ++ _0 = MulUnchecked(_7, _6); ++ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/ui/mir/simplify-pow-of-two.rs b/tests/ui/mir/simplify-pow-of-two.rs index cee55ed044059..70df62717ea11 100644 --- a/tests/ui/mir/simplify-pow-of-two.rs +++ b/tests/ui/mir/simplify-pow-of-two.rs @@ -1,5 +1,10 @@ // run-pass +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +use std::intrinsics::mir::*; + fn slow_2_u(a: u32) -> u32 { 2u32.pow(a) } @@ -41,4 +46,33 @@ fn main() { assert_eq!(slow_4_i(17), 0); assert_eq!(slow_256_u(2), 65536); assert_eq!(slow_256_i(2), 65536); + + for i in 0..300 { + for j in 0..3000 { + let ix = 2u128.pow(i); + assert_eq!(ix.pow(j), test_mir(i, j), "{ix}, {j}"); + } + } +} + +/// num is the power used to get recv, will be calculated while building this +/// MIR but it's necessary here for testing +/// +/// You can test this out in the playground here: +/// https://play.rust-lang.org/?version=nightly&mode=release&edition=2021&gist=de34e2a6a8f9114ce01bfb62f9379413 +/// +/// This equals `ix.pow(j)` both with and without this optimization. +#[custom_mir(dialect = "built")] +pub fn test_mir(num: u32, exp: u32) -> u128 { + mir! { + { + let num_shl = Checked(exp * num); + let shl_result = num_shl.0 < 128; + let shl = 1u128 << num_shl.0; + let fine_bool = shl_result | num_shl.1; + let fine = fine_bool as u128; + RET = shl * fine; + Return() + } + } } From f944ebadabdb2145ed436edcf4f15a392ce64d90 Mon Sep 17 00:00:00 2001 From: Catherine Flores Date: Sun, 30 Jul 2023 20:09:38 +0000 Subject: [PATCH 5/5] Use `continue` instead of `unreachable` to prevent immediate UB --- .../src/simplify_pow_of_two.rs | 3 +- .../simplify_pow_of_two_no_overflow_checks.rs | 13 ++++---- ...ecks.slow_256_i.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...ow_checks.slow_256_i.SimplifyPowOfTwo.diff | 32 ------------------- ...ecks.slow_256_u.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...ow_checks.slow_256_u.SimplifyPowOfTwo.diff | 32 ------------------- ...checks.slow_2_i.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...flow_checks.slow_2_i.SimplifyPowOfTwo.diff | 32 ------------------- ...checks.slow_2_u.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...flow_checks.slow_2_u.SimplifyPowOfTwo.diff | 32 ------------------- ...checks.slow_4_i.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...flow_checks.slow_4_i.SimplifyPowOfTwo.diff | 32 ------------------- ...checks.slow_4_u.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...flow_checks.slow_4_u.SimplifyPowOfTwo.diff | 32 ------------------- .../simplify_pow_of_two_overflow_checks.rs | 13 ++++---- ...ecks.slow_256_i.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...ow_checks.slow_256_i.SimplifyPowOfTwo.diff | 32 ------------------- ...ecks.slow_256_u.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...ow_checks.slow_256_u.SimplifyPowOfTwo.diff | 32 ------------------- ...checks.slow_2_i.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...flow_checks.slow_2_i.SimplifyPowOfTwo.diff | 32 ------------------- ...checks.slow_2_u.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...flow_checks.slow_2_u.SimplifyPowOfTwo.diff | 32 ------------------- ...checks.slow_4_i.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...flow_checks.slow_4_i.SimplifyPowOfTwo.diff | 32 ------------------- ...checks.slow_4_u.SimplifyPowOfTwo.after.mir | 29 +++++++++++++++++ ...flow_checks.slow_4_u.SimplifyPowOfTwo.diff | 32 ------------------- 27 files changed, 363 insertions(+), 398 deletions(-) create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff create mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.after.mir delete mode 100644 tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff diff --git a/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs b/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs index 20e8e19aa1193..a500b45651c88 100644 --- a/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs +++ b/compiler/rustc_mir_transform/src/simplify_pow_of_two.rs @@ -25,7 +25,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { args, destination, target: Some(target), - unwind, call_source: CallSource::Normal, .. } = &term.kind @@ -199,7 +198,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyPowOfTwo { Operand::Copy(num_shl.into()), )), target: *target, - unwind: *unwind, + unwind: UnwindAction::Continue, }, ); } else { diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs index 1953276bb78c7..1315aa8a60107 100644 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.rs @@ -1,31 +1,32 @@ +// unit-test: SimplifyPowOfTwo // compile-flags: -Cdebug-assertions=false -// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.after.mir fn slow_2_u(a: u32) -> u32 { 2u32.pow(a) } -// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.after.mir fn slow_2_i(a: u32) -> i32 { 2i32.pow(a) } -// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.after.mir fn slow_4_u(a: u32) -> u32 { 4u32.pow(a) } -// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.after.mir fn slow_4_i(a: u32) -> i32 { 4i32.pow(a) } -// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.after.mir fn slow_256_u(a: u32) -> u32 { 256u32.pow(a) } -// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.after.mir fn slow_256_i(a: u32) -> i32 { 256i32.pow(a) } diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..23dc99e9d846a --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_256_i` after SimplifyPowOfTwo + +fn slow_256_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; + let mut _7: i32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); + _7 = Shl(const 1_i32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff deleted file mode 100644 index a6369d4ec89d6..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_256_i` before SimplifyPowOfTwo -+ // MIR for `slow_256_i` after SimplifyPowOfTwo - - fn slow_256_i(_1: u32) -> i32 { - debug a => _1; - let mut _0: i32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: i32; -+ let mut _7: i32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 8_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_i32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ goto -> bb1; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..49d3236f4ca49 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_256_u` after SimplifyPowOfTwo + +fn slow_256_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff deleted file mode 100644 index b8f6a929ecf73..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_256_u` before SimplifyPowOfTwo -+ // MIR for `slow_256_u` after SimplifyPowOfTwo - - fn slow_256_u(_1: u32) -> u32 { - debug a => _1; - let mut _0: u32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: u32; -+ let mut _7: u32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 8_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as u32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ goto -> bb1; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..73c9e5607d22c --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_2_i` after SimplifyPowOfTwo + +fn slow_2_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; + let mut _7: i32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); + _7 = Shl(const 1_i32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff deleted file mode 100644 index 0de879d057224..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_2_i` before SimplifyPowOfTwo -+ // MIR for `slow_2_i` after SimplifyPowOfTwo - - fn slow_2_i(_1: u32) -> i32 { - debug a => _1; - let mut _0: i32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: i32; -+ let mut _7: i32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 1_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_i32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ goto -> bb1; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..216e3909a0479 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_2_u` after SimplifyPowOfTwo + +fn slow_2_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff deleted file mode 100644 index 2cc8f88624d63..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_2_u` before SimplifyPowOfTwo -+ // MIR for `slow_2_u` after SimplifyPowOfTwo - - fn slow_2_u(_1: u32) -> u32 { - debug a => _1; - let mut _0: u32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: u32; -+ let mut _7: u32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 1_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as u32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ goto -> bb1; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..bfe055d0be5c6 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_4_i` after SimplifyPowOfTwo + +fn slow_4_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; + let mut _7: i32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); + _7 = Shl(const 1_i32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff deleted file mode 100644 index cf9342a14434d..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_4_i` before SimplifyPowOfTwo -+ // MIR for `slow_4_i` after SimplifyPowOfTwo - - fn slow_4_i(_1: u32) -> i32 { - debug a => _1; - let mut _0: i32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: i32; -+ let mut _7: i32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 2_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_i32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ goto -> bb1; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..238528a0b5275 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_4_u` after SimplifyPowOfTwo + +fn slow_4_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + goto -> bb1; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff deleted file mode 100644 index 5037093ac900a..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_no_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_4_u` before SimplifyPowOfTwo -+ // MIR for `slow_4_u` after SimplifyPowOfTwo - - fn slow_4_u(_1: u32) -> u32 { - debug a => _1; - let mut _0: u32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: u32; -+ let mut _7: u32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 2_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as u32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ goto -> bb1; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs b/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs index 0dd819b5ffc9e..c8d219755c747 100644 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.rs @@ -1,31 +1,32 @@ +// unit-test: SimplifyPowOfTwo // compile-flags: -Cdebug-assertions=true -// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.after.mir fn slow_2_u(a: u32) -> u32 { 2u32.pow(a) } -// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.after.mir fn slow_2_i(a: u32) -> i32 { 2i32.pow(a) } -// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.after.mir fn slow_4_u(a: u32) -> u32 { 4u32.pow(a) } -// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.after.mir fn slow_4_i(a: u32) -> i32 { 4i32.pow(a) } -// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.after.mir fn slow_256_u(a: u32) -> u32 { 256u32.pow(a) } -// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff +// EMIT_MIR simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.after.mir fn slow_256_i(a: u32) -> i32 { 256i32.pow(a) } diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..e6b7a74bfbab5 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_256_i` after SimplifyPowOfTwo + +fn slow_256_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; + let mut _7: i32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); + _7 = Shl(const 1_i32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff deleted file mode 100644 index e9323e3deb470..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_i.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_256_i` before SimplifyPowOfTwo -+ // MIR for `slow_256_i` after SimplifyPowOfTwo - - fn slow_256_i(_1: u32) -> i32 { - debug a => _1; - let mut _0: i32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: i32; -+ let mut _7: i32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 256_i32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 8_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_i32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..2c8921d0d2add --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_256_u` after SimplifyPowOfTwo + +fn slow_256_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 8_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff deleted file mode 100644 index c9f5c5c5568e7..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_256_u.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_256_u` before SimplifyPowOfTwo -+ // MIR for `slow_256_u` after SimplifyPowOfTwo - - fn slow_256_u(_1: u32) -> u32 { - debug a => _1; - let mut _0: u32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: u32; -+ let mut _7: u32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 256_u32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 8_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as u32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..f525bcb8309ba --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_2_i` after SimplifyPowOfTwo + +fn slow_2_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; + let mut _7: i32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); + _7 = Shl(const 1_i32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff deleted file mode 100644 index 0ad56062a1f72..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_i.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_2_i` before SimplifyPowOfTwo -+ // MIR for `slow_2_i` after SimplifyPowOfTwo - - fn slow_2_i(_1: u32) -> i32 { - debug a => _1; - let mut _0: i32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: i32; -+ let mut _7: i32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 2_i32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 1_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_i32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..905b2797b3ff2 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_2_u` after SimplifyPowOfTwo + +fn slow_2_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 1_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff deleted file mode 100644 index f27d3a704d2c0..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_2_u.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_2_u` before SimplifyPowOfTwo -+ // MIR for `slow_2_u` after SimplifyPowOfTwo - - fn slow_2_u(_1: u32) -> u32 { - debug a => _1; - let mut _0: u32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: u32; -+ let mut _7: u32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 2_u32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 1_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as u32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..388d52e3abfc9 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_4_i` after SimplifyPowOfTwo + +fn slow_4_i(_1: u32) -> i32 { + debug a => _1; + let mut _0: i32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: i32; + let mut _7: i32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as i32 (IntToInt); + _7 = Shl(const 1_i32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff deleted file mode 100644 index dc0c72d9c4aae..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_i.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_4_i` before SimplifyPowOfTwo -+ // MIR for `slow_4_i` after SimplifyPowOfTwo - - fn slow_4_i(_1: u32) -> i32 { - debug a => _1; - let mut _0: i32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: i32; -+ let mut _7: i32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 4_i32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 2_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as i32 (IntToInt); -+ _7 = Shl(const 1_i32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_2); - return; - } - } - diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.after.mir b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.after.mir new file mode 100644 index 0000000000000..a4536affbc5c4 --- /dev/null +++ b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.after.mir @@ -0,0 +1,29 @@ +// MIR for `slow_4_u` after SimplifyPowOfTwo + +fn slow_4_u(_1: u32) -> u32 { + debug a => _1; + let mut _0: u32; + let mut _2: u32; + let mut _3: (u32, bool); + let mut _4: bool; + let mut _5: bool; + let mut _6: u32; + let mut _7: u32; + + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedMul(move _2, const 2_u32); + _4 = Lt((_3.0: u32), const 32_u32); + _5 = BitOr((_3.1: bool), _4); + _6 = _5 as u32 (IntToInt); + _7 = Shl(const 1_u32, (_3.0: u32)); + _0 = MulUnchecked(_7, _6); + assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff b/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff deleted file mode 100644 index 39bd3ea438600..0000000000000 --- a/tests/mir-opt/simplify_pow_of_two_overflow_checks.slow_4_u.SimplifyPowOfTwo.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `slow_4_u` before SimplifyPowOfTwo -+ // MIR for `slow_4_u` after SimplifyPowOfTwo - - fn slow_4_u(_1: u32) -> u32 { - debug a => _1; - let mut _0: u32; - let mut _2: u32; -+ let mut _3: (u32, bool); -+ let mut _4: bool; -+ let mut _5: bool; -+ let mut _6: u32; -+ let mut _7: u32; - - bb0: { - StorageLive(_2); - _2 = _1; -- _0 = core::num::::pow(const 4_u32, move _2) -> [return: bb1, unwind unreachable]; -+ _3 = CheckedMul(move _2, const 2_u32); -+ _4 = Lt((_3.0: u32), const 32_u32); -+ _5 = BitOr((_3.1: bool), _4); -+ _6 = _5 as u32 (IntToInt); -+ _7 = Shl(const 1_u32, (_3.0: u32)); -+ _0 = MulUnchecked(_7, _6); -+ assert(_5, "attempt to compute `{} * {}`, which would overflow", const 1_u32, (_3.0: u32)) -> [success: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_2); - return; - } - } -