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

YunQiang Su via llvm-commits llvm-commits at lists.llvm.org
Wed May 7 22:01:23 PDT 2025


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

>From ec390f06db525e1eddb53ac60bd154e3cb23ebd7 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 01/20] 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 80ef32aff62ae..16c086fcf3a8e 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 41fed692c7025..9b1205d4fd453 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -875,6 +875,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 d0b69b88748a9..1f4b1367f7374 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:
@@ -4879,6 +4881,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 2a68903c34cef..9479f993b36ff 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -7491,6 +7491,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 8faf97271d99e..6f846bedf3c82 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -124,6 +124,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 1bc30336a02bf..586728a44571e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -3264,6 +3264,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 a49411ca1c4fd4ba9a93e258a8d2ecbe403f1ece 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 02/20] 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 9b1205d4fd453..b28a8b118de7a 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -875,7 +875,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 3dc3f6240669064ad984936dd993e77c95c33f67 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 03/20] 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 9479f993b36ff..6b8291e27cbf2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5832,6 +5832,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) {
@@ -7494,7 +7505,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 9d138d364bad7..26c60918a12a2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11823,6 +11823,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 2a976f3dd6fbfdc687ebf330b182742e83c8f17a 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 04/20] 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 16c086fcf3a8e..a66b367081bc9 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 0923628045757ef90c1bf0207ef864f4baae82e7 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 05/20] 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 a66b367081bc9..f88b681d47772 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 47e8e9860d2003eedc75ae71710836adbcf25ced 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 06/20] 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 6b8291e27cbf2..691f1c0d575e4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -7502,10 +7502,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();

>From ab90805413de0fa0ba5ceeaba14119a54a5e9e8b Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Wed, 7 May 2025 18:12:20 +0800
Subject: [PATCH 07/20] Fix code styles

1. Use Op.getConstantOperandVal to get Constant value
2. (NoFPClass & fcNan) == fcNan
3. Use N2->getAsZExtValue() to get Constant value
4. Use getTargetConstant with ptr width to fix 32bit target
5. Don't propagate the flags
6. Add MIPSr6 testcase for 32bit target tests
---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 13 +++++--------
 .../SelectionDAG/SelectionDAGBuilder.cpp       |  7 +++----
 llvm/test/CodeGen/Mips/nofpclass.ll            | 18 ++++++++++++++++++
 3 files changed, 26 insertions(+), 12 deletions(-)
 create mode 100644 llvm/test/CodeGen/Mips/nofpclass.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 691f1c0d575e4..60b2018b1228f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5833,13 +5833,11 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
     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)
+    FPClassTest NoFPClass =
+        static_cast<FPClassTest>(Op.getConstantOperandVal(1));
+    if ((NoFPClass & fcNan) == fcNan)
       return true;
-    if (SNaN && (NoFPClass & fcSNan))
+    if (SNaN && (NoFPClass & fcSNan) == fcSNan)
       return true;
     return isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1);
   }
@@ -7506,8 +7504,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
     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());
+    FPClassTest NoFPClass = static_cast<FPClassTest>(N2->getAsZExtVal());
     assert(llvm::to_underlying(NoFPClass) <=
                BitmaskEnumDetail::Mask<FPClassTest>() &&
            "FPClassTest value too large");
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 26c60918a12a2..189fd1dc68e90 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11825,12 +11825,11 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
 
     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();
+          DAG.getTargetConstant(static_cast<uint64_t>(NoFPClass), dl,
+                                TLI->getPointerTy(DAG.getDataLayout()));
       Res = DAG.getNode(ISD::AssertNoFPClass, dl, Res.getValueType(), Res,
-                        SDNoFPClass, ResFlags);
+                        SDNoFPClass);
     }
 
     SDB->setValue(&Arg, Res);
diff --git a/llvm/test/CodeGen/Mips/nofpclass.ll b/llvm/test/CodeGen/Mips/nofpclass.ll
new file mode 100644
index 0000000000000..a1eab763f4d01
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/nofpclass.ll
@@ -0,0 +1,18 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc --mtriple=mipsisa32r6-linux-gnu < %s | FileCheck %s --check-prefix=MIPS32R6
+; RUN: llc --mtriple=mipsisa64r6-linux-gnu < %s | FileCheck %s --check-prefix=MIPS64R6
+
+define nofpclass(nzero) float @f(float nofpclass(nan) %a, float nofpclass(nan) %b) {
+; MIPS32R6-LABEL: f:
+; MIPS32R6:       # %bb.0: # %entry
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f14
+;
+; MIPS64R6-LABEL: f:
+; MIPS64R6:       # %bb.0: # %entry
+; MIPS64R6-NEXT:    jr $ra
+; MIPS64R6-NEXT:    max.s $f0, $f12, $f13
+entry:
+  %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
+  ret float %cond
+}

>From bdfb262906e2d3836b3d8a9ee76178c668babb3a Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 21 Apr 2025 18:36:37 +0800
Subject: [PATCH 08/20] Add Vector test case

---
 llvm/test/CodeGen/AArch64/nofpclass.ll | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/AArch64/nofpclass.ll b/llvm/test/CodeGen/AArch64/nofpclass.ll
index f34081699a5a4..2a8c64f94737e 100644
--- a/llvm/test/CodeGen/AArch64/nofpclass.ll
+++ b/llvm/test/CodeGen/AArch64/nofpclass.ll
@@ -1,7 +1,7 @@
 ; 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) {
+define nofpclass(nzero) float @f(float nofpclass(nan) %a, float nofpclass(nan) %b) {
 ; CHECK-LABEL: f:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    fmaxnm s0, s0, s1
@@ -10,3 +10,13 @@ entry:
   %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
   ret float %cond
 }
+
+define <4 x float> @fv4f32(<4 x float> nofpclass(nan) %a, <4 x float> nofpclass(nan) %b) {
+; CHECK-LABEL: fv4f32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fmaxnm v0.4s, v0.4s, v1.4s
+; CHECK-NEXT:    ret
+entry:
+  %c = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> %a, <4 x float> %b)
+  ret <4 x float> %c
+}

>From 5132dea13390f2baead04b880cb25f527d2473e3 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 21 Apr 2025 20:21:44 +0800
Subject: [PATCH 09/20] Add DemandedElts

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 60b2018b1228f..5fc240dfc86d7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5839,7 +5839,7 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
       return true;
     if (SNaN && (NoFPClass & fcSNan) == fcSNan)
       return true;
-    return isKnownNeverNaN(Op.getOperand(0), SNaN, Depth + 1);
+    return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1);
   }
   default:
     if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||

>From 27d3f1c5f339ffdaecc74ece611ade8fa02d0e74 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 21 Apr 2025 20:57:17 +0800
Subject: [PATCH 10/20] Use 32bit target

---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 189fd1dc68e90..084279b3b4004 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11827,7 +11827,7 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
     if (NoFPClass != fcNone) {
       SDValue SDNoFPClass =
           DAG.getTargetConstant(static_cast<uint64_t>(NoFPClass), dl,
-                                TLI->getPointerTy(DAG.getDataLayout()));
+                                EVT::getIntegerVT(*DAG.getContext(), 32));
       Res = DAG.getNode(ISD::AssertNoFPClass, dl, Res.getValueType(), Res,
                         SDNoFPClass);
     }

>From ad3fbcb7739c0c1f238efa263272b19e53779434 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Mon, 21 Apr 2025 21:23:17 +0800
Subject: [PATCH 11/20] Fix MERGE_VALUE cases

---
 .../SelectionDAG/SelectionDAGBuilder.cpp      | 24 +++++++++----------
 llvm/test/CodeGen/AArch64/nofpclass.ll        |  7 ++++++
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 084279b3b4004..c5f65cee23c5b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11803,9 +11803,18 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
         else if (Arg.hasAttribute(Attribute::ZExt))
           AssertOp = ISD::AssertZext;
 
-        ArgValues.push_back(getCopyFromParts(DAG, dl, &InVals[i], NumParts,
-                                             PartVT, VT, nullptr, NewRoot,
-                                             F.getCallingConv(), AssertOp));
+        SDValue OutVal =
+            getCopyFromParts(DAG, dl, &InVals[i], NumParts, PartVT, VT, nullptr,
+                             NewRoot, F.getCallingConv(), AssertOp);
+
+        FPClassTest NoFPClass = Arg.getNoFPClass();
+        if (NoFPClass != fcNone) {
+          SDValue SDNoFPClass = DAG.getTargetConstant(
+              static_cast<uint64_t>(NoFPClass), dl, MVT::i32);
+          OutVal = DAG.getNode(ISD::AssertNoFPClass, dl, OutVal.getValueType(),
+                               OutVal, SDNoFPClass);
+        }
+        ArgValues.push_back(OutVal);
       }
 
       i += NumParts;
