[llvm] [DAG] Add ISD::FSQRT handling to computeKnownFPClass (PR #213620)

Varad Rahul Kamthe via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 4 01:51:26 PDT 2026


https://github.com/varadk27 updated https://github.com/llvm/llvm-project/pull/213620

>From 4863cde7f6a9e7f48802fcdecab6314071683ede Mon Sep 17 00:00:00 2001
From: Varad Kamthe <varadk.2704 at gmail.com>
Date: Mon, 3 Aug 2026 14:05:20 +0530
Subject: [PATCH 1/3] [DAG] Add ISD::FSQRT handling to computeKnownFPClass

Ports the ISD::FSQRT case from ValueTracking.cpp's computeKnownFPClass
to the SelectionDAG version, per #189583.

sqrt can never produce a negative normal or -infinity; with nnan set,
it also can't produce NaN. Unlike an earlier attempt (#195405), this
does not treat nsz as proof that the result can't be negative zero,
since nsz is a fast-math hint rather than a guarantee -- doing so risks
promoting a value to poison.

Fixes #189583
---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  19 +++
 .../CodeGen/RISCV/fold-is-fpclass-sqrt.ll     | 124 ++++++++++++++++++
 2 files changed, 143 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/fold-is-fpclass-sqrt.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 683cf2517b2f5..21f2727927e60 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6191,6 +6191,25 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
     Known.fneg();
     break;
   }
+  case ISD::FSQRT: {
+    FPClassTest InterestedSrcs = InterestedClasses;
+    if (InterestedClasses & fcNan)
+      InterestedSrcs |= KnownFPClass::OrderedLessThanZeroMask;
+
+    KnownFPClass KnownSrc = computeKnownFPClass(Op.getOperand(0), DemandedElts,
+                                                InterestedSrcs, Depth + 1);
+
+    const fltSemantics &FltSem =
+        Op.getValueType().getScalarType().getFltSemantics();
+    DenormalMode Mode = getMachineFunction().getDenormalMode(FltSem);
+
+    Known = KnownFPClass::sqrt(KnownSrc, Mode);
+
+    if (Op->getFlags().hasNoNaNs())
+      Known.knownNot(fcNan);
+
+    break;
+  }
   case ISD::BUILD_VECTOR: {
     assert(!VT.isScalableVector());
     bool First = true;
diff --git a/llvm/test/CodeGen/RISCV/fold-is-fpclass-sqrt.ll b/llvm/test/CodeGen/RISCV/fold-is-fpclass-sqrt.ll
new file mode 100644
index 0000000000000..9472259c62cc9
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/fold-is-fpclass-sqrt.ll
@@ -0,0 +1,124 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv64 -mattr=+f,+d,+v -target-abi=lp64d < %s | FileCheck %s
+
+define i1 @sqrt_nnan_check_f32(float %a0) {
+; CHECK-LABEL: sqrt_nnan_check_f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %sqr = call nnan float @llvm.sqrt.f32(float %a0)
+  %res = tail call i1 @llvm.is.fpclass.f32(float %sqr, i32 3)
+  ret i1 %res
+}
+
+define i1 @sqrt_neginf_f32(float %a0) {
+; CHECK-LABEL: sqrt_neginf_f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %sqr = call float @llvm.sqrt.f32(float %a0)
+  %res = tail call i1 @llvm.is.fpclass.f32(float %sqr, i32 4)
+  ret i1 %res
+}
+
+define i1 @sqrt_negnormal_f32(float %a0) {
+; CHECK-LABEL: sqrt_negnormal_f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %sqr = call float @llvm.sqrt.f32(float %a0)
+  %res = tail call i1 @llvm.is.fpclass.f32(float %sqr, i32 8)
+  ret i1 %res
+}
+
+define i1 @sqrt_nsz_negzero_f32(float %a0) {
+; CHECK-LABEL: sqrt_nsz_negzero_f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fsqrt.s fa5, fa0
+; CHECK-NEXT:    fclass.s a0, fa5
+; CHECK-NEXT:    slli a0, a0, 60
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    ret
+  %sqr = call nsz float @llvm.sqrt.f32(float %a0)
+  %res = tail call i1 @llvm.is.fpclass.f32(float %sqr, i32 32)
+  ret i1 %res
+}
+
+define i1 @sqrt_posinf_f32(float %a0) {
+; CHECK-LABEL: sqrt_posinf_f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fsqrt.s fa5, fa0
+; CHECK-NEXT:    fclass.s a0, fa5
+; CHECK-NEXT:    slli a0, a0, 56
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    ret
+  %sqr = call float @llvm.sqrt.f32(float %a0)
+  %res = tail call i1 @llvm.is.fpclass.f32(float %sqr, i32 512)
+  ret i1 %res
+}
+
+declare float @llvm.sqrt.f32(float)
+declare i1 @llvm.is.fpclass.f32(float, i32)
+
+declare <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float>)
+declare <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float>, i32)
+
+define <vscale x 2 x i1> @vsqrt_nnan_check_nxv2f32(<vscale x 2 x float> %a0) {
+; CHECK-LABEL: vsqrt_nnan_check_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %sqr = call nnan <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float> %a0)
+  %res = tail call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float> %sqr, i32 3)
+  ret <vscale x 2 x i1> %res
+}
+
+define <vscale x 2 x i1> @vsqrt_neginf_nxv2f32(<vscale x 2 x float> %a0) {
+; CHECK-LABEL: vsqrt_neginf_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %sqr = call <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float> %a0)
+  %res = tail call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float> %sqr, i32 4)
+  ret <vscale x 2 x i1> %res
+}
+
+define <vscale x 2 x i1> @vsqrt_negnormal_nxv2f32(<vscale x 2 x float> %a0) {
+; CHECK-LABEL: vsqrt_negnormal_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %sqr = call <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float> %a0)
+  %res = tail call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float> %sqr, i32 8)
+  ret <vscale x 2 x i1> %res
+}
+
+define <vscale x 2 x i1> @vsqrt_nsz_negzero_nxv2f32(<vscale x 2 x float> %a0) {
+; CHECK-LABEL: vsqrt_nsz_negzero_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT:    vfsqrt.v v8, v8
+; CHECK-NEXT:    vfclass.v v8, v8
+; CHECK-NEXT:    vmseq.vi v0, v8, 8
+; CHECK-NEXT:    ret
+  %sqr = call nsz <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float> %a0)
+  %res = tail call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float> %sqr, i32 32)
+  ret <vscale x 2 x i1> %res
+}
+
+define <vscale x 2 x i1> @vsqrt_posinf_nxv2f32(<vscale x 2 x float> %a0) {
+; CHECK-LABEL: vsqrt_posinf_nxv2f32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT:    vfsqrt.v v8, v8
+; CHECK-NEXT:    vfclass.v v8, v8
+; CHECK-NEXT:    li a0, 128
+; CHECK-NEXT:    vmseq.vx v0, v8, a0
+; CHECK-NEXT:    ret
+  %sqr = call <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float> %a0)
+  %res = tail call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float> %sqr, i32 512)
+  ret <vscale x 2 x i1> %res
+}

