Skip to content

add a fallback for more f16 intrinsics #159175

Merged
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
folkertdev:f16-ceil-floor-fallback
Jul 18, 2026
Merged

add a fallback for more f16 intrinsics #159175
rust-bors[bot] merged 2 commits into
rust-lang:mainfrom
folkertdev:f16-ceil-floor-fallback

Conversation

@folkertdev

@folkertdev folkertdev commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

View all comments

tracking issue: #116909

Add several more fallbacks for f16 intrinsics, so that they will work on platforms without the corresponding libcalls.

related

@folkertdev folkertdev added the F-f16_and_f128 `#![feature(f16)]`, `#![feature(f128)]` label Jul 12, 2026
@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 12, 2026
Comment thread compiler/rustc_codegen_llvm/src/lib.rs
@folkertdev

Copy link
Copy Markdown
Contributor Author

r? tgross35

@rustbot

rustbot commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

tgross35 is currently at their maximum review capacity.
They may take a while to respond.

@folkertdev
folkertdev marked this pull request as ready for review July 12, 2026 12:10
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jul 12, 2026
@rustbot

rustbot commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

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

@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 12, 2026
@folkertdev
folkertdev force-pushed the f16-ceil-floor-fallback branch from f878252 to 3db7de3 Compare July 16, 2026 13:02
@rustbot

This comment has been minimized.

@folkertdev

Copy link
Copy Markdown
Contributor Author

I've added some more fallbacks based on what cg_gcc and cg_clif actually use. With these additions, the f16-specific logic in the backends can mostly be removed I think.

sym::fmaf16 | sym::fmuladdf16 => {
CValue::by_val(codegen_f16_f128::fma_f16(fx, args[0], args[1], args[2]), layout)
}
sym::fmaf32 | sym::fmaf64 | sym::fmuladdf32 | sym::fmuladdf64 => {
CValue::by_val(fx.bcx.ins().fma(args[0], args[1], args[2]), layout)
}
sym::copysignf16 => {
CValue::by_val(codegen_f16_f128::copysign_f16(fx, args[0], args[1]), layout)
}
sym::copysignf128 => {
CValue::by_val(codegen_f16_f128::copysign_f128(fx, args[0], args[1]), layout)
}

let builtin_name = match name {
sym::ceilf16 => "__builtin_ceilf",
sym::copysignf16 => "__builtin_copysignf",
sym::expf16 => "expf",
sym::exp2f16 => "exp2f",
sym::fabs => "fabsf",
sym::floorf16 => "__builtin_floorf",
sym::fmaf16 => "fmaf",
sym::logf16 => "logf",
sym::log2f16 => "log2f",
sym::log10f16 => "log10f",
sym::powf16 => "__builtin_powf",
sym::roundf16 => "__builtin_roundf",
sym::round_ties_even_f16 => "__builtin_rintf",
sym::sqrtf16 => "__builtin_sqrtf",
sym::truncf16 => "__builtin_truncf",
_ => unreachable!(),
};

@rust-log-analyzer

This comment has been minimized.

@folkertdev
folkertdev force-pushed the f16-ceil-floor-fallback branch from 3db7de3 to c54fad0 Compare July 16, 2026 13:31
@folkertdev

Copy link
Copy Markdown
Contributor Author

I split out #159386, that one is a bit more subtle and I'm not sure what we want to do with those fmuladd intrinsics anyway.

@folkertdev
folkertdev force-pushed the f16-ceil-floor-fallback branch from c54fad0 to 37bfe32 Compare July 16, 2026 14:17
pub const fn copysignf32(x: f32, y: f32) -> f32;
pub const fn copysignf32(x: f32, y: f32) -> f32 {
f32::from_bits((x.to_bits() & !f32::SIGN_MASK) | (y.to_bits() & f32::SIGN_MASK))
}

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.

@RalfJung should I remove the custom const-eval implementation (and add miri::intrinsic_fallback_is_spec) when adding a const fallback? const-eval already duplicates minimumf*, and I think it makes sense to split out sym::fabs into a variant for each float too (all backends need to retrieve the width anyway, if you look at its usage).

@RalfJung RalfJung Jul 17, 2026

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.

fabs was merged a few months ago by @N1ark and I think she planned to merge the others as well. Just from the perspective of not having to duplicate the signatures and doc comments four times in this file, it'd be nice to merge more intrinsics... but either way please coordinate with her. I am very much not a fan of how the float intrinsics are turning this file into a mess where every change has to be done 4 times, so I think merging the different type variants is quite important.

Merging makes the fallback bodies more tricky of course. For these bitwise operations maybe a simple trait is enough to implement them generically?

Minimum has non-determinism and other complications, so that's not duplicated in const-eval, it's a genuinely different implementation. For these here... not sure, they seem sufficiently primitive to me that I think it's worth keeping the existing const-eval implementations.

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.

yes sorry i started doing it in #153934 and never got around to finishing it 🫠 ill pick it back up next week, @folkertdev once im done maybe rebasing this PR on that will make your life easier?

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.

