@@ -112,25 +112,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
112
112
113
113
// Shift ops can have an RHS with a different numeric type.
114
114
if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) {
115
- let size = left.layout.size.bits();
115
+ let l_bits = left.layout.size.bits();
116
116
// Compute the equivalent shift modulo `size` that is in the range `0..size`. (This is
117
117
// the one MIR operator that does *not* directly map to a single LLVM operation.)
118
118
let (shift_amount, overflow) = if right.layout.abi.is_signed() {
119
119
let shift_amount = r_signed();
120
- let overflow = shift_amount < 0 || shift_amount >= i128::from(size);
121
- // Deliberately wrapping `as` casts: shift_amount *can* be negative, but the result
122
- // of the `as` will be equal modulo `size` (since it is a power of two).
123
- let masked_amount = (shift_amount as u128) % u128::from(size);
124
- assert_eq!(overflow, shift_amount != i128::try_from(masked_amount).unwrap());
125
- (masked_amount, overflow)
120
+ let rem = shift_amount.rem_euclid(l_bits.into());
121
+ // `rem` is guaranteed positive, so the `unwrap` cannot fail
122
+ (u128::try_from(rem).unwrap(), rem != shift_amount)
126
123
} else {
127
124
let shift_amount = r_unsigned();
128
- let overflow = shift_amount >= u128::from(size);
129
- let masked_amount = shift_amount % u128::from(size);
130
- assert_eq!(overflow, shift_amount != masked_amount);
131
- (masked_amount, overflow)
125
+ let rem = shift_amount.rem_euclid(l_bits.into());
126
+ (rem, rem != shift_amount)
132
127
};
133
- let shift_amount = u32::try_from(shift_amount).unwrap(); // we masked so this will always fit
128
+ let shift_amount = u32::try_from(shift_amount).unwrap(); // we brought this in the range `0..size` so this will always fit
134
129
// Compute the shifted result.
135
130
let result = if left.layout.abi.is_signed() {
136
131
let l = l_signed();
0 commit comments