Skip to content

Ensure floats are returned losslessly by the C ABI on 32-bit x86 - #161950

Open
beetrees wants to merge 1 commit into
rust-lang:mainfrom
beetrees:x86-ret-snan-c
Open

Ensure floats are returned losslessly by the C ABI on 32-bit x86#161950
beetrees wants to merge 1 commit into
rust-lang:mainfrom
beetrees:x86-ret-snan-c

Conversation

@beetrees

@beetrees beetrees commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

The x86 C ABI returns f32 and f64 using the x87 extended precision floating point format (henceforth x86_fp80) on the x87 floating point stack. Currently, LLVM uses regular fld/fstp instructions to convert f32/f64 to and from x86_fp80 when returning from a function with the C ABI, however these instructions perform floating point format conversions that quieten signalling NaNs, which breaks Rust's (and LLVM's) guarantees. This is a long-standing LLVM bug (llvm/llvm-project#66803) but is difficult to fix on the LLVM side as it ties into larger problems with the way LLVM handles x87 registers holding f32/f64, combined with the general lack of developer interest in 32-bit x86 without SSE (although the ABI bug specifically also affects targets with SSE2 enabled). This problem has been tracked on the Rust side in #115567, with #123351 ensuring that Rustic ABIs avoid the x87 stack altogether and #113053 adding notes to the platform support page detailing how the targets are non-complaint (including the tier 1 targets i686-unknown-linux-gnu and i686-pc-windows-msvc).

This PR fixes #115567 by manually converting NaNs to and from x86_fp80 when a function returns f32/f64 (this was briefly discussed in #t-compiler > `x87_f80` is weird @ 💬).

r? @tgross35
cc @RalfJung

try-job: i686-*

@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 28, 2026
@rustbot

rustbot commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

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

@rust-log-analyzer

This comment has been minimized.

@folkertdev

Copy link
Copy Markdown
Contributor

@bors delegate try

@rust-bors

rust-bors Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

✌️ @beetrees, you can now perform try builds on this pull request!

You can now post @bors try to start a try build.

@beetrees

Copy link
Copy Markdown
Contributor Author

@bors try

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Aug 28, 2026
Ensure floats are returned losslessly by the C ABI on 32-bit x86

try-job: i686-*
@rust-log-analyzer

Copy link
Copy Markdown
Collaborator

The job aarch64-gnu-llvm-21-1 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
test [codegen] tests/codegen-llvm/zip.rs ... ok

failures:

---- [codegen] tests/codegen-llvm/float/x86-return-float-c.rs#linux stdout ----
------FileCheck stdout------------------------------

------FileCheck stderr------------------------------
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:57:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 1.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:31:47: note: scanning from here
define noundef x86_fp80 @return_constant_f32() unnamed_addr #0 {
                                              ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:33:2: note: possible intended match here
 ret x86_fp80 0xK3FFFC000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:64:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 2.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:37:47: note: scanning from here
define noundef x86_fp80 @return_constant_f64() unnamed_addr #0 {
                                              ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:39:2: note: possible intended match here
 ret x86_fp80 0xK4000A000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:71:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 1.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:43:45: note: scanning from here
define noundef x86_fp80 @call_constant_f32() unnamed_addr #0 {
                                            ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:45:2: note: possible intended match here
 ret x86_fp80 0xK3FFFC000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:78:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 2.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:49:45: note: scanning from here
define noundef x86_fp80 @call_constant_f64() unnamed_addr #0 {
                                            ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:51:2: note: possible intended match here
 ret x86_fp80 0xK4000A000000000000000
 ^

Input file: /checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll
Check file: /checkout/tests/codegen-llvm/float/x86-return-float-c.rs

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1: ; ModuleID = 'x86_return_float_c.bed34aab08e0e5b4-cgu.0' 
            2: source_filename = "x86_return_float_c.bed34aab08e0e5b4-cgu.0" 
            3: target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128" 
            4: target triple = "i686-unknown-linux-gnu" 
            5:  
            6: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
            7: define noundef x86_fp80 @return_undef_f32() unnamed_addr #0 { 
            8: start: 
            9:  ret x86_fp80 0xK00000000000000000000 
           10: } 
           11:  
           12: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           13: define noundef x86_fp80 @return_undef_f64() unnamed_addr #0 { 
           14: start: 
           15:  ret x86_fp80 0xK00000000000000000000 
           16: } 
           17:  
           18: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           19: define noundef x86_fp80 @call_undef_f32() unnamed_addr #0 { 
           20: float_pre_ret.after: 
           21:  ret x86_fp80 0xK00000000000000000000 
           22: } 
           23:  
           24: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           25: define noundef x86_fp80 @call_undef_f64() unnamed_addr #0 { 
           26: float_pre_ret.after: 
           27:  ret x86_fp80 0xK00000000000000000000 
           28: } 
           29:  
           30: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           31: define noundef x86_fp80 @return_constant_f32() unnamed_addr #0 { 
