[llvm] [llvm] Don't combine repeated subnormal divisors (PR #149333)

Asher Mancinelli via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 17 17:56:24 PDT 2025


https://github.com/ashermancinelli updated https://github.com/llvm/llvm-project/pull/149333

>From f24da99fcc6aaa6efb56f63326bd73d6505d8bff Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Wed, 16 Jul 2025 17:25:54 -0700
Subject: [PATCH 1/3] [llvm] Don't combine repeated fp divisors with subnormals

DAGCombiner performs this rewrite:
(a / D; b / D;) -> (recip = 1.0 / D; a * recip; b * recip)

However, when D is subnormal, this produces a*inf and b*inf.
With fast-math flags enabled, this creates poisons that break
the rewritten consumers. Guard this transformation with checks
for subnormal operands.
---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 10 +++++++++
 .../X86/repeated-fp-divisors-denorm.ll        | 22 +++++++++++++++++++
 2 files changed, 32 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 0e8e4c9618bb2..2c810c2b885d3 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -18235,6 +18235,16 @@ SDValue DAGCombiner::combineRepeatedFPDivisors(SDNode *N) {
   if (N0CFP && (N0CFP->isExactlyValue(1.0) || N0CFP->isExactlyValue(-1.0)))
     return SDValue();
 
+  // Skip if we have subnormals, multiplying with the reciprocal will introduce
+  // infinities.
+  ConstantFPSDNode *N1CFP = isConstOrConstSplatFP(N1, /* AllowUndefs */ true);
+  if (N1CFP) {
+    FPClassTest FPClass = N1CFP->getValueAPF().classify();
+    if (FPClass == fcPosSubnormal || FPClass == fcNegSubnormal) {
+      return SDValue();
+    }
+  }
+
   // Exit early if the target does not want this transform or if there can't
   // possibly be enough uses of the divisor to make the transform worthwhile.
   unsigned MinUses = TLI.combineRepeatedFPDivisors();
diff --git a/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll b/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll
new file mode 100644
index 0000000000000..59246068b3597
--- /dev/null
+++ b/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=x86_64 -verify-machineinstrs < %s | FileCheck %s
+
+; Negative test: repeated FP divisor transform should bail out when the rewrite
+; would introduce infinities because of subnormal constant divisors.
+define void @two_denorm_fdivs(float %a0, float %a1, float %a2, ptr %res) {
+; CHECK-LABEL: two_denorm_fdivs:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movss {{.*#+}} xmm0 = [1.95915678E-39,0.0E+0,0.0E+0,0.0E+0]
+; CHECK-NEXT:    divss %xmm0, %xmm1
+; CHECK-NEXT:    movss %xmm1, (%rdi)
+; CHECK-NEXT:    divss %xmm0, %xmm2
+; CHECK-NEXT:    movss %xmm2, 4(%rdi)
+; CHECK-NEXT:    retq
+entry:
+  %div0 = fdiv ninf float %a1, 0x37E5555500000000
+  store float %div0, ptr %res
+  %ptr1 = getelementptr inbounds float, ptr %res, i64 1
+  %div1 = fdiv ninf float %a2, 0x37E5555500000000
+  store float %div1, ptr %ptr1
+  ret void
+}

>From 0963938b577228b4007966e17d1ec9feab0e042d Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Thu, 17 Jul 2025 14:35:36 -0700
Subject: [PATCH 2/3] Add arcp fmf to test case

---
 llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll b/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll
index 59246068b3597..fbb9a5ce27ec1 100644
--- a/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll
+++ b/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll
@@ -13,10 +13,10 @@ define void @two_denorm_fdivs(float %a0, float %a1, float %a2, ptr %res) {
 ; CHECK-NEXT:    movss %xmm2, 4(%rdi)
 ; CHECK-NEXT:    retq
 entry:
-  %div0 = fdiv ninf float %a1, 0x37E5555500000000
+  %div0 = fdiv arcp float %a1, 0x37E5555500000000
   store float %div0, ptr %res
   %ptr1 = getelementptr inbounds float, ptr %res, i64 1
-  %div1 = fdiv ninf float %a2, 0x37E5555500000000
+  %div1 = fdiv arcp float %a2, 0x37E5555500000000
   store float %div1, ptr %ptr1
   ret void
 }

>From b08bd7a78353a5e8771adfdd3daa41f081e145c3 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Thu, 17 Jul 2025 17:56:10 -0700
Subject: [PATCH 3/3] remove instr verification

---
 llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll b/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll
index fbb9a5ce27ec1..a6987de790e41 100644
--- a/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll
+++ b/llvm/test/CodeGen/X86/repeated-fp-divisors-denorm.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=x86_64 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=x86_64 < %s | FileCheck %s
 
 ; Negative test: repeated FP divisor transform should bail out when the rewrite
 ; would introduce infinities because of subnormal constant divisors.



More information about the llvm-commits mailing list