Skip to content

Commit 23601d2

Browse files
folkertdevsayantn
authored andcommitted
fix logic, add test
1 parent 16220b2 commit 23601d2

File tree

3 files changed

+25
-11
lines changed

3 files changed

+25
-11
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -313,21 +313,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
313313
let rhs = self.read_scalar(&args[1])?;
314314
let rhs_bits = rhs.to_bits(layout_val.size)?; // sign is ignored here
315315

316-
let layout_raw_shift = self.layout_of(self.tcx.types.u32)?;
317316
let raw_shift = self.read_scalar(&args[2])?;
318-
let raw_shift_bits = raw_shift.to_bits(layout_raw_shift.size)?;
317+
let raw_shift_bits = raw_shift.to_u32()?;
319318

320-
let width_bits = u128::from(layout_val.size.bits());
319+
// The funnel shifts modulo by T::BITS to circumvent panics/UB.
320+
let width_bits = u32::try_from(layout_val.size.bits()).unwrap();
321321
let shift_bits = raw_shift_bits % width_bits;
322-
let inv_shift_bits = (width_bits - shift_bits) % width_bits;
323-
let result_bits = if shift_bits == 0 {
324-
if intrinsic_name == sym::funnel_shl { lhs_bits } else { rhs_bits }
322+
let inv_shift_bits = (width_bits - shift_bits);
323+
let result_bits = if intrinsic_name == sym::funnel_shl {
324+
lhs_bits.unbounded_shl(shift_bits) | rhs_bits.unbounded_shr(inv_shift_bits)
325325
} else {
326-
if intrinsic_name == sym::rotate_left {
327-
(lhs_bits << shift_bits) | (rhs_bits >> inv_shift_bits)
328-
} else {
329-
(rhs_bits >> shift_bits) | (lhs_bits << inv_shift_bits)
330-
}
326+
rhs_bits.unbounded_shr(shift_bits) | lhs_bits.unbounded_shl(inv_shift_bits)
331327
};
332328
let truncated_bits = layout_val.size.truncate(result_bits);
333329
let result = Scalar::from_uint(truncated_bits, layout_val.size);

library/coretests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#![feature(fmt_internals)]
5151
#![feature(formatting_options)]
5252
#![feature(freeze)]
53+
#![feature(funnel_shifts)]
5354
#![feature(future_join)]
5455
#![feature(generic_assert_internals)]
5556
#![feature(hasher_prefixfree_extras)]

library/coretests/tests/num/uint_macros.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,23 @@ macro_rules! uint_module {
104104
assert_eq_const_safe!($T: C.rotate_left(128), C);
105105
}
106106

107+
fn test_funnel_shift() {
108+
// Shifting by 0 should have no effect
109+
assert_eq_const_safe!($T: <$T>::funnel_shl(A, B, 0), A);
110+
assert_eq_const_safe!($T: <$T>::funnel_shr(A, B, 0), B);
111+
112+
// Shifting by a multiple of `T::BITS` should also have no effect
113+
assert_eq_const_safe!($T: <$T>::funnel_shl(A, B, $T::BITS), A);
114+
assert_eq_const_safe!($T: <$T>::funnel_shr(A, B, $T::BITS), B);
115+
116+
assert_eq_const_safe!($T: <$T>::funnel_shl(_0, _1, 4), 0b1111);
117+
assert_eq_const_safe!($T: <$T>::funnel_shr(_0, _1, 4), _1 >> 4);
118+
119+
// The shift amount is taken modulo `T::BITS`.
120+
assert_eq_const_safe!($T: <$T>::funnel_shl(_0, _1, $T::BITS + 4), 0b1111);
121+
assert_eq_const_safe!($T: <$T>::funnel_shr(_0, _1, $T::BITS + 4), _1 >> 4);
122+
}
123+
107124
fn test_swap_bytes() {
108125
assert_eq_const_safe!($T: A.swap_bytes().swap_bytes(), A);
109126
assert_eq_const_safe!($T: B.swap_bytes().swap_bytes(), B);

0 commit comments

Comments
 (0)