check:57'0                                                   X~~~~~~~~~~~~~~~~~~ error: no match found
           32: start: 
check:57'0     ~~~~~~~
           33:  ret x86_fp80 0xK3FFFC000000000000000 
check:57'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:57'1      ?                                     possible intended match
           34: } 
check:57'0     ~~
           35:  
check:57'0     ~
           36: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
check:57'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           37: define noundef x86_fp80 @return_constant_f64() unnamed_addr #0 { 
check:57'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:64'0                                                   X~~~~~~~~~~~~~~~~~~ error: no match found
           38: start: 
check:64'0     ~~~~~~~
           39:  ret x86_fp80 0xK4000A000000000000000 
check:64'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:64'1      ?                                     possible intended match
           40: } 
check:64'0     ~~
           41:  
check:64'0     ~
           42: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
check:64'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           43: define noundef x86_fp80 @call_constant_f32() unnamed_addr #0 { 
check:64'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:71'0                                                 X~~~~~~~~~~~~~~~~~~ error: no match found
           44: start: 
check:71'0     ~~~~~~~
           45:  ret x86_fp80 0xK3FFFC000000000000000 
check:71'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:71'1      ?                                     possible intended match
           46: } 
check:71'0     ~~
           47:  
check:71'0     ~
           48: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
check:71'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           49: define noundef x86_fp80 @call_constant_f64() unnamed_addr #0 { 
check:71'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:78'0                                                 X~~~~~~~~~~~~~~~~~~ error: no match found
           50: start: 
check:78'0     ~~~~~~~
           51:  ret x86_fp80 0xK4000A000000000000000 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:78'1      ?                                     possible intended match
           52: } 
check:78'0     ~~
           53:  
check:78'0     ~
           54: attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable "probe-stack"="inline-asm" "target-cpu"="pentium4" } 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           55:  
check:78'0     ~
           56: !llvm.module.flags = !{!0, !1} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           57: !llvm.ident = !{!2} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~
           58:  
check:78'0     ~
           59: !0 = !{i32 8, !"PIC Level", i32 2} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           60: !1 = !{i32 7, !"uwtable", i32 2} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           61: !2 = !{!"rustc version 1.100.0-nightly (67fde0fc0 2026-08-28)"} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>>

------------------------------------------

error in revision `linux`: verification with 'FileCheck' failed
status: exit status: 1
command: "/usr/lib/llvm-21/bin/FileCheck" "--input-file" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll" "/checkout/tests/codegen-llvm/float/x86-return-float-c.rs" "--check-prefix=CHECK" "--check-prefix" "linux" "--allow-unused-prefixes" "--dump-input-context" "100"
stdout: none
--- stderr -------------------------------
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:57:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 1.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:31:47: note: scanning from here
define noundef x86_fp80 @return_constant_f32() unnamed_addr #0 {
                                              ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:33:2: note: possible intended match here
 ret x86_fp80 0xK3FFFC000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:64:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 2.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:37:47: note: scanning from here
define noundef x86_fp80 @return_constant_f64() unnamed_addr #0 {
                                              ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:39:2: note: possible intended match here
 ret x86_fp80 0xK4000A000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:71:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 1.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:43:45: note: scanning from here
define noundef x86_fp80 @call_constant_f32() unnamed_addr #0 {
                                            ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:45:2: note: possible intended match here
 ret x86_fp80 0xK3FFFC000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:78:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 2.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:49:45: note: scanning from here
