Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,66 @@ macro_rules! int_impl {
}
}

/// Exact shift left. Computes `self << rhs` as long as it can be reversed losslessly.
///
/// Returns `None` if any bits that would be shifted out differ from the resulting sign bit
/// or if `rhs` >=
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
/// Otherwise, returns `Some(self << rhs)`.
///
/// # Examples
///
/// ```
/// #![feature(exact_bitshifts)]
///
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(", stringify!($SelfT), "::BITS - 2), Some(1 << ", stringify!($SelfT), "::BITS - 2));")]
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(", stringify!($SelfT), "::BITS - 1), None);")]
#[doc = concat!("assert_eq!((-0x2", stringify!($SelfT), ").exact_shl(", stringify!($SelfT), "::BITS - 2), Some(-0x2 << ", stringify!($SelfT), "::BITS - 2));")]
#[doc = concat!("assert_eq!((-0x2", stringify!($SelfT), ").exact_shl(", stringify!($SelfT), "::BITS - 1), None);")]
/// ```
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
if rhs < self.leading_zeros() || rhs < self.leading_ones() {
// SAFETY: rhs is checked above
Some(unsafe { self.unchecked_shl(rhs) })
} else {
None
}
}

/// Unchecked exact shift left. Computes `self << rhs`, assuming the operation can be
/// losslessly reversed and `rhs` cannot be larger than
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Safety
///
/// This results in undefined behavior when `rhs >= self.leading_zeros() && rhs >=
/// self.leading_ones()` i.e. when
#[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
/// would return `None`.
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::unchecked_exact_shl cannot shift out non-zero bits"),
(
zeros: u32 = self.leading_zeros(),
ones: u32 = self.leading_ones(),
rhs: u32 = rhs,
) => rhs < zeros || rhs < ones,
);

// SAFETY: this is guaranteed to be safe by the caller
unsafe { self.unchecked_shl(rhs) }
Comment on lines +1462 to +1473
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of check_language_ub here seems wrong. The following code has language UB if rhs >= BITS, but the condition you are checking is stronger than that. check_language_ub should only be used if a violation of the precondition will always lead to language UB, and that is not the case here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Qelxiros are you interested in putting up a PR adding the intrinsics mentioned at #144342 (comment)? The comment here could be fixed at the same time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am interested, but I'm not sure exactly how to do it. Do I need to add implementations to all the rustc_codegen_* crates, or just llvm? How exactly are intrinsics added? It looks like I need a combination of LLVMBuildShl/LLVMBuildShr and LLVMSetNUW/LLVMSetNSW/LLVMSetExact (although LLVMSetExact currently only exists in C++ code). However, I'm not sure where that goes or how to associate it with the appropriate symbol.

Copy link
Contributor

@tgross35 tgross35 Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ralf got these already in #146878, thanks for the interest though

}

/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
/// larger than or equal to the number of bits in `self`.
///
Expand Down Expand Up @@ -1534,6 +1594,63 @@ macro_rules! int_impl {
}
}

/// Exact shift right. Computes `self >> rhs` as long as it can be reversed losslessly.
///
/// Returns `None` if any non-zero bits would be shifted out or if `rhs` >=
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
/// Otherwise, returns `Some(self >> rhs)`.
///
/// # Examples
///
/// ```
/// #![feature(exact_bitshifts)]
///
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(5), None);")]
/// ```
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
if rhs <= self.trailing_zeros() && rhs < <$SelfT>::BITS {
// SAFETY: rhs is checked above
Some(unsafe { self.unchecked_shr(rhs) })
} else {
None
}
}

/// Unchecked exact shift right. Computes `self >> rhs`, assuming the operation can be
/// losslessly reversed and `rhs` cannot be larger than
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Safety
///
/// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
#[doc = concat!(stringify!($SelfT), "::BITS`")]
/// i.e. when
#[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
/// would return `None`.
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::unchecked_exact_shr cannot shift out non-zero bits"),
(
zeros: u32 = self.trailing_zeros(),
bits: u32 = <$SelfT>::BITS,
rhs: u32 = rhs,
) => rhs <= zeros && rhs < bits,
);

// SAFETY: this is guaranteed to be safe by the caller
unsafe { self.unchecked_shr(rhs) }
}

/// Checked absolute value. Computes `self.abs()`, returning `None` if
/// `self == MIN`.
///
Expand Down
114 changes: 114 additions & 0 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1734,6 +1734,63 @@ macro_rules! uint_impl {
}
}

/// Exact shift left. Computes `self << rhs` as long as it can be reversed losslessly.
///
/// Returns `None` if any non-zero bits would be shifted out or if `rhs` >=
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
/// Otherwise, returns `Some(self << rhs)`.
///
/// # Examples
///
/// ```
/// #![feature(exact_bitshifts)]
///
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")]
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(129), None);")]
/// ```
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn exact_shl(self, rhs: u32) -> Option<$SelfT> {
if rhs <= self.leading_zeros() && rhs < <$SelfT>::BITS {
// SAFETY: rhs is checked above
Some(unsafe { self.unchecked_shl(rhs) })
} else {
None
}
}

/// Unchecked exact shift left. Computes `self << rhs`, assuming the operation can be
/// losslessly reversed `rhs` cannot be larger than
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Safety
///
/// This results in undefined behavior when `rhs > self.leading_zeros() || rhs >=
#[doc = concat!(stringify!($SelfT), "::BITS`")]
/// i.e. when
#[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")]
/// would return `None`.
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"),
(
zeros: u32 = self.leading_zeros(),
bits: u32 = <$SelfT>::BITS,
rhs: u32 = rhs,
) => rhs <= zeros && rhs < bits,
);

// SAFETY: this is guaranteed to be safe by the caller
unsafe { self.unchecked_shl(rhs) }
}

/// Checked shift right. Computes `self >> rhs`, returning `None`
/// if `rhs` is larger than or equal to the number of bits in `self`.
///
Expand Down Expand Up @@ -1849,6 +1906,63 @@ macro_rules! uint_impl {
}
}

/// Exact shift right. Computes `self >> rhs` as long as it can be reversed losslessly.
///
/// Returns `None` if any non-zero bits would be shifted out or if `rhs` >=
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
/// Otherwise, returns `Some(self >> rhs)`.
///
/// # Examples
///
/// ```
/// #![feature(exact_bitshifts)]
///
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")]
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(5), None);")]
/// ```
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn exact_shr(self, rhs: u32) -> Option<$SelfT> {
if rhs <= self.trailing_zeros() && rhs < <$SelfT>::BITS {
// SAFETY: rhs is checked above
Some(unsafe { self.unchecked_shr(rhs) })
} else {
None
}
}

/// Unchecked exact shift right. Computes `self >> rhs`, assuming the operation can be
/// losslessly reversed and `rhs` cannot be larger than
#[doc = concat!("`", stringify!($SelfT), "::BITS`.")]
///
/// # Safety
///
/// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >=
#[doc = concat!(stringify!($SelfT), "::BITS`")]
/// i.e. when
#[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")]
/// would return `None`.
#[unstable(feature = "exact_bitshifts", issue = "144336")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT {
assert_unsafe_precondition!(
check_language_ub,
concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"),
(
zeros: u32 = self.trailing_zeros(),
bits: u32 = <$SelfT>::BITS,
rhs: u32 = rhs,
) => rhs <= zeros && rhs < bits,
);

// SAFETY: this is guaranteed to be safe by the caller
unsafe { self.unchecked_shr(rhs) }
}

/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
/// overflow occurred.
///
Expand Down
Loading