[llvm] [KnownFPClass] Infer signs of finite nonzero fdiv results (PR #214912)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 7 19:01:02 PDT 2026


https://github.com/ZERICO2005 created https://github.com/llvm/llvm-project/pull/214912

None

>From 389182cb4c2dedd50f47045b0e5f87d12da1b2cc Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Fri, 7 Aug 2026 19:57:05 -0600
Subject: [PATCH] [KnownFPClass] Infer signs of finite nonzero fdiv results

---
 llvm/lib/Analysis/ValueTracking.cpp           | 27 +++---
 .../CodeGen/GlobalISel/GISelValueTracking.cpp | 25 ++++--
 llvm/lib/Support/KnownFPClass.cpp             | 12 +++
 .../Transforms/Attributor/nofpclass-fdiv.ll   | 22 ++---
 .../Attributor/nofpclass-inv-sqrt.ll          | 76 +++++++++++++++++
 .../CodeGen/GlobalISel/KnownFPClassTest.cpp   | 84 +++++++++++++++++++
 6 files changed, 216 insertions(+), 30 deletions(-)
 create mode 100644 llvm/test/Transforms/Attributor/nofpclass-inv-sqrt.ll

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 44a1240f5635a..dd4d91747c959 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5914,22 +5914,29 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
     }
 
     const bool WantNegative = (InterestedClasses & fcNegative) != fcNone;
-    const bool WantPositive =
-        Opc == Instruction::FRem && (InterestedClasses & fcPositive) != fcNone;
+    const bool WantPositive = (InterestedClasses & fcPositive) != fcNone;
     if (!WantNan && !WantNegative && !WantPositive)
       break;
 
     KnownFPClass KnownLHS, KnownRHS;
+    const bool IsFDiv = Opc == Instruction::FDiv;
+    FPClassTest InterestedRHS =
+        IsFDiv ? fcAllFlags : fcNan | fcInf | fcZero | fcNegative;
 
-    computeKnownFPClass(Op->getOperand(1), DemandedElts,
-                        fcNan | fcInf | fcZero | fcNegative, KnownRHS, Q,
-                        Depth + 1);
+    computeKnownFPClass(Op->getOperand(1), DemandedElts, InterestedRHS,
+                        KnownRHS, Q, Depth + 1);
 
-    bool KnowSomethingUseful = KnownRHS.isKnownNeverNaN() ||
-                               KnownRHS.isKnownNever(fcNegative) ||
-                               KnownRHS.isKnownNever(fcPositive);
+    bool KnowSomethingUseful = KnownRHS.isKnownNeverNaN();
+    if (IsFDiv) {
+      KnowSomethingUseful |=
+          KnownRHS.isKnownNever(fcNegNormal | fcNegSubnormal) ||
+          KnownRHS.isKnownNever(fcPosNormal | fcPosSubnormal);
+    } else {
+      KnowSomethingUseful |= KnownRHS.isKnownNever(fcNegative) ||
+                             KnownRHS.isKnownNever(fcPositive);
+    }
 