define noundef x86_fp80 @call_constant_f64() unnamed_addr #0 {
                                            ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll:51:2: note: possible intended match here
 ret x86_fp80 0xK4000A000000000000000
 ^

Input file: /checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.linux/x86-return-float-c.ll
Check file: /checkout/tests/codegen-llvm/float/x86-return-float-c.rs

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1: ; ModuleID = 'x86_return_float_c.bed34aab08e0e5b4-cgu.0' 
            2: source_filename = "x86_return_float_c.bed34aab08e0e5b4-cgu.0" 
            3: target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128" 
            4: target triple = "i686-unknown-linux-gnu" 
            5:  
            6: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
            7: define noundef x86_fp80 @return_undef_f32() unnamed_addr #0 { 
            8: start: 
            9:  ret x86_fp80 0xK00000000000000000000 
           10: } 
           11:  
           12: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           13: define noundef x86_fp80 @return_undef_f64() unnamed_addr #0 { 
           14: start: 
           15:  ret x86_fp80 0xK00000000000000000000 
           16: } 
           17:  
           18: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           19: define noundef x86_fp80 @call_undef_f32() unnamed_addr #0 { 
           20: float_pre_ret.after: 
           21:  ret x86_fp80 0xK00000000000000000000 
           22: } 
           23:  
           24: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           25: define noundef x86_fp80 @call_undef_f64() unnamed_addr #0 { 
           26: float_pre_ret.after: 
           27:  ret x86_fp80 0xK00000000000000000000 
           28: } 
           29:  
           30: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           31: define noundef x86_fp80 @return_constant_f32() unnamed_addr #0 { 
check:57'0                                                   X~~~~~~~~~~~~~~~~~~ error: no match found
           32: start: 
check:57'0     ~~~~~~~
           33:  ret x86_fp80 0xK3FFFC000000000000000 
check:57'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:57'1      ?                                     possible intended match
           34: } 
check:57'0     ~~
           35:  
check:57'0     ~
           36: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
check:57'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           37: define noundef x86_fp80 @return_constant_f64() unnamed_addr #0 { 
check:57'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:64'0                                                   X~~~~~~~~~~~~~~~~~~ error: no match found
           38: start: 
check:64'0     ~~~~~~~
           39:  ret x86_fp80 0xK4000A000000000000000 
check:64'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:64'1      ?                                     possible intended match
           40: } 
check:64'0     ~~
           41:  
check:64'0     ~
           42: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
check:64'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           43: define noundef x86_fp80 @call_constant_f32() unnamed_addr #0 { 
check:64'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:71'0                                                 X~~~~~~~~~~~~~~~~~~ error: no match found
           44: start: 
check:71'0     ~~~~~~~
           45:  ret x86_fp80 0xK3FFFC000000000000000 
check:71'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:71'1      ?                                     possible intended match
           46: } 
check:71'0     ~~
           47:  
check:71'0     ~
           48: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
check:71'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           49: define noundef x86_fp80 @call_constant_f64() unnamed_addr #0 { 
check:71'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:78'0                                                 X~~~~~~~~~~~~~~~~~~ error: no match found
           50: start: 
check:78'0     ~~~~~~~
           51:  ret x86_fp80 0xK4000A000000000000000 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:78'1      ?                                     possible intended match
           52: } 
check:78'0     ~~
           53:  
check:78'0     ~
           54: attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable "probe-stack"="inline-asm" "target-cpu"="pentium4" } 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           55:  
check:78'0     ~
           56: !llvm.module.flags = !{!0, !1} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           57: !llvm.ident = !{!2} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~
           58:  
check:78'0     ~
           59: !0 = !{i32 8, !"PIC Level", i32 2} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           60: !1 = !{i32 7, !"uwtable", i32 2} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           61: !2 = !{!"rustc version 1.100.0-nightly (67fde0fc0 2026-08-28)"} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>>
------------------------------------------

---- [codegen] tests/codegen-llvm/float/x86-return-float-c.rs#linux stdout end ----
---- [codegen] tests/codegen-llvm/float/x86-return-float-c.rs#windows-gnu stdout ----
------FileCheck stdout------------------------------

