From 015776f38c9a3f24ce3fdcda3b296bbaa823dcec Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Tue, 21 Oct 2014 23:01:01 +0000 Subject: [PATCH] Add minnum / maxnum codegen git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@220342 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/ISDOpcodes.h | 3 +- include/llvm/CodeGen/RuntimeLibcalls.h | 10 + include/llvm/CodeGen/SelectionDAG.h | 5 +- lib/CodeGen/BasicTargetTransformInfo.cpp | 2 + lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 46 +++++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 10 + .../SelectionDAG/LegalizeFloatTypes.cpp | 50 +++++ lib/CodeGen/SelectionDAG/LegalizeTypes.h | 4 + .../SelectionDAG/LegalizeVectorOps.cpp | 2 + .../SelectionDAG/LegalizeVectorTypes.cpp | 7 + .../SelectionDAG/SelectionDAGBuilder.cpp | 44 ++++ .../SelectionDAG/SelectionDAGBuilder.h | 1 + .../SelectionDAG/SelectionDAGDumper.cpp | 2 + lib/CodeGen/TargetLoweringBase.cpp | 20 ++ lib/Target/R600/AMDGPUISelLowering.cpp | 2 + lib/Target/R600/SIISelLowering.cpp | 5 + lib/Target/R600/SIInstructions.td | 9 +- lib/Target/X86/X86ISelLowering.cpp | 2 + test/CodeGen/PowerPC/fmaxnum.ll | 86 ++++++++ test/CodeGen/PowerPC/fminnum.ll | 86 ++++++++ test/CodeGen/R600/fmaxnum.f64.ll | 75 +++++++ test/CodeGen/R600/fmaxnum.ll | 191 ++++++++++++++++++ test/CodeGen/R600/fminnum.f64.ll | 75 +++++++ test/CodeGen/R600/fminnum.ll | 189 +++++++++++++++++ test/CodeGen/X86/fmaxnum.ll | 50 +++++ test/CodeGen/X86/fminnum.ll | 95 +++++++++ 26 files changed, 1065 insertions(+), 6 deletions(-) create mode 100644 test/CodeGen/PowerPC/fmaxnum.ll create mode 100644 test/CodeGen/PowerPC/fminnum.ll create mode 100644 test/CodeGen/R600/fmaxnum.f64.ll create mode 100644 test/CodeGen/R600/fmaxnum.ll create mode 100644 test/CodeGen/R600/fminnum.f64.ll create mode 100644 test/CodeGen/R600/fminnum.ll create mode 100644 test/CodeGen/X86/fmaxnum.ll create mode 100644 test/CodeGen/X86/fminnum.ll diff --git a/include/llvm/CodeGen/ISDOpcodes.h b/include/llvm/CodeGen/ISDOpcodes.h index 84447616c98..bbf0ad30458 100644 --- a/include/llvm/CodeGen/ISDOpcodes.h +++ b/include/llvm/CodeGen/ISDOpcodes.h @@ -485,7 +485,8 @@ namespace ISD { FNEG, FABS, FSQRT, FSIN, FCOS, FPOWI, FPOW, FLOG, FLOG2, FLOG10, FEXP, FEXP2, FCEIL, FTRUNC, FRINT, FNEARBYINT, FROUND, FFLOOR, - + FMINNUM, FMAXNUM, + /// FSINCOS - Compute both fsin and fcos as a single operation. FSINCOS, diff --git a/include/llvm/CodeGen/RuntimeLibcalls.h b/include/llvm/CodeGen/RuntimeLibcalls.h index 81db8a2f79b..64c9c4729e9 100644 --- a/include/llvm/CodeGen/RuntimeLibcalls.h +++ b/include/llvm/CodeGen/RuntimeLibcalls.h @@ -203,6 +203,16 @@ namespace RTLIB { COPYSIGN_F80, COPYSIGN_F128, COPYSIGN_PPCF128, + FMIN_F32, + FMIN_F64, + FMIN_F80, + FMIN_F128, + FMIN_PPCF128, + FMAX_F32, + FMAX_F64, + FMAX_F80, + FMAX_F128, + FMAX_PPCF128, // CONVERSION FPEXT_F64_F128, diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h index f737be5022f..ade7e566942 100644 --- a/include/llvm/CodeGen/SelectionDAG.h +++ b/include/llvm/CodeGen/SelectionDAG.h @@ -1067,7 +1067,10 @@ public: case ISD::SADDO: case ISD::UADDO: case ISD::ADDC: - case ISD::ADDE: return true; + case ISD::ADDE: + case ISD::FMINNUM: + case ISD::FMAXNUM: + return true; default: return false; } } diff --git a/lib/CodeGen/BasicTargetTransformInfo.cpp b/lib/CodeGen/BasicTargetTransformInfo.cpp index 9a3e296c324..190e38bd8c1 100644 --- a/lib/CodeGen/BasicTargetTransformInfo.cpp +++ b/lib/CodeGen/BasicTargetTransformInfo.cpp @@ -565,6 +565,8 @@ unsigned BasicTTI::getIntrinsicInstrCost(Intrinsic::ID IID, Type *RetTy, case Intrinsic::log10: ISD = ISD::FLOG10; break; case Intrinsic::log2: ISD = ISD::FLOG2; break; case Intrinsic::fabs: ISD = ISD::FABS; break; + case Intrinsic::minnum: ISD = ISD::FMINNUM; break; + case Intrinsic::maxnum: ISD = ISD::FMAXNUM; break; case Intrinsic::copysign: ISD = ISD::FCOPYSIGN; break; case Intrinsic::floor: ISD = ISD::FFLOOR; break; case Intrinsic::ceil: ISD = ISD::FCEIL; break; diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index c131599931e..df95d291a39 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -290,6 +290,8 @@ namespace { SDValue visitFCEIL(SDNode *N); SDValue visitFTRUNC(SDNode *N); SDValue visitFFLOOR(SDNode *N); + SDValue visitFMINNUM(SDNode *N); + SDValue visitFMAXNUM(SDNode *N); SDValue visitBRCOND(SDNode *N); SDValue visitBR_CC(SDNode *N); SDValue visitLOAD(SDNode *N); @@ -1321,6 +1323,8 @@ SDValue DAGCombiner::visit(SDNode *N) { case ISD::FNEG: return visitFNEG(N); case ISD::FABS: return visitFABS(N); case ISD::FFLOOR: return visitFFLOOR(N); + case ISD::FMINNUM: return visitFMINNUM(N); + case ISD::FMAXNUM: return visitFMAXNUM(N); case ISD::FCEIL: return visitFCEIL(N); case ISD::FTRUNC: return visitFTRUNC(N); case ISD::BRCOND: return visitBRCOND(N); @@ -7493,6 +7497,48 @@ SDValue DAGCombiner::visitFNEG(SDNode *N) { return SDValue(); } +SDValue DAGCombiner::visitFMINNUM(SDNode *N) { + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + const ConstantFPSDNode *N0CFP = dyn_cast(N0); + const ConstantFPSDNode *N1CFP = dyn_cast(N1); + + if (N0CFP && N1CFP) { + const APFloat &C0 = N0CFP->getValueAPF(); + const APFloat &C1 = N1CFP->getValueAPF(); + return DAG.getConstantFP(minnum(C0, C1), N->getValueType(0)); + } + + if (N0CFP) { + EVT VT = N->getValueType(0); + // Canonicalize to constant on RHS. + return DAG.getNode(ISD::FMINNUM, SDLoc(N), VT, N1, N0); + } + + return SDValue(); +} + +SDValue DAGCombiner::visitFMAXNUM(SDNode *N) { + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + const ConstantFPSDNode *N0CFP = dyn_cast(N0); + const ConstantFPSDNode *N1CFP = dyn_cast(N1); + + if (N0CFP && N1CFP) { + const APFloat &C0 = N0CFP->getValueAPF(); + const APFloat &C1 = N1CFP->getValueAPF(); + return DAG.getConstantFP(maxnum(C0, C1), N->getValueType(0)); + } + + if (N0CFP) { + EVT VT = N->getValueType(0); + // Canonicalize to constant on RHS. + return DAG.getNode(ISD::FMAXNUM, SDLoc(N), VT, N1, N0); + } + + return SDValue(); +} + SDValue DAGCombiner::visitFABS(SDNode *N) { SDValue N0 = N->getOperand(0); EVT VT = N->getValueType(0); diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index f901823f1eb..d050e07a1ec 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -3400,6 +3400,16 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node) { Results.push_back(Tmp1); break; } + case ISD::FMINNUM: + Results.push_back(ExpandFPLibCall(Node, RTLIB::FMIN_F32, RTLIB::FMIN_F64, + RTLIB::FMIN_F80, RTLIB::FMIN_F128, + RTLIB::FMIN_PPCF128)); + break; + case ISD::FMAXNUM: + Results.push_back(ExpandFPLibCall(Node, RTLIB::FMAX_F32, RTLIB::FMAX_F64, + RTLIB::FMAX_F80, RTLIB::FMAX_F128, + RTLIB::FMAX_PPCF128)); + break; case ISD::FSQRT: Results.push_back(ExpandFPLibCall(Node, RTLIB::SQRT_F32, RTLIB::SQRT_F64, RTLIB::SQRT_F80, RTLIB::SQRT_F128, diff --git a/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp index bcda2b8de65..4591e79316d 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -68,6 +68,8 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) { case ISD::EXTRACT_VECTOR_ELT: R = SoftenFloatRes_EXTRACT_VECTOR_ELT(N); break; case ISD::FABS: R = SoftenFloatRes_FABS(N); break; + case ISD::FMINNUM: R = SoftenFloatRes_FMINNUM(N); break; + case ISD::FMAXNUM: R = SoftenFloatRes_FMAXNUM(N); break; case ISD::FADD: R = SoftenFloatRes_FADD(N); break; case ISD::FCEIL: R = SoftenFloatRes_FCEIL(N); break; case ISD::FCOPYSIGN: R = SoftenFloatRes_FCOPYSIGN(N); break; @@ -153,6 +155,32 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FABS(SDNode *N) { return DAG.getNode(ISD::AND, SDLoc(N), NVT, Op, Mask); } +SDValue DAGTypeLegalizer::SoftenFloatRes_FMINNUM(SDNode *N) { + EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); + SDValue Ops[2] = { GetSoftenedFloat(N->getOperand(0)), + GetSoftenedFloat(N->getOperand(1)) }; + return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), + RTLIB::FMIN_F32, + RTLIB::FMIN_F64, + RTLIB::FMIN_F80, + RTLIB::FMIN_F128, + RTLIB::FMIN_PPCF128), + NVT, Ops, 2, false, SDLoc(N)).first; +} + +SDValue DAGTypeLegalizer::SoftenFloatRes_FMAXNUM(SDNode *N) { + EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); + SDValue Ops[2] = { GetSoftenedFloat(N->getOperand(0)), + GetSoftenedFloat(N->getOperand(1)) }; + return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), + RTLIB::FMAX_F32, + RTLIB::FMAX_F64, + RTLIB::FMAX_F80, + RTLIB::FMAX_F128, + RTLIB::FMAX_PPCF128), + NVT, Ops, 2, false, SDLoc(N)).first; +} + SDValue DAGTypeLegalizer::SoftenFloatRes_FADD(SDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Ops[2] = { GetSoftenedFloat(N->getOperand(0)), @@ -856,6 +884,8 @@ void DAGTypeLegalizer::ExpandFloatResult(SDNode *N, unsigned ResNo) { case ISD::ConstantFP: ExpandFloatRes_ConstantFP(N, Lo, Hi); break; case ISD::FABS: ExpandFloatRes_FABS(N, Lo, Hi); break; + case ISD::FMINNUM: ExpandFloatRes_FMINNUM(N, Lo, Hi); break; + case ISD::FMAXNUM: ExpandFloatRes_FMAXNUM(N, Lo, Hi); break; case ISD::FADD: ExpandFloatRes_FADD(N, Lo, Hi); break; case ISD::FCEIL: ExpandFloatRes_FCEIL(N, Lo, Hi); break; case ISD::FCOPYSIGN: ExpandFloatRes_FCOPYSIGN(N, Lo, Hi); break; @@ -919,6 +949,26 @@ void DAGTypeLegalizer::ExpandFloatRes_FABS(SDNode *N, SDValue &Lo, ISD::SETEQ); } +void DAGTypeLegalizer::ExpandFloatRes_FMINNUM(SDNode *N, SDValue &Lo, + SDValue &Hi) { + SDValue Call = LibCallify(GetFPLibCall(N->getValueType(0), + RTLIB::FMIN_F32, RTLIB::FMIN_F64, + RTLIB::FMIN_F80, RTLIB::FMIN_F128, + RTLIB::FMIN_PPCF128), + N, false); + GetPairElements(Call, Lo, Hi); +} + +void DAGTypeLegalizer::ExpandFloatRes_FMAXNUM(SDNode *N, SDValue &Lo, + SDValue &Hi) { + SDValue Call = LibCallify(GetFPLibCall(N->getValueType(0), + RTLIB::FMAX_F32, RTLIB::FMAX_F64, + RTLIB::FMAX_F80, RTLIB::FMAX_F128, + RTLIB::FMAX_PPCF128), + N, false); + GetPairElements(Call, Lo, Hi); +} + void DAGTypeLegalizer::ExpandFloatRes_FADD(SDNode *N, SDValue &Lo, SDValue &Hi) { SDValue Call = LibCallify(GetFPLibCall(N->getValueType(0), diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index b82b39ff68c..9974c13915f 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -387,6 +387,8 @@ private: SDValue SoftenFloatRes_ConstantFP(ConstantFPSDNode *N); SDValue SoftenFloatRes_EXTRACT_VECTOR_ELT(SDNode *N); SDValue SoftenFloatRes_FABS(SDNode *N); + SDValue SoftenFloatRes_FMINNUM(SDNode *N); + SDValue SoftenFloatRes_FMAXNUM(SDNode *N); SDValue SoftenFloatRes_FADD(SDNode *N); SDValue SoftenFloatRes_FCEIL(SDNode *N); SDValue SoftenFloatRes_FCOPYSIGN(SDNode *N); @@ -450,6 +452,8 @@ private: void ExpandFloatResult(SDNode *N, unsigned ResNo); void ExpandFloatRes_ConstantFP(SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_FABS (SDNode *N, SDValue &Lo, SDValue &Hi); + void ExpandFloatRes_FMINNUM (SDNode *N, SDValue &Lo, SDValue &Hi); + void ExpandFloatRes_FMAXNUM (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_FADD (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_FCEIL (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandFloatRes_FCOPYSIGN (SDNode *N, SDValue &Lo, SDValue &Hi); diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp index 16cf2deffb1..b5af7b706b0 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp @@ -290,6 +290,8 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) { case ISD::FP_TO_UINT: case ISD::FNEG: case ISD::FABS: + case ISD::FMINNUM: + case ISD::FMAXNUM: case ISD::FCOPYSIGN: case ISD::FSQRT: case ISD::FSIN: diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index 28727a61a6a..3b67b31d9d5 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -106,6 +106,9 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) { case ISD::FCOPYSIGN: case ISD::FDIV: case ISD::FMUL: + case ISD::FMINNUM: + case ISD::FMAXNUM: + case ISD::FPOW: case ISD::FREM: case ISD::FSUB: @@ -627,6 +630,8 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) { case ISD::FCOPYSIGN: case ISD::FSUB: case ISD::FMUL: + case ISD::FMINNUM: + case ISD::FMAXNUM: case ISD::SDIV: case ISD::UDIV: case ISD::FDIV: @@ -1583,6 +1588,8 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) { case ISD::OR: case ISD::SUB: case ISD::XOR: + case ISD::FMINNUM: + case ISD::FMAXNUM: Res = WidenVecRes_Binary(N); break; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 3a14a3702e8..3a11277c473 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5087,6 +5087,18 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { getValue(I.getArgOperand(0)))); return nullptr; } + case Intrinsic::minnum: + setValue(&I, DAG.getNode(ISD::FMINNUM, sdl, + getValue(I.getArgOperand(0)).getValueType(), + getValue(I.getArgOperand(0)), + getValue(I.getArgOperand(1)))); + return nullptr; + case Intrinsic::maxnum: + setValue(&I, DAG.getNode(ISD::FMAXNUM, sdl, + getValue(I.getArgOperand(0)).getValueType(), + getValue(I.getArgOperand(0)), + getValue(I.getArgOperand(1)))); + return nullptr; case Intrinsic::copysign: setValue(&I, DAG.getNode(ISD::FCOPYSIGN, sdl, getValue(I.getArgOperand(0)).getValueType(), @@ -5887,6 +5899,26 @@ bool SelectionDAGBuilder::visitUnaryFloatCall(const CallInst &I, return true; } +/// visitBinaryFloatCall - If a call instruction is a unary floating-point +/// operation (as expected), translate it to an SDNode with the specified opcode +/// and return true. +bool SelectionDAGBuilder::visitBinaryFloatCall(const CallInst &I, + unsigned Opcode) { + // Sanity check that it really is a unary floating-point call. + if (I.getNumArgOperands() != 2 || + !I.getArgOperand(0)->getType()->isFloatingPointTy() || + I.getType() != I.getArgOperand(0)->getType() || + I.getType() != I.getArgOperand(1)->getType() || + !I.onlyReadsMemory()) + return false; + + SDValue Tmp0 = getValue(I.getArgOperand(0)); + SDValue Tmp1 = getValue(I.getArgOperand(1)); + EVT VT = Tmp0.getValueType(); + setValue(&I, DAG.getNode(Opcode, getCurSDLoc(), VT, Tmp0, Tmp1)); + return true; +} + void SelectionDAGBuilder::visitCall(const CallInst &I) { // Handle inline assembly differently. if (isa(I.getCalledValue())) { @@ -5943,6 +5975,18 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) { if (visitUnaryFloatCall(I, ISD::FABS)) return; break; + case LibFunc::fmin: + case LibFunc::fminf: + case LibFunc::fminl: + if (visitBinaryFloatCall(I, ISD::FMINNUM)) + return; + break; + case LibFunc::fmax: + case LibFunc::fmaxf: + case LibFunc::fmaxl: + if (visitBinaryFloatCall(I, ISD::FMAXNUM)) + return; + break; case LibFunc::sin: case LibFunc::sinf: case LibFunc::sinl: diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h index 4cdb69196d7..f74e6525b0c 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -768,6 +768,7 @@ private: bool visitStrLenCall(const CallInst &I); bool visitStrNLenCall(const CallInst &I); bool visitUnaryFloatCall(const CallInst &I, unsigned Opcode); + bool visitBinaryFloatCall(const CallInst &I, unsigned Opcode); void visitAtomicLoad(const LoadInst &I); void visitAtomicStore(const StoreInst &I); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp index c10803f55b7..1871e3defb0 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -141,6 +141,8 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { // Unary operators case ISD::FABS: return "fabs"; + case ISD::FMINNUM: return "fminnum"; + case ISD::FMAXNUM: return "fmaxnum"; case ISD::FNEG: return "fneg"; case ISD::FSQRT: return "fsqrt"; case ISD::FSIN: return "fsin"; diff --git a/lib/CodeGen/TargetLoweringBase.cpp b/lib/CodeGen/TargetLoweringBase.cpp index b60a73f7fc1..a5889db9104 100644 --- a/lib/CodeGen/TargetLoweringBase.cpp +++ b/lib/CodeGen/TargetLoweringBase.cpp @@ -206,6 +206,16 @@ static void InitLibcallNames(const char **Names, const Triple &TT) { Names[RTLIB::FLOOR_F80] = "floorl"; Names[RTLIB::FLOOR_F128] = "floorl"; Names[RTLIB::FLOOR_PPCF128] = "floorl"; + Names[RTLIB::FMIN_F32] = "fminf"; + Names[RTLIB::FMIN_F64] = "fmin"; + Names[RTLIB::FMIN_F80] = "fminl"; + Names[RTLIB::FMIN_F128] = "fminl"; + Names[RTLIB::FMIN_PPCF128] = "fminl"; + Names[RTLIB::FMAX_F32] = "fmaxf"; + Names[RTLIB::FMAX_F64] = "fmax"; + Names[RTLIB::FMAX_F80] = "fmaxl"; + Names[RTLIB::FMAX_F128] = "fmaxl"; + Names[RTLIB::FMAX_PPCF128] = "fmaxl"; Names[RTLIB::ROUND_F32] = "roundf"; Names[RTLIB::ROUND_F64] = "round"; Names[RTLIB::ROUND_F80] = "roundl"; @@ -757,6 +767,8 @@ void TargetLoweringBase::initActions() { // These operations default to expand. setOperationAction(ISD::FGETSIGN, (MVT::SimpleValueType)VT, Expand); setOperationAction(ISD::CONCAT_VECTORS, (MVT::SimpleValueType)VT, Expand); + setOperationAction(ISD::FMINNUM, (MVT::SimpleValueType)VT, Expand); + setOperationAction(ISD::FMAXNUM, (MVT::SimpleValueType)VT, Expand); // These library functions default to expand. setOperationAction(ISD::FROUND, (MVT::SimpleValueType)VT, Expand); @@ -793,6 +805,8 @@ void TargetLoweringBase::initActions() { setOperationAction(ISD::FEXP , MVT::f16, Expand); setOperationAction(ISD::FEXP2, MVT::f16, Expand); setOperationAction(ISD::FFLOOR, MVT::f16, Expand); + setOperationAction(ISD::FMINNUM, MVT::f16, Expand); + setOperationAction(ISD::FMAXNUM, MVT::f16, Expand); setOperationAction(ISD::FNEARBYINT, MVT::f16, Expand); setOperationAction(ISD::FCEIL, MVT::f16, Expand); setOperationAction(ISD::FRINT, MVT::f16, Expand); @@ -804,6 +818,8 @@ void TargetLoweringBase::initActions() { setOperationAction(ISD::FEXP , MVT::f32, Expand); setOperationAction(ISD::FEXP2, MVT::f32, Expand); setOperationAction(ISD::FFLOOR, MVT::f32, Expand); + setOperationAction(ISD::FMINNUM, MVT::f32, Expand); + setOperationAction(ISD::FMAXNUM, MVT::f32, Expand); setOperationAction(ISD::FNEARBYINT, MVT::f32, Expand); setOperationAction(ISD::FCEIL, MVT::f32, Expand); setOperationAction(ISD::FRINT, MVT::f32, Expand); @@ -815,6 +831,8 @@ void TargetLoweringBase::initActions() { setOperationAction(ISD::FEXP , MVT::f64, Expand); setOperationAction(ISD::FEXP2, MVT::f64, Expand); setOperationAction(ISD::FFLOOR, MVT::f64, Expand); + setOperationAction(ISD::FMINNUM, MVT::f64, Expand); + setOperationAction(ISD::FMAXNUM, MVT::f64, Expand); setOperationAction(ISD::FNEARBYINT, MVT::f64, Expand); setOperationAction(ISD::FCEIL, MVT::f64, Expand); setOperationAction(ISD::FRINT, MVT::f64, Expand); @@ -826,6 +844,8 @@ void TargetLoweringBase::initActions() { setOperationAction(ISD::FEXP , MVT::f128, Expand); setOperationAction(ISD::FEXP2, MVT::f128, Expand); setOperationAction(ISD::FFLOOR, MVT::f128, Expand); + setOperationAction(ISD::FMINNUM, MVT::f128, Expand); + setOperationAction(ISD::FMAXNUM, MVT::f128, Expand); setOperationAction(ISD::FNEARBYINT, MVT::f128, Expand); setOperationAction(ISD::FCEIL, MVT::f128, Expand); setOperationAction(ISD::FRINT, MVT::f128, Expand); diff --git a/lib/Target/R600/AMDGPUISelLowering.cpp b/lib/Target/R600/AMDGPUISelLowering.cpp index 37c444d220f..2ac20db6dc7 100644 --- a/lib/Target/R600/AMDGPUISelLowering.cpp +++ b/lib/Target/R600/AMDGPUISelLowering.cpp @@ -347,6 +347,8 @@ AMDGPUTargetLowering::AMDGPUTargetLowering(TargetMachine &TM) : for (MVT VT : FloatVectorTypes) { setOperationAction(ISD::FABS, VT, Expand); + setOperationAction(ISD::FMINNUM, VT, Expand); + setOperationAction(ISD::FMAXNUM, VT, Expand); setOperationAction(ISD::FADD, VT, Expand); setOperationAction(ISD::FCEIL, VT, Expand); setOperationAction(ISD::FCOS, VT, Expand); diff --git a/lib/Target/R600/SIISelLowering.cpp b/lib/Target/R600/SIISelLowering.cpp index 039282939f1..f306a3bf9f4 100644 --- a/lib/Target/R600/SIISelLowering.cpp +++ b/lib/Target/R600/SIISelLowering.cpp @@ -90,6 +90,11 @@ SITargetLowering::SITargetLowering(TargetMachine &TM) : setOperationAction(ISD::FSIN, MVT::f32, Custom); setOperationAction(ISD::FCOS, MVT::f32, Custom); + setOperationAction(ISD::FMINNUM, MVT::f32, Legal); + setOperationAction(ISD::FMAXNUM, MVT::f32, Legal); + setOperationAction(ISD::FMINNUM, MVT::f64, Legal); + setOperationAction(ISD::FMAXNUM, MVT::f64, Legal); + // We need to custom lower vector stores from local memory setOperationAction(ISD::LOAD, MVT::v4i32, Custom); setOperationAction(ISD::LOAD, MVT::v8i32, Custom); diff --git a/lib/Target/R600/SIInstructions.td b/lib/Target/R600/SIInstructions.td index 479eebefec0..d437fb252b7 100644 --- a/lib/Target/R600/SIInstructions.td +++ b/lib/Target/R600/SIInstructions.td @@ -1407,8 +1407,8 @@ defm V_MAX_LEGACY_F32 : VOP2Inst , "V_MAX_LEGACY_F32", VOP_F32_F32_F32, AMDGPUfmax >; -defm V_MIN_F32 : VOP2Inst , "V_MIN_F32", VOP_F32_F32_F32>; -defm V_MAX_F32 : VOP2Inst , "V_MAX_F32", VOP_F32_F32_F32>; +defm V_MIN_F32 : VOP2Inst , "V_MIN_F32", VOP_F32_F32_F32, fminnum>; +defm V_MAX_F32 : VOP2Inst , "V_MAX_F32", VOP_F32_F32_F32, fmaxnum>; defm V_MIN_I32 : VOP2Inst , "V_MIN_I32", VOP_I32_I32_I32, AMDGPUsmin>; defm V_MAX_I32 : VOP2Inst , "V_MAX_I32", VOP_I32_I32_I32, AMDGPUsmax>; defm V_MIN_U32 : VOP2Inst , "V_MIN_U32", VOP_I32_I32_I32, AMDGPUumin>; @@ -1593,11 +1593,12 @@ defm V_ADD_F64 : VOP3Inst , "V_ADD_F64", defm V_MUL_F64 : VOP3Inst , "V_MUL_F64", VOP_F64_F64_F64, fmul >; + defm V_MIN_F64 : VOP3Inst , "V_MIN_F64", - VOP_F64_F64_F64 + VOP_F64_F64_F64, fminnum >; defm V_MAX_F64 : VOP3Inst , "V_MAX_F64", - VOP_F64_F64_F64 + VOP_F64_F64_F64, fmaxnum >; } // isCommutable = 1 diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 543a2fdc99f..73cbd563f5a 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -811,6 +811,8 @@ void X86TargetLowering::resetOperationActions() { setOperationAction(ISD::FLOG10, MVT::f80, Expand); setOperationAction(ISD::FEXP, MVT::f80, Expand); setOperationAction(ISD::FEXP2, MVT::f80, Expand); + setOperationAction(ISD::FMINNUM, MVT::f80, Expand); + setOperationAction(ISD::FMAXNUM, MVT::f80, Expand); // First set operation action for all vector types to either promote // (for widening) or expand (for scalarization). Then we will selectively diff --git a/test/CodeGen/PowerPC/fmaxnum.ll b/test/CodeGen/PowerPC/fmaxnum.ll new file mode 100644 index 00000000000..18258502907 --- /dev/null +++ b/test/CodeGen/PowerPC/fmaxnum.ll @@ -0,0 +1,86 @@ +; RUN: llc -march=ppc32 -mtriple=powerpc-unknown-linux-gnu < %s | FileCheck %s + +declare float @fmaxf(float, float) +declare double @fmax(double, double) +declare ppc_fp128 @fmaxl(ppc_fp128, ppc_fp128) +declare float @llvm.maxnum.f32(float, float) +declare double @llvm.maxnum.f64(double, double) +declare ppc_fp128 @llvm.maxnum.ppcf128(ppc_fp128, ppc_fp128) + +declare <2 x float> @llvm.maxnum.v2f32(<2 x float>, <2 x float>) +declare <4 x float> @llvm.maxnum.v4f32(<4 x float>, <4 x float>) +declare <8 x float> @llvm.maxnum.v8f32(<8 x float>, <8 x float>) + +; CHECK-LABEL: @test_fmaxf +; CHECK: bl fmaxf +define float @test_fmaxf(float %x, float %y) { + %z = call float @fmaxf(float %x, float %y) readnone + ret float %z +} + +; CHECK-LABEL: @test_fmax +; CHECK: bl fmax +define double @test_fmax(double %x, double %y) { + %z = call double @fmax(double %x, double %y) readnone + ret double %z +} + +; CHECK-LABEL: @test_fmaxl +; CHECK: bl fmaxl +define ppc_fp128 @test_fmaxl(ppc_fp128 %x, ppc_fp128 %y) { + %z = call ppc_fp128 @fmaxl(ppc_fp128 %x, ppc_fp128 %y) readnone + ret ppc_fp128 %z +} + +; CHECK-LABEL: @test_intrinsic_fmaxf +; CHECK: bl fmaxf +define float @test_intrinsic_fmaxf(float %x, float %y) { + %z = call float @llvm.maxnum.f32(float %x, float %y) readnone + ret float %z +} + +; CHECK-LABEL: @test_intrinsic_fmax +; CHECK: bl fmax +define double @test_intrinsic_fmax(double %x, double %y) { + %z = call double @llvm.maxnum.f64(double %x, double %y) readnone + ret double %z +} + +; CHECK-LABEL: @test_intrinsic_fmaxl +; CHECK: bl fmaxl +define ppc_fp128 @test_intrinsic_fmaxl(ppc_fp128 %x, ppc_fp128 %y) { + %z = call ppc_fp128 @llvm.maxnum.ppcf128(ppc_fp128 %x, ppc_fp128 %y) readnone + ret ppc_fp128 %z +} + +; CHECK-LABEL: @test_intrinsic_fmaxf_v2f32 +; CHECK: bl fmaxf +; CHECK: bl fmaxf +define <2 x float> @test_intrinsic_fmaxf_v2f32(<2 x float> %x, <2 x float> %y) { + %z = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> %y) readnone + ret <2 x float> %z +} + +; CHECK-LABEL: @test_intrinsic_fmaxf_v4f32 +; CHECK: bl fmaxf +; CHECK: bl fmaxf +; CHECK: bl fmaxf +; CHECK: bl fmaxf +define <4 x float> @test_intrinsic_fmaxf_v4f32(<4 x float> %x, <4 x float> %y) { + %z = call <4 x float> @llvm.maxnum.v4f32(<4 x float> %x, <4 x float> %y) readnone + ret <4 x float> %z +} + +; CHECK-LABEL: @test_intrinsic_fmaxf_v8f32 +; CHECK: bl fmaxf +; CHECK: bl fmaxf +; CHECK: bl fmaxf +; CHECK: bl fmaxf +; CHECK: bl fmaxf +; CHECK: bl fmaxf +; CHECK: bl fmaxf +; CHECK: bl fmaxf +define <8 x float> @test_intrinsic_fmaxf_v8f32(<8 x float> %x, <8 x float> %y) { + %z = call <8 x float> @llvm.maxnum.v8f32(<8 x float> %x, <8 x float> %y) readnone + ret <8 x float> %z +} diff --git a/test/CodeGen/PowerPC/fminnum.ll b/test/CodeGen/PowerPC/fminnum.ll new file mode 100644 index 00000000000..fe91284cdb7 --- /dev/null +++ b/test/CodeGen/PowerPC/fminnum.ll @@ -0,0 +1,86 @@ +; RUN: llc -march=ppc32 -mtriple=powerpc-unknown-linux-gnu < %s | FileCheck %s + +declare float @fminf(float, float) +declare double @fmin(double, double) +declare ppc_fp128 @fminl(ppc_fp128, ppc_fp128) +declare float @llvm.minnum.f32(float, float) +declare double @llvm.minnum.f64(double, double) +declare ppc_fp128 @llvm.minnum.ppcf128(ppc_fp128, ppc_fp128) + +declare <2 x float> @llvm.minnum.v2f32(<2 x float>, <2 x float>) +declare <4 x float> @llvm.minnum.v4f32(<4 x float>, <4 x float>) +declare <8 x float> @llvm.minnum.v8f32(<8 x float>, <8 x float>) + +; CHECK-LABEL: @test_fminf +; CHECK: bl fminf +define float @test_fminf(float %x, float %y) { + %z = call float @fminf(float %x, float %y) readnone + ret float %z +} + +; CHECK-LABEL: @test_fmin +; CHECK: bl fmin +define double @test_fmin(double %x, double %y) { + %z = call double @fmin(double %x, double %y) readnone + ret double %z +} + +; CHECK-LABEL: @test_fminl +; CHECK: bl fminl +define ppc_fp128 @test_fminl(ppc_fp128 %x, ppc_fp128 %y) { + %z = call ppc_fp128 @fminl(ppc_fp128 %x, ppc_fp128 %y) readnone + ret ppc_fp128 %z +} + +; CHECK-LABEL: @test_intrinsic_fmin_f32 +; CHECK: bl fminf +define float @test_intrinsic_fmin_f32(float %x, float %y) { + %z = call float @llvm.minnum.f32(float %x, float %y) readnone + ret float %z +} + +; CHECK-LABEL: @test_intrinsic_fmin_f64 +; CHECK: bl fmin +define double @test_intrinsic_fmin_f64(double %x, double %y) { + %z = call double @llvm.minnum.f64(double %x, double %y) readnone + ret double %z +} + +; CHECK-LABEL: @test_intrinsic_fmin_f128 +; CHECK: bl fminl +define ppc_fp128 @test_intrinsic_fmin_f128(ppc_fp128 %x, ppc_fp128 %y) { + %z = call ppc_fp128 @llvm.minnum.ppcf128(ppc_fp128 %x, ppc_fp128 %y) readnone + ret ppc_fp128 %z +} + +; CHECK-LABEL: @test_intrinsic_fminf_v2f32 +; CHECK: bl fminf +; CHECK: bl fminf +define <2 x float> @test_intrinsic_fminf_v2f32(<2 x float> %x, <2 x float> %y) { + %z = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> %y) readnone + ret <2 x float> %z +} + +; CHECK-LABEL: @test_intrinsic_fmin_v4f32 +; CHECK: bl fminf +; CHECK: bl fminf +; CHECK: bl fminf +; CHECK: bl fminf +define <4 x float> @test_intrinsic_fmin_v4f32(<4 x float> %x, <4 x float> %y) { + %z = call <4 x float> @llvm.minnum.v4f32(<4 x float> %x, <4 x float> %y) readnone + ret <4 x float> %z +} + +; CHECK-LABEL: @test_intrinsic_fmin_v8f32 +; CHECK: bl fminf +; CHECK: bl fminf +; CHECK: bl fminf +; CHECK: bl fminf +; CHECK: bl fminf +; CHECK: bl fminf +; CHECK: bl fminf +; CHECK: bl fminf +define <8 x float> @test_intrinsic_fmin_v8f32(<8 x float> %x, <8 x float> %y) { + %z = call <8 x float> @llvm.minnum.v8f32(<8 x float> %x, <8 x float> %y) readnone + ret <8 x float> %z +} diff --git a/test/CodeGen/R600/fmaxnum.f64.ll b/test/CodeGen/R600/fmaxnum.f64.ll new file mode 100644 index 00000000000..af762e108ee --- /dev/null +++ b/test/CodeGen/R600/fmaxnum.f64.ll @@ -0,0 +1,75 @@ +; RUN: llc -march=r600 -mcpu=SI < %s | FileCheck -check-prefix=SI -check-prefix=FUNC %s + +declare double @llvm.maxnum.f64(double, double) #0 +declare <2 x double> @llvm.maxnum.v2f64(<2 x double>, <2 x double>) #0 +declare <4 x double> @llvm.maxnum.v4f64(<4 x double>, <4 x double>) #0 +declare <8 x double> @llvm.maxnum.v8f64(<8 x double>, <8 x double>) #0 +declare <16 x double> @llvm.maxnum.v16f64(<16 x double>, <16 x double>) #0 + +; FUNC-LABEL: @test_fmax_f64 +; SI: V_MAX_F64 +define void @test_fmax_f64(double addrspace(1)* %out, double %a, double %b) nounwind { + %val = call double @llvm.maxnum.f64(double %a, double %b) #0 + store double %val, double addrspace(1)* %out, align 8 + ret void +} + +; FUNC-LABEL: @test_fmax_v2f64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +define void @test_fmax_v2f64(<2 x double> addrspace(1)* %out, <2 x double> %a, <2 x double> %b) nounwind { + %val = call <2 x double> @llvm.maxnum.v2f64(<2 x double> %a, <2 x double> %b) #0 + store <2 x double> %val, <2 x double> addrspace(1)* %out, align 16 + ret void +} + +; FUNC-LABEL: @test_fmax_v4f64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +define void @test_fmax_v4f64(<4 x double> addrspace(1)* %out, <4 x double> %a, <4 x double> %b) nounwind { + %val = call <4 x double> @llvm.maxnum.v4f64(<4 x double> %a, <4 x double> %b) #0 + store <4 x double> %val, <4 x double> addrspace(1)* %out, align 32 + ret void +} + +; FUNC-LABEL: @test_fmax_v8f64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +define void @test_fmax_v8f64(<8 x double> addrspace(1)* %out, <8 x double> %a, <8 x double> %b) nounwind { + %val = call <8 x double> @llvm.maxnum.v8f64(<8 x double> %a, <8 x double> %b) #0 + store <8 x double> %val, <8 x double> addrspace(1)* %out, align 64 + ret void +} + +; FUNC-LABEL: @test_fmax_v16f64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +; SI: V_MAX_F64 +define void @test_fmax_v16f64(<16 x double> addrspace(1)* %out, <16 x double> %a, <16 x double> %b) nounwind { + %val = call <16 x double> @llvm.maxnum.v16f64(<16 x double> %a, <16 x double> %b) #0 + store <16 x double> %val, <16 x double> addrspace(1)* %out, align 128 + ret void +} + +attributes #0 = { nounwind readnone } diff --git a/test/CodeGen/R600/fmaxnum.ll b/test/CodeGen/R600/fmaxnum.ll new file mode 100644 index 00000000000..227537df716 --- /dev/null +++ b/test/CodeGen/R600/fmaxnum.ll @@ -0,0 +1,191 @@ +; RUN: llc -march=r600 -mcpu=SI < %s | FileCheck -check-prefix=SI -check-prefix=FUNC %s + +declare float @llvm.maxnum.f32(float, float) #0 +declare <2 x float> @llvm.maxnum.v2f32(<2 x float>, <2 x float>) #0 +declare <4 x float> @llvm.maxnum.v4f32(<4 x float>, <4 x float>) #0 +declare <8 x float> @llvm.maxnum.v8f32(<8 x float>, <8 x float>) #0 +declare <16 x float> @llvm.maxnum.v16f32(<16 x float>, <16 x float>) #0 + +declare double @llvm.maxnum.f64(double, double) + +; FUNC-LABEL: @test_fmax_f32 +; SI: V_MAX_F32_e32 +define void @test_fmax_f32(float addrspace(1)* %out, float %a, float %b) nounwind { + %val = call float @llvm.maxnum.f32(float %a, float %b) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @test_fmax_v2f32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +define void @test_fmax_v2f32(<2 x float> addrspace(1)* %out, <2 x float> %a, <2 x float> %b) nounwind { + %val = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %a, <2 x float> %b) #0 + store <2 x float> %val, <2 x float> addrspace(1)* %out, align 8 + ret void +} + +; FUNC-LABEL: @test_fmax_v4f32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +define void @test_fmax_v4f32(<4 x float> addrspace(1)* %out, <4 x float> %a, <4 x float> %b) nounwind { + %val = call <4 x float> @llvm.maxnum.v4f32(<4 x float> %a, <4 x float> %b) #0 + store <4 x float> %val, <4 x float> addrspace(1)* %out, align 16 + ret void +} + +; FUNC-LABEL: @test_fmax_v8f32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +define void @test_fmax_v8f32(<8 x float> addrspace(1)* %out, <8 x float> %a, <8 x float> %b) nounwind { + %val = call <8 x float> @llvm.maxnum.v8f32(<8 x float> %a, <8 x float> %b) #0 + store <8 x float> %val, <8 x float> addrspace(1)* %out, align 32 + ret void +} + +; FUNC-LABEL: @test_fmax_v16f32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +; SI: V_MAX_F32_e32 +define void @test_fmax_v16f32(<16 x float> addrspace(1)* %out, <16 x float> %a, <16 x float> %b) nounwind { + %val = call <16 x float> @llvm.maxnum.v16f32(<16 x float> %a, <16 x float> %b) #0 + store <16 x float> %val, <16 x float> addrspace(1)* %out, align 64 + ret void +} + +; FUNC-LABEL: @constant_fold_fmax_f32 +; SI-NOT: V_MAX_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 2.0 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmax_f32(float addrspace(1)* %out) nounwind { + %val = call float @llvm.maxnum.f32(float 1.0, float 2.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmax_f32_nan_nan +; SI-NOT: V_MAX_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0x7fc00000 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmax_f32_nan_nan(float addrspace(1)* %out) nounwind { + %val = call float @llvm.maxnum.f32(float 0x7FF8000000000000, float 0x7FF8000000000000) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmax_f32_val_nan +; SI-NOT: V_MAX_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 1.0 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmax_f32_val_nan(float addrspace(1)* %out) nounwind { + %val = call float @llvm.maxnum.f32(float 1.0, float 0x7FF8000000000000) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmax_f32_nan_val +; SI-NOT: V_MAX_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 1.0 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmax_f32_nan_val(float addrspace(1)* %out) nounwind { + %val = call float @llvm.maxnum.f32(float 0x7FF8000000000000, float 1.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmax_f32_p0_p0 +; SI-NOT: V_MAX_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmax_f32_p0_p0(float addrspace(1)* %out) nounwind { + %val = call float @llvm.maxnum.f32(float 0.0, float 0.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmax_f32_p0_n0 +; SI-NOT: V_MAX_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmax_f32_p0_n0(float addrspace(1)* %out) nounwind { + %val = call float @llvm.maxnum.f32(float 0.0, float -0.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmax_f32_n0_p0 +; SI-NOT: V_MAX_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0x80000000 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmax_f32_n0_p0(float addrspace(1)* %out) nounwind { + %val = call float @llvm.maxnum.f32(float -0.0, float 0.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmax_f32_n0_n0 +; SI-NOT: V_MAX_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0x80000000 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmax_f32_n0_n0(float addrspace(1)* %out) nounwind { + %val = call float @llvm.maxnum.f32(float -0.0, float -0.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @fmax_var_immediate_f32 +; SI: V_MAX_F32_e64 {{v[0-9]+}}, 2.0, {{s[0-9]+}} +define void @fmax_var_immediate_f32(float addrspace(1)* %out, float %a) nounwind { + %val = call float @llvm.maxnum.f32(float %a, float 2.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @fmax_immediate_var_f32 +; SI: V_MAX_F32_e64 {{v[0-9]+}}, 2.0, {{s[0-9]+}} +define void @fmax_immediate_var_f32(float addrspace(1)* %out, float %a) nounwind { + %val = call float @llvm.maxnum.f32(float 2.0, float %a) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @fmax_var_literal_f32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0x42c60000 +; SI: V_MAX_F32_e32 {{v[0-9]+}}, {{s[0-9]+}}, [[REG]] +define void @fmax_var_literal_f32(float addrspace(1)* %out, float %a) nounwind { + %val = call float @llvm.maxnum.f32(float %a, float 99.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @fmax_literal_var_f32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0x42c60000 +; SI: V_MAX_F32_e32 {{v[0-9]+}}, {{s[0-9]+}}, [[REG]] +define void @fmax_literal_var_f32(float addrspace(1)* %out, float %a) nounwind { + %val = call float @llvm.maxnum.f32(float 99.0, float %a) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +attributes #0 = { nounwind readnone } diff --git a/test/CodeGen/R600/fminnum.f64.ll b/test/CodeGen/R600/fminnum.f64.ll new file mode 100644 index 00000000000..5feef60f90d --- /dev/null +++ b/test/CodeGen/R600/fminnum.f64.ll @@ -0,0 +1,75 @@ +; RUN: llc -march=r600 -mcpu=SI < %s | FileCheck -check-prefix=SI -check-prefix=FUNC %s + +declare double @llvm.minnum.f64(double, double) #0 +declare <2 x double> @llvm.minnum.v2f64(<2 x double>, <2 x double>) #0 +declare <4 x double> @llvm.minnum.v4f64(<4 x double>, <4 x double>) #0 +declare <8 x double> @llvm.minnum.v8f64(<8 x double>, <8 x double>) #0 +declare <16 x double> @llvm.minnum.v16f64(<16 x double>, <16 x double>) #0 + +; FUNC-LABEL: @test_fmin_f64 +; SI: V_MIN_F64 +define void @test_fmin_f64(double addrspace(1)* %out, double %a, double %b) nounwind { + %val = call double @llvm.minnum.f64(double %a, double %b) #0 + store double %val, double addrspace(1)* %out, align 8 + ret void +} + +; FUNC-LABEL: @test_fmin_v2f64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +define void @test_fmin_v2f64(<2 x double> addrspace(1)* %out, <2 x double> %a, <2 x double> %b) nounwind { + %val = call <2 x double> @llvm.minnum.v2f64(<2 x double> %a, <2 x double> %b) #0 + store <2 x double> %val, <2 x double> addrspace(1)* %out, align 16 + ret void +} + +; FUNC-LABEL: @test_fmin_v4f64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +define void @test_fmin_v4f64(<4 x double> addrspace(1)* %out, <4 x double> %a, <4 x double> %b) nounwind { + %val = call <4 x double> @llvm.minnum.v4f64(<4 x double> %a, <4 x double> %b) #0 + store <4 x double> %val, <4 x double> addrspace(1)* %out, align 32 + ret void +} + +; FUNC-LABEL: @test_fmin_v8f64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +define void @test_fmin_v8f64(<8 x double> addrspace(1)* %out, <8 x double> %a, <8 x double> %b) nounwind { + %val = call <8 x double> @llvm.minnum.v8f64(<8 x double> %a, <8 x double> %b) #0 + store <8 x double> %val, <8 x double> addrspace(1)* %out, align 64 + ret void +} + +; FUNC-LABEL: @test_fmin_v16f64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +; SI: V_MIN_F64 +define void @test_fmin_v16f64(<16 x double> addrspace(1)* %out, <16 x double> %a, <16 x double> %b) nounwind { + %val = call <16 x double> @llvm.minnum.v16f64(<16 x double> %a, <16 x double> %b) #0 + store <16 x double> %val, <16 x double> addrspace(1)* %out, align 128 + ret void +} + +attributes #0 = { nounwind readnone } diff --git a/test/CodeGen/R600/fminnum.ll b/test/CodeGen/R600/fminnum.ll new file mode 100644 index 00000000000..b2853f921fc --- /dev/null +++ b/test/CodeGen/R600/fminnum.ll @@ -0,0 +1,189 @@ +; RUN: llc -march=r600 -mcpu=SI < %s | FileCheck -check-prefix=SI -check-prefix=FUNC %s + +declare float @llvm.minnum.f32(float, float) #0 +declare <2 x float> @llvm.minnum.v2f32(<2 x float>, <2 x float>) #0 +declare <4 x float> @llvm.minnum.v4f32(<4 x float>, <4 x float>) #0 +declare <8 x float> @llvm.minnum.v8f32(<8 x float>, <8 x float>) #0 +declare <16 x float> @llvm.minnum.v16f32(<16 x float>, <16 x float>) #0 + +; FUNC-LABEL: @test_fmin_f32 +; SI: V_MIN_F32_e32 +define void @test_fmin_f32(float addrspace(1)* %out, float %a, float %b) nounwind { + %val = call float @llvm.minnum.f32(float %a, float %b) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @test_fmin_v2f32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +define void @test_fmin_v2f32(<2 x float> addrspace(1)* %out, <2 x float> %a, <2 x float> %b) nounwind { + %val = call <2 x float> @llvm.minnum.v2f32(<2 x float> %a, <2 x float> %b) #0 + store <2 x float> %val, <2 x float> addrspace(1)* %out, align 8 + ret void +} + +; FUNC-LABEL: @test_fmin_v4f32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +define void @test_fmin_v4f32(<4 x float> addrspace(1)* %out, <4 x float> %a, <4 x float> %b) nounwind { + %val = call <4 x float> @llvm.minnum.v4f32(<4 x float> %a, <4 x float> %b) #0 + store <4 x float> %val, <4 x float> addrspace(1)* %out, align 16 + ret void +} + +; FUNC-LABEL: @test_fmin_v8f32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +define void @test_fmin_v8f32(<8 x float> addrspace(1)* %out, <8 x float> %a, <8 x float> %b) nounwind { + %val = call <8 x float> @llvm.minnum.v8f32(<8 x float> %a, <8 x float> %b) #0 + store <8 x float> %val, <8 x float> addrspace(1)* %out, align 32 + ret void +} + +; FUNC-LABEL: @test_fmin_v16f32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +; SI: V_MIN_F32_e32 +define void @test_fmin_v16f32(<16 x float> addrspace(1)* %out, <16 x float> %a, <16 x float> %b) nounwind { + %val = call <16 x float> @llvm.minnum.v16f32(<16 x float> %a, <16 x float> %b) #0 + store <16 x float> %val, <16 x float> addrspace(1)* %out, align 64 + ret void +} + +; FUNC-LABEL: @constant_fold_fmin_f32 +; SI-NOT: V_MIN_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 1.0 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmin_f32(float addrspace(1)* %out) nounwind { + %val = call float @llvm.minnum.f32(float 1.0, float 2.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmin_f32_nan_nan +; SI-NOT: V_MIN_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0x7fc00000 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmin_f32_nan_nan(float addrspace(1)* %out) nounwind { + %val = call float @llvm.minnum.f32(float 0x7FF8000000000000, float 0x7FF8000000000000) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmin_f32_val_nan +; SI-NOT: V_MIN_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 1.0 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmin_f32_val_nan(float addrspace(1)* %out) nounwind { + %val = call float @llvm.minnum.f32(float 1.0, float 0x7FF8000000000000) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmin_f32_nan_val +; SI-NOT: V_MIN_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 1.0 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmin_f32_nan_val(float addrspace(1)* %out) nounwind { + %val = call float @llvm.minnum.f32(float 0x7FF8000000000000, float 1.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmin_f32_p0_p0 +; SI-NOT: V_MIN_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmin_f32_p0_p0(float addrspace(1)* %out) nounwind { + %val = call float @llvm.minnum.f32(float 0.0, float 0.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmin_f32_p0_n0 +; SI-NOT: V_MIN_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmin_f32_p0_n0(float addrspace(1)* %out) nounwind { + %val = call float @llvm.minnum.f32(float 0.0, float -0.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmin_f32_n0_p0 +; SI-NOT: V_MIN_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0x80000000 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmin_f32_n0_p0(float addrspace(1)* %out) nounwind { + %val = call float @llvm.minnum.f32(float -0.0, float 0.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @constant_fold_fmin_f32_n0_n0 +; SI-NOT: V_MIN_F32_e32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0x80000000 +; SI: BUFFER_STORE_DWORD [[REG]] +define void @constant_fold_fmin_f32_n0_n0(float addrspace(1)* %out) nounwind { + %val = call float @llvm.minnum.f32(float -0.0, float -0.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @fmin_var_immediate_f32 +; SI: V_MIN_F32_e64 {{v[0-9]+}}, 2.0, {{s[0-9]+}} +define void @fmin_var_immediate_f32(float addrspace(1)* %out, float %a) nounwind { + %val = call float @llvm.minnum.f32(float %a, float 2.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @fmin_immediate_var_f32 +; SI: V_MIN_F32_e64 {{v[0-9]+}}, 2.0, {{s[0-9]+}} +define void @fmin_immediate_var_f32(float addrspace(1)* %out, float %a) nounwind { + %val = call float @llvm.minnum.f32(float 2.0, float %a) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @fmin_var_literal_f32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0x42c60000 +; SI: V_MIN_F32_e32 {{v[0-9]+}}, {{s[0-9]+}}, [[REG]] +define void @fmin_var_literal_f32(float addrspace(1)* %out, float %a) nounwind { + %val = call float @llvm.minnum.f32(float %a, float 99.0) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +; FUNC-LABEL: @fmin_literal_var_f32 +; SI: V_MOV_B32_e32 [[REG:v[0-9]+]], 0x42c60000 +; SI: V_MIN_F32_e32 {{v[0-9]+}}, {{s[0-9]+}}, [[REG]] +define void @fmin_literal_var_f32(float addrspace(1)* %out, float %a) nounwind { + %val = call float @llvm.minnum.f32(float 99.0, float %a) #0 + store float %val, float addrspace(1)* %out, align 4 + ret void +} + +attributes #0 = { nounwind readnone } diff --git a/test/CodeGen/X86/fmaxnum.ll b/test/CodeGen/X86/fmaxnum.ll new file mode 100644 index 00000000000..23678c46dba --- /dev/null +++ b/test/CodeGen/X86/fmaxnum.ll @@ -0,0 +1,50 @@ +; RUN: llc -march=x86 -mtriple=i386-linux-gnu < %s | FileCheck %s + +declare float @fmaxf(float, float) +declare double @fmax(double, double) +declare x86_fp80 @fmaxl(x86_fp80, x86_fp80) +declare float @llvm.maxnum.f32(float, float) +declare double @llvm.maxnum.f64(double, double) +declare x86_fp80 @llvm.maxnum.f80(x86_fp80, x86_fp80) + +; CHECK-LABEL: @test_fmaxf +; CHECK: calll fmaxf +define float @test_fmaxf(float %x, float %y) { + %z = call float @fmaxf(float %x, float %y) readnone + ret float %z +} + +; CHECK-LABEL: @test_fmax +; CHECK: calll fmax +define double @test_fmax(double %x, double %y) { + %z = call double @fmax(double %x, double %y) readnone + ret double %z +} + +; CHECK-LABEL: @test_fmaxl +; CHECK: calll fmaxl +define x86_fp80 @test_fmaxl(x86_fp80 %x, x86_fp80 %y) { + %z = call x86_fp80 @fmaxl(x86_fp80 %x, x86_fp80 %y) readnone + ret x86_fp80 %z +} + +; CHECK-LABEL: @test_intrinsic_fmaxf +; CHECK: calll fmaxf +define float @test_intrinsic_fmaxf(float %x, float %y) { + %z = call float @llvm.maxnum.f32(float %x, float %y) readnone + ret float %z +} + +; CHECK-LABEL: @test_intrinsic_fmax +; CHECK: calll fmax +define double @test_intrinsic_fmax(double %x, double %y) { + %z = call double @llvm.maxnum.f64(double %x, double %y) readnone + ret double %z +} + +; CHECK-LABEL: @test_intrinsic_fmaxl +; CHECK: calll fmaxl +define x86_fp80 @test_intrinsic_fmaxl(x86_fp80 %x, x86_fp80 %y) { + %z = call x86_fp80 @llvm.maxnum.f80(x86_fp80 %x, x86_fp80 %y) readnone + ret x86_fp80 %z +} diff --git a/test/CodeGen/X86/fminnum.ll b/test/CodeGen/X86/fminnum.ll new file mode 100644 index 00000000000..1e33cf4696a --- /dev/null +++ b/test/CodeGen/X86/fminnum.ll @@ -0,0 +1,95 @@ +; RUN: llc -march=x86 -mtriple=i386-linux-gnu -mattr=+sse,+sse2 < %s | FileCheck %s + +declare float @fminf(float, float) +declare double @fmin(double, double) +declare x86_fp80 @fminl(x86_fp80, x86_fp80) +declare float @llvm.minnum.f32(float, float) +declare double @llvm.minnum.f64(double, double) +declare x86_fp80 @llvm.minnum.f80(x86_fp80, x86_fp80) + +declare <2 x float> @llvm.minnum.v2f32(<2 x float>, <2 x float>) +declare <4 x float> @llvm.minnum.v4f32(<4 x float>, <4 x float>) +declare <2 x double> @llvm.minnum.v2f64(<2 x double>, <2 x double>) +declare <8 x double> @llvm.minnum.v8f64(<8 x double>, <8 x double>) + +; CHECK-LABEL: @test_fminf +; CHECK: jmp fminf +define float @test_fminf(float %x, float %y) { + %z = call float @fminf(float %x, float %y) readnone + ret float %z +} + +; CHECK-LABEL: @test_fmin +; CHECK: jmp fmin +define double @test_fmin(double %x, double %y) { + %z = call double @fmin(double %x, double %y) readnone + ret double %z +} + +; CHECK-LABEL: @test_fminl +; CHECK: calll fminl +define x86_fp80 @test_fminl(x86_fp80 %x, x86_fp80 %y) { + %z = call x86_fp80 @fminl(x86_fp80 %x, x86_fp80 %y) readnone + ret x86_fp80 %z +} + +; CHECK-LABEL: @test_intrinsic_fminf +; CHECK: jmp fminf +define float @test_intrinsic_fminf(float %x, float %y) { + %z = call float @llvm.minnum.f32(float %x, float %y) readnone + ret float %z +} + +; CHECK-LABEL: @test_intrinsic_fmin +; CHECK: jmp fmin +define double @test_intrinsic_fmin(double %x, double %y) { + %z = call double @llvm.minnum.f64(double %x, double %y) readnone + ret double %z +} + +; CHECK-LABEL: @test_intrinsic_fminl +; CHECK: calll fminl +define x86_fp80 @test_intrinsic_fminl(x86_fp80 %x, x86_fp80 %y) { + %z = call x86_fp80 @llvm.minnum.f80(x86_fp80 %x, x86_fp80 %y) readnone + ret x86_fp80 %z +} + +; CHECK-LABEL: @test_intrinsic_fmin_v2f32 +; CHECK: calll fminf +; CHECK: calll fminf +define <2 x float> @test_intrinsic_fmin_v2f32(<2 x float> %x, <2 x float> %y) { + %z = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> %y) readnone + ret <2 x float> %z +} + +; CHECK-LABEL: @test_intrinsic_fmin_v4f32 +; CHECK: calll fminf +; CHECK: calll fminf +; CHECK: calll fminf +; CHECK: calll fminf +define <4 x float> @test_intrinsic_fmin_v4f32(<4 x float> %x, <4 x float> %y) { + %z = call <4 x float> @llvm.minnum.v4f32(<4 x float> %x, <4 x float> %y) readnone + ret <4 x float> %z +} + +; CHECK-LABEL: @test_intrinsic_fmin_v2f64 +; CHECK: calll fmin +; CHECK: calll fmin +define <2 x double> @test_intrinsic_fmin_v2f64(<2 x double> %x, <2 x double> %y) { + %z = call <2 x double> @llvm.minnum.v2f64(<2 x double> %x, <2 x double> %y) readnone + ret <2 x double> %z +} + +; CHECK-LABEL: @test_intrinsic_fmin_v8f64 +; CHECK: calll fmin +; CHECK: calll fmin +; CHECK: calll fmin +; CHECK: calll fmin +; CHECK: calll fmin +; CHECK: calll fmin +; CHECK: calll fmin +; CHECK: calll fmin +define <8 x double> @test_intrinsic_fmin_v8f64(<8 x double> %x, <8 x double> %y) { + %z = call <8 x double> @llvm.minnum.v8f64(<8 x double> %x, <8 x double> %y) readnone + ret <8 x double> %z +} -- 2.34.1