[llvm] [DAG] computeKnownFPClass - add ISD::SINT_TO_FP/UINT_TO_FP handling (PR #190539)

Pau Sum via llvm-commits llvm-commits at lists.llvm.org
Wed May 6 21:52:12 PDT 2026


https://github.com/pau-sum updated https://github.com/llvm/llvm-project/pull/190539

>From ff38dc55078c05f78b2fef758f3ac402cb8fa221 Mon Sep 17 00:00:00 2001
From: Pau Sum <pau at sumpau.com>
Date: Sun, 5 Apr 2026 08:50:09 -0400
Subject: [PATCH 01/10] [DAG] computeKnownFPClass - add
 ISD::SINT_TO_FP/UINT_TO_FP handling

---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  55 ++++
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 281 ++++++++++++++++++
 2 files changed, 336 insertions(+)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 857ff98f84b32..f65136af5e719 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6119,6 +6119,61 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
     Known = computeKnownFPClass(Op.getOperand(0), InterestedClasses, Depth + 1);
     break;
   }
+  case ISD::SINT_TO_FP:
+  case ISD::UINT_TO_FP: {
+    // Cannot produce nan
+    Known.knownNot(fcNan);
+
+    // Integers cannot be subnormal
+    Known.knownNot(fcSubnormal);
+
+    // sitofp and uitofp turn into +0.0 for zero.
+    Known.knownNot(fcNegZero);
+
+    // UIToFP is always non-negative regardless of known bits.
+    if (Opcode == ISD::UINT_TO_FP)
+      Known.signBitMustBeZero();
+
+    // Only compute known bits if we can learn something useful from them.
+    if (!(InterestedClasses & (fcPosZero | fcNormal | fcInf)))
+      break;
+
+    KnownBits IntKnown =
+        computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
+
+    // If the integer is non-zero, the result cannot be +0.0
+    if (IntKnown.isNonZero())
+      Known.knownNot(fcPosZero);
+
+    if (Opcode == ISD::SINT_TO_FP) {
+      // If the signed integer is known non-negative, the result is
+      // non-negative. If the signed integer is known negative, the result is
+      // negative.
+      if (IntKnown.isNonNegative())
+        Known.signBitMustBeZero();
+      else if (IntKnown.isNegative())
+        Known.signBitMustBeOne();
+    }
+
+    // Guard kept for ilogb()
+    if (InterestedClasses & fcInf) {
+      // Get width of largest magnitude integer known.
+      // This still works for a signed minimum value because the largest FP
+      // value is scaled by some fraction close to 2.0 (1.0 + 0.xxxx).
+      int IntSize = IntKnown.getBitWidth();
+      if (Opcode == ISD::UINT_TO_FP)
+        IntSize -= IntKnown.countMinLeadingZeros();
+      else if (Opcode == ISD::SINT_TO_FP)
+        IntSize -= IntKnown.countMinSignBits();
+
+      // If the exponent of the largest finite FP value can hold the largest
+      // integer, the result of the cast must be finite.
+      if (ilogb(APFloat::getLargest(VT.getScalarType().getFltSemantics())) >=
+          IntSize)
+        Known.knownNot(fcInf);
+    }
+    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,
diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index a4482873808d8..183c99612c56b 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -196,6 +196,287 @@ define i1 @fabs_is_nonneg_or_nan(float %x) nounwind {
   ret i1 %res
 }
 
+define i1 @uitofp_isnan(i32 %x) {
+; CHECK-LABEL: uitofp_isnan:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %f = uitofp i32 %x to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 3) ; 3 = nan
+  ret i1 %res
+}
+
+define i1 @uitofp_issubnormal(i32 %x) {
+; CHECK-LABEL: uitofp_issubnormal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %f = uitofp i32 %x to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 144) ; 144 = subnormal
+  ret i1 %res
+}
+
+define i1 @uitofp_isnegzero(i32 %x) {
+; CHECK-LABEL: uitofp_isnegzero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %f = uitofp i32 %x to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 32) ; 32 = neg_zero
+  ret i1 %res
+}
+
+define i1 @uitofp_isneg(i32 %x) {
+; CHECK-LABEL: uitofp_isneg:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %f = uitofp i32 %x to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 60) ; 60 = negative
+  ret i1 %res
+}
+
+define i1 @uitofp_isposzero(i32 %x) {
+; CHECK-LABEL: uitofp_isposzero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %nz = or i32 %x, 1            ; Ensure nonzero
+  %f = uitofp i32 %nz to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 64) ; 64 = pos_zero
+  ret i1 %res
+}
+
+define i1 @uitofp_isinf(i32 %x) {
+; CHECK-LABEL: uitofp_isinf:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %f = uitofp i32 %x to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 516) ; 516 = inf
+  ret i1 %res
+}
+
+define i1 @sitofp_isnan(i32 %x) {
+; CHECK-LABEL: sitofp_isnan:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %f = sitofp i32 %x to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 3) ; 3 = nan
+  ret i1 %res
+}
+
+define i1 @sitofp_issubnormal(i32 %x) {
+; CHECK-LABEL: sitofp_issubnormal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %f = sitofp i32 %x to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 144) ; 144 = subnormal
+  ret i1 %res
+}
+
+define i1 @sitofp_isnegzero(i32 %x) {
+; CHECK-LABEL: sitofp_isnegzero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %f = sitofp i32 %x to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 32) ; 32 = neg_zero
+  ret i1 %res
+}
+
+define i1 @sitofp_isposzero(i32 %x) {
+; CHECK-LABEL: sitofp_isposzero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %npz = or i32 %x, -2147483648 ; | 0x80000000: Set sign bit
+  %f = sitofp i32 %npz to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 64) ; 64 = pos_zero
+  ret i1 %res
+}
+
+define i1 @sitofp_isneg(i32 %x) {
+; CHECK-LABEL: sitofp_isneg:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %nn = and i32 %x, 2147483647 ; & 0x7FFFFFFF: Clear sign bit
+  %f = sitofp i32 %nn to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 60) ; 60 = negative
+  ret i1 %res
+}
+
+define i1 @sitofp_isnonneg(i32 %x) {
+; CHECK-LABEL: sitofp_isnonneg:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %n = or i32 %x, -2147483648 ; | 0x80000000: Set sign bit
+  %f = sitofp i32 %n to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 960) ; 960 = positive
+  ret i1 %res
+}
+
+define i1 @sitofp_isinf(i32 %x) {
+; CHECK-LABEL: sitofp_isinf:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    ret
+  %f = sitofp i32 %x to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 516) ; 516 = inf
+  ret i1 %res
+}
+
+define <4 x i1> @uitofp_v4_isnan(<4 x i32> %x) {
+; CHECK-LABEL: uitofp_v4_isnan:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %f = uitofp <4 x i32> %x to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 3) ; 3 = nan
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @uitofp_v4_issubnormal(<4 x i32> %x) {
+; CHECK-LABEL: uitofp_v4_issubnormal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %f = uitofp <4 x i32> %x to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 144) ; 144 subnormal
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @uitofp_v4_isnegzero(<4 x i32> %x) {
+; CHECK-LABEL: uitofp_v4_isnegzero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %f = uitofp <4 x i32> %x to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 32); 32 = neg_zero
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @uitofp_v4_isneg(<4 x i32> %x) {
+; CHECK-LABEL: uitofp_v4_isneg:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %f = uitofp <4 x i32> %x to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 60) ; 60 = negative
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @uitofp_v4_isposzero(<4 x i32> %x) {
+; CHECK-LABEL: uitofp_v4_isposzero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %nz = or <4 x i32> %x, <i32 1, i32 1, i32 1, i32 1>
+  %f = uitofp <4 x i32> %nz to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 64) ; 64 = pos_zero
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @uitofp_v4_isinf(<4 x i32> %x) {
+; CHECK-LABEL: uitofp_v4_isinf:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %f = uitofp <4 x i32> %x to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 516) ; 516 = inf
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @sitofp_v4_isnan(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_isnan:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %f = sitofp <4 x i32> %x to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 3) ; 3 = nan
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @sitofp_v4_issubnormal(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_issubnormal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %f = sitofp <4 x i32> %x to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 144) ; 144 = subnormal
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @sitofp_v4_isnegzero(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_isnegzero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %f = sitofp <4 x i32> %x to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 32) ; 32 = neg_zero
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @sitofp_v4_isposzero(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_isposzero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %npz = or <4 x i32> %x, <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648> ; | 0x80000000: Set sign bit
+  %f = sitofp <4 x i32> %npz to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 64)  ; 64 = pos_zero
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @sitofp_v4_isneg(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_isneg:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %nn = and <4 x i32> %x, <i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647> ; & 0x7FFFFFFF: Clear sign bit
+  %f = sitofp <4 x i32> %nn to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 60) ; 60 = negative
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @sitofp_v4_isnonneg(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_isnonneg:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %n = or <4 x i32> %x, <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648> ;  | 0x80000000: Set sign bit
+  %f = sitofp <4 x i32> %n to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 960) ; 960 = positive
+  ret <4 x i1> %res
+}
+
+define <4 x i1> @sitofp_v4_isinf(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_isinf:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
+; CHECK-NEXT:    vmclr.m v0
+; CHECK-NEXT:    ret
+  %f = sitofp <4 x i32> %x to <4 x float>
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 516) ; 516 = inf
+  ret <4 x i1> %res
+}
+
 define <vscale x 4 x i1> @splat_constant_is_pos_normal() {
 ; CHECK-LABEL: splat_constant_is_pos_normal:
 ; CHECK:       # %bb.0:

>From 37c309e2dc803cc04c35b1a5aa42fe3f42c9f82d Mon Sep 17 00:00:00 2001
From: Pau Sum <pau at sumpau.com>
Date: Tue, 7 Apr 2026 20:57:34 -0400
Subject: [PATCH 02/10] Add itofp logic to Support/KnownFPClass

---
 llvm/include/llvm/Support/KnownFPClass.h |  7 +++
 llvm/lib/Support/KnownFPClass.cpp        | 67 ++++++++++++++++++++++++
 2 files changed, 74 insertions(+)

diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 7e018d25d2d1d..29f590197a32c 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -240,6 +240,13 @@ struct KnownFPClass {
   LLVM_ABI static KnownFPClass bitcast(const fltSemantics &FltSemantics,
                                        const KnownBits &Bits);
 
+  LLVM_ABI static KnownFPClass sitofp(const KnownBits &KnownSrc,
+                                      const fltSemantics &FltSem,
+                                      FPClassTest InterestedClasses);
+  LLVM_ABI static KnownFPClass uitofp(const KnownBits &KnownSrc,
+                                      const fltSemantics &FltSem,
+                                      FPClassTest InterestedClasses);
+
   /// Report known values for fadd
   LLVM_ABI static KnownFPClass
   fadd(const KnownFPClass &LHS, const KnownFPClass &RHS,
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 3e2f6a1704b01..7638e39cd85ad 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -287,6 +287,73 @@ KnownFPClass KnownFPClass::bitcast(const fltSemantics &FltSemantics,
   return Known;
 }
 
+static KnownFPClass itofp_impl(const KnownBits &KnownSrc,
+                               const fltSemantics &FltSem,
+                               FPClassTest InterestedClasses, bool IsSigned) {
+  KnownFPClass Known;
+  // Cannot produce nan
+  Known.knownNot(fcNan);
+
+  // Integers cannot be subnormal
+  Known.knownNot(fcSubnormal);
+
+  // sitofp and uitofp turn into +0.0 for zero.
+  Known.knownNot(fcNegZero);
+
+  // UIToFP is always non-negative regardless of known bits.
+  if (!IsSigned)
+    Known.signBitMustBeZero();
+
+  // Only compute known bits if we can learn something useful from them.
+  if (!(InterestedClasses & (fcPosZero | fcNormal | fcInf)))
+    return Known;
+
+  // If the integer is non-zero, the result cannot be +0.0
+  if (KnownSrc.isNonZero())
+    Known.knownNot(fcPosZero);
+
+  if (IsSigned) {
+    // If the signed integer is known non-negative, the result is
+    // non-negative. If the signed integer is known negative, the result is
+    // negative.
+    if (KnownSrc.isNonNegative())
+      Known.signBitMustBeZero();
+    else if (KnownSrc.isNegative())
+      Known.signBitMustBeOne();
+  }
+
+  // Guard kept for ilogb()
+  if (InterestedClasses & fcInf) {
+    // Get width of largest magnitude integer known.
+    // This still works for a signed minimum value because the largest FP
+    // value is scaled by some fraction close to 2.0 (1.0 + 0.xxxx).
+    int IntSize = KnownSrc.getBitWidth();
+    if (!IsSigned)
+      IntSize -= KnownSrc.countMinLeadingZeros();
+    else
+      IntSize -= KnownSrc.countMinSignBits();
+
+    // If the exponent of the largest finite FP value can hold the largest
+    // integer, the result of the cast must be finite.
+    if (APFloat::semanticsMaxExponent(FltSem) >= IntSize)
+      Known.knownNot(fcInf);
+  }
+
+  return Known;
+}
+
+KnownFPClass KnownFPClass::sitofp(const KnownBits &SrcKnown,
+                                  const fltSemantics &FltSem,
+                                  FPClassTest InterestedClasses) {
+  return itofp_impl(SrcKnown, FltSem, InterestedClasses, /*IsSigned=*/true);
+}
+
+KnownFPClass KnownFPClass::uitofp(const KnownBits &SrcKnown,
+                                  const fltSemantics &FltSem,
+                                  FPClassTest InterestedClasses) {
+  return itofp_impl(SrcKnown, FltSem, InterestedClasses, /*IsSigned=*/false);
+}
+
 // Handle known sign bit and nan cases for fadd.
 static KnownFPClass fadd_impl(const KnownFPClass &KnownLHS,
                               const KnownFPClass &KnownRHS, DenormalMode Mode) {

>From 378243ca0258def5561577c46cf2030039389435 Mon Sep 17 00:00:00 2001
From: Pau Sum <pau at sumpau.com>
Date: Tue, 7 Apr 2026 20:59:08 -0400
Subject: [PATCH 03/10] refactor: Use Support/KnownFPClass for itofp cases for
 SelDAG

---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 53 ++-----------------
 1 file changed, 4 insertions(+), 49 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index f65136af5e719..01b198ba72522 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6121,57 +6121,12 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
   }
   case ISD::SINT_TO_FP:
   case ISD::UINT_TO_FP: {
-    // Cannot produce nan
-    Known.knownNot(fcNan);
-
-    // Integers cannot be subnormal
-    Known.knownNot(fcSubnormal);
-
-    // sitofp and uitofp turn into +0.0 for zero.
-    Known.knownNot(fcNegZero);
-
-    // UIToFP is always non-negative regardless of known bits.
-    if (Opcode == ISD::UINT_TO_FP)
-      Known.signBitMustBeZero();
-
-    // Only compute known bits if we can learn something useful from them.
-    if (!(InterestedClasses & (fcPosZero | fcNormal | fcInf)))
-      break;
-
     KnownBits IntKnown =
         computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
-
-    // If the integer is non-zero, the result cannot be +0.0
-    if (IntKnown.isNonZero())
-      Known.knownNot(fcPosZero);
-
-    if (Opcode == ISD::SINT_TO_FP) {
-      // If the signed integer is known non-negative, the result is
-      // non-negative. If the signed integer is known negative, the result is
-      // negative.
-      if (IntKnown.isNonNegative())
-        Known.signBitMustBeZero();
-      else if (IntKnown.isNegative())
-        Known.signBitMustBeOne();
-    }
-
-    // Guard kept for ilogb()
-    if (InterestedClasses & fcInf) {
-      // Get width of largest magnitude integer known.
-      // This still works for a signed minimum value because the largest FP
-      // value is scaled by some fraction close to 2.0 (1.0 + 0.xxxx).
-      int IntSize = IntKnown.getBitWidth();
-      if (Opcode == ISD::UINT_TO_FP)
-        IntSize -= IntKnown.countMinLeadingZeros();
-      else if (Opcode == ISD::SINT_TO_FP)
-        IntSize -= IntKnown.countMinSignBits();
-
-      // If the exponent of the largest finite FP value can hold the largest
-      // integer, the result of the cast must be finite.
-      if (ilogb(APFloat::getLargest(VT.getScalarType().getFltSemantics())) >=
-          IntSize)
-        Known.knownNot(fcInf);
-    }
+    const fltSemantics &FltSem = VT.getScalarType().getFltSemantics();
+    Known = Opcode == ISD::SINT_TO_FP
+                ? KnownFPClass::sitofp(IntKnown, FltSem, InterestedClasses)
+                : KnownFPClass::uitofp(IntKnown, FltSem, InterestedClasses);
     break;
   }
   case ISD::BITCAST: {

>From c6bc4e02750bec4e9fe071f2a62ad8c554e13199 Mon Sep 17 00:00:00 2001
From: Pau Sum <pau at sumpau.com>
Date: Tue, 7 Apr 2026 21:01:59 -0400
Subject: [PATCH 04/10] refactor: Use Support/KnownFPClass for itofp cases in
 ValueTracking

---
 llvm/lib/Analysis/ValueTracking.cpp | 56 +++--------------------------
 1 file changed, 5 insertions(+), 51 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 8f10bbae3d462..919ccd56c60ea 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5834,59 +5834,13 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
   }
   case Instruction::SIToFP:
   case Instruction::UIToFP: {
-    // Cannot produce nan
-    Known.knownNot(fcNan);
-
-    // Integers cannot be subnormal
-    Known.knownNot(fcSubnormal);
-
-    // sitofp and uitofp turn into +0.0 for zero.
-    Known.knownNot(fcNegZero);
-
-    // UIToFP is always non-negative regardless of known bits.
-    if (Op->getOpcode() == Instruction::UIToFP)
-      Known.signBitMustBeZero();
-
-    // Only compute known bits if we can learn something useful from them.
-    if (!(InterestedClasses & (fcPosZero | fcNormal | fcInf)))
-      break;
-
     KnownBits IntKnown =
         computeKnownBits(Op->getOperand(0), DemandedElts, Q, Depth + 1);
-
-    // If the integer is non-zero, the result cannot be +0.0
-    if (IntKnown.isNonZero())
-      Known.knownNot(fcPosZero);
-
-    if (Op->getOpcode() == Instruction::SIToFP) {
-      // If the signed integer is known non-negative, the result is
-      // non-negative. If the signed integer is known negative, the result is
-      // negative.
-      if (IntKnown.isNonNegative()) {
-        Known.signBitMustBeZero();
-      } else if (IntKnown.isNegative()) {
-        Known.signBitMustBeOne();
-      }
-    }
-
-    // Guard kept for ilogb()
-    if (InterestedClasses & fcInf) {
-      // Get width of largest magnitude integer known.
-      // This still works for a signed minimum value because the largest FP
-      // value is scaled by some fraction close to 2.0 (1.0 + 0.xxxx).
-      int IntSize = IntKnown.getBitWidth();
-      if (Op->getOpcode() == Instruction::UIToFP)
-        IntSize -= IntKnown.countMinLeadingZeros();
-      else if (Op->getOpcode() == Instruction::SIToFP)
-        IntSize -= IntKnown.countMinSignBits();
-
-      // If the exponent of the largest finite FP value can hold the largest
-      // integer, the result of the cast must be finite.
-      Type *FPTy = Op->getType()->getScalarType();
-      if (ilogb(APFloat::getLargest(FPTy->getFltSemantics())) >= IntSize)
-        Known.knownNot(fcInf);
-    }
-
+    const fltSemantics &FltSem =
+        Op->getType()->getScalarType()->getFltSemantics();
+    Known = Op->getOpcode() == Instruction::SIToFP
+                ? KnownFPClass::sitofp(IntKnown, FltSem, InterestedClasses)
+                : KnownFPClass::uitofp(IntKnown, FltSem, InterestedClasses);
     break;
   }
   case Instruction::ExtractElement: {

>From 563a3b9bd4a391a9263d966aa24ad6031125a6aa Mon Sep 17 00:00:00 2001
From: Pau Sum <pau at sumpau.com>
Date: Wed, 8 Apr 2026 17:55:21 -0400
Subject: [PATCH 05/10] refactor: Remove InterestedClasses param from itofp
 function

---
 llvm/include/llvm/Support/KnownFPClass.h      |  9 ++--
 llvm/lib/Analysis/ValueTracking.cpp           |  4 +-
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  5 +-
 llvm/lib/Support/KnownFPClass.cpp             | 46 ++++++++-----------
 4 files changed, 27 insertions(+), 37 deletions(-)

diff --git a/llvm/include/llvm/Support/KnownFPClass.h b/llvm/include/llvm/Support/KnownFPClass.h
index 29f590197a32c..50b10f5acf554 100644
--- a/llvm/include/llvm/Support/KnownFPClass.h
+++ b/llvm/include/llvm/Support/KnownFPClass.h
@@ -240,12 +240,13 @@ struct KnownFPClass {
   LLVM_ABI static KnownFPClass bitcast(const fltSemantics &FltSemantics,
                                        const KnownBits &Bits);
 
+  /// Report known values for sitofp
   LLVM_ABI static KnownFPClass sitofp(const KnownBits &KnownSrc,
-                                      const fltSemantics &FltSem,
-                                      FPClassTest InterestedClasses);
+                                      const fltSemantics &FltSemantics);
+
+  /// Report known values for uitofp
   LLVM_ABI static KnownFPClass uitofp(const KnownBits &KnownSrc,
-                                      const fltSemantics &FltSem,
-                                      FPClassTest InterestedClasses);
+                                      const fltSemantics &FltSemantics);
 
   /// Report known values for fadd
   LLVM_ABI static KnownFPClass
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 919ccd56c60ea..acc02fa61cbda 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5839,8 +5839,8 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
     const fltSemantics &FltSem =
         Op->getType()->getScalarType()->getFltSemantics();
     Known = Op->getOpcode() == Instruction::SIToFP
-                ? KnownFPClass::sitofp(IntKnown, FltSem, InterestedClasses)
-                : KnownFPClass::uitofp(IntKnown, FltSem, InterestedClasses);
+                ? KnownFPClass::sitofp(IntKnown, FltSem)
+                : KnownFPClass::uitofp(IntKnown, FltSem);
     break;
   }
   case Instruction::ExtractElement: {
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 01b198ba72522..6d5aea1bf8568 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6124,9 +6124,8 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
     KnownBits IntKnown =
         computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
     const fltSemantics &FltSem = VT.getScalarType().getFltSemantics();
-    Known = Opcode == ISD::SINT_TO_FP
-                ? KnownFPClass::sitofp(IntKnown, FltSem, InterestedClasses)
-                : KnownFPClass::uitofp(IntKnown, FltSem, InterestedClasses);
+    Known = Opcode == ISD::SINT_TO_FP ? KnownFPClass::sitofp(IntKnown, FltSem)
+                                      : KnownFPClass::uitofp(IntKnown, FltSem);
     break;
   }
   case ISD::BITCAST: {
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 7638e39cd85ad..e57469035bf9b 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -288,8 +288,7 @@ KnownFPClass KnownFPClass::bitcast(const fltSemantics &FltSemantics,
 }
 
 static KnownFPClass itofp_impl(const KnownBits &KnownSrc,
-                               const fltSemantics &FltSem,
-                               FPClassTest InterestedClasses, bool IsSigned) {
+                               const fltSemantics &FltSem, bool IsSigned) {
   KnownFPClass Known;
   // Cannot produce nan
   Known.knownNot(fcNan);
@@ -304,10 +303,6 @@ static KnownFPClass itofp_impl(const KnownBits &KnownSrc,
   if (!IsSigned)
     Known.signBitMustBeZero();
 
-  // Only compute known bits if we can learn something useful from them.
-  if (!(InterestedClasses & (fcPosZero | fcNormal | fcInf)))
-    return Known;
-
   // If the integer is non-zero, the result cannot be +0.0
   if (KnownSrc.isNonZero())
     Known.knownNot(fcPosZero);
@@ -322,36 +317,31 @@ static KnownFPClass itofp_impl(const KnownBits &KnownSrc,
       Known.signBitMustBeOne();
   }
 
-  // Guard kept for ilogb()
-  if (InterestedClasses & fcInf) {
-    // Get width of largest magnitude integer known.
-    // This still works for a signed minimum value because the largest FP
-    // value is scaled by some fraction close to 2.0 (1.0 + 0.xxxx).
-    int IntSize = KnownSrc.getBitWidth();
-    if (!IsSigned)
-      IntSize -= KnownSrc.countMinLeadingZeros();
-    else
-      IntSize -= KnownSrc.countMinSignBits();
-
-    // If the exponent of the largest finite FP value can hold the largest
-    // integer, the result of the cast must be finite.
-    if (APFloat::semanticsMaxExponent(FltSem) >= IntSize)
-      Known.knownNot(fcInf);
-  }
+  // Get width of largest magnitude integer known.
+  // This still works for a signed minimum value because the largest FP
+  // value is scaled by some fraction close to 2.0 (1.0 + 0.xxxx).
+  int IntSize = KnownSrc.getBitWidth();
+  if (!IsSigned)
+    IntSize -= KnownSrc.countMinLeadingZeros();
+  else
+    IntSize -= KnownSrc.countMinSignBits();
+
+  // If the exponent of the largest finite FP value can hold the largest
+  // integer, the result of the cast must be finite.
+  if (APFloat::semanticsMaxExponent(FltSem) >= IntSize)
+    Known.knownNot(fcInf);
 
   return Known;
 }
 
 KnownFPClass KnownFPClass::sitofp(const KnownBits &SrcKnown,
-                                  const fltSemantics &FltSem,
-                                  FPClassTest InterestedClasses) {
-  return itofp_impl(SrcKnown, FltSem, InterestedClasses, /*IsSigned=*/true);
+                                  const fltSemantics &FltSem) {
+  return itofp_impl(SrcKnown, FltSem, /*IsSigned=*/true);
 }
 
 KnownFPClass KnownFPClass::uitofp(const KnownBits &SrcKnown,
-                                  const fltSemantics &FltSem,
-                                  FPClassTest InterestedClasses) {
-  return itofp_impl(SrcKnown, FltSem, InterestedClasses, /*IsSigned=*/false);
+                                  const fltSemantics &FltSem) {
+  return itofp_impl(SrcKnown, FltSem, /*IsSigned=*/false);
 }
 
 // Handle known sign bit and nan cases for fadd.

>From bd8d3dd12cbea70bdfae29a3b5a2c5225759f687 Mon Sep 17 00:00:00 2001
From: Pau Sum <pau at sumpau.com>
Date: Sun, 12 Apr 2026 13:46:44 -0400
Subject: [PATCH 06/10] Add back InterestedClasses short-circuit

---
 llvm/lib/Analysis/ValueTracking.cpp           | 24 +++++++++++++++---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 25 ++++++++++++++++---
 llvm/lib/Support/KnownFPClass.cpp             | 21 +++-------------
 3 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index acc02fa61cbda..746f44f078ff4 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5834,13 +5834,31 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
   }
   case Instruction::SIToFP:
   case Instruction::UIToFP: {
+    // Cannot produce nan
+    Known.knownNot(fcNan);
+
+    // Integers cannot be subnormal
+    Known.knownNot(fcSubnormal);
+
+    // sitofp and uitofp turn into +0.0 for zero.
+    Known.knownNot(fcNegZero);
+
+    // UIToFP is always non-negative regardless of known bits.
+    if (Op->getOpcode() == Instruction::UIToFP)
+      Known.signBitMustBeZero();
+
+    if (!(InterestedClasses & (fcPosZero | fcNormal | fcInf)))
+      break;
+
     KnownBits IntKnown =
         computeKnownBits(Op->getOperand(0), DemandedElts, Q, Depth + 1);
     const fltSemantics &FltSem =
         Op->getType()->getScalarType()->getFltSemantics();
-    Known = Op->getOpcode() == Instruction::SIToFP
-                ? KnownFPClass::sitofp(IntKnown, FltSem)
-                : KnownFPClass::uitofp(IntKnown, FltSem);
+    KnownFPClass Known2 = Op->getOpcode() == Instruction::SIToFP
+                              ? KnownFPClass::sitofp(IntKnown, FltSem)
+                              : KnownFPClass::uitofp(IntKnown, FltSem);
+
+    Known = Known.unionWith(Known2);
     break;
   }
   case Instruction::ExtractElement: {
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 6d5aea1bf8568..f7103b4c1f48c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6121,11 +6121,30 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
   }
   case ISD::SINT_TO_FP:
   case ISD::UINT_TO_FP: {
+    // Cannot produce nan
+    Known.knownNot(fcNan);
+
+    // Integers cannot be subnormal
+    Known.knownNot(fcSubnormal);
+
+    // sitofp and uitofp turn into +0.0 for zero.
+    Known.knownNot(fcNegZero);
+
+    // UIToFP is always non-negative regardless of known bits.
+    if (Opcode == ISD::UINT_TO_FP)
+      Known.signBitMustBeZero();
+
+    if (!(InterestedClasses & (fcPosZero | fcNormal | fcInf)))
+      break;
+
     KnownBits IntKnown =
         computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
-    const fltSemantics &FltSem = VT.getScalarType().getFltSemantics();
-    Known = Opcode == ISD::SINT_TO_FP ? KnownFPClass::sitofp(IntKnown, FltSem)
-                                      : KnownFPClass::uitofp(IntKnown, FltSem);
+    const fltSemantics &FltSem = VT.getFltSemantics();
+    KnownFPClass Known2 = Opcode == ISD::SINT_TO_FP
+                              ? KnownFPClass::sitofp(IntKnown, FltSem)
+                              : KnownFPClass::uitofp(IntKnown, FltSem);
+
+    Known = Known.unionWith(Known2);
     break;
   }
   case ISD::BITCAST: {
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index e57469035bf9b..7f2a34429bc07 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -290,19 +290,6 @@ KnownFPClass KnownFPClass::bitcast(const fltSemantics &FltSemantics,
 static KnownFPClass itofp_impl(const KnownBits &KnownSrc,
                                const fltSemantics &FltSem, bool IsSigned) {
   KnownFPClass Known;
-  // Cannot produce nan
-  Known.knownNot(fcNan);
-
-  // Integers cannot be subnormal
-  Known.knownNot(fcSubnormal);
-
-  // sitofp and uitofp turn into +0.0 for zero.
-  Known.knownNot(fcNegZero);
-
-  // UIToFP is always non-negative regardless of known bits.
-  if (!IsSigned)
-    Known.signBitMustBeZero();
-
   // If the integer is non-zero, the result cannot be +0.0
   if (KnownSrc.isNonZero())
     Known.knownNot(fcPosZero);
@@ -334,14 +321,14 @@ static KnownFPClass itofp_impl(const KnownBits &KnownSrc,
   return Known;
 }
 
-KnownFPClass KnownFPClass::sitofp(const KnownBits &SrcKnown,
+KnownFPClass KnownFPClass::sitofp(const KnownBits &KnownSrc,
                                   const fltSemantics &FltSem) {
-  return itofp_impl(SrcKnown, FltSem, /*IsSigned=*/true);
+  return itofp_impl(KnownSrc, FltSem, /*IsSigned=*/true);
 }
 
-KnownFPClass KnownFPClass::uitofp(const KnownBits &SrcKnown,
+KnownFPClass KnownFPClass::uitofp(const KnownBits &KnownSrc,
                                   const fltSemantics &FltSem) {
-  return itofp_impl(SrcKnown, FltSem, /*IsSigned=*/false);
+  return itofp_impl(KnownSrc, FltSem, /*IsSigned=*/false);
 }
 
 // Handle known sign bit and nan cases for fadd.

>From 129311ea6a73210d72a463b696aead2a0f0c2556 Mon Sep 17 00:00:00 2001
From: Pau Sum <pau at sumpau.com>
Date: Sun, 12 Apr 2026 15:44:04 -0400
Subject: [PATCH 07/10] Update ll test with hex ops

---
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index 183c99612c56b..8450ba5daabfe 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -292,7 +292,7 @@ define i1 @sitofp_isposzero(i32 %x) {
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
-  %npz = or i32 %x, -2147483648 ; | 0x80000000: Set sign bit
+  %npz = or i32 %x, u0x80000000 ; Set sign bit
   %f = sitofp i32 %npz to float
   %res = call i1 @llvm.is.fpclass.f32(float %f, i32 64) ; 64 = pos_zero
   ret i1 %res
@@ -303,7 +303,7 @@ define i1 @sitofp_isneg(i32 %x) {
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
-  %nn = and i32 %x, 2147483647 ; & 0x7FFFFFFF: Clear sign bit
+  %nn = and i32 %x, u0x7fffffff ; Clear sign bit
   %f = sitofp i32 %nn to float
   %res = call i1 @llvm.is.fpclass.f32(float %f, i32 60) ; 60 = negative
   ret i1 %res
@@ -314,7 +314,7 @@ define i1 @sitofp_isnonneg(i32 %x) {
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
-  %n = or i32 %x, -2147483648 ; | 0x80000000: Set sign bit
+  %n = or i32 %x, u0x80000000 ; Set sign bit
   %f = sitofp i32 %n to float
   %res = call i1 @llvm.is.fpclass.f32(float %f, i32 960) ; 960 = positive
   ret i1 %res
@@ -436,7 +436,7 @@ define <4 x i1> @sitofp_v4_isposzero(<4 x i32> %x) {
 ; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
 ; CHECK-NEXT:    vmclr.m v0
 ; CHECK-NEXT:    ret
-  %npz = or <4 x i32> %x, <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648> ; | 0x80000000: Set sign bit
+  %npz = or <4 x i32> %x, <i32 u0x80000000, i32 u0x80000000, i32 u0x80000000, i32 u0x80000000> ; Set sign bit
   %f = sitofp <4 x i32> %npz to <4 x float>
   %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 64)  ; 64 = pos_zero
   ret <4 x i1> %res
@@ -448,7 +448,7 @@ define <4 x i1> @sitofp_v4_isneg(<4 x i32> %x) {
 ; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
 ; CHECK-NEXT:    vmclr.m v0
 ; CHECK-NEXT:    ret
-  %nn = and <4 x i32> %x, <i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647> ; & 0x7FFFFFFF: Clear sign bit
+  %nn = and <4 x i32> %x, <i32 u0x7fffffff, i32 u0x7fffffff, i32 u0x7fffffff, i32 u0x7fffffff> ; Clear sign bit
   %f = sitofp <4 x i32> %nn to <4 x float>
   %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 60) ; 60 = negative
   ret <4 x i1> %res
@@ -460,7 +460,7 @@ define <4 x i1> @sitofp_v4_isnonneg(<4 x i32> %x) {
 ; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
 ; CHECK-NEXT:    vmclr.m v0
 ; CHECK-NEXT:    ret
-  %n = or <4 x i32> %x, <i32 -2147483648, i32 -2147483648, i32 -2147483648, i32 -2147483648> ;  | 0x80000000: Set sign bit
+  %n = or <4 x i32> %x, <i32 u0x80000000, i32 u0x80000000, i32 u0x80000000, i32 u0x80000000> ; Set sign bit
   %f = sitofp <4 x i32> %n to <4 x float>
   %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 960) ; 960 = positive
   ret <4 x i1> %res

>From 205150f7cb699473a90ab27db5f6c8c3c09b4490 Mon Sep 17 00:00:00 2001
From: Pau Sum <pau at sumpau.com>
Date: Tue, 28 Apr 2026 19:38:41 -0400
Subject: [PATCH 08/10] Keep all masks in helper

---
 llvm/lib/Analysis/ValueTracking.cpp            |  1 +
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  1 +
 llvm/lib/Support/KnownFPClass.cpp              | 11 +++++++++--
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 746f44f078ff4..d162cccd5270f 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5847,6 +5847,7 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
     if (Op->getOpcode() == Instruction::UIToFP)
       Known.signBitMustBeZero();
 
+    // Only compute known bits if we can learn something useful from them.
     if (!(InterestedClasses & (fcPosZero | fcNormal | fcInf)))
       break;
 
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index f7103b4c1f48c..793da1d70ab85 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6134,6 +6134,7 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
     if (Opcode == ISD::UINT_TO_FP)
       Known.signBitMustBeZero();
 
+    // Only compute known bits if we can learn something useful from them.
     if (!(InterestedClasses & (fcPosZero | fcNormal | fcInf)))
       break;
 
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 7f2a34429bc07..11ce35d2fd910 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -290,9 +290,16 @@ KnownFPClass KnownFPClass::bitcast(const fltSemantics &FltSemantics,
 static KnownFPClass itofp_impl(const KnownBits &KnownSrc,
                                const fltSemantics &FltSem, bool IsSigned) {
   KnownFPClass Known;
-  // If the integer is non-zero, the result cannot be +0.0
+  
+  Known.knownNot(fcNan);
+  Known.knownNot(fcSubnormal);
+  Known.knownNot(fcNegZero);
+    
+  if (!IsSigned)
+      Known.signBitMustBeZero();
+  
   if (KnownSrc.isNonZero())
-    Known.knownNot(fcPosZero);
+    Known.knownNot(fcZero);
 
   if (IsSigned) {
     // If the signed integer is known non-negative, the result is

>From 3e7eb8a01222615dfc227e1225f6e0c5a503def6 Mon Sep 17 00:00:00 2001
From: Pau Sum <pau at sumpau.com>
Date: Wed, 6 May 2026 22:51:49 -0400
Subject: [PATCH 09/10] Combine test cases for same code paths

---
 llvm/lib/Support/KnownFPClass.cpp             |   8 +-
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 224 +++---------------
 2 files changed, 36 insertions(+), 196 deletions(-)

diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 11ce35d2fd910..e519a443f4179 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -290,14 +290,14 @@ KnownFPClass KnownFPClass::bitcast(const fltSemantics &FltSemantics,
 static KnownFPClass itofp_impl(const KnownBits &KnownSrc,
                                const fltSemantics &FltSem, bool IsSigned) {
   KnownFPClass Known;
-  
+
   Known.knownNot(fcNan);
   Known.knownNot(fcSubnormal);
   Known.knownNot(fcNegZero);
-    
+
   if (!IsSigned)
-      Known.signBitMustBeZero();
-  
+    Known.signBitMustBeZero();
+
   if (KnownSrc.isNonZero())
     Known.knownNot(fcZero);
 
diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index 8450ba5daabfe..5700f62ee48c9 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -196,59 +196,19 @@ define i1 @fabs_is_nonneg_or_nan(float %x) nounwind {
   ret i1 %res
 }
 
-define i1 @uitofp_isnan(i32 %x) {
-; CHECK-LABEL: uitofp_isnan:
+define i1 @uitofp_is_nan_neg_zero_subnorm(i32 %x) {
+; CHECK-LABEL: uitofp_is_nan_neg_zero_subnorm:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
-  %f = uitofp i32 %x to float
-  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 3) ; 3 = nan
-  ret i1 %res
-}
-
-define i1 @uitofp_issubnormal(i32 %x) {
-; CHECK-LABEL: uitofp_issubnormal:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 0
-; CHECK-NEXT:    ret
-  %f = uitofp i32 %x to float
-  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 144) ; 144 = subnormal
-  ret i1 %res
-}
-
-define i1 @uitofp_isnegzero(i32 %x) {
-; CHECK-LABEL: uitofp_isnegzero:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 0
-; CHECK-NEXT:    ret
-  %f = uitofp i32 %x to float
-  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 32) ; 32 = neg_zero
-  ret i1 %res
-}
-
-define i1 @uitofp_isneg(i32 %x) {
-; CHECK-LABEL: uitofp_isneg:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 0
-; CHECK-NEXT:    ret
-  %f = uitofp i32 %x to float
-  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 60) ; 60 = negative
-  ret i1 %res
-}
-
-define i1 @uitofp_isposzero(i32 %x) {
-; CHECK-LABEL: uitofp_isposzero:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 0
-; CHECK-NEXT:    ret
-  %nz = or i32 %x, 1            ; Ensure nonzero
+  %nz = or i32 %x, 1
   %f = uitofp i32 %nz to float
-  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 64) ; 64 = pos_zero
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 255)
   ret i1 %res
 }
 
-define i1 @uitofp_isinf(i32 %x) {
-; CHECK-LABEL: uitofp_isinf:
+define i1 @uitofp_is_inf(i32 %x) {
+; CHECK-LABEL: uitofp_is_inf:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
@@ -257,71 +217,40 @@ define i1 @uitofp_isinf(i32 %x) {
   ret i1 %res
 }
 
-define i1 @sitofp_isnan(i32 %x) {
-; CHECK-LABEL: sitofp_isnan:
+define i1 @sitofp_is_nan_subnorm_negzero(i32 %x) {
+; CHECK-LABEL: sitofp_is_nan_subnorm_negzero:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
   %f = sitofp i32 %x to float
-  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 3) ; 3 = nan
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 179) ; 179 = nan | subnorm | negzero
   ret i1 %res
 }
 
-define i1 @sitofp_issubnormal(i32 %x) {
-; CHECK-LABEL: sitofp_issubnormal:
+define i1 @sitofp_is_pos(i32 %x) {
+; CHECK-LABEL: sitofp_is_pos:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
-  %f = sitofp i32 %x to float
-  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 144) ; 144 = subnormal
-  ret i1 %res
-}
-
-define i1 @sitofp_isnegzero(i32 %x) {
-; CHECK-LABEL: sitofp_isnegzero:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 0
-; CHECK-NEXT:    ret
-  %f = sitofp i32 %x to float
-  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 32) ; 32 = neg_zero
-  ret i1 %res
-}
-
-define i1 @sitofp_isposzero(i32 %x) {
-; CHECK-LABEL: sitofp_isposzero:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 0
-; CHECK-NEXT:    ret
-  %npz = or i32 %x, u0x80000000 ; Set sign bit
-  %f = sitofp i32 %npz to float
-  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 64) ; 64 = pos_zero
+  %n = or i32 %x, u0x80000000 ; Set sign bit
+  %f = sitofp i32 %n to float
+  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 960) ; 960 = positive
   ret i1 %res
 }
 
-define i1 @sitofp_isneg(i32 %x) {
-; CHECK-LABEL: sitofp_isneg:
+define i1 @sitofp_is_neg(i32 %x) {
+; CHECK-LABEL: sitofp_is_neg:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
-  %nn = and i32 %x, u0x7fffffff ; Clear sign bit
-  %f = sitofp i32 %nn to float
+  %p = and i32 %x, u0x7fffffff ; Clear sign bit
+  %f = sitofp i32 %p to float
   %res = call i1 @llvm.is.fpclass.f32(float %f, i32 60) ; 60 = negative
   ret i1 %res
 }
 
-define i1 @sitofp_isnonneg(i32 %x) {
-; CHECK-LABEL: sitofp_isnonneg:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a0, 0
-; CHECK-NEXT:    ret
-  %n = or i32 %x, u0x80000000 ; Set sign bit
-  %f = sitofp i32 %n to float
-  %res = call i1 @llvm.is.fpclass.f32(float %f, i32 960) ; 960 = positive
-  ret i1 %res
-}
-
-define i1 @sitofp_isinf(i32 %x) {
-; CHECK-LABEL: sitofp_isinf:
+define i1 @sitofp_is_inf(i32 %x) {
+; CHECK-LABEL: sitofp_is_inf:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    li a0, 0
 ; CHECK-NEXT:    ret
@@ -330,120 +259,31 @@ define i1 @sitofp_isinf(i32 %x) {
   ret i1 %res
 }
 
-define <4 x i1> @uitofp_v4_isnan(<4 x i32> %x) {
-; CHECK-LABEL: uitofp_v4_isnan:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
-; CHECK-NEXT:    vmclr.m v0
-; CHECK-NEXT:    ret
-  %f = uitofp <4 x i32> %x to <4 x float>
-  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 3) ; 3 = nan
-  ret <4 x i1> %res
-}
-
-define <4 x i1> @uitofp_v4_issubnormal(<4 x i32> %x) {
-; CHECK-LABEL: uitofp_v4_issubnormal:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
-; CHECK-NEXT:    vmclr.m v0
-; CHECK-NEXT:    ret
-  %f = uitofp <4 x i32> %x to <4 x float>
-  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 144) ; 144 subnormal
-  ret <4 x i1> %res
-}
-
-define <4 x i1> @uitofp_v4_isnegzero(<4 x i32> %x) {
-; CHECK-LABEL: uitofp_v4_isnegzero:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
-; CHECK-NEXT:    vmclr.m v0
-; CHECK-NEXT:    ret
-  %f = uitofp <4 x i32> %x to <4 x float>
-  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 32); 32 = neg_zero
-  ret <4 x i1> %res
-}
-
-define <4 x i1> @uitofp_v4_isneg(<4 x i32> %x) {
-; CHECK-LABEL: uitofp_v4_isneg:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
-; CHECK-NEXT:    vmclr.m v0
-; CHECK-NEXT:    ret
-  %f = uitofp <4 x i32> %x to <4 x float>
-  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 60) ; 60 = negative
-  ret <4 x i1> %res
-}
-
-define <4 x i1> @uitofp_v4_isposzero(<4 x i32> %x) {
-; CHECK-LABEL: uitofp_v4_isposzero:
+define <4 x i1> @uitofp_v4_is_nan_neg_zero_subnorm(<4 x i32> %x) {
+; CHECK-LABEL: uitofp_v4_is_nan_neg_zero_subnorm:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
 ; CHECK-NEXT:    vmclr.m v0
 ; CHECK-NEXT:    ret
   %nz = or <4 x i32> %x, <i32 1, i32 1, i32 1, i32 1>
   %f = uitofp <4 x i32> %nz to <4 x float>
-  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 64) ; 64 = pos_zero
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 255)
   ret <4 x i1> %res
 }
 
-define <4 x i1> @uitofp_v4_isinf(<4 x i32> %x) {
-; CHECK-LABEL: uitofp_v4_isinf:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
-; CHECK-NEXT:    vmclr.m v0
-; CHECK-NEXT:    ret
-  %f = uitofp <4 x i32> %x to <4 x float>
-  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 516) ; 516 = inf
-  ret <4 x i1> %res
-}
-
-define <4 x i1> @sitofp_v4_isnan(<4 x i32> %x) {
-; CHECK-LABEL: sitofp_v4_isnan:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
-; CHECK-NEXT:    vmclr.m v0
-; CHECK-NEXT:    ret
-  %f = sitofp <4 x i32> %x to <4 x float>
-  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 3) ; 3 = nan
-  ret <4 x i1> %res
-}
-
-define <4 x i1> @sitofp_v4_issubnormal(<4 x i32> %x) {
-; CHECK-LABEL: sitofp_v4_issubnormal:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
-; CHECK-NEXT:    vmclr.m v0
-; CHECK-NEXT:    ret
-  %f = sitofp <4 x i32> %x to <4 x float>
-  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 144) ; 144 = subnormal
-  ret <4 x i1> %res
-}
-
-define <4 x i1> @sitofp_v4_isnegzero(<4 x i32> %x) {
-; CHECK-LABEL: sitofp_v4_isnegzero:
+define <4 x i1> @sitofp_v4_is_nan_subnorm_negzero(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_is_nan_subnorm_negzero:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
 ; CHECK-NEXT:    vmclr.m v0
 ; CHECK-NEXT:    ret
   %f = sitofp <4 x i32> %x to <4 x float>
-  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 32) ; 32 = neg_zero
-  ret <4 x i1> %res
-}
-
-define <4 x i1> @sitofp_v4_isposzero(<4 x i32> %x) {
-; CHECK-LABEL: sitofp_v4_isposzero:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
-; CHECK-NEXT:    vmclr.m v0
-; CHECK-NEXT:    ret
-  %npz = or <4 x i32> %x, <i32 u0x80000000, i32 u0x80000000, i32 u0x80000000, i32 u0x80000000> ; Set sign bit
-  %f = sitofp <4 x i32> %npz to <4 x float>
-  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 64)  ; 64 = pos_zero
+  %res = call <4 x i1> @llvm.is.fpclass.v4f32(<4 x float> %f, i32 179) ; 179 = nan | subnorm | negzero
   ret <4 x i1> %res
 }
 
-define <4 x i1> @sitofp_v4_isneg(<4 x i32> %x) {
-; CHECK-LABEL: sitofp_v4_isneg:
+define <4 x i1> @sitofp_v4_is_neg(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_is_neg:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
 ; CHECK-NEXT:    vmclr.m v0
@@ -454,8 +294,8 @@ define <4 x i1> @sitofp_v4_isneg(<4 x i32> %x) {
   ret <4 x i1> %res
 }
 
-define <4 x i1> @sitofp_v4_isnonneg(<4 x i32> %x) {
-; CHECK-LABEL: sitofp_v4_isnonneg:
+define <4 x i1> @sitofp_v4_is_pos(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_is_pos:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
 ; CHECK-NEXT:    vmclr.m v0
@@ -466,8 +306,8 @@ define <4 x i1> @sitofp_v4_isnonneg(<4 x i32> %x) {
   ret <4 x i1> %res
 }
 
-define <4 x i1> @sitofp_v4_isinf(<4 x i32> %x) {
-; CHECK-LABEL: sitofp_v4_isinf:
+define <4 x i1> @sitofp_v4_is_inf(<4 x i32> %x) {
+; CHECK-LABEL: sitofp_v4_is_inf:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma
 ; CHECK-NEXT:    vmclr.m v0

>From ad6e842ba54061e2fd7a969aeac8ceb12b6897a6 Mon Sep 17 00:00:00 2001
From: Pau Sum <pau at sumpau.com>
Date: Thu, 7 May 2026 00:41:44 -0400
Subject: [PATCH 10/10] Add uitofp inf check that does not fold

---
 llvm/test/CodeGen/RISCV/combine-is_fpclass.ll | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index 5700f62ee48c9..c4e3ffa6e67c0 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
-; RUN: llc -mtriple=riscv64 -mattr=+v,+f,+d < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+v,+f,+d,+zfh < %s | FileCheck %s
 
 define i1 @isneginf_constant_f32() nounwind {
 ; CHECK-LABEL: isneginf_constant_f32:
@@ -217,6 +217,19 @@ define i1 @uitofp_is_inf(i32 %x) {
   ret i1 %res
 }
 
+define i1 @uitofp_is_maybe_inf(i32 %x) {
+; CHECK-LABEL: uitofp_is_maybe_inf:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    fcvt.h.wu fa5, a0
+; CHECK-NEXT:    fclass.h a0, fa5
+; CHECK-NEXT:    slli a0, a0, 56
+; CHECK-NEXT:    srli a0, a0, 63
+; CHECK-NEXT:    ret
+  %f = uitofp i32 %x to half
+  %res = call i1 @llvm.is.fpclass.f16(half %f, i32 516) ; 516 = inf
+  ret i1 %res
+}
+
 define i1 @sitofp_is_nan_subnorm_negzero(i32 %x) {
 ; CHECK-LABEL: sitofp_is_nan_subnorm_negzero:
 ; CHECK:       # %bb.0:



More information about the llvm-commits mailing list