@@ -11823,15 +11832,6 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
     SDValue Res = DAG.getMergeValues(ArrayRef(ArgValues.data(), NumValues),
                                      SDB->getCurSDLoc());
 
-    FPClassTest NoFPClass = Arg.getNoFPClass();
-    if (NoFPClass != fcNone) {
-      SDValue SDNoFPClass =
-          DAG.getTargetConstant(static_cast<uint64_t>(NoFPClass), dl,
-                                EVT::getIntegerVT(*DAG.getContext(), 32));
-      Res = DAG.getNode(ISD::AssertNoFPClass, dl, Res.getValueType(), Res,
-                        SDNoFPClass);
-    }
-
     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
index 2a8c64f94737e..bf8e5b4783dc8 100644
--- a/llvm/test/CodeGen/AArch64/nofpclass.ll
+++ b/llvm/test/CodeGen/AArch64/nofpclass.ll
@@ -20,3 +20,10 @@ entry:
   %c = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> %a, <4 x float> %b)
   ret <4 x float> %c
 }
+
+define { float, float } @struct({ float, float } nofpclass(nan) %a) {
+; CHECK-LABEL: struct:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ret
+   ret {float, float} %a
+}

>From b729fa4123d1eadb6398f62edd23c56558c6f2c1 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Tue, 22 Apr 2025 08:26:59 +0800
Subject: [PATCH 12/20] Add aggregate tests with fmin

---
 llvm/test/CodeGen/AArch64/nofpclass.ll | 21 ++++++++++++-
 llvm/test/CodeGen/Mips/nofpclass.ll    | 42 ++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/llvm/test/CodeGen/AArch64/nofpclass.ll b/llvm/test/CodeGen/AArch64/nofpclass.ll
index bf8e5b4783dc8..2eff2cf6a22de 100644
--- a/llvm/test/CodeGen/AArch64/nofpclass.ll
+++ b/llvm/test/CodeGen/AArch64/nofpclass.ll
@@ -21,9 +21,28 @@ entry:
   ret <4 x float> %c
 }
 
-define { float, float } @struct({ float, float } nofpclass(nan) %a) {
+define { float, float } @struct({ float, float} nofpclass(nan) %a) {
 ; CHECK-LABEL: struct:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ret
    ret {float, float} %a
 }
+
+%struct.f2 = type { float, float }
+define %struct.f2 @m([2 x float] nofpclass(nan) %a0, [2 x float] nofpclass(nan) %a1) {
+; CHECK-LABEL: m:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fmaxnm s1, s1, s3
+; CHECK-NEXT:    fmaxnm s0, s0, s2
+; CHECK-NEXT:    ret
+entry:
+  %a0f0 = extractvalue [2 x float] %a0, 0
+  %a0f1 = extractvalue [2 x float] %a0, 1
+  %a1f0 = extractvalue [2 x float] %a1, 0
+  %a1f1 = extractvalue [2 x float] %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
+  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
+  ret %struct.f2 %ret1
+}
diff --git a/llvm/test/CodeGen/Mips/nofpclass.ll b/llvm/test/CodeGen/Mips/nofpclass.ll
index a1eab763f4d01..253b90a587bcd 100644
--- a/llvm/test/CodeGen/Mips/nofpclass.ll
+++ b/llvm/test/CodeGen/Mips/nofpclass.ll
@@ -16,3 +16,45 @@ entry:
   %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
   ret float %cond
 }
+
+define { float, float } @struct({ float, float} nofpclass(nan) %a) {
+; MIPS32R6-LABEL: struct:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    mov.s $f2, $f14
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    mov.s $f0, $f12
+;
+; MIPS64R6-LABEL: struct:
+; MIPS64R6:       # %bb.0:
+; MIPS64R6-NEXT:    mov.s $f2, $f13
+; MIPS64R6-NEXT:    jr $ra
+; MIPS64R6-NEXT:    mov.s $f0, $f12
+   ret {float, float} %a
+}
+
+%struct.f2 = type { float, float }
+define %struct.f2 @m([2 x float] nofpclass(nan) %a0, [2 x float] nofpclass(nan) %a1) {
+; MIPS32R6-LABEL: m:
+; MIPS32R6:       # %bb.0: # %entry
+; MIPS32R6-NEXT:    mtc1 $6, $f0
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f0
+; MIPS32R6-NEXT:    mtc1 $7, $f1
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f2, $f14, $f1
+;
+; MIPS64R6-LABEL: m:
+; MIPS64R6:       # %bb.0: # %entry
+; MIPS64R6-NEXT:    max.s $f0, $f12, $f14
+; MIPS64R6-NEXT:    jr $ra
+; MIPS64R6-NEXT:    max.s $f2, $f13, $f15
+entry:
+  %a0f0 = extractvalue [2 x float] %a0, 0
+  %a0f1 = extractvalue [2 x float] %a0, 1
+  %a1f0 = extractvalue [2 x float] %a1, 0
+  %a1f1 = extractvalue [2 x float] %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
+  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
+  ret %struct.f2 %ret1
+}

>From e196c4a56a93822d6e06152af5fe89f3dada8a32 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Tue, 22 Apr 2025 08:28:35 +0800
Subject: [PATCH 13/20] Fix comment

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

diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index f88b681d47772..1042318343987 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -70,8 +70,8 @@ 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 some float types. and the second is a constant value with
-  /// the value of FPClassTest (casted to uint64_t).
+  /// never to be some float types; the second is a constant value with
+  /// the value of FPClassTest (casted to uint32_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 430f146c4409d933c1a5e2c8f317140333d695e4 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Tue, 22 Apr 2025 08:41:57 +0800
Subject: [PATCH 14/20] Add snan and qnan test cases

---
 llvm/test/CodeGen/AArch64/nofpclass.ll | 103 +++++++++++++++++++-
 llvm/test/CodeGen/Mips/nofpclass.ll    | 130 ++++++++++++++++++++++++-
 2 files changed, 229 insertions(+), 4 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/nofpclass.ll b/llvm/test/CodeGen/AArch64/nofpclass.ll
