Skip to content

Add fallback for intrinsics::fabs#159605

Open
N1ark wants to merge 1 commit into
rust-lang:mainfrom
N1ark:fabs-fallback
Open

Add fallback for intrinsics::fabs#159605
N1ark wants to merge 1 commit into
rust-lang:mainfrom
N1ark:fabs-fallback

Conversation

@N1ark

@N1ark N1ark commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Add a fallback for the fabs intrinsic. Because it uses const traits and const ops it required adding rustc_const_unstable -- i'm not certain it's right but it seems to make sense. I also added #[miri::intrinsic_fallback_is_spec], though im not sure if I need to modify the const eval code to remove fabs handling or to remove it from any of the backends

r? folkertdev

@rustbot

rustbot commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Any special-casing of Miri in the standard library requires review.

cc @rust-lang/miri

Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter
gets adapted for the changes, if necessary.

cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr

⚠️ #[miri::intrinsic_fallback_is_spec] must only be used if the function actively checks for all UB cases,
and explores the possible non-determinism of the intrinsic.

cc @rust-lang/miri

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 20, 2026

@folkertdev folkertdev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm still skeptical that this is an improvement over the naive "just duplicate it 4 times" approach.

View changes since this review

Comment thread library/core/src/intrinsics/bounds.rs Outdated
Comment on lines +3634 to +3643
#[miri::intrinsic_fallback_is_spec]
pub const fn fabs<T: bounds::FloatPrimitive>(x: T) -> T {
// SAFETY: the implementation of `FloatPrimitive` guarantees that `T` is a
// floating-point type, and that `T::Unsigned` is the corresponding unsigned
// integer type with the same size as `T`. Both are valid for all bit patterns.
let bits: T::Unsigned = unsafe { transmute_unchecked(x) };
let abs = bits & !T::SIGN_MASK;
// SAFETY: same as above
unsafe { transmute_unchecked(abs) }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@RalfJung does this spark joy? I'd much rather have the one-liner duplicated 4 times than the (trivial, but still) unsafety and const trait stuff that is required.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The question is whether it sparks more or less joy than copy-paste. The status quo is definitely not joyful. ;)

But yeah I agree needing unsafe is pretty bad.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

does it spark joy now ? ^-^

pub const fn fabs<T: const bounds::FloatPrimitive>(x: T) -> T {
    T::from_bits(x.to_bits() & !T::SIGN_MASK)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes that seems exactly as readable as the per-type version, just less duplicated :)

Comment on lines +57 to +67
#[rustc_const_unstable(feature = "core_intrinsics", issue = "none")]
const unsafe impl FloatPrimitive for f16 {
type Unsigned = u16;
const SIGN_MASK: Self::Unsigned = f16::SIGN_MASK;
fn to_bits(self) -> Self::Unsigned {
f16::to_bits(self)
}
fn from_bits(bits: Self::Unsigned) -> Self {
f16::from_bits(bits)
}
}

@N1ark N1ark Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this can be macro'd if you'd rather i have no strong opinions on that

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's hold off on using macros, this seems manageable now and a macro won't work for fallbacks that need a per-type implementation (e.g. sin or fma)

Comment thread library/core/src/intrinsics/bounds.rs Outdated

@folkertdev folkertdev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

So how will this work for the heterogeneous fallbacks (like fma)? Just add more methods to the trait?

View changes since this review

Comment on lines +57 to +67
#[rustc_const_unstable(feature = "core_intrinsics", issue = "none")]
const unsafe impl FloatPrimitive for f16 {
type Unsigned = u16;
const SIGN_MASK: Self::Unsigned = f16::SIGN_MASK;
fn to_bits(self) -> Self::Unsigned {
f16::to_bits(self)
}
fn from_bits(bits: Self::Unsigned) -> Self {
f16::from_bits(bits)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's hold off on using macros, this seems manageable now and a macro won't work for fallbacks that need a per-type implementation (e.g. sin or fma)

Comment thread library/core/src/intrinsics/bounds.rs Outdated
@RalfJung

Copy link
Copy Markdown
Member

So how will this work for the heterogeneous fallbacks (like fma)? Just add more methods to the trait?

Either that, more a per-operation trait defined locally by a macro.

@N1ark

N1ark commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author
edit: Ralf beat me to it

So how will this work for the heterogeneous fallbacks (like fma)? Just add more methods to the trait?

for those i think what's easiest (which @RalfJung ) commented on Zulip. i dont think i would format it like that, but something along the lines of

intrinsic_dispatch_on_type! {
    pub fn fma<T: bounds::FloatPrimitive>(x: T, y: T, z: T) -> T;
    f16 => {
      fma(x as f64, y as f64, z as f64) as f16
    }
    f32 => { 
      libm::fmaf(x, y, z)
    }
    // etc
}

which then would create a trait for that specific intrinsic that does the thing, adds it to the trait bound and what not? or add it to the FloatPrimitive trait directly, i dont feel strongly abt this

yes it duplicates the impl but it still allows a pretty good cleanup in the rest of the compiler which personally i think is worth the code here (also avoids duplicating comments which can be quite long and technical:) )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants