Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -12449,6 +12449,80 @@ 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 --------------------------- Index: llvm/trunk/include/llvm/CodeGen/ISDOpcodes.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/ISDOpcodes.h +++ llvm/trunk/include/llvm/CodeGen/ISDOpcodes.h @@ -610,7 +610,7 @@ 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. Index: llvm/trunk/include/llvm/IR/Intrinsics.td =================================================================== --- llvm/trunk/include/llvm/IR/Intrinsics.td +++ llvm/trunk/include/llvm/IR/Intrinsics.td @@ -541,6 +541,8 @@ 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], Index: llvm/trunk/include/llvm/IR/RuntimeLibcalls.def =================================================================== --- llvm/trunk/include/llvm/IR/RuntimeLibcalls.def +++ llvm/trunk/include/llvm/IR/RuntimeLibcalls.def @@ -264,6 +264,16 @@ 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") Index: llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -1003,6 +1003,8 @@ 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 @@ 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)); Index: llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -774,6 +774,8 @@ 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 @@ 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 @@ 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 @@ 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 //===----------------------------------------------------------------------===// Index: llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -1624,6 +1624,7 @@ 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 @@ 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)) { Index: llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeTypes.h =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -419,6 +419,7 @@ 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 @@ 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 @@ 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); Index: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -6029,12 +6029,16 @@ 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()); Index: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -332,6 +332,8 @@ 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"; Index: llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp +++ llvm/trunk/lib/CodeGen/TargetLoweringBase.cpp @@ -713,6 +713,8 @@ 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). Index: llvm/trunk/lib/IR/Verifier.cpp =================================================================== --- llvm/trunk/lib/IR/Verifier.cpp +++ llvm/trunk/lib/IR/Verifier.cpp @@ -4622,7 +4622,9 @@ 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(), Index: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp @@ -674,6 +674,8 @@ 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. Index: llvm/trunk/test/CodeGen/AArch64/llrint-conv.ll =================================================================== --- llvm/trunk/test/CodeGen/AArch64/llrint-conv.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/AArch64/lrint-conv.ll =================================================================== --- llvm/trunk/test/CodeGen/AArch64/lrint-conv.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/ARM/llrint-conv.ll =================================================================== --- llvm/trunk/test/CodeGen/ARM/llrint-conv.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/ARM/lrint-conv.ll =================================================================== --- llvm/trunk/test/CodeGen/ARM/lrint-conv.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/Mips/llrint-conv.ll =================================================================== --- llvm/trunk/test/CodeGen/Mips/llrint-conv.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/Mips/lrint-conv.ll =================================================================== --- llvm/trunk/test/CodeGen/Mips/lrint-conv.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/PowerPC/llrint-conv.ll =================================================================== --- llvm/trunk/test/CodeGen/PowerPC/llrint-conv.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/PowerPC/lrint-conv.ll =================================================================== --- llvm/trunk/test/CodeGen/PowerPC/lrint-conv.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/X86/llrint-conv-i32.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/llrint-conv-i32.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/X86/llrint-conv.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/llrint-conv.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/X86/lrint-conv-i32.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/lrint-conv-i32.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/X86/lrint-conv.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/lrint-conv.ll +++ llvm/trunk/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