[llvm] [X86] Avoid redundant SSE bounce in x87 FP_EXTEND(FP_ROUND) conversions (PR #213494)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 1 17:13:39 PDT 2026
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/213494
>From c3bb27afc982313752b20e544bf825e7344053c4 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sat, 1 Aug 2026 20:08:12 -0400
Subject: [PATCH 1/2] [X86] Add pre-commit test case for x87 float return and
SSE roundtrip
---
llvm/test/CodeGen/X86/x87-inout-bounce.ll | 94 +++++++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 llvm/test/CodeGen/X86/x87-inout-bounce.ll
diff --git a/llvm/test/CodeGen/X86/x87-inout-bounce.ll b/llvm/test/CodeGen/X86/x87-inout-bounce.ll
new file mode 100644
index 0000000000000..161ca2c1742b1
--- /dev/null
+++ b/llvm/test/CodeGen/X86/x87-inout-bounce.ll
@@ -0,0 +1,94 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=i386-unknown-linux-gnu -mattr=+sse2,+x87 | FileCheck %s
+
+define float @returns_float() {
+; CHECK-LABEL: returns_float:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: subl $12, %esp
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: calll rand at PLT
+; CHECK-NEXT: cvtsi2ss %eax, %xmm0
+; CHECK-NEXT: movss %xmm0, {{[0-9]+}}(%esp)
+; CHECK-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-NEXT: addl $12, %esp
+; CHECK-NEXT: .cfi_def_cfa_offset 4
+; CHECK-NEXT: retl
+entry:
+ %call = call i32 @rand()
+ %conv = sitofp i32 %call to float
+ ret float %conv
+}
+
+declare i32 @rand()
+
+define float @example_float() {
+; CHECK-LABEL: example_float:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: subl $28, %esp
+; CHECK-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NEXT: calll returns_float at PLT
+; CHECK-NEXT: fstps {{[0-9]+}}(%esp)
+; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; CHECK-NEXT: movss %xmm0, (%esp) # 4-byte Spill
+; CHECK-NEXT: calll returns_float at PLT
+; CHECK-NEXT: fstps {{[0-9]+}}(%esp)
+; CHECK-NEXT: movss (%esp), %xmm0 # 4-byte Reload
+; CHECK-NEXT: # xmm0 = mem[0],zero,zero,zero
+; CHECK-NEXT: addss {{[0-9]+}}(%esp), %xmm0
+; CHECK-NEXT: movss %xmm0, (%esp) # 4-byte Spill
+; CHECK-NEXT: calll returns_float at PLT
+; CHECK-NEXT: fstps {{[0-9]+}}(%esp)
+; CHECK-NEXT: movss (%esp), %xmm0 # 4-byte Reload
+; CHECK-NEXT: # xmm0 = mem[0],zero,zero,zero
+; CHECK-NEXT: addss {{[0-9]+}}(%esp), %xmm0
+; CHECK-NEXT: movss %xmm0, (%esp) # 4-byte Spill
+; CHECK-NEXT: calll returns_float at PLT
+; CHECK-NEXT: fstps {{[0-9]+}}(%esp)
+; CHECK-NEXT: movss (%esp), %xmm0 # 4-byte Reload
+; CHECK-NEXT: # xmm0 = mem[0],zero,zero,zero
+; CHECK-NEXT: addss {{[0-9]+}}(%esp), %xmm0
+; CHECK-NEXT: movss %xmm0, (%esp) # 4-byte Spill
+; CHECK-NEXT: calll returns_float at PLT
+; CHECK-NEXT: fstps {{[0-9]+}}(%esp)
+; CHECK-NEXT: movss (%esp), %xmm0 # 4-byte Reload
+; CHECK-NEXT: # xmm0 = mem[0],zero,zero,zero
+; CHECK-NEXT: addss {{[0-9]+}}(%esp), %xmm0
+; CHECK-NEXT: movss %xmm0, {{[0-9]+}}(%esp)
+; CHECK-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-NEXT: addl $28, %esp
+; CHECK-NEXT: .cfi_def_cfa_offset 4
+; CHECK-NEXT: retl
+entry:
+ %call = call float @returns_float()
+ %call1 = call float @returns_float()
+ %add = fadd float %call, %call1
+ %call2 = call float @returns_float()
+ %add3 = fadd float %add, %call2
+ %call4 = call float @returns_float()
+ %add5 = fadd float %add3, %call4
+ %call6 = call float @returns_float()
+ %add7 = fadd float %add5, %call6
+ ret float %add7
+}
+
+declare x86_fp80 @returns_long_double()
+
+define x86_fp80 @testC() {
+; CHECK-LABEL: testC:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: subl $12, %esp
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: calll returns_long_double at PLT
+; CHECK-NEXT: fstps {{[0-9]+}}(%esp)
+; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; CHECK-NEXT: movss %xmm0, {{[0-9]+}}(%esp)
+; CHECK-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-NEXT: addl $12, %esp
+; CHECK-NEXT: .cfi_def_cfa_offset 4
+; CHECK-NEXT: retl
+entry:
+ %call = call x86_fp80 @returns_long_double()
+ %conv = fptrunc x86_fp80 %call to float
+ %conv1 = fpext float %conv to x86_fp80
+ ret x86_fp80 %conv1
+}
>From 402cde2e60137f93ef70266ba419e6228aa40dcc Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Sat, 1 Aug 2026 20:10:08 -0400
Subject: [PATCH 2/2] [X86] Avoid redundant SSE bounce in x87
FP_EXTEND(FP_ROUND) conversions
In 32-bit x86 code generation with both x87 and SSE enabled (e.g., `-mtriple=i386-unknown-linux-gnu -mattr=+sse2,+x87`), floating-point values returned in `st(0)` that undergo a sequence of truncation and extension (such as `fptrunc` to `float` followed by `fpext` to `x86_fp80`) were previously bouncing through SSE XMM registers (`movss`).
---
llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 36 ++++++++++++++++++-----
llvm/test/CodeGen/X86/x87-inout-bounce.ll | 2 --
2 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index d078117061677..80bf5bab2aca7 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -1449,18 +1449,40 @@ void X86DAGToDAGISel::PreprocessISelDAG() {
// FPStack has extload and truncstore. SSE can fold direct loads into other
// operations. Based on this, decide what we want to do.
MVT MemVT = (N->getOpcode() == ISD::FP_ROUND) ? DstVT : SrcVT;
- SDValue MemTmp = CurDAG->CreateStackTemporary(MemVT);
- int SPFI = cast<FrameIndexSDNode>(MemTmp)->getIndex();
- MachinePointerInfo MPI =
- MachinePointerInfo::getFixedStack(CurDAG->getMachineFunction(), SPFI);
SDLoc dl(N);
// FIXME: optimize the case where the src/dest is a load or store?
+ SDValue SrcVal = N->getOperand(0);
+ SDValue Store, MemTmp;
+ MachinePointerInfo MemMPI;
+
+ if (auto *LD = dyn_cast<LoadSDNode>(SrcVal)) {
+ if (LD->getMemoryVT() == MemVT) {
+ Store = LD->getChain();
+ MemTmp = LD->getBasePtr();
+ MemMPI = LD->getPointerInfo();
+ }
+ } else if (SrcVal.getOpcode() == ISD::FP_ROUND) {
+ MemTmp = CurDAG->CreateStackTemporary(MemVT);
+ int SPFI = cast<FrameIndexSDNode>(MemTmp)->getIndex();
+ MemMPI = MachinePointerInfo::getFixedStack(CurDAG->getMachineFunction(),
+ SPFI);
+ Store =
+ CurDAG->getTruncStore(CurDAG->getEntryNode(), dl,
+ SrcVal.getOperand(0), MemTmp, MemMPI, MemVT);
+ }
+
+ if (!MemTmp) {
+ MemTmp = CurDAG->CreateStackTemporary(MemVT);
+ int SPFI = cast<FrameIndexSDNode>(MemTmp)->getIndex();
+ MemMPI = MachinePointerInfo::getFixedStack(CurDAG->getMachineFunction(),
+ SPFI);
+ Store = CurDAG->getTruncStore(CurDAG->getEntryNode(), dl, SrcVal,
+ MemTmp, MemMPI, MemVT);
+ }
- SDValue Store = CurDAG->getTruncStore(
- CurDAG->getEntryNode(), dl, N->getOperand(0), MemTmp, MPI, MemVT);
SDValue Result = CurDAG->getExtLoad(ISD::EXTLOAD, dl, DstVT, Store,
- MemTmp, MPI, MemVT);
+ MemTmp, MemMPI, MemVT);
// We're about to replace all uses of the FP_ROUND/FP_EXTEND with the
// extload we created. This will cause general havok on the dag because
diff --git a/llvm/test/CodeGen/X86/x87-inout-bounce.ll b/llvm/test/CodeGen/X86/x87-inout-bounce.ll
index 161ca2c1742b1..bc531aef9219c 100644
--- a/llvm/test/CodeGen/X86/x87-inout-bounce.ll
+++ b/llvm/test/CodeGen/X86/x87-inout-bounce.ll
@@ -80,8 +80,6 @@ define x86_fp80 @testC() {
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: calll returns_long_double at PLT
; CHECK-NEXT: fstps {{[0-9]+}}(%esp)
-; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
-; CHECK-NEXT: movss %xmm0, {{[0-9]+}}(%esp)
; CHECK-NEXT: flds {{[0-9]+}}(%esp)
; CHECK-NEXT: addl $12, %esp
; CHECK-NEXT: .cfi_def_cfa_offset 4
More information about the llvm-commits
mailing list