[llvm] [SelectionDAG] Fix load/store legalization for softened x86_fp80 (PR #209991)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 03:11:29 PDT 2026


https://github.com/RKSimon updated https://github.com/llvm/llvm-project/pull/209991

>From be9b447c5fa8a7ec91d0e0028b74aa5da2935024 Mon Sep 17 00:00:00 2001
From: Shiyas-N <muhammedshiyasn811 at gmail.com>
Date: Thu, 16 Jul 2026 06:38:45 +0000
Subject: [PATCH 1/5] [SelectionDAG] Fix load/store legalization for softened
 x86_fp80

When x86_fp80 is softened to a wider integer type, use extending loads
and truncating stores to preserve the original memory width.
---
 .../SelectionDAG/LegalizeFloatTypes.cpp       | 24 +++++--
 .../CodeGen/X86/x86-fp80-load-store-no-x87.ll | 65 +++++++++++++++++++
 2 files changed, 85 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 25cc420c42482..0c869e1b23778 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -1016,10 +1016,19 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_LOAD(SDNode *N) {
       ~(MachineMemOperand::MOInvariant | MachineMemOperand::MODereferenceable);
   SDValue NewL;
   if (L->getExtensionType() == ISD::NON_EXTLOAD) {
-    NewL = DAG.getLoad(L->getAddressingMode(), L->getExtensionType(), NVT, dl,
-                       L->getChain(), L->getBasePtr(), L->getOffset(),
-                       L->getPointerInfo(), NVT, L->getBaseAlign(), MMOFlags,
-                       L->getAAInfo());
+    // If softening widens the integer representation (e.g. x86_fp80 -> i96),
+    // load the original memory width and extend to the softened type.
+    EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits());
+    if (NVT.bitsGT(MemVT))
+      NewL = DAG.getLoad(L->getAddressingMode(), ISD::EXTLOAD, NVT, dl,
+                         L->getChain(), L->getBasePtr(), L->getOffset(),
+                         L->getPointerInfo(), MemVT, L->getBaseAlign(),
+                         MMOFlags, L->getAAInfo());
+    else
+      NewL = DAG.getLoad(L->getAddressingMode(), L->getExtensionType(), NVT, dl,
+                         L->getChain(), L->getBasePtr(), L->getOffset(),
+                         L->getPointerInfo(), NVT, L->getBaseAlign(), MMOFlags,
+                         L->getAAInfo());
     // Legalized the chain result - switch anything that used the old chain to
     // use the new one.
     ReplaceValueWith(SDValue(N, 1), NewL.getValue(1));
@@ -1423,6 +1432,13 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_STORE(SDNode *N, unsigned OpNo) {
   else
     Val = GetSoftenedFloat(Val);
 
+  // If softening widens the integer representation (e.g. x86_fp80 -> i96),
+  // truncate the value before storing to preserve the original memory width.
+  EVT MemVT =
+      EVT::getIntegerVT(*DAG.getContext(), ST->getMemoryVT().getSizeInBits());
+  if (Val.getValueType().bitsGT(MemVT))
+    return DAG.getTruncStore(ST->getChain(), dl, Val, ST->getBasePtr(), MemVT,
+                             ST->getMemOperand());
   return DAG.getStore(ST->getChain(), dl, Val, ST->getBasePtr(),
                       ST->getMemOperand());
 }
diff --git a/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll b/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
new file mode 100644
index 0000000000000..dd563bdd746f3
--- /dev/null
+++ b/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
@@ -0,0 +1,65 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mattr=-x87 | FileCheck %s --check-prefix=X64
+; RUN: llc < %s -mtriple=i686-unknown-linux-gnu -mattr=-x87 | FileCheck %s --check-prefix=X86
+
+; Verify that x86_fp80 load/store legalization handles widened softened types
+; correctly when x87 is disabled.
+define void @test_load_store_f80(ptr %p, ptr %q) #0 {
+; X64-LABEL: test_load_store_f80:
+; X64:       # %bb.0:
+; X64-NEXT:    movl 8(%rdi), %eax
+; X64-NEXT:    movq (%rdi), %rcx
+; X64-NEXT:    movq %rcx, (%rsi)
+; X64-NEXT:    movw %ax, 8(%rsi)
+; X64-NEXT:    retq
+;
+; X86-LABEL: test_load_store_f80:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    movl 8(%ecx), %edx
+; X86-NEXT:    movl (%ecx), %esi
+; X86-NEXT:    movl 4(%ecx), %ecx
+; X86-NEXT:    movl %esi, (%eax)
+; X86-NEXT:    movl %ecx, 4(%eax)
+; X86-NEXT:    movw %dx, 8(%eax)
+; X86-NEXT:    popl %esi
+; X86-NEXT:    retl
+  %v = load x86_fp80, ptr %p, align 16
+  store x86_fp80 %v, ptr %q, align 16
+  ret void
+}
+
+; Verify that returning a struct containing x86_fp80 values works with
+; x87 disabled.
+define { x86_fp80, x86_fp80 } @test_struct_ret_f80() #0 {
+; X64-LABEL: test_struct_ret_f80:
+; X64:       # %bb.0: # %entry
+; X64-NEXT:    movq %rdi, %rax
+; X64-NEXT:    movl 8, %ecx
+; X64-NEXT:    movq 0, %rdx
+; X64-NEXT:    movq %rdx, (%rdi)
+; X64-NEXT:    movw %cx, 8(%rdi)
+; X64-NEXT:    retq
+;
+; X86-LABEL: test_struct_ret_f80:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl 8, %ecx
+; X86-NEXT:    movl 0, %edx
+; X86-NEXT:    movl 4, %esi
+; X86-NEXT:    movl %esi, 4(%eax)
+; X86-NEXT:    movl %edx, (%eax)
+; X86-NEXT:    movw %cx, 8(%eax)
+; X86-NEXT:    popl %esi
+; X86-NEXT:    retl $4
+entry:
+  %r.real = load x86_fp80, ptr null, align 16
+  %.fca.0.insert = insertvalue { x86_fp80, x86_fp80 } zeroinitializer, x86_fp80 %r.real, 0
+  %.fca.1.insert = insertvalue { x86_fp80, x86_fp80 } %.fca.0.insert, x86_fp80 undef, 1
+  ret { x86_fp80, x86_fp80 } %.fca.1.insert
+}
+
+attributes #0 = { nounwind "target-features"="-x87" }