Not really, combining the intrinsics means it's impossible to add fallbacks for just f16 (by deferring to f32). Adding those fallbacks removes nasty logic from the backends, and if the price is a to copy-paste a comment, that seems acceptable to me? Especially for simple intrinsics without complex safety/soundness requirements.

For abs and copysign we can use some trait machinery to provide a fallback for all four float types, but for functions like powf or sqrt that won't work.

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.

I have edited the various minimum intrinsics' docs quite a bit, so those certainly do not qualify as "simple". So I feel very strongly that we should deduplicate these comments -- but we can do that without merging the functions, by writings the docs once on the f32 version and making all the others a link.

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.

Yeah, fair. So then I think next steps are

  • combine the docs of some of the trickier functions
  • write a generic fallback for e.g. abs and copysign where we can reasonably provide a fallback for all 4 float types.
  • simplify the backends because they won't have to handle many libcall cases any more (I made a start with that in use core fallbacks for more f16/f128 operations rustc_codegen_gcc#910), with this PR we can do more, and cranelift can also remove some logic. It's probably best to do this in their respective repos for improved CI coverage.

@N1ark are you interested in any of that? I'll be doing some of the cranelift stuff to remove another .patch there but otherwise I'm happy to leave it to you.

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.

To add a bit of context -- the reason why merging the intrinsics is nice is that every single tool that consumes MIR (such as the verification tool @N1ark is working on) needs to deal with all those intrinsics, and they can typically deal with them uniformly across all types, so merging them avoids a bunch of code duplication.

Now, when in doubt we'll prioritize in-tree MIR consumers over out-of-tree MIR consumers. But it is a shame that we need to make a choice either way at all. So I wonder if we can somehow have our cake and eat it too. Is the problem with sqrt and pow and the others that they have a fallback for some types but not for others? Or could we have a fallback for them always, and what's annoying is just dispatching on the type? The latter could be solved...

@tgross35 tgross35 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.

One request then r=me

View changes since this review

#[rustc_nounwind]
pub const fn fmaf16(a: f16, b: f16, c: f16) -> f16;
pub const fn fmaf16(a: f16, b: f16, c: f16) -> f16 {
fmaf64(a as f64, b as f64, c as f64) as f16

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.

Could you add a comment that f32 isn't enough precision so we need f64? The difference isn't obvious if you don't know the context.

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.

Have you verified that f64 gives enough precision? I am not aware of a theorem for this case.

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.

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.

Hm, I can't really follow but good to know they looked into it. :D

This might be something one can just exhaustively test though?

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.

This might be something one can just exhaustively test though?

I did a quick estimate by changing https://github.com/rust-lang/compiler-builtins/blob/5af7a65c0342d3f5ac1d250c7902aaabbfc2bd49/libm/src/math/fmaf16.rs to:

extern crate std;
(x as f64).mul_add(y as f64, z as f64) as f16

And running LIBM_EXTENSIVE_TESTS=fmaf16 LIBM_EXTENSIVE_ITERATIONS=max cargo test --features build-mpfr --test z_extensive --profile release-checked --no-default-features --features unstable-float. On my 11 core laptop it estimates half a year to complete :D. Maybe on something like a threadripper that's more feasible, or against hardware fma if available.

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.

Hm fair, 48 bits is too big. Oh well.

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.

Doesn't llvm/llvm-project#131531 say that f64 is not enough?

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.

That is for bf16 (bfloat in LLVM)

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.

Ah I'm mixing up the various 16-bit floats....

@folkertdev
folkertdev force-pushed the f16-ceil-floor-fallback branch from 37bfe32 to 91ecf62 Compare July 17, 2026 18:11
@rust-bors

This comment has been minimized.

- `floorf16`
- `ceilf16`
- `truncf16,`
- `round_ties_even_f16`
- `roundf16`

- `powif16`
- `sqrtf16`

- `fmaf16`
@folkertdev
folkertdev force-pushed the f16-ceil-floor-fallback branch from 91ecf62 to da925bb Compare July 17, 2026 20:33
@rustbot

rustbot commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@folkertdev

Copy link
Copy Markdown
Contributor Author

@bors r=tgross35

@rust-bors

rust-bors Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

📌 Commit da925bb has been approved by tgross35

It is now in the queue for this repository.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 17, 2026
rust-bors Bot pushed a commit that referenced this pull request Jul 18, 2026
Rollup of 5 pull requests

Successful merges:

 - #159164 ([cg_ssa] Eliminate the `is_backend_{immediate,scalar_pair,ref}` methods)
 - #159175 (add a fallback for more `f16` intrinsics )
 - #158586 (update 'allocation' docs with memory atomicity requirement)
 - #159390 (rustc: Avoid passing jobserver proxy around the compiler)
 - #159468 (Android platform support: add links to make it easier to figure out the supported API levels)
@rust-bors
rust-bors Bot merged commit e045e1f into rust-lang:main Jul 18, 2026
13 checks passed
@rustbot rustbot added this to the 1.99.0 milestone Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. F-f16_and_f128 `#![feature(f16)]`, `#![feature(f128)]` S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. 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.

7 participants