index 2eff2cf6a22de..3218803f3d17a 100644
--- a/llvm/test/CodeGen/AArch64/nofpclass.ll
+++ b/llvm/test/CodeGen/AArch64/nofpclass.ll
@@ -1,7 +1,9 @@
 ; 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 nofpclass(nan) %a, float nofpclass(nan) %b) {
+%struct.f2 = type { float, float }
+
+define float @f(float nofpclass(nan) %a, float nofpclass(nan) %b) {
 ; CHECK-LABEL: f:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    fmaxnm s0, s0, s1
@@ -28,7 +30,6 @@ define { float, float } @struct({ float, float} nofpclass(nan) %a) {
    ret {float, float} %a
 }
 
-%struct.f2 = type { float, float }
 define %struct.f2 @m([2 x float] nofpclass(nan) %a0, [2 x float] nofpclass(nan) %a1) {
 ; CHECK-LABEL: m:
 ; CHECK:       // %bb.0: // %entry
@@ -46,3 +47,101 @@ entry:
   %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
   ret %struct.f2 %ret1
 }
+
+define float @fS(float nofpclass(snan) %a, float nofpclass(snan) %b) {
+; CHECK-LABEL: fS:
+; 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
+}
+
+define <4 x float> @fSv4f32(<4 x float> nofpclass(snan) %a, <4 x float> nofpclass(snan) %b) {
+; CHECK-LABEL: fSv4f32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fmaxnm v0.4s, v0.4s, v1.4s
+; CHECK-NEXT:    ret
+entry:
+  %c = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> %a, <4 x float> %b)
+  ret <4 x float> %c
+}
+
+define { float, float } @structS({ float, float} nofpclass(snan) %a) {
+; CHECK-LABEL: structS:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ret
+   ret {float, float} %a
+}
+
+define %struct.f2 @mS([2 x float] nofpclass(snan) %a0, [2 x float] nofpclass(snan) %a1) {
+; CHECK-LABEL: mS:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fmaxnm s1, s1, s3
+; CHECK-NEXT:    fmaxnm s0, s0, s2
+; CHECK-NEXT:    ret
+entry:
+  %a0f0 = extractvalue [2 x float] %a0, 0
+  %a0f1 = extractvalue [2 x float] %a0, 1
+  %a1f0 = extractvalue [2 x float] %a1, 0
+  %a1f1 = extractvalue [2 x float] %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
+  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
+  ret %struct.f2 %ret1
+}
+
+define float @fQ(float nofpclass(qnan) %a, float nofpclass(qnan) %b) {
+; CHECK-LABEL: fQ:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fminnm s1, s1, s1
+; CHECK-NEXT:    fminnm s0, s0, s0
+; CHECK-NEXT:    fmaxnm s0, s0, s1
+; CHECK-NEXT:    ret
+entry:
+  %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
+  ret float %cond
+}
+
+define <4 x float> @fQv4f32(<4 x float> nofpclass(qnan) %a, <4 x float> nofpclass(qnan) %b) {
+; CHECK-LABEL: fQv4f32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fminnm v1.4s, v1.4s, v1.4s
+; CHECK-NEXT:    fminnm v0.4s, v0.4s, v0.4s
+; CHECK-NEXT:    fmaxnm v0.4s, v0.4s, v1.4s
+; CHECK-NEXT:    ret
+entry:
+  %c = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> %a, <4 x float> %b)
+  ret <4 x float> %c
+}
+
+define { float, float } @structQ({ float, float} nofpclass(qnan) %a) {
+; CHECK-LABEL: structQ:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ret
+   ret {float, float} %a
+}
+
+define %struct.f2 @mQ([2 x float] nofpclass(qnan) %a0, [2 x float] nofpclass(qnan) %a1) {
+; CHECK-LABEL: mQ:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fminnm s2, s2, s2
+; CHECK-NEXT:    fminnm s0, s0, s0
+; CHECK-NEXT:    fminnm s3, s3, s3
+; CHECK-NEXT:    fminnm s1, s1, s1
+; CHECK-NEXT:    fmaxnm s0, s0, s2
+; CHECK-NEXT:    fmaxnm s1, s1, s3
+; CHECK-NEXT:    ret
+entry:
+  %a0f0 = extractvalue [2 x float] %a0, 0
+  %a0f1 = extractvalue [2 x float] %a0, 1
+  %a1f0 = extractvalue [2 x float] %a1, 0
+  %a1f1 = extractvalue [2 x float] %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
+  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
+  ret %struct.f2 %ret1
+}
diff --git a/llvm/test/CodeGen/Mips/nofpclass.ll b/llvm/test/CodeGen/Mips/nofpclass.ll
index 253b90a587bcd..0e035a8da2ada 100644
--- a/llvm/test/CodeGen/Mips/nofpclass.ll
+++ b/llvm/test/CodeGen/Mips/nofpclass.ll
@@ -2,7 +2,10 @@
 ; RUN: llc --mtriple=mipsisa32r6-linux-gnu < %s | FileCheck %s --check-prefix=MIPS32R6
 ; RUN: llc --mtriple=mipsisa64r6-linux-gnu < %s | FileCheck %s --check-prefix=MIPS64R6
 
