[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
Sun Apr 5 17:48:12 PDT 2026
https://github.com/pau-sum updated https://github.com/llvm/llvm-project/pull/190539
>From 0e82bd5d812a9a581aaedc3d5b9667fa6f449966 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] [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 137922aa62557..aaec1d9eb0f4f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6082,6 +6082,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 5049775710628..beeacc1391653 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -22,6 +22,287 @@ define i8 @iszero_constant_v4f32() nounwind {
ret i8 %r
}
+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:
More information about the llvm-commits
mailing list