[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