>From 2e568ef63d1faff311ada61274de6527478a1609 Mon Sep 17 00:00:00 2001
From: Varad Kamthe <varadk.2704 at gmail.com>
Date: Mon, 3 Aug 2026 16:52:48 +0530
Subject: [PATCH 2/3] [DAG] Move nnan/ninf flag handling into scope_exit,
 matching IR version

Per review feedback, replaces the manual nnan check in the FSQRT case
with a generic scope_exit-based mechanism applied before the switch,
mirroring ValueTracking.cpp's computeKnownFPClass.

Wraps the switch in an explicit nested block so the scope_exit
destructor runs before the function's return statement, rather than
racing NRVO -- without this, the flag-based exclusion could silently
fail to apply depending on whether the compiler elides the copy.

Diff looks larger than expected because wrapping the switch requires
reindenting the whole block; no logic inside the switch changed.
---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 329 +++++++++---------
 1 file changed, 170 insertions(+), 159 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 21f2727927e60..bd95f8ac4c16a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -20,6 +20,7 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Twine.h"
@@ -6178,186 +6179,196 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
   if (!DemandedElts)
     return Known;
 
-  unsigned Opcode = Op.getOpcode();
-  switch (Opcode) {
-  case ISD::POISON: {
-    Known.KnownFPClasses = fcNone;
-    Known.SignBit = false;
-    break;
-  }
-  case ISD::FNEG: {
-    Known = computeKnownFPClass(Op.getOperand(0), DemandedElts,
-                                InterestedClasses, Depth + 1);
-    Known.fneg();
-    break;
-  }
-  case ISD::FSQRT: {
-    FPClassTest InterestedSrcs = InterestedClasses;
-    if (InterestedClasses & fcNan)
-      InterestedSrcs |= KnownFPClass::OrderedLessThanZeroMask;
+  {
+    FPClassTest KnownNotFromFlags = fcNone;
+    if (Op->getFlags().hasNoNaNs())
+      KnownNotFromFlags |= fcNan;
+    if (Op->getFlags().hasNoInfs())
+      KnownNotFromFlags |= fcInf;
 
-    KnownFPClass KnownSrc = computeKnownFPClass(Op.getOperand(0), DemandedElts,
-                                                InterestedSrcs, Depth + 1);
+    llvm::scope_exit ClearClassesFromFlags(
+        [=, &Known] { Known.knownNot(KnownNotFromFlags); });
 
-    const fltSemantics &FltSem =
-        Op.getValueType().getScalarType().getFltSemantics();
-    DenormalMode Mode = getMachineFunction().getDenormalMode(FltSem);
+    unsigned Opcode = Op.getOpcode();
+    switch (Opcode) {
+    case ISD::POISON: {
+      Known.KnownFPClasses = fcNone;
+      Known.SignBit = false;
+      break;
+    }
+    case ISD::FNEG: {
+      Known = computeKnownFPClass(Op.getOperand(0), DemandedElts,
+                                  InterestedClasses, Depth + 1);
+      Known.fneg();
+      break;
+    }
+    case ISD::FSQRT: {
+      FPClassTest InterestedSrcs = InterestedClasses;
+      if (InterestedClasses & fcNan)
+        InterestedSrcs |= KnownFPClass::OrderedLessThanZeroMask;
 
-    Known = KnownFPClass::sqrt(KnownSrc, Mode);
+      KnownFPClass KnownSrc = computeKnownFPClass(
+          Op.getOperand(0), DemandedElts, InterestedSrcs, Depth + 1);
 
-    if (Op->getFlags().hasNoNaNs())
-      Known.knownNot(fcNan);
+      const fltSemantics &FltSem =
+          Op.getValueType().getScalarType().getFltSemantics();
+      DenormalMode Mode = getMachineFunction().getDenormalMode(FltSem);
 
-    break;
-  }
-  case ISD::BUILD_VECTOR: {
-    assert(!VT.isScalableVector());
-    bool First = true;
-    for (unsigned I = 0, E = Op.getNumOperands(); I != E; ++I) {
-      if (!DemandedElts[I])
-        continue;
+      Known = KnownFPClass::sqrt(KnownSrc, Mode);
+      break;
+    }
+    case ISD::BUILD_VECTOR: {
+      assert(!VT.isScalableVector());
+      bool First = true;
+      for (unsigned I = 0, E = Op.getNumOperands(); I != E; ++I) {
+        if (!DemandedElts[I])
+          continue;
+
+        if (First) {
+          Known = computeKnownFPClass(Op.getOperand(I), InterestedClasses,
+                                      Depth + 1);
+          First = false;
+        } else {
+          Known |= computeKnownFPClass(Op.getOperand(I), InterestedClasses,
+                                       Depth + 1);
+        }
 
-      if (First) {
-        Known =
-            computeKnownFPClass(Op.getOperand(I), InterestedClasses, Depth + 1);
-        First = false;
+        if (Known.isUnknown())
+          break;
+      }
+      break;
+    }
+    case ISD::EXTRACT_VECTOR_ELT: {
+      SDValue Src = Op.getOperand(0);
+      auto *CIdx = dyn_cast<ConstantSDNode>(Op.getOperand(1));
+      EVT SrcVT = Src.getValueType();
+      if (SrcVT.isFixedLengthVector() && CIdx) {
+        if (CIdx->getAPIntValue().ult(SrcVT.getVectorNumElements())) {
+          APInt DemandedSrcElts = APInt::getOneBitSet(
+              SrcVT.getVectorNumElements(), CIdx->getZExtValue());
+          Known = computeKnownFPClass(Src, DemandedSrcElts, InterestedClasses,
+                                      Depth + 1);
+        } else {
+          // Out of bounds index is poison.
+          Known.KnownFPClasses = fcNone;
+        }
       } else {
-        Known |=
-            computeKnownFPClass(Op.getOperand(I), InterestedClasses, Depth + 1);
+        Known = computeKnownFPClass(Src, InterestedClasses, Depth + 1);
       }
-
-      if (Known.isUnknown())
+      break;
+    }
+    case ISD::SPLAT_VECTOR: {
+      Known =
+          computeKnownFPClass(Op.getOperand(0), InterestedClasses, Depth + 1);
+      break;
+    }
+    case ISD::BITCAST: {
+      // FIXME: It should not be necessary to check for an elementwise bitcast.
+      // If a bitcast is not elementwise between vector / scalar types,
+      // computeKnownBits already splices the known bits of the source elements
+      // appropriately so as to line up with the bits of the result's demanded
+      // elements.
+      EVT SrcVT = Op.getOperand(0).getValueType();
+      if (VT.isScalableVector() || SrcVT.isScalableVector())
+        break;
+      unsigned VTNumElts = VT.isVector() ? VT.getVectorNumElements() : 1;
+      unsigned SrcVTNumElts =
+          SrcVT.isVector() ? SrcVT.getVectorNumElements() : 1;
+      if (VTNumElts != SrcVTNumElts)
         break;
+
+      KnownBits Bits = computeKnownBits(Op, DemandedElts, Depth + 1);
+      Known = KnownFPClass::bitcast(VT.getFltSemantics(), Bits);
+      break;
     }
-    break;
-  }
-  case ISD::EXTRACT_VECTOR_ELT: {
-    SDValue Src = Op.getOperand(0);
-    auto *CIdx = dyn_cast<ConstantSDNode>(Op.getOperand(1));
-    EVT SrcVT = Src.getValueType();
-    if (SrcVT.isFixedLengthVector() && CIdx) {
-      if (CIdx->getAPIntValue().ult(SrcVT.getVectorNumElements())) {
-        APInt DemandedSrcElts = APInt::getOneBitSet(
-            SrcVT.getVectorNumElements(), CIdx->getZExtValue());
+    case ISD::FABS: {
+      Known = computeKnownFPClass(Op.getOperand(0), DemandedElts,
+                                  InterestedClasses, Depth + 1);
+      Known.fabs();
+      break;
+    }
+    case ISD::FCOPYSIGN: {
+      Known = computeKnownFPClass(Op.getOperand(0), DemandedElts,
+                                  InterestedClasses, Depth + 1);
+      KnownFPClass KnownSign = computeKnownFPClass(
+          Op.getOperand(1), DemandedElts, InterestedClasses, Depth + 1);
+      Known.copysign(KnownSign);
+      break;
+    }
+    case ISD::AssertNoFPClass: {
+      Known = computeKnownFPClass(Op.getOperand(0), DemandedElts,
+                                  InterestedClasses, Depth + 1);
+      FPClassTest AssertedClasses =
+          static_cast<FPClassTest>(Op->getConstantOperandVal(1));
+      Known.KnownFPClasses &= ~AssertedClasses;
+      break;
+    }
+    case ISD::EXTRACT_SUBVECTOR: {
+      SDValue Src = Op.getOperand(0);
+      EVT SrcVT = Src.getValueType();
+      if (SrcVT.isFixedLengthVector()) {
+        unsigned Idx = Op.getConstantOperandVal(1);
+        unsigned NumSrcElts = SrcVT.getVectorNumElements();
+
+        APInt DemandedSrcElts = DemandedElts.zextOrTrunc(NumSrcElts).shl(Idx);
         Known = computeKnownFPClass(Src, DemandedSrcElts, InterestedClasses,
                                     Depth + 1);
       } else {
-        // Out of bounds index is poison.
-        Known.KnownFPClasses = fcNone;
+        Known = computeKnownFPClass(Src, InterestedClasses, Depth + 1);
       }
-    } else {
-      Known = computeKnownFPClass(Src, InterestedClasses, Depth + 1);
+      break;
     }
-    break;
-  }
-  case ISD::SPLAT_VECTOR: {
-    Known = computeKnownFPClass(Op.getOperand(0), InterestedClasses, Depth + 1);
-    break;
-  }
-  case ISD::BITCAST: {
-    // FIXME: It should not be necessary to check for an elementwise bitcast.
-    // If a bitcast is not elementwise between vector / scalar types,
-    // computeKnownBits already splices the known bits of the source elements
-    // appropriately so as to line up with the bits of the result's demanded
-    // elements.
-    EVT SrcVT = Op.getOperand(0).getValueType();
-    if (VT.isScalableVector() || SrcVT.isScalableVector())
+    case ISD::INSERT_SUBVECTOR: {
+      SDValue BaseVector = Op.getOperand(0);
+      SDValue SubVector = Op.getOperand(1);
+      EVT BaseVT = BaseVector.getValueType();
+      if (BaseVT.isFixedLengthVector()) {
+        unsigned Idx = Op.getConstantOperandVal(2);
+        unsigned NumBaseElts = BaseVT.getVectorNumElements();
+        unsigned NumSubElts = SubVector.getValueType().getVectorNumElements();
+
+        APInt DemandedMask =
+            APInt::getBitsSet(NumBaseElts, Idx, Idx + NumSubElts);
+        APInt DemandedSrcElts = DemandedElts & ~DemandedMask;
+        APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, Idx);
+
+        if (!DemandedSrcElts.isZero())
+          Known = computeKnownFPClass(BaseVector, DemandedSrcElts,
+                                      InterestedClasses, Depth + 1);
+        if (!DemandedSubElts.isZero()) {
+          KnownFPClass SubKnown = computeKnownFPClass(
+              SubVector, DemandedSubElts, InterestedClasses, Depth + 1);
+          Known = DemandedSrcElts.isZero() ? SubKnown : (Known | SubKnown);
+        }
+      } else {
+        Known = computeKnownFPClass(SubVector, InterestedClasses, Depth + 1);
+        if (!Known.isUnknown())
+          Known |=
+              computeKnownFPClass(BaseVector, InterestedClasses, Depth + 1);
+      }
       break;
-    unsigned VTNumElts = VT.isVector() ? VT.getVectorNumElements() : 1;
-    unsigned SrcVTNumElts = SrcVT.isVector() ? SrcVT.getVectorNumElements() : 1;
-    if (VTNumElts != SrcVTNumElts)
+    }
+    case ISD::SELECT:
+    case ISD::VSELECT: {
+      // TODO: Add adjustKnownFPClassForSelectArm clamp recognition as in
+      // IR-level ValueTracking.
+      KnownFPClass KnownFalseClass = computeKnownFPClass(
+          Op.getOperand(2), DemandedElts, InterestedClasses, Depth + 1);
+      if (KnownFalseClass.isUnknown())
+        break;
+      KnownFPClass KnownTrueClass = computeKnownFPClass(
+          Op.getOperand(1), DemandedElts, InterestedClasses, Depth + 1);
+      Known = KnownTrueClass.intersectWith(KnownFalseClass);
       break;
-
-    KnownBits Bits = computeKnownBits(Op, DemandedElts, Depth + 1);
-    Known = KnownFPClass::bitcast(VT.getFltSemantics(), Bits);
-    break;
-  }
-  case ISD::FABS: {
-    Known = computeKnownFPClass(Op.getOperand(0), DemandedElts,
-                                InterestedClasses, Depth + 1);
-    Known.fabs();
-    break;
-  }
-  case ISD::FCOPYSIGN: {
-    Known = computeKnownFPClass(Op.getOperand(0), DemandedElts,
-                                InterestedClasses, Depth + 1);
-    KnownFPClass KnownSign = computeKnownFPClass(Op.getOperand(1), DemandedElts,
-                                                 InterestedClasses, Depth + 1);
-    Known.copysign(KnownSign);
-    break;
-  }
-  case ISD::AssertNoFPClass: {
-    Known = computeKnownFPClass(Op.getOperand(0), DemandedElts,
-                                InterestedClasses, Depth + 1);
-    FPClassTest AssertedClasses =
-        static_cast<FPClassTest>(Op->getConstantOperandVal(1));
-    Known.KnownFPClasses &= ~AssertedClasses;
-    break;
-  }
-  case ISD::EXTRACT_SUBVECTOR: {
-    SDValue Src = Op.getOperand(0);
-    EVT SrcVT = Src.getValueType();
-    if (SrcVT.isFixedLengthVector()) {
-      unsigned Idx = Op.getConstantOperandVal(1);
-      unsigned NumSrcElts = SrcVT.getVectorNumElements();
-
-      APInt DemandedSrcElts = DemandedElts.zextOrTrunc(NumSrcElts).shl(Idx);
-      Known = computeKnownFPClass(Src, DemandedSrcElts, InterestedClasses,
-                                  Depth + 1);
-    } else {
-      Known = computeKnownFPClass(Src, InterestedClasses, Depth + 1);
     }
-    break;
-  }
-  case ISD::INSERT_SUBVECTOR: {
-    SDValue BaseVector = Op.getOperand(0);
-    SDValue SubVector = Op.getOperand(1);
-    EVT BaseVT = BaseVector.getValueType();
-    if (BaseVT.isFixedLengthVector()) {
-      unsigned Idx = Op.getConstantOperandVal(2);
-      unsigned NumBaseElts = BaseVT.getVectorNumElements();
-      unsigned NumSubElts = SubVector.getValueType().getVectorNumElements();
-
-      APInt DemandedMask =
-          APInt::getBitsSet(NumBaseElts, Idx, Idx + NumSubElts);
-      APInt DemandedSrcElts = DemandedElts & ~DemandedMask;
-      APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, Idx);
-
-      if (!DemandedSrcElts.isZero())
-        Known = computeKnownFPClass(BaseVector, DemandedSrcElts,
-                                    InterestedClasses, Depth + 1);
-      if (!DemandedSubElts.isZero()) {
-        KnownFPClass SubKnown = computeKnownFPClass(
-            SubVector, DemandedSubElts, InterestedClasses, Depth + 1);
-        Known = DemandedSrcElts.isZero() ? SubKnown : (Known | SubKnown);
+    default:
+      if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
+          Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
+        TLI->computeKnownFPClassForTargetNode(Op, Known, DemandedElts, *this,
+                                              Depth);
       }
-    } else {
-      Known = computeKnownFPClass(SubVector, InterestedClasses, Depth + 1);
-      if (!Known.isUnknown())
-        Known |= computeKnownFPClass(BaseVector, InterestedClasses, Depth + 1);
-    }
-    break;
-  }
-  case ISD::SELECT:
-  case ISD::VSELECT: {
-    // TODO: Add adjustKnownFPClassForSelectArm clamp recognition as in
-    // IR-level ValueTracking.
-    KnownFPClass KnownFalseClass = computeKnownFPClass(
-        Op.getOperand(2), DemandedElts, InterestedClasses, Depth + 1);
-    if (KnownFalseClass.isUnknown())
       break;
-    KnownFPClass KnownTrueClass = computeKnownFPClass(
-        Op.getOperand(1), DemandedElts, InterestedClasses, Depth + 1);
-    Known = KnownTrueClass.intersectWith(KnownFalseClass);
-    break;
-  }
-  default:
-    if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
-        Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
-      TLI->computeKnownFPClassForTargetNode(Op, Known, DemandedElts, *this,
-                                            Depth);
     }
-    break;
   }
 
   return Known;

>From a3418c12d323c81477fd6f1eb979da6e0e494dfe Mon Sep 17 00:00:00 2001
From: Varad Kamthe <varadk.2704 at gmail.com>
Date: Tue, 4 Aug 2026 14:14:47 +0530
Subject: [PATCH 3/3] [AMDGPU] Regenerate fsqrt.f32.ll test checks

computeKnownFPClass now propagates nnan/ninf flags generically, so
AMDGPU's degenerate-value guard in lowerFSQRTF32 (which checks
fcZero|fcPosInf via ISD::IS_FPCLASS) can now prove +inf is impossible
for ninf-flagged sqrt calls, narrowing the generated hardware compare
mask. No manual code change -- just regenerated CHECK lines to match
the improved codegen.
---
 llvm/test/CodeGen/AMDGPU/fsqrt.f32.ll | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/llvm/test/CodeGen/AMDGPU/fsqrt.f32.ll b/llvm/test/CodeGen/AMDGPU/fsqrt.f32.ll
index ea61e1122c6a9..311777d9ae67e 100644
--- a/llvm/test/CodeGen/AMDGPU/fsqrt.f32.ll
+++ b/llvm/test/CodeGen/AMDGPU/fsqrt.f32.ll
@@ -414,7 +414,7 @@ define float @v_sqrt_f32_ninf(float %x) {
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e64 v1, v2, v3, s[4:5]
 ; SDAG-IEEE-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-IEEE-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-IEEE-NEXT:    s_setpc_b64 s[30:31]
@@ -459,7 +459,7 @@ define float @v_sqrt_f32_ninf(float %x) {
 ; SDAG-DAZ-NEXT:    v_fma_f32 v1, v4, v1, v2
 ; SDAG-DAZ-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-DAZ-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-DAZ-NEXT:    s_setpc_b64 s[30:31]
@@ -508,7 +508,7 @@ define float @v_sqrt_f32_no_infs_attribute(float %x) #5 {
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e64 v1, v2, v3, s[4:5]
 ; SDAG-IEEE-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-IEEE-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-IEEE-NEXT:    s_setpc_b64 s[30:31]
@@ -553,7 +553,7 @@ define float @v_sqrt_f32_no_infs_attribute(float %x) #5 {
 ; SDAG-DAZ-NEXT:    v_fma_f32 v1, v4, v1, v2
 ; SDAG-DAZ-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-DAZ-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-DAZ-NEXT:    s_setpc_b64 s[30:31]
@@ -814,7 +814,7 @@ define amdgpu_ps i32 @s_sqrt_f32_ninf(float inreg %x) {
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v1, v2, v3, vcc
 ; SDAG-IEEE-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e64 v1, v1, v2, s[0:1]
-; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-IEEE-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-IEEE-NEXT:    v_readfirstlane_b32 s0, v0
@@ -873,7 +873,7 @@ define amdgpu_ps i32 @s_sqrt_f32_ninf(float inreg %x) {
 ; SDAG-DAZ-NEXT:    v_fma_f32 v1, v4, v1, v2
 ; SDAG-DAZ-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-DAZ-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-DAZ-NEXT:    v_readfirstlane_b32 s0, v0
@@ -1048,7 +1048,7 @@ define float @v_sqrt_f32_nnan_ninf(float %x) {
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e64 v1, v2, v3, s[4:5]
 ; SDAG-IEEE-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-IEEE-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-IEEE-NEXT:    s_setpc_b64 s[30:31]
@@ -1093,7 +1093,7 @@ define float @v_sqrt_f32_nnan_ninf(float %x) {
 ; SDAG-DAZ-NEXT:    v_fma_f32 v1, v4, v1, v2
 ; SDAG-DAZ-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-DAZ-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-DAZ-NEXT:    s_setpc_b64 s[30:31]
@@ -1142,7 +1142,7 @@ define float @v_sqrt_f32_nnan_ninf_nsz(float %x) {
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e64 v1, v2, v3, s[4:5]
 ; SDAG-IEEE-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-IEEE-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-IEEE-NEXT:    s_setpc_b64 s[30:31]
@@ -1187,7 +1187,7 @@ define float @v_sqrt_f32_nnan_ninf_nsz(float %x) {
 ; SDAG-DAZ-NEXT:    v_fma_f32 v1, v4, v1, v2
 ; SDAG-DAZ-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-DAZ-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-DAZ-NEXT:    s_setpc_b64 s[30:31]
@@ -3162,7 +3162,7 @@ define float @v_sqrt_f32_ninf_known_never_zero(float nofpclass(zero) %x) {
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e64 v1, v2, v3, s[4:5]
 ; SDAG-IEEE-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-IEEE-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-IEEE-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-IEEE-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-IEEE-NEXT:    s_setpc_b64 s[30:31]
@@ -3207,7 +3207,7 @@ define float @v_sqrt_f32_ninf_known_never_zero(float nofpclass(zero) %x) {
 ; SDAG-DAZ-NEXT:    v_fma_f32 v1, v4, v1, v2
 ; SDAG-DAZ-NEXT:    v_mul_f32_e32 v2, 0x37800000, v1
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v1, v1, v2, vcc
-; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x260
+; SDAG-DAZ-NEXT:    v_mov_b32_e32 v2, 0x60
 ; SDAG-DAZ-NEXT:    v_cmp_class_f32_e32 vcc, v0, v2
 ; SDAG-DAZ-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
 ; SDAG-DAZ-NEXT:    s_setpc_b64 s[30:31]



More information about the llvm-commits mailing list