From 29f026d977e01fc255284a0bb90afda1435b0e6a Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Tue, 28 May 2019 20:47:44 +0000 Subject: [PATCH] [CodeGen] Add lrint/llrint builtins This patch add the ISD::LRINT and ISD::LLRINT along with new intrinsics. The changes are straightforward as for other floating-point rounding functions, with just some adjustments required to handle the return value being an interger. The idea is to optimize lrint/llrint generation for AArch64 in a subsequent patch. Current semantic is just route it to libm symbol. Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D62017 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@361875 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LangRef.rst | 74 +++++++++++++++++ include/llvm/CodeGen/ISDOpcodes.h | 2 +- include/llvm/IR/Intrinsics.td | 2 + include/llvm/IR/RuntimeLibcalls.def | 10 +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 14 ++++ .../SelectionDAG/LegalizeFloatTypes.cpp | 56 +++++++++++++ .../SelectionDAG/LegalizeIntegerTypes.cpp | 27 ++++++ lib/CodeGen/SelectionDAG/LegalizeTypes.h | 5 ++ .../SelectionDAG/SelectionDAGBuilder.cpp | 6 +- .../SelectionDAG/SelectionDAGDumper.cpp | 2 + lib/CodeGen/TargetLoweringBase.cpp | 2 + lib/IR/Verifier.cpp | 4 +- lib/Target/X86/X86ISelLowering.cpp | 2 + test/CodeGen/AArch64/llrint-conv.ll | 56 +++++++++++++ test/CodeGen/AArch64/lrint-conv.ll | 56 +++++++++++++ test/CodeGen/ARM/llrint-conv.ll | 25 ++++++ test/CodeGen/ARM/lrint-conv.ll | 25 ++++++ test/CodeGen/Mips/llrint-conv.ll | 56 +++++++++++++ test/CodeGen/Mips/lrint-conv.ll | 56 +++++++++++++ test/CodeGen/PowerPC/llrint-conv.ll | 56 +++++++++++++ test/CodeGen/PowerPC/lrint-conv.ll | 56 +++++++++++++ test/CodeGen/X86/llrint-conv-i32.ll | 60 ++++++++++++++ test/CodeGen/X86/llrint-conv.ll | 83 +++++++++++++++++++ test/CodeGen/X86/lrint-conv-i32.ll | 32 +++++++ test/CodeGen/X86/lrint-conv.ll | 83 +++++++++++++++++++ 25 files changed, 847 insertions(+), 3 deletions(-) create mode 100644 test/CodeGen/AArch64/llrint-conv.ll create mode 100644 test/CodeGen/AArch64/lrint-conv.ll create mode 100644 test/CodeGen/ARM/llrint-conv.ll create mode 100644 test/CodeGen/ARM/lrint-conv.ll create mode 100644 test/CodeGen/Mips/llrint-conv.ll create mode 100644 test/CodeGen/Mips/lrint-conv.ll create mode 100644 test/CodeGen/PowerPC/llrint-conv.ll create mode 100644 test/CodeGen/PowerPC/lrint-conv.ll create mode 100644 test/CodeGen/X86/llrint-conv-i32.ll create mode 100644 test/CodeGen/X86/llrint-conv.ll create mode 100644 test/CodeGen/X86/lrint-conv-i32.ll create mode 100644 test/CodeGen/X86/lrint-conv.ll diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 6311f6f6163..43f27da1afc 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -12449,6 +12449,80 @@ Semantics: This function returns the same values as the libm ``llround`` functions would, but without setting errno. +'``llvm.lrint.*``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +This is an overloaded intrinsic. You can use ``llvm.lrint`` on any +floating-point type. Not all targets support all types however. + +:: + + declare i32 @llvm.lrint.i32.f32(float %Val) + declare i32 @llvm.lrint.i32.f64(double %Val) + declare i32 @llvm.lrint.i32.f80(float %Val) + declare i32 @llvm.lrint.i32.f128(double %Val) + declare i32 @llvm.lrint.i32.ppcf128(double %Val) + + declare i64 @llvm.lrint.i64.f32(float %Val) + declare i64 @llvm.lrint.i64.f64(double %Val) + declare i64 @llvm.lrint.i64.f80(float %Val) + declare i64 @llvm.lrint.i64.f128(double %Val) + declare i64 @llvm.lrint.i64.ppcf128(double %Val) + +Overview: +""""""""" + +The '``llvm.lrint.*``' intrinsics returns the operand rounded to the +nearest integer. + +Arguments: +"""""""""" + +The argument is a floating-point number and return is an integer type. + +Semantics: +"""""""""" + +This function returns the same values as the libm ``lrint`` +functions would, but without setting errno. + +'``llvm.llrint.*``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +This is an overloaded intrinsic. You can use ``llvm.llrint`` on any +floating-point type. Not all targets support all types however. + +:: + + declare i64 @llvm.llrint.i64.f32(float %Val) + declare i64 @llvm.llrint.i64.f64(double %Val) + declare i64 @llvm.llrint.i64.f80(float %Val) + declare i64 @llvm.llrint.i64.f128(double %Val) + declare i64 @llvm.llrint.i64.ppcf128(double %Val) + +Overview: +""""""""" + +The '``llvm.llrint.*``' intrinsics returns the operand rounded to the +nearest integer. + +Arguments: +"""""""""" + +The argument is a floating-point number and return is an integer type. + +Semantics: +"""""""""" + +This function returns the same values as the libm ``llrint`` +functions would, but without setting errno. + Bit Manipulation Intrinsics --------------------------- diff --git a/include/llvm/CodeGen/ISDOpcodes.h b/include/llvm/CodeGen/ISDOpcodes.h index 9b765299b10..acf27dcc5fa 100644 --- a/include/llvm/CodeGen/ISDOpcodes.h +++ b/include/llvm/CodeGen/ISDOpcodes.h @@ -610,7 +610,7 @@ namespace ISD { FNEG, FABS, FSQRT, FCBRT, FSIN, FCOS, FPOWI, FPOW, FLOG, FLOG2, FLOG10, FEXP, FEXP2, FCEIL, FTRUNC, FRINT, FNEARBYINT, FROUND, FFLOOR, - LROUND, LLROUND, + LROUND, LLROUND, LRINT, LLRINT, /// FMINNUM/FMAXNUM - Perform floating-point minimum or maximum on two /// values. diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index b329d5c3eb8..06620feee3c 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -541,6 +541,8 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable] in { def int_lround : Intrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty]>; def int_llround : Intrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty]>; + def int_lrint : Intrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty]>; + def int_llrint : Intrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty]>; } def int_minnum : Intrinsic<[llvm_anyfloat_ty], diff --git a/include/llvm/IR/RuntimeLibcalls.def b/include/llvm/IR/RuntimeLibcalls.def index c617ef9a8d3..f6c74d497b1 100644 --- a/include/llvm/IR/RuntimeLibcalls.def +++ b/include/llvm/IR/RuntimeLibcalls.def @@ -264,6 +264,16 @@ HANDLE_LIBCALL(LLROUND_F64, "llround") HANDLE_LIBCALL(LLROUND_F80, "llroundl") HANDLE_LIBCALL(LLROUND_F128, "llroundl") HANDLE_LIBCALL(LLROUND_PPCF128, "llroundl") +HANDLE_LIBCALL(LRINT_F32, "lrintf") +HANDLE_LIBCALL(LRINT_F64, "lrint") +HANDLE_LIBCALL(LRINT_F80, "lrintl") +HANDLE_LIBCALL(LRINT_F128, "lrintl") +HANDLE_LIBCALL(LRINT_PPCF128, "lrintl") +HANDLE_LIBCALL(LLRINT_F32, "llrintf") +HANDLE_LIBCALL(LLRINT_F64, "llrint") +HANDLE_LIBCALL(LLRINT_F80, "llrintl") +HANDLE_LIBCALL(LLRINT_F128, "llrintl") +HANDLE_LIBCALL(LLRINT_PPCF128, "llrintl") // Conversion HANDLE_LIBCALL(FPEXT_F32_PPCF128, "__gcc_stoq") diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 19baf178f12..4f7d14ab67e 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -1003,6 +1003,8 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) { case ISD::EXTRACT_VECTOR_ELT: case ISD::LROUND: case ISD::LLROUND: + case ISD::LRINT: + case ISD::LLRINT: Action = TLI.getOperationAction(Node->getOpcode(), Node->getOperand(0).getValueType()); break; @@ -2919,6 +2921,18 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) { RTLIB::LLROUND_F128, RTLIB::LLROUND_PPCF128)); break; + case ISD::LRINT: + Results.push_back(ExpandArgFPLibCall(Node, RTLIB::LRINT_F32, + RTLIB::LRINT_F64, RTLIB::LRINT_F80, + RTLIB::LRINT_F128, + RTLIB::LRINT_PPCF128)); + break; + case ISD::LLRINT: + Results.push_back(ExpandArgFPLibCall(Node, RTLIB::LLRINT_F32, + RTLIB::LLRINT_F64, RTLIB::LLRINT_F80, + RTLIB::LLRINT_F128, + RTLIB::LLRINT_PPCF128)); + break; case ISD::VAARG: Results.push_back(DAG.expandVAArg(Node)); Results.push_back(Results[0].getValue(1)); diff --git a/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp index 1b21f7df4c8..b4849b2881e 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -774,6 +774,8 @@ bool DAGTypeLegalizer::SoftenFloatOperand(SDNode *N, unsigned OpNo) { case ISD::FP_TO_UINT: Res = SoftenFloatOp_FP_TO_XINT(N); break; case ISD::LROUND: Res = SoftenFloatOp_LROUND(N); break; case ISD::LLROUND: Res = SoftenFloatOp_LLROUND(N); break; + case ISD::LRINT: Res = SoftenFloatOp_LRINT(N); break; + case ISD::LLRINT: Res = SoftenFloatOp_LLRINT(N); break; case ISD::SELECT: Res = SoftenFloatOp_SELECT(N); break; case ISD::SELECT_CC: Res = SoftenFloatOp_SELECT_CC(N); break; case ISD::SETCC: Res = SoftenFloatOp_SETCC(N); break; @@ -1068,6 +1070,34 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_LLROUND(SDNode *N) { NVT, Op, false, SDLoc(N)).first; } +SDValue DAGTypeLegalizer::SoftenFloatOp_LRINT(SDNode *N) { + EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); + + SDValue Op = GetSoftenedFloat(N->getOperand(0)); + EVT RetVT = N->getOperand(0).getValueType().getSimpleVT().SimpleTy; + return TLI.makeLibCall(DAG, GetFPLibCall(RetVT, + RTLIB::LRINT_F32, + RTLIB::LRINT_F64, + RTLIB::LRINT_F80, + RTLIB::LRINT_F128, + RTLIB::LRINT_PPCF128), + NVT, Op, false, SDLoc(N)).first; +} + +SDValue DAGTypeLegalizer::SoftenFloatOp_LLRINT(SDNode *N) { + EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); + + SDValue Op = GetSoftenedFloat(N->getOperand(0)); + EVT RetVT = N->getOperand(0).getValueType().getSimpleVT().SimpleTy; + return TLI.makeLibCall(DAG, GetFPLibCall(RetVT, + RTLIB::LLRINT_F32, + RTLIB::LLRINT_F64, + RTLIB::LLRINT_F80, + RTLIB::LLRINT_F128, + RTLIB::LLRINT_PPCF128), + NVT, Op, false, SDLoc(N)).first; +} + //===----------------------------------------------------------------------===// // Float Result Expansion //===----------------------------------------------------------------------===// @@ -1602,6 +1632,8 @@ bool DAGTypeLegalizer::ExpandFloatOperand(SDNode *N, unsigned OpNo) { case ISD::FP_TO_UINT: Res = ExpandFloatOp_FP_TO_UINT(N); break; case ISD::LROUND: Res = ExpandFloatOp_LROUND(N); break; case ISD::LLROUND: Res = ExpandFloatOp_LLROUND(N); break; + case ISD::LRINT: Res = ExpandFloatOp_LRINT(N); break; + case ISD::LLRINT: Res = ExpandFloatOp_LLRINT(N); break; case ISD::SELECT_CC: Res = ExpandFloatOp_SELECT_CC(N); break; case ISD::SETCC: Res = ExpandFloatOp_SETCC(N); break; case ISD::STORE: Res = ExpandFloatOp_STORE(cast(N), @@ -1796,6 +1828,30 @@ SDValue DAGTypeLegalizer::ExpandFloatOp_LLROUND(SDNode *N) { RVT, N->getOperand(0), false, SDLoc(N)).first; } +SDValue DAGTypeLegalizer::ExpandFloatOp_LRINT(SDNode *N) { + EVT RVT = N->getValueType(0); + EVT RetVT = N->getOperand(0).getValueType().getSimpleVT().SimpleTy; + return TLI.makeLibCall(DAG, GetFPLibCall(RetVT, + RTLIB::LRINT_F32, + RTLIB::LRINT_F64, + RTLIB::LRINT_F80, + RTLIB::LRINT_F128, + RTLIB::LRINT_PPCF128), + RVT, N->getOperand(0), false, SDLoc(N)).first; +} + +SDValue DAGTypeLegalizer::ExpandFloatOp_LLRINT(SDNode *N) { + EVT RVT = N->getValueType(0); + EVT RetVT = N->getOperand(0).getValueType().getSimpleVT().SimpleTy; + return TLI.makeLibCall(DAG, GetFPLibCall(RetVT, + RTLIB::LLRINT_F32, + RTLIB::LLRINT_F64, + RTLIB::LLRINT_F80, + RTLIB::LLRINT_F128, + RTLIB::LLRINT_PPCF128), + RVT, N->getOperand(0), false, SDLoc(N)).first; +} + //===----------------------------------------------------------------------===// // Float Operand Promotion //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index 357654fb1af..56bc237258f 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -1624,6 +1624,7 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) { case ISD::FP_TO_SINT: ExpandIntRes_FP_TO_SINT(N, Lo, Hi); break; case ISD::FP_TO_UINT: ExpandIntRes_FP_TO_UINT(N, Lo, Hi); break; case ISD::LLROUND: ExpandIntRes_LLROUND(N, Lo, Hi); break; + case ISD::LLRINT: ExpandIntRes_LLRINT(N, Lo, Hi); break; case ISD::LOAD: ExpandIntRes_LOAD(cast(N), Lo, Hi); break; case ISD::MUL: ExpandIntRes_MUL(N, Lo, Hi); break; case ISD::READCYCLECOUNTER: ExpandIntRes_READCYCLECOUNTER(N, Lo, Hi); break; @@ -2517,6 +2518,32 @@ void DAGTypeLegalizer::ExpandIntRes_LLROUND(SDNode *N, SDValue &Lo, Lo, Hi); } +void DAGTypeLegalizer::ExpandIntRes_LLRINT(SDNode *N, SDValue &Lo, + SDValue &Hi) { + RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; + EVT VT = N->getOperand(0).getValueType().getSimpleVT().SimpleTy; + if (VT == MVT::f32) + LC = RTLIB::LLRINT_F32; + else if (VT == MVT::f64) + LC = RTLIB::LLRINT_F64; + else if (VT == MVT::f80) + LC = RTLIB::LLRINT_F80; + else if (VT == MVT::f128) + LC = RTLIB::LLRINT_F128; + else if (VT == MVT::ppcf128) + LC = RTLIB::LLRINT_PPCF128; + assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unexpected llrint input type!"); + + SDValue Op = N->getOperand(0); + if (getTypeAction(Op.getValueType()) == TargetLowering::TypePromoteFloat) + Op = GetPromotedFloat(Op); + + SDLoc dl(N); + EVT RetVT = N->getValueType(0); + SplitInteger(TLI.makeLibCall(DAG, LC, RetVT, Op, true/*irrelevant*/, dl).first, + Lo, Hi); +} + void DAGTypeLegalizer::ExpandIntRes_LOAD(LoadSDNode *N, SDValue &Lo, SDValue &Hi) { if (ISD::isNormalLoad(N)) { diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index 590b5c7e5a0..a0e7c8a89c1 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -419,6 +419,7 @@ private: void ExpandIntRes_FP_TO_SINT (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_FP_TO_UINT (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_LLROUND (SDNode *N, SDValue &Lo, SDValue &Hi); + void ExpandIntRes_LLRINT (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_Logical (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_ADDSUB (SDNode *N, SDValue &Lo, SDValue &Hi); @@ -556,6 +557,8 @@ private: SDValue SoftenFloatOp_FP_TO_XINT(SDNode *N); SDValue SoftenFloatOp_LROUND(SDNode *N); SDValue SoftenFloatOp_LLROUND(SDNode *N); + SDValue SoftenFloatOp_LRINT(SDNode *N); + SDValue SoftenFloatOp_LLRINT(SDNode *N); SDValue SoftenFloatOp_SELECT(SDNode *N); SDValue SoftenFloatOp_SELECT_CC(SDNode *N); SDValue SoftenFloatOp_SETCC(SDNode *N); @@ -617,6 +620,8 @@ private: SDValue ExpandFloatOp_FP_TO_UINT(SDNode *N); SDValue ExpandFloatOp_LROUND(SDNode *N); SDValue ExpandFloatOp_LLROUND(SDNode *N); + SDValue ExpandFloatOp_LRINT(SDNode *N); + SDValue ExpandFloatOp_LLRINT(SDNode *N); SDValue ExpandFloatOp_SELECT_CC(SDNode *N); SDValue ExpandFloatOp_SETCC(SDNode *N); SDValue ExpandFloatOp_STORE(SDNode *N, unsigned OpNo); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index a5274877ece..fe857f73b25 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6029,12 +6029,16 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, return; } case Intrinsic::lround: - case Intrinsic::llround: { + case Intrinsic::llround: + case Intrinsic::lrint: + case Intrinsic::llrint: { unsigned Opcode; switch (Intrinsic) { default: llvm_unreachable("Impossible intrinsic"); // Can't reach here. case Intrinsic::lround: Opcode = ISD::LROUND; break; case Intrinsic::llround: Opcode = ISD::LLROUND; break; + case Intrinsic::lrint: Opcode = ISD::LRINT; break; + case Intrinsic::llrint: Opcode = ISD::LLRINT; break; } EVT RetVT = TLI.getValueType(DAG.getDataLayout(), I.getType()); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp index 28416336578..da3049881d3 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -332,6 +332,8 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::FP_TO_FP16: return "fp_to_fp16"; case ISD::LROUND: return "lround"; case ISD::LLROUND: return "llround"; + case ISD::LRINT: return "lrint"; + case ISD::LLRINT: return "llrint"; // Control flow instructions case ISD::BR: return "br"; diff --git a/lib/CodeGen/TargetLoweringBase.cpp b/lib/CodeGen/TargetLoweringBase.cpp index 32f97f7e2aa..888d420a441 100644 --- a/lib/CodeGen/TargetLoweringBase.cpp +++ b/lib/CodeGen/TargetLoweringBase.cpp @@ -713,6 +713,8 @@ void TargetLoweringBase::initActions() { setOperationAction(ISD::FROUND, VT, Expand); setOperationAction(ISD::LROUND, VT, Expand); setOperationAction(ISD::LLROUND, VT, Expand); + setOperationAction(ISD::LRINT, VT, Expand); + setOperationAction(ISD::LLRINT, VT, Expand); } // Default ISD::TRAP to expand (which turns it into abort). diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index fc8d210e67a..878a0081e19 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -4622,7 +4622,9 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { break; } case Intrinsic::lround: - case Intrinsic::llround: { + case Intrinsic::llround: + case Intrinsic::lrint: + case Intrinsic::llrint: { Type *ValTy = Call.getArgOperand(0)->getType(); Type *ResultTy = Call.getType(); Assert(!ValTy->isVectorTy() && !ResultTy->isVectorTy(), diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 7b4ce08b578..e1c0c8a6bd5 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -674,6 +674,8 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM, setOperationAction(ISD::FMA, MVT::f80, Expand); setOperationAction(ISD::LROUND, MVT::f80, Expand); setOperationAction(ISD::LLROUND, MVT::f80, Expand); + setOperationAction(ISD::LRINT, MVT::f80, Expand); + setOperationAction(ISD::LLRINT, MVT::f80, Expand); } // Always use a library call for pow. diff --git a/test/CodeGen/AArch64/llrint-conv.ll b/test/CodeGen/AArch64/llrint-conv.ll new file mode 100644 index 00000000000..365f6b5456d --- /dev/null +++ b/test/CodeGen/AArch64/llrint-conv.ll @@ -0,0 +1,56 @@ +; RUN: llc < %s -mtriple=aarch64 -mattr=+neon | FileCheck %s + +; CHECK-LABEL: testmsws: +; CHECK: bl llrintf +define i32 @testmsws(float %x) { +entry: + %0 = tail call i64 @llvm.llrint.f32(float %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsxs: +; CHECK: b llrintf +define i64 @testmsxs(float %x) { +entry: + %0 = tail call i64 @llvm.llrint.f32(float %x) + ret i64 %0 +} + +; CHECK-LABEL: testmswd: +; CHECK: bl llrint +define i32 @testmswd(double %x) { +entry: + %0 = tail call i64 @llvm.llrint.f64(double %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsxd: +; CHECK: b llrint +define i64 @testmsxd(double %x) { +entry: + %0 = tail call i64 @llvm.llrint.f64(double %x) + ret i64 %0 +} + +; CHECK-LABEL: testmswl: +; CHECK: bl llrintl +define i32 @testmswl(fp128 %x) { +entry: + %0 = tail call i64 @llvm.llrint.f128(fp128 %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsll: +; CHECK: b llrintl +define i64 @testmsll(fp128 %x) { +entry: + %0 = tail call i64 @llvm.llrint.f128(fp128 %x) + ret i64 %0 +} + +declare i64 @llvm.llrint.f32(float) nounwind readnone +declare i64 @llvm.llrint.f64(double) nounwind readnone +declare i64 @llvm.llrint.f128(fp128) nounwind readnone diff --git a/test/CodeGen/AArch64/lrint-conv.ll b/test/CodeGen/AArch64/lrint-conv.ll new file mode 100644 index 00000000000..a652de9cb3e --- /dev/null +++ b/test/CodeGen/AArch64/lrint-conv.ll @@ -0,0 +1,56 @@ +; RUN: llc < %s -mtriple=aarch64 -mattr=+neon | FileCheck %s + +; CHECK-LABEL: testmsws: +; CHECK: bl lrintf +define i32 @testmsws(float %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.f32(float %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsxs: +; CHECK: b lrintf +define i64 @testmsxs(float %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.f32(float %x) + ret i64 %0 +} + +; CHECK-LABEL: testmswd: +; CHECK: bl lrint +define i32 @testmswd(double %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.f64(double %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsxd: +; CHECK: b lrint +define i64 @testmsxd(double %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.f64(double %x) + ret i64 %0 +} + +; CHECK-LABEL: testmswl: +; CHECK: bl lrintl +define dso_local i32 @testmswl(fp128 %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.f128(fp128 %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsll: +; CHECK: b lrintl +define dso_local i64 @testmsll(fp128 %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.f128(fp128 %x) + ret i64 %0 +} + +declare i64 @llvm.lrint.i64.f32(float) nounwind readnone +declare i64 @llvm.lrint.i64.f64(double) nounwind readnone +declare i64 @llvm.lrint.i64.f128(fp128) nounwind readnone diff --git a/test/CodeGen/ARM/llrint-conv.ll b/test/CodeGen/ARM/llrint-conv.ll new file mode 100644 index 00000000000..017955bb43a --- /dev/null +++ b/test/CodeGen/ARM/llrint-conv.ll @@ -0,0 +1,25 @@ +; RUN: llc < %s -mtriple=arm-eabi -float-abi=soft | FileCheck %s --check-prefix=SOFTFP +; RUN: llc < %s -mtriple=arm-eabi -float-abi=hard | FileCheck %s --check-prefix=HARDFP + +; SOFTFP-LABEL: testmsxs_builtin: +; SOFTFP: bl llrintf +; HARDFP-LABEL: testmsxs_builtin: +; HARDFP: bl llrintf +define i64 @testmsxs_builtin(float %x) { +entry: + %0 = tail call i64 @llvm.llrint.f32(float %x) + ret i64 %0 +} + +; SOFTFP-LABEL: testmsxd_builtin: +; SOFTFP: bl llrint +; HARDFP-LABEL: testmsxd_builtin: +; HARDFP: bl llrint +define i64 @testmsxd_builtin(double %x) { +entry: + %0 = tail call i64 @llvm.llrint.f64(double %x) + ret i64 %0 +} + +declare i64 @llvm.llrint.f32(float) nounwind readnone +declare i64 @llvm.llrint.f64(double) nounwind readnone diff --git a/test/CodeGen/ARM/lrint-conv.ll b/test/CodeGen/ARM/lrint-conv.ll new file mode 100644 index 00000000000..192da565c12 --- /dev/null +++ b/test/CodeGen/ARM/lrint-conv.ll @@ -0,0 +1,25 @@ +; RUN: llc < %s -mtriple=arm-eabi -float-abi=soft | FileCheck %s --check-prefix=SOFTFP +; RUN: llc < %s -mtriple=arm-eabi -float-abi=hard | FileCheck %s --check-prefix=HARDFP + +; SOFTFP-LABEL: testmsws_builtin: +; SOFTFP: bl lrintf +; HARDFP-LABEL: testmsws_builtin: +; HARDFP: bl lrintf +define i32 @testmsws_builtin(float %x) { +entry: + %0 = tail call i32 @llvm.lrint.i32.f32(float %x) + ret i32 %0 +} + +; SOFTFP-LABEL: testmswd_builtin: +; SOFTFP: bl lrint +; HARDFP-LABEL: testmswd_builtin: +; HARDFP: bl lrint +define i32 @testmswd_builtin(double %x) { +entry: + %0 = tail call i32 @llvm.lrint.i32.f64(double %x) + ret i32 %0 +} + +declare i32 @llvm.lrint.i32.f32(float) nounwind readnone +declare i32 @llvm.lrint.i32.f64(double) nounwind readnone diff --git a/test/CodeGen/Mips/llrint-conv.ll b/test/CodeGen/Mips/llrint-conv.ll new file mode 100644 index 00000000000..dcb4e5657e8 --- /dev/null +++ b/test/CodeGen/Mips/llrint-conv.ll @@ -0,0 +1,56 @@ +; RUN: llc < %s -mtriple=mips64el -mattr=+soft-float | FileCheck %s + +define signext i32 @testmsws(float %x) { +; CHECK-LABEL: testmsws: +; CHECK: jal llrintf +entry: + %0 = tail call i64 @llvm.llrint.f32(float %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define i64 @testmsxs(float %x) { +; CHECK-LABEL: testmsxs: +; CHECK: jal llrintf +entry: + %0 = tail call i64 @llvm.llrint.f32(float %x) + ret i64 %0 +} + +define signext i32 @testmswd(double %x) { +; CHECK-LABEL: testmswd: +; CHECK: jal llrint +entry: + %0 = tail call i64 @llvm.llrint.f64(double %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define i64 @testmsxd(double %x) { +; CHECK-LABEL: testmsxd: +; CHECK: jal llrint +entry: + %0 = tail call i64 @llvm.llrint.f64(double %x) + ret i64 %0 +} + +define signext i32 @testmswl(fp128 %x) { +; CHECK-LABEL: testmswl: +; CHECK: jal llrintl +entry: + %0 = tail call i64 @llvm.llrint.f128(fp128 %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define i64 @testmsll(fp128 %x) { +; CHECK-LABEL: testmsll: +; CHECK: jal llrintl +entry: + %0 = tail call i64 @llvm.llrint.f128(fp128 %x) + ret i64 %0 +} + +declare i64 @llvm.llrint.f32(float) nounwind readnone +declare i64 @llvm.llrint.f64(double) nounwind readnone +declare i64 @llvm.llrint.f128(fp128) nounwind readnone diff --git a/test/CodeGen/Mips/lrint-conv.ll b/test/CodeGen/Mips/lrint-conv.ll new file mode 100644 index 00000000000..bd3f7b3babe --- /dev/null +++ b/test/CodeGen/Mips/lrint-conv.ll @@ -0,0 +1,56 @@ +; RUN: llc < %s -mtriple=mips64el -mattr=+soft-float | FileCheck %s + +define signext i32 @testmsws(float %x) { +; CHECK-LABEL: testmsws: +; CHECK: jal lrintf +entry: + %0 = tail call i64 @llvm.lrint.i64.f32(float %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define i64 @testmsxs(float %x) { +; CHECK-LABEL: testmsxs: +; CHECK: jal lrintf +entry: + %0 = tail call i64 @llvm.lrint.i64.f32(float %x) + ret i64 %0 +} + +define signext i32 @testmswd(double %x) { +; CHECK-LABEL: testmswd: +; CHECK: jal lrint +entry: + %0 = tail call i64 @llvm.lrint.i64.f64(double %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define i64 @testmsxd(double %x) { +; CHECK-LABEL: testmsxd: +; CHECK: jal lrint +entry: + %0 = tail call i64 @llvm.lrint.i64.f64(double %x) + ret i64 %0 +} + +define signext i32 @testmswl(fp128 %x) { +; CHECK-LABEL: testmswl: +; CHECK: jal lrintl +entry: + %0 = tail call i64 @llvm.lrint.i64.f128(fp128 %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define signext i64 @testmsll(fp128 %x) { +; CHECK-LABEL: testmsll: +; CHECK: jal lrintl +entry: + %0 = tail call i64 @llvm.lrint.i64.f128(fp128 %x) + ret i64 %0 +} + +declare i64 @llvm.lrint.i64.f32(float) nounwind readnone +declare i64 @llvm.lrint.i64.f64(double) nounwind readnone +declare i64 @llvm.lrint.i64.f128(fp128) nounwind readnone diff --git a/test/CodeGen/PowerPC/llrint-conv.ll b/test/CodeGen/PowerPC/llrint-conv.ll new file mode 100644 index 00000000000..daadf85b408 --- /dev/null +++ b/test/CodeGen/PowerPC/llrint-conv.ll @@ -0,0 +1,56 @@ +; RUN: llc < %s -mtriple=powerpc64le | FileCheck %s + +; CHECK-LABEL: testmsws: +; CHECK: bl llrintf +define signext i32 @testmsws(float %x) { +entry: + %0 = tail call i64 @llvm.llrint.f32(float %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsxs: +; CHECK: bl llrintf +define i64 @testmsxs(float %x) { +entry: + %0 = tail call i64 @llvm.llrint.f32(float %x) + ret i64 %0 +} + +; CHECK-LABEL: testmswd: +; CHECK: bl llrint +define signext i32 @testmswd(double %x) { +entry: + %0 = tail call i64 @llvm.llrint.f64(double %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsxd: +; CHECK: bl llrint +define i64 @testmsxd(double %x) { +entry: + %0 = tail call i64 @llvm.llrint.f64(double %x) + ret i64 %0 +} + +; CHECK-LABEL: testmswl: +; CHECK: bl llrintl +define signext i32 @testmswl(ppc_fp128 %x) { +entry: + %0 = tail call i64 @llvm.llrint.ppcf128(ppc_fp128 %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsll: +; CHECK: bl llrintl +define i64 @testmsll(ppc_fp128 %x) { +entry: + %0 = tail call i64 @llvm.llrint.ppcf128(ppc_fp128 %x) + ret i64 %0 +} + +declare i64 @llvm.llrint.f32(float) nounwind readnone +declare i64 @llvm.llrint.f64(double) nounwind readnone +declare i64 @llvm.llrint.ppcf128(ppc_fp128) nounwind readnone diff --git a/test/CodeGen/PowerPC/lrint-conv.ll b/test/CodeGen/PowerPC/lrint-conv.ll new file mode 100644 index 00000000000..adfc9944973 --- /dev/null +++ b/test/CodeGen/PowerPC/lrint-conv.ll @@ -0,0 +1,56 @@ +; RUN: llc < %s -mtriple=powerpc64le | FileCheck %s + +; CHECK-LABEL: testmsws: +; CHECK: bl lrintf +define signext i32 @testmsws(float %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.f32(float %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsxs: +; CHECK: bl lrintf +define i64 @testmsxs(float %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.f32(float %x) + ret i64 %0 +} + +; CHECK-LABEL: testmswd: +; CHECK: bl lrint +define signext i32 @testmswd(double %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.f64(double %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsxd: +; CHECK: bl lrint +define i64 @testmsxd(double %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.f64(double %x) + ret i64 %0 +} + +; CHECK-LABEL: testmswl: +; CHECK: bl lrintl +define signext i32 @testmswl(ppc_fp128 %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.ppcf128(ppc_fp128 %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: testmsll: +; CHECK: bl lrintl +define i64 @testmsll(ppc_fp128 %x) { +entry: + %0 = tail call i64 @llvm.lrint.i64.ppcf128(ppc_fp128 %x) + ret i64 %0 +} + +declare i64 @llvm.lrint.i64.f32(float) nounwind readnone +declare i64 @llvm.lrint.i64.f64(double) nounwind readnone +declare i64 @llvm.lrint.i64.ppcf128(ppc_fp128) nounwind readnone diff --git a/test/CodeGen/X86/llrint-conv-i32.ll b/test/CodeGen/X86/llrint-conv-i32.ll new file mode 100644 index 00000000000..de05af14fa1 --- /dev/null +++ b/test/CodeGen/X86/llrint-conv-i32.ll @@ -0,0 +1,60 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=i686-unknown | FileCheck %s +; RUN: llc < %s -mtriple=i686-unknown -mattr=sse2 | FileCheck %s --check-prefix=SSE2 + +define i64 @testmsxs_builtin(float %x) { +; CHECK-LABEL: testmsxs_builtin: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushl %eax +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: flds {{[0-9]+}}(%esp) +; CHECK-NEXT: fstps (%esp) +; CHECK-NEXT: calll llrintf +; CHECK-NEXT: popl %ecx +; CHECK-NEXT: .cfi_def_cfa_offset 4 +; CHECK-NEXT: retl +; +; SSE2-LABEL: testmsxs_builtin: +; SSE2: # %bb.0: # %entry +; SSE2-NEXT: pushl %eax +; SSE2-NEXT: .cfi_def_cfa_offset 8 +; SSE2-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; SSE2-NEXT: movss %xmm0, (%esp) +; SSE2-NEXT: calll llrintf +; SSE2-NEXT: popl %ecx +; SSE2-NEXT: .cfi_def_cfa_offset 4 +; SSE2-NEXT: retl +entry: + %0 = tail call i64 @llvm.llrint.f32(float %x) + ret i64 %0 +} + +define i64 @testmsxd_builtin(double %x) { +; CHECK-LABEL: testmsxd_builtin: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: subl $8, %esp +; CHECK-NEXT: .cfi_def_cfa_offset 12 +; CHECK-NEXT: fldl {{[0-9]+}}(%esp) +; CHECK-NEXT: fstpl (%esp) +; CHECK-NEXT: calll llrint +; CHECK-NEXT: addl $8, %esp +; CHECK-NEXT: .cfi_def_cfa_offset 4 +; CHECK-NEXT: retl +; +; SSE2-LABEL: testmsxd_builtin: +; SSE2: # %bb.0: # %entry +; SSE2-NEXT: subl $8, %esp +; SSE2-NEXT: .cfi_def_cfa_offset 12 +; SSE2-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; SSE2-NEXT: movsd %xmm0, (%esp) +; SSE2-NEXT: calll llrint +; SSE2-NEXT: addl $8, %esp +; SSE2-NEXT: .cfi_def_cfa_offset 4 +; SSE2-NEXT: retl +entry: + %0 = tail call i64 @llvm.llrint.f64(double %x) + ret i64 %0 +} + +declare i64 @llvm.llrint.f32(float) nounwind readnone +declare i64 @llvm.llrint.f64(double) nounwind readnone diff --git a/test/CodeGen/X86/llrint-conv.ll b/test/CodeGen/X86/llrint-conv.ll new file mode 100644 index 00000000000..bcdea81b023 --- /dev/null +++ b/test/CodeGen/X86/llrint-conv.ll @@ -0,0 +1,83 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s + +define i32 @testmsws(float %x) { +; CHECK-LABEL: testmsws: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq llrintf +; CHECK-NEXT: # kill: def $eax killed $eax killed $rax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %0 = tail call i64 @llvm.llrint.f32(float %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define i64 @testmsxs(float %x) { +; CHECK-LABEL: testmsxs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: jmp llrintf # TAILCALL +entry: + %0 = tail call i64 @llvm.llrint.f32(float %x) + ret i64 %0 +} + +define i32 @testmswd(double %x) { +; CHECK-LABEL: testmswd: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq llrint +; CHECK-NEXT: # kill: def $eax killed $eax killed $rax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %0 = tail call i64 @llvm.llrint.f64(double %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define i64 @testmsxd(double %x) { +; CHECK-LABEL: testmsxd: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: jmp llrint # TAILCALL +entry: + %0 = tail call i64 @llvm.llrint.f64(double %x) + ret i64 %0 +} + +define dso_local i32 @testmswl(x86_fp80 %x) { +; CHECK-LABEL: testmswl: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: subq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fstpt (%rsp) +; CHECK-NEXT: callq llrintl +; CHECK-NEXT: # kill: def $eax killed $eax killed $rax +; CHECK-NEXT: addq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %0 = tail call i64 @llvm.llrint.f80(x86_fp80 %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define dso_local i64 @testmsll(x86_fp80 %x) { +; CHECK-LABEL: testmsll: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: jmp llrintl # TAILCALL +entry: + %0 = tail call i64 @llvm.llrint.f80(x86_fp80 %x) + ret i64 %0 +} + +declare i64 @llvm.llrint.f32(float) nounwind readnone +declare i64 @llvm.llrint.f64(double) nounwind readnone +declare i64 @llvm.llrint.f80(x86_fp80) nounwind readnone diff --git a/test/CodeGen/X86/lrint-conv-i32.ll b/test/CodeGen/X86/lrint-conv-i32.ll new file mode 100644 index 00000000000..7bc8c36741f --- /dev/null +++ b/test/CodeGen/X86/lrint-conv-i32.ll @@ -0,0 +1,32 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=i686-unknown | FileCheck %s +; RUN: llc < %s -mtriple=i686-unknown -mattr=sse2 | FileCheck %s --check-prefix=SSE2 + +define i32 @testmsws_builtin(float %x) { +; CHECK-LABEL: testmsws_builtin: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: jmp lrintf # TAILCALL +; +; SSE2-LABEL: testmsws_builtin: +; SSE2: # %bb.0: # %entry +; SSE2-NEXT: jmp lrintf # TAILCALL +entry: + %0 = tail call i32 @llvm.lrint.i32.f32(float %x) + ret i32 %0 +} + +define i32 @testmswd_builtin(double %x) { +; CHECK-LABEL: testmswd_builtin: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: jmp lrint # TAILCALL +; +; SSE2-LABEL: testmswd_builtin: +; SSE2: # %bb.0: # %entry +; SSE2-NEXT: jmp lrint # TAILCALL +entry: + %0 = tail call i32 @llvm.lrint.i32.f64(double %x) + ret i32 %0 +} + +declare i32 @llvm.lrint.i32.f32(float) nounwind readnone +declare i32 @llvm.lrint.i32.f64(double) nounwind readnone diff --git a/test/CodeGen/X86/lrint-conv.ll b/test/CodeGen/X86/lrint-conv.ll new file mode 100644 index 00000000000..a34c31e889d --- /dev/null +++ b/test/CodeGen/X86/lrint-conv.ll @@ -0,0 +1,83 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s + +define i32 @testmsws(float %x) { +; CHECK-LABEL: testmsws: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq lrintf +; CHECK-NEXT: # kill: def $eax killed $eax killed $rax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %0 = tail call i64 @llvm.lrint.i64.f32(float %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define i64 @testmsxs(float %x) { +; CHECK-LABEL: testmsxs: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: jmp lrintf # TAILCALL +entry: + %0 = tail call i64 @llvm.lrint.i64.f32(float %x) + ret i64 %0 +} + +define i32 @testmswd(double %x) { +; CHECK-LABEL: testmswd: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq lrint +; CHECK-NEXT: # kill: def $eax killed $eax killed $rax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %0 = tail call i64 @llvm.lrint.i64.f64(double %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define i64 @testmsxd(double %x) { +; CHECK-LABEL: testmsxd: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: jmp lrint # TAILCALL +entry: + %0 = tail call i64 @llvm.lrint.i64.f64(double %x) + ret i64 %0 +} + +define dso_local i32 @testmswl(x86_fp80 %x) { +; CHECK-LABEL: testmswl: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: subq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fstpt (%rsp) +; CHECK-NEXT: callq lrintl +; CHECK-NEXT: # kill: def $eax killed $eax killed $rax +; CHECK-NEXT: addq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq +entry: + %0 = tail call i64 @llvm.lrint.i64.f80(x86_fp80 %x) + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +define dso_local i64 @testmsll(x86_fp80 %x) { +; CHECK-LABEL: testmsll: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: jmp lrintl # TAILCALL +entry: + %0 = tail call i64 @llvm.lrint.i64.f80(x86_fp80 %x) + ret i64 %0 +} + +declare i64 @llvm.lrint.i64.f32(float) nounwind readnone +declare i64 @llvm.lrint.i64.f64(double) nounwind readnone +declare i64 @llvm.lrint.i64.f80(x86_fp80) nounwind readnone