------FileCheck stderr------------------------------
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:57:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 1.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:31:47: note: scanning from here
define noundef x86_fp80 @return_constant_f32() unnamed_addr #0 {
                                              ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:33:2: note: possible intended match here
 ret x86_fp80 0xK3FFFC000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:64:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 2.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:37:47: note: scanning from here
define noundef x86_fp80 @return_constant_f64() unnamed_addr #0 {
                                              ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:39:2: note: possible intended match here
 ret x86_fp80 0xK4000A000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:71:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 1.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:43:45: note: scanning from here
define noundef x86_fp80 @call_constant_f32() unnamed_addr #0 {
                                            ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:45:2: note: possible intended match here
 ret x86_fp80 0xK3FFFC000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:78:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 2.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:49:45: note: scanning from here
define noundef x86_fp80 @call_constant_f64() unnamed_addr #0 {
                                            ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:51:2: note: possible intended match here
 ret x86_fp80 0xK4000A000000000000000
 ^

Input file: /checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll
Check file: /checkout/tests/codegen-llvm/float/x86-return-float-c.rs

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            1: ; ModuleID = 'x86_return_float_c.bed34aab08e0e5b4-cgu.0' 
            2: source_filename = "x86_return_float_c.bed34aab08e0e5b4-cgu.0" 
            3: target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:32-n8:16:32-a:0:32-S32" 
            4: target triple = "i686-pc-windows-gnu" 
            5:  
            6: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
            7: define noundef x86_fp80 @return_undef_f32() unnamed_addr #0 { 
            8: start: 
            9:  ret x86_fp80 0xK00000000000000000000 
           10: } 
           11:  
           12: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           13: define noundef x86_fp80 @return_undef_f64() unnamed_addr #0 { 
           14: start: 
           15:  ret x86_fp80 0xK00000000000000000000 
           16: } 
           17:  
           18: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           19: define noundef x86_fp80 @call_undef_f32() unnamed_addr #0 { 
           20: float_pre_ret.after: 
           21:  ret x86_fp80 0xK00000000000000000000 
           22: } 
           23:  
           24: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           25: define noundef x86_fp80 @call_undef_f64() unnamed_addr #0 { 
           26: float_pre_ret.after: 
           27:  ret x86_fp80 0xK00000000000000000000 
           28: } 
           29:  
           30: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
           31: define noundef x86_fp80 @return_constant_f32() unnamed_addr #0 { 
check:57'0                                                   X~~~~~~~~~~~~~~~~~~ error: no match found
           32: start: 
check:57'0     ~~~~~~~
           33:  ret x86_fp80 0xK3FFFC000000000000000 
check:57'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:57'1      ?                                     possible intended match
           34: } 
check:57'0     ~~
           35:  
check:57'0     ~
           36: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
check:57'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           37: define noundef x86_fp80 @return_constant_f64() unnamed_addr #0 { 
check:57'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:64'0                                                   X~~~~~~~~~~~~~~~~~~ error: no match found
           38: start: 
check:64'0     ~~~~~~~
           39:  ret x86_fp80 0xK4000A000000000000000 
check:64'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:64'1      ?                                     possible intended match
           40: } 
check:64'0     ~~
           41:  
check:64'0     ~
           42: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
check:64'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           43: define noundef x86_fp80 @call_constant_f32() unnamed_addr #0 { 
check:64'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:71'0                                                 X~~~~~~~~~~~~~~~~~~ error: no match found
           44: start: 
check:71'0     ~~~~~~~
           45:  ret x86_fp80 0xK3FFFC000000000000000 
check:71'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:71'1      ?                                     possible intended match
           46: } 
check:71'0     ~~
           47:  
check:71'0     ~
           48: ; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable 
check:71'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           49: define noundef x86_fp80 @call_constant_f64() unnamed_addr #0 { 
check:71'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:78'0                                                 X~~~~~~~~~~~~~~~~~~ error: no match found
           50: start: 
check:78'0     ~~~~~~~
           51:  ret x86_fp80 0xK4000A000000000000000 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:78'1      ?                                     possible intended match
           52: } 
check:78'0     ~~
           53:  
check:78'0     ~
           54: attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable "frame-pointer"="all" "target-cpu"="pentium4" } 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           55:  
