-
Notifications
You must be signed in to change notification settings - Fork 13.5k
CodeGen: Add ISD::AssertNoFPClass #138839
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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.
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/pr-subscribers-llvm-selectiondag Author: YunQiang Su (wzssyqa) ChangesIt is used to mark a value that we are sure that it is not some fcType.
So that the following operation can make some assumptions. Patch is 29.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138839.diff 13 Files Affected:
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 80ef32aff62ae..1042318343987 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -67,6 +67,15 @@ 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.
+ /// This node takes two operands. The first is the node that is known
+ /// 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,
+
/// Various leaf nodes.
BasicBlock,
VALUETYPE,
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 41fed692c7025..b28a8b118de7a 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 assertnofpclass : 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..feb6648749c51 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:
@@ -2637,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,
@@ -2803,6 +2809,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
@@ -2996,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
@@ -3242,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;
@@ -3280,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
@@ -3601,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/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index d0b69b88748a9..3318e7eae15c3 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:
@@ -5623,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/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 2a68903c34cef..5fc240dfc86d7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5832,6 +5832,15 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
return false;
return true;
}
+ case ISD::AssertNoFPClass: {
+ FPClassTest NoFPClass =
+ static_cast<FPClassTest>(Op.getConstantOperandVal(1));
+ if ((NoFPClass & fcNan) == fcNan)
+ return true;
+ if (SNaN && (NoFPClass & fcSNan) == fcSNan)
+ return true;
+ return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1);
+ }
default:
if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
@@ -7491,6 +7500,16 @@ 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");
+ assert(isa<ConstantSDNode>(N2) && "NoFPClass is not Constant");
+ FPClassTest NoFPClass = static_cast<FPClassTest>(N2->getAsZExtVal());
+ 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();
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 9d138d364bad7..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;
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);
diff --git a/llvm/test/CodeGen/AArch64/nofpclass.ll b/llvm/test/CodeGen/AArch64/nofpclass.ll
new file mode 100644
index 0000000000000..3139aa0ef0bf6
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/nofpclass.ll
@@ -0,0 +1,182 @@
+; 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 float @f(float nofpclass(nan) %a, float 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
+}
+
+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
+}
+
+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
+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 [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
+; 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 [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) {
+; 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} @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
+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 [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
+; 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 [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) {
+; 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} @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
+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 [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
+; 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 [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/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: vc...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
89e6e89
to
f9b709f
Compare
@arsenm ping |
It is used to mark a value that we are sure that it is not some fcType.
The examples include:
So that the following operation can make some assumptions.