[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