Skip to content

Commit 0485d6a

Browse files
committed
De-LLVM the unchecked shifts [MCP#693]
This is just one part of the MCP, but it's the one that IMHO removes the most noise from the standard library code. Seems net simpler this way, since MIR already supported heterogeneous shifts anyway, and thus it's not more work for backends than before.
1 parent bd43b55 commit 0485d6a

File tree

5 files changed

+64
-31
lines changed

5 files changed

+64
-31
lines changed

core/src/intrinsics.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2224,18 +2224,20 @@ extern "rust-intrinsic" {
22242224
/// Safe wrappers for this intrinsic are available on the integer
22252225
/// primitives via the `checked_shl` method. For example,
22262226
/// [`u32::checked_shl`]
2227+
#[cfg(not(bootstrap))]
22272228
#[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
22282229
#[rustc_nounwind]
2229-
pub fn unchecked_shl<T: Copy>(x: T, y: T) -> T;
2230+
pub fn unchecked_shl<T: Copy, U: Copy>(x: T, y: U) -> T;
22302231
/// Performs an unchecked right shift, resulting in undefined behavior when
22312232
/// `y < 0` or `y >= N`, where N is the width of T in bits.
22322233
///
22332234
/// Safe wrappers for this intrinsic are available on the integer
22342235
/// primitives via the `checked_shr` method. For example,
22352236
/// [`u32::checked_shr`]
2237+
#[cfg(not(bootstrap))]
22362238
#[rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0")]
22372239
#[rustc_nounwind]
2238-
pub fn unchecked_shr<T: Copy>(x: T, y: T) -> T;
2240+
pub fn unchecked_shr<T: Copy, U: Copy>(x: T, y: U) -> T;
22392241

22402242
/// Returns the result of an unchecked addition, resulting in
22412243
/// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`.

core/src/num/int_macros.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,10 +1253,18 @@ macro_rules! int_impl {
12531253
#[inline(always)]
12541254
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
12551255
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
1256-
// SAFETY: the caller must uphold the safety contract for
1257-
// `unchecked_shl`.
1258-
// Any legal shift amount is losslessly representable in the self type.
1259-
unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1256+
#[cfg(bootstrap)]
1257+
{
1258+
// For bootstrapping, just use built-in primitive shift.
1259+
// panicking is a legal manifestation of UB
1260+
self << rhs
1261+
}
1262+
#[cfg(not(bootstrap))]
1263+
{
1264+
// SAFETY: the caller must uphold the safety contract for
1265+
// `unchecked_shl`.
1266+
unsafe { intrinsics::unchecked_shl(self, rhs) }
1267+
}
12601268
}
12611269

12621270
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
@@ -1336,10 +1344,18 @@ macro_rules! int_impl {
13361344
#[inline(always)]
13371345
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
13381346
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
1339-
// SAFETY: the caller must uphold the safety contract for
1340-
// `unchecked_shr`.
1341-
// Any legal shift amount is losslessly representable in the self type.
1342-
unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1347+
#[cfg(bootstrap)]
1348+
{
1349+
// For bootstrapping, just use built-in primitive shift.
1350+
// panicking is a legal manifestation of UB
1351+
self >> rhs
1352+
}
1353+
#[cfg(not(bootstrap))]
1354+
{
1355+
// SAFETY: the caller must uphold the safety contract for
1356+
// `unchecked_shr`.
1357+
unsafe { intrinsics::unchecked_shr(self, rhs) }
1358+
}
13431359
}
13441360

13451361
/// Checked absolute value. Computes `self.abs()`, returning `None` if

core/src/num/mod.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -286,17 +286,6 @@ macro_rules! widening_impl {
286286
};
287287
}
288288

289-
macro_rules! conv_rhs_for_unchecked_shift {
290-
($SelfT:ty, $x:expr) => {{
291-
// If the `as` cast will truncate, ensure we still tell the backend
292-
// that the pre-truncation value was also small.
293-
if <$SelfT>::BITS < 32 {
294-
intrinsics::assume($x <= (<$SelfT>::MAX as u32));
295-
}
296-
$x as $SelfT
297-
}};
298-
}
299-
300289
impl i8 {
301290
int_impl! {
302291
Self = i8,

core/src/num/uint_macros.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,10 +1313,18 @@ macro_rules! uint_impl {
13131313
#[inline(always)]
13141314
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
13151315
pub const unsafe fn unchecked_shl(self, rhs: u32) -> Self {
1316-
// SAFETY: the caller must uphold the safety contract for
1317-
// `unchecked_shl`.
1318-
// Any legal shift amount is losslessly representable in the self type.
1319-
unsafe { intrinsics::unchecked_shl(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1316+
#[cfg(bootstrap)]
1317+
{
1318+
// For bootstrapping, just use built-in primitive shift.
1319+
// panicking is a legal manifestation of UB
1320+
self << rhs
1321+
}
1322+
#[cfg(not(bootstrap))]
1323+
{
1324+
// SAFETY: the caller must uphold the safety contract for
1325+
// `unchecked_shl`.
1326+
unsafe { intrinsics::unchecked_shl(self, rhs) }
1327+
}
13201328
}
13211329

13221330
/// Checked shift right. Computes `self >> rhs`, returning `None`
@@ -1396,10 +1404,18 @@ macro_rules! uint_impl {
13961404
#[inline(always)]
13971405
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
13981406
pub const unsafe fn unchecked_shr(self, rhs: u32) -> Self {
1399-
// SAFETY: the caller must uphold the safety contract for
1400-
// `unchecked_shr`.
1401-
// Any legal shift amount is losslessly representable in the self type.
1402-
unsafe { intrinsics::unchecked_shr(self, conv_rhs_for_unchecked_shift!($SelfT, rhs)) }
1407+
#[cfg(bootstrap)]
1408+
{
1409+
// For bootstrapping, just use built-in primitive shift.
1410+
// panicking is a legal manifestation of UB
1411+
self >> rhs
1412+
}
1413+
#[cfg(not(bootstrap))]
1414+
{
1415+
// SAFETY: the caller must uphold the safety contract for
1416+
// `unchecked_shr`.
1417+
unsafe { intrinsics::unchecked_shr(self, rhs) }
1418+
}
14031419
}
14041420

14051421
/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if

core/src/ptr/mod.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,9 +1781,19 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
17811781
// FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
17821782
// 1, where the method versions of these operations are not inlined.
17831783
use intrinsics::{
1784-
assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_shl,
1785-
unchecked_shr, unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub,
1784+
assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_sub,
1785+
wrapping_add, wrapping_mul, wrapping_sub,
17861786
};
1787+
#[cfg(bootstrap)]
1788+
const unsafe fn unchecked_shl(value: usize, shift: usize) -> usize {
1789+
value << shift
1790+
}
1791+
#[cfg(bootstrap)]
1792+
const unsafe fn unchecked_shr(value: usize, shift: usize) -> usize {
1793+
value >> shift
1794+
}
1795+
#[cfg(not(bootstrap))]
1796+
use intrinsics::{unchecked_shl, unchecked_shr};
17871797

17881798
/// Calculate multiplicative modular inverse of `x` modulo `m`.
17891799
///

0 commit comments

Comments
 (0)