-    if (KnowSomethingUseful || WantPositive) {
+    if (KnowSomethingUseful || (!IsFDiv && WantPositive)) {
       computeKnownFPClass(Op->getOperand(0), DemandedElts, fcAllFlags, KnownLHS,
                           Q, Depth + 1);
     }
@@ -5938,7 +5945,7 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
     const fltSemantics &FltSem =
         Op->getType()->getScalarType()->getFltSemantics();
 
-    if (Op->getOpcode() == Instruction::FDiv) {
+    if (IsFDiv) {
       DenormalMode Mode =
           F ? F->getDenormalMode(FltSem) : DenormalMode::getDynamic();
       Known = KnownFPClass::fdiv(KnownLHS, KnownRHS, Mode);
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 7ff23d8e1bd6e..d2aa5625ecbc6 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1751,26 +1751,33 @@ void GISelValueTracking::computeKnownFPClass(Register R,
 
     const bool WantNan = (InterestedClasses & fcNan) != fcNone;
     const bool WantNegative = (InterestedClasses & fcNegative) != fcNone;
-    const bool WantPositive = Opcode == TargetOpcode::G_FREM &&
-                              (InterestedClasses & fcPositive) != fcNone;
+    const bool WantPositive = (InterestedClasses & fcPositive) != fcNone;
     if (!WantNan && !WantNegative && !WantPositive) {
       break;
     }
 
     KnownFPClass KnownLHS, KnownRHS;
+    const bool IsFDiv = Opcode == TargetOpcode::G_FDIV;
+    FPClassTest InterestedRHS =
+        IsFDiv ? fcAllFlags : fcNan | fcInf | fcZero | fcNegative;
 
-    computeKnownFPClass(RHS, DemandedElts, fcNan | fcInf | fcZero | fcNegative,
-                        KnownRHS, Depth + 1);
+    computeKnownFPClass(RHS, DemandedElts, InterestedRHS, KnownRHS, Depth + 1);
 
-    bool KnowSomethingUseful = KnownRHS.isKnownNeverNaN() ||
-                               KnownRHS.isKnownNever(fcNegative) ||
-                               KnownRHS.isKnownNever(fcPositive);
+    bool KnowSomethingUseful = KnownRHS.isKnownNeverNaN();
+    if (IsFDiv) {
+      KnowSomethingUseful |=
+          KnownRHS.isKnownNever(fcNegNormal | fcNegSubnormal) ||
+          KnownRHS.isKnownNever(fcPosNormal | fcPosSubnormal);
+    } else {
+      KnowSomethingUseful |= KnownRHS.isKnownNever(fcNegative) ||
+                             KnownRHS.isKnownNever(fcPositive);
+    }
 
-    if (KnowSomethingUseful || WantPositive) {
+    if (KnowSomethingUseful || (!IsFDiv && WantPositive)) {
       computeKnownFPClass(LHS, DemandedElts, fcAllFlags, KnownLHS, Depth + 1);
     }
 
-    if (Opcode == TargetOpcode::G_FDIV) {
+    if (IsFDiv) {
       Known = KnownFPClass::fdiv(KnownLHS, KnownRHS, Mode);
     } else {
       // Inf REM x and x REM 0 produce NaN.
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index eccd83451a05f..545b7bd6af0b6 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -434,6 +434,18 @@ KnownFPClass KnownFPClass::fdiv(const KnownFPClass &KnownLHS,
   // +X / -Y or -X / +Y => -Q
   Known.propagateXorSign(KnownLHS, KnownRHS);
 
+  // Normal and subnormal results require two non-zero finite operands.
+  if ((KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal) &&
+       KnownRHS.isKnownNever(fcNegNormal | fcNegSubnormal)) ||
+      (KnownLHS.isKnownNever(fcPosNormal | fcPosSubnormal) &&
+       KnownRHS.isKnownNever(fcPosNormal | fcPosSubnormal)))
+    Known.knownNot(fcNegNormal | fcNegSubnormal);
+  if ((KnownLHS.isKnownNever(fcNegNormal | fcNegSubnormal) &&
+       KnownRHS.isKnownNever(fcPosNormal | fcPosSubnormal)) ||
+      (KnownLHS.isKnownNever(fcPosNormal | fcPosSubnormal) &&
+       KnownRHS.isKnownNever(fcNegNormal | fcNegSubnormal)))
+    Known.knownNot(fcPosNormal | fcPosSubnormal);
+
   // 0 / X => 0 or NaN
   if (KnownLHS.isKnownAlways(fcZero))
     Known.knownNot(fcSubnormal | fcNormal | fcInf);
diff --git a/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll b/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll
index fef871a1e85f7..f49b13d7b3f78 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-fdiv.ll
@@ -509,7 +509,7 @@ define float @ret_fdiv_no_neg_nzero_rhs(float %arg0, float nofpclass(ninf nsub n
 }
 
 define float @ret_fdiv_no_neg(float nofpclass(ninf nsub nnorm) %arg0, float nofpclass(ninf nsub nnorm) %arg1) #0 {
-; CHECK-LABEL: define float @ret_fdiv_no_neg
+; CHECK-LABEL: define nofpclass(nsub nnorm) float @ret_fdiv_no_neg
 ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -529,7 +529,7 @@ define float @ret_fdiv_no_neg_nzero(float nofpclass(ninf nsub nnorm nzero) %arg0
 }
 
 define float @ret_fdiv_no_neg_rhs_no_nzero(float nofpclass(ninf nsub nnorm) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) #0 {
-; CHECK-LABEL: define float @ret_fdiv_no_neg_rhs_no_nzero
+; CHECK-LABEL: define nofpclass(nsub nnorm) float @ret_fdiv_no_neg_rhs_no_nzero
 ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -569,7 +569,7 @@ define float @ret_fdiv_no_pos_rhs(float %arg0, float nofpclass(pinf psub pnorm)
 }
 
 define float @ret_fdiv_no_pos(float nofpclass(pinf psub pnorm) %arg0, float nofpclass(pinf psub pnorm) %arg1) #0 {
-; CHECK-LABEL: define float @ret_fdiv_no_pos
+; CHECK-LABEL: define nofpclass(nsub nnorm) float @ret_fdiv_no_pos
 ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG0:%.*]], float nofpclass(pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -802,7 +802,7 @@ define float @ret_known_inf_or_nan_fdiv_known_zero(float nofpclass(norm sub zero
 
 ; -> nan
 define float @ret_known_inf_fdiv_known_zero_or_nan(float nofpclass(nan norm sub zero) %arg0, float nofpclass(inf norm sub) %arg1) {
-; CHECK-LABEL: define float @ret_known_inf_fdiv_known_zero_or_nan
+; CHECK-LABEL: define nofpclass(sub norm) float @ret_known_inf_fdiv_known_zero_or_nan
 ; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float nofpclass(inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -846,7 +846,7 @@ define float @ret_known_zero_fdiv_known_inf(float nofpclass(nan inf norm sub) %a
 
 ; -> zero
 define float @ret_known_zero_fdiv_known_inf_or_nan(float nofpclass(nan inf norm sub) %arg0, float nofpclass(norm sub zero) %arg1) {
-; CHECK-LABEL: define float @ret_known_zero_fdiv_known_inf_or_nan
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_known_zero_fdiv_known_inf_or_nan
 ; CHECK-SAME: (float nofpclass(nan inf sub norm) [[ARG0:%.*]], float nofpclass(zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -857,7 +857,7 @@ define float @ret_known_zero_fdiv_known_inf_or_nan(float nofpclass(nan inf norm
 
 ; -> zero or nan
 define float @ret_known_zero_or_nan_fdiv_known_inf(float nofpclass(inf norm sub) %arg0, float nofpclass(nan norm sub zero) %arg1) {
-; CHECK-LABEL: define float @ret_known_zero_or_nan_fdiv_known_inf
+; CHECK-LABEL: define nofpclass(sub norm) float @ret_known_zero_or_nan_fdiv_known_inf
 ; CHECK-SAME: (float nofpclass(inf sub norm) [[ARG0:%.*]], float nofpclass(nan zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -962,7 +962,7 @@ define float @ret_fdiv_rhs_negative_lhs_positive(float %lhs, float %rhs) {
 
 ; Could be inf of either sign
 define float @ret_known_inf_fdiv_known_inf(float nofpclass(norm sub zero nan) %arg0, float nofpclass(norm sub zero nan) %arg1) {
-; CHECK-LABEL: define float @ret_known_inf_fdiv_known_inf
+; CHECK-LABEL: define nofpclass(sub norm) float @ret_known_inf_fdiv_known_inf
 ; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float nofpclass(nan zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -973,7 +973,7 @@ define float @ret_known_inf_fdiv_known_inf(float nofpclass(norm sub zero nan) %a
 
 ; Could be inf of either sign, or nan
 define float @ret_known_inf_fdiv_known_inf_or_nan(float nofpclass(norm sub zero nan) %arg0, float nofpclass(norm sub zero) %arg1) {
-; CHECK-LABEL: define float @ret_known_inf_fdiv_known_inf_or_nan
+; CHECK-LABEL: define nofpclass(sub norm) float @ret_known_inf_fdiv_known_inf_or_nan
 ; CHECK-SAME: (float nofpclass(nan zero sub norm) [[ARG0:%.*]], float nofpclass(zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -984,7 +984,7 @@ define float @ret_known_inf_fdiv_known_inf_or_nan(float nofpclass(norm sub zero
 
 ; Could be inf of either sign, or nan
 define float @ret_known_inf_or_nan_fdiv_known_inf(float nofpclass(norm sub zero) %arg0, float nofpclass(norm sub zero nan) %arg1) {
-; CHECK-LABEL: define float @ret_known_inf_or_nan_fdiv_known_inf
+; CHECK-LABEL: define nofpclass(sub norm) float @ret_known_inf_or_nan_fdiv_known_inf
 ; CHECK-SAME: (float nofpclass(zero sub norm) [[ARG0:%.*]], float nofpclass(nan zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -1006,7 +1006,7 @@ define float @ret_known_zero_fdiv_known_zero(float nofpclass(inf norm sub nan) %
 
 ; Could be zero of either sign, or nan
 define float @ret_known_zero_fdiv_known_zero_or_nan(float nofpclass(inf norm sub nan) %arg0, float nofpclass(inf norm sub) %arg1) {
-; CHECK-LABEL: define float @ret_known_zero_fdiv_known_zero_or_nan
+; CHECK-LABEL: define nofpclass(inf sub norm) float @ret_known_zero_fdiv_known_zero_or_nan
 ; CHECK-SAME: (float nofpclass(nan inf sub norm) [[ARG0:%.*]], float nofpclass(inf sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
@@ -1047,7 +1047,7 @@ define float @ret_unknown_fdiv_known_inf_or_nan(float %arg0, float nofpclass(nor
 }
 
 define float @ret_known_inf_or_nan_fdiv_known_inf_or_nan(float nofpclass(norm sub zero) %arg0, float nofpclass(norm sub zero) %arg1) {
-; CHECK-LABEL: define float @ret_known_inf_or_nan_fdiv_known_inf_or_nan
+; CHECK-LABEL: define nofpclass(sub norm) float @ret_known_inf_or_nan_fdiv_known_inf_or_nan
 ; CHECK-SAME: (float nofpclass(zero sub norm) [[ARG0:%.*]], float nofpclass(zero sub norm) [[ARG1:%.*]]) #[[ATTR4]] {
 ; CHECK-NEXT:    [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]]
 ; CHECK-NEXT:    ret float [[FDIV]]
diff --git a/llvm/test/Transforms/Attributor/nofpclass-inv-sqrt.ll b/llvm/test/Transforms/Attributor/nofpclass-inv-sqrt.ll
new file mode 100644
index 0000000000000..d580f74abea73
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-inv-sqrt.ll
@@ -0,0 +1,76 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -S < %s | FileCheck %s
+
+declare float @llvm.sqrt.f32(float)
+
+; The only negative value sqrt(x) can produce is -0.0, so the only negative
+; value 1.0 / sqrt(x) can produce is -Inf.
+define float @ret_inv_sqrt(float %x) {
+; CHECK-LABEL: define nofpclass(nsub nnorm) float @ret_inv_sqrt
+; CHECK-SAME: (float [[X:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT:    [[SQRT:%.*]] = call float @llvm.sqrt.f32(float [[X]]) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT:    [[INV_SQRT:%.*]] = fdiv float 1.000000e+00, [[SQRT]]
+; CHECK-NEXT:    ret float [[INV_SQRT]]
+;
+  %sqrt = call float @llvm.sqrt.f32(float %x)
+  %inv.sqrt = fdiv float 1.0, %sqrt
+  ret float %inv.sqrt
+}
+
+; Positive infinity and positive zero are impossible here. However, they are
+; reported as being possible because fdiv is not aware that the LHS is one.
+; fdiv only knows that it is computing the result of (normal / normal), which
+; may overflow to infinity or underflow to zero.
+define float @ret_inv_sqrt_x_not_infinity_not_zero(float nofpclass(inf zero) %x) {
+; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_inv_sqrt_x_not_infinity_not_zero
+; CHECK-SAME: (float nofpclass(inf zero) [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[SQRT:%.*]] = call float @llvm.sqrt.f32(float nofpclass(inf zero) [[X]]) #[[ATTR2]]
+; CHECK-NEXT:    [[INV_SQRT:%.*]] = fdiv float 1.000000e+00, [[SQRT]]
+; CHECK-NEXT:    ret float [[INV_SQRT]]
+;
+  %sqrt = call float @llvm.sqrt.f32(float nofpclass(inf zero) %x)
+  %inv.sqrt = fdiv float 1.0, %sqrt
+  ret float %inv.sqrt
+}
+
+; sqrt(1.0 / x) may produce -0.0 when x is -Inf, but cannot produce any other
+; negative value or a subnormal value.
+define float @ret_sqrt_inv(float %x) {
+; CHECK-LABEL: define nofpclass(ninf sub nnorm) float @ret_sqrt_inv
+; CHECK-SAME: (float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[INV:%.*]] = fdiv float 1.000000e+00, [[X]]
+; CHECK-NEXT:    [[SQRT_INV:%.*]] = call nofpclass(ninf sub nnorm) float @llvm.sqrt.f32(float [[INV]]) #[[ATTR2]]
+; CHECK-NEXT:    ret float [[SQRT_INV]]
+;
+  %inv = fdiv float 1.0, %x
+  %sqrt.inv = call float @llvm.sqrt.f32(float %inv)
+  ret float %sqrt.inv
+}
+
+define float @ret_sqrt_inv_not_infinity_not_zero(float nofpclass(inf zero) %x) {
+; CHECK-LABEL: define nofpclass(ninf sub nnorm) float @ret_sqrt_inv_not_infinity_not_zero
+; CHECK-SAME: (float nofpclass(inf zero) [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[INV:%.*]] = fdiv float 1.000000e+00, [[X]]
+; CHECK-NEXT:    [[SQRT_INV:%.*]] = call nofpclass(ninf sub nnorm) float @llvm.sqrt.f32(float [[INV]]) #[[ATTR2]]
+; CHECK-NEXT:    ret float [[SQRT_INV]]
+;
+  %inv = fdiv float 1.0, %x
+  %sqrt.inv = call float @llvm.sqrt.f32(float %inv)
+  ret float %sqrt.inv
+}
+
+; The only negative value sqrt(-x) can produce is -0.0, so the only positive
+; value -1.0 / sqrt(-x) can produce is +Inf.
+define float @ret_neg_inv_sqrt_neg(float %x) {
+; CHECK-LABEL: define nofpclass(psub pnorm) float @ret_neg_inv_sqrt_neg
+; CHECK-SAME: (float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[NEG_X:%.*]] = fneg float [[X]]
+; CHECK-NEXT:    [[SQRT:%.*]] = call float @llvm.sqrt.f32(float [[NEG_X]]) #[[ATTR2]]
+; CHECK-NEXT:    [[NEG_INV_SQRT:%.*]] = fdiv float -1.000000e+00, [[SQRT]]
+; CHECK-NEXT:    ret float [[NEG_INV_SQRT]]
+;
+  %neg.x = fneg float %x
+  %sqrt = call float @llvm.sqrt.f32(float %neg.x)
+  %neg.inv.sqrt = fdiv float -1.0, %sqrt
+  ret float %neg.inv.sqrt
+}
diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index 9e3ed2f159b6f..e63bcb2e58e62 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -1171,6 +1171,90 @@ TEST_F(AArch64GISelMITest, TestFPClassFDiv_Inf) {
   EXPECT_EQ(false, Known.SignBit);
 }
 
+TEST_F(AArch64GISelMITest, TestFPClassFDivSqrt) {
+  // The only negative value sqrt(x) can produce is -0.0, so the only negative
+  // value 1.0 / sqrt(x) can produce is -Inf.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %x:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %sqrt:_(s32) = G_FSQRT %x
+    %one:_(s32) = G_FCONSTANT float 1.0
+    %fdiv:_(s32) = G_FDIV %one, %sqrt
+    %copy_fdiv:_(s32) = COPY %fdiv
+)";
+
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+
+  EXPECT_EQ(fcAllFlags & ~(fcNegNormal | fcNegSubnormal),
+            Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFDivNegSqrtNeg) {
+  // The only negative value sqrt(-x) can produce is -0.0, so the only positive
+  // value -1.0 / sqrt(-x) can produce is +Inf.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %x:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %neg_x:_(s32) = G_FNEG %x
+    %sqrt:_(s32) = G_FSQRT %neg_x
+    %neg_one:_(s32) = G_FCONSTANT float -1.0
+    %fdiv:_(s32) = G_FDIV %neg_one, %sqrt
+    %copy_fdiv:_(s32) = COPY %fdiv
+)";
+
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg, fcPositive);
+
+  EXPECT_EQ(fcAllFlags & ~(fcPosNormal | fcPosSubnormal),
+            Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassSqrtFDiv) {
+  // sqrt(1.0 / x) may produce -0.0 when x is -Inf, but cannot produce any
+  // other negative value or a subnormal value.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %x:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %one:_(s32) = G_FCONSTANT float 1.0
+    %inv:_(s32) = G_FDIV %one, %x
+    %sqrt:_(s32) = G_FSQRT %inv
+    %copy_sqrt:_(s32) = COPY %sqrt
+)";
+
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+
+  EXPECT_EQ(fcNan | fcZero | fcPosNormal | fcPosInf, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
 TEST_F(AArch64GISelMITest, TestFPClassFRem) {
   StringRef MIRString = R"(
     %ptr:_(p0) = G_IMPLICIT_DEF



More information about the llvm-commits mailing list