Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -13081,6 +13081,119 @@ %a = load i16, i16* @x, align 2 %res = call float @llvm.convert.from.fp16(i16 %a) +Saturating floating-point to integer conversions +------------------------------------------------ + +The ``fptoui`` and ``fptosi`` instructions return a +:ref:`poison value ` if the rounded-towards-zero value is not +representable by the result type. These intrinsics provide an alternative +conversion, which will saturate towards the smallest and largest representable +integer values instead. + +'``llvm.fptoui.set.*``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +This is an overloaded intrinsic. You can use ``llvm.fptoui.sat`` on any +floating-point argument type and any integer result type, or vectors thereof. +Not all targets may support all types, however. + +:: + + declare i32 @llvm.fptoui.sat.f32.i32(float %f) + declare i19 @llvm.fptoui.sat.f64.i19(double %f) + declare <4 x i100> @llvm.fptoui.sat.v4f128.v4i100(<4 x fp128> %f) + +Overview: +""""""""" + +This intrinsic converts the argument into an unsigned integer using saturating +semantics. + +Arguments: +"""""""""" + +The argument may be any floating-point or vector of floating-point type. The +return value may be any integer or vector of integer type. The number of vector +elements in argument and return must be same. + +Semantics: +"""""""""" + +The conversion to integer is performed subject to the following rules: + +- If the argument is any NaN, zero is returned. +- If the argument is smaller than zero, zero is returned. +- If the argument is larger than the largest representable integer of the + result type (this includes positive infinity), the largest representable + integer is returned. +- Otherwise, the result of rounding the argument towards zero is returned. + +Example: +"""""""" + +.. code-block:: text + + %a = call i8 @llvm.fptoui.sat.f32.i8(float 123.9) ; yields i8: 123 + %b = call i8 @llvm.fptoui.sat.f32.i8(float -5.7) ; yields i8: 0 + %c = call i8 @llvm.fptoui.sat.f32.i8(float 377.0) ; yields i8: 255 + %d = call i8 @llvm.fptoui.sat.f32.i8(float 0xFFF8000000000000) ; yields i8: 0 + +'``llvm.fptosi.sat.*``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +This is an overloaded intrinsic. You can use ``llvm.fptosi.sat`` on any +floating-point argument type and any integer result type, or vectors thereof. +Not all targets may support all types, however. + +:: + + declare i32 @llvm.fptosi.sat.f32.i32(float %f) + declare i19 @llvm.fptosi.sat.f64.i19(double %f) + declare <4 x i100> @llvm.fptosi.sat.v4f128.v4i100(<4 x fp128> %f) + +Overview: +""""""""" + +This intrinsic converts the argument into a signed integer using saturating +semantics. + +Arguments: +"""""""""" + +The argument may be any floating-point or vector of floating-point type. The +return value may be any integer or vector of integer type. The number of vector +elements in argument and return must be same. + +Semantics: +"""""""""" + +The conversion to integer is performed subject to the following rules: + +- If the argument is any NaN, zero is returned. +- If the argument is smaller than the smallest representable integer of the + result type (this includes negative infinity), the smallest representable + integer is returned. +- If the argument is larger than the largest representable integer of the + result type (this includes positive infinity), the largest representable + integer is returned. +- Otherwise, the result of rounding the argument towards zero is returned. + +Example: +"""""""" + +.. code-block:: text + + %a = call i8 @llvm.fptosi.sat.f32.i8(float 23.9) ; yields i8: 23 + %b = call i8 @llvm.fptosi.sat.f32.i8(float -130.8) ; yields i8: -128 + %c = call i8 @llvm.fptosi.sat.f32.i8(float 999.0) ; yields i8: 127 + %d = call i8 @llvm.fptosi.sat.f32.i8(float 0xFFF8000000000000) ; yields i8: 0 + .. _dbg_intrinsics: Debugger Intrinsics Index: include/llvm/CodeGen/ISDOpcodes.h =================================================================== --- include/llvm/CodeGen/ISDOpcodes.h +++ include/llvm/CodeGen/ISDOpcodes.h @@ -513,6 +513,17 @@ FP_TO_SINT, FP_TO_UINT, + /// FP_TO_[US]INT_SAT - Convert floating point value in operand 0 to a + /// signed or unsigned integer type given in operand 1. If the FP value cannot + /// fit in the integer type, then if the FP value is NaN return 0, otherwise + /// return the largest/smallest integer value, if the FP value is + /// larger/smaller (or +INF/-INF) than the largest/smallest integer value. + /// + /// The type in operand 1 may be smaller than the result type as a result of + /// integer type legalization. + FP_TO_SINT_SAT, + FP_TO_UINT_SAT, + /// X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type /// down to the precision of the destination VT. TRUNC is a flag, which is /// always an integer that is zero or one. If TRUNC is 0, this is a Index: include/llvm/CodeGen/RuntimeLibcalls.h =================================================================== --- include/llvm/CodeGen/RuntimeLibcalls.h +++ include/llvm/CodeGen/RuntimeLibcalls.h @@ -49,6 +49,14 @@ /// UNKNOWN_LIBCALL if there is none. Libcall getFPTOUINT(EVT OpVT, EVT RetVT); + /// getFPTOSINT_SAT - Return the FPTOSINT_SAT_*_* value for the given types, + /// or UNKNOWN_LIBCALL if there is none. + Libcall getFPTOSINT_SAT(EVT OpVT, EVT RetVT); + + /// getFPTOUINT_SAT - Return the FPTOUINT_SAT_*_* value for the given types, + /// or UNKNOWN_LIBCALL if there is none. + Libcall getFPTOUINT_SAT(EVT OpVT, EVT RetVT); + /// getSINTTOFP - Return the SINTTOFP_*_* value for the given types, or /// UNKNOWN_LIBCALL if there is none. Libcall getSINTTOFP(EVT OpVT, EVT RetVT); Index: include/llvm/CodeGen/TargetLowering.h =================================================================== --- include/llvm/CodeGen/TargetLowering.h +++ include/llvm/CodeGen/TargetLowering.h @@ -3686,6 +3686,15 @@ /// Expand fminnum/fmaxnum into fminnum_ieee/fmaxnum_ieee with quieted inputs. SDValue expandFMINNUM_FMAXNUM(SDNode *N, SelectionDAG &DAG) const; + /// Expand FP_TO_[US]INT_SAT into FP_TO_[US]INT and selects or min/max. + /// \param N Node to expand + /// \param NativeSaturating whether the native FP_TO_XINT conversion + /// is saturating and we're only expanding in order to handle + /// a non-native saturation width. + /// \returns The expansion result + SDValue expandFP_TO_INT_SAT(SDNode *N, SelectionDAG &DAG, + bool NativeSaturating = false) const; + /// Expand CTPOP nodes. Expands vector/scalar CTPOP nodes, /// vector nodes can only succeed if all operations are legal/custom. /// \param N Node to expand Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -899,6 +899,13 @@ def int_convert_from_fp16 : Intrinsic<[llvm_anyfloat_ty], [llvm_i16_ty]>; } +// Saturating floating point to integer intrinsics +def int_fptoui_sat : Intrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty], + [IntrNoMem, IntrSpeculatable]>; + +def int_fptosi_sat : Intrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty], + [IntrNoMem, IntrSpeculatable]>; + // Clear cache intrinsic, default to ignore (ie. emit nothing) // maps to void __clear_cache() on supporting platforms def int_clear_cache : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty], Index: include/llvm/IR/RuntimeLibcalls.def =================================================================== --- include/llvm/IR/RuntimeLibcalls.def +++ include/llvm/IR/RuntimeLibcalls.def @@ -307,6 +307,36 @@ HANDLE_LIBCALL(FPTOUINT_PPCF128_I32, "__fixunstfsi") HANDLE_LIBCALL(FPTOUINT_PPCF128_I64, "__fixunstfdi") HANDLE_LIBCALL(FPTOUINT_PPCF128_I128, "__fixunstfti") +HANDLE_LIBCALL(FPTOSINT_SAT_F32_I32, "__fixsfsi_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F32_I64, "__fixsfdi_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F32_I128, "__fixsfti_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F64_I32, "__fixdfsi_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F64_I64, "__fixdfdi_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F64_I128, "__fixdfti_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F80_I32, "__fixxfsi_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F80_I64, "__fixxfdi_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F80_I128, "__fixxfti_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F128_I32, "__fixtfsi_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F128_I64, "__fixtfdi_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_F128_I128, "__fixtfti_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_PPCF128_I32, "__fixtfsi_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_PPCF128_I64, "__fixtfdi_sat") +HANDLE_LIBCALL(FPTOSINT_SAT_PPCF128_I128, "__fixtfti_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F32_I32, "__fixunssfsi_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F32_I64, "__fixunssfdi_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F32_I128, "__fixunssfti_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F64_I32, "__fixunsdfsi_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F64_I64, "__fixunsdfdi_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F64_I128, "__fixunsdfti_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F80_I32, "__fixunsxfsi_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F80_I64, "__fixunsxfdi_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F80_I128, "__fixunsxfti_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F128_I32, "__fixunstfsi_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F128_I64, "__fixunstfdi_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_F128_I128, "__fixunstfti_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_PPCF128_I32, "__fixunstfsi_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_PPCF128_I64, "__fixunstfdi_sat") +HANDLE_LIBCALL(FPTOUINT_SAT_PPCF128_I128, "__fixunstfti_sat") HANDLE_LIBCALL(SINTTOFP_I32_F32, "__floatsisf") HANDLE_LIBCALL(SINTTOFP_I32_F64, "__floatsidf") HANDLE_LIBCALL(SINTTOFP_I32_F80, "__floatsixf") Index: include/llvm/Target/TargetSelectionDAG.td =================================================================== --- include/llvm/Target/TargetSelectionDAG.td +++ include/llvm/Target/TargetSelectionDAG.td @@ -156,6 +156,9 @@ def SDTFPToIntOp : SDTypeProfile<1, 1, [ // fp_to_[su]int SDTCisInt<0>, SDTCisFP<1>, SDTCisSameNumEltsAs<0, 1> ]>; +def SDTFPToIntSatOp : SDTypeProfile<1, 2, [ // fp_to_[su]int_sat + SDTCisInt<0>, SDTCisFP<1>, SDTCisVT<2, OtherVT>, SDTCisSameNumEltsAs<0, 1> +]>; def SDTExtInreg : SDTypeProfile<1, 2, [ // sext_inreg SDTCisSameAs<0, 1>, SDTCisInt<0>, SDTCisVT<2, OtherVT>, SDTCisVTSmallerThanOp<2, 1> @@ -443,6 +446,8 @@ def uint_to_fp : SDNode<"ISD::UINT_TO_FP" , SDTIntToFPOp>; def fp_to_sint : SDNode<"ISD::FP_TO_SINT" , SDTFPToIntOp>; def fp_to_uint : SDNode<"ISD::FP_TO_UINT" , SDTFPToIntOp>; +def fp_to_sint_sat : SDNode<"ISD::FP_TO_SINT_SAT" , SDTFPToIntSatOp>; +def fp_to_uint_sat : SDNode<"ISD::FP_TO_UINT_SAT" , SDTFPToIntSatOp>; def f16_to_fp : SDNode<"ISD::FP16_TO_FP" , SDTIntToFPOp>; def fp_to_f16 : SDNode<"ISD::FP_TO_FP16" , SDTFPToIntOp>; Index: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -173,6 +173,7 @@ const SDLoc &dl); SDValue PromoteLegalFP_TO_INT(SDValue LegalOp, EVT DestVT, bool isSigned, const SDLoc &dl); + SDValue PromoteLegalFP_TO_INT_SAT(SDNode *Node, const SDLoc &dl); SDValue ExpandBITREVERSE(SDValue Op, const SDLoc &dl); SDValue ExpandBSWAP(SDValue Op, const SDLoc &dl); @@ -1124,10 +1125,11 @@ case ISD::SADDSAT: case ISD::UADDSAT: case ISD::SSUBSAT: - case ISD::USUBSAT: { + case ISD::USUBSAT: + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); break; - } case ISD::MSCATTER: Action = TLI.getOperationAction(Node->getOpcode(), cast(Node)->getValue().getValueType()); @@ -2509,6 +2511,29 @@ return DAG.getNode(ISD::TRUNCATE, dl, DestVT, Operation); } +/// Promote FP_TO_*INT_SAT operation to a larger result type. At this point +/// the result and operand types are legal and there must be a legal +/// FP_TO_*INT_SAT operation for a larger result type. +SDValue SelectionDAGLegalize::PromoteLegalFP_TO_INT_SAT(SDNode *Node, + const SDLoc &dl) { + unsigned Opcode = Node->getOpcode(); + + // Scan for the appropriate larger type to use. + EVT NewOutTy = Node->getValueType(0); + while (true) { + NewOutTy = (MVT::SimpleValueType)(NewOutTy.getSimpleVT().SimpleTy+1); + if (TLI.isOperationLegalOrCustom(Opcode, NewOutTy)) { + break; + } + } + + // Saturation width is determined by second operand, so we don't have to + // perform any fixup and can directly truncate the result. + SDValue Result = DAG.getNode(Opcode, dl, NewOutTy, + Node->getOperand(0), Node->getOperand(1)); + return DAG.getNode(ISD::TRUNCATE, dl, Node->getValueType(0), Result); +} + /// Legalize a BITREVERSE scalar/vector operation as a series of mask + shifts. SDValue SelectionDAGLegalize::ExpandBITREVERSE(SDValue Op, const SDLoc &dl) { EVT VT = Op.getValueType(); @@ -2863,6 +2888,10 @@ if (TLI.expandFP_TO_UINT(Node, Tmp1, DAG)) Results.push_back(Tmp1); break; + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: + Results.push_back(TLI.expandFP_TO_INT_SAT(Node, DAG)); + break; case ISD::VAARG: Results.push_back(DAG.expandVAArg(Node)); Results.push_back(Results[0].getValue(1)); @@ -4180,6 +4209,10 @@ Node->getOpcode() == ISD::FP_TO_SINT, dl); Results.push_back(Tmp1); break; + case ISD::FP_TO_UINT_SAT: + case ISD::FP_TO_SINT_SAT: + Results.push_back(PromoteLegalFP_TO_INT_SAT(Node, dl)); + break; case ISD::UINT_TO_FP: case ISD::SINT_TO_FP: Tmp1 = PromoteLegalINT_TO_FP(Node->getOperand(0), Node->getValueType(0), Index: lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -763,6 +763,8 @@ case ISD::FP_ROUND: Res = SoftenFloatOp_FP_ROUND(N); break; case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: Res = SoftenFloatOp_FP_TO_XINT(N); break; + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: Res = SoftenFloatOp_FP_TO_XINT_SAT(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; @@ -955,6 +957,37 @@ return DAG.getNode(ISD::TRUNCATE, dl, RVT, Res); } +SDValue DAGTypeLegalizer::SoftenFloatOp_FP_TO_XINT_SAT(SDNode *N) { + // The logic here is essentially the same as for FP_TO_XINT, we just pass + // and extra argument with the saturation width. + bool Signed = N->getOpcode() == ISD::FP_TO_SINT_SAT; + EVT SVT = N->getOperand(0).getValueType(); + EVT SatVT = cast(N->getOperand(1))->getVT(); + EVT RVT = N->getValueType(0); + EVT NVT = EVT(); + SDLoc dl(N); + + RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; + for (unsigned IntVT = MVT::FIRST_INTEGER_VALUETYPE; + IntVT <= MVT::LAST_INTEGER_VALUETYPE && LC == RTLIB::UNKNOWN_LIBCALL; + ++IntVT) { + NVT = (MVT::SimpleValueType)IntVT; + // The type needs to big enough to hold the result. + if (NVT.bitsGE(RVT)) + LC = Signed ? RTLIB::getFPTOSINT_SAT(SVT, NVT) + : RTLIB::getFPTOUINT_SAT(SVT, NVT); + } + assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported FP_TO_XINT_SAT!"); + + SDValue Op = GetSoftenedFloat(N->getOperand(0)); + SDValue SatWidth = DAG.getConstant(SatVT.getScalarSizeInBits(), dl, MVT::i32); + SDValue Ops[2] = { Op, SatWidth }; + SDValue Res = TLI.makeLibCall(DAG, LC, NVT, Ops, false, dl).first; + + // Truncate the result if the libcall returns a larger type. + return DAG.getNode(ISD::TRUNCATE, dl, RVT, Res); +} + SDValue DAGTypeLegalizer::SoftenFloatOp_SELECT(SDNode *N) { SDValue Op1 = GetSoftenedFloat(N->getOperand(1)); SDValue Op2 = GetSoftenedFloat(N->getOperand(2)); @@ -1768,6 +1801,9 @@ case ISD::FCOPYSIGN: R = PromoteFloatOp_FCOPYSIGN(N, OpNo); break; case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: R = PromoteFloatOp_FP_TO_XINT(N, OpNo); break; + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: + R = PromoteFloatOp_FP_TO_XINT_SAT(N, OpNo); break; case ISD::FP_EXTEND: R = PromoteFloatOp_FP_EXTEND(N, OpNo); break; case ISD::SELECT_CC: R = PromoteFloatOp_SELECT_CC(N, OpNo); break; case ISD::SETCC: R = PromoteFloatOp_SETCC(N, OpNo); break; @@ -1811,6 +1847,12 @@ return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), Op); } +SDValue DAGTypeLegalizer::PromoteFloatOp_FP_TO_XINT_SAT(SDNode *N, unsigned OpNo) { + SDValue Op = GetPromotedFloat(N->getOperand(0)); + return DAG.getNode( + N->getOpcode(), SDLoc(N), N->getValueType(0), Op, N->getOperand(1)); +} + SDValue DAGTypeLegalizer::PromoteFloatOp_FP_EXTEND(SDNode *N, unsigned OpNo) { SDValue Op = GetPromotedFloat(N->getOperand(0)); EVT VT = N->getValueType(0); Index: lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -116,6 +116,10 @@ case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: Res = PromoteIntRes_FP_TO_XINT(N); break; + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: + Res = PromoteIntRes_FP_TO_XINT_SAT(N); break; + case ISD::FP_TO_FP16: Res = PromoteIntRes_FP_TO_FP16(N); break; case ISD::AND: @@ -468,6 +472,14 @@ DAG.getValueType(N->getValueType(0).getScalarType())); } +SDValue DAGTypeLegalizer::PromoteIntRes_FP_TO_XINT_SAT(SDNode *N) { + // Promote the result type, while keeping the original type in Op1. + EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); + SDLoc dl(N); + return DAG.getNode( + N->getOpcode(), dl, NVT, N->getOperand(0), N->getOperand(1)); +} + SDValue DAGTypeLegalizer::PromoteIntRes_FP_TO_FP16(SDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDLoc dl(N); @@ -1454,6 +1466,8 @@ case ISD::FLT_ROUNDS_: ExpandIntRes_FLT_ROUNDS(N, Lo, Hi); break; 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::FP_TO_SINT_SAT: ExpandIntRes_FP_TO_SINT_SAT(N, Lo, Hi); break; + case ISD::FP_TO_UINT_SAT: ExpandIntRes_FP_TO_UINT_SAT(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; @@ -2289,6 +2303,56 @@ Lo, Hi); } +void DAGTypeLegalizer::ExpandIntRes_FP_TO_SINT_SAT(SDNode *N, SDValue &Lo, + SDValue &Hi) { + SDLoc dl(N); + EVT VT = N->getValueType(0); + + SDValue Op = N->getOperand(0); + if (getTypeAction(Op.getValueType()) == TargetLowering::TypePromoteFloat) + Op = GetPromotedFloat(Op); + + // There are no half-float to integer builtins, so force promotion. + if (Op.getValueType() == MVT::f16) + Op = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f32, Op); + + EVT SatVT = cast(N->getOperand(1))->getVT(); + SDValue SatWidth = DAG.getConstant(SatVT.getScalarSizeInBits(), dl, MVT::i32); + + RTLIB::Libcall LC = RTLIB::getFPTOSINT_SAT(Op.getValueType(), VT); + assert(LC != RTLIB::UNKNOWN_LIBCALL && + "Unexpected fp-to-uint-sat conversion!"); + + SDValue Ops[2] = { Op, SatWidth }; + SplitInteger(TLI.makeLibCall(DAG, LC, VT, Ops, false/*irrelevant*/, dl).first, + Lo, Hi); +} + +void DAGTypeLegalizer::ExpandIntRes_FP_TO_UINT_SAT(SDNode *N, SDValue &Lo, + SDValue &Hi) { + SDLoc dl(N); + EVT VT = N->getValueType(0); + + SDValue Op = N->getOperand(0); + if (getTypeAction(Op.getValueType()) == TargetLowering::TypePromoteFloat) + Op = GetPromotedFloat(Op); + + // There are no half-float to integer builtins, so force promotion. + if (Op.getValueType() == MVT::f16) + Op = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f32, Op); + + EVT SatVT = cast(N->getOperand(1))->getVT(); + SDValue SatWidth = DAG.getConstant(SatVT.getScalarSizeInBits(), dl, MVT::i32); + + RTLIB::Libcall LC = RTLIB::getFPTOUINT_SAT(Op.getValueType(), VT); + assert(LC != RTLIB::UNKNOWN_LIBCALL && + "Unexpected fp-to-uint-sat conversion!"); + + SDValue Ops[2] = { Op, SatWidth }; + SplitInteger(TLI.makeLibCall(DAG, LC, VT, Ops, false/*irrelevant*/, dl).first, + Lo, Hi); +} + void DAGTypeLegalizer::ExpandIntRes_LOAD(LoadSDNode *N, SDValue &Lo, SDValue &Hi) { if (ISD::isNormalLoad(N)) { Index: lib/CodeGen/SelectionDAG/LegalizeTypes.h =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -306,6 +306,7 @@ SDValue PromoteIntRes_CTTZ(SDNode *N); SDValue PromoteIntRes_EXTRACT_VECTOR_ELT(SDNode *N); SDValue PromoteIntRes_FP_TO_XINT(SDNode *N); + SDValue PromoteIntRes_FP_TO_XINT_SAT(SDNode *N); SDValue PromoteIntRes_FP_TO_FP16(SDNode *N); SDValue PromoteIntRes_INT_EXTEND(SDNode *N); SDValue PromoteIntRes_LOAD(LoadSDNode *N); @@ -395,6 +396,8 @@ void ExpandIntRes_FLT_ROUNDS (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_FP_TO_SINT (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_FP_TO_UINT (SDNode *N, SDValue &Lo, SDValue &Hi); + void ExpandIntRes_FP_TO_SINT_SAT (SDNode *N, SDValue &Lo, SDValue &Hi); + void ExpandIntRes_FP_TO_UINT_SAT (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_Logical (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_ADDSUB (SDNode *N, SDValue &Lo, SDValue &Hi); @@ -528,6 +531,7 @@ SDValue SoftenFloatOp_FP_EXTEND(SDNode *N); SDValue SoftenFloatOp_FP_ROUND(SDNode *N); SDValue SoftenFloatOp_FP_TO_XINT(SDNode *N); + SDValue SoftenFloatOp_FP_TO_XINT_SAT(SDNode *N); SDValue SoftenFloatOp_SELECT(SDNode *N); SDValue SoftenFloatOp_SELECT_CC(SDNode *N); SDValue SoftenFloatOp_SETCC(SDNode *N); @@ -627,6 +631,7 @@ SDValue PromoteFloatOp_FCOPYSIGN(SDNode *N, unsigned OpNo); SDValue PromoteFloatOp_FP_EXTEND(SDNode *N, unsigned OpNo); SDValue PromoteFloatOp_FP_TO_XINT(SDNode *N, unsigned OpNo); + SDValue PromoteFloatOp_FP_TO_XINT_SAT(SDNode *N, unsigned OpNo); SDValue PromoteFloatOp_STORE(SDNode *N, unsigned OpNo); SDValue PromoteFloatOp_SELECT_CC(SDNode *N, unsigned OpNo); SDValue PromoteFloatOp_SETCC(SDNode *N, unsigned OpNo); @@ -670,6 +675,7 @@ SDValue ScalarizeVecRes_SETCC(SDNode *N); SDValue ScalarizeVecRes_UNDEF(SDNode *N); SDValue ScalarizeVecRes_VECTOR_SHUFFLE(SDNode *N); + SDValue ScalarizeVecRes_FP_TO_XINT_SAT(SDNode *N); // Vector Operand Scalarization: <1 x ty> -> ty. bool ScalarizeVectorOperand(SDNode *N, unsigned OpNo); @@ -721,6 +727,7 @@ void SplitVecRes_SETCC(SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVecRes_VECTOR_SHUFFLE(ShuffleVectorSDNode *N, SDValue &Lo, SDValue &Hi); + void SplitVecRes_FP_TO_XINT_SAT(SDNode *N, SDValue &Lo, SDValue &Hi); // Vector Operand Splitting: <128 x ty> -> 2 x <64 x ty>. bool SplitVectorOperand(SDNode *N, unsigned OpNo); @@ -741,6 +748,7 @@ SDValue SplitVecOp_VSETCC(SDNode *N); SDValue SplitVecOp_FP_ROUND(SDNode *N); SDValue SplitVecOp_FCOPYSIGN(SDNode *N); + SDValue SplitVecOp_FP_TO_XINT_SAT(SDNode *N); //===--------------------------------------------------------------------===// // Vector Widening Support: LegalizeVectorTypes.cpp @@ -785,6 +793,7 @@ SDValue WidenVecRes_BinaryCanTrap(SDNode *N); SDValue WidenVecRes_StrictFP(SDNode *N); SDValue WidenVecRes_Convert(SDNode *N); + SDValue WidenVecRes_FP_TO_XINT_SAT(SDNode *N); SDValue WidenVecRes_FCOPYSIGN(SDNode *N); SDValue WidenVecRes_POWI(SDNode *N); SDValue WidenVecRes_Shift(SDNode *N); @@ -805,6 +814,7 @@ SDValue WidenVecOp_SETCC(SDNode* N); SDValue WidenVecOp_Convert(SDNode *N); + SDValue WidenVecOp_FP_TO_XINT_SAT(SDNode *N); SDValue WidenVecOp_FCOPYSIGN(SDNode *N); //===--------------------------------------------------------------------===// Index: lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp +++ lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp @@ -401,6 +401,8 @@ case ISD::UADDSAT: case ISD::SSUBSAT: case ISD::USUBSAT: + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); break; case ISD::FP_ROUND_INREG: Index: lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -172,6 +172,11 @@ case ISD::STRICT_FTRUNC: R = ScalarizeVecRes_StrictFPOp(N); break; + + case ISD::FP_TO_UINT_SAT: + case ISD::FP_TO_SINT_SAT: + R = ScalarizeVecRes_FP_TO_XINT_SAT(N); + break; } // If R is null, the sub-method took care of registering the result. @@ -499,6 +504,24 @@ return DAG.getNode(ExtendCode, DL, NVT, Res); } +SDValue DAGTypeLegalizer::ScalarizeVecRes_FP_TO_XINT_SAT(SDNode *N) { + SDValue Src = N->getOperand(0); + EVT SrcVT = Src.getValueType(); + SDLoc dl(N); + + // Handle case where result is scalarized but operand is not + if (getTypeAction(SrcVT) == TargetLowering::TypeScalarizeVector) + Src = GetScalarizedVector(Src); + else + Src = DAG.getNode( + ISD::EXTRACT_VECTOR_ELT, dl, SrcVT.getVectorElementType(), Src, + DAG.getConstant(0, dl, TLI.getVectorIdxTy(DAG.getDataLayout()))); + + EVT SatVT = cast(N->getOperand(1))->getVT().getVectorElementType(); + EVT DstVT = N->getValueType(0).getVectorElementType(); + return DAG.getNode(N->getOpcode(), dl, DstVT, Src, DAG.getValueType(SatVT)); +} + //===----------------------------------------------------------------------===// // Operand Vector Scalarization <1 x ty> -> ty. @@ -848,6 +871,10 @@ case ISD::STRICT_FTRUNC: SplitVecRes_StrictFPOp(N, Lo, Hi); break; + case ISD::FP_TO_UINT_SAT: + case ISD::FP_TO_SINT_SAT: + SplitVecRes_FP_TO_XINT_SAT(N, Lo, Hi); + break; } // If Lo/Hi is null, the sub-method took care of registering results etc. @@ -1641,6 +1668,28 @@ } } +void DAGTypeLegalizer::SplitVecRes_FP_TO_XINT_SAT(SDNode *N, SDValue &Lo, + SDValue &Hi) { + EVT DstVTLo, DstVTHi; + std::tie(DstVTLo, DstVTHi) = DAG.GetSplitDestVTs(N->getValueType(0)); + EVT SatVTLo, SatVTHi; + std::tie(SatVTLo, SatVTHi) = + DAG.GetSplitDestVTs(cast(N->getOperand(1))->getVT()); + SDLoc dl(N); + + SDValue SrcLo, SrcHi; + EVT SrcVT = N->getOperand(0).getValueType(); + if (getTypeAction(SrcVT) == TargetLowering::TypeSplitVector) + GetSplitVector(N->getOperand(0), SrcLo, SrcHi); + else + std::tie(SrcLo, SrcHi) = DAG.SplitVectorOperand(N, 0); + + Lo = DAG.getNode(N->getOpcode(), dl, DstVTLo, + SrcLo, DAG.getValueType(SatVTLo)); + Hi = DAG.getNode(N->getOpcode(), dl, DstVTHi, + SrcHi, DAG.getValueType(SatVTHi)); +} + //===----------------------------------------------------------------------===// // Operand Vector Splitting @@ -1708,6 +1757,10 @@ else Res = SplitVecOp_UnaryOp(N); break; + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: + Res = SplitVecOp_FP_TO_XINT_SAT(N); + break; case ISD::CTTZ: case ISD::CTLZ: case ISD::CTPOP: @@ -2323,6 +2376,27 @@ return DAG.UnrollVectorOp(N, N->getValueType(0).getVectorNumElements()); } +SDValue DAGTypeLegalizer::SplitVecOp_FP_TO_XINT_SAT(SDNode *N) { + EVT ResVT = N->getValueType(0); + SDValue Lo, Hi; + SDLoc dl(N); + GetSplitVector(N->getOperand(0), Lo, Hi); + EVT InVT = Lo.getValueType(); + EVT SatVT = cast(N->getOperand(1))->getVT(); + + EVT NewResVT = EVT::getVectorVT( + *DAG.getContext(), ResVT.getVectorElementType(), + InVT.getVectorNumElements()); + EVT NewSatVT = EVT::getVectorVT( + *DAG.getContext(), SatVT.getVectorElementType(), + InVT.getVectorNumElements()); + SDValue NewSatOp = DAG.getValueType(NewSatVT); + + Lo = DAG.getNode(N->getOpcode(), dl, NewResVT, Lo, NewSatOp); + Hi = DAG.getNode(N->getOpcode(), dl, NewResVT, Hi, NewSatOp); + + return DAG.getNode(ISD::CONCAT_VECTORS, dl, ResVT, Lo, Hi); +} //===----------------------------------------------------------------------===// // Result Vector Widening @@ -2463,6 +2537,11 @@ Res = WidenVecRes_Convert(N); break; + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: + Res = WidenVecRes_FP_TO_XINT_SAT(N); + break; + case ISD::FABS: case ISD::FCEIL: case ISD::FCOS: @@ -2887,6 +2966,33 @@ return DAG.getBuildVector(WidenVT, DL, Ops); } +SDValue DAGTypeLegalizer::WidenVecRes_FP_TO_XINT_SAT(SDNode *N) { + SDLoc dl(N); + EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); + unsigned WidenNumElts = WidenVT.getVectorNumElements(); + + SDValue Src = N->getOperand(0); + EVT SrcVT = Src.getValueType(); + + // Also widen the input. + if (getTypeAction(SrcVT) == TargetLowering::TypeWidenVector) { + Src = GetWidenedVector(Src); + SrcVT = Src.getValueType(); + } + + // Input and output not widened to the same size, give up. + if (WidenNumElts != SrcVT.getVectorNumElements()) { + return DAG.UnrollVectorOp(N, WidenNumElts); + } + + EVT SatVT = cast(N->getOperand(1))->getVT(); + EVT SatWidenVT = EVT::getVectorVT( + *DAG.getContext(), SatVT.getVectorElementType(), WidenNumElts); + + return DAG.getNode( + N->getOpcode(), dl, WidenVT, Src, DAG.getValueType(SatWidenVT)); +} + SDValue DAGTypeLegalizer::WidenVecRes_EXTEND_VECTOR_INREG(SDNode *N) { unsigned Opcode = N->getOpcode(); SDValue InOp = N->getOperand(0); @@ -3672,6 +3778,11 @@ case ISD::TRUNCATE: Res = WidenVecOp_Convert(N); break; + + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: + Res = WidenVecOp_FP_TO_XINT_SAT(N); + break; } // If Res is null, the sub-method took care of registering the result. @@ -3796,6 +3907,31 @@ return DAG.getBuildVector(VT, dl, Ops); } +SDValue DAGTypeLegalizer::WidenVecOp_FP_TO_XINT_SAT(SDNode *N) { + EVT DstVT = N->getValueType(0); + SDValue Src = GetWidenedVector(N->getOperand(0)); + EVT SrcVT = Src.getValueType(); + unsigned WideNumElts = SrcVT.getVectorNumElements(); + SDLoc dl(N); + + // See if a widened result type would be legal, if so widen the node. + EVT WideDstVT = EVT::getVectorVT( + *DAG.getContext(), DstVT.getVectorElementType(), WideNumElts); + if (TLI.isTypeLegal(WideDstVT)) { + EVT SatVT = cast(N->getOperand(1))->getVT(); + EVT WideSatVT = EVT::getVectorVT( + *DAG.getContext(), SatVT.getVectorElementType(), WideNumElts); + SDValue Res = DAG.getNode( + N->getOpcode(), dl, WideDstVT, Src, DAG.getValueType(WideSatVT)); + return DAG.getNode( + ISD::EXTRACT_SUBVECTOR, dl, DstVT, Res, + DAG.getConstant(0, dl, TLI.getVectorIdxTy(DAG.getDataLayout()))); + } + + // Give up and unroll. + return DAG.UnrollVectorOp(N); +} + SDValue DAGTypeLegalizer::WidenVecOp_BITCAST(SDNode *N) { EVT VT = N->getValueType(0); SDValue InOp = GetWidenedVector(N->getOperand(0)); Index: lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -8633,7 +8633,9 @@ Operands[1]))); break; case ISD::SIGN_EXTEND_INREG: - case ISD::FP_ROUND_INREG: { + case ISD::FP_ROUND_INREG: + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: { EVT ExtVT = cast(Operands[1])->getVT().getVectorElementType(); Scalars.push_back(getNode(N->getOpcode(), dl, EltVT, Operands[0], Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5679,6 +5679,20 @@ DAG.getNode(ISD::BITCAST, sdl, MVT::f16, getValue(I.getArgOperand(0))))); return nullptr; + case Intrinsic::fptosi_sat: { + EVT Type = TLI.getValueType(DAG.getDataLayout(), I.getType()); + setValue(&I, DAG.getNode(ISD::FP_TO_SINT_SAT, sdl, Type, + getValue(I.getArgOperand(0)), + DAG.getValueType(Type))); + return nullptr; + } + case Intrinsic::fptoui_sat: { + EVT Type = TLI.getValueType(DAG.getDataLayout(), I.getType()); + setValue(&I, DAG.getNode(ISD::FP_TO_UINT_SAT, sdl, Type, + getValue(I.getArgOperand(0)), + DAG.getValueType(Type))); + return nullptr; + } case Intrinsic::pcmarker: { SDValue Tmp = getValue(I.getArgOperand(0)); DAG.setRoot(DAG.getNode(ISD::PCMARKER, sdl, MVT::Other, getRoot(), Tmp)); Index: lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -314,6 +314,8 @@ case ISD::UINT_TO_FP: return "uint_to_fp"; case ISD::FP_TO_SINT: return "fp_to_sint"; case ISD::FP_TO_UINT: return "fp_to_uint"; + case ISD::FP_TO_SINT_SAT: return "fp_to_sint_sat"; + case ISD::FP_TO_UINT_SAT: return "fp_to_uint_sat"; case ISD::BITCAST: return "bitcast"; case ISD::ADDRSPACECAST: return "addrspacecast"; case ISD::FP16_TO_FP: return "fp16_to_fp"; Index: lib/CodeGen/SelectionDAG/TargetLowering.cpp =================================================================== --- lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -5063,3 +5063,109 @@ return DAG.getSelect(dl, ResultType, Overflow, Result, SumDiff); } } + +SDValue TargetLowering::expandFP_TO_INT_SAT( + SDNode *Node, SelectionDAG &DAG, bool NativeSaturating) const { + bool IsSigned = Node->getOpcode() == ISD::FP_TO_SINT_SAT; + SDLoc dl(SDValue(Node, 0)); + SDValue Src = Node->getOperand(0); + + // DstVT is the result type, while SatVT is the size to which we saturate + EVT SrcVT = Src.getValueType(); + EVT SatVT = cast(Node->getOperand(1))->getVT(); + EVT DstVT = Node->getValueType(0); + + unsigned SatWidth = SatVT.getScalarSizeInBits(); + unsigned DstWidth = DstVT.getScalarSizeInBits(); + assert(SatWidth <= DstWidth && + "Expected saturation width smaller than result width"); + + // Determine minimum and maximum integer values and their corresponding + // floating-point values. + APInt MinInt, MaxInt; + if (IsSigned) { + MinInt = APInt::getSignedMinValue(SatWidth).sextOrSelf(DstWidth); + MaxInt = APInt::getSignedMaxValue(SatWidth).sextOrSelf(DstWidth); + } else { + MinInt = APInt::getMinValue(SatWidth).zextOrSelf(DstWidth); + MaxInt = APInt::getMaxValue(SatWidth).zextOrSelf(DstWidth); + } + + APFloat MinFloat(DAG.EVTToAPFloatSemantics(SrcVT)); + APFloat MaxFloat(DAG.EVTToAPFloatSemantics(SrcVT)); + + APFloat::opStatus MinStatus = MinFloat.convertFromAPInt( + MinInt, IsSigned, APFloat::rmTowardZero); + APFloat::opStatus MaxStatus = MaxFloat.convertFromAPInt( + MaxInt, IsSigned, APFloat::rmTowardZero); + bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) + && !(MaxStatus & APFloat::opStatus::opInexact); + + SDValue MinFloatNode = DAG.getConstantFP(MinFloat, dl, SrcVT); + SDValue MaxFloatNode = DAG.getConstantFP(MaxFloat, dl, SrcVT); + + // If the integer bounds are exactly representable as floats and min/max are + // legal, emit a min+max+fptoi sequence. Otherwise we have to use a sequence + // of comparisons and selects. + bool MinMaxLegal = isOperationLegal(ISD::FMINNUM, SrcVT) + && isOperationLegal(ISD::FMAXNUM, SrcVT); + if (AreExactFloatBounds && MinMaxLegal) { + SDValue Clamped = Src; + if (IsSigned || !NativeSaturating) { + // Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat. + // If unsigned and native saturating, we don't need to clamp, because the + // zero bound is independent of the saturation width. + Clamped = DAG.getNode(ISD::FMAXNUM, dl, SrcVT, Src, MinFloatNode); + } + + // Clamp by MaxFloat from above. + Clamped = DAG.getNode(ISD::FMINNUM, dl, SrcVT, Clamped, MaxFloatNode); + // Convert clamped value to integer. + SDValue FpToInt = DAG.getNode( + IsSigned ? ISD::FP_TO_SINT : ISD::FP_TO_UINT, dl, DstVT, Clamped); + + // In the unsigned case we're done, because we mapped NaN to MinFloat, + // which will cast to zero. + if (!IsSigned || NativeSaturating) { + return FpToInt; + } + + // Otherwise, select 0 if Src is NaN. + SDValue ZeroInt = DAG.getConstant(0, dl, DstVT); + return DAG.getSelectCC( + dl, Src, Src, ZeroInt, FpToInt, ISD::CondCode::SETUO); + } + + SDValue MinIntNode = DAG.getConstant(MinInt, dl, DstVT); + SDValue MaxIntNode = DAG.getConstant(MaxInt, dl, DstVT); + + // Result of direct conversion. The assumption here is that the operation is + // non-trapping and it's fine to apply it to an out-of-range value if we + // select it away later. + SDValue FpToInt = DAG.getNode( + IsSigned ? ISD::FP_TO_SINT : ISD::FP_TO_UINT, dl, DstVT, Src); + + SDValue Select = FpToInt; + if (IsSigned || !NativeSaturating) { + // If Src ULT MinFloat, select MinInt. In particular, this also selects + // MinInt if Src is NaN. If unsigned and native saturating, we don't need + // check the lower bound, as zero is independent of the saturation width. + Select = DAG.getSelectCC( + dl, Src, MinFloatNode, MinIntNode, FpToInt, ISD::CondCode::SETULT); + } + + // If Src OGT MaxFloat, select MaxInt. + Select = DAG.getSelectCC( + dl, Src, MaxFloatNode, MaxIntNode, Select, ISD::CondCode::SETOGT); + + // In the unsigned case we are done, because we mapped NaN to MinInt, which + // is already zero. + if (!IsSigned || NativeSaturating) { + return Select; + } + + // Otherwise, select 0 if Src is NaN. + SDValue ZeroInt = DAG.getConstant(0, dl, DstVT); + return DAG.getSelectCC( + dl, Src, Src, ZeroInt, Select, ISD::CondCode::SETUO); +} Index: lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- lib/CodeGen/TargetLoweringBase.cpp +++ lib/CodeGen/TargetLoweringBase.cpp @@ -323,6 +323,90 @@ return UNKNOWN_LIBCALL; } +/// getFPTOSINT_SAT - Return the FPTOSINT_SAT_*_* value for the given types, +/// or UNKNOWN_LIBCALL if there is none. +RTLIB::Libcall RTLIB::getFPTOSINT_SAT(EVT OpVT, EVT RetVT) { + if (OpVT == MVT::f32) { + if (RetVT == MVT::i32) + return FPTOSINT_SAT_F32_I32; + if (RetVT == MVT::i64) + return FPTOSINT_SAT_F32_I64; + if (RetVT == MVT::i128) + return FPTOSINT_SAT_F32_I128; + } else if (OpVT == MVT::f64) { + if (RetVT == MVT::i32) + return FPTOSINT_SAT_F64_I32; + if (RetVT == MVT::i64) + return FPTOSINT_SAT_F64_I64; + if (RetVT == MVT::i128) + return FPTOSINT_SAT_F64_I128; + } else if (OpVT == MVT::f80) { + if (RetVT == MVT::i32) + return FPTOSINT_SAT_F80_I32; + if (RetVT == MVT::i64) + return FPTOSINT_SAT_F80_I64; + if (RetVT == MVT::i128) + return FPTOSINT_SAT_F80_I128; + } else if (OpVT == MVT::f128) { + if (RetVT == MVT::i32) + return FPTOSINT_SAT_F128_I32; + if (RetVT == MVT::i64) + return FPTOSINT_SAT_F128_I64; + if (RetVT == MVT::i128) + return FPTOSINT_SAT_F128_I128; + } else if (OpVT == MVT::ppcf128) { + if (RetVT == MVT::i32) + return FPTOSINT_SAT_PPCF128_I32; + if (RetVT == MVT::i64) + return FPTOSINT_SAT_PPCF128_I64; + if (RetVT == MVT::i128) + return FPTOSINT_SAT_PPCF128_I128; + } + return UNKNOWN_LIBCALL; +} + +/// getFPTOUINT_SAT - Return the FPTOUINT_SAT_*_* value for the given types, +/// or UNKNOWN_LIBCALL if there is none. +RTLIB::Libcall RTLIB::getFPTOUINT_SAT(EVT OpVT, EVT RetVT) { + if (OpVT == MVT::f32) { + if (RetVT == MVT::i32) + return FPTOUINT_SAT_F32_I32; + if (RetVT == MVT::i64) + return FPTOUINT_SAT_F32_I64; + if (RetVT == MVT::i128) + return FPTOUINT_SAT_F32_I128; + } else if (OpVT == MVT::f64) { + if (RetVT == MVT::i32) + return FPTOUINT_SAT_F64_I32; + if (RetVT == MVT::i64) + return FPTOUINT_SAT_F64_I64; + if (RetVT == MVT::i128) + return FPTOUINT_SAT_F64_I128; + } else if (OpVT == MVT::f80) { + if (RetVT == MVT::i32) + return FPTOUINT_SAT_F80_I32; + if (RetVT == MVT::i64) + return FPTOUINT_SAT_F80_I64; + if (RetVT == MVT::i128) + return FPTOUINT_SAT_F80_I128; + } else if (OpVT == MVT::f128) { + if (RetVT == MVT::i32) + return FPTOUINT_SAT_F128_I32; + if (RetVT == MVT::i64) + return FPTOUINT_SAT_F128_I64; + if (RetVT == MVT::i128) + return FPTOUINT_SAT_F128_I128; + } else if (OpVT == MVT::ppcf128) { + if (RetVT == MVT::i32) + return FPTOUINT_SAT_PPCF128_I32; + if (RetVT == MVT::i64) + return FPTOUINT_SAT_PPCF128_I64; + if (RetVT == MVT::i128) + return FPTOUINT_SAT_PPCF128_I128; + } + return UNKNOWN_LIBCALL; +} + /// getSINTTOFP - Return the SINTTOFP_*_* value for the given types, or /// UNKNOWN_LIBCALL if there is none. RTLIB::Libcall RTLIB::getSINTTOFP(EVT OpVT, EVT RetVT) { @@ -614,6 +698,8 @@ setOperationAction(ISD::UADDSAT, VT, Expand); setOperationAction(ISD::SSUBSAT, VT, Expand); setOperationAction(ISD::USUBSAT, VT, Expand); + setOperationAction(ISD::FP_TO_SINT_SAT, VT, Expand); + setOperationAction(ISD::FP_TO_UINT_SAT, VT, Expand); // Overflow operations default to expand setOperationAction(ISD::SADDO, VT, Expand); Index: lib/Target/AArch64/AArch64ISelLowering.h =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.h +++ lib/Target/AArch64/AArch64ISelLowering.h @@ -649,6 +649,7 @@ SDValue LowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFP_TO_INT_SAT(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVectorAND(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVectorOR(SDValue Op, SelectionDAG &DAG) const; Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -246,6 +246,13 @@ setOperationAction(ISD::FP_ROUND, MVT::f32, Custom); setOperationAction(ISD::FP_ROUND, MVT::f64, Custom); + // These are equivalent to FP_TO_[SU]INT if the saturation width matches + // the result width, otherwise they require expansion. + setOperationAction(ISD::FP_TO_SINT_SAT, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_SINT_SAT, MVT::i64, Custom); + setOperationAction(ISD::FP_TO_UINT_SAT, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_UINT_SAT, MVT::i64, Custom); + // Variable arguments. setOperationAction(ISD::VASTART, MVT::Other, Custom); setOperationAction(ISD::VAARG, MVT::Other, Custom); @@ -646,6 +653,8 @@ setOperationAction(ISD::FP_TO_SINT, MVT::v1i64, Expand); setOperationAction(ISD::FP_TO_UINT, MVT::v1i64, Expand); + setOperationAction(ISD::FP_TO_SINT_SAT, MVT::v1i64, Expand); + setOperationAction(ISD::FP_TO_UINT_SAT, MVT::v1i64, Expand); setOperationAction(ISD::SINT_TO_FP, MVT::v1i64, Expand); setOperationAction(ISD::UINT_TO_FP, MVT::v1i64, Expand); setOperationAction(ISD::FP_ROUND, MVT::v1f64, Expand); @@ -804,6 +813,8 @@ setOperationAction(ISD::FP_TO_SINT, VT, Custom); setOperationAction(ISD::FP_TO_UINT, VT, Custom); + setOperationAction(ISD::FP_TO_SINT_SAT, VT, Custom); + setOperationAction(ISD::FP_TO_UINT_SAT, VT, Custom); if (!VT.isFloatingPoint()) setOperationAction(ISD::ABS, VT, Legal); @@ -2383,6 +2394,64 @@ return Op; } +SDValue AArch64TargetLowering::LowerFP_TO_INT_SAT(SDValue Op, + SelectionDAG &DAG) const { + SDValue Src = Op.getOperand(0); + EVT SrcVT = Src.getValueType(); + EVT SatVT = cast(Op.getOperand(1))->getVT(); + EVT DstVT = Op.getValueType(); + SDLoc dl(Op); + + if (SrcVT.isVector()) { + unsigned NumElts = SrcVT.getVectorNumElements(); + + // If necessary, extend the source vector to a larger FP type. It's + // better to do this prior to SAT lowering, because it allows us to + // generate min/max based code more often. + if (SrcVT.getVectorElementType() == MVT::f16) { + MVT ExtVT = MVT::getVectorVT(MVT::f32, NumElts); + Src = DAG.getNode(ISD::FP_EXTEND, dl, ExtVT, Src); + return DAG.getNode(Op.getOpcode(), dl, DstVT, Src, Op.getOperand(1)); + } + + if (DstVT.getSizeInBits() > SrcVT.getSizeInBits()) { + MVT ExtVT = MVT::getVectorVT( + MVT::getFloatingPointVT(DstVT.getScalarSizeInBits()), NumElts); + Src = DAG.getNode(ISD::FP_EXTEND, dl, ExtVT, Src); + return DAG.getNode(Op.getOpcode(), dl, DstVT, Src, Op.getOperand(1)); + } + } + + // f16 conversions are promoted to f32 when full fp16 is not supported. + if (SrcVT == MVT::f16 && !Subtarget->hasFullFP16()) { + SDValue Extend = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f32, Src); + return DAG.getNode(Op.getOpcode(), dl, DstVT, Extend, Op.getOperand(1)); + } + + if (SrcVT == MVT::f128) { + // Dispatch to builtin. + RTLIB::Libcall LC = Op.getOpcode() == ISD::FP_TO_SINT_SAT + ? RTLIB::getFPTOSINT_SAT(SrcVT, DstVT) + : RTLIB::getFPTOUINT_SAT(SrcVT, DstVT); + SDValue SatWidth = DAG.getConstant( + SatVT.getScalarSizeInBits(), dl, MVT::i32); + SDValue Ops[2] = { Src, SatWidth }; + return makeLibCall(DAG, LC, DstVT, Ops, false, SDLoc(Op)).first; + } + + if (DstVT != SatVT) { + // Fallback to generic implementation, but make use of the fact that NaN + // will already be mapped to zero. + return DAG.getTargetLoweringInfo() + .expandFP_TO_INT_SAT(Op.getNode(), DAG, true); + } + + // The native fp to int conversions are already saturating, lower to them. + unsigned Opcode = Op.getOpcode() == ISD::FP_TO_SINT_SAT + ? ISD::FP_TO_SINT : ISD::FP_TO_UINT; + return DAG.getNode(Opcode, dl, DstVT, Src); +} + SDValue AArch64TargetLowering::LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) const { if (Op.getValueType().isVector()) @@ -2926,6 +2995,9 @@ case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: return LowerFP_TO_INT(Op, DAG); + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: + return LowerFP_TO_INT_SAT(Op, DAG); case ISD::FSINCOS: return LowerFSINCOS(Op, DAG); case ISD::FLT_ROUNDS_: Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -1231,6 +1231,7 @@ SDValue LowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG) const; SDValue LowerTRUNCATE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFP_TO_INT_SAT(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSETCCCARRY(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSELECT(SDValue Op, SelectionDAG &DAG) const; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -295,6 +295,19 @@ setOperationAction(ISD::FP_TO_UINT , MVT::i64 , Custom); } + if (Subtarget.hasSSE1()) { + // Custom lowering for saturating float to int conversions. + // We handle promotion to larger result types manually. + for (MVT VT : { MVT::i8, MVT::i16, MVT::i32 }) { + setOperationAction(ISD::FP_TO_UINT_SAT, VT, Custom); + setOperationAction(ISD::FP_TO_SINT_SAT, VT, Custom); + } + if (Subtarget.is64Bit()) { + setOperationAction(ISD::FP_TO_UINT_SAT, MVT::i64, Custom); + setOperationAction(ISD::FP_TO_SINT_SAT, MVT::i64, Custom); + } + } + // TODO: when we have SSE, these could be more efficient, by using movd/movq. if (!X86ScalarSSEf64) { setOperationAction(ISD::BITCAST , MVT::f32 , Expand); @@ -18107,6 +18120,156 @@ return FIST; } +SDValue X86TargetLowering::LowerFP_TO_INT_SAT(SDValue Op, SelectionDAG &DAG) const { + // This is based on the TargetLowering::expandFP_TO_INT_SAT implementation, + // but making use of X86 specifics to produce better instruction sequences. + SDNode *Node = Op.getNode(); + bool IsSigned = Node->getOpcode() == ISD::FP_TO_SINT_SAT; + unsigned FpToIntOpcode = IsSigned ? ISD::FP_TO_SINT : ISD::FP_TO_UINT; + SDLoc dl(SDValue(Node, 0)); + SDValue Src = Node->getOperand(0); + + // There are four types involved here: SrcVT is the source floating point + // type, SatVT specified the integer width to which we saturate, DstVT + // is the type of the result, and TmpVT is the result of the intermediate + // FP_TO_*INT operation we'll use (which may be a promotion of DstVT). + EVT SrcVT = Src.getValueType(); + EVT SatVT = cast(Node->getOperand(1))->getVT(); + EVT DstVT = Node->getValueType(0); + EVT TmpVT = DstVT; + + // This code is only for floats and doubles. Fall back to generic code for + // anything else. + if (SrcVT != MVT::f32 && SrcVT != MVT::f64) { + return SDValue(); + } + + unsigned SatWidth = SatVT.getScalarSizeInBits(); + unsigned DstWidth = DstVT.getScalarSizeInBits(); + unsigned TmpWidth = TmpVT.getScalarSizeInBits(); + assert(SatWidth <= DstWidth && SatWidth <= TmpWidth && + "Expected saturation width smaller than result width"); + + // Promote result of FP_TO_*INT to at least 32 bits. + if (TmpWidth < 32) { + TmpVT = MVT::i32; + TmpWidth = 32; + } + + // Promote conversions to unsigned 32-bit to 64-bit, because it will allow + // us to use a native signed conversion instead. + if (SatWidth == 32 && !IsSigned && Subtarget.is64Bit()) { + TmpVT = MVT::i64; + TmpWidth = 64; + } + + // If the saturation width is smaller than the size of the temporary result, + // we can always use signed conversion, which is native. + if (SatWidth < TmpWidth) + FpToIntOpcode = ISD::FP_TO_SINT; + + // Determine minimum and maximum integer values and their corresponding + // floating-point values. + APInt MinInt, MaxInt; + if (IsSigned) { + MinInt = APInt::getSignedMinValue(SatWidth).sextOrSelf(DstWidth); + MaxInt = APInt::getSignedMaxValue(SatWidth).sextOrSelf(DstWidth); + } else { + MinInt = APInt::getMinValue(SatWidth).zextOrSelf(DstWidth); + MaxInt = APInt::getMaxValue(SatWidth).zextOrSelf(DstWidth); + } + + APFloat MinFloat(DAG.EVTToAPFloatSemantics(SrcVT)); + APFloat MaxFloat(DAG.EVTToAPFloatSemantics(SrcVT)); + + APFloat::opStatus MinStatus = MinFloat.convertFromAPInt( + MinInt, IsSigned, APFloat::rmTowardZero); + APFloat::opStatus MaxStatus = MaxFloat.convertFromAPInt( + MaxInt, IsSigned, APFloat::rmTowardZero); + bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) + && !(MaxStatus & APFloat::opStatus::opInexact); + + SDValue MinFloatNode = DAG.getConstantFP(MinFloat, dl, SrcVT); + SDValue MaxFloatNode = DAG.getConstantFP(MaxFloat, dl, SrcVT); + + // If the integer bounds are exactly representable as floats, emit a + // min+max+fptoi sequence. Otherwise use comparisons and selects. + if (AreExactFloatBounds) { + if (DstVT != TmpVT) { + // Clamp by MinFloat from below. If Src is NaN, propagate NaN. + SDValue MinClamped = DAG.getNode( + X86ISD::FMAX, dl, SrcVT, MinFloatNode, Src); + // Clamp by MaxFloat from above. If Src is NaN, propagate NaN. + SDValue BothClamped = DAG.getNode( + X86ISD::FMIN, dl, SrcVT, MaxFloatNode, MinClamped); + // Convert clamped value to integer. + SDValue FpToInt = DAG.getNode(FpToIntOpcode, dl, TmpVT, BothClamped); + + // NaN will become INDVAL, with the top bit set and the rest zero. + // Truncation will discard the top bit, resulting in zero. + return DAG.getNode(ISD::TRUNCATE, dl, DstVT, FpToInt); + } + + // Clamp by MinFloat from below. If Src is NaN, the result is MinFloat. + SDValue MinClamped = DAG.getNode( + X86ISD::FMAX, dl, SrcVT, Src, MinFloatNode); + // Clamp by MaxFloat from above. NaN cannot occur. + SDValue BothClamped = DAG.getNode( + X86ISD::FMINC, dl, SrcVT, MinClamped, MaxFloatNode); + // Convert clamped value to integer. + SDValue FpToInt = DAG.getNode(FpToIntOpcode, dl, DstVT, BothClamped); + + if (!IsSigned) { + // In the unsigned case we're done, because we mapped NaN to MinFloat, + // which is zero. + return FpToInt; + } + + // Otherwise, select zero if Src is NaN. + SDValue ZeroInt = DAG.getConstant(0, dl, DstVT); + return DAG.getSelectCC( + dl, Src, Src, ZeroInt, FpToInt, ISD::CondCode::SETUO); + } + + SDValue MinIntNode = DAG.getConstant(MinInt, dl, DstVT); + SDValue MaxIntNode = DAG.getConstant(MaxInt, dl, DstVT); + + // Result of direct conversion, which may be selected away. + SDValue FpToInt = DAG.getNode(FpToIntOpcode, dl, TmpVT, Src); + + if (DstVT != TmpVT) { + // NaN will become INDVAL, with the top bit set and the rest zero. + // Truncation will discard the top bit, resulting in zero. + FpToInt = DAG.getNode(ISD::TRUNCATE, dl, DstVT, FpToInt); + } + + SDValue Select = FpToInt; + // For signed conversions where we saturate to the same size as the + // result type of the fptoi instructions, INDVAL coincides with integer + // minimum, so we don't need to explicitly check it. + if (!IsSigned || SatWidth != TmpVT.getScalarSizeInBits()) { + // If Src ULT MinFloat, select MinInt. In particular, this also selects + // MinInt if Src is NaN. + Select = DAG.getSelectCC( + dl, Src, MinFloatNode, MinIntNode, Select, ISD::CondCode::SETULT); + } + + // If Src OGT MaxFloat, select MaxInt. + Select = DAG.getSelectCC( + dl, Src, MaxFloatNode, MaxIntNode, Select, ISD::CondCode::SETOGT); + + // In the unsigned case we are done, because we mapped NaN to MinInt, which + // is already zero. The promoted case was already handled above. + if (!IsSigned || DstVT != TmpVT) { + return Select; + } + + // Otherwise, select 0 if Src is NaN. + SDValue ZeroInt = DAG.getConstant(0, dl, DstVT); + return DAG.getSelectCC( + dl, Src, Src, ZeroInt, Select, ISD::CondCode::SETUO); +} + static SDValue LowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) { SDLoc DL(Op); MVT VT = Op.getSimpleValueType(); @@ -26012,6 +26175,8 @@ return LowerEXTEND_VECTOR_INREG(Op, Subtarget, DAG); case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: return LowerFP_TO_INT(Op, DAG); + case ISD::FP_TO_SINT_SAT: + case ISD::FP_TO_UINT_SAT: return LowerFP_TO_INT_SAT(Op, DAG); case ISD::FP_EXTEND: return LowerFP_EXTEND(Op, DAG); case ISD::LOAD: return LowerLoad(Op, Subtarget, DAG); case ISD::STORE: return LowerStore(Op, Subtarget, DAG); Index: test/CodeGen/AArch64/fptoi-sat-scalar.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/fptoi-sat-scalar.ll @@ -0,0 +1,1195 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=aarch64 < %s | FileCheck %s + +; +; 32-bit float to signed integer +; + +declare i1 @llvm.fptosi.sat.f32.i1 (float) +declare i8 @llvm.fptosi.sat.f32.i8 (float) +declare i13 @llvm.fptosi.sat.f32.i13 (float) +declare i16 @llvm.fptosi.sat.f32.i16 (float) +declare i19 @llvm.fptosi.sat.f32.i19 (float) +declare i32 @llvm.fptosi.sat.f32.i32 (float) +declare i50 @llvm.fptosi.sat.f32.i50 (float) +declare i64 @llvm.fptosi.sat.f32.i64 (float) +declare i100 @llvm.fptosi.sat.f32.i100(float) +declare i128 @llvm.fptosi.sat.f32.i128(float) + +define i1 @test_signed_f32_i1(float %f) { +; CHECK-LABEL: test_signed_f32_i1: +; CHECK: // %bb.0: +; CHECK-NEXT: fmov s1, #-1.00000000 +; CHECK-NEXT: fmaxnm s0, s0, s1 +; CHECK-NEXT: fmov s1, wzr +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzs w8, s0 +; CHECK-NEXT: and w0, w8, #0x1 +; CHECK-NEXT: ret + %x = call i1 @llvm.fptosi.sat.f32.i1(float %f) + ret i1 %x +} + +define i8 @test_signed_f32_i8(float %f) { +; CHECK-LABEL: test_signed_f32_i8: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI1_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI1_0] +; CHECK-NEXT: adrp x8, .LCPI1_1 +; CHECK-NEXT: ldr s2, [x8, :lo12:.LCPI1_1] +; CHECK-NEXT: fmaxnm s0, s0, s1 +; CHECK-NEXT: fminnm s0, s0, s2 +; CHECK-NEXT: fcvtzs w0, s0 +; CHECK-NEXT: ret + %x = call i8 @llvm.fptosi.sat.f32.i8(float %f) + ret i8 %x +} + +define i13 @test_signed_f32_i13(float %f) { +; CHECK-LABEL: test_signed_f32_i13: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI2_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI2_0] +; CHECK-NEXT: adrp x8, .LCPI2_1 +; CHECK-NEXT: ldr s2, [x8, :lo12:.LCPI2_1] +; CHECK-NEXT: fmaxnm s0, s0, s1 +; CHECK-NEXT: fminnm s0, s0, s2 +; CHECK-NEXT: fcvtzs w0, s0 +; CHECK-NEXT: ret + %x = call i13 @llvm.fptosi.sat.f32.i13(float %f) + ret i13 %x +} + +define i16 @test_signed_f32_i16(float %f) { +; CHECK-LABEL: test_signed_f32_i16: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI3_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI3_0] +; CHECK-NEXT: adrp x8, .LCPI3_1 +; CHECK-NEXT: ldr s2, [x8, :lo12:.LCPI3_1] +; CHECK-NEXT: fmaxnm s0, s0, s1 +; CHECK-NEXT: fminnm s0, s0, s2 +; CHECK-NEXT: fcvtzs w0, s0 +; CHECK-NEXT: ret + %x = call i16 @llvm.fptosi.sat.f32.i16(float %f) + ret i16 %x +} + +define i19 @test_signed_f32_i19(float %f) { +; CHECK-LABEL: test_signed_f32_i19: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI4_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI4_0] +; CHECK-NEXT: adrp x8, .LCPI4_1 +; CHECK-NEXT: ldr s2, [x8, :lo12:.LCPI4_1] +; CHECK-NEXT: fmaxnm s0, s0, s1 +; CHECK-NEXT: fminnm s0, s0, s2 +; CHECK-NEXT: fcvtzs w0, s0 +; CHECK-NEXT: ret + %x = call i19 @llvm.fptosi.sat.f32.i19(float %f) + ret i19 %x +} + +define i32 @test_signed_f32_i32(float %f) { +; CHECK-LABEL: test_signed_f32_i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs w0, s0 +; CHECK-NEXT: ret + %x = call i32 @llvm.fptosi.sat.f32.i32(float %f) + ret i32 %x +} + +define i50 @test_signed_f32_i50(float %f) { +; CHECK-LABEL: test_signed_f32_i50: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x9, .LCPI6_0 +; CHECK-NEXT: ldr s1, [x9, :lo12:.LCPI6_0] +; CHECK-NEXT: adrp x9, .LCPI6_1 +; CHECK-NEXT: ldr s2, [x9, :lo12:.LCPI6_1] +; CHECK-NEXT: fcvtzs x8, s0 +; CHECK-NEXT: orr x9, xzr, #0xfffe000000000000 +; CHECK-NEXT: fcmp s0, s1 +; CHECK-NEXT: csel x8, x9, x8, lt +; CHECK-NEXT: fcmp s0, s2 +; CHECK-NEXT: orr x9, xzr, #0x1ffffffffffff +; CHECK-NEXT: csel x0, x9, x8, gt +; CHECK-NEXT: ret + %x = call i50 @llvm.fptosi.sat.f32.i50(float %f) + ret i50 %x +} + +define i64 @test_signed_f32_i64(float %f) { +; CHECK-LABEL: test_signed_f32_i64: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs x0, s0 +; CHECK-NEXT: ret + %x = call i64 @llvm.fptosi.sat.f32.i64(float %f) + ret i64 %x +} + +define i100 @test_signed_f32_i100(float %f) { +; CHECK-LABEL: test_signed_f32_i100: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i100 @llvm.fptosi.sat.f32.i100(float %f) + ret i100 %x +} + +define i128 @test_signed_f32_i128(float %f) { +; CHECK-LABEL: test_signed_f32_i128: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i128 @llvm.fptosi.sat.f32.i128(float %f) + ret i128 %x +} + +; +; 32-bit float to unsigned integer +; + +declare i1 @llvm.fptoui.sat.f32.i1 (float) +declare i8 @llvm.fptoui.sat.f32.i8 (float) +declare i13 @llvm.fptoui.sat.f32.i13 (float) +declare i16 @llvm.fptoui.sat.f32.i16 (float) +declare i19 @llvm.fptoui.sat.f32.i19 (float) +declare i32 @llvm.fptoui.sat.f32.i32 (float) +declare i50 @llvm.fptoui.sat.f32.i50 (float) +declare i64 @llvm.fptoui.sat.f32.i64 (float) +declare i100 @llvm.fptoui.sat.f32.i100(float) +declare i128 @llvm.fptoui.sat.f32.i128(float) + +define i1 @test_unsigned_f32_i1(float %f) { +; CHECK-LABEL: test_unsigned_f32_i1: +; CHECK: // %bb.0: +; CHECK-NEXT: fmov s1, #1.00000000 +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzu w8, s0 +; CHECK-NEXT: and w0, w8, #0x1 +; CHECK-NEXT: ret + %x = call i1 @llvm.fptoui.sat.f32.i1(float %f) + ret i1 %x +} + +define i8 @test_unsigned_f32_i8(float %f) { +; CHECK-LABEL: test_unsigned_f32_i8: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI11_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI11_0] +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzu w0, s0 +; CHECK-NEXT: ret + %x = call i8 @llvm.fptoui.sat.f32.i8(float %f) + ret i8 %x +} + +define i13 @test_unsigned_f32_i13(float %f) { +; CHECK-LABEL: test_unsigned_f32_i13: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI12_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI12_0] +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzu w0, s0 +; CHECK-NEXT: ret + %x = call i13 @llvm.fptoui.sat.f32.i13(float %f) + ret i13 %x +} + +define i16 @test_unsigned_f32_i16(float %f) { +; CHECK-LABEL: test_unsigned_f32_i16: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI13_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI13_0] +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzu w0, s0 +; CHECK-NEXT: ret + %x = call i16 @llvm.fptoui.sat.f32.i16(float %f) + ret i16 %x +} + +define i19 @test_unsigned_f32_i19(float %f) { +; CHECK-LABEL: test_unsigned_f32_i19: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI14_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI14_0] +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzu w0, s0 +; CHECK-NEXT: ret + %x = call i19 @llvm.fptoui.sat.f32.i19(float %f) + ret i19 %x +} + +define i32 @test_unsigned_f32_i32(float %f) { +; CHECK-LABEL: test_unsigned_f32_i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzu w0, s0 +; CHECK-NEXT: ret + %x = call i32 @llvm.fptoui.sat.f32.i32(float %f) + ret i32 %x +} + +define i50 @test_unsigned_f32_i50(float %f) { +; CHECK-LABEL: test_unsigned_f32_i50: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI16_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI16_0] +; CHECK-NEXT: fcvtzu x8, s0 +; CHECK-NEXT: orr x9, xzr, #0x3ffffffffffff +; CHECK-NEXT: fcmp s0, s1 +; CHECK-NEXT: csel x0, x9, x8, gt +; CHECK-NEXT: ret + %x = call i50 @llvm.fptoui.sat.f32.i50(float %f) + ret i50 %x +} + +define i64 @test_unsigned_f32_i64(float %f) { +; CHECK-LABEL: test_unsigned_f32_i64: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzu x0, s0 +; CHECK-NEXT: ret + %x = call i64 @llvm.fptoui.sat.f32.i64(float %f) + ret i64 %x +} + +define i100 @test_unsigned_f32_i100(float %f) { +; CHECK-LABEL: test_unsigned_f32_i100: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixunssfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i100 @llvm.fptoui.sat.f32.i100(float %f) + ret i100 %x +} + +define i128 @test_unsigned_f32_i128(float %f) { +; CHECK-LABEL: test_unsigned_f32_i128: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixunssfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i128 @llvm.fptoui.sat.f32.i128(float %f) + ret i128 %x +} + +; +; 64-bit float to signed integer +; + +declare i1 @llvm.fptosi.sat.f64.i1 (double) +declare i8 @llvm.fptosi.sat.f64.i8 (double) +declare i13 @llvm.fptosi.sat.f64.i13 (double) +declare i16 @llvm.fptosi.sat.f64.i16 (double) +declare i19 @llvm.fptosi.sat.f64.i19 (double) +declare i32 @llvm.fptosi.sat.f64.i32 (double) +declare i50 @llvm.fptosi.sat.f64.i50 (double) +declare i64 @llvm.fptosi.sat.f64.i64 (double) +declare i100 @llvm.fptosi.sat.f64.i100(double) +declare i128 @llvm.fptosi.sat.f64.i128(double) + +define i1 @test_signed_f64_i1(double %f) { +; CHECK-LABEL: test_signed_f64_i1: +; CHECK: // %bb.0: +; CHECK-NEXT: fmov d1, #-1.00000000 +; CHECK-NEXT: fmaxnm d0, d0, d1 +; CHECK-NEXT: fmov d1, xzr +; CHECK-NEXT: fminnm d0, d0, d1 +; CHECK-NEXT: fcvtzs w8, d0 +; CHECK-NEXT: and w0, w8, #0x1 +; CHECK-NEXT: ret + %x = call i1 @llvm.fptosi.sat.f64.i1(double %f) + ret i1 %x +} + +define i8 @test_signed_f64_i8(double %f) { +; CHECK-LABEL: test_signed_f64_i8: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI21_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI21_0] +; CHECK-NEXT: adrp x8, .LCPI21_1 +; CHECK-NEXT: ldr d2, [x8, :lo12:.LCPI21_1] +; CHECK-NEXT: fmaxnm d0, d0, d1 +; CHECK-NEXT: fminnm d0, d0, d2 +; CHECK-NEXT: fcvtzs w0, d0 +; CHECK-NEXT: ret + %x = call i8 @llvm.fptosi.sat.f64.i8(double %f) + ret i8 %x +} + +define i13 @test_signed_f64_i13(double %f) { +; CHECK-LABEL: test_signed_f64_i13: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI22_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI22_0] +; CHECK-NEXT: adrp x8, .LCPI22_1 +; CHECK-NEXT: ldr d2, [x8, :lo12:.LCPI22_1] +; CHECK-NEXT: fmaxnm d0, d0, d1 +; CHECK-NEXT: fminnm d0, d0, d2 +; CHECK-NEXT: fcvtzs w0, d0 +; CHECK-NEXT: ret + %x = call i13 @llvm.fptosi.sat.f64.i13(double %f) + ret i13 %x +} + +define i16 @test_signed_f64_i16(double %f) { +; CHECK-LABEL: test_signed_f64_i16: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI23_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI23_0] +; CHECK-NEXT: adrp x8, .LCPI23_1 +; CHECK-NEXT: ldr d2, [x8, :lo12:.LCPI23_1] +; CHECK-NEXT: fmaxnm d0, d0, d1 +; CHECK-NEXT: fminnm d0, d0, d2 +; CHECK-NEXT: fcvtzs w0, d0 +; CHECK-NEXT: ret + %x = call i16 @llvm.fptosi.sat.f64.i16(double %f) + ret i16 %x +} + +define i19 @test_signed_f64_i19(double %f) { +; CHECK-LABEL: test_signed_f64_i19: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI24_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI24_0] +; CHECK-NEXT: adrp x8, .LCPI24_1 +; CHECK-NEXT: ldr d2, [x8, :lo12:.LCPI24_1] +; CHECK-NEXT: fmaxnm d0, d0, d1 +; CHECK-NEXT: fminnm d0, d0, d2 +; CHECK-NEXT: fcvtzs w0, d0 +; CHECK-NEXT: ret + %x = call i19 @llvm.fptosi.sat.f64.i19(double %f) + ret i19 %x +} + +define i32 @test_signed_f64_i32(double %f) { +; CHECK-LABEL: test_signed_f64_i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs w0, d0 +; CHECK-NEXT: ret + %x = call i32 @llvm.fptosi.sat.f64.i32(double %f) + ret i32 %x +} + +define i50 @test_signed_f64_i50(double %f) { +; CHECK-LABEL: test_signed_f64_i50: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI26_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI26_0] +; CHECK-NEXT: adrp x8, .LCPI26_1 +; CHECK-NEXT: ldr d2, [x8, :lo12:.LCPI26_1] +; CHECK-NEXT: fmaxnm d0, d0, d1 +; CHECK-NEXT: fminnm d0, d0, d2 +; CHECK-NEXT: fcvtzs x0, d0 +; CHECK-NEXT: ret + %x = call i50 @llvm.fptosi.sat.f64.i50(double %f) + ret i50 %x +} + +define i64 @test_signed_f64_i64(double %f) { +; CHECK-LABEL: test_signed_f64_i64: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs x0, d0 +; CHECK-NEXT: ret + %x = call i64 @llvm.fptosi.sat.f64.i64(double %f) + ret i64 %x +} + +define i100 @test_signed_f64_i100(double %f) { +; CHECK-LABEL: test_signed_f64_i100: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixdfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i100 @llvm.fptosi.sat.f64.i100(double %f) + ret i100 %x +} + +define i128 @test_signed_f64_i128(double %f) { +; CHECK-LABEL: test_signed_f64_i128: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixdfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i128 @llvm.fptosi.sat.f64.i128(double %f) + ret i128 %x +} + +; +; 64-bit float to unsigned integer +; + +declare i1 @llvm.fptoui.sat.f64.i1 (double) +declare i8 @llvm.fptoui.sat.f64.i8 (double) +declare i13 @llvm.fptoui.sat.f64.i13 (double) +declare i16 @llvm.fptoui.sat.f64.i16 (double) +declare i19 @llvm.fptoui.sat.f64.i19 (double) +declare i32 @llvm.fptoui.sat.f64.i32 (double) +declare i50 @llvm.fptoui.sat.f64.i50 (double) +declare i64 @llvm.fptoui.sat.f64.i64 (double) +declare i100 @llvm.fptoui.sat.f64.i100(double) +declare i128 @llvm.fptoui.sat.f64.i128(double) + +define i1 @test_unsigned_f64_i1(double %f) { +; CHECK-LABEL: test_unsigned_f64_i1: +; CHECK: // %bb.0: +; CHECK-NEXT: fmov d1, #1.00000000 +; CHECK-NEXT: fminnm d0, d0, d1 +; CHECK-NEXT: fcvtzu w8, d0 +; CHECK-NEXT: and w0, w8, #0x1 +; CHECK-NEXT: ret + %x = call i1 @llvm.fptoui.sat.f64.i1(double %f) + ret i1 %x +} + +define i8 @test_unsigned_f64_i8(double %f) { +; CHECK-LABEL: test_unsigned_f64_i8: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI31_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI31_0] +; CHECK-NEXT: fminnm d0, d0, d1 +; CHECK-NEXT: fcvtzu w0, d0 +; CHECK-NEXT: ret + %x = call i8 @llvm.fptoui.sat.f64.i8(double %f) + ret i8 %x +} + +define i13 @test_unsigned_f64_i13(double %f) { +; CHECK-LABEL: test_unsigned_f64_i13: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI32_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI32_0] +; CHECK-NEXT: fminnm d0, d0, d1 +; CHECK-NEXT: fcvtzu w0, d0 +; CHECK-NEXT: ret + %x = call i13 @llvm.fptoui.sat.f64.i13(double %f) + ret i13 %x +} + +define i16 @test_unsigned_f64_i16(double %f) { +; CHECK-LABEL: test_unsigned_f64_i16: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI33_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI33_0] +; CHECK-NEXT: fminnm d0, d0, d1 +; CHECK-NEXT: fcvtzu w0, d0 +; CHECK-NEXT: ret + %x = call i16 @llvm.fptoui.sat.f64.i16(double %f) + ret i16 %x +} + +define i19 @test_unsigned_f64_i19(double %f) { +; CHECK-LABEL: test_unsigned_f64_i19: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI34_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI34_0] +; CHECK-NEXT: fminnm d0, d0, d1 +; CHECK-NEXT: fcvtzu w0, d0 +; CHECK-NEXT: ret + %x = call i19 @llvm.fptoui.sat.f64.i19(double %f) + ret i19 %x +} + +define i32 @test_unsigned_f64_i32(double %f) { +; CHECK-LABEL: test_unsigned_f64_i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzu w0, d0 +; CHECK-NEXT: ret + %x = call i32 @llvm.fptoui.sat.f64.i32(double %f) + ret i32 %x +} + +define i50 @test_unsigned_f64_i50(double %f) { +; CHECK-LABEL: test_unsigned_f64_i50: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI36_0 +; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI36_0] +; CHECK-NEXT: fminnm d0, d0, d1 +; CHECK-NEXT: fcvtzu x0, d0 +; CHECK-NEXT: ret + %x = call i50 @llvm.fptoui.sat.f64.i50(double %f) + ret i50 %x +} + +define i64 @test_unsigned_f64_i64(double %f) { +; CHECK-LABEL: test_unsigned_f64_i64: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzu x0, d0 +; CHECK-NEXT: ret + %x = call i64 @llvm.fptoui.sat.f64.i64(double %f) + ret i64 %x +} + +define i100 @test_unsigned_f64_i100(double %f) { +; CHECK-LABEL: test_unsigned_f64_i100: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixunsdfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i100 @llvm.fptoui.sat.f64.i100(double %f) + ret i100 %x +} + +define i128 @test_unsigned_f64_i128(double %f) { +; CHECK-LABEL: test_unsigned_f64_i128: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixunsdfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i128 @llvm.fptoui.sat.f64.i128(double %f) + ret i128 %x +} + +; +; 16-bit float to signed integer +; + +declare i1 @llvm.fptosi.sat.f16.i1 (half) +declare i8 @llvm.fptosi.sat.f16.i8 (half) +declare i13 @llvm.fptosi.sat.f16.i13 (half) +declare i16 @llvm.fptosi.sat.f16.i16 (half) +declare i19 @llvm.fptosi.sat.f16.i19 (half) +declare i32 @llvm.fptosi.sat.f16.i32 (half) +declare i50 @llvm.fptosi.sat.f16.i50 (half) +declare i64 @llvm.fptosi.sat.f16.i64 (half) +declare i100 @llvm.fptosi.sat.f16.i100(half) +declare i128 @llvm.fptosi.sat.f16.i128(half) + +define i1 @test_signed_f16_i1(half %f) { +; CHECK-LABEL: test_signed_f16_i1: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fmov s1, #-1.00000000 +; CHECK-NEXT: fmaxnm s0, s0, s1 +; CHECK-NEXT: fmov s1, wzr +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzs w8, s0 +; CHECK-NEXT: and w0, w8, #0x1 +; CHECK-NEXT: ret + %x = call i1 @llvm.fptosi.sat.f16.i1(half %f) + ret i1 %x +} + +define i8 @test_signed_f16_i8(half %f) { +; CHECK-LABEL: test_signed_f16_i8: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI41_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI41_0] +; CHECK-NEXT: adrp x8, .LCPI41_1 +; CHECK-NEXT: ldr s2, [x8, :lo12:.LCPI41_1] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fmaxnm s0, s0, s1 +; CHECK-NEXT: fminnm s0, s0, s2 +; CHECK-NEXT: fcvtzs w0, s0 +; CHECK-NEXT: ret + %x = call i8 @llvm.fptosi.sat.f16.i8(half %f) + ret i8 %x +} + +define i13 @test_signed_f16_i13(half %f) { +; CHECK-LABEL: test_signed_f16_i13: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI42_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI42_0] +; CHECK-NEXT: adrp x8, .LCPI42_1 +; CHECK-NEXT: ldr s2, [x8, :lo12:.LCPI42_1] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fmaxnm s0, s0, s1 +; CHECK-NEXT: fminnm s0, s0, s2 +; CHECK-NEXT: fcvtzs w0, s0 +; CHECK-NEXT: ret + %x = call i13 @llvm.fptosi.sat.f16.i13(half %f) + ret i13 %x +} + +define i16 @test_signed_f16_i16(half %f) { +; CHECK-LABEL: test_signed_f16_i16: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI43_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI43_0] +; CHECK-NEXT: adrp x8, .LCPI43_1 +; CHECK-NEXT: ldr s2, [x8, :lo12:.LCPI43_1] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fmaxnm s0, s0, s1 +; CHECK-NEXT: fminnm s0, s0, s2 +; CHECK-NEXT: fcvtzs w0, s0 +; CHECK-NEXT: ret + %x = call i16 @llvm.fptosi.sat.f16.i16(half %f) + ret i16 %x +} + +define i19 @test_signed_f16_i19(half %f) { +; CHECK-LABEL: test_signed_f16_i19: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI44_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI44_0] +; CHECK-NEXT: adrp x8, .LCPI44_1 +; CHECK-NEXT: ldr s2, [x8, :lo12:.LCPI44_1] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fmaxnm s0, s0, s1 +; CHECK-NEXT: fminnm s0, s0, s2 +; CHECK-NEXT: fcvtzs w0, s0 +; CHECK-NEXT: ret + %x = call i19 @llvm.fptosi.sat.f16.i19(half %f) + ret i19 %x +} + +define i32 @test_signed_f16_i32(half %f) { +; CHECK-LABEL: test_signed_f16_i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fcvtzs w0, s0 +; CHECK-NEXT: ret + %x = call i32 @llvm.fptosi.sat.f16.i32(half %f) + ret i32 %x +} + +define i50 @test_signed_f16_i50(half %f) { +; CHECK-LABEL: test_signed_f16_i50: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI46_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI46_0] +; CHECK-NEXT: adrp x8, .LCPI46_1 +; CHECK-NEXT: ldr s2, [x8, :lo12:.LCPI46_1] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: orr x9, xzr, #0xfffe000000000000 +; CHECK-NEXT: fcvtzs x8, s0 +; CHECK-NEXT: fcmp s0, s1 +; CHECK-NEXT: csel x8, x9, x8, lt +; CHECK-NEXT: fcmp s0, s2 +; CHECK-NEXT: orr x9, xzr, #0x1ffffffffffff +; CHECK-NEXT: csel x0, x9, x8, gt +; CHECK-NEXT: ret + %x = call i50 @llvm.fptosi.sat.f16.i50(half %f) + ret i50 %x +} + +define i64 @test_signed_f16_i64(half %f) { +; CHECK-LABEL: test_signed_f16_i64: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fcvtzs x0, s0 +; CHECK-NEXT: ret + %x = call i64 @llvm.fptosi.sat.f16.i64(half %f) + ret i64 %x +} + +define i100 @test_signed_f16_i100(half %f) { +; CHECK-LABEL: test_signed_f16_i100: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i100 @llvm.fptosi.sat.f16.i100(half %f) + ret i100 %x +} + +define i128 @test_signed_f16_i128(half %f) { +; CHECK-LABEL: test_signed_f16_i128: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i128 @llvm.fptosi.sat.f16.i128(half %f) + ret i128 %x +} + +; +; 16-bit float to unsigned integer +; + +declare i1 @llvm.fptoui.sat.f16.i1 (half) +declare i8 @llvm.fptoui.sat.f16.i8 (half) +declare i13 @llvm.fptoui.sat.f16.i13 (half) +declare i16 @llvm.fptoui.sat.f16.i16 (half) +declare i19 @llvm.fptoui.sat.f16.i19 (half) +declare i32 @llvm.fptoui.sat.f16.i32 (half) +declare i50 @llvm.fptoui.sat.f16.i50 (half) +declare i64 @llvm.fptoui.sat.f16.i64 (half) +declare i100 @llvm.fptoui.sat.f16.i100(half) +declare i128 @llvm.fptoui.sat.f16.i128(half) + +define i1 @test_unsigned_f16_i1(half %f) { +; CHECK-LABEL: test_unsigned_f16_i1: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fmov s1, #1.00000000 +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzu w8, s0 +; CHECK-NEXT: and w0, w8, #0x1 +; CHECK-NEXT: ret + %x = call i1 @llvm.fptoui.sat.f16.i1(half %f) + ret i1 %x +} + +define i8 @test_unsigned_f16_i8(half %f) { +; CHECK-LABEL: test_unsigned_f16_i8: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI51_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI51_0] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzu w0, s0 +; CHECK-NEXT: ret + %x = call i8 @llvm.fptoui.sat.f16.i8(half %f) + ret i8 %x +} + +define i13 @test_unsigned_f16_i13(half %f) { +; CHECK-LABEL: test_unsigned_f16_i13: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI52_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI52_0] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzu w0, s0 +; CHECK-NEXT: ret + %x = call i13 @llvm.fptoui.sat.f16.i13(half %f) + ret i13 %x +} + +define i16 @test_unsigned_f16_i16(half %f) { +; CHECK-LABEL: test_unsigned_f16_i16: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI53_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI53_0] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzu w0, s0 +; CHECK-NEXT: ret + %x = call i16 @llvm.fptoui.sat.f16.i16(half %f) + ret i16 %x +} + +define i19 @test_unsigned_f16_i19(half %f) { +; CHECK-LABEL: test_unsigned_f16_i19: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI54_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI54_0] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fminnm s0, s0, s1 +; CHECK-NEXT: fcvtzu w0, s0 +; CHECK-NEXT: ret + %x = call i19 @llvm.fptoui.sat.f16.i19(half %f) + ret i19 %x +} + +define i32 @test_unsigned_f16_i32(half %f) { +; CHECK-LABEL: test_unsigned_f16_i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fcvtzu w0, s0 +; CHECK-NEXT: ret + %x = call i32 @llvm.fptoui.sat.f16.i32(half %f) + ret i32 %x +} + +define i50 @test_unsigned_f16_i50(half %f) { +; CHECK-LABEL: test_unsigned_f16_i50: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI56_0 +; CHECK-NEXT: ldr s1, [x8, :lo12:.LCPI56_0] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fcvtzu x8, s0 +; CHECK-NEXT: orr x9, xzr, #0x3ffffffffffff +; CHECK-NEXT: fcmp s0, s1 +; CHECK-NEXT: csel x0, x9, x8, gt +; CHECK-NEXT: ret + %x = call i50 @llvm.fptoui.sat.f16.i50(half %f) + ret i50 %x +} + +define i64 @test_unsigned_f16_i64(half %f) { +; CHECK-LABEL: test_unsigned_f16_i64: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fcvtzu x0, s0 +; CHECK-NEXT: ret + %x = call i64 @llvm.fptoui.sat.f16.i64(half %f) + ret i64 %x +} + +define i100 @test_unsigned_f16_i100(half %f) { +; CHECK-LABEL: test_unsigned_f16_i100: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixunssfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i100 @llvm.fptoui.sat.f16.i100(half %f) + ret i100 %x +} + +define i128 @test_unsigned_f16_i128(half %f) { +; CHECK-LABEL: test_unsigned_f16_i128: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixunssfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i128 @llvm.fptoui.sat.f16.i128(half %f) + ret i128 %x +} + +; +; 128-bit float to signed integer +; + +declare i1 @llvm.fptosi.sat.f128.i1 (fp128) +declare i8 @llvm.fptosi.sat.f128.i8 (fp128) +declare i13 @llvm.fptosi.sat.f128.i13 (fp128) +declare i16 @llvm.fptosi.sat.f128.i16 (fp128) +declare i19 @llvm.fptosi.sat.f128.i19 (fp128) +declare i32 @llvm.fptosi.sat.f128.i32 (fp128) +declare i50 @llvm.fptosi.sat.f128.i50 (fp128) +declare i64 @llvm.fptosi.sat.f128.i64 (fp128) +declare i100 @llvm.fptosi.sat.f128.i100(fp128) +declare i128 @llvm.fptosi.sat.f128.i128(fp128) + +define i1 @test_signed_f128_i1(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i1: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x1 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: and w0, w0, #0x1 +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i1 @llvm.fptosi.sat.f128.i1(fp128 %f) + ret i1 %x +} + +define i8 @test_signed_f128_i8(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i8: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x8 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i8 @llvm.fptosi.sat.f128.i8(fp128 %f) + ret i8 %x +} + +define i13 @test_signed_f128_i13(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i13: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #13 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i13 @llvm.fptosi.sat.f128.i13(fp128 %f) + ret i13 %x +} + +define i16 @test_signed_f128_i16(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i16: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x10 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i16 @llvm.fptosi.sat.f128.i16(fp128 %f) + ret i16 %x +} + +define i19 @test_signed_f128_i19(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i19: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #19 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i19 @llvm.fptosi.sat.f128.i19(fp128 %f) + ret i19 %x +} + +define i32 @test_signed_f128_i32(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i32: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i32 @llvm.fptosi.sat.f128.i32(fp128 %f) + ret i32 %x +} + +define i50 @test_signed_f128_i50(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i50: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #50 +; CHECK-NEXT: bl __fixtfdi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i50 @llvm.fptosi.sat.f128.i50(fp128 %f) + ret i50 %x +} + +define i64 @test_signed_f128_i64(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i64: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x40 +; CHECK-NEXT: bl __fixtfdi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i64 @llvm.fptosi.sat.f128.i64(fp128 %f) + ret i64 %x +} + +define i100 @test_signed_f128_i100(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i100: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixtfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i100 @llvm.fptosi.sat.f128.i100(fp128 %f) + ret i100 %x +} + +define i128 @test_signed_f128_i128(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i128: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixtfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i128 @llvm.fptosi.sat.f128.i128(fp128 %f) + ret i128 %x +} + +; +; 128-bit float to unsigned integer +; + +declare i1 @llvm.fptoui.sat.f128.i1 (fp128) +declare i8 @llvm.fptoui.sat.f128.i8 (fp128) +declare i13 @llvm.fptoui.sat.f128.i13 (fp128) +declare i16 @llvm.fptoui.sat.f128.i16 (fp128) +declare i19 @llvm.fptoui.sat.f128.i19 (fp128) +declare i32 @llvm.fptoui.sat.f128.i32 (fp128) +declare i50 @llvm.fptoui.sat.f128.i50 (fp128) +declare i64 @llvm.fptoui.sat.f128.i64 (fp128) +declare i100 @llvm.fptoui.sat.f128.i100(fp128) +declare i128 @llvm.fptoui.sat.f128.i128(fp128) + +define i1 @test_unsigned_f128_i1(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i1: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x1 +; CHECK-NEXT: bl __fixunstfsi_sat +; CHECK-NEXT: and w0, w0, #0x1 +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i1 @llvm.fptoui.sat.f128.i1(fp128 %f) + ret i1 %x +} + +define i8 @test_unsigned_f128_i8(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i8: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x8 +; CHECK-NEXT: bl __fixunstfsi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i8 @llvm.fptoui.sat.f128.i8(fp128 %f) + ret i8 %x +} + +define i13 @test_unsigned_f128_i13(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i13: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #13 +; CHECK-NEXT: bl __fixunstfsi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i13 @llvm.fptoui.sat.f128.i13(fp128 %f) + ret i13 %x +} + +define i16 @test_unsigned_f128_i16(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i16: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x10 +; CHECK-NEXT: bl __fixunstfsi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i16 @llvm.fptoui.sat.f128.i16(fp128 %f) + ret i16 %x +} + +define i19 @test_unsigned_f128_i19(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i19: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #19 +; CHECK-NEXT: bl __fixunstfsi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i19 @llvm.fptoui.sat.f128.i19(fp128 %f) + ret i19 %x +} + +define i32 @test_unsigned_f128_i32(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i32: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: bl __fixunstfsi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i32 @llvm.fptoui.sat.f128.i32(fp128 %f) + ret i32 %x +} + +define i50 @test_unsigned_f128_i50(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i50: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #50 +; CHECK-NEXT: bl __fixunstfdi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i50 @llvm.fptoui.sat.f128.i50(fp128 %f) + ret i50 %x +} + +define i64 @test_unsigned_f128_i64(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i64: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x40 +; CHECK-NEXT: bl __fixunstfdi_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i64 @llvm.fptoui.sat.f128.i64(fp128 %f) + ret i64 %x +} + +define i100 @test_unsigned_f128_i100(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i100: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixunstfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i100 @llvm.fptoui.sat.f128.i100(fp128 %f) + ret i100 %x +} + +define i128 @test_unsigned_f128_i128(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i128: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixunstfti_sat +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call i128 @llvm.fptoui.sat.f128.i128(fp128 %f) + ret i128 %x +} Index: test/CodeGen/AArch64/fptoi-sat-vector.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/fptoi-sat-vector.ll @@ -0,0 +1,1173 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=aarch64 < %s | FileCheck %s + +; +; Float to signed 32-bit -- Vector size variation +; + +declare <1 x i32> @llvm.fptosi.sat.v1f32.v1i32 (<1 x float>) +declare <2 x i32> @llvm.fptosi.sat.v2f32.v2i32 (<2 x float>) +declare <3 x i32> @llvm.fptosi.sat.v3f32.v3i32 (<3 x float>) +declare <4 x i32> @llvm.fptosi.sat.v4f32.v4i32 (<4 x float>) +declare <5 x i32> @llvm.fptosi.sat.v5f32.v5i32 (<5 x float>) +declare <6 x i32> @llvm.fptosi.sat.v6f32.v6i32 (<6 x float>) +declare <7 x i32> @llvm.fptosi.sat.v7f32.v7i32 (<7 x float>) +declare <8 x i32> @llvm.fptosi.sat.v8f32.v8i32 (<8 x float>) + +define <1 x i32> @test_signed_v1f32_v1i32(<1 x float> %f) { +; CHECK-LABEL: test_signed_v1f32_v1i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs v0.2s, v0.2s +; CHECK-NEXT: ret + %x = call <1 x i32> @llvm.fptosi.sat.v1f32.v1i32(<1 x float> %f) + ret <1 x i32> %x +} + +define <2 x i32> @test_signed_v2f32_v2i32(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs v0.2s, v0.2s +; CHECK-NEXT: ret + %x = call <2 x i32> @llvm.fptosi.sat.v2f32.v2i32(<2 x float> %f) + ret <2 x i32> %x +} + +define <3 x i32> @test_signed_v3f32_v3i32(<3 x float> %f) { +; CHECK-LABEL: test_signed_v3f32_v3i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: ret + %x = call <3 x i32> @llvm.fptosi.sat.v3f32.v3i32(<3 x float> %f) + ret <3 x i32> %x +} + +define <4 x i32> @test_signed_v4f32_v4i32(<4 x float> %f) { +; CHECK-LABEL: test_signed_v4f32_v4i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: ret + %x = call <4 x i32> @llvm.fptosi.sat.v4f32.v4i32(<4 x float> %f) + ret <4 x i32> %x +} + +define <5 x i32> @test_signed_v5f32_v5i32(<5 x float> %f) { +; CHECK-LABEL: test_signed_v5f32_v5i32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $s0 killed $s0 def $q0 +; CHECK-NEXT: // kill: def $s1 killed $s1 def $q1 +; CHECK-NEXT: // kill: def $s2 killed $s2 def $q2 +; CHECK-NEXT: // kill: def $s4 killed $s4 def $q4 +; CHECK-NEXT: // kill: def $s3 killed $s3 def $q3 +; CHECK-NEXT: mov v0.s[1], v1.s[0] +; CHECK-NEXT: mov v0.s[2], v2.s[0] +; CHECK-NEXT: mov v0.s[3], v3.s[0] +; CHECK-NEXT: fcvtzs v4.4s, v4.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: mov w1, v0.s[1] +; CHECK-NEXT: mov w2, v0.s[2] +; CHECK-NEXT: mov w3, v0.s[3] +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: fmov w4, s4 +; CHECK-NEXT: ret + %x = call <5 x i32> @llvm.fptosi.sat.v5f32.v5i32(<5 x float> %f) + ret <5 x i32> %x +} + +define <6 x i32> @test_signed_v6f32_v6i32(<6 x float> %f) { +; CHECK-LABEL: test_signed_v6f32_v6i32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $s0 killed $s0 def $q0 +; CHECK-NEXT: // kill: def $s1 killed $s1 def $q1 +; CHECK-NEXT: // kill: def $s4 killed $s4 def $q4 +; CHECK-NEXT: // kill: def $s2 killed $s2 def $q2 +; CHECK-NEXT: // kill: def $s5 killed $s5 def $q5 +; CHECK-NEXT: // kill: def $s3 killed $s3 def $q3 +; CHECK-NEXT: mov v0.s[1], v1.s[0] +; CHECK-NEXT: mov v0.s[2], v2.s[0] +; CHECK-NEXT: mov v4.s[1], v5.s[0] +; CHECK-NEXT: mov v0.s[3], v3.s[0] +; CHECK-NEXT: fcvtzs v1.4s, v4.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: mov w5, v1.s[1] +; CHECK-NEXT: mov w1, v0.s[1] +; CHECK-NEXT: mov w2, v0.s[2] +; CHECK-NEXT: mov w3, v0.s[3] +; CHECK-NEXT: fmov w4, s1 +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: ret + %x = call <6 x i32> @llvm.fptosi.sat.v6f32.v6i32(<6 x float> %f) + ret <6 x i32> %x +} + +define <7 x i32> @test_signed_v7f32_v7i32(<7 x float> %f) { +; CHECK-LABEL: test_signed_v7f32_v7i32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $s0 killed $s0 def $q0 +; CHECK-NEXT: // kill: def $s4 killed $s4 def $q4 +; CHECK-NEXT: // kill: def $s1 killed $s1 def $q1 +; CHECK-NEXT: // kill: def $s5 killed $s5 def $q5 +; CHECK-NEXT: // kill: def $s2 killed $s2 def $q2 +; CHECK-NEXT: // kill: def $s6 killed $s6 def $q6 +; CHECK-NEXT: // kill: def $s3 killed $s3 def $q3 +; CHECK-NEXT: mov v0.s[1], v1.s[0] +; CHECK-NEXT: mov v4.s[1], v5.s[0] +; CHECK-NEXT: mov v0.s[2], v2.s[0] +; CHECK-NEXT: mov v4.s[2], v6.s[0] +; CHECK-NEXT: mov v0.s[3], v3.s[0] +; CHECK-NEXT: fcvtzs v1.4s, v4.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: mov w5, v1.s[1] +; CHECK-NEXT: mov w6, v1.s[2] +; CHECK-NEXT: mov w1, v0.s[1] +; CHECK-NEXT: mov w2, v0.s[2] +; CHECK-NEXT: mov w3, v0.s[3] +; CHECK-NEXT: fmov w4, s1 +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: ret + %x = call <7 x i32> @llvm.fptosi.sat.v7f32.v7i32(<7 x float> %f) + ret <7 x i32> %x +} + +define <8 x i32> @test_signed_v8f32_v8i32(<8 x float> %f) { +; CHECK-LABEL: test_signed_v8f32_v8i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: fcvtzs v1.4s, v1.4s +; CHECK-NEXT: ret + %x = call <8 x i32> @llvm.fptosi.sat.v8f32.v8i32(<8 x float> %f) + ret <8 x i32> %x +} + +; +; Double to signed 32-bit -- Vector size variation +; + +declare <1 x i32> @llvm.fptosi.sat.v1f64.v1i32 (<1 x double>) +declare <2 x i32> @llvm.fptosi.sat.v2f64.v2i32 (<2 x double>) +declare <3 x i32> @llvm.fptosi.sat.v3f64.v3i32 (<3 x double>) +declare <4 x i32> @llvm.fptosi.sat.v4f64.v4i32 (<4 x double>) +declare <5 x i32> @llvm.fptosi.sat.v5f64.v5i32 (<5 x double>) +declare <6 x i32> @llvm.fptosi.sat.v6f64.v6i32 (<6 x double>) + +define <1 x i32> @test_signed_v1f64_v1i32(<1 x double> %f) { +; CHECK-LABEL: test_signed_v1f64_v1i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs w8, d0 +; CHECK-NEXT: fmov s0, w8 +; CHECK-NEXT: ret + %x = call <1 x i32> @llvm.fptosi.sat.v1f64.v1i32(<1 x double> %f) + ret <1 x i32> %x +} + +define <2 x i32> @test_signed_v2f64_v2i32(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i32> @llvm.fptosi.sat.v2f64.v2i32(<2 x double> %f) + ret <2 x i32> %x +} + +define <3 x i32> @test_signed_v3f64_v3i32(<3 x double> %f) { +; CHECK-LABEL: test_signed_v3f64_v3i32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NEXT: // kill: def $d1 killed $d1 def $q1 +; CHECK-NEXT: // kill: def $d2 killed $d2 def $q2 +; CHECK-NEXT: mov v0.d[1], v1.d[0] +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: fcvtzs v2.2d, v2.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: xtn2 v0.4s, v2.2d +; CHECK-NEXT: ret + %x = call <3 x i32> @llvm.fptosi.sat.v3f64.v3i32(<3 x double> %f) + ret <3 x i32> %x +} + +define <4 x i32> @test_signed_v4f64_v4i32(<4 x double> %f) { +; CHECK-LABEL: test_signed_v4f64_v4i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: fcvtzs v1.2d, v1.2d +; CHECK-NEXT: xtn2 v0.4s, v1.2d +; CHECK-NEXT: ret + %x = call <4 x i32> @llvm.fptosi.sat.v4f64.v4i32(<4 x double> %f) + ret <4 x i32> %x +} + +define <5 x i32> @test_signed_v5f64_v5i32(<5 x double> %f) { +; CHECK-LABEL: test_signed_v5f64_v5i32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NEXT: // kill: def $d2 killed $d2 def $q2 +; CHECK-NEXT: // kill: def $d1 killed $d1 def $q1 +; CHECK-NEXT: // kill: def $d4 killed $d4 def $q4 +; CHECK-NEXT: // kill: def $d3 killed $d3 def $q3 +; CHECK-NEXT: mov v0.d[1], v1.d[0] +; CHECK-NEXT: mov v2.d[1], v3.d[0] +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: fcvtzs v4.2d, v4.2d +; CHECK-NEXT: fcvtzs v2.2d, v2.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: xtn v1.2s, v4.2d +; CHECK-NEXT: xtn2 v0.4s, v2.2d +; CHECK-NEXT: mov w1, v0.s[1] +; CHECK-NEXT: mov w2, v0.s[2] +; CHECK-NEXT: mov w3, v0.s[3] +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: fmov w4, s1 +; CHECK-NEXT: ret + %x = call <5 x i32> @llvm.fptosi.sat.v5f64.v5i32(<5 x double> %f) + ret <5 x i32> %x +} + +define <6 x i32> @test_signed_v6f64_v6i32(<6 x double> %f) { +; CHECK-LABEL: test_signed_v6f64_v6i32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NEXT: // kill: def $d4 killed $d4 def $q4 +; CHECK-NEXT: // kill: def $d2 killed $d2 def $q2 +; CHECK-NEXT: // kill: def $d1 killed $d1 def $q1 +; CHECK-NEXT: // kill: def $d5 killed $d5 def $q5 +; CHECK-NEXT: // kill: def $d3 killed $d3 def $q3 +; CHECK-NEXT: mov v0.d[1], v1.d[0] +; CHECK-NEXT: mov v4.d[1], v5.d[0] +; CHECK-NEXT: mov v2.d[1], v3.d[0] +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: fcvtzs v1.2d, v2.2d +; CHECK-NEXT: fcvtzs v2.2d, v4.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: xtn v2.2s, v2.2d +; CHECK-NEXT: xtn2 v0.4s, v1.2d +; CHECK-NEXT: mov w1, v0.s[1] +; CHECK-NEXT: mov w2, v0.s[2] +; CHECK-NEXT: mov w3, v0.s[3] +; CHECK-NEXT: mov w5, v2.s[1] +; CHECK-NEXT: fmov w0, s0 +; CHECK-NEXT: fmov w4, s2 +; CHECK-NEXT: ret + %x = call <6 x i32> @llvm.fptosi.sat.v6f64.v6i32(<6 x double> %f) + ret <6 x i32> %x +} + +; +; FP128 to signed 32-bit -- Vector size variation +; + +declare <1 x i32> @llvm.fptosi.sat.v1f128.v1i32 (<1 x fp128>) +declare <2 x i32> @llvm.fptosi.sat.v2f128.v2i32 (<2 x fp128>) +declare <3 x i32> @llvm.fptosi.sat.v3f128.v3i32 (<3 x fp128>) +declare <4 x i32> @llvm.fptosi.sat.v4f128.v4i32 (<4 x fp128>) + +define <1 x i32> @test_signed_v1f128_v1i32(<1 x fp128> %f) { +; CHECK-LABEL: test_signed_v1f128_v1i32: +; CHECK: // %bb.0: +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: fmov s0, w0 +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret + %x = call <1 x i32> @llvm.fptosi.sat.v1f128.v1i32(<1 x fp128> %f) + ret <1 x i32> %x +} + +define <2 x i32> @test_signed_v2f128_v2i32(<2 x fp128> %f) { +; CHECK-LABEL: test_signed_v2f128_v2i32: +; CHECK: // %bb.0: +; CHECK-NEXT: sub sp, sp, #32 // =32 +; CHECK-NEXT: stp x19, x30, [sp, #16] // 16-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w19, -16 +; CHECK-NEXT: str q0, [sp] // 16-byte Folded Spill +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: mov v0.16b, v1.16b +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov w19, w0 +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: fmov s0, w0 +; CHECK-NEXT: mov v0.s[1], w19 +; CHECK-NEXT: ldp x19, x30, [sp, #16] // 16-byte Folded Reload +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0 +; CHECK-NEXT: add sp, sp, #32 // =32 +; CHECK-NEXT: ret + %x = call <2 x i32> @llvm.fptosi.sat.v2f128.v2i32(<2 x fp128> %f) + ret <2 x i32> %x +} + +define <3 x i32> @test_signed_v3f128_v3i32(<3 x fp128> %f) { +; CHECK-LABEL: test_signed_v3f128_v3i32: +; CHECK: // %bb.0: +; CHECK-NEXT: sub sp, sp, #48 // =48 +; CHECK-NEXT: stp x19, x30, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w19, -16 +; CHECK-NEXT: stp q0, q2, [sp] // 32-byte Folded Spill +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: mov v0.16b, v1.16b +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov w19, w0 +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: fmov s0, w0 +; CHECK-NEXT: mov v0.s[1], w19 +; CHECK-NEXT: str q0, [sp] // 16-byte Folded Spill +; CHECK-NEXT: ldr q0, [sp, #16] // 16-byte Folded Reload +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: ldp x19, x30, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: mov v0.s[2], w0 +; CHECK-NEXT: add sp, sp, #48 // =48 +; CHECK-NEXT: ret + %x = call <3 x i32> @llvm.fptosi.sat.v3f128.v3i32(<3 x fp128> %f) + ret <3 x i32> %x +} + +define <4 x i32> @test_signed_v4f128_v4i32(<4 x fp128> %f) { +; CHECK-LABEL: test_signed_v4f128_v4i32: +; CHECK: // %bb.0: +; CHECK-NEXT: sub sp, sp, #64 // =64 +; CHECK-NEXT: stp x19, x30, [sp, #48] // 16-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 64 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w19, -16 +; CHECK-NEXT: str q0, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: mov v0.16b, v1.16b +; CHECK-NEXT: stp q2, q3, [sp] // 32-byte Folded Spill +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr q0, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: mov w19, w0 +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: fmov s0, w0 +; CHECK-NEXT: mov v0.s[1], w19 +; CHECK-NEXT: str q0, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr q0, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: mov v0.s[2], w0 +; CHECK-NEXT: str q0, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: ldr q0, [sp, #16] // 16-byte Folded Reload +; CHECK-NEXT: orr w0, wzr, #0x20 +; CHECK-NEXT: bl __fixtfsi_sat +; CHECK-NEXT: ldr q0, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: ldp x19, x30, [sp, #48] // 16-byte Folded Reload +; CHECK-NEXT: mov v0.s[3], w0 +; CHECK-NEXT: add sp, sp, #64 // =64 +; CHECK-NEXT: ret + %x = call <4 x i32> @llvm.fptosi.sat.v4f128.v4i32(<4 x fp128> %f) + ret <4 x i32> %x +} + +; +; FP16 to signed 32-bit -- Vector size variation +; + +declare <1 x i32> @llvm.fptosi.sat.v1f16.v1i32 (<1 x half>) +declare <2 x i32> @llvm.fptosi.sat.v2f16.v2i32 (<2 x half>) +declare <3 x i32> @llvm.fptosi.sat.v3f16.v3i32 (<3 x half>) +declare <4 x i32> @llvm.fptosi.sat.v4f16.v4i32 (<4 x half>) +declare <5 x i32> @llvm.fptosi.sat.v5f16.v5i32 (<5 x half>) +declare <6 x i32> @llvm.fptosi.sat.v6f16.v6i32 (<6 x half>) +declare <7 x i32> @llvm.fptosi.sat.v7f16.v7i32 (<7 x half>) +declare <8 x i32> @llvm.fptosi.sat.v8f16.v8i32 (<8 x half>) + +define <1 x i32> @test_signed_v1f16_v1i32(<1 x half> %f) { +; CHECK-LABEL: test_signed_v1f16_v1i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fcvtzs w8, s0 +; CHECK-NEXT: fmov s0, w8 +; CHECK-NEXT: ret + %x = call <1 x i32> @llvm.fptosi.sat.v1f16.v1i32(<1 x half> %f) + ret <1 x i32> %x +} + +define <2 x i32> @test_signed_v2f16_v2i32(<2 x half> %f) { +; CHECK-LABEL: test_signed_v2f16_v2i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v0.4s, v0.4h +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0 +; CHECK-NEXT: ret + %x = call <2 x i32> @llvm.fptosi.sat.v2f16.v2i32(<2 x half> %f) + ret <2 x i32> %x +} + +define <3 x i32> @test_signed_v3f16_v3i32(<3 x half> %f) { +; CHECK-LABEL: test_signed_v3f16_v3i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v0.4s, v0.4h +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: ret + %x = call <3 x i32> @llvm.fptosi.sat.v3f16.v3i32(<3 x half> %f) + ret <3 x i32> %x +} + +define <4 x i32> @test_signed_v4f16_v4i32(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v0.4s, v0.4h +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: ret + %x = call <4 x i32> @llvm.fptosi.sat.v4f16.v4i32(<4 x half> %f) + ret <4 x i32> %x +} + +define <5 x i32> @test_signed_v5f16_v5i32(<5 x half> %f) { +; CHECK-LABEL: test_signed_v5f16_v5i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v1.4s, v0.4h +; CHECK-NEXT: fcvtl2 v0.4s, v0.8h +; CHECK-NEXT: fcvtzs v1.4s, v1.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: mov w1, v1.s[1] +; CHECK-NEXT: mov w2, v1.s[2] +; CHECK-NEXT: mov w3, v1.s[3] +; CHECK-NEXT: fmov w4, s0 +; CHECK-NEXT: fmov w0, s1 +; CHECK-NEXT: ret + %x = call <5 x i32> @llvm.fptosi.sat.v5f16.v5i32(<5 x half> %f) + ret <5 x i32> %x +} + +define <6 x i32> @test_signed_v6f16_v6i32(<6 x half> %f) { +; CHECK-LABEL: test_signed_v6f16_v6i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v1.4s, v0.4h +; CHECK-NEXT: fcvtl2 v0.4s, v0.8h +; CHECK-NEXT: fcvtzs v1.4s, v1.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: mov w5, v0.s[1] +; CHECK-NEXT: mov w1, v1.s[1] +; CHECK-NEXT: mov w2, v1.s[2] +; CHECK-NEXT: mov w3, v1.s[3] +; CHECK-NEXT: fmov w4, s0 +; CHECK-NEXT: fmov w0, s1 +; CHECK-NEXT: ret + %x = call <6 x i32> @llvm.fptosi.sat.v6f16.v6i32(<6 x half> %f) + ret <6 x i32> %x +} + +define <7 x i32> @test_signed_v7f16_v7i32(<7 x half> %f) { +; CHECK-LABEL: test_signed_v7f16_v7i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v1.4s, v0.4h +; CHECK-NEXT: fcvtl2 v0.4s, v0.8h +; CHECK-NEXT: fcvtzs v1.4s, v1.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: mov w5, v0.s[1] +; CHECK-NEXT: mov w6, v0.s[2] +; CHECK-NEXT: mov w1, v1.s[1] +; CHECK-NEXT: mov w2, v1.s[2] +; CHECK-NEXT: mov w3, v1.s[3] +; CHECK-NEXT: fmov w4, s0 +; CHECK-NEXT: fmov w0, s1 +; CHECK-NEXT: ret + %x = call <7 x i32> @llvm.fptosi.sat.v7f16.v7i32(<7 x half> %f) + ret <7 x i32> %x +} + +define <8 x i32> @test_signed_v8f16_v8i32(<8 x half> %f) { +; CHECK-LABEL: test_signed_v8f16_v8i32: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl2 v1.4s, v0.8h +; CHECK-NEXT: fcvtl v0.4s, v0.4h +; CHECK-NEXT: fcvtzs v1.4s, v1.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: ret + %x = call <8 x i32> @llvm.fptosi.sat.v8f16.v8i32(<8 x half> %f) + ret <8 x i32> %x +} + +; +; 2-Vector float to signed integer -- result size variation +; + +declare <2 x i1> @llvm.fptosi.sat.v2f32.v2i1 (<2 x float>) +declare <2 x i8> @llvm.fptosi.sat.v2f32.v2i8 (<2 x float>) +declare <2 x i13> @llvm.fptosi.sat.v2f32.v2i13 (<2 x float>) +declare <2 x i16> @llvm.fptosi.sat.v2f32.v2i16 (<2 x float>) +declare <2 x i19> @llvm.fptosi.sat.v2f32.v2i19 (<2 x float>) +declare <2 x i50> @llvm.fptosi.sat.v2f32.v2i50 (<2 x float>) +declare <2 x i64> @llvm.fptosi.sat.v2f32.v2i64 (<2 x float>) +declare <2 x i100> @llvm.fptosi.sat.v2f32.v2i100(<2 x float>) +declare <2 x i128> @llvm.fptosi.sat.v2f32.v2i128(<2 x float>) + +define <2 x i1> @test_signed_v2f32_v2i1(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i1: +; CHECK: // %bb.0: +; CHECK-NEXT: fmov v1.2s, #-1.00000000 +; CHECK-NEXT: fmaxnm v0.2s, v0.2s, v1.2s +; CHECK-NEXT: movi d1, #0000000000000000 +; CHECK-NEXT: fminnm v0.2s, v0.2s, v1.2s +; CHECK-NEXT: fcvtzs v0.2s, v0.2s +; CHECK-NEXT: ret + %x = call <2 x i1> @llvm.fptosi.sat.v2f32.v2i1(<2 x float> %f) + ret <2 x i1> %x +} + +define <2 x i8> @test_signed_v2f32_v2i8(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i8: +; CHECK: // %bb.0: +; CHECK-NEXT: movi v1.2s, #195, lsl #24 +; CHECK-NEXT: mov w8, #1123942400 +; CHECK-NEXT: fmaxnm v0.2s, v0.2s, v1.2s +; CHECK-NEXT: dup v1.2s, w8 +; CHECK-NEXT: fminnm v0.2s, v0.2s, v1.2s +; CHECK-NEXT: fcvtzs v0.2s, v0.2s +; CHECK-NEXT: ret + %x = call <2 x i8> @llvm.fptosi.sat.v2f32.v2i8(<2 x float> %f) + ret <2 x i8> %x +} + +define <2 x i13> @test_signed_v2f32_v2i13(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i13: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, #-981467136 +; CHECK-NEXT: mov w9, #61440 +; CHECK-NEXT: movk w9, #17791, lsl #16 +; CHECK-NEXT: dup v1.2s, w8 +; CHECK-NEXT: fmaxnm v0.2s, v0.2s, v1.2s +; CHECK-NEXT: dup v1.2s, w9 +; CHECK-NEXT: fminnm v0.2s, v0.2s, v1.2s +; CHECK-NEXT: fcvtzs v0.2s, v0.2s +; CHECK-NEXT: ret + %x = call <2 x i13> @llvm.fptosi.sat.v2f32.v2i13(<2 x float> %f) + ret <2 x i13> %x +} + +define <2 x i16> @test_signed_v2f32_v2i16(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i16: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, #65024 +; CHECK-NEXT: movi v1.2s, #199, lsl #24 +; CHECK-NEXT: movk w8, #18175, lsl #16 +; CHECK-NEXT: fmaxnm v0.2s, v0.2s, v1.2s +; CHECK-NEXT: dup v1.2s, w8 +; CHECK-NEXT: fminnm v0.2s, v0.2s, v1.2s +; CHECK-NEXT: fcvtzs v0.2s, v0.2s +; CHECK-NEXT: ret + %x = call <2 x i16> @llvm.fptosi.sat.v2f32.v2i16(<2 x float> %f) + ret <2 x i16> %x +} + +define <2 x i19> @test_signed_v2f32_v2i19(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i19: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, #-931135488 +; CHECK-NEXT: mov w9, #65472 +; CHECK-NEXT: movk w9, #18559, lsl #16 +; CHECK-NEXT: dup v1.2s, w8 +; CHECK-NEXT: fmaxnm v0.2s, v0.2s, v1.2s +; CHECK-NEXT: dup v1.2s, w9 +; CHECK-NEXT: fminnm v0.2s, v0.2s, v1.2s +; CHECK-NEXT: fcvtzs v0.2s, v0.2s +; CHECK-NEXT: ret + %x = call <2 x i19> @llvm.fptosi.sat.v2f32.v2i19(<2 x float> %f) + ret <2 x i19> %x +} + +define <2 x i32> @test_signed_v2f32_v2i32_duplicate(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i32_duplicate: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs v0.2s, v0.2s +; CHECK-NEXT: ret + %x = call <2 x i32> @llvm.fptosi.sat.v2f32.v2i32(<2 x float> %f) + ret <2 x i32> %x +} + +define <2 x i50> @test_signed_v2f32_v2i50(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i50: +; CHECK: // %bb.0: +; CHECK-NEXT: mov x8, #-4395513236313604096 +; CHECK-NEXT: mov x9, #-16 +; CHECK-NEXT: fcvtl v0.2d, v0.2s +; CHECK-NEXT: movk x9, #17151, lsl #48 +; CHECK-NEXT: dup v1.2d, x8 +; CHECK-NEXT: fmaxnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: dup v1.2d, x9 +; CHECK-NEXT: fminnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i50> @llvm.fptosi.sat.v2f32.v2i50(<2 x float> %f) + ret <2 x i50> %x +} + +define <2 x i64> @test_signed_v2f32_v2i64(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i64: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v0.2d, v0.2s +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i64> @llvm.fptosi.sat.v2f32.v2i64(<2 x float> %f) + ret <2 x i64> %x +} + +define <2 x i100> @test_signed_v2f32_v2i100(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i100: +; CHECK: // %bb.0: +; CHECK-NEXT: sub sp, sp, #48 // =48 +; CHECK-NEXT: str x20, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: stp x19, x30, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w19, -16 +; CHECK-NEXT: .cfi_offset w20, -32 +; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NEXT: str q0, [sp] // 16-byte Folded Spill +; CHECK-NEXT: mov s0, v0.s[1] +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: mov x19, x0 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov x20, x1 +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $q0 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: mov x2, x19 +; CHECK-NEXT: mov x3, x20 +; CHECK-NEXT: ldp x19, x30, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: ldr x20, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: fmov d0, x0 +; CHECK-NEXT: mov v0.d[1], x1 +; CHECK-NEXT: fmov x0, d0 +; CHECK-NEXT: add sp, sp, #48 // =48 +; CHECK-NEXT: ret + %x = call <2 x i100> @llvm.fptosi.sat.v2f32.v2i100(<2 x float> %f) + ret <2 x i100> %x +} + +define <2 x i128> @test_signed_v2f32_v2i128(<2 x float> %f) { +; CHECK-LABEL: test_signed_v2f32_v2i128: +; CHECK: // %bb.0: +; CHECK-NEXT: sub sp, sp, #48 // =48 +; CHECK-NEXT: str x20, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: stp x19, x30, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w19, -16 +; CHECK-NEXT: .cfi_offset w20, -32 +; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NEXT: str q0, [sp] // 16-byte Folded Spill +; CHECK-NEXT: mov s0, v0.s[1] +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: mov x19, x0 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov x20, x1 +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $q0 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: mov x2, x19 +; CHECK-NEXT: mov x3, x20 +; CHECK-NEXT: ldp x19, x30, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: ldr x20, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: fmov d0, x0 +; CHECK-NEXT: mov v0.d[1], x1 +; CHECK-NEXT: fmov x0, d0 +; CHECK-NEXT: add sp, sp, #48 // =48 +; CHECK-NEXT: ret + %x = call <2 x i128> @llvm.fptosi.sat.v2f32.v2i128(<2 x float> %f) + ret <2 x i128> %x +} + +; +; 2-Vector double to signed integer -- result size variation +; + +declare <2 x i1> @llvm.fptosi.sat.v2f64.v2i1 (<2 x double>) +declare <2 x i8> @llvm.fptosi.sat.v2f64.v2i8 (<2 x double>) +declare <2 x i13> @llvm.fptosi.sat.v2f64.v2i13 (<2 x double>) +declare <2 x i16> @llvm.fptosi.sat.v2f64.v2i16 (<2 x double>) +declare <2 x i19> @llvm.fptosi.sat.v2f64.v2i19 (<2 x double>) +declare <2 x i50> @llvm.fptosi.sat.v2f64.v2i50 (<2 x double>) +declare <2 x i64> @llvm.fptosi.sat.v2f64.v2i64 (<2 x double>) +declare <2 x i100> @llvm.fptosi.sat.v2f64.v2i100(<2 x double>) +declare <2 x i128> @llvm.fptosi.sat.v2f64.v2i128(<2 x double>) + +define <2 x i1> @test_signed_v2f64_v2i1(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i1: +; CHECK: // %bb.0: +; CHECK-NEXT: fmov v1.2d, #-1.00000000 +; CHECK-NEXT: fmaxnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: movi v1.2d, #0000000000000000 +; CHECK-NEXT: fminnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i1> @llvm.fptosi.sat.v2f64.v2i1(<2 x double> %f) + ret <2 x i1> %x +} + +define <2 x i8> @test_signed_v2f64_v2i8(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i8: +; CHECK: // %bb.0: +; CHECK-NEXT: mov x8, #-4584664420663164928 +; CHECK-NEXT: mov x9, #211106232532992 +; CHECK-NEXT: movk x9, #16479, lsl #48 +; CHECK-NEXT: dup v1.2d, x8 +; CHECK-NEXT: fmaxnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: dup v1.2d, x9 +; CHECK-NEXT: fminnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i8> @llvm.fptosi.sat.v2f64.v2i8(<2 x double> %f) + ret <2 x i8> %x +} + +define <2 x i13> @test_signed_v2f64_v2i13(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i13: +; CHECK: // %bb.0: +; CHECK-NEXT: mov x8, #-4562146422526312448 +; CHECK-NEXT: mov x9, #279275953455104 +; CHECK-NEXT: movk x9, #16559, lsl #48 +; CHECK-NEXT: dup v1.2d, x8 +; CHECK-NEXT: fmaxnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: dup v1.2d, x9 +; CHECK-NEXT: fminnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i13> @llvm.fptosi.sat.v2f64.v2i13(<2 x double> %f) + ret <2 x i13> %x +} + +define <2 x i16> @test_signed_v2f64_v2i16(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i16: +; CHECK: // %bb.0: +; CHECK-NEXT: mov x8, #-4548635623644200960 +; CHECK-NEXT: mov x9, #281200098803712 +; CHECK-NEXT: movk x9, #16607, lsl #48 +; CHECK-NEXT: dup v1.2d, x8 +; CHECK-NEXT: fmaxnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: dup v1.2d, x9 +; CHECK-NEXT: fminnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i16> @llvm.fptosi.sat.v2f64.v2i16(<2 x double> %f) + ret <2 x i16> %x +} + +define <2 x i19> @test_signed_v2f64_v2i19(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i19: +; CHECK: // %bb.0: +; CHECK-NEXT: mov x8, #-4535124824762089472 +; CHECK-NEXT: mov x9, #281440616972288 +; CHECK-NEXT: movk x9, #16655, lsl #48 +; CHECK-NEXT: dup v1.2d, x8 +; CHECK-NEXT: fmaxnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: dup v1.2d, x9 +; CHECK-NEXT: fminnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i19> @llvm.fptosi.sat.v2f64.v2i19(<2 x double> %f) + ret <2 x i19> %x +} + +define <2 x i32> @test_signed_v2f64_v2i32_duplicate(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i32_duplicate: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: xtn v0.2s, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i32> @llvm.fptosi.sat.v2f64.v2i32(<2 x double> %f) + ret <2 x i32> %x +} + +define <2 x i50> @test_signed_v2f64_v2i50(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i50: +; CHECK: // %bb.0: +; CHECK-NEXT: mov x8, #-4395513236313604096 +; CHECK-NEXT: mov x9, #-16 +; CHECK-NEXT: movk x9, #17151, lsl #48 +; CHECK-NEXT: dup v1.2d, x8 +; CHECK-NEXT: fmaxnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: dup v1.2d, x9 +; CHECK-NEXT: fminnm v0.2d, v0.2d, v1.2d +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i50> @llvm.fptosi.sat.v2f64.v2i50(<2 x double> %f) + ret <2 x i50> %x +} + +define <2 x i64> @test_signed_v2f64_v2i64(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i64: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtzs v0.2d, v0.2d +; CHECK-NEXT: ret + %x = call <2 x i64> @llvm.fptosi.sat.v2f64.v2i64(<2 x double> %f) + ret <2 x i64> %x +} + +define <2 x i100> @test_signed_v2f64_v2i100(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i100: +; CHECK: // %bb.0: +; CHECK-NEXT: sub sp, sp, #48 // =48 +; CHECK-NEXT: str x20, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: stp x19, x30, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w19, -16 +; CHECK-NEXT: .cfi_offset w20, -32 +; CHECK-NEXT: str q0, [sp] // 16-byte Folded Spill +; CHECK-NEXT: mov d0, v0.d[1] +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixdfti_sat +; CHECK-NEXT: mov x19, x0 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov x20, x1 +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0 +; CHECK-NEXT: bl __fixdfti_sat +; CHECK-NEXT: mov x2, x19 +; CHECK-NEXT: mov x3, x20 +; CHECK-NEXT: ldp x19, x30, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: ldr x20, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: fmov d0, x0 +; CHECK-NEXT: mov v0.d[1], x1 +; CHECK-NEXT: fmov x0, d0 +; CHECK-NEXT: add sp, sp, #48 // =48 +; CHECK-NEXT: ret + %x = call <2 x i100> @llvm.fptosi.sat.v2f64.v2i100(<2 x double> %f) + ret <2 x i100> %x +} + +define <2 x i128> @test_signed_v2f64_v2i128(<2 x double> %f) { +; CHECK-LABEL: test_signed_v2f64_v2i128: +; CHECK: // %bb.0: +; CHECK-NEXT: sub sp, sp, #48 // =48 +; CHECK-NEXT: str x20, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: stp x19, x30, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 48 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w19, -16 +; CHECK-NEXT: .cfi_offset w20, -32 +; CHECK-NEXT: str q0, [sp] // 16-byte Folded Spill +; CHECK-NEXT: mov d0, v0.d[1] +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixdfti_sat +; CHECK-NEXT: mov x19, x0 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov x20, x1 +; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0 +; CHECK-NEXT: bl __fixdfti_sat +; CHECK-NEXT: mov x2, x19 +; CHECK-NEXT: mov x3, x20 +; CHECK-NEXT: ldp x19, x30, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: ldr x20, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: fmov d0, x0 +; CHECK-NEXT: mov v0.d[1], x1 +; CHECK-NEXT: fmov x0, d0 +; CHECK-NEXT: add sp, sp, #48 // =48 +; CHECK-NEXT: ret + %x = call <2 x i128> @llvm.fptosi.sat.v2f64.v2i128(<2 x double> %f) + ret <2 x i128> %x +} + +; +; 4-Vector half to signed integer -- result size variation +; + +declare <4 x i1> @llvm.fptosi.sat.v4f16.v4i1 (<4 x half>) +declare <4 x i8> @llvm.fptosi.sat.v4f16.v4i8 (<4 x half>) +declare <4 x i13> @llvm.fptosi.sat.v4f16.v4i13 (<4 x half>) +declare <4 x i16> @llvm.fptosi.sat.v4f16.v4i16 (<4 x half>) +declare <4 x i19> @llvm.fptosi.sat.v4f16.v4i19 (<4 x half>) +declare <4 x i50> @llvm.fptosi.sat.v4f16.v4i50 (<4 x half>) +declare <4 x i64> @llvm.fptosi.sat.v4f16.v4i64 (<4 x half>) +declare <4 x i100> @llvm.fptosi.sat.v4f16.v4i100(<4 x half>) +declare <4 x i128> @llvm.fptosi.sat.v4f16.v4i128(<4 x half>) + +define <4 x i1> @test_signed_v4f16_v4i1(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i1: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v0.4s, v0.4h +; CHECK-NEXT: fmov v1.4s, #-1.00000000 +; CHECK-NEXT: fmaxnm v0.4s, v0.4s, v1.4s +; CHECK-NEXT: movi v1.2d, #0000000000000000 +; CHECK-NEXT: fminnm v0.4s, v0.4s, v1.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: xtn v0.4h, v0.4s +; CHECK-NEXT: ret + %x = call <4 x i1> @llvm.fptosi.sat.v4f16.v4i1(<4 x half> %f) + ret <4 x i1> %x +} + +define <4 x i8> @test_signed_v4f16_v4i8(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i8: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v0.4s, v0.4h +; CHECK-NEXT: movi v1.4s, #195, lsl #24 +; CHECK-NEXT: mov w8, #1123942400 +; CHECK-NEXT: fmaxnm v0.4s, v0.4s, v1.4s +; CHECK-NEXT: dup v1.4s, w8 +; CHECK-NEXT: fminnm v0.4s, v0.4s, v1.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: xtn v0.4h, v0.4s +; CHECK-NEXT: ret + %x = call <4 x i8> @llvm.fptosi.sat.v4f16.v4i8(<4 x half> %f) + ret <4 x i8> %x +} + +define <4 x i13> @test_signed_v4f16_v4i13(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i13: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, #-981467136 +; CHECK-NEXT: mov w9, #61440 +; CHECK-NEXT: fcvtl v0.4s, v0.4h +; CHECK-NEXT: movk w9, #17791, lsl #16 +; CHECK-NEXT: dup v1.4s, w8 +; CHECK-NEXT: fmaxnm v0.4s, v0.4s, v1.4s +; CHECK-NEXT: dup v1.4s, w9 +; CHECK-NEXT: fminnm v0.4s, v0.4s, v1.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: xtn v0.4h, v0.4s +; CHECK-NEXT: ret + %x = call <4 x i13> @llvm.fptosi.sat.v4f16.v4i13(<4 x half> %f) + ret <4 x i13> %x +} + +define <4 x i16> @test_signed_v4f16_v4i16(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i16: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v0.4s, v0.4h +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: xtn v0.4h, v0.4s +; CHECK-NEXT: ret + %x = call <4 x i16> @llvm.fptosi.sat.v4f16.v4i16(<4 x half> %f) + ret <4 x i16> %x +} + +define <4 x i19> @test_signed_v4f16_v4i19(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i19: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, #-931135488 +; CHECK-NEXT: mov w9, #65472 +; CHECK-NEXT: fcvtl v0.4s, v0.4h +; CHECK-NEXT: movk w9, #18559, lsl #16 +; CHECK-NEXT: dup v1.4s, w8 +; CHECK-NEXT: fmaxnm v0.4s, v0.4s, v1.4s +; CHECK-NEXT: dup v1.4s, w9 +; CHECK-NEXT: fminnm v0.4s, v0.4s, v1.4s +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: ret + %x = call <4 x i19> @llvm.fptosi.sat.v4f16.v4i19(<4 x half> %f) + ret <4 x i19> %x +} + +define <4 x i32> @test_signed_v4f16_v4i32_duplicate(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i32_duplicate: +; CHECK: // %bb.0: +; CHECK-NEXT: fcvtl v0.4s, v0.4h +; CHECK-NEXT: fcvtzs v0.4s, v0.4s +; CHECK-NEXT: ret + %x = call <4 x i32> @llvm.fptosi.sat.v4f16.v4i32(<4 x half> %f) + ret <4 x i32> %x +} + +define <4 x i50> @test_signed_v4f16_v4i50(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i50: +; CHECK: // %bb.0: +; CHECK-NEXT: adrp x8, .LCPI52_0 +; CHECK-NEXT: adrp x10, .LCPI52_1 +; CHECK-NEXT: ldr s2, [x8, :lo12:.LCPI52_0] +; CHECK-NEXT: ldr s3, [x10, :lo12:.LCPI52_1] +; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NEXT: fcvt s1, h0 +; CHECK-NEXT: orr x9, xzr, #0xfffe000000000000 +; CHECK-NEXT: fcvtzs x10, s1 +; CHECK-NEXT: fcmp s1, s2 +; CHECK-NEXT: csel x10, x9, x10, lt +; CHECK-NEXT: fcmp s1, s3 +; CHECK-NEXT: mov h1, v0.h[1] +; CHECK-NEXT: orr x8, xzr, #0x1ffffffffffff +; CHECK-NEXT: fcvt s1, h1 +; CHECK-NEXT: fcvtzs x11, s1 +; CHECK-NEXT: csel x0, x8, x10, gt +; CHECK-NEXT: fcmp s1, s2 +; CHECK-NEXT: csel x10, x9, x11, lt +; CHECK-NEXT: fcmp s1, s3 +; CHECK-NEXT: mov h1, v0.h[2] +; CHECK-NEXT: fcvt s1, h1 +; CHECK-NEXT: mov h0, v0.h[3] +; CHECK-NEXT: fcvtzs x11, s1 +; CHECK-NEXT: csel x1, x8, x10, gt +; CHECK-NEXT: fcmp s1, s2 +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: csel x10, x9, x11, lt +; CHECK-NEXT: fcmp s1, s3 +; CHECK-NEXT: fcvtzs x12, s0 +; CHECK-NEXT: csel x2, x8, x10, gt +; CHECK-NEXT: fcmp s0, s2 +; CHECK-NEXT: csel x9, x9, x12, lt +; CHECK-NEXT: fcmp s0, s3 +; CHECK-NEXT: csel x3, x8, x9, gt +; CHECK-NEXT: ret + %x = call <4 x i50> @llvm.fptosi.sat.v4f16.v4i50(<4 x half> %f) + ret <4 x i50> %x +} + +define <4 x i64> @test_signed_v4f16_v4i64(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i64: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NEXT: fcvt s1, h0 +; CHECK-NEXT: mov h2, v0.h[1] +; CHECK-NEXT: fcvtzs x8, s1 +; CHECK-NEXT: fcvt s1, h2 +; CHECK-NEXT: fmov d2, x8 +; CHECK-NEXT: fcvtzs x8, s1 +; CHECK-NEXT: mov h1, v0.h[2] +; CHECK-NEXT: mov h0, v0.h[3] +; CHECK-NEXT: fcvt s1, h1 +; CHECK-NEXT: mov v2.d[1], x8 +; CHECK-NEXT: fcvtzs x8, s1 +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: fmov d1, x8 +; CHECK-NEXT: fcvtzs x8, s0 +; CHECK-NEXT: mov v1.d[1], x8 +; CHECK-NEXT: mov v0.16b, v2.16b +; CHECK-NEXT: ret + %x = call <4 x i64> @llvm.fptosi.sat.v4f16.v4i64(<4 x half> %f) + ret <4 x i64> %x +} + +define <4 x i100> @test_signed_v4f16_v4i100(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i100: +; CHECK: // %bb.0: +; CHECK-NEXT: sub sp, sp, #80 // =80 +; CHECK-NEXT: str x24, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: stp x23, x22, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: stp x21, x20, [sp, #48] // 16-byte Folded Spill +; CHECK-NEXT: stp x19, x30, [sp, #64] // 16-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 80 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w19, -16 +; CHECK-NEXT: .cfi_offset w20, -24 +; CHECK-NEXT: .cfi_offset w21, -32 +; CHECK-NEXT: .cfi_offset w22, -40 +; CHECK-NEXT: .cfi_offset w23, -48 +; CHECK-NEXT: .cfi_offset w24, -64 +; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NEXT: mov h1, v0.h[1] +; CHECK-NEXT: str q0, [sp] // 16-byte Folded Spill +; CHECK-NEXT: fcvt s0, h1 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov x19, x0 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: mov x20, x1 +; CHECK-NEXT: mov h0, v0.h[2] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov x21, x0 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: mov x22, x1 +; CHECK-NEXT: mov h0, v0.h[3] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov x23, x0 +; CHECK-NEXT: mov w0, #100 +; CHECK-NEXT: mov x24, x1 +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: mov x2, x19 +; CHECK-NEXT: mov x3, x20 +; CHECK-NEXT: mov x4, x21 +; CHECK-NEXT: mov x5, x22 +; CHECK-NEXT: mov x6, x23 +; CHECK-NEXT: mov x7, x24 +; CHECK-NEXT: ldp x19, x30, [sp, #64] // 16-byte Folded Reload +; CHECK-NEXT: ldp x21, x20, [sp, #48] // 16-byte Folded Reload +; CHECK-NEXT: ldp x23, x22, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: ldr x24, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: fmov d0, x0 +; CHECK-NEXT: mov v0.d[1], x1 +; CHECK-NEXT: fmov x0, d0 +; CHECK-NEXT: add sp, sp, #80 // =80 +; CHECK-NEXT: ret + %x = call <4 x i100> @llvm.fptosi.sat.v4f16.v4i100(<4 x half> %f) + ret <4 x i100> %x +} + +define <4 x i128> @test_signed_v4f16_v4i128(<4 x half> %f) { +; CHECK-LABEL: test_signed_v4f16_v4i128: +; CHECK: // %bb.0: +; CHECK-NEXT: sub sp, sp, #80 // =80 +; CHECK-NEXT: str x24, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: stp x23, x22, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: stp x21, x20, [sp, #48] // 16-byte Folded Spill +; CHECK-NEXT: stp x19, x30, [sp, #64] // 16-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 80 +; CHECK-NEXT: .cfi_offset w30, -8 +; CHECK-NEXT: .cfi_offset w19, -16 +; CHECK-NEXT: .cfi_offset w20, -24 +; CHECK-NEXT: .cfi_offset w21, -32 +; CHECK-NEXT: .cfi_offset w22, -40 +; CHECK-NEXT: .cfi_offset w23, -48 +; CHECK-NEXT: .cfi_offset w24, -64 +; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NEXT: mov h1, v0.h[1] +; CHECK-NEXT: str q0, [sp] // 16-byte Folded Spill +; CHECK-NEXT: fcvt s0, h1 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov x19, x0 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: mov x20, x1 +; CHECK-NEXT: mov h0, v0.h[2] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov x21, x0 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: mov x22, x1 +; CHECK-NEXT: mov h0, v0.h[3] +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: ldr q0, [sp] // 16-byte Folded Reload +; CHECK-NEXT: mov x23, x0 +; CHECK-NEXT: orr w0, wzr, #0x80 +; CHECK-NEXT: mov x24, x1 +; CHECK-NEXT: fcvt s0, h0 +; CHECK-NEXT: bl __fixsfti_sat +; CHECK-NEXT: mov x2, x19 +; CHECK-NEXT: mov x3, x20 +; CHECK-NEXT: mov x4, x21 +; CHECK-NEXT: mov x5, x22 +; CHECK-NEXT: mov x6, x23 +; CHECK-NEXT: mov x7, x24 +; CHECK-NEXT: ldp x19, x30, [sp, #64] // 16-byte Folded Reload +; CHECK-NEXT: ldp x21, x20, [sp, #48] // 16-byte Folded Reload +; CHECK-NEXT: ldp x23, x22, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: ldr x24, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: fmov d0, x0 +; CHECK-NEXT: mov v0.d[1], x1 +; CHECK-NEXT: fmov x0, d0 +; CHECK-NEXT: add sp, sp, #80 // =80 +; CHECK-NEXT: ret + %x = call <4 x i128> @llvm.fptosi.sat.v4f16.v4i128(<4 x half> %f) + ret <4 x i128> %x +} + Index: test/CodeGen/X86/fptoi-sat-scalar.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/fptoi-sat-scalar.ll @@ -0,0 +1,2109 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-linux | FileCheck %s + +; +; 32-bit float to signed integer +; + +declare i1 @llvm.fptosi.sat.f32.i1 (float) +declare i8 @llvm.fptosi.sat.f32.i8 (float) +declare i13 @llvm.fptosi.sat.f32.i13 (float) +declare i16 @llvm.fptosi.sat.f32.i16 (float) +declare i19 @llvm.fptosi.sat.f32.i19 (float) +declare i32 @llvm.fptosi.sat.f32.i32 (float) +declare i50 @llvm.fptosi.sat.f32.i50 (float) +declare i64 @llvm.fptosi.sat.f32.i64 (float) +declare i100 @llvm.fptosi.sat.f32.i100(float) +declare i128 @llvm.fptosi.sat.f32.i128(float) + +define i1 @test_signed_f32_i1(float %f) { +; CHECK-LABEL: test_signed_f32_i1: +; CHECK: # %bb.0: +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: xorps %xmm0, %xmm0 +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq + %x = call i1 @llvm.fptosi.sat.f32.i1(float %f) + ret i1 %x +} + +define i8 @test_signed_f32_i8(float %f) { +; CHECK-LABEL: test_signed_f32_i8: +; CHECK: # %bb.0: +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq + %x = call i8 @llvm.fptosi.sat.f32.i8(float %f) + ret i8 %x +} + +define i13 @test_signed_f32_i13(float %f) { +; CHECK-LABEL: test_signed_f32_i13: +; CHECK: # %bb.0: +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i13 @llvm.fptosi.sat.f32.i13(float %f) + ret i13 %x +} + +define i16 @test_signed_f32_i16(float %f) { +; CHECK-LABEL: test_signed_f32_i16: +; CHECK: # %bb.0: +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i16 @llvm.fptosi.sat.f32.i16(float %f) + ret i16 %x +} + +define i19 @test_signed_f32_i19(float %f) { +; CHECK-LABEL: test_signed_f32_i19: +; CHECK: # %bb.0: +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomiss %xmm0, %xmm0 +; CHECK-NEXT: maxss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: minss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %ecx +; CHECK-NEXT: cmovnpl %ecx, %eax +; CHECK-NEXT: retq + %x = call i19 @llvm.fptosi.sat.f32.i19(float %f) + ret i19 %x +} + +define i32 @test_signed_f32_i32(float %f) { +; CHECK-LABEL: test_signed_f32_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movl $2147483647, %ecx # imm = 0x7FFFFFFF +; CHECK-NEXT: cmovbel %eax, %ecx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomiss %xmm0, %xmm0 +; CHECK-NEXT: cmovnpl %ecx, %eax +; CHECK-NEXT: retq + %x = call i32 @llvm.fptosi.sat.f32.i32(float %f) + ret i32 %x +} + +define i50 @test_signed_f32_i50(float %f) { +; CHECK-LABEL: test_signed_f32_i50: +; CHECK: # %bb.0: +; CHECK-NEXT: cvttss2si %xmm0, %rax +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movabsq $-562949953421312, %rcx # imm = 0xFFFE000000000000 +; CHECK-NEXT: cmovaeq %rax, %rcx +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movabsq $562949953421311, %rdx # imm = 0x1FFFFFFFFFFFF +; CHECK-NEXT: cmovbeq %rcx, %rdx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomiss %xmm0, %xmm0 +; CHECK-NEXT: cmovnpq %rdx, %rax +; CHECK-NEXT: retq + %x = call i50 @llvm.fptosi.sat.f32.i50(float %f) + ret i50 %x +} + +define i64 @test_signed_f32_i64(float %f) { +; CHECK-LABEL: test_signed_f32_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: cvttss2si %xmm0, %rax +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF +; CHECK-NEXT: cmovbeq %rax, %rcx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomiss %xmm0, %xmm0 +; CHECK-NEXT: cmovnpq %rcx, %rax +; CHECK-NEXT: retq + %x = call i64 @llvm.fptosi.sat.f32.i64(float %f) + ret i64 %x +} + +define i100 @test_signed_f32_i100(float %f) { +; CHECK-LABEL: test_signed_f32_i100: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $100, %edi +; CHECK-NEXT: callq __fixsfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i100 @llvm.fptosi.sat.f32.i100(float %f) + ret i100 %x +} + +define i128 @test_signed_f32_i128(float %f) { +; CHECK-LABEL: test_signed_f32_i128: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $128, %edi +; CHECK-NEXT: callq __fixsfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i128 @llvm.fptosi.sat.f32.i128(float %f) + ret i128 %x +} + +; +; 32-bit float to unsigned integer +; + +declare i1 @llvm.fptoui.sat.f32.i1 (float) +declare i8 @llvm.fptoui.sat.f32.i8 (float) +declare i13 @llvm.fptoui.sat.f32.i13 (float) +declare i16 @llvm.fptoui.sat.f32.i16 (float) +declare i19 @llvm.fptoui.sat.f32.i19 (float) +declare i32 @llvm.fptoui.sat.f32.i32 (float) +declare i50 @llvm.fptoui.sat.f32.i50 (float) +declare i64 @llvm.fptoui.sat.f32.i64 (float) +declare i100 @llvm.fptoui.sat.f32.i100(float) +declare i128 @llvm.fptoui.sat.f32.i128(float) + +define i1 @test_unsigned_f32_i1(float %f) { +; CHECK-LABEL: test_unsigned_f32_i1: +; CHECK: # %bb.0: +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq + %x = call i1 @llvm.fptoui.sat.f32.i1(float %f) + ret i1 %x +} + +define i8 @test_unsigned_f32_i8(float %f) { +; CHECK-LABEL: test_unsigned_f32_i8: +; CHECK: # %bb.0: +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq + %x = call i8 @llvm.fptoui.sat.f32.i8(float %f) + ret i8 %x +} + +define i13 @test_unsigned_f32_i13(float %f) { +; CHECK-LABEL: test_unsigned_f32_i13: +; CHECK: # %bb.0: +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i13 @llvm.fptoui.sat.f32.i13(float %f) + ret i13 %x +} + +define i16 @test_unsigned_f32_i16(float %f) { +; CHECK-LABEL: test_unsigned_f32_i16: +; CHECK: # %bb.0: +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i16 @llvm.fptoui.sat.f32.i16(float %f) + ret i16 %x +} + +define i19 @test_unsigned_f32_i19(float %f) { +; CHECK-LABEL: test_unsigned_f32_i19: +; CHECK: # %bb.0: +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: maxss %xmm1, %xmm0 +; CHECK-NEXT: minss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: retq + %x = call i19 @llvm.fptoui.sat.f32.i19(float %f) + ret i19 %x +} + +define i32 @test_unsigned_f32_i32(float %f) { +; CHECK-LABEL: test_unsigned_f32_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: cvttss2si %xmm0, %rax +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: cmovael %eax, %ecx +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movl $-1, %eax +; CHECK-NEXT: cmovbel %ecx, %eax +; CHECK-NEXT: retq + %x = call i32 @llvm.fptoui.sat.f32.i32(float %f) + ret i32 %x +} + +define i50 @test_unsigned_f32_i50(float %f) { +; CHECK-LABEL: test_unsigned_f32_i50: +; CHECK: # %bb.0: +; CHECK-NEXT: cvttss2si %xmm0, %rax +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: cmovaeq %rax, %rcx +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movabsq $1125899906842623, %rax # imm = 0x3FFFFFFFFFFFF +; CHECK-NEXT: cmovbeq %rcx, %rax +; CHECK-NEXT: retq + %x = call i50 @llvm.fptoui.sat.f32.i50(float %f) + ret i50 %x +} + +define i64 @test_unsigned_f32_i64(float %f) { +; CHECK-LABEL: test_unsigned_f32_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: movaps %xmm0, %xmm2 +; CHECK-NEXT: subss %xmm1, %xmm2 +; CHECK-NEXT: cvttss2si %xmm2, %rax +; CHECK-NEXT: movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000 +; CHECK-NEXT: xorq %rax, %rcx +; CHECK-NEXT: cvttss2si %xmm0, %rax +; CHECK-NEXT: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: cmovaeq %rcx, %rax +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: cmovaeq %rax, %rcx +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movq $-1, %rax +; CHECK-NEXT: cmovbeq %rcx, %rax +; CHECK-NEXT: retq + %x = call i64 @llvm.fptoui.sat.f32.i64(float %f) + ret i64 %x +} + +define i100 @test_unsigned_f32_i100(float %f) { +; CHECK-LABEL: test_unsigned_f32_i100: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $100, %edi +; CHECK-NEXT: callq __fixunssfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i100 @llvm.fptoui.sat.f32.i100(float %f) + ret i100 %x +} + +define i128 @test_unsigned_f32_i128(float %f) { +; CHECK-LABEL: test_unsigned_f32_i128: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $128, %edi +; CHECK-NEXT: callq __fixunssfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i128 @llvm.fptoui.sat.f32.i128(float %f) + ret i128 %x +} + +; +; 64-bit float to signed integer +; + +declare i1 @llvm.fptosi.sat.f64.i1 (double) +declare i8 @llvm.fptosi.sat.f64.i8 (double) +declare i13 @llvm.fptosi.sat.f64.i13 (double) +declare i16 @llvm.fptosi.sat.f64.i16 (double) +declare i19 @llvm.fptosi.sat.f64.i19 (double) +declare i32 @llvm.fptosi.sat.f64.i32 (double) +declare i50 @llvm.fptosi.sat.f64.i50 (double) +declare i64 @llvm.fptosi.sat.f64.i64 (double) +declare i100 @llvm.fptosi.sat.f64.i100(double) +declare i128 @llvm.fptosi.sat.f64.i128(double) + +define i1 @test_signed_f64_i1(double %f) { +; CHECK-LABEL: test_signed_f64_i1: +; CHECK: # %bb.0: +; CHECK-NEXT: movsd {{.*#+}} xmm1 = mem[0],zero +; CHECK-NEXT: maxsd %xmm0, %xmm1 +; CHECK-NEXT: xorpd %xmm0, %xmm0 +; CHECK-NEXT: minsd %xmm1, %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq + %x = call i1 @llvm.fptosi.sat.f64.i1(double %f) + ret i1 %x +} + +define i8 @test_signed_f64_i8(double %f) { +; CHECK-LABEL: test_signed_f64_i8: +; CHECK: # %bb.0: +; CHECK-NEXT: movsd {{.*#+}} xmm1 = mem[0],zero +; CHECK-NEXT: maxsd %xmm0, %xmm1 +; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; CHECK-NEXT: minsd %xmm1, %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq + %x = call i8 @llvm.fptosi.sat.f64.i8(double %f) + ret i8 %x +} + +define i13 @test_signed_f64_i13(double %f) { +; CHECK-LABEL: test_signed_f64_i13: +; CHECK: # %bb.0: +; CHECK-NEXT: movsd {{.*#+}} xmm1 = mem[0],zero +; CHECK-NEXT: maxsd %xmm0, %xmm1 +; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; CHECK-NEXT: minsd %xmm1, %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i13 @llvm.fptosi.sat.f64.i13(double %f) + ret i13 %x +} + +define i16 @test_signed_f64_i16(double %f) { +; CHECK-LABEL: test_signed_f64_i16: +; CHECK: # %bb.0: +; CHECK-NEXT: movsd {{.*#+}} xmm1 = mem[0],zero +; CHECK-NEXT: maxsd %xmm0, %xmm1 +; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; CHECK-NEXT: minsd %xmm1, %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i16 @llvm.fptosi.sat.f64.i16(double %f) + ret i16 %x +} + +define i19 @test_signed_f64_i19(double %f) { +; CHECK-LABEL: test_signed_f64_i19: +; CHECK: # %bb.0: +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomisd %xmm0, %xmm0 +; CHECK-NEXT: maxsd {{.*}}(%rip), %xmm0 +; CHECK-NEXT: minsd {{.*}}(%rip), %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %ecx +; CHECK-NEXT: cmovnpl %ecx, %eax +; CHECK-NEXT: retq + %x = call i19 @llvm.fptosi.sat.f64.i19(double %f) + ret i19 %x +} + +define i32 @test_signed_f64_i32(double %f) { +; CHECK-LABEL: test_signed_f64_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomisd %xmm0, %xmm0 +; CHECK-NEXT: maxsd {{.*}}(%rip), %xmm0 +; CHECK-NEXT: minsd {{.*}}(%rip), %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %ecx +; CHECK-NEXT: cmovnpl %ecx, %eax +; CHECK-NEXT: retq + %x = call i32 @llvm.fptosi.sat.f64.i32(double %f) + ret i32 %x +} + +define i50 @test_signed_f64_i50(double %f) { +; CHECK-LABEL: test_signed_f64_i50: +; CHECK: # %bb.0: +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomisd %xmm0, %xmm0 +; CHECK-NEXT: maxsd {{.*}}(%rip), %xmm0 +; CHECK-NEXT: minsd {{.*}}(%rip), %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %rcx +; CHECK-NEXT: cmovnpq %rcx, %rax +; CHECK-NEXT: retq + %x = call i50 @llvm.fptosi.sat.f64.i50(double %f) + ret i50 %x +} + +define i64 @test_signed_f64_i64(double %f) { +; CHECK-LABEL: test_signed_f64_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: cvttsd2si %xmm0, %rax +; CHECK-NEXT: ucomisd {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF +; CHECK-NEXT: cmovbeq %rax, %rcx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomisd %xmm0, %xmm0 +; CHECK-NEXT: cmovnpq %rcx, %rax +; CHECK-NEXT: retq + %x = call i64 @llvm.fptosi.sat.f64.i64(double %f) + ret i64 %x +} + +define i100 @test_signed_f64_i100(double %f) { +; CHECK-LABEL: test_signed_f64_i100: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $100, %edi +; CHECK-NEXT: callq __fixdfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i100 @llvm.fptosi.sat.f64.i100(double %f) + ret i100 %x +} + +define i128 @test_signed_f64_i128(double %f) { +; CHECK-LABEL: test_signed_f64_i128: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $128, %edi +; CHECK-NEXT: callq __fixdfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i128 @llvm.fptosi.sat.f64.i128(double %f) + ret i128 %x +} + +; +; 64-bit float to unsigned integer +; + +declare i1 @llvm.fptoui.sat.f64.i1 (double) +declare i8 @llvm.fptoui.sat.f64.i8 (double) +declare i13 @llvm.fptoui.sat.f64.i13 (double) +declare i16 @llvm.fptoui.sat.f64.i16 (double) +declare i19 @llvm.fptoui.sat.f64.i19 (double) +declare i32 @llvm.fptoui.sat.f64.i32 (double) +declare i50 @llvm.fptoui.sat.f64.i50 (double) +declare i64 @llvm.fptoui.sat.f64.i64 (double) +declare i100 @llvm.fptoui.sat.f64.i100(double) +declare i128 @llvm.fptoui.sat.f64.i128(double) + +define i1 @test_unsigned_f64_i1(double %f) { +; CHECK-LABEL: test_unsigned_f64_i1: +; CHECK: # %bb.0: +; CHECK-NEXT: xorpd %xmm1, %xmm1 +; CHECK-NEXT: maxsd %xmm0, %xmm1 +; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; CHECK-NEXT: minsd %xmm1, %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq + %x = call i1 @llvm.fptoui.sat.f64.i1(double %f) + ret i1 %x +} + +define i8 @test_unsigned_f64_i8(double %f) { +; CHECK-LABEL: test_unsigned_f64_i8: +; CHECK: # %bb.0: +; CHECK-NEXT: xorpd %xmm1, %xmm1 +; CHECK-NEXT: maxsd %xmm0, %xmm1 +; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; CHECK-NEXT: minsd %xmm1, %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq + %x = call i8 @llvm.fptoui.sat.f64.i8(double %f) + ret i8 %x +} + +define i13 @test_unsigned_f64_i13(double %f) { +; CHECK-LABEL: test_unsigned_f64_i13: +; CHECK: # %bb.0: +; CHECK-NEXT: xorpd %xmm1, %xmm1 +; CHECK-NEXT: maxsd %xmm0, %xmm1 +; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; CHECK-NEXT: minsd %xmm1, %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i13 @llvm.fptoui.sat.f64.i13(double %f) + ret i13 %x +} + +define i16 @test_unsigned_f64_i16(double %f) { +; CHECK-LABEL: test_unsigned_f64_i16: +; CHECK: # %bb.0: +; CHECK-NEXT: xorpd %xmm1, %xmm1 +; CHECK-NEXT: maxsd %xmm0, %xmm1 +; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; CHECK-NEXT: minsd %xmm1, %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i16 @llvm.fptoui.sat.f64.i16(double %f) + ret i16 %x +} + +define i19 @test_unsigned_f64_i19(double %f) { +; CHECK-LABEL: test_unsigned_f64_i19: +; CHECK: # %bb.0: +; CHECK-NEXT: xorpd %xmm1, %xmm1 +; CHECK-NEXT: maxsd %xmm1, %xmm0 +; CHECK-NEXT: minsd {{.*}}(%rip), %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %eax +; CHECK-NEXT: retq + %x = call i19 @llvm.fptoui.sat.f64.i19(double %f) + ret i19 %x +} + +define i32 @test_unsigned_f64_i32(double %f) { +; CHECK-LABEL: test_unsigned_f64_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: xorpd %xmm1, %xmm1 +; CHECK-NEXT: maxsd %xmm0, %xmm1 +; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero +; CHECK-NEXT: minsd %xmm1, %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %rax +; CHECK-NEXT: # kill: def $eax killed $eax killed $rax +; CHECK-NEXT: retq + %x = call i32 @llvm.fptoui.sat.f64.i32(double %f) + ret i32 %x +} + +define i50 @test_unsigned_f64_i50(double %f) { +; CHECK-LABEL: test_unsigned_f64_i50: +; CHECK: # %bb.0: +; CHECK-NEXT: xorpd %xmm1, %xmm1 +; CHECK-NEXT: maxsd %xmm1, %xmm0 +; CHECK-NEXT: minsd {{.*}}(%rip), %xmm0 +; CHECK-NEXT: cvttsd2si %xmm0, %rax +; CHECK-NEXT: retq + %x = call i50 @llvm.fptoui.sat.f64.i50(double %f) + ret i50 %x +} + +define i64 @test_unsigned_f64_i64(double %f) { +; CHECK-LABEL: test_unsigned_f64_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: movsd {{.*#+}} xmm1 = mem[0],zero +; CHECK-NEXT: movapd %xmm0, %xmm2 +; CHECK-NEXT: subsd %xmm1, %xmm2 +; CHECK-NEXT: cvttsd2si %xmm2, %rax +; CHECK-NEXT: movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000 +; CHECK-NEXT: xorq %rax, %rcx +; CHECK-NEXT: cvttsd2si %xmm0, %rax +; CHECK-NEXT: ucomisd %xmm1, %xmm0 +; CHECK-NEXT: cmovaeq %rcx, %rax +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: xorpd %xmm1, %xmm1 +; CHECK-NEXT: ucomisd %xmm1, %xmm0 +; CHECK-NEXT: cmovaeq %rax, %rcx +; CHECK-NEXT: ucomisd {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movq $-1, %rax +; CHECK-NEXT: cmovbeq %rcx, %rax +; CHECK-NEXT: retq + %x = call i64 @llvm.fptoui.sat.f64.i64(double %f) + ret i64 %x +} + +define i100 @test_unsigned_f64_i100(double %f) { +; CHECK-LABEL: test_unsigned_f64_i100: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $100, %edi +; CHECK-NEXT: callq __fixunsdfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i100 @llvm.fptoui.sat.f64.i100(double %f) + ret i100 %x +} + +define i128 @test_unsigned_f64_i128(double %f) { +; CHECK-LABEL: test_unsigned_f64_i128: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $128, %edi +; CHECK-NEXT: callq __fixunsdfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i128 @llvm.fptoui.sat.f64.i128(double %f) + ret i128 %x +} + +; +; 16-bit float to signed integer +; + +declare i1 @llvm.fptosi.sat.f16.i1 (half) +declare i8 @llvm.fptosi.sat.f16.i8 (half) +declare i13 @llvm.fptosi.sat.f16.i13 (half) +declare i16 @llvm.fptosi.sat.f16.i16 (half) +declare i19 @llvm.fptosi.sat.f16.i19 (half) +declare i32 @llvm.fptosi.sat.f16.i32 (half) +declare i50 @llvm.fptosi.sat.f16.i50 (half) +declare i64 @llvm.fptosi.sat.f16.i64 (half) +declare i100 @llvm.fptosi.sat.f16.i100(half) +declare i128 @llvm.fptosi.sat.f16.i128(half) + +define i1 @test_signed_f16_i1(half %f) { +; CHECK-LABEL: test_signed_f16_i1: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: xorps %xmm0, %xmm0 +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i1 @llvm.fptosi.sat.f16.i1(half %f) + ret i1 %x +} + +define i8 @test_signed_f16_i8(half %f) { +; CHECK-LABEL: test_signed_f16_i8: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i8 @llvm.fptosi.sat.f16.i8(half %f) + ret i8 %x +} + +define i13 @test_signed_f16_i13(half %f) { +; CHECK-LABEL: test_signed_f16_i13: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i13 @llvm.fptosi.sat.f16.i13(half %f) + ret i13 %x +} + +define i16 @test_signed_f16_i16(half %f) { +; CHECK-LABEL: test_signed_f16_i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i16 @llvm.fptosi.sat.f16.i16(half %f) + ret i16 %x +} + +define i19 @test_signed_f16_i19(half %f) { +; CHECK-LABEL: test_signed_f16_i19: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomiss %xmm0, %xmm0 +; CHECK-NEXT: maxss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: minss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %ecx +; CHECK-NEXT: cmovnpl %ecx, %eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i19 @llvm.fptosi.sat.f16.i19(half %f) + ret i19 %x +} + +define i32 @test_signed_f16_i32(half %f) { +; CHECK-LABEL: test_signed_f16_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movl $2147483647, %ecx # imm = 0x7FFFFFFF +; CHECK-NEXT: cmovbel %eax, %ecx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomiss %xmm0, %xmm0 +; CHECK-NEXT: cmovnpl %ecx, %eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i32 @llvm.fptosi.sat.f16.i32(half %f) + ret i32 %x +} + +define i50 @test_signed_f16_i50(half %f) { +; CHECK-LABEL: test_signed_f16_i50: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: cvttss2si %xmm0, %rax +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movabsq $-562949953421312, %rcx # imm = 0xFFFE000000000000 +; CHECK-NEXT: cmovaeq %rax, %rcx +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movabsq $562949953421311, %rdx # imm = 0x1FFFFFFFFFFFF +; CHECK-NEXT: cmovbeq %rcx, %rdx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomiss %xmm0, %xmm0 +; CHECK-NEXT: cmovnpq %rdx, %rax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i50 @llvm.fptosi.sat.f16.i50(half %f) + ret i50 %x +} + +define i64 @test_signed_f16_i64(half %f) { +; CHECK-LABEL: test_signed_f16_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: cvttss2si %xmm0, %rax +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF +; CHECK-NEXT: cmovbeq %rax, %rcx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: ucomiss %xmm0, %xmm0 +; CHECK-NEXT: cmovnpq %rcx, %rax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i64 @llvm.fptosi.sat.f16.i64(half %f) + ret i64 %x +} + +define i100 @test_signed_f16_i100(half %f) { +; CHECK-LABEL: test_signed_f16_i100: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: movl $100, %edi +; CHECK-NEXT: callq __fixsfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i100 @llvm.fptosi.sat.f16.i100(half %f) + ret i100 %x +} + +define i128 @test_signed_f16_i128(half %f) { +; CHECK-LABEL: test_signed_f16_i128: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: movl $128, %edi +; CHECK-NEXT: callq __fixsfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i128 @llvm.fptosi.sat.f16.i128(half %f) + ret i128 %x +} + +; +; 16-bit float to unsigned integer +; + +declare i1 @llvm.fptoui.sat.f16.i1 (half) +declare i8 @llvm.fptoui.sat.f16.i8 (half) +declare i13 @llvm.fptoui.sat.f16.i13 (half) +declare i16 @llvm.fptoui.sat.f16.i16 (half) +declare i19 @llvm.fptoui.sat.f16.i19 (half) +declare i32 @llvm.fptoui.sat.f16.i32 (half) +declare i50 @llvm.fptoui.sat.f16.i50 (half) +declare i64 @llvm.fptoui.sat.f16.i64 (half) +declare i100 @llvm.fptoui.sat.f16.i100(half) +declare i128 @llvm.fptoui.sat.f16.i128(half) + +define i1 @test_unsigned_f16_i1(half %f) { +; CHECK-LABEL: test_unsigned_f16_i1: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i1 @llvm.fptoui.sat.f16.i1(half %f) + ret i1 %x +} + +define i8 @test_unsigned_f16_i8(half %f) { +; CHECK-LABEL: test_unsigned_f16_i8: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i8 @llvm.fptoui.sat.f16.i8(half %f) + ret i8 %x +} + +define i13 @test_unsigned_f16_i13(half %f) { +; CHECK-LABEL: test_unsigned_f16_i13: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i13 @llvm.fptoui.sat.f16.i13(half %f) + ret i13 %x +} + +define i16 @test_unsigned_f16_i16(half %f) { +; CHECK-LABEL: test_unsigned_f16_i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: maxss %xmm0, %xmm1 +; CHECK-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero +; CHECK-NEXT: minss %xmm1, %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i16 @llvm.fptoui.sat.f16.i16(half %f) + ret i16 %x +} + +define i19 @test_unsigned_f16_i19(half %f) { +; CHECK-LABEL: test_unsigned_f16_i19: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: maxss %xmm1, %xmm0 +; CHECK-NEXT: minss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: cvttss2si %xmm0, %eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i19 @llvm.fptoui.sat.f16.i19(half %f) + ret i19 %x +} + +define i32 @test_unsigned_f16_i32(half %f) { +; CHECK-LABEL: test_unsigned_f16_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: cvttss2si %xmm0, %rax +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: cmovael %eax, %ecx +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movl $-1, %eax +; CHECK-NEXT: cmovbel %ecx, %eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i32 @llvm.fptoui.sat.f16.i32(half %f) + ret i32 %x +} + +define i50 @test_unsigned_f16_i50(half %f) { +; CHECK-LABEL: test_unsigned_f16_i50: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: cvttss2si %xmm0, %rax +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: cmovaeq %rax, %rcx +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movabsq $1125899906842623, %rax # imm = 0x3FFFFFFFFFFFF +; CHECK-NEXT: cmovbeq %rcx, %rax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i50 @llvm.fptoui.sat.f16.i50(half %f) + ret i50 %x +} + +define i64 @test_unsigned_f16_i64(half %f) { +; CHECK-LABEL: test_unsigned_f16_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: movaps %xmm0, %xmm2 +; CHECK-NEXT: subss %xmm1, %xmm2 +; CHECK-NEXT: cvttss2si %xmm2, %rax +; CHECK-NEXT: movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000 +; CHECK-NEXT: xorq %rax, %rcx +; CHECK-NEXT: cvttss2si %xmm0, %rax +; CHECK-NEXT: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: cmovaeq %rcx, %rax +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: xorps %xmm1, %xmm1 +; CHECK-NEXT: ucomiss %xmm1, %xmm0 +; CHECK-NEXT: cmovaeq %rax, %rcx +; CHECK-NEXT: ucomiss {{.*}}(%rip), %xmm0 +; CHECK-NEXT: movq $-1, %rax +; CHECK-NEXT: cmovbeq %rcx, %rax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i64 @llvm.fptoui.sat.f16.i64(half %f) + ret i64 %x +} + +define i100 @test_unsigned_f16_i100(half %f) { +; CHECK-LABEL: test_unsigned_f16_i100: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: movl $100, %edi +; CHECK-NEXT: callq __fixunssfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i100 @llvm.fptoui.sat.f16.i100(half %f) + ret i100 %x +} + +define i128 @test_unsigned_f16_i128(half %f) { +; CHECK-LABEL: test_unsigned_f16_i128: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: callq __gnu_f2h_ieee +; CHECK-NEXT: movzwl %ax, %edi +; CHECK-NEXT: callq __gnu_h2f_ieee +; CHECK-NEXT: movl $128, %edi +; CHECK-NEXT: callq __fixunssfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i128 @llvm.fptoui.sat.f16.i128(half %f) + ret i128 %x +} + +; +; 128-bit float to signed integer +; + +declare i1 @llvm.fptosi.sat.f128.i1 (fp128) +declare i8 @llvm.fptosi.sat.f128.i8 (fp128) +declare i13 @llvm.fptosi.sat.f128.i13 (fp128) +declare i16 @llvm.fptosi.sat.f128.i16 (fp128) +declare i19 @llvm.fptosi.sat.f128.i19 (fp128) +declare i32 @llvm.fptosi.sat.f128.i32 (fp128) +declare i50 @llvm.fptosi.sat.f128.i50 (fp128) +declare i64 @llvm.fptosi.sat.f128.i64 (fp128) +declare i100 @llvm.fptosi.sat.f128.i100(fp128) +declare i128 @llvm.fptosi.sat.f128.i128(fp128) + +define i1 @test_signed_f128_i1(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i1: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $1, %edx +; CHECK-NEXT: callq __fixtfsi_sat +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i1 @llvm.fptosi.sat.f128.i1(fp128 %f) + ret i1 %x +} + +define i8 @test_signed_f128_i8(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i8: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $8, %edx +; CHECK-NEXT: callq __fixtfsi_sat +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i8 @llvm.fptosi.sat.f128.i8(fp128 %f) + ret i8 %x +} + +define i13 @test_signed_f128_i13(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i13: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $13, %edx +; CHECK-NEXT: callq __fixtfsi_sat +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i13 @llvm.fptosi.sat.f128.i13(fp128 %f) + ret i13 %x +} + +define i16 @test_signed_f128_i16(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $16, %edx +; CHECK-NEXT: callq __fixtfsi_sat +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i16 @llvm.fptosi.sat.f128.i16(fp128 %f) + ret i16 %x +} + +define i19 @test_signed_f128_i19(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i19: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $19, %edx +; CHECK-NEXT: callq __fixtfsi_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i19 @llvm.fptosi.sat.f128.i19(fp128 %f) + ret i19 %x +} + +define i32 @test_signed_f128_i32(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $32, %edx +; CHECK-NEXT: callq __fixtfsi_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i32 @llvm.fptosi.sat.f128.i32(fp128 %f) + ret i32 %x +} + +define i50 @test_signed_f128_i50(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i50: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $50, %edx +; CHECK-NEXT: callq __fixtfdi_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i50 @llvm.fptosi.sat.f128.i50(fp128 %f) + ret i50 %x +} + +define i64 @test_signed_f128_i64(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $64, %edx +; CHECK-NEXT: callq __fixtfdi_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i64 @llvm.fptosi.sat.f128.i64(fp128 %f) + ret i64 %x +} + +define i100 @test_signed_f128_i100(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i100: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $100, %edx +; CHECK-NEXT: callq __fixtfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i100 @llvm.fptosi.sat.f128.i100(fp128 %f) + ret i100 %x +} + +define i128 @test_signed_f128_i128(fp128 %f) { +; CHECK-LABEL: test_signed_f128_i128: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $128, %edx +; CHECK-NEXT: callq __fixtfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i128 @llvm.fptosi.sat.f128.i128(fp128 %f) + ret i128 %x +} + +; +; 128-bit float to unsigned integer +; + +declare i1 @llvm.fptoui.sat.f128.i1 (fp128) +declare i8 @llvm.fptoui.sat.f128.i8 (fp128) +declare i13 @llvm.fptoui.sat.f128.i13 (fp128) +declare i16 @llvm.fptoui.sat.f128.i16 (fp128) +declare i19 @llvm.fptoui.sat.f128.i19 (fp128) +declare i32 @llvm.fptoui.sat.f128.i32 (fp128) +declare i50 @llvm.fptoui.sat.f128.i50 (fp128) +declare i64 @llvm.fptoui.sat.f128.i64 (fp128) +declare i100 @llvm.fptoui.sat.f128.i100(fp128) +declare i128 @llvm.fptoui.sat.f128.i128(fp128) + +define i1 @test_unsigned_f128_i1(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i1: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $1, %edx +; CHECK-NEXT: callq __fixunstfsi_sat +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i1 @llvm.fptoui.sat.f128.i1(fp128 %f) + ret i1 %x +} + +define i8 @test_unsigned_f128_i8(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i8: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $8, %edx +; CHECK-NEXT: callq __fixunstfsi_sat +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i8 @llvm.fptoui.sat.f128.i8(fp128 %f) + ret i8 %x +} + +define i13 @test_unsigned_f128_i13(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i13: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $13, %edx +; CHECK-NEXT: callq __fixunstfsi_sat +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i13 @llvm.fptoui.sat.f128.i13(fp128 %f) + ret i13 %x +} + +define i16 @test_unsigned_f128_i16(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i16: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $16, %edx +; CHECK-NEXT: callq __fixunstfsi_sat +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i16 @llvm.fptoui.sat.f128.i16(fp128 %f) + ret i16 %x +} + +define i19 @test_unsigned_f128_i19(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i19: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $19, %edx +; CHECK-NEXT: callq __fixunstfsi_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i19 @llvm.fptoui.sat.f128.i19(fp128 %f) + ret i19 %x +} + +define i32 @test_unsigned_f128_i32(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $32, %edx +; CHECK-NEXT: callq __fixunstfsi_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i32 @llvm.fptoui.sat.f128.i32(fp128 %f) + ret i32 %x +} + +define i50 @test_unsigned_f128_i50(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i50: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $50, %edx +; CHECK-NEXT: callq __fixunstfdi_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i50 @llvm.fptoui.sat.f128.i50(fp128 %f) + ret i50 %x +} + +define i64 @test_unsigned_f128_i64(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $64, %edx +; CHECK-NEXT: callq __fixunstfdi_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i64 @llvm.fptoui.sat.f128.i64(fp128 %f) + ret i64 %x +} + +define i100 @test_unsigned_f128_i100(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i100: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $100, %edx +; CHECK-NEXT: callq __fixunstfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i100 @llvm.fptoui.sat.f128.i100(fp128 %f) + ret i100 %x +} + +define i128 @test_unsigned_f128_i128(fp128 %f) { +; CHECK-LABEL: test_unsigned_f128_i128: +; CHECK: # %bb.0: +; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: movl $128, %edx +; CHECK-NEXT: callq __fixunstfti_sat +; CHECK-NEXT: popq %rcx +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i128 @llvm.fptoui.sat.f128.i128(fp128 %f) + ret i128 %x +} + +; +; 80-bit float to signed integer +; + +declare i1 @llvm.fptosi.sat.f80.i1 (x86_fp80) +declare i8 @llvm.fptosi.sat.f80.i8 (x86_fp80) +declare i13 @llvm.fptosi.sat.f80.i13 (x86_fp80) +declare i16 @llvm.fptosi.sat.f80.i16 (x86_fp80) +declare i19 @llvm.fptosi.sat.f80.i19 (x86_fp80) +declare i32 @llvm.fptosi.sat.f80.i32 (x86_fp80) +declare i50 @llvm.fptosi.sat.f80.i50 (x86_fp80) +declare i64 @llvm.fptosi.sat.f80.i64 (x86_fp80) +declare i100 @llvm.fptosi.sat.f80.i100(x86_fp80) +declare i128 @llvm.fptosi.sat.f80.i128(x86_fp80) + +define i1 @test_signed_f80_i1(x86_fp80 %f) { +; CHECK-LABEL: test_signed_f80_i1: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistl -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fld1 +; CHECK-NEXT: fchs +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movb $-1, %cl +; CHECK-NEXT: jb .LBB80_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: movb -{{[0-9]+}}(%rsp), %cl +; CHECK-NEXT: .LBB80_2: +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: fldz +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movl $0, %edx +; CHECK-NEXT: jbe .LBB80_3 +; CHECK-NEXT: # %bb.4: +; CHECK-NEXT: fucompi %st(0) +; CHECK-NEXT: jnp .LBB80_5 +; CHECK-NEXT: .LBB80_6: +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq +; CHECK-NEXT: .LBB80_3: +; CHECK-NEXT: movl %ecx, %edx +; CHECK-NEXT: fucompi %st(0) +; CHECK-NEXT: jp .LBB80_6 +; CHECK-NEXT: .LBB80_5: +; CHECK-NEXT: movl %edx, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq + %x = call i1 @llvm.fptosi.sat.f80.i1(x86_fp80 %f) + ret i1 %x +} + +define i8 @test_signed_f80_i8(x86_fp80 %f) { +; CHECK-LABEL: test_signed_f80_i8: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistl -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movb $-128, %cl +; CHECK-NEXT: jb .LBB81_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: movb -{{[0-9]+}}(%rsp), %cl +; CHECK-NEXT: .LBB81_2: +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movb $127, %al +; CHECK-NEXT: jbe .LBB81_3 +; CHECK-NEXT: # %bb.4: +; CHECK-NEXT: fucompi %st(0) +; CHECK-NEXT: jp .LBB81_5 +; CHECK-NEXT: .LBB81_6: +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq +; CHECK-NEXT: .LBB81_3: +; CHECK-NEXT: movl %ecx, %eax +; CHECK-NEXT: fucompi %st(0) +; CHECK-NEXT: jnp .LBB81_6 +; CHECK-NEXT: .LBB81_5: +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: # kill: def $al killed $al killed $eax +; CHECK-NEXT: retq + %x = call i8 @llvm.fptosi.sat.f80.i8(x86_fp80 %f) + ret i8 %x +} + +define i13 @test_signed_f80_i13(x86_fp80 %f) { +; CHECK-LABEL: test_signed_f80_i13: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistl -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movl $61440, %eax # imm = 0xF000 +; CHECK-NEXT: jb .LBB82_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: .LBB82_2: +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movl $4095, %ecx # imm = 0xFFF +; CHECK-NEXT: cmovbel %eax, %ecx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: fucompi %st(0) +; CHECK-NEXT: cmovnpl %ecx, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i13 @llvm.fptosi.sat.f80.i13(x86_fp80 %f) + ret i13 %x +} + +define i16 @test_signed_f80_i16(x86_fp80 %f) { +; CHECK-LABEL: test_signed_f80_i16: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistl -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movl $32768, %eax # imm = 0x8000 +; CHECK-NEXT: jb .LBB83_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: .LBB83_2: +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movl $32767, %ecx # imm = 0x7FFF +; CHECK-NEXT: cmovbel %eax, %ecx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: fucompi %st(0) +; CHECK-NEXT: cmovnpl %ecx, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i16 @llvm.fptosi.sat.f80.i16(x86_fp80 %f) + ret i16 %x +} + +define i19 @test_signed_f80_i19(x86_fp80 %f) { +; CHECK-LABEL: test_signed_f80_i19: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistl -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movl $-262144, %eax # imm = 0xFFFC0000 +; CHECK-NEXT: jb .LBB84_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: .LBB84_2: +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movl $262143, %ecx # imm = 0x3FFFF +; CHECK-NEXT: cmovbel %eax, %ecx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: fucompi %st(0) +; CHECK-NEXT: cmovnpl %ecx, %eax +; CHECK-NEXT: retq + %x = call i19 @llvm.fptosi.sat.f80.i19(x86_fp80 %f) + ret i19 %x +} + +define i32 @test_signed_f80_i32(x86_fp80 %f) { +; CHECK-LABEL: test_signed_f80_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistl -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movl $-2147483648, %eax # imm = 0x80000000 +; CHECK-NEXT: jb .LBB85_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: .LBB85_2: +; CHECK-NEXT: fldl {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movl $2147483647, %ecx # imm = 0x7FFFFFFF +; CHECK-NEXT: cmovbel %eax, %ecx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: fucompi %st(0) +; CHECK-NEXT: cmovnpl %ecx, %eax +; CHECK-NEXT: retq + %x = call i32 @llvm.fptosi.sat.f80.i32(x86_fp80 %f) + ret i32 %x +} + +define i50 @test_signed_f80_i50(x86_fp80 %f) { +; CHECK-LABEL: test_signed_f80_i50: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fld %st(0) +; CHECK-NEXT: fistpll -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: jb .LBB86_1 +; CHECK-NEXT: # %bb.2: +; CHECK-NEXT: movq -{{[0-9]+}}(%rsp), %rax +; CHECK-NEXT: jmp .LBB86_3 +; CHECK-NEXT: .LBB86_1: +; CHECK-NEXT: movabsq $-562949953421312, %rax # imm = 0xFFFE000000000000 +; CHECK-NEXT: .LBB86_3: +; CHECK-NEXT: fldl {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movabsq $562949953421311, %rcx # imm = 0x1FFFFFFFFFFFF +; CHECK-NEXT: cmovbeq %rax, %rcx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: fucompi %st(0) +; CHECK-NEXT: cmovnpq %rcx, %rax +; CHECK-NEXT: retq + %x = call i50 @llvm.fptosi.sat.f80.i50(x86_fp80 %f) + ret i50 %x +} + +define i64 @test_signed_f80_i64(x86_fp80 %f) { +; CHECK-LABEL: test_signed_f80_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fld %st(0) +; CHECK-NEXT: fistpll -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: jb .LBB87_1 +; CHECK-NEXT: # %bb.2: +; CHECK-NEXT: movq -{{[0-9]+}}(%rsp), %rax +; CHECK-NEXT: jmp .LBB87_3 +; CHECK-NEXT: .LBB87_1: +; CHECK-NEXT: movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000 +; CHECK-NEXT: .LBB87_3: +; CHECK-NEXT: fldt {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: movabsq $9223372036854775807, %rcx # imm = 0x7FFFFFFFFFFFFFFF +; CHECK-NEXT: cmovbeq %rax, %rcx +; CHECK-NEXT: xorl %eax, %eax +; CHECK-NEXT: fucompi %st(0) +; CHECK-NEXT: cmovnpq %rcx, %rax +; CHECK-NEXT: retq + %x = call i64 @llvm.fptosi.sat.f80.i64(x86_fp80 %f) + ret i64 %x +} + +define i100 @test_signed_f80_i100(x86_fp80 %f) { +; CHECK-LABEL: test_signed_f80_i100: +; CHECK: # %bb.0: +; CHECK-NEXT: subq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fstpt (%rsp) +; CHECK-NEXT: movl $100, %edi +; CHECK-NEXT: callq __fixxfti_sat +; CHECK-NEXT: addq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i100 @llvm.fptosi.sat.f80.i100(x86_fp80 %f) + ret i100 %x +} + +define i128 @test_signed_f80_i128(x86_fp80 %f) { +; CHECK-LABEL: test_signed_f80_i128: +; CHECK: # %bb.0: +; CHECK-NEXT: subq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fstpt (%rsp) +; CHECK-NEXT: movl $128, %edi +; CHECK-NEXT: callq __fixxfti_sat +; CHECK-NEXT: addq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i128 @llvm.fptosi.sat.f80.i128(x86_fp80 %f) + ret i128 %x +} + +; +; 80-bit float to unsigned integer +; + +declare i1 @llvm.fptoui.sat.f80.i1 (x86_fp80) +declare i8 @llvm.fptoui.sat.f80.i8 (x86_fp80) +declare i13 @llvm.fptoui.sat.f80.i13 (x86_fp80) +declare i16 @llvm.fptoui.sat.f80.i16 (x86_fp80) +declare i19 @llvm.fptoui.sat.f80.i19 (x86_fp80) +declare i32 @llvm.fptoui.sat.f80.i32 (x86_fp80) +declare i50 @llvm.fptoui.sat.f80.i50 (x86_fp80) +declare i64 @llvm.fptoui.sat.f80.i64 (x86_fp80) +declare i100 @llvm.fptoui.sat.f80.i100(x86_fp80) +declare i128 @llvm.fptoui.sat.f80.i128(x86_fp80) + +define i1 @test_unsigned_f80_i1(x86_fp80 %f) { +; CHECK-LABEL: test_unsigned_f80_i1: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistl -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldz +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: jb .LBB90_1 +; CHECK-NEXT: # %bb.2: +; CHECK-NEXT: movb -{{[0-9]+}}(%rsp), %cl +; CHECK-NEXT: jmp .LBB90_3 +; CHECK-NEXT: .LBB90_1: +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: .LBB90_3: +; CHECK-NEXT: fld1 +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucompi %st(1) +; CHECK-NEXT: fstp %st(0) +; CHECK-NEXT: movb $1, %al +; CHECK-NEXT: ja .LBB90_5 +; CHECK-NEXT: # %bb.4: +; CHECK-NEXT: movl %ecx, %eax +; CHECK-NEXT: .LBB90_5: +; CHECK-NEXT: retq + %x = call i1 @llvm.fptoui.sat.f80.i1(x86_fp80 %f) + ret i1 %x +} + +define i8 @test_unsigned_f80_i8(x86_fp80 %f) { +; CHECK-LABEL: test_unsigned_f80_i8: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistl -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldz +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: jb .LBB91_1 +; CHECK-NEXT: # %bb.2: +; CHECK-NEXT: movb -{{[0-9]+}}(%rsp), %cl +; CHECK-NEXT: jmp .LBB91_3 +; CHECK-NEXT: .LBB91_1: +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: .LBB91_3: +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucompi %st(1) +; CHECK-NEXT: fstp %st(0) +; CHECK-NEXT: movb $-1, %al +; CHECK-NEXT: ja .LBB91_5 +; CHECK-NEXT: # %bb.4: +; CHECK-NEXT: movl %ecx, %eax +; CHECK-NEXT: .LBB91_5: +; CHECK-NEXT: retq + %x = call i8 @llvm.fptoui.sat.f80.i8(x86_fp80 %f) + ret i8 %x +} + +define i13 @test_unsigned_f80_i13(x86_fp80 %f) { +; CHECK-LABEL: test_unsigned_f80_i13: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistl -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: fldz +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: jb .LBB92_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ecx +; CHECK-NEXT: .LBB92_2: +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucompi %st(1) +; CHECK-NEXT: fstp %st(0) +; CHECK-NEXT: movl $8191, %eax # imm = 0x1FFF +; CHECK-NEXT: cmovbel %ecx, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i13 @llvm.fptoui.sat.f80.i13(x86_fp80 %f) + ret i13 %x +} + +define i16 @test_unsigned_f80_i16(x86_fp80 %f) { +; CHECK-LABEL: test_unsigned_f80_i16: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistl -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: fldz +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: jb .LBB93_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ecx +; CHECK-NEXT: .LBB93_2: +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucompi %st(1) +; CHECK-NEXT: fstp %st(0) +; CHECK-NEXT: movl $65535, %eax # imm = 0xFFFF +; CHECK-NEXT: cmovbel %ecx, %eax +; CHECK-NEXT: # kill: def $ax killed $ax killed $eax +; CHECK-NEXT: retq + %x = call i16 @llvm.fptoui.sat.f80.i16(x86_fp80 %f) + ret i16 %x +} + +define i19 @test_unsigned_f80_i19(x86_fp80 %f) { +; CHECK-LABEL: test_unsigned_f80_i19: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fld %st(0) +; CHECK-NEXT: fistpll -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: fldz +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: jb .LBB94_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ecx +; CHECK-NEXT: .LBB94_2: +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucompi %st(1) +; CHECK-NEXT: fstp %st(0) +; CHECK-NEXT: movl $524287, %eax # imm = 0x7FFFF +; CHECK-NEXT: cmovbel %ecx, %eax +; CHECK-NEXT: retq + %x = call i19 @llvm.fptoui.sat.f80.i19(x86_fp80 %f) + ret i19 %x +} + +define i32 @test_unsigned_f80_i32(x86_fp80 %f) { +; CHECK-LABEL: test_unsigned_f80_i32: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fld %st(0) +; CHECK-NEXT: fistpll -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: fldz +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: jb .LBB95_2 +; CHECK-NEXT: # %bb.1: +; CHECK-NEXT: movl -{{[0-9]+}}(%rsp), %ecx +; CHECK-NEXT: .LBB95_2: +; CHECK-NEXT: fldl {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucompi %st(1) +; CHECK-NEXT: fstp %st(0) +; CHECK-NEXT: movl $-1, %eax +; CHECK-NEXT: cmovbel %ecx, %eax +; CHECK-NEXT: retq + %x = call i32 @llvm.fptoui.sat.f80.i32(x86_fp80 %f) + ret i32 %x +} + +define i50 @test_unsigned_f80_i50(x86_fp80 %f) { +; CHECK-LABEL: test_unsigned_f80_i50: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fld %st(1) +; CHECK-NEXT: fsub %st(1) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistpll -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fld %st(1) +; CHECK-NEXT: fistpll -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fucompi %st(1) +; CHECK-NEXT: jbe .LBB96_1 +; CHECK-NEXT: # %bb.2: +; CHECK-NEXT: movq -{{[0-9]+}}(%rsp), %rax +; CHECK-NEXT: jmp .LBB96_3 +; CHECK-NEXT: .LBB96_1: +; CHECK-NEXT: movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000 +; CHECK-NEXT: xorq -{{[0-9]+}}(%rsp), %rax +; CHECK-NEXT: .LBB96_3: +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: fldz +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: cmovaeq %rax, %rcx +; CHECK-NEXT: fldl {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucompi %st(1) +; CHECK-NEXT: fstp %st(0) +; CHECK-NEXT: movabsq $1125899906842623, %rax # imm = 0x3FFFFFFFFFFFF +; CHECK-NEXT: cmovbeq %rcx, %rax +; CHECK-NEXT: retq + %x = call i50 @llvm.fptoui.sat.f80.i50(x86_fp80 %f) + ret i50 %x +} + +define i64 @test_unsigned_f80_i64(x86_fp80 %f) { +; CHECK-LABEL: test_unsigned_f80_i64: +; CHECK: # %bb.0: +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: flds {{.*}}(%rip) +; CHECK-NEXT: fld %st(1) +; CHECK-NEXT: fsub %st(1) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fistpll -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fnstcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movzwl -{{[0-9]+}}(%rsp), %eax +; CHECK-NEXT: movw $3199, -{{[0-9]+}}(%rsp) # imm = 0xC7F +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: movw %ax, -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fld %st(1) +; CHECK-NEXT: fistpll -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fldcw -{{[0-9]+}}(%rsp) +; CHECK-NEXT: fucompi %st(1) +; CHECK-NEXT: jbe .LBB97_1 +; CHECK-NEXT: # %bb.2: +; CHECK-NEXT: movq -{{[0-9]+}}(%rsp), %rax +; CHECK-NEXT: jmp .LBB97_3 +; CHECK-NEXT: .LBB97_1: +; CHECK-NEXT: movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000 +; CHECK-NEXT: xorq -{{[0-9]+}}(%rsp), %rax +; CHECK-NEXT: .LBB97_3: +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: fldz +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucomi %st(1) +; CHECK-NEXT: fstp %st(1) +; CHECK-NEXT: cmovaeq %rax, %rcx +; CHECK-NEXT: fldt {{.*}}(%rip) +; CHECK-NEXT: fxch %st(1) +; CHECK-NEXT: fucompi %st(1) +; CHECK-NEXT: fstp %st(0) +; CHECK-NEXT: movq $-1, %rax +; CHECK-NEXT: cmovbeq %rcx, %rax +; CHECK-NEXT: retq + %x = call i64 @llvm.fptoui.sat.f80.i64(x86_fp80 %f) + ret i64 %x +} + +define i100 @test_unsigned_f80_i100(x86_fp80 %f) { +; CHECK-LABEL: test_unsigned_f80_i100: +; CHECK: # %bb.0: +; CHECK-NEXT: subq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fstpt (%rsp) +; CHECK-NEXT: movl $100, %edi +; CHECK-NEXT: callq __fixunsxfti_sat +; CHECK-NEXT: addq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i100 @llvm.fptoui.sat.f80.i100(x86_fp80 %f) + ret i100 %x +} + +define i128 @test_unsigned_f80_i128(x86_fp80 %f) { +; CHECK-LABEL: test_unsigned_f80_i128: +; CHECK: # %bb.0: +; CHECK-NEXT: subq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 32 +; CHECK-NEXT: fldt {{[0-9]+}}(%rsp) +; CHECK-NEXT: fstpt (%rsp) +; CHECK-NEXT: movl $128, %edi +; CHECK-NEXT: callq __fixunsxfti_sat +; CHECK-NEXT: addq $24, %rsp +; CHECK-NEXT: .cfi_def_cfa_offset 8 +; CHECK-NEXT: retq + %x = call i128 @llvm.fptoui.sat.f80.i128(x86_fp80 %f) + ret i128 %x +}