Repository navigation
Tracking Issue for f16 and f128 float types #116909
Description
Activity
- addedC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFC
on Oct 18, 2023 traviscross commented
on Oct 18, 2023 on Oct 18, 2023 · Hidden as resolvedAuthorshow commentMore actionstraviscross commented
on Oct 19, 2023 on Oct 19, 2023 · Hidden as resolvedAuthorshow commentMore actions- addedB-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.Blocker: Approved by a merged RFC but not yet implemented.
on Oct 19, 2023 - addedI-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}Issue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
on Oct 27, 2023 132 remaining items
- added a commit that references this issue
on Jan 22, 2026 - added a commit that references this issue
on Jan 23, 2026 We will provide a soft float implementation for all targets, and use hardware support where possible.
This is bad form. The underyling target should decide if f16 and f128 are support rather than the language. This is how Fortran, C and many other languages are done.
Reacted by JubileeNote I think the gate for f16 and f128 should be independent.
That is have#![feature(f16)]and#![feature(f128)].They are already, and with the exact naming that you propose. ;)
We will provide a soft float implementation for all targets, and use hardware support where possible.
This is bad form. The underyling target should decide if f16 and f128 are support rather than the language.
It seems that the consensus is to yield such optimisations to the programmer. But this statement also assumes that performance is more important than portability, which is not always the case for all software. Also, even just having the types for storage is useful.
This is how Fortran, C and many other languages are done.
Almost. It is not uncommon for compilers to provide soft floats on some embedded targets. But GCC and Clang, at least, do not seem do so on every target.
We will provide a soft float implementation for all targets, and use hardware support where possible.
This is bad form. The underyling target should decide if f16 and f128 are support rather than the language. This is how Fortran, C and many other languages are done.
I strongly disagree, any pure-computation API that Rust has should work anywhere, that allows code that needs those types to work anywhere even if a bit slowly instead of only wherever the target deigns to provide those types (not that many targets and IIRC some of them need very recent CPUs).
That said, tracking issues aren't the place to have a long discussion, if you want to discuss it more, feel free to create a topic on https://internals.rust-lang.org/ and link it here.
I assume you are coming here from the discussion on a GCC fallback?
We eventually want these types available on all platforms because that shouldn't be the average programmer's concern. Of course the best case scenario is that the platform's ABI tells us exactly what to do, but it's not a good user experience if an otherwise functional library doesn't build on some platform just because they stopped updating their ABI a decade ago. Maybe the library could do something better on platforms that don't support f16/f128, but we'd like that to be a performance concern rather than a "does it work" concern. And then if they do eventually update the ABI, rust can adjust things as needed to match.
I realize this is differs from the usual GCC path which e.g. doesn't support __int128 on i386 since it (despite my efforts) isn't specified there. But I think this is the perfect example where it would be nice if the compiler smoothed things over, because it is inconvenient and measurably bad for performance to roll your own __int128 to implement soft _Float128 ops (which is specified in i386. I'm aware
_BitIntexists now.). And GCC also has some extensions.some targets don't have f16 (even in LLVM).
AFAIK LLVM's
halftype now works on all targets since LLVM22, using i16 ABI and libcalls as a fallback. f128 still has some work to be done. For reference, we keep track of this at.rust/compiler/rustc_codegen_llvm/src/llvm_util.rs
Lines 374 to 445 in d222ddc
cfg.has_reliable_f16 = match (target_arch, target_os) { // LLVM crash without neon <https://github.com/llvm/llvm-project/issues/129394> (fixed in LLVM 20.1.1) (Arch::AArch64, _) if !cfg.target_features.iter().any(|f| f.as_str() == "neon") && version < (20, 1, 1) => { false } // Unsupported <https://github.com/llvm/llvm-project/issues/94434> (fixed in llvm22) (Arch::Arm64EC, _) if major < 22 => false, // Selection failure <https://github.com/llvm/llvm-project/issues/50374> (fixed in llvm21) (Arch::S390x, _) if major < 21 => false, // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false, // Infinite recursion <https://github.com/llvm/llvm-project/issues/97981> (Arch::CSky, _) if major < 22 => false, // (fixed in llvm22) (Arch::Hexagon, _) if major < 21 => false, // (fixed in llvm21) (Arch::LoongArch32 | Arch::LoongArch64, _) if major < 21 => false, // (fixed in llvm21) (Arch::PowerPC | Arch::PowerPC64, _) if major < 22 => false, // (fixed in llvm22) (Arch::Sparc | Arch::Sparc64, _) if major < 22 => false, // (fixed in llvm22) (Arch::Wasm32 | Arch::Wasm64, _) if major < 22 => false, // (fixed in llvm22) // `f16` support only requires that symbols converting to and from `f32` are available. We // provide these in `compiler-builtins`, so `f16` should be available on all platforms that // do not have other ABI issues or LLVM crashes. _ => true, }; cfg.has_reliable_f128 = match (target_arch, target_os) { // Unsupported https://github.com/llvm/llvm-project/issues/121122 (Arch::AmdGpu, _) => false, // Unsupported <https://github.com/llvm/llvm-project/issues/94434> (Arch::Arm64EC, _) => false, // Selection bug <https://github.com/llvm/llvm-project/issues/96432> (fixed in LLVM 20.1.0) (Arch::Mips64 | Arch::Mips64r6, _) if version < (20, 1, 0) => false, // Selection bug <https://github.com/llvm/llvm-project/issues/95471>. This issue is closed // but basic math still does not work. (Arch::Nvptx64, _) => false, // ABI bugs <https://github.com/rust-lang/rust/issues/125109> et al. (full // list at <https://github.com/rust-lang/rust/issues/116909>) (Arch::PowerPC | Arch::PowerPC64, _) => false, // ABI unsupported <https://github.com/llvm/llvm-project/issues/41838> (Arch::Sparc, _) => false, // Stack alignment bug <https://github.com/llvm/llvm-project/issues/77401>. NB: tests may // not fail if our compiler-builtins is linked. (fixed in llvm21) (Arch::X86, _) if major < 21 => false, // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false, // There are no known problems on other platforms, so the only requirement is that symbols // are available. `compiler-builtins` provides all symbols required for core `f128` // support, so this should work for everything else. _ => true, }; // Assume that working `f16` means working `f16` math for most platforms, since // operations just go through `f32`. cfg.has_reliable_f16_math = cfg.has_reliable_f16; cfg.has_reliable_f128_math = match (target_arch, target_os) { // LLVM lowers `fp128` math to `long double` symbols even on platforms where // `long double` is not IEEE binary128. See // <https://github.com/llvm/llvm-project/issues/44744>. // // This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits // (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86` // (ld is 80-bit extended precision). // // musl does not implement the symbols required for f128 math at all. _ if *target_env == Env::Musl => false, (Arch::X86_64, _) => false, (_, Os::Linux) if target_pointer_width == 64 => true, _ => false, } && cfg.has_reliable_f128; Regarding where to discuss: the policy is absolutely not for the purpose of ignoring feedback. Things just get cluttered given the lack of threads on GH issues. Discussing on separate issues or at https://rust-lang.zulipchat.com is preferred for that reason, but I'd rather address this here than not at all.
Reacted by Tom and SurajOpened #151557 to continue this thread.
Is there an email list instead? Email has a better interface than anything else?
There is not, Zulip more or less took over the threaded discussion / public archive role.
Reacted by Jacob LifshayWhile it seems that this discussion has been successfully channeled, I am locking this to discourage further reuse of this issue out-of-bounds of strictly "tracking" concerns, per rust-lang/compiler-team#739
If you are not a team member and so cannot speak "over" the lock then you can create a new issue and ping back this one by linking to it. If it constitutes what should be an "unresolved question", "future step", or what-have-you, then a team member can edit that new issue into the tracking issue's initial post. Let all new comments from this point be of a similar procedural or "meta-level" nature.
- locked and limited conversation to collaborators
on Jan 25, 2026 The maximum intrinsic is missing for wasm targets: #158673
View all comments
This is a tracking issue for the RFC 3453 (rust-lang/rfcs#3453).
The feature gate for the issue is
#![feature(f16)]and#![feature(f128)].From the RFC:
About tracking issues
Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
Steps
Unresolved questions
*onf16if LLVM would get the ABI wrong.extern "C"should do, so maybe we should just reject code that tries to pass such values acrossextern "C"?Implementation history and Future Steps
f16andf128#121728f16andf128step 2: intrinsics #121841 (comment)f16andf128step 3: compiler support & feature gate #121926rustcmore or less expects for primitives Add basic trait impls forf16andf128#123085f16andf128to rustdoc'sPrimitiveType#123581Some parts are blocked on const eval, compiler builtins updates, and LLVM lowering bugs.hooray, this part is done!f16andf128step 4: basic library support #122470Debugimpl and some basic functions tof16andf128#123783f16andf128#126608f16andf128math functions #127027f16/f128float conversions compiler-builtins#593f128compiler-builtins#606f128float to integer conversion functions compiler-builtins#613__divtf3compiler-builtins#622__powitf2symbol forf128integer exponentiation compiler-builtins#614test-float-parsein Rust #127510f16, which should be straightforward Addf16formatting and parsing #127013f128which will not be straightforward. Our current implementations are prettyu64-dependent so they can't fit af128mantissa. We could make them generic but probably want to instead use an implementation that is slower but better for size.f16andf128const eval for binary and unary operationations #126429f16andf128#127032f16shims addf16support miri#4895f128shims (partially implemented by implement sqrt and add fixme forf128miri#4902)Add encoding forAdd v0 symbol mangling forf16andf128#122106f16andf128#123816Ensure known demanglers get updated or at least have issues for adding the new typesunneeded with the forward-compatible demanglingf16andf128in assembly on platforms that support it #125398f16andf128inline ASM support foraarch64#129536f16andf128inline ASM support forx86andx86-64#126417f16inline ASM support for RISC-V #126530f16inline ASM support for 32-bit ARM #126555f16inline asm support for LoongArch #142481f16inline ASM support for s390x #150826f16inline ASM support for MIPS #160851f16andf128inline ASM support for PowerPC #161135f16inline ASM support fornvptx64-nvidia-cuda#161667f16inline ASM support tospirv.rs#163281f128and validate that it works correctlyf128(but only of 8 fori128)f16andf128rustc_codegen_gcc#461f16andf128rustc_codegen_cranelift#1461unimplementeds andFIXMEs are removed from tools that need library supportf16andf128unimplemented!/FIXMEs #126636f16andf128pattern matching stubs with real implementations #123088f16/f128FIXMEs that needed(NEG_)INFINITY#127496f16_nanAddf16andf128toinvalid_nan_comparison#132439f16_epsilonfor Clippy (needs to be added)f16generates code that uses the incorrect ABI for compiler-rt #123885halfoperations by using too much precision on several backends llvm/llvm-project#97975 LLVM miscompiles passing/returninghalfon several backends by using lossy conversions llvm/llvm-project#97981@llvm.fabs.f16generates call to__extendhfsf2llvm/llvm-project#104915 (comment)f128symbols on powerpc64 give inaccurate results #125109f128from_bits/to_bitssometimes gets reversed on ppc #125102f128 as f16casting bug LLVM f128 -> f16 conversion selection failure on powerpc64le llvm/llvm-project#92866fp128->halfuses__trunctfhf2but should be__trunckfhf2llvm/llvm-project#98126+fand+dllvm/llvm-project#93894 (fixed upstream)f128Can't pass or returnhalforfp128onarm64ecllvm/llvm-project#94434 (f16supported since [Arm64EC] Add support forhalfllvm/llvm-project#152843)-fp-armv8crash usingselectwithhalfllvm/llvm-project#129394wasm32,halfoperation results aren't correctly rounded between each operation llvm/llvm-project#96437fp128causes compilation failures when compiling fornvptx64-nvidia-cudallvm/llvm-project#95471f128Compiler crash when targetingmips64when returningfp128after calling a function returning{ i8, i128 }llvm/llvm-project#96432powerpc64-ibm-aixdoesn't currently supportf128arguments:fp128arguments cause a compiler error onpowerpc64-ibm-aixllvm/llvm-project#101545-Ctarget-feature#116344 (and in particular Figure out which target features are required/incompatible for which ABI #131799) for all targets; those issues are mostly focusing on f32 and f64 so there might be more target features we have to worry about for f16/f128 (see f16 and f128 have non-trivial ABI requirements on some targets #138616)minimumandmaximumdon't work on x86 and aarch64 [aarch64]Cannot select: constant:i128<0>forllvm.maximum.f128llvm/llvm-project#139380 [x86]: Cannot select:constant:i128<0>forllvm.maximum.f128llvm/llvm-project#139381 (nonblocking as we are using the fallback for now)minimum/maximumforf128don't work on tier 2 wasm targetsf128on wasm does not support maximum intrinsic #158673fma.f16incorrectlyllvm.fma.f16intrinsic is expanded incorrectly on targets without nativehalfFMA support llvm/llvm-project#98389powi.f16constant folding returns incorrect values Misoptimization:EarlyCSEPassuses replacespowi.f16withfloatresult llvm/llvm-project#98665cfgthat lets us gate tests based on backend support Implement the internal featurecfg_target_has_reliable_f16_f128#140323Note that
// FIXME(f128)/// FIXME(f16)/// FIXME(f16,f128)andunimplemented!("f16_f128")are being used where relevant, to make the todo list easily greppable.Nice to have changes:
f16: Add Natvis visualiser and debuginfo tests forf16#127001f128: Add Natvis visualiser and debuginfo tests forf128#161777f16andf128support (add toFloatTy) rust-analyzer#17451f16andf128under a nightly flag Lokathor/bytemuck#250