Skip to content

Commit

Permalink
Updated statically_known and pow
Browse files Browse the repository at this point in the history
Co-Authored-By: Catherine Flores <[email protected]>
  • Loading branch information
NCGThompson and Centri3 committed Jan 11, 2024
1 parent 49d9676 commit 3c0b2d3
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 33 deletions.
25 changes: 20 additions & 5 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2525,15 +2525,30 @@ extern "rust-intrinsic" {
/// or `false`, and the caller has to ensure sound behavior for both cases.
/// In other words, the following code has *Undefined Behavior*:
///
/// ```rust
/// if !is_val_statically_known(0) { unreachable_unchecked(); }
/// ```
/// #![feature(is_val_statically_known)]
/// #![feature(core_intrinsics)]
/// # #![allow(internal_features)]
/// use std::hint::unreachable_unchecked;
/// use std::intrinsics::is_val_statically_known;
///
/// unsafe {
/// if !is_val_statically_known(0) { unreachable_unchecked(); }
/// }
/// ```
///
/// This also means that the following code's behavior is unspecified; it
/// may panic, or it may not:
///
/// ```rust,no_run
/// assert_eq!(is_val_statically_known(0), black_box(is_val_statically_known(0)))
/// ```no_run
/// #![feature(is_val_statically_known)]
/// #![feature(core_intrinsics)]
/// # #![allow(internal_features)]
/// use std::intrinsics::is_val_statically_known;
///
/// unsafe {
/// assert_eq!(is_val_statically_known(0), is_val_statically_known(0));
/// }
/// ```
///
/// Unsafe code may not rely on `is_val_statically_known` returning any
Expand All @@ -2552,7 +2567,7 @@ extern "rust-intrinsic" {

// FIXME: Seems using `unstable` here completely ignores `rustc_allow_const_fn_unstable`
// and thus compiling stage0 core doesn't work.
#[rustc_const_stable(feature = "is_val_statically_known", since = "never")]
#[rustc_const_stable(feature = "is_val_statically_known", since = "0.0.0")]
#[cfg(bootstrap)]
pub const unsafe fn is_val_statically_known<T>(t: T) -> bool {
mem::forget(t);
Expand Down
26 changes: 13 additions & 13 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2088,28 +2088,28 @@ macro_rules! int_impl {
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
#[track_caller] // Hides the hackish overflow check for powers of two.
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
pub const fn pow(self, mut exp: u32) -> Self {
// SAFETY: This path has the same behavior as the other.
if unsafe { intrinsics::is_val_statically_known(self) }
&& self > 0
&& (self & (self - 1) == 0)
{
let power_used = match self.checked_ilog2() {
Some(v) => v,
// SAFETY: We just checked this is a power of two. and above zero.
None => unsafe { core::hint::unreachable_unchecked() },
// SAFETY: We just checked this is a power of two. and above zero.
let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
let num_shl = power_used.saturating_mul(exp);
let res = match (1 as Self).checked_shl(num_shl) {
Some(x) => x,
None => 0
};
// So it panics. Have to use `overflowing_mul` to efficiently set the
// result to 0 if not.
#[cfg(debug_assertions)]
{
_ = power_used * exp;

#[allow(arithmetic_overflow)]
if res <= 0 {
// So it panics.
_ = Self::MAX * Self::MAX;
}
let (num_shl, overflowed) = power_used.overflowing_mul(exp);
let fine = !overflowed
& (num_shl < (mem::size_of::<Self>() * 8) as u32);
(1 << num_shl) * fine as Self
res
} else {
if exp == 0 {
return 1;
Expand Down
24 changes: 9 additions & 15 deletions library/core/src/num/uint_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1973,6 +1973,7 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline]
#[rustc_inherit_overflow_checks]
#[track_caller] // Hides the hackish overflow check for powers of two.
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
pub const fn pow(self, mut exp: u32) -> Self {
// LLVM now knows that `self` is a constant value, but not a
Expand All @@ -1990,22 +1991,15 @@ macro_rules! uint_impl {
if unsafe { intrinsics::is_val_statically_known(self) }
&& self.is_power_of_two()
{
let power_used = match self.checked_ilog2() {
Some(v) => v,
// SAFETY: We just checked this is a power of two. `0` is not a
// power of two.
None => unsafe { core::hint::unreachable_unchecked() },
};
// So it panics. Have to use `overflowing_mul` to efficiently set the
// result to 0 if not.
#[cfg(debug_assertions)]
{
_ = power_used * exp;
// SAFETY: We just checked this is a power of two. and above zero.
let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
let num_shl = power_used.saturating_mul(exp);

#[allow(arithmetic_overflow)]
match (1 as Self).checked_shl(num_shl) {
Some(x) => x,
None => Self::MAX * Self::MAX * 0
}
let (num_shl, overflowed) = power_used.overflowing_mul(exp);
let fine = !overflowed
& (num_shl < (mem::size_of::<Self>() * 8) as u32);
(1 << num_shl) * fine as Self
} else {
if exp == 0 {
return 1;
Expand Down

0 comments on commit 3c0b2d3

Please sign in to comment.