[llvm] CodeGen: Add ISD::AssertNoFPClass (PR #135946)

YunQiang Su via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 20 20:44:02 PDT 2025


https://github.com/wzssyqa updated https://github.com/llvm/llvm-project/pull/135946

>From 62e1163a9eaadbb3fe845f2d7ee40a91d1189dee Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Wed, 16 Apr 2025 18:10:21 +0800
Subject: [PATCH 1/6] CodeGen: Add ISD::AssertNoFPClass

It is used to mark a value that we are sure that it is not some fcType.
The examples include:
  * An arguments of a function is marked with nofpclass
  * Output value of an intrinsic can be sure to not be some type
So that the following operation can make some assumptions.
---
 llvm/include/llvm/CodeGen/ISDOpcodes.h                | 6 ++++++
 llvm/include/llvm/Target/TargetSelectionDAG.td        | 1 +
 llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp  | 3 +++
 llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp | 3 +++
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp        | 4 ++++
 llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp  | 1 +
 llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp    | 1 +
 7 files changed, 19 insertions(+)

diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index ad8a95a353b56..7a9b716f652f3 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -67,6 +67,12 @@ enum NodeType {
   /// poisoned the assertion will not be true for that value.
   AssertAlign,
 
+  /// AssertNoFPClass - These nodes record if a register contains a float
+  /// value that is known to be not some type.
+  /// NOTE: In case of the source value (or any vector element value) is
+  /// poisoned the assertion will not be true for that value.
+  AssertNoFPClass,
+
   /// Various leaf nodes.
   BasicBlock,
   VALUETYPE,
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 9c241b6c4df0f..8453cf7f4e58a 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -859,6 +859,7 @@ def SDT_assert : SDTypeProfile<1, 1,
   [SDTCisInt<0>, SDTCisInt<1>, SDTCisSameAs<1, 0>]>;
 def assertsext : SDNode<"ISD::AssertSext", SDT_assert>;
 def assertzext : SDNode<"ISD::AssertZext", SDT_assert>;
+def assernofpclass : SDNode<"ISD::AssertNoFPClass", SDTFPUnaryOp>;
 def assertalign : SDNode<"ISD::AssertAlign", SDT_assert>;
 
 def convergencectrl_anchor : SDNode<"ISD::CONVERGENCECTRL_ANCHOR",
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 432209e8ecb0a..d03eeaa01b697 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -168,6 +168,7 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) {
     case ISD::POISON:
     case ISD::UNDEF:       R = SoftenFloatRes_UNDEF(N); break;
     case ISD::VAARG:       R = SoftenFloatRes_VAARG(N); break;
+    case ISD::AssertNoFPClass:       R = GetSoftenedFloat(N->getOperand(0)); break;
     case ISD::VECREDUCE_FADD:
     case ISD::VECREDUCE_FMUL:
     case ISD::VECREDUCE_FMIN:
@@ -2576,6 +2577,7 @@ bool DAGTypeLegalizer::PromoteFloatOperand(SDNode *N, unsigned OpNo) {
       R = PromoteFloatOp_FAKE_USE(N, OpNo);
       break;
     case ISD::FCOPYSIGN:  R = PromoteFloatOp_FCOPYSIGN(N, OpNo); break;
+    case ISD::AssertNoFPClass:
     case ISD::FP_TO_SINT:
     case ISD::FP_TO_UINT:
     case ISD::LROUND:
@@ -2803,6 +2805,7 @@ void DAGTypeLegalizer::PromoteFloatResult(SDNode *N, unsigned ResNo) {
     case ISD::FTRUNC:
     case ISD::FTAN:
     case ISD::FTANH:
+    case ISD::AssertNoFPClass:
     case ISD::FCANONICALIZE: R = PromoteFloatRes_UnaryOp(N); break;
 
     // Binary FP Operations
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index a01e1cff74564..54da9fe3c6a40 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -129,6 +129,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
   case ISD::UINT_TO_FP:
   case ISD::ZERO_EXTEND:
   case ISD::FCANONICALIZE:
+  case ISD::AssertNoFPClass:
     R = ScalarizeVecRes_UnaryOp(N);
     break;
   case ISD::ADDRSPACECAST:
@@ -1276,6 +1277,7 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
   case ISD::UINT_TO_FP:
   case ISD::VP_UINT_TO_FP:
   case ISD::FCANONICALIZE:
+  case ISD::AssertNoFPClass:
     SplitVecRes_UnaryOp(N, Lo, Hi);
     break;
   case ISD::ADDRSPACECAST:
@@ -4844,6 +4846,7 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
   case ISD::FREEZE:
   case ISD::ARITH_FENCE:
   case ISD::FCANONICALIZE:
+  case ISD::AssertNoFPClass:
     Res = WidenVecRes_Unary(N);
     break;
   case ISD::FMA: case ISD::VP_FMA:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index f502a536d43b1..3c7367ac7002a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -7406,6 +7406,10 @@ 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::AssertNoFPClass:
+    assert(N1.getValueType().isFloatingPoint() &&
+           "AssertNoFPClass is used for a non-floating type");
+    return N1;
   case ISD::AssertSext:
   case ISD::AssertZext: {
     EVT EVT = cast<VTSDNode>(N2)->getVT();
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 8fcec6c6cd7c6..240115ac739f0 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -122,6 +122,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
   case ISD::TokenFactor:                return "TokenFactor";
   case ISD::AssertSext:                 return "AssertSext";
   case ISD::AssertZext:                 return "AssertZext";
+  case ISD::AssertNoFPClass:            return "AssertNoFPClass";
   case ISD::AssertAlign:                return "AssertAlign";
 
   case ISD::BasicBlock:                 return "BasicBlock";
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 598de6b207754..62d911fed2a3f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -3265,6 +3265,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
     return;
   case ISD::AssertSext:
   case ISD::AssertZext:
+  case ISD::AssertNoFPClass:
   case ISD::AssertAlign:
     ReplaceUses(SDValue(NodeToMatch, 0), NodeToMatch->getOperand(0));
     CurDAG->RemoveDeadNode(NodeToMatch);

>From e727de166f33911ddf501e0270cf098df9ab08c6 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Fri, 18 Apr 2025 11:19:08 +0800
Subject: [PATCH 2/6] fix typo assernofpclass

---
 llvm/include/llvm/Target/TargetSelectionDAG.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 8453cf7f4e58a..156fbb925873e 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -859,7 +859,7 @@ def SDT_assert : SDTypeProfile<1, 1,
   [SDTCisInt<0>, SDTCisInt<1>, SDTCisSameAs<1, 0>]>;
 def assertsext : SDNode<"ISD::AssertSext", SDT_assert>;
 def assertzext : SDNode<"ISD::AssertZext", SDT_assert>;
-def assernofpclass : SDNode<"ISD::AssertNoFPClass", SDTFPUnaryOp>;
+def assertnofpclass : SDNode<"ISD::AssertNoFPClass", SDTFPUnaryOp>;
 def assertalign : SDNode<"ISD::AssertAlign", SDT_assert>;
 
 def convergencectrl_anchor : SDNode<"ISD::CONVERGENCECTRL_ANCHOR",

>From 1024b94f87e8e3053f04a2f344117040b709aecf Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 21 Apr 2025 10:48:36 +0800
Subject: [PATCH 3/6] Add isKnownNeverNaN test

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp      | 13 ++++++++++++-
 .../CodeGen/SelectionDAG/SelectionDAGBuilder.cpp    | 10 ++++++++++
 llvm/test/CodeGen/AArch64/nofpclass.ll              | 12 ++++++++++++
 3 files changed, 34 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/AArch64/nofpclass.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 3c7367ac7002a..68d8fd5a93f38 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5760,6 +5760,17 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
         return false;
     return true;
   }
+  case ISD::AssertNoFPClass: {
+    SDValue SDNoFPClass = Op.getOperand(1);
+    assert(isa<ConstantSDNode>(SDNoFPClass) && "NoFPClass is not Constant");
+    FPClassTest NoFPClass = static_cast<FPClassTest>(
+        dyn_cast<ConstantSDNode>(SDNoFPClass)->getZExtValue());
+    if (NoFPClass & fcNan)
+      return true;
+    if (SNaN && (NoFPClass & fcSNan))
+      return true;
+    return isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1);
+  }
   default:
     if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
         Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
@@ -7409,7 +7420,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
   case ISD::AssertNoFPClass:
     assert(N1.getValueType().isFloatingPoint() &&
            "AssertNoFPClass is used for a non-floating type");
-    return N1;
+    break;
   case ISD::AssertSext:
   case ISD::AssertZext: {
     EVT EVT = cast<VTSDNode>(N2)->getVT();
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index d7a67cca3c197..9e8cdb21536f2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11848,6 +11848,16 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
     SDValue Res = DAG.getMergeValues(ArrayRef(ArgValues.data(), NumValues),
                                      SDB->getCurSDLoc());
 
+    FPClassTest NoFPClass = Arg.getNoFPClass();
+    if (NoFPClass != fcNone) {
+      EVT I64EVT = EVT::getIntegerVT(*DAG.getContext(), 64);
+      SDValue SDNoFPClass =
+          DAG.getConstant(static_cast<uint64_t>(NoFPClass), dl, I64EVT);
+      SDNodeFlags ResFlags = Res->getFlags();
+      Res = DAG.getNode(ISD::AssertNoFPClass, dl, Res.getValueType(), Res,
+                        SDNoFPClass, ResFlags);
+    }
+
     SDB->setValue(&Arg, Res);
     if (!TM.Options.EnableFastISel && Res.getOpcode() == ISD::BUILD_PAIR) {
       // We want to associate the argument with the frame index, among
diff --git a/llvm/test/CodeGen/AArch64/nofpclass.ll b/llvm/test/CodeGen/AArch64/nofpclass.ll
new file mode 100644
index 0000000000000..f34081699a5a4
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/nofpclass.ll
@@ -0,0 +1,12 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=aarch64-linux-gnu < %s | FileCheck %s
+
+define nofpclass(nzero) float @f(float noundef nofpclass(nan) %a, float noundef nofpclass(nan) %b) {
+; CHECK-LABEL: f:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fmaxnm s0, s0, s1
+; CHECK-NEXT:    ret
+entry:
+  %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
+  ret float %cond
+}

>From d77aef15ba338b10800425720cd5a6fe429199fb Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 21 Apr 2025 10:52:27 +0800
Subject: [PATCH 4/6] Mention operands

---
 llvm/include/llvm/CodeGen/ISDOpcodes.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 7a9b716f652f3..1b3ac8dc3ee8a 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -69,6 +69,9 @@ enum NodeType {
 
   /// AssertNoFPClass - These nodes record if a register contains a float
   /// value that is known to be not some type.
+  /// This node takes two operands.  The first is the node that is known
+  /// never to be a float type. and the second is a constant value with
+  /// the value of FPClassTest (casted to uint64_t).
   /// NOTE: In case of the source value (or any vector element value) is
   /// poisoned the assertion will not be true for that value.
   AssertNoFPClass,

>From 5d3aaac0ff6a8946f96d4aed5275625a49aa2695 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 21 Apr 2025 10:56:01 +0800
Subject: [PATCH 5/6] Fix typo

---
 llvm/include/llvm/CodeGen/ISDOpcodes.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 1b3ac8dc3ee8a..3fc1457f835b9 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -70,7 +70,7 @@ enum NodeType {
   /// AssertNoFPClass - These nodes record if a register contains a float
   /// value that is known to be not some type.
   /// This node takes two operands.  The first is the node that is known
-  /// never to be a float type. and the second is a constant value with
+  /// never to be some float types. and the second is a constant value with
   /// the value of FPClassTest (casted to uint64_t).
   /// NOTE: In case of the source value (or any vector element value) is
   /// poisoned the assertion will not be true for that value.

>From b06150fa18402e636ae015f029b01d9caf57518f Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 21 Apr 2025 11:43:40 +0800
Subject: [PATCH 6/6] Fix AssertNoFPClass assert

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 68d8fd5a93f38..0d1f334dafe85 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -7417,10 +7417,17 @@ 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::AssertNoFPClass:
+  case ISD::AssertNoFPClass: {
     assert(N1.getValueType().isFloatingPoint() &&
            "AssertNoFPClass is used for a non-floating type");
+    assert(isa<ConstantSDNode>(N2) && "NoFPClass is not Constant");
+    FPClassTest NoFPClass =
+        static_cast<FPClassTest>(dyn_cast<ConstantSDNode>(N2)->getZExtValue());
+    assert(llvm::to_underlying(NoFPClass) <=
+               BitmaskEnumDetail::Mask<FPClassTest>() &&
+           "FPClassTest value too large");
     break;
+  }
   case ISD::AssertSext:
   case ISD::AssertZext: {
     EVT EVT = cast<VTSDNode>(N2)->getVT();



More information about the llvm-commits mailing list