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
---------------------------
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.
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],
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")
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;
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));
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;
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
//===----------------------------------------------------------------------===//
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<StoreSDNode>(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
//===----------------------------------------------------------------------===//
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<LoadSDNode>(N), Lo, Hi); break;
case ISD::MUL: ExpandIntRes_MUL(N, Lo, Hi); break;
case ISD::READCYCLECOUNTER: ExpandIntRes_READCYCLECOUNTER(N, Lo, Hi); break;
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)) {
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);
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);
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);
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());
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";
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).
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(),
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.
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; 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