[llvm] 9a33125 - [DAG] Add basic ISD::IS_FPCLASS constant/identity folds (#189944)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 1 06:06:32 PDT 2026
Author: Simon Pilgrim
Date: 2026-04-01T13:06:27Z
New Revision: 9a33125e42925c1e4a9c9f83a2f251b046dd65cd
URL: https://github.com/llvm/llvm-project/commit/9a33125e42925c1e4a9c9f83a2f251b046dd65cd
DIFF: https://github.com/llvm/llvm-project/commit/9a33125e42925c1e4a9c9f83a2f251b046dd65cd.diff
LOG: [DAG] Add basic ISD::IS_FPCLASS constant/identity folds (#189944)
Attempts to match middle-end implementation in InstructionSimplify/foldIntrinsicIsFPClass
Fixes #189919
Added:
Modified:
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
llvm/test/CodeGen/LoongArch/is_fpclass_f32.ll
llvm/test/CodeGen/LoongArch/is_fpclass_f64.ll
llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 6ad5df3d3272c..dbca440a0d199 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -489,6 +489,7 @@ namespace {
SDValue visitANY_EXTEND(SDNode *N);
SDValue visitAssertExt(SDNode *N);
SDValue visitAssertAlign(SDNode *N);
+ SDValue visitIS_FPCLASS(SDNode *N);
SDValue visitSIGN_EXTEND_INREG(SDNode *N);
SDValue visitEXTEND_VECTOR_INREG(SDNode *N);
SDValue visitTRUNCATE(SDNode *N);
@@ -2009,6 +2010,7 @@ SDValue DAGCombiner::visit(SDNode *N) {
case ISD::AssertSext:
case ISD::AssertZext: return visitAssertExt(N);
case ISD::AssertAlign: return visitAssertAlign(N);
+ case ISD::IS_FPCLASS: return visitIS_FPCLASS(N);
case ISD::SIGN_EXTEND_INREG: return visitSIGN_EXTEND_INREG(N);
case ISD::SIGN_EXTEND_VECTOR_INREG:
case ISD::ZERO_EXTEND_VECTOR_INREG:
@@ -16012,6 +16014,27 @@ SDValue DAGCombiner::visitAssertAlign(SDNode *N) {
return SDValue();
}
+SDValue DAGCombiner::visitIS_FPCLASS(SDNode *N) {
+ SDValue Src = N->getOperand(0);
+ FPClassTest Mask = static_cast<FPClassTest>(N->getConstantOperandVal(1));
+ EVT VT = N->getValueType(0);
+ SDLoc DL(N);
+
+ KnownFPClass Known = DAG.computeKnownFPClass(Src, Mask);
+
+ // Clear test bits we know must be false from the source value.
+ // fp_class (nnan x), qnan|snan|other -> fp_class (nnan x), other
+ // fp_class (ninf x), ninf|pinf|other -> fp_class (ninf x), other
+ if ((Mask & Known.KnownFPClasses) != Mask) {
+ return DAG.getNode(
+ ISD::IS_FPCLASS, DL, VT, Src,
+ DAG.getTargetConstant(Mask & Known.KnownFPClasses, DL, MVT::i32),
+ N->getFlags());
+ }
+
+ return SDValue();
+}
+
/// If the result of a load is shifted/masked/truncated to an effectively
/// narrower type, try to transform the load to a narrower type and/or
/// use an extending load.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 3716de880cce3..f60a006c51e82 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -8290,6 +8290,18 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
N2.getOpcode() == ISD::TargetConstant && "Invalid FP_ROUND!");
if (N1.getValueType() == VT) return N1; // noop conversion.
break;
+ case ISD::IS_FPCLASS: {
+ assert(N1.getValueType().isFloatingPoint() &&
+ "IS_FPCLASS is used for a non-floating type");
+ assert(isa<ConstantSDNode>(N2) && "FPClassTest is not Constant");
+ FPClassTest Mask = static_cast<FPClassTest>(N2->getAsZExtVal());
+ // If all tests are made, it doesn't matter what the value is.
+ if ((Mask & fcAllFlags) == fcAllFlags)
+ return getBoolConstant(true, DL, VT, N1.getValueType());
+ if ((Mask & fcAllFlags) == 0)
+ return getBoolConstant(false, DL, VT, N1.getValueType());
+ break;
+ }
case ISD::AssertNoFPClass: {
assert(N1.getValueType().isFloatingPoint() &&
"AssertNoFPClass is used for a non-floating type");
diff --git a/llvm/test/CodeGen/LoongArch/is_fpclass_f32.ll b/llvm/test/CodeGen/LoongArch/is_fpclass_f32.ll
index af128fa52e1d2..fdbea762a1111 100644
--- a/llvm/test/CodeGen/LoongArch/is_fpclass_f32.ll
+++ b/llvm/test/CodeGen/LoongArch/is_fpclass_f32.ll
@@ -447,10 +447,7 @@ entry:
define i1 @isnone_f(float %x) {
; CHECK-LABEL: isnone_f:
; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: fclass.s $fa0, $fa0
-; CHECK-NEXT: movfr2gr.s $a0, $fa0
-; CHECK-NEXT: andi $a0, $a0, 0
-; CHECK-NEXT: sltu $a0, $zero, $a0
+; CHECK-NEXT: move $a0, $zero
; CHECK-NEXT: ret
entry:
%0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 0)
@@ -460,10 +457,7 @@ entry:
define i1 @isany_f(float %x) {
; CHECK-LABEL: isany_f:
; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: fclass.s $fa0, $fa0
-; CHECK-NEXT: movfr2gr.s $a0, $fa0
-; CHECK-NEXT: andi $a0, $a0, 1023
-; CHECK-NEXT: sltu $a0, $zero, $a0
+; CHECK-NEXT: ori $a0, $zero, 1
; CHECK-NEXT: ret
entry:
%0 = tail call i1 @llvm.is.fpclass.f32(float %x, i32 1023)
diff --git a/llvm/test/CodeGen/LoongArch/is_fpclass_f64.ll b/llvm/test/CodeGen/LoongArch/is_fpclass_f64.ll
index e58f81a08e4c5..d10e21ccbf705 100644
--- a/llvm/test/CodeGen/LoongArch/is_fpclass_f64.ll
+++ b/llvm/test/CodeGen/LoongArch/is_fpclass_f64.ll
@@ -719,18 +719,12 @@ entry:
define i1 @isnone_d(double %x) {
; CHECK32-LABEL: isnone_d:
; CHECK32: # %bb.0: # %entry
-; CHECK32-NEXT: fclass.d $fa0, $fa0
-; CHECK32-NEXT: movfr2gr.s $a0, $fa0
-; CHECK32-NEXT: andi $a0, $a0, 0
-; CHECK32-NEXT: sltu $a0, $zero, $a0
+; CHECK32-NEXT: move $a0, $zero
; CHECK32-NEXT: ret
;
; CHECK64-LABEL: isnone_d:
; CHECK64: # %bb.0: # %entry
-; CHECK64-NEXT: fclass.d $fa0, $fa0
-; CHECK64-NEXT: movfr2gr.d $a0, $fa0
-; CHECK64-NEXT: andi $a0, $a0, 0
-; CHECK64-NEXT: sltu $a0, $zero, $a0
+; CHECK64-NEXT: move $a0, $zero
; CHECK64-NEXT: ret
entry:
%0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 0)
@@ -740,18 +734,12 @@ entry:
define i1 @isany_d(double %x) {
; CHECK32-LABEL: isany_d:
; CHECK32: # %bb.0: # %entry
-; CHECK32-NEXT: fclass.d $fa0, $fa0
-; CHECK32-NEXT: movfr2gr.s $a0, $fa0
-; CHECK32-NEXT: andi $a0, $a0, 1023
-; CHECK32-NEXT: sltu $a0, $zero, $a0
+; CHECK32-NEXT: ori $a0, $zero, 1
; CHECK32-NEXT: ret
;
; CHECK64-LABEL: isany_d:
; CHECK64: # %bb.0: # %entry
-; CHECK64-NEXT: fclass.d $fa0, $fa0
-; CHECK64-NEXT: movfr2gr.d $a0, $fa0
-; CHECK64-NEXT: andi $a0, $a0, 1023
-; CHECK64-NEXT: sltu $a0, $zero, $a0
+; CHECK64-NEXT: ori $a0, $zero, 1
; CHECK64-NEXT: ret
entry:
%0 = tail call i1 @llvm.is.fpclass.f64(double %x, i32 1023)
diff --git a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
index 07c22ecf130d0..0292df415a655 100644
--- a/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
+++ b/llvm/test/CodeGen/RISCV/combine-is_fpclass.ll
@@ -4,10 +4,7 @@
define i1 @isneginf_constant_f32() nounwind {
; CHECK-LABEL: isneginf_constant_f32:
; CHECK: # %bb.0:
-; CHECK-NEXT: lui a0, 260096
-; CHECK-NEXT: fmv.w.x fa5, a0
-; CHECK-NEXT: fclass.s a0, fa5
-; CHECK-NEXT: andi a0, a0, 1
+; CHECK-NEXT: li a0, 0
; CHECK-NEXT: ret
%f = tail call i1 @llvm.is.fpclass.f32(float 1.0, i32 4) ; 0x4 = "neginf"
ret i1 %f
@@ -16,16 +13,9 @@ define i1 @isneginf_constant_f32() nounwind {
define i8 @iszero_constant_v4f32() nounwind {
; CHECK-LABEL: iszero_constant_v4f32:
; CHECK: # %bb.0:
-; CHECK-NEXT: lui a0, %hi(.LCPI1_0)
-; CHECK-NEXT: addi a0, a0, %lo(.LCPI1_0)
-; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma
-; CHECK-NEXT: vle32.v v8, (a0)
-; CHECK-NEXT: vfclass.v v8, v8
-; CHECK-NEXT: li a0, 24
-; CHECK-NEXT: vand.vx v8, v8, a0
-; CHECK-NEXT: vmsne.vi v10, v8, 0
-; CHECK-NEXT: vsetvli zero, zero, e8, mf2, ta, ma
-; CHECK-NEXT: vmv.x.s a0, v10
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vmclr.m v8
+; CHECK-NEXT: vmv.x.s a0, v8
; CHECK-NEXT: ret
%f = tail call <8 x i1> @llvm.is.fpclass.v4f32(<8 x float> <float 1.0, float 2.0, float 3.0, float 4.0, float -1.0, float -2.0, float -3.0, float -4.0>, i32 96) ; 0x60 = "zero"
%r = bitcast <8 x i1> %f to i8
More information about the llvm-commits
mailing list