>From 1fffd8997f5c9f60bd3cd94a09ffabe59f6d59c9 Mon Sep 17 00:00:00 2001
From: Shiyas-N <muhammedshiyasn811 at gmail.com>
Date: Thu, 16 Jul 2026 07:25:51 +0000
Subject: [PATCH 2/5] Replace depricated undef with poison

---
 llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll b/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
index dd563bdd746f3..6bd5b69090cf2 100644
--- a/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
+++ b/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
@@ -58,7 +58,7 @@ define { x86_fp80, x86_fp80 } @test_struct_ret_f80() #0 {
 entry:
   %r.real = load x86_fp80, ptr null, align 16
   %.fca.0.insert = insertvalue { x86_fp80, x86_fp80 } zeroinitializer, x86_fp80 %r.real, 0
-  %.fca.1.insert = insertvalue { x86_fp80, x86_fp80 } %.fca.0.insert, x86_fp80 undef, 1
+  %.fca.1.insert = insertvalue { x86_fp80, x86_fp80 } %.fca.0.insert, x86_fp80 poison, 1
   ret { x86_fp80, x86_fp80 } %.fca.1.insert
 }
 

>From 8a58d5fcf414c2829afe8b3c8bb2843d682ea4c8 Mon Sep 17 00:00:00 2001
From: Shiyas-N <muhammedshiyasn811 at gmail.com>
Date: Thu, 16 Jul 2026 08:08:15 +0000
Subject: [PATCH 3/5] remove redundant load call,drop -mattr from the test

---
 .../SelectionDAG/LegalizeFloatTypes.cpp       | 19 +++++++++----------
 .../CodeGen/X86/x86-fp80-load-store-no-x87.ll |  4 ++--
 2 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 0c869e1b23778..94a074bf052f7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -1019,16 +1019,15 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_LOAD(SDNode *N) {
     // If softening widens the integer representation (e.g. x86_fp80 -> i96),
     // load the original memory width and extend to the softened type.
     EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits());
-    if (NVT.bitsGT(MemVT))
-      NewL = DAG.getLoad(L->getAddressingMode(), ISD::EXTLOAD, NVT, dl,
-                         L->getChain(), L->getBasePtr(), L->getOffset(),
-                         L->getPointerInfo(), MemVT, L->getBaseAlign(),
-                         MMOFlags, L->getAAInfo());
-    else
-      NewL = DAG.getLoad(L->getAddressingMode(), L->getExtensionType(), NVT, dl,
-                         L->getChain(), L->getBasePtr(), L->getOffset(),
-                         L->getPointerInfo(), NVT, L->getBaseAlign(), MMOFlags,
-                         L->getAAInfo());
+    ISD::LoadExtType ExtType = L->getExtensionType();
+    EVT LoadMemVT = NVT;
+    if (NVT.bitsGT(MemVT)) {
+      ExtType = ISD::EXTLOAD;
+      LoadMemVT = MemVT;
+    }
+    NewL = DAG.getLoad(L->getAddressingMode(), ExtType, NVT, dl, L->getChain(),
+                       L->getBasePtr(), L->getOffset(), L->getPointerInfo(),
+                       LoadMemVT, L->getBaseAlign(), MMOFlags, L->getAAInfo());
     // Legalized the chain result - switch anything that used the old chain to
     // use the new one.
     ReplaceValueWith(SDValue(N, 1), NewL.getValue(1));