check:78'0     ~
           56: !llvm.module.flags = !{!0, !1, !2} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           57: !llvm.ident = !{!3} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~
           58:  
check:78'0     ~
           59: !0 = !{i32 8, !"PIC Level", i32 2} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           60: !1 = !{i32 7, !"uwtable", i32 2} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           61: !2 = !{i32 7, !"frame-pointer", i32 2} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           62: !3 = !{!"rustc version 1.100.0-nightly (67fde0fc0 2026-08-28)"} 
check:78'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>>

------------------------------------------

error in revision `windows-gnu`: verification with 'FileCheck' failed
status: exit status: 1
command: "/usr/lib/llvm-21/bin/FileCheck" "--input-file" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll" "/checkout/tests/codegen-llvm/float/x86-return-float-c.rs" "--check-prefix=CHECK" "--check-prefix" "windows-gnu" "--allow-unused-prefixes" "--dump-input-context" "100"
stdout: none
--- stderr -------------------------------
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:57:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 1.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:31:47: note: scanning from here
define noundef x86_fp80 @return_constant_f32() unnamed_addr #0 {
                                              ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:33:2: note: possible intended match here
 ret x86_fp80 0xK3FFFC000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:64:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 2.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:37:47: note: scanning from here
define noundef x86_fp80 @return_constant_f64() unnamed_addr #0 {
                                              ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:39:2: note: possible intended match here
 ret x86_fp80 0xK4000A000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:71:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 1.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:43:45: note: scanning from here
define noundef x86_fp80 @call_constant_f32() unnamed_addr #0 {
                                            ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:45:2: note: possible intended match here
 ret x86_fp80 0xK3FFFC000000000000000
 ^
/checkout/tests/codegen-llvm/float/x86-return-float-c.rs:78:11: error: CHECK: expected string not found in input
// CHECK: ret x86_fp80 2.500000e+00
          ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:49:45: note: scanning from here
define noundef x86_fp80 @call_constant_f64() unnamed_addr #0 {
                                            ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/float/x86-return-float-c.windows-gnu/x86-return-float-c.ll:51:2: note: possible intended match here
 ret x86_fp80 0xK4000A000000000000000

@rust-bors

rust-bors Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: a9e9507 (a9e95070267a88d3be44d2d95464f64d39bb751d)
Base parent: 17fd5b8 (17fd5b8a37b6667b6cc137f3cc35f09759768a3b)

@RalfJung RalfJung left a comment

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 can't review this, but I love it. :) I see that there's a separate path for nnan, so if LLVM can infer nnan all the new code should optimize away. That might be worth a test as well if we don't already have one?

View changes since this review

C: HasDataLayout + HasTargetSpec,
{
if !fn_abi.ret.is_ignore() {
// "vectorcall" returns floats in `xmm0`, and soft float also does not use the x87 stack.

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.

vectorcall does not show up in the code below, so this comment is a bit confusing.

Comment on lines 17 to 19
// FIXME(#114479): LLVM miscompiles loading and storing `f32` and `f64` when SSE is disabled on
// x86.
if cfg!(not(all(target_arch = "x86", not(target_feature = "sse2")))) {

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.

Shouldn't the FIXME and if be removed as this PR is supposed to fix exactly that?

/// 32-bit x86. This is needed as LLVM needs to generate extra code to ensure that signalling
/// NaNs are passed losslessly on the x87 floating point stack. Only valid on return types on
/// 32-bit x86 with a cast target of either `Reg::f32()` or `Reg::f64()`.
pub x87_floating_point_stack: bool,

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.

This should mention that the LLVM-level type is then changed to x86_fp80.

// any initialized bytes within a partially uninitialized value survive the round trip,
// freeze the value.
let value = if no_undef { value } else { self.freeze(value) };
let is_nan = self.fcmp(RealPredicate::RealUNO, value, value);

@RalfJung RalfJung Aug 29, 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.

Wouldn't the ideal test be "is it a signaling NaN"? Or do normal NaNs also get garbled?
Though I can imagine that that's annoying enough to implement that it's not worth it.

View changes since the review

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. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tracking issue: 32bit x86 targets lose float NaN payload in return values

6 participants