-define nofpclass(nzero) float @f(float nofpclass(nan) %a, float nofpclass(nan) %b) {
+%struct.f2 = type { float, float }
+
+
+define float @f(float nofpclass(nan) %a, float nofpclass(nan) %b) {
 ; MIPS32R6-LABEL: f:
 ; MIPS32R6:       # %bb.0: # %entry
 ; MIPS32R6-NEXT:    jr $ra
@@ -32,7 +35,6 @@ define { float, float } @struct({ float, float} nofpclass(nan) %a) {
    ret {float, float} %a
 }
 
-%struct.f2 = type { float, float }
 define %struct.f2 @m([2 x float] nofpclass(nan) %a0, [2 x float] nofpclass(nan) %a1) {
 ; MIPS32R6-LABEL: m:
 ; MIPS32R6:       # %bb.0: # %entry
@@ -58,3 +60,127 @@ entry:
   %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
   ret %struct.f2 %ret1
 }
+
+define float @fS(float nofpclass(snan) %a, float nofpclass(snan) %b) {
+; MIPS32R6-LABEL: fS:
+; MIPS32R6:       # %bb.0: # %entry
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f14
+;
+; MIPS64R6-LABEL: fS:
+; MIPS64R6:       # %bb.0: # %entry
+; MIPS64R6-NEXT:    jr $ra
+; MIPS64R6-NEXT:    max.s $f0, $f12, $f13
+entry:
+  %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
+  ret float %cond
+}
+
+define { float, float } @structS({ float, float} nofpclass(snan) %a) {
+; MIPS32R6-LABEL: structS:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    mov.s $f2, $f14
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    mov.s $f0, $f12
+;
+; MIPS64R6-LABEL: structS:
+; MIPS64R6:       # %bb.0:
+; MIPS64R6-NEXT:    mov.s $f2, $f13
+; MIPS64R6-NEXT:    jr $ra
+; MIPS64R6-NEXT:    mov.s $f0, $f12
+   ret {float, float} %a
+}
+
+define %struct.f2 @mS([2 x float] nofpclass(snan) %a0, [2 x float] nofpclass(snan) %a1) {
+; MIPS32R6-LABEL: mS:
+; MIPS32R6:       # %bb.0: # %entry
+; MIPS32R6-NEXT:    mtc1 $6, $f0
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f0
+; MIPS32R6-NEXT:    mtc1 $7, $f1
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f2, $f14, $f1
+;
+; MIPS64R6-LABEL: mS:
+; MIPS64R6:       # %bb.0: # %entry
+; MIPS64R6-NEXT:    max.s $f0, $f12, $f14
+; MIPS64R6-NEXT:    jr $ra
+; MIPS64R6-NEXT:    max.s $f2, $f13, $f15
+entry:
+  %a0f0 = extractvalue [2 x float] %a0, 0
+  %a0f1 = extractvalue [2 x float] %a0, 1
+  %a1f0 = extractvalue [2 x float] %a1, 0
+  %a1f1 = extractvalue [2 x float] %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
+  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
+  ret %struct.f2 %ret1
+}
+
+define float @fQ(float nofpclass(qnan) %a, float nofpclass(qnan) %b) {
+; MIPS32R6-LABEL: fQ:
+; MIPS32R6:       # %bb.0: # %entry
+; MIPS32R6-NEXT:    min.s $f0, $f14, $f14
+; MIPS32R6-NEXT:    min.s $f1, $f12, $f12
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f0, $f1, $f0
+;
+; MIPS64R6-LABEL: fQ:
+; MIPS64R6:       # %bb.0: # %entry
+; MIPS64R6-NEXT:    min.s $f0, $f13, $f13
+; MIPS64R6-NEXT:    min.s $f1, $f12, $f12
+; MIPS64R6-NEXT:    jr $ra
+; MIPS64R6-NEXT:    max.s $f0, $f1, $f0
+entry:
+  %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
+  ret float %cond
+}
+
+define { float, float } @structQ({ float, float} nofpclass(qnan) %a) {
+; MIPS32R6-LABEL: structQ:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    mov.s $f2, $f14
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    mov.s $f0, $f12
+;
+; MIPS64R6-LABEL: structQ:
+; MIPS64R6:       # %bb.0:
+; MIPS64R6-NEXT:    mov.s $f2, $f13
+; MIPS64R6-NEXT:    jr $ra
+; MIPS64R6-NEXT:    mov.s $f0, $f12
+   ret {float, float} %a
+}
+
+define %struct.f2 @mQ([2 x float] nofpclass(qnan) %a0, [2 x float] nofpclass(qnan) %a1) {
+; MIPS32R6-LABEL: mQ:
+; MIPS32R6:       # %bb.0: # %entry
+; MIPS32R6-NEXT:    min.s $f0, $f12, $f12
+; MIPS32R6-NEXT:    mtc1 $6, $f1
+; MIPS32R6-NEXT:    min.s $f1, $f1, $f1
+; MIPS32R6-NEXT:    max.s $f0, $f0, $f1
+; MIPS32R6-NEXT:    min.s $f1, $f14, $f14
+; MIPS32R6-NEXT:    mtc1 $7, $f2
+; MIPS32R6-NEXT:    min.s $f2, $f2, $f2
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f2, $f1, $f2
+;
+; MIPS64R6-LABEL: mQ:
+; MIPS64R6:       # %bb.0: # %entry
+; MIPS64R6-NEXT:    min.s $f0, $f14, $f14
+; MIPS64R6-NEXT:    min.s $f1, $f12, $f12
+; MIPS64R6-NEXT:    max.s $f0, $f1, $f0
+; MIPS64R6-NEXT:    min.s $f1, $f15, $f15
+; MIPS64R6-NEXT:    min.s $f2, $f13, $f13
+; MIPS64R6-NEXT:    jr $ra
+; MIPS64R6-NEXT:    max.s $f2, $f2, $f1
+entry:
+  %a0f0 = extractvalue [2 x float] %a0, 0
+  %a0f1 = extractvalue [2 x float] %a0, 1
+  %a1f0 = extractvalue [2 x float] %a1, 0
+  %a1f1 = extractvalue [2 x float] %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
+  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
+  ret %struct.f2 %ret1
+}

>From 79116922cc2535a62dd94e2eeee198e6ef9d4375 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Thu, 24 Apr 2025 13:30:54 +0800
Subject: [PATCH 15/20] Test both array and struct

---
 llvm/test/CodeGen/AArch64/nofpclass.ll |  93 +++++++++++-----
 llvm/test/CodeGen/Mips/nofpclass.ll    | 140 ++++++++++++++++---------
 2 files changed, 153 insertions(+), 80 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/nofpclass.ll b/llvm/test/CodeGen/AArch64/nofpclass.ll
index 3218803f3d17a..3139aa0ef0bf6 100644
--- a/llvm/test/CodeGen/AArch64/nofpclass.ll
+++ b/llvm/test/CodeGen/AArch64/nofpclass.ll
@@ -1,8 +1,6 @@
 ; 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
 
-%struct.f2 = type { float, float }
-
 define float @f(float nofpclass(nan) %a, float nofpclass(nan) %b) {
 ; CHECK-LABEL: f:
 ; CHECK:       // %bb.0: // %entry
@@ -23,15 +21,26 @@ entry:
   ret <4 x float> %c
 }
 
-define { float, float } @struct({ float, float} nofpclass(nan) %a) {
-; CHECK-LABEL: struct:
-; CHECK:       // %bb.0:
+define {float, float} @m({float, float} nofpclass(nan) %a0, {float, float} nofpclass(nan) %a1) {
+; CHECK-LABEL: m:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fmaxnm s1, s1, s3
+; CHECK-NEXT:    fmaxnm s0, s0, s2
 ; CHECK-NEXT:    ret
-   ret {float, float} %a
+entry:
+  %a0f0 = extractvalue {float, float} %a0, 0
+  %a0f1 = extractvalue {float, float} %a0, 1
+  %a1f0 = extractvalue {float, float} %a1, 0
+  %a1f1 = extractvalue {float, float} %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue {float, float} poison, float %max0, 0
+  %ret1 = insertvalue {float, float} %ret0, float %max1, 1
+  ret {float, float} %ret1
 }
 
-define %struct.f2 @m([2 x float] nofpclass(nan) %a0, [2 x float] nofpclass(nan) %a1) {
-; CHECK-LABEL: m:
+define [2 x float] @mA([2 x float] nofpclass(nan) %a0, [2 x float] nofpclass(nan) %a1) {
+; CHECK-LABEL: mA:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    fmaxnm s1, s1, s3
 ; CHECK-NEXT:    fmaxnm s0, s0, s2
@@ -43,9 +52,9 @@ entry:
   %a1f1 = extractvalue [2 x float] %a1, 1
   %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
   %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
-  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
-  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
-  ret %struct.f2 %ret1
+  %ret0 = insertvalue [2 x float] poison, float %max0, 0
+  %ret1 = insertvalue [2 x float] %ret0, float %max1, 1
+  ret [2 x float] %ret1
 }
 
 define float @fS(float nofpclass(snan) %a, float nofpclass(snan) %b) {
@@ -68,15 +77,26 @@ entry:
   ret <4 x float> %c
 }
 
-define { float, float } @structS({ float, float} nofpclass(snan) %a) {
-; CHECK-LABEL: structS:
-; CHECK:       // %bb.0:
+define {float, float} @mS({float, float} nofpclass(snan) %a0, {float, float} nofpclass(snan) %a1) {
+; CHECK-LABEL: mS:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fmaxnm s1, s1, s3
+; CHECK-NEXT:    fmaxnm s0, s0, s2
 ; CHECK-NEXT:    ret
-   ret {float, float} %a
+entry:
+  %a0f0 = extractvalue {float, float} %a0, 0
+  %a0f1 = extractvalue {float, float} %a0, 1
+  %a1f0 = extractvalue {float, float} %a1, 0
+  %a1f1 = extractvalue {float, float} %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue {float, float} poison, float %max0, 0
+  %ret1 = insertvalue {float, float} %ret0, float %max1, 1
+  ret {float, float} %ret1
 }
 
-define %struct.f2 @mS([2 x float] nofpclass(snan) %a0, [2 x float] nofpclass(snan) %a1) {
-; CHECK-LABEL: mS:
+define [2 x float] @mAS([2 x float] nofpclass(snan) %a0, [2 x float] nofpclass(snan) %a1) {
+; CHECK-LABEL: mAS:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    fmaxnm s1, s1, s3
 ; CHECK-NEXT:    fmaxnm s0, s0, s2
@@ -88,9 +108,9 @@ entry:
   %a1f1 = extractvalue [2 x float] %a1, 1
   %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
   %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
-  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
-  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
-  ret %struct.f2 %ret1
+  %ret0 = insertvalue [2 x float] poison, float %max0, 0
+  %ret1 = insertvalue [2 x float] %ret0, float %max1, 1
+  ret [2 x float] %ret1
 }
 
 define float @fQ(float nofpclass(qnan) %a, float nofpclass(qnan) %b) {
@@ -117,15 +137,30 @@ entry:
   ret <4 x float> %c
 }
 
-define { float, float } @structQ({ float, float} nofpclass(qnan) %a) {
-; CHECK-LABEL: structQ:
-; CHECK:       // %bb.0:
+define {float, float} @mQ({float, float} nofpclass(qnan) %a0, {float, float} nofpclass(qnan) %a1) {
+; CHECK-LABEL: mQ:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    fminnm s2, s2, s2
+; CHECK-NEXT:    fminnm s0, s0, s0
+; CHECK-NEXT:    fminnm s3, s3, s3
+; CHECK-NEXT:    fminnm s1, s1, s1
+; CHECK-NEXT:    fmaxnm s0, s0, s2
+; CHECK-NEXT:    fmaxnm s1, s1, s3
 ; CHECK-NEXT:    ret
-   ret {float, float} %a
+entry:
+  %a0f0 = extractvalue {float, float} %a0, 0
+  %a0f1 = extractvalue {float, float} %a0, 1
+  %a1f0 = extractvalue {float, float} %a1, 0
+  %a1f1 = extractvalue {float, float} %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue {float, float} poison, float %max0, 0
+  %ret1 = insertvalue {float, float} %ret0, float %max1, 1
+  ret {float, float} %ret1
 }
 
-define %struct.f2 @mQ([2 x float] nofpclass(qnan) %a0, [2 x float] nofpclass(qnan) %a1) {
-; CHECK-LABEL: mQ:
+define [2 x float] @mAQ([2 x float] nofpclass(qnan) %a0, [2 x float] nofpclass(qnan) %a1) {
+; CHECK-LABEL: mAQ:
 ; CHECK:       // %bb.0: // %entry
 ; CHECK-NEXT:    fminnm s2, s2, s2
 ; CHECK-NEXT:    fminnm s0, s0, s0
@@ -141,7 +176,7 @@ entry:
   %a1f1 = extractvalue [2 x float] %a1, 1
   %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
   %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
-  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
-  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
-  ret %struct.f2 %ret1
+  %ret0 = insertvalue [2 x float] poison, float %max0, 0
+  %ret1 = insertvalue [2 x float] %ret0, float %max1, 1
+  ret [2 x float] %ret1
 }
diff --git a/llvm/test/CodeGen/Mips/nofpclass.ll b/llvm/test/CodeGen/Mips/nofpclass.ll
index 0e035a8da2ada..b9737fe1175b9 100644
--- a/llvm/test/CodeGen/Mips/nofpclass.ll
+++ b/llvm/test/CodeGen/Mips/nofpclass.ll
@@ -2,9 +2,6 @@
 ; RUN: llc --mtriple=mipsisa32r6-linux-gnu < %s | FileCheck %s --check-prefix=MIPS32R6
 ; RUN: llc --mtriple=mipsisa64r6-linux-gnu < %s | FileCheck %s --check-prefix=MIPS64R6
 
-%struct.f2 = type { float, float }
-
-
 define float @f(float nofpclass(nan) %a, float nofpclass(nan) %b) {
 ; MIPS32R6-LABEL: f:
 ; MIPS32R6:       # %bb.0: # %entry
@@ -20,23 +17,34 @@ entry:
   ret float %cond
 }
 
-define { float, float } @struct({ float, float} nofpclass(nan) %a) {
-; MIPS32R6-LABEL: struct:
-; MIPS32R6:       # %bb.0:
-; MIPS32R6-NEXT:    mov.s $f2, $f14
+define {float, float} @m({float, float} nofpclass(nan) %a0, {float, float} nofpclass(nan) %a1) {
+; MIPS32R6-LABEL: m:
+; MIPS32R6:       # %bb.0: # %entry
+; MIPS32R6-NEXT:    mtc1 $6, $f0
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f0
+; MIPS32R6-NEXT:    mtc1 $7, $f1
 ; MIPS32R6-NEXT:    jr $ra
-; MIPS32R6-NEXT:    mov.s $f0, $f12
+; MIPS32R6-NEXT:    max.s $f2, $f14, $f1
 ;
-; MIPS64R6-LABEL: struct:
-; MIPS64R6:       # %bb.0:
-; MIPS64R6-NEXT:    mov.s $f2, $f13
+; MIPS64R6-LABEL: m:
+; MIPS64R6:       # %bb.0: # %entry
+; MIPS64R6-NEXT:    max.s $f0, $f12, $f14
 ; MIPS64R6-NEXT:    jr $ra
-; MIPS64R6-NEXT:    mov.s $f0, $f12
-   ret {float, float} %a
+; MIPS64R6-NEXT:    max.s $f2, $f13, $f15
+entry:
+  %a0f0 = extractvalue {float, float} %a0, 0
+  %a0f1 = extractvalue {float, float} %a0, 1
+  %a1f0 = extractvalue {float, float} %a1, 0
+  %a1f1 = extractvalue {float, float} %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue {float, float} poison, float %max0, 0
+  %ret1 = insertvalue {float, float} %ret0, float %max1, 1
+  ret {float, float} %ret1
 }
 
-define %struct.f2 @m([2 x float] nofpclass(nan) %a0, [2 x float] nofpclass(nan) %a1) {
-; MIPS32R6-LABEL: m:
+define [2 x float] @mA([2 x float] nofpclass(nan) %a0, [2 x float] nofpclass(nan) %a1) {
+; MIPS32R6-LABEL: mA:
 ; MIPS32R6:       # %bb.0: # %entry
 ; MIPS32R6-NEXT:    mtc1 $6, $f0
 ; MIPS32R6-NEXT:    max.s $f0, $f12, $f0
@@ -44,7 +52,7 @@ define %struct.f2 @m([2 x float] nofpclass(nan) %a0, [2 x float] nofpclass(nan)
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.s $f2, $f14, $f1
 ;
-; MIPS64R6-LABEL: m:
+; MIPS64R6-LABEL: mA:
 ; MIPS64R6:       # %bb.0: # %entry
 ; MIPS64R6-NEXT:    max.s $f0, $f12, $f14
 ; MIPS64R6-NEXT:    jr $ra
@@ -56,9 +64,9 @@ entry:
   %a1f1 = extractvalue [2 x float] %a1, 1
   %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
   %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
-  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
-  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
-  ret %struct.f2 %ret1
+  %ret0 = insertvalue [2 x float] poison, float %max0, 0
+  %ret1 = insertvalue [2 x float] %ret0, float %max1, 1
+  ret [2 x float] %ret1
 }
 
 define float @fS(float nofpclass(snan) %a, float nofpclass(snan) %b) {
@@ -76,23 +84,34 @@ entry:
   ret float %cond
 }
 
-define { float, float } @structS({ float, float} nofpclass(snan) %a) {
-; MIPS32R6-LABEL: structS:
-; MIPS32R6:       # %bb.0:
-; MIPS32R6-NEXT:    mov.s $f2, $f14
+define {float, float} @mS({float, float} nofpclass(snan) %a0, {float, float} nofpclass(snan) %a1) {
+; MIPS32R6-LABEL: mS:
+; MIPS32R6:       # %bb.0: # %entry
+; MIPS32R6-NEXT:    mtc1 $6, $f0
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f0
+; MIPS32R6-NEXT:    mtc1 $7, $f1
 ; MIPS32R6-NEXT:    jr $ra
-; MIPS32R6-NEXT:    mov.s $f0, $f12
+; MIPS32R6-NEXT:    max.s $f2, $f14, $f1
 ;
-; MIPS64R6-LABEL: structS:
-; MIPS64R6:       # %bb.0:
-; MIPS64R6-NEXT:    mov.s $f2, $f13
+; MIPS64R6-LABEL: mS:
+; MIPS64R6:       # %bb.0: # %entry
+; MIPS64R6-NEXT:    max.s $f0, $f12, $f14
 ; MIPS64R6-NEXT:    jr $ra
-; MIPS64R6-NEXT:    mov.s $f0, $f12
-   ret {float, float} %a
+; MIPS64R6-NEXT:    max.s $f2, $f13, $f15
+entry:
+  %a0f0 = extractvalue {float, float} %a0, 0
+  %a0f1 = extractvalue {float, float} %a0, 1
+  %a1f0 = extractvalue {float, float} %a1, 0
+  %a1f1 = extractvalue {float, float} %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue {float, float} poison, float %max0, 0
+  %ret1 = insertvalue {float, float} %ret0, float %max1, 1
+  ret {float, float} %ret1
 }
 
-define %struct.f2 @mS([2 x float] nofpclass(snan) %a0, [2 x float] nofpclass(snan) %a1) {
-; MIPS32R6-LABEL: mS:
+define [2 x float] @mAS([2 x float] nofpclass(snan) %a0, [2 x float] nofpclass(snan) %a1) {
+; MIPS32R6-LABEL: mAS:
 ; MIPS32R6:       # %bb.0: # %entry
 ; MIPS32R6-NEXT:    mtc1 $6, $f0
 ; MIPS32R6-NEXT:    max.s $f0, $f12, $f0
@@ -100,7 +119,7 @@ define %struct.f2 @mS([2 x float] nofpclass(snan) %a0, [2 x float] nofpclass(sna
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.s $f2, $f14, $f1
 ;
-; MIPS64R6-LABEL: mS:
+; MIPS64R6-LABEL: mAS:
 ; MIPS64R6:       # %bb.0: # %entry
 ; MIPS64R6-NEXT:    max.s $f0, $f12, $f14
 ; MIPS64R6-NEXT:    jr $ra
@@ -112,9 +131,9 @@ entry:
   %a1f1 = extractvalue [2 x float] %a1, 1
   %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
   %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
-  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
-  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
-  ret %struct.f2 %ret1
+  %ret0 = insertvalue [2 x float] poison, float %max0, 0
+  %ret1 = insertvalue [2 x float] %ret0, float %max1, 1
+  ret [2 x float] %ret1
 }
 
 define float @fQ(float nofpclass(qnan) %a, float nofpclass(qnan) %b) {
@@ -136,23 +155,42 @@ entry:
   ret float %cond
 }
 
-define { float, float } @structQ({ float, float} nofpclass(qnan) %a) {
-; MIPS32R6-LABEL: structQ:
-; MIPS32R6:       # %bb.0:
-; MIPS32R6-NEXT:    mov.s $f2, $f14
+define {float, float} @mQ({float, float} nofpclass(qnan) %a0, {float, float} nofpclass(qnan) %a1) {
+; MIPS32R6-LABEL: mQ:
+; MIPS32R6:       # %bb.0: # %entry
+; MIPS32R6-NEXT:    min.s $f0, $f12, $f12
+; MIPS32R6-NEXT:    mtc1 $6, $f1
+; MIPS32R6-NEXT:    min.s $f1, $f1, $f1
+; MIPS32R6-NEXT:    max.s $f0, $f0, $f1
+; MIPS32R6-NEXT:    min.s $f1, $f14, $f14
+; MIPS32R6-NEXT:    mtc1 $7, $f2
+; MIPS32R6-NEXT:    min.s $f2, $f2, $f2
 ; MIPS32R6-NEXT:    jr $ra
-; MIPS32R6-NEXT:    mov.s $f0, $f12
+; MIPS32R6-NEXT:    max.s $f2, $f1, $f2
 ;
-; MIPS64R6-LABEL: structQ:
-; MIPS64R6:       # %bb.0:
-; MIPS64R6-NEXT:    mov.s $f2, $f13
+; MIPS64R6-LABEL: mQ:
+; MIPS64R6:       # %bb.0: # %entry
+; MIPS64R6-NEXT:    min.s $f0, $f14, $f14
+; MIPS64R6-NEXT:    min.s $f1, $f12, $f12
+; MIPS64R6-NEXT:    max.s $f0, $f1, $f0
+; MIPS64R6-NEXT:    min.s $f1, $f15, $f15
+; MIPS64R6-NEXT:    min.s $f2, $f13, $f13
 ; MIPS64R6-NEXT:    jr $ra
-; MIPS64R6-NEXT:    mov.s $f0, $f12
-   ret {float, float} %a
+; MIPS64R6-NEXT:    max.s $f2, $f2, $f1
+entry:
+  %a0f0 = extractvalue {float, float} %a0, 0
+  %a0f1 = extractvalue {float, float} %a0, 1
+  %a1f0 = extractvalue {float, float} %a1, 0
+  %a1f1 = extractvalue {float, float} %a1, 1
+  %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
+  %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
+  %ret0 = insertvalue {float, float} poison, float %max0, 0
+  %ret1 = insertvalue {float, float} %ret0, float %max1, 1
+  ret {float, float} %ret1
 }
 
-define %struct.f2 @mQ([2 x float] nofpclass(qnan) %a0, [2 x float] nofpclass(qnan) %a1) {
-; MIPS32R6-LABEL: mQ:
+define [2 x float] @mAQ([2 x float] nofpclass(qnan) %a0, [2 x float] nofpclass(qnan) %a1) {
+; MIPS32R6-LABEL: mAQ:
 ; MIPS32R6:       # %bb.0: # %entry
 ; MIPS32R6-NEXT:    min.s $f0, $f12, $f12
 ; MIPS32R6-NEXT:    mtc1 $6, $f1
@@ -164,7 +202,7 @@ define %struct.f2 @mQ([2 x float] nofpclass(qnan) %a0, [2 x float] nofpclass(qna
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.s $f2, $f1, $f2
 ;
-; MIPS64R6-LABEL: mQ:
+; MIPS64R6-LABEL: mAQ:
 ; MIPS64R6:       # %bb.0: # %entry
 ; MIPS64R6-NEXT:    min.s $f0, $f14, $f14
 ; MIPS64R6-NEXT:    min.s $f1, $f12, $f12
@@ -180,7 +218,7 @@ entry:
   %a1f1 = extractvalue [2 x float] %a1, 1
   %max0 = tail call float @llvm.maximumnum.f32(float %a0f0, float %a1f0)
   %max1 = tail call float @llvm.maximumnum.f32(float %a0f1, float %a1f1)
-  %ret0 = insertvalue %struct.f2 poison, float %max0, 0
-  %ret1 = insertvalue %struct.f2 %ret0, float %max1, 1
-  ret %struct.f2 %ret1
+  %ret0 = insertvalue [2 x float] poison, float %max0, 0
+  %ret1 = insertvalue [2 x float] %ret0, float %max1, 1
+  ret [2 x float] %ret1
 }

>From 4cdbc893345f5c18ced784cd824e4da2d1812433 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Wed, 7 May 2025 18:10:47 +0800
Subject: [PATCH 16/20] Fix WidenVectorResult

---
 .../SelectionDAG/LegalizeVectorTypes.cpp      |  3 +++
 llvm/test/CodeGen/X86/nofpclass.ll            | 25 +++++++++++++++++++
 2 files changed, 28 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/nofpclass.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index 1f4b1367f7374..3318e7eae15c3 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -5626,6 +5626,9 @@ SDValue DAGTypeLegalizer::WidenVecRes_Unary(SDNode *N) {
   SDValue InOp = GetWidenedVector(N->getOperand(0));
   if (N->getNumOperands() == 1)
     return DAG.getNode(N->getOpcode(), SDLoc(N), WidenVT, InOp, N->getFlags());
+  if (N->getOpcode() == ISD::AssertNoFPClass)
+    return DAG.getNode(N->getOpcode(), SDLoc(N), WidenVT, InOp,
+                       N->getOperand(1), N->getFlags());
 
   assert(N->getNumOperands() == 3 && "Unexpected number of operands!");
   assert(N->isVPOpcode() && "Expected VP opcode");
diff --git a/llvm/test/CodeGen/X86/nofpclass.ll b/llvm/test/CodeGen/X86/nofpclass.ll
new file mode 100644
index 0000000000000..55f0af904a38d
--- /dev/null
+++ b/llvm/test/CodeGen/X86/nofpclass.ll
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=-sse2,-sse | FileCheck %s --check-prefix=NOSSE
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=SSE
+
+ at gf = global { float, float } zeroinitializer, align 8
+
+define void @f(<2 x float> noundef nofpclass(nan inf) %e.coerce) {
+; NOSSE-LABEL: f:
+; NOSSE:       # %bb.0: # %entry
+; NOSSE-NEXT:    flds {{[0-9]+}}(%rsp)
+; NOSSE-NEXT:    flds {{[0-9]+}}(%rsp)
+; NOSSE-NEXT:    movq gf at GOTPCREL(%rip), %rax
+; NOSSE-NEXT:    fstps 4(%rax)
+; NOSSE-NEXT:    fstps (%rax)
+; NOSSE-NEXT:    retq
+;
+; SSE-LABEL: f:
+; SSE:       # %bb.0: # %entry
+; SSE-NEXT:    movq gf at GOTPCREL(%rip), %rax
+; SSE-NEXT:    movlps %xmm0, (%rax)
+; SSE-NEXT:    retq
+entry:
+  store <2 x float> %e.coerce, ptr @gf, align 8
+  ret void
+}

>From 3357e284b49a9278bb76610bc3541cc859982cae Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Wed, 7 May 2025 18:13:37 +0800
Subject: [PATCH 17/20] Fix PromoteHalf support

---
 .../SelectionDAG/LegalizeFloatTypes.cpp       | 21 +++++++++++++---
 llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h |  6 ++++-
 llvm/test/CodeGen/ARM/nofpclass.ll            | 25 +++++++++++++++++++
 3 files changed, 47 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/CodeGen/ARM/nofpclass.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index d03eeaa01b697..feb6648749c51 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -2639,7 +2639,11 @@ SDValue DAGTypeLegalizer::PromoteFloatOp_FCOPYSIGN(SDNode *N, unsigned OpNo) {
 // Convert the promoted float value to the desired integer type
 SDValue DAGTypeLegalizer::PromoteFloatOp_UnaryOp(SDNode *N, unsigned OpNo) {
   SDValue Op = GetPromotedFloat(N->getOperand(0));
-  return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), Op);
+  if (N->getOpcode() == ISD::AssertNoFPClass)
+    return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), Op,
+                       N->getOperand(1));
+  else
+    return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), Op);
 }
 
 SDValue DAGTypeLegalizer::PromoteFloatOp_FP_TO_XINT_SAT(SDNode *N,
@@ -2999,8 +3003,10 @@ SDValue DAGTypeLegalizer::PromoteFloatRes_UnaryOp(SDNode *N) {
   EVT VT = N->getValueType(0);
   EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
   SDValue Op = GetPromotedFloat(N->getOperand(0));
-
-  return DAG.getNode(N->getOpcode(), SDLoc(N), NVT, Op);
+  if (N->getOpcode() == ISD::AssertNoFPClass)
+    return DAG.getNode(N->getOpcode(), SDLoc(N), NVT, Op, N->getOperand(1));
+  else
+    return DAG.getNode(N->getOpcode(), SDLoc(N), NVT, Op);
 }
 
 // Binary operations where the result and both operands have PromoteFloat type
@@ -3245,6 +3251,8 @@ void DAGTypeLegalizer::SoftPromoteHalfResult(SDNode *N, unsigned ResNo) {
     report_fatal_error("Do not know how to soft promote this operator's "
                        "result!");
 
+  // case ISD::AssertNoFPClass:
+  //   break;
   case ISD::ARITH_FENCE:
     R = SoftPromoteHalfRes_ARITH_FENCE(N); break;
   case ISD::BITCAST:    R = SoftPromoteHalfRes_BITCAST(N); break;
@@ -3283,6 +3291,7 @@ void DAGTypeLegalizer::SoftPromoteHalfResult(SDNode *N, unsigned ResNo) {
   case ISD::FTRUNC:
   case ISD::FTAN:
   case ISD::FTANH:
+  case ISD::AssertNoFPClass:
   case ISD::FCANONICALIZE: R = SoftPromoteHalfRes_UnaryOp(N); break;
 
   // Binary FP Operations
@@ -3604,7 +3613,11 @@ SDValue DAGTypeLegalizer::SoftPromoteHalfRes_UnaryOp(SDNode *N) {
   // Promote to the larger FP type.
   Op = DAG.getNode(GetPromotionOpcode(OVT, NVT), dl, NVT, Op);
 
-  SDValue Res = DAG.getNode(N->getOpcode(), dl, NVT, Op);
+  SDValue Res;
+  if (N->getOpcode() == ISD::AssertNoFPClass)
+    Res = DAG.getNode(N->getOpcode(), dl, NVT, Op, N->getOperand(1));
+  else
+    Res = DAG.getNode(N->getOpcode(), dl, NVT, Op);
 
   // Convert back to FP16 as an integer.
   return DAG.getNode(GetPromotionOpcode(NVT, OVT), dl, MVT::i16, Res);
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 720393158aa5e..24bcd0de266dc 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -80,7 +80,9 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
   /// Pretend all of this node's results are legal.
   bool IgnoreNodeResults(SDNode *N) const {
     return N->getOpcode() == ISD::TargetConstant ||
-           N->getOpcode() == ISD::Register;
+           N->getOpcode() == ISD::Register ||
+           (N->getOpcode() == ISD::AssertNoFPClass &&
+            IgnoreNodeResults(N->getOperand(0).getNode()));
   }
 
   // Bijection from SDValue to unique id. As each created node gets a
@@ -796,6 +798,8 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
   //===--------------------------------------------------------------------===//
 
   SDValue GetSoftPromotedHalf(SDValue Op) {
+    while (Op.getNode()->getOpcode() == ISD::AssertNoFPClass)
+      Op = Op.getNode()->getOperand(0);
     TableId &PromotedId = SoftPromotedHalfs[getTableId(Op)];
     SDValue PromotedOp = getSDValue(PromotedId);
     assert(PromotedOp.getNode() && "Operand wasn't promoted?");
diff --git a/llvm/test/CodeGen/ARM/nofpclass.ll b/llvm/test/CodeGen/ARM/nofpclass.ll
new file mode 100644
index 0000000000000..052ab7a8645a6
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/nofpclass.ll
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=armv8-unknown-none-eabi < %s | FileCheck %s
+
+define nofpclass(nan inf) half @f1(half returned nofpclass(nan inf) %x) {
+; CHECK-LABEL: f1:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    bx lr
+entry:
+  ret half %x
+}
+
+define noundef half @f2(half nofpclass(nan) %a) {
+; CHECK-LABEL: f2:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    vmov.f32 s0, #1.000000e+00
+; CHECK-NEXT:    vmov s2, r0
+; CHECK-NEXT:    vcvtb.f32.f16 s2, s2
+; CHECK-NEXT:    vadd.f32 s0, s2, s0
+; CHECK-NEXT:    vcvtb.f16.f32 s0, s0
+; CHECK-NEXT:    vmov r0, s0
+; CHECK-NEXT:    bx lr
+entry:
+  %0 = fadd half %a, 0xH3C00
+  ret half %0
+}

>From 102edaea517fb3772f98a4e8d71694325c498b43 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Wed, 7 May 2025 19:12:41 +0800
Subject: [PATCH 18/20] Use seperate function for assertnofpclass

---
 .../SelectionDAG/LegalizeFloatTypes.cpp       | 35 ++++++++++++-------
 llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h |  2 ++
 llvm/test/CodeGen/ARM/nofpclass.ll            | 32 +++++++++++------
 3 files changed, 46 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index feb6648749c51..7f94e6899f996 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -2577,13 +2577,13 @@ 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:
     case ISD::LLROUND:
     case ISD::LRINT:
     case ISD::LLRINT:     R = PromoteFloatOp_UnaryOp(N, OpNo); break;
+    case ISD::AssertNoFPClass:     R = PromoteFloatOp_UnaryOpExt1(N, OpNo); break;
     case ISD::FP_TO_SINT_SAT:
     case ISD::FP_TO_UINT_SAT:
                           R = PromoteFloatOp_FP_TO_XINT_SAT(N, OpNo); break;
@@ -2646,6 +2646,13 @@ SDValue DAGTypeLegalizer::PromoteFloatOp_UnaryOp(SDNode *N, unsigned OpNo) {
     return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), Op);
 }
 
+// Convert the promoted float value to the desired integer type
+SDValue DAGTypeLegalizer::PromoteFloatOp_UnaryOpExt1(SDNode *N, unsigned OpNo) {
+  SDValue Op = GetPromotedFloat(N->getOperand(0));
+  return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), Op,
+                     N->getOperand(1));
+}
+
 SDValue DAGTypeLegalizer::PromoteFloatOp_FP_TO_XINT_SAT(SDNode *N,
                                                         unsigned OpNo) {
   SDValue Op = GetPromotedFloat(N->getOperand(0));
@@ -2809,8 +2816,10 @@ 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;
+    case ISD::AssertNoFPClass:
+      R = PromoteFloatRes_UnaryOpExt1(N);
+      break;
 
     // Binary FP Operations
     case ISD::FADD:
@@ -3003,12 +3012,18 @@ SDValue DAGTypeLegalizer::PromoteFloatRes_UnaryOp(SDNode *N) {
   EVT VT = N->getValueType(0);
   EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
   SDValue Op = GetPromotedFloat(N->getOperand(0));
-  if (N->getOpcode() == ISD::AssertNoFPClass)
-    return DAG.getNode(N->getOpcode(), SDLoc(N), NVT, Op, N->getOperand(1));
-  else
-    return DAG.getNode(N->getOpcode(), SDLoc(N), NVT, Op);
+  return DAG.getNode(N->getOpcode(), SDLoc(N), NVT, Op);
 }
 
+// Unary operation with a more non-float operand where the result and the
+// operand have PromoteFloat type action.  Construct a new SDNode with the
+// promoted float value of the old operand.
+SDValue DAGTypeLegalizer::PromoteFloatRes_UnaryOpExt1(SDNode *N) {
+  EVT VT = N->getValueType(0);
+  EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
+  SDValue Op = GetPromotedFloat(N->getOperand(0));
+  return DAG.getNode(N->getOpcode(), SDLoc(N), NVT, Op, N->getOperand(1));
+}
 // Binary operations where the result and both operands have PromoteFloat type
 // action.  Construct a new SDNode with the promoted float values of the old
 // operands.
@@ -3251,8 +3266,6 @@ void DAGTypeLegalizer::SoftPromoteHalfResult(SDNode *N, unsigned ResNo) {
     report_fatal_error("Do not know how to soft promote this operator's "
                        "result!");
 
-  // case ISD::AssertNoFPClass:
-  //   break;
   case ISD::ARITH_FENCE:
     R = SoftPromoteHalfRes_ARITH_FENCE(N); break;
   case ISD::BITCAST:    R = SoftPromoteHalfRes_BITCAST(N); break;
@@ -3613,11 +3626,7 @@ SDValue DAGTypeLegalizer::SoftPromoteHalfRes_UnaryOp(SDNode *N) {
   // Promote to the larger FP type.
   Op = DAG.getNode(GetPromotionOpcode(OVT, NVT), dl, NVT, Op);
 
-  SDValue Res;
-  if (N->getOpcode() == ISD::AssertNoFPClass)
-    Res = DAG.getNode(N->getOpcode(), dl, NVT, Op, N->getOperand(1));
-  else
-    Res = DAG.getNode(N->getOpcode(), dl, NVT, Op);
+  SDValue Res = DAG.getNode(N->getOpcode(), dl, NVT, Op, N->getOperand(1));
 
   // Convert back to FP16 as an integer.
   return DAG.getNode(GetPromotionOpcode(NVT, OVT), dl, MVT::i16, Res);
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 24bcd0de266dc..87e05e9e35995 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -774,6 +774,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
   SDValue PromoteFloatRes_SELECT(SDNode *N);
   SDValue PromoteFloatRes_SELECT_CC(SDNode *N);
   SDValue PromoteFloatRes_UnaryOp(SDNode *N);
+  SDValue PromoteFloatRes_UnaryOpExt1(SDNode *N);
   SDValue PromoteFloatRes_UNDEF(SDNode *N);
   SDValue BitcastToInt_ATOMIC_SWAP(SDNode *N);
   SDValue PromoteFloatRes_XINT_TO_FP(SDNode *N);
@@ -787,6 +788,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
   SDValue PromoteFloatOp_FP_EXTEND(SDNode *N, unsigned OpNo);
   SDValue PromoteFloatOp_STRICT_FP_EXTEND(SDNode *N, unsigned OpNo);
   SDValue PromoteFloatOp_UnaryOp(SDNode *N, unsigned OpNo);
+  SDValue PromoteFloatOp_UnaryOpExt1(SDNode *N, unsigned OpNo);
   SDValue PromoteFloatOp_FP_TO_XINT_SAT(SDNode *N, unsigned OpNo);
   SDValue PromoteFloatOp_STORE(SDNode *N, unsigned OpNo);
   SDValue PromoteFloatOp_ATOMIC_STORE(SDNode *N, unsigned OpNo);
diff --git a/llvm/test/CodeGen/ARM/nofpclass.ll b/llvm/test/CodeGen/ARM/nofpclass.ll
index 052ab7a8645a6..aaeb6c11fa598 100644
--- a/llvm/test/CodeGen/ARM/nofpclass.ll
+++ b/llvm/test/CodeGen/ARM/nofpclass.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
-; RUN: llc -mtriple=armv8-unknown-none-eabi < %s | FileCheck %s
+; RUN: llc -mtriple=armv8-unknown-none-eabi < %s | FileCheck %s --check-prefixes=CHECK,HARD
+; RUN: llc -mtriple=armv8-unknown-none-eabi -mattr=+soft-float < %s | FileCheck %s --check-prefixes=CHECK,SOFT
 
 define nofpclass(nan inf) half @f1(half returned nofpclass(nan inf) %x) {
 ; CHECK-LABEL: f1:
@@ -10,15 +11,26 @@ entry:
 }
 
 define noundef half @f2(half nofpclass(nan) %a) {
-; CHECK-LABEL: f2:
-; CHECK:       @ %bb.0: @ %entry
-; CHECK-NEXT:    vmov.f32 s0, #1.000000e+00
-; CHECK-NEXT:    vmov s2, r0
-; CHECK-NEXT:    vcvtb.f32.f16 s2, s2
-; CHECK-NEXT:    vadd.f32 s0, s2, s0
-; CHECK-NEXT:    vcvtb.f16.f32 s0, s0
-; CHECK-NEXT:    vmov r0, s0
-; CHECK-NEXT:    bx lr
+; HARD-LABEL: f2:
+; HARD:       @ %bb.0: @ %entry
+; HARD-NEXT:    vmov.f32 s0, #1.000000e+00
+; HARD-NEXT:    vmov s2, r0
+; HARD-NEXT:    vcvtb.f32.f16 s2, s2
+; HARD-NEXT:    vadd.f32 s0, s2, s0
+; HARD-NEXT:    vcvtb.f16.f32 s0, s0
+; HARD-NEXT:    vmov r0, s0
+; HARD-NEXT:    bx lr
+;
+; SOFT-LABEL: f2:
+; SOFT:       @ %bb.0: @ %entry
+; SOFT-NEXT:    .save {r11, lr}
+; SOFT-NEXT:    push {r11, lr}
+; SOFT-NEXT:    uxth r0, r0
+; SOFT-NEXT:    bl __aeabi_h2f
+; SOFT-NEXT:    mov r1, #1065353216
+; SOFT-NEXT:    bl __aeabi_fadd
+; SOFT-NEXT:    bl __aeabi_f2h
+; SOFT-NEXT:    pop {r11, pc}
 entry:
   %0 = fadd half %a, 0xH3C00
   ret half %0

>From 30e6bb7239ba13d9c63b7ed5e7aa15d46345d623 Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Thu, 8 May 2025 08:42:59 +0800
Subject: [PATCH 19/20] Fix wrong dead code from SoftPromoteHalfRes_UnaryOp

---
 llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 7f94e6899f996..94944565e359b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -3626,7 +3626,7 @@ SDValue DAGTypeLegalizer::SoftPromoteHalfRes_UnaryOp(SDNode *N) {
   // Promote to the larger FP type.
   Op = DAG.getNode(GetPromotionOpcode(OVT, NVT), dl, NVT, Op);
 
-  SDValue Res = DAG.getNode(N->getOpcode(), dl, NVT, Op, N->getOperand(1));
+  SDValue Res = DAG.getNode(N->getOpcode(), dl, NVT, Op);
 
   // Convert back to FP16 as an integer.
   return DAG.getNode(GetPromotionOpcode(NVT, OVT), dl, MVT::i16, Res);

>From 89e6e89b8f5e0e07bfa4f79ca65ec8ea98e5d3bd Mon Sep 17 00:00:00 2001
From: YunQiang Su <yunqiang at isrc.iscas.ac.cn>
Date: Thu, 8 May 2025 13:00:55 +0800
Subject: [PATCH 20/20] Fix internal error

---
 .../SelectionDAG/LegalizeFloatTypes.cpp       | 23 ++++++++++++++-----
 llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h |  1 +
 .../SelectionDAG/LegalizeVectorTypes.cpp      |  4 ++--
 3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 94944565e359b..c0507c74542b1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -2639,11 +2639,7 @@ SDValue DAGTypeLegalizer::PromoteFloatOp_FCOPYSIGN(SDNode *N, unsigned OpNo) {
 // Convert the promoted float value to the desired integer type
 SDValue DAGTypeLegalizer::PromoteFloatOp_UnaryOp(SDNode *N, unsigned OpNo) {
   SDValue Op = GetPromotedFloat(N->getOperand(0));
-  if (N->getOpcode() == ISD::AssertNoFPClass)
-    return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), Op,
-                       N->getOperand(1));
-  else
-    return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), Op);
+  return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), Op);
 }
 
 // Convert the promoted float value to the desired integer type
@@ -3304,8 +3300,8 @@ void DAGTypeLegalizer::SoftPromoteHalfResult(SDNode *N, unsigned ResNo) {
   case ISD::FTRUNC:
   case ISD::FTAN:
   case ISD::FTANH:
-  case ISD::AssertNoFPClass:
   case ISD::FCANONICALIZE: R = SoftPromoteHalfRes_UnaryOp(N); break;
+  case ISD::AssertNoFPClass: R = SoftPromoteHalfRes_UnaryOpExt1(N); break;
 
   // Binary FP Operations
   case ISD::FADD:
@@ -3632,6 +3628,21 @@ SDValue DAGTypeLegalizer::SoftPromoteHalfRes_UnaryOp(SDNode *N) {
   return DAG.getNode(GetPromotionOpcode(NVT, OVT), dl, MVT::i16, Res);
 }
 
+SDValue DAGTypeLegalizer::SoftPromoteHalfRes_UnaryOpExt1(SDNode *N) {
+  EVT OVT = N->getValueType(0);
+  EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), OVT);
+  SDValue Op = GetSoftPromotedHalf(N->getOperand(0));
+  SDLoc dl(N);
+
+  // Promote to the larger FP type.
+  Op = DAG.getNode(GetPromotionOpcode(OVT, NVT), dl, NVT, Op);
+
+  SDValue Res = DAG.getNode(N->getOpcode(), dl, NVT, Op, N->getOperand(1));
+
+  // Convert back to FP16 as an integer.
+  return DAG.getNode(GetPromotionOpcode(NVT, OVT), dl, MVT::i16, Res);
+}
+
 SDValue DAGTypeLegalizer::SoftPromoteHalfRes_BinOp(SDNode *N) {
   EVT OVT = N->getValueType(0);
   EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), OVT);
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 87e05e9e35995..f4d5fa230f821 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -826,6 +826,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
   SDValue SoftPromoteHalfRes_SELECT(SDNode *N);
   SDValue SoftPromoteHalfRes_SELECT_CC(SDNode *N);
   SDValue SoftPromoteHalfRes_UnaryOp(SDNode *N);
+  SDValue SoftPromoteHalfRes_UnaryOpExt1(SDNode *N);
   SDValue SoftPromoteHalfRes_XINT_TO_FP(SDNode *N);
   SDValue SoftPromoteHalfRes_UNDEF(SDNode *N);
   SDValue SoftPromoteHalfRes_VECREDUCE(SDNode *N);
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index 3318e7eae15c3..834f0e2b8038d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -61,6 +61,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
   case ISD::AssertZext:
   case ISD::AssertSext:
   case ISD::FPOWI:
+  case ISD::AssertNoFPClass:
     R = ScalarizeVecRes_UnaryOpWithExtraInput(N);
     break;
   case ISD::INSERT_VECTOR_ELT: R = ScalarizeVecRes_INSERT_VECTOR_ELT(N); break;
@@ -129,7 +130,6 @@ 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:
@@ -2616,7 +2616,7 @@ void DAGTypeLegalizer::SplitVecRes_UnaryOp(SDNode *N, SDValue &Lo,
   const SDNodeFlags Flags = N->getFlags();
   unsigned Opcode = N->getOpcode();
   if (N->getNumOperands() <= 2) {
-    if (Opcode == ISD::FP_ROUND) {
+    if (Opcode == ISD::FP_ROUND || Opcode == ISD::AssertNoFPClass) {
       Lo = DAG.getNode(Opcode, dl, LoVT, Lo, N->getOperand(1), Flags);
       Hi = DAG.getNode(Opcode, dl, HiVT, Hi, N->getOperand(1), Flags);
     } else {



More information about the llvm-commits mailing list