[llvm] f0c61d2 - CodeGen: Add ISD::AssertNoFPClass (#135946)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 24 18:12:44 PDT 2025
Author: YunQiang Su
Date: 2025-04-25T09:12:41+08:00
New Revision: f0c61d2242bbc7576ca5e4137a5ea8f63e4859a9
URL: https://github.com/llvm/llvm-project/commit/f0c61d2242bbc7576ca5e4137a5ea8f63e4859a9
DIFF: https://github.com/llvm/llvm-project/commit/f0c61d2242bbc7576ca5e4137a5ea8f63e4859a9.diff
LOG: CodeGen: Add ISD::AssertNoFPClass (#135946)
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.
---------
Co-authored-by: Your Name <you at example.com>
Added:
llvm/test/CodeGen/AArch64/nofpclass.ll
llvm/test/CodeGen/Mips/nofpclass.ll
Modified:
llvm/include/llvm/CodeGen/ISDOpcodes.h
llvm/include/llvm/Target/TargetSelectionDAG.td
llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index ad8a95a353b56..5d9e96e3b5286 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 cd0dc26a1f257..30c9a036a39ce 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -868,6 +868,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..d03eeaa01b697 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -168,6 +168,7 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) {
case ISD::POISON:
case ISD::UNDEF: R = SoftenFloatRes_UNDEF(N); break;
case ISD::VAARG: R = SoftenFloatRes_VAARG(N); break;
+ case ISD::AssertNoFPClass: R = GetSoftenedFloat(N->getOperand(0)); break;
case ISD::VECREDUCE_FADD:
case ISD::VECREDUCE_FMUL:
case ISD::VECREDUCE_FMIN:
@@ -2576,6 +2577,7 @@ bool DAGTypeLegalizer::PromoteFloatOperand(SDNode *N, unsigned OpNo) {
R = PromoteFloatOp_FAKE_USE(N, OpNo);
break;
case ISD::FCOPYSIGN: R = PromoteFloatOp_FCOPYSIGN(N, OpNo); break;
+ case ISD::AssertNoFPClass:
case ISD::FP_TO_SINT:
case ISD::FP_TO_UINT:
case ISD::LROUND:
@@ -2803,6 +2805,7 @@ void DAGTypeLegalizer::PromoteFloatResult(SDNode *N, unsigned ResNo) {
case ISD::FTRUNC:
case ISD::FTAN:
case ISD::FTANH:
+ case ISD::AssertNoFPClass:
case ISD::FCANONICALIZE: R = PromoteFloatRes_UnaryOp(N); break;
// Binary FP Operations
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index a01e1cff74564..54da9fe3c6a40 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -129,6 +129,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
case ISD::UINT_TO_FP:
case ISD::ZERO_EXTEND:
case ISD::FCANONICALIZE:
+ case ISD::AssertNoFPClass:
R = ScalarizeVecRes_UnaryOp(N);
break;
case ISD::ADDRSPACECAST:
@@ -1276,6 +1277,7 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
case ISD::UINT_TO_FP:
case ISD::VP_UINT_TO_FP:
case ISD::FCANONICALIZE:
+ case ISD::AssertNoFPClass:
SplitVecRes_UnaryOp(N, Lo, Hi);
break;
case ISD::ADDRSPACECAST:
@@ -4844,6 +4846,7 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
case ISD::FREEZE:
case ISD::ARITH_FENCE:
case ISD::FCANONICALIZE:
+ case ISD::AssertNoFPClass:
Res = WidenVecRes_Unary(N);
break;
case ISD::FMA: case ISD::VP_FMA:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 3b2dafc9e0fa8..6d3433c475ecd 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) {
@@ -7486,6 +7495,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 4b05d89417d2c..25b47838e2c17 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11829,9 +11829,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 8fcec6c6cd7c6..240115ac739f0 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -122,6 +122,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
case ISD::TokenFactor: return "TokenFactor";
case ISD::AssertSext: return "AssertSext";
case ISD::AssertZext: return "AssertZext";
+ case ISD::AssertNoFPClass: return "AssertNoFPClass";
case ISD::AssertAlign: return "AssertAlign";
case ISD::BasicBlock: return "BasicBlock";
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 598de6b207754..62d911fed2a3f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -3265,6 +3265,7 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
return;
case ISD::AssertSext:
case ISD::AssertZext:
+ case ISD::AssertNoFPClass:
case ISD::AssertAlign:
ReplaceUses(SDValue(NodeToMatch, 0), NodeToMatch->getOperand(0));
CurDAG->RemoveDeadNode(NodeToMatch);
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/Mips/nofpclass.ll b/llvm/test/CodeGen/Mips/nofpclass.ll
new file mode 100644
index 0000000000000..b9737fe1175b9
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/nofpclass.ll
@@ -0,0 +1,224 @@
+; 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 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
+}
+
+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: 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 {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) {
+; MIPS32R6-LABEL: mA:
+; 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: mA:
+; 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 [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) {
+; 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} @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: 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 {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) {
+; MIPS32R6-LABEL: mAS:
+; 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: mAS:
+; 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 [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) {
+; 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} @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: 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 {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) {
+; MIPS32R6-LABEL: mAQ:
+; 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: mAQ:
+; 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 [2 x float] poison, float %max0, 0
+ %ret1 = insertvalue [2 x float] %ret0, float %max1, 1
+ ret [2 x float] %ret1
+}
More information about the llvm-commits
mailing list