diff --git a/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll b/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
index 6bd5b69090cf2..21dc22cb31596 100644
--- a/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
+++ b/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mattr=-x87 | FileCheck %s --check-prefix=X64
-; RUN: llc < %s -mtriple=i686-unknown-linux-gnu -mattr=-x87 | FileCheck %s --check-prefix=X86
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefix=X64
+; RUN: llc < %s -mtriple=i686-unknown-linux-gnu | FileCheck %s --check-prefix=X86
 
 ; Verify that x86_fp80 load/store legalization handles widened softened types
 ; correctly when x87 is disabled.

>From c8901f6f9816b815cb6f8031c7c4cc2fa512e89a Mon Sep 17 00:00:00 2001
From: Shiyas-N <muhammedshiyasn811 at gmail.com>
Date: Wed, 5 Aug 2026 12:40:29 +0000
Subject: [PATCH 4/5] Remove unnecessary label from test file

---
 llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll b/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
index 21dc22cb31596..e6dc0369928b2 100644
--- a/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
+++ b/llvm/test/CodeGen/X86/x86-fp80-load-store-no-x87.ll
@@ -35,7 +35,7 @@ define void @test_load_store_f80(ptr %p, ptr %q) #0 {
 ; x87 disabled.
 define { x86_fp80, x86_fp80 } @test_struct_ret_f80() #0 {
 ; X64-LABEL: test_struct_ret_f80:
-; X64:       # %bb.0: # %entry
+; X64:       # %bb.0:
 ; X64-NEXT:    movq %rdi, %rax
 ; X64-NEXT:    movl 8, %ecx
 ; X64-NEXT:    movq 0, %rdx
@@ -44,7 +44,7 @@ define { x86_fp80, x86_fp80 } @test_struct_ret_f80() #0 {
 ; X64-NEXT:    retq
 ;
 ; X86-LABEL: test_struct_ret_f80:
-; X86:       # %bb.0: # %entry
+; X86:       # %bb.0:
 ; X86-NEXT:    pushl %esi
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
 ; X86-NEXT:    movl 8, %ecx
@@ -55,7 +55,6 @@ define { x86_fp80, x86_fp80 } @test_struct_ret_f80() #0 {
 ; X86-NEXT:    movw %cx, 8(%eax)
 ; X86-NEXT:    popl %esi
 ; X86-NEXT:    retl $4
-entry:
   %r.real = load x86_fp80, ptr null, align 16
   %.fca.0.insert = insertvalue { x86_fp80, x86_fp80 } zeroinitializer, x86_fp80 %r.real, 0
   %.fca.1.insert = insertvalue { x86_fp80, x86_fp80 } %.fca.0.insert, x86_fp80 poison, 1

>From f4cc264567283115296067b4571876e1eb8a42de Mon Sep 17 00:00:00 2001
From: Shiyas-N <muhammedshiyasn811 at gmail.com>
Date: Thu, 20 Aug 2026 18:36:07 +0000
Subject: [PATCH 5/5] simplified calls to remove redundant checks

---
 .../SelectionDAG/LegalizeFloatTypes.cpp       | 20 ++++++-------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 94a074bf052f7..5ddc4df11122c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -1019,15 +1019,10 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_LOAD(SDNode *N) {
     // If softening widens the integer representation (e.g. x86_fp80 -> i96),
     // load the original memory width and extend to the softened type.
     EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits());
-    ISD::LoadExtType ExtType = L->getExtensionType();
-    EVT LoadMemVT = NVT;
-    if (NVT.bitsGT(MemVT)) {
-      ExtType = ISD::EXTLOAD;
-      LoadMemVT = MemVT;
-    }
-    NewL = DAG.getLoad(L->getAddressingMode(), ExtType, NVT, dl, L->getChain(),
-                       L->getBasePtr(), L->getOffset(), L->getPointerInfo(),
-                       LoadMemVT, L->getBaseAlign(), MMOFlags, L->getAAInfo());
+    NewL = DAG.getLoad(L->getAddressingMode(), ISD::EXTLOAD, NVT, dl,
+                       L->getChain(), L->getBasePtr(), L->getOffset(),
+                       L->getPointerInfo(), MemVT, L->getBaseAlign(), MMOFlags,
+                       L->getAAInfo());
     // Legalized the chain result - switch anything that used the old chain to
     // use the new one.
     ReplaceValueWith(SDValue(N, 1), NewL.getValue(1));
@@ -1435,11 +1430,8 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_STORE(SDNode *N, unsigned OpNo) {
   // truncate the value before storing to preserve the original memory width.
   EVT MemVT =
       EVT::getIntegerVT(*DAG.getContext(), ST->getMemoryVT().getSizeInBits());
-  if (Val.getValueType().bitsGT(MemVT))
-    return DAG.getTruncStore(ST->getChain(), dl, Val, ST->getBasePtr(), MemVT,
-                             ST->getMemOperand());
-  return DAG.getStore(ST->getChain(), dl, Val, ST->getBasePtr(),
-                      ST->getMemOperand());
+  return DAG.getTruncStore(ST->getChain(), dl, Val, ST->getBasePtr(), MemVT,
+                           ST->getMemOperand());
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatOp_ATOMIC_STORE(SDNode *N, unsigned OpNo) {



More information about the llvm-commits mailing list