Rollup merge of #126469 - RalfJung:mir-shifts, r=scottmcm
MIR Shl/Shr: the offset can be computed with rem_euclid r? ````@scottmcm````
This commit is contained in:
commit
f24509aa23
@ -112,25 +112,20 @@ fn binary_int_op(
|
|||||||
|
|
||||||
// Shift ops can have an RHS with a different numeric type.
|
// Shift ops can have an RHS with a different numeric type.
|
||||||
if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) {
|
if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) {
|
||||||
let size = left.layout.size.bits();
|
let l_bits = left.layout.size.bits();
|
||||||
// Compute the equivalent shift modulo `size` that is in the range `0..size`. (This is
|
// Compute the equivalent shift modulo `size` that is in the range `0..size`. (This is
|
||||||
// the one MIR operator that does *not* directly map to a single LLVM operation.)
|
// the one MIR operator that does *not* directly map to a single LLVM operation.)
|
||||||
let (shift_amount, overflow) = if right.layout.abi.is_signed() {
|
let (shift_amount, overflow) = if right.layout.abi.is_signed() {
|
||||||
let shift_amount = r_signed();
|
let shift_amount = r_signed();
|
||||||
let overflow = shift_amount < 0 || shift_amount >= i128::from(size);
|
let rem = shift_amount.rem_euclid(l_bits.into());
|
||||||
// Deliberately wrapping `as` casts: shift_amount *can* be negative, but the result
|
// `rem` is guaranteed positive, so the `unwrap` cannot fail
|
||||||
// of the `as` will be equal modulo `size` (since it is a power of two).
|
(u128::try_from(rem).unwrap(), rem != shift_amount)
|
||||||
let masked_amount = (shift_amount as u128) % u128::from(size);
|
|
||||||
assert_eq!(overflow, shift_amount != i128::try_from(masked_amount).unwrap());
|
|
||||||
(masked_amount, overflow)
|
|
||||||
} else {
|
} else {
|
||||||
let shift_amount = r_unsigned();
|
let shift_amount = r_unsigned();
|
||||||
let overflow = shift_amount >= u128::from(size);
|
let rem = shift_amount.rem_euclid(l_bits.into());
|
||||||
let masked_amount = shift_amount % u128::from(size);
|
(rem, rem != shift_amount)
|
||||||
assert_eq!(overflow, shift_amount != masked_amount);
|
|
||||||
(masked_amount, overflow)
|
|
||||||
};
|
};
|
||||||
let shift_amount = u32::try_from(shift_amount).unwrap(); // we masked so this will always fit
|
let shift_amount = u32::try_from(shift_amount).unwrap(); // we brought this in the range `0..size` so this will always fit
|
||||||
// Compute the shifted result.
|
// Compute the shifted result.
|
||||||
let result = if left.layout.abi.is_signed() {
|
let result = if left.layout.abi.is_signed() {
|
||||||
let l = l_signed();
|
let l = l_signed();
|
||||||
|
@ -1490,7 +1490,8 @@ pub enum BinOp {
|
|||||||
BitOr,
|
BitOr,
|
||||||
/// The `<<` operator (shift left)
|
/// The `<<` operator (shift left)
|
||||||
///
|
///
|
||||||
/// The offset is (uniquely) determined as follows:
|
/// The offset is given by `RHS.rem_euclid(LHS::BITS)`.
|
||||||
|
/// In other words, it is (uniquely) determined as follows:
|
||||||
/// - it is "equal modulo LHS::BITS" to the RHS
|
/// - it is "equal modulo LHS::BITS" to the RHS
|
||||||
/// - it is in the range `0..LHS::BITS`
|
/// - it is in the range `0..LHS::BITS`
|
||||||
Shl,
|
Shl,
|
||||||
@ -1498,7 +1499,8 @@ pub enum BinOp {
|
|||||||
ShlUnchecked,
|
ShlUnchecked,
|
||||||
/// The `>>` operator (shift right)
|
/// The `>>` operator (shift right)
|
||||||
///
|
///
|
||||||
/// The offset is (uniquely) determined as follows:
|
/// The offset is given by `RHS.rem_euclid(LHS::BITS)`.
|
||||||
|
/// In other words, it is (uniquely) determined as follows:
|
||||||
/// - it is "equal modulo LHS::BITS" to the RHS
|
/// - it is "equal modulo LHS::BITS" to the RHS
|
||||||
/// - it is in the range `0..LHS::BITS`
|
/// - it is in the range `0..LHS::BITS`
|
||||||
///
|
///
|
||||||
|
Loading…
Reference in New Issue
Block a user