diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h --- a/llvm/lib/Target/PowerPC/PPCISelLowering.h +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h @@ -434,6 +434,12 @@ /// Constrained direct move from VSR instruction. STRICT_MFVSR = ISD::FIRST_TARGET_STRICTFP_OPCODE, + /// Constrained integer-to-floating-point conversion instructions. + STRICT_FCFID, + STRICT_FCFIDU, + STRICT_FCFIDS, + STRICT_FCFIDUS, + /// CHAIN = STBRX CHAIN, GPRC, Ptr, Type - This is a /// byte-swapping store instruction. It byte-swaps the low "Type" bits of /// the GPRC input, then stores it through Ptr. Type can be either i16 or diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -216,6 +216,13 @@ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); if (isPPC64 || Subtarget.hasFPCVT()) { + setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i1, Promote); + AddPromotedToType (ISD::STRICT_SINT_TO_FP, MVT::i1, + isPPC64 ? MVT::i64 : MVT::i32); + setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i1, Promote); + AddPromotedToType (ISD::STRICT_UINT_TO_FP, MVT::i1, + isPPC64 ? MVT::i64 : MVT::i32); + setOperationAction(ISD::SINT_TO_FP, MVT::i1, Promote); AddPromotedToType (ISD::SINT_TO_FP, MVT::i1, isPPC64 ? MVT::i64 : MVT::i32); @@ -223,6 +230,8 @@ AddPromotedToType(ISD::UINT_TO_FP, MVT::i1, isPPC64 ? MVT::i64 : MVT::i32); } else { + setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i1, Custom); + setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i1, Custom); setOperationAction(ISD::SINT_TO_FP, MVT::i1, Custom); setOperationAction(ISD::UINT_TO_FP, MVT::i1, Custom); } @@ -424,6 +433,8 @@ if (Subtarget.hasSPE()) { // SPE has built-in conversions setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i32, Legal); + setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i32, Legal); + setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i32, Legal); setOperationAction(ISD::FP_TO_SINT, MVT::i32, Legal); setOperationAction(ISD::SINT_TO_FP, MVT::i32, Legal); setOperationAction(ISD::UINT_TO_FP, MVT::i32, Legal); @@ -433,6 +444,8 @@ setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); // PowerPC does not have [U|S]INT_TO_FP + setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i32, Expand); + setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i32, Expand); setOperationAction(ISD::SINT_TO_FP, MVT::i32, Expand); setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); } @@ -564,6 +577,8 @@ // They also have instructions for converting between i64 and fp. setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i64, Custom); setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::i64, Expand); + setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i64, Custom); + setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i64, Expand); setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom); setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand); setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom); @@ -573,8 +588,10 @@ setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::i32, Custom); setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); - if (Subtarget.hasLFIWAX() || Subtarget.isPPC64()) + if (Subtarget.hasLFIWAX() || Subtarget.isPPC64()) { + setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i32, Custom); setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom); + } } else { // PowerPC does not have FP_TO_UINT on 32-bit implementations. if (Subtarget.hasSPE()) { @@ -591,6 +608,8 @@ if (Subtarget.has64BitSupport()) { setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i64, Custom); setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::i64, Custom); + setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i64, Custom); + setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i64, Custom); setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom); setOperationAction(ISD::FP_TO_UINT, MVT::i64, Custom); setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom); @@ -599,6 +618,8 @@ setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i32, Custom); setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::i32, Custom); + setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::i32, Custom); + setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i32, Custom); setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom); @@ -1581,6 +1602,10 @@ case PPCISD::LD_SPLAT: return "PPCISD::LD_SPLAT"; case PPCISD::FNMSUB: return "PPCISD::FNMSUB"; case PPCISD::STRICT_MFVSR: return "PPCISD::STRICT_MFVSR"; + case PPCISD::STRICT_FCFID: return "PPCISD::STRICT_FCFID"; + case PPCISD::STRICT_FCFIDU: return "PPCISD::STRICT_FCFIDU"; + case PPCISD::STRICT_FCFIDS: return "PPCISD::STRICT_FCFIDS"; + case PPCISD::STRICT_FCFIDUS: return "PPCISD::STRICT_FCFIDUS"; } return nullptr; } @@ -8141,14 +8166,11 @@ return Op; } -static SDValue getFPNode(unsigned Opc, EVT VT, SDValue Op, SDValue Chain, - SelectionDAG &DAG, bool Strict) { - SDLoc dl(Op); - if (!Strict) - return DAG.getNode(Opc, dl, VT, Op); +static SDValue getStrictFPNode(unsigned Opc, EVT VT, ArrayRef Ops, + SelectionDAG &DAG) { + assert(Ops.size() >= 2 && Ops[0] && "Missing chain for strict nodes!"); // Try to generate a STRICT node version - assert(Chain && "Missing chain for creating strict nodes"); unsigned NewOpc = ISD::DELETED_NODE; switch (Opc) { default: @@ -8156,6 +8178,18 @@ case PPCISD::MFVSR: NewOpc = PPCISD::STRICT_MFVSR; break; + case PPCISD::FCFID: + NewOpc = PPCISD::STRICT_FCFID; + break; + case PPCISD::FCFIDU: + NewOpc = PPCISD::STRICT_FCFIDU; + break; + case PPCISD::FCFIDS: + NewOpc = PPCISD::STRICT_FCFIDS; + break; + case PPCISD::FCFIDUS: + NewOpc = PPCISD::STRICT_FCFIDUS; + break; #define DAG_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN) \ case ISD::DAGN: \ NewOpc = ISD::STRICT_##DAGN; \ @@ -8165,7 +8199,21 @@ #undef DAG_INSTRUCTION #undef CMP_INSTRUCTION } - return DAG.getNode(NewOpc, dl, {VT, MVT::Other}, {Chain, Op}); + return DAG.getNode(NewOpc, SDLoc(Ops[1]), {VT, MVT::Other}, Ops); +} + +static SDValue getFPNode(unsigned Opc, EVT VT, SDValue Op, SDValue Chain, + SelectionDAG& DAG, bool Strict) { + if (!Strict) + return DAG.getNode(Opc, SDLoc(Op), VT, Op); + return getStrictFPNode(Opc, VT, { Chain, Op }, DAG); +} + +static SDValue getFPNode(unsigned Opc, EVT VT, SDValue Op1, SDValue Op2, + SDValue Chain, SelectionDAG& DAG, bool Strict) { + if (!Strict) + return DAG.getNode(Opc, SDLoc(Op1), VT, Op1, Op2); + return getStrictFPNode(Opc, VT, { Chain, Op1, Op2 }, DAG); } static SDValue convertFPToInt(SDValue Op, SelectionDAG &DAG, @@ -8410,23 +8458,29 @@ continue; if (UI->getOpcode() != ISD::SINT_TO_FP && - UI->getOpcode() != ISD::UINT_TO_FP) + UI->getOpcode() != ISD::UINT_TO_FP && + UI->getOpcode() != ISD::STRICT_SINT_TO_FP && + UI->getOpcode() != ISD::STRICT_UINT_TO_FP) return true; } return false; } -static SDValue convertIntToFP(SDValue Op, SDValue Src, SelectionDAG &DAG, - const PPCSubtarget &Subtarget) { - bool Signed = Op.getOpcode() == ISD::SINT_TO_FP; - SDLoc dl(Op); +SDValue convertIntToFP(SDValue Op, SDValue Src, + SelectionDAG &DAG, + const PPCSubtarget& Subtarget) { + bool Strict = Op->isStrictFPOpcode(); + bool Signed = (Op.getOpcode() == ISD::SINT_TO_FP || + Op.getOpcode() == ISD::STRICT_SINT_TO_FP); // If we have FCFIDS, then use it when converting to single-precision. // Otherwise, convert to double-precision and then round. - bool Single = Op.getValueType() == MVT::f32 && Subtarget.hasFPCVT(); - unsigned ConvOpc = Single ? (Signed ? PPCISD::FCFIDS : PPCISD::FCFIDUS) - : (Signed ? PPCISD::FCFID : PPCISD::FCFIDU); - return DAG.getNode(ConvOpc, dl, Single ? MVT::f32 : MVT::f64, Src); + bool Single = (Op.getValueType() == MVT::f32 && Subtarget.hasFPCVT()); + unsigned ConvOpc = Single + ? (Signed ? PPCISD::FCFIDS : PPCISD::FCFIDUS) + : (Signed ? PPCISD::FCFID : PPCISD::FCFIDU); + return getFPNode(ConvOpc, Single ? MVT::f32 : MVT::f64, Src, + Op.getOperand(0), DAG, Strict); } /// Custom lowers integer to floating point conversions to use @@ -8440,12 +8494,12 @@ "Invalid floating point type as target of conversion"); assert(Subtarget.hasFPCVT() && "Int to FP conversions with direct moves require FPCVT"); - SDValue Src = Op.getOperand(0); + SDValue Src = Op.getOperand(Op->isStrictFPOpcode() ? 1 : 0); bool WordInt = Src.getSimpleValueType().SimpleTy == MVT::i32; bool Signed = Op.getOpcode() == ISD::SINT_TO_FP; unsigned MovOpc = (WordInt && !Signed) ? PPCISD::MTVSRZ : PPCISD::MTVSRA; - SDValue Mov = DAG.getNode(MovOpc, dl, MVT::f64, Src); - return convertIntToFP(Op, Mov, DAG, Subtarget); + SDValue FP = DAG.getNode(MovOpc, dl, MVT::f64, Src); + return convertIntToFP(Op, FP, DAG, Subtarget); } static SDValue widenVec(SelectionDAG &DAG, SDValue Vec, const SDLoc &dl) { @@ -8521,8 +8575,10 @@ SDValue PPCTargetLowering::LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) const { SDLoc dl(Op); - SDValue Src = Op.getOperand(0); - bool Signed = Op.getOpcode() == ISD::SINT_TO_FP; + bool Strict = Op->isStrictFPOpcode(); + bool Signed = (Op.getOpcode() == ISD::SINT_TO_FP || + Op.getOpcode() == ISD::STRICT_SINT_TO_FP); + SDValue Src = Op.getOperand(Strict ? 1 : 0); EVT InVT = Src.getValueType(); EVT OutVT = Op.getValueType(); @@ -8690,8 +8746,8 @@ SDValue FP = convertIntToFP(Op, Bits, DAG, Subtarget); if (Op.getValueType() == MVT::f32 && !Subtarget.hasFPCVT()) - FP = DAG.getNode(ISD::FP_ROUND, dl, - MVT::f32, FP, DAG.getIntPtrConstant(0, dl)); + FP = getFPNode(ISD::FP_ROUND, MVT::f32, FP, DAG.getIntPtrConstant(0, dl), + Op.getOperand(0), DAG, Strict); return FP; } @@ -8759,8 +8815,8 @@ // FCFID it and return it. SDValue FP = convertIntToFP(Op, Ld, DAG, Subtarget); if (Op.getValueType() == MVT::f32 && !Subtarget.hasFPCVT()) - FP = DAG.getNode(ISD::FP_ROUND, dl, MVT::f32, FP, - DAG.getIntPtrConstant(0, dl)); + FP = getFPNode(ISD::FP_ROUND, MVT::f32, FP, DAG.getIntPtrConstant(0, dl), + Op.getOperand(0), DAG, Strict); return FP; } @@ -10930,6 +10986,8 @@ case ISD::STRICT_FP_TO_SINT: case ISD::FP_TO_UINT: case ISD::FP_TO_SINT: return LowerFP_TO_INT(Op, DAG, SDLoc(Op)); + case ISD::STRICT_UINT_TO_FP: + case ISD::STRICT_SINT_TO_FP: case ISD::UINT_TO_FP: case ISD::SINT_TO_FP: return LowerINT_TO_FP(Op, DAG); case ISD::FLT_ROUNDS_: return LowerFLT_ROUNDS_(Op, DAG); diff --git a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td --- a/llvm/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/llvm/lib/Target/PowerPC/PPCInstr64Bit.td @@ -1496,6 +1496,15 @@ def : Pat<(unaligned4store i64:$rS, xoaddr:$dst), (STDX $rS, xoaddr:$dst)>; +def : Pat<(f64 (PPCstrict_fcfid f64:$A)), + (f64 (FCFID f64:$A))>; +def : Pat<(f64 (PPCstrict_fcfidu f64:$A)), + (f64 (FCFIDU f64:$A))>; +def : Pat<(f32 (PPCstrict_fcfids f64:$A)), + (f32 (FCFIDS f64:$A))>; +def : Pat<(f32 (PPCstrict_fcfidus f64:$A)), + (f32 (FCFIDUS f64:$A))>; + // 64-bits atomic loads and stores def : Pat<(atomic_load_64 iaddrX4:$src), (LD memrix:$src)>; def : Pat<(atomic_load_64 xaddrX4:$src), (LDX memrr:$src)>; diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -130,6 +130,15 @@ def PPCfctiduz: SDNode<"PPCISD::FCTIDUZ",SDTFPUnaryOp, []>; def PPCfctiwuz: SDNode<"PPCISD::FCTIWUZ",SDTFPUnaryOp, []>; +def PPCstrict_fcfid : SDNode<"PPCISD::STRICT_FCFID", + SDTFPUnaryOp, [SDNPHasChain]>; +def PPCstrict_fcfidu : SDNode<"PPCISD::STRICT_FCFIDU", + SDTFPUnaryOp, [SDNPHasChain]>; +def PPCstrict_fcfids : SDNode<"PPCISD::STRICT_FCFIDS", + SDTFPRoundOp, [SDNPHasChain]>; +def PPCstrict_fcfidus : SDNode<"PPCISD::STRICT_FCFIDUS", + SDTFPRoundOp, [SDNPHasChain]>; + def PPCcv_fp_to_uint_in_vsr: SDNode<"PPCISD::FP_TO_UINT_IN_VSR", SDT_PPCcv_fp_to_int, []>; def PPCcv_fp_to_sint_in_vsr: diff --git a/llvm/lib/Target/PowerPC/PPCInstrSPE.td b/llvm/lib/Target/PowerPC/PPCInstrSPE.td --- a/llvm/lib/Target/PowerPC/PPCInstrSPE.td +++ b/llvm/lib/Target/PowerPC/PPCInstrSPE.td @@ -158,7 +158,7 @@ def EFDCFSI : EFXForm_2a<753, (outs sperc:$RT), (ins gprc:$RB), "efdcfsi $RT, $RB", IIC_FPDGeneral, - [(set f64:$RT, (sint_to_fp i32:$RB))]>; + [(set f64:$RT, (any_sint_to_fp i32:$RB))]>; def EFDCFSID : EFXForm_2a<739, (outs sperc:$RT), (ins gprc:$RB), "efdcfsid $RT, $RB", IIC_FPDGeneral, @@ -169,7 +169,7 @@ def EFDCFUI : EFXForm_2a<752, (outs sperc:$RT), (ins gprc:$RB), "efdcfui $RT, $RB", IIC_FPDGeneral, - [(set f64:$RT, (uint_to_fp i32:$RB))]>; + [(set f64:$RT, (any_uint_to_fp i32:$RB))]>; def EFDCFUID : EFXForm_2a<738, (outs sperc:$RT), (ins gprc:$RB), "efdcfuid $RT, $RB", IIC_FPDGeneral, @@ -261,14 +261,14 @@ def EFSCFSI : EFXForm_2a<721, (outs spe4rc:$RT), (ins gprc:$RB), "efscfsi $RT, $RB", IIC_FPSGeneral, - [(set f32:$RT, (sint_to_fp i32:$RB))]>; + [(set f32:$RT, (any_sint_to_fp i32:$RB))]>; def EFSCFUF : EFXForm_2a<722, (outs spe4rc:$RT), (ins spe4rc:$RB), "efscfuf $RT, $RB", IIC_FPSGeneral, []>; def EFSCFUI : EFXForm_2a<720, (outs spe4rc:$RT), (ins gprc:$RB), "efscfui $RT, $RB", IIC_FPSGeneral, - [(set f32:$RT, (uint_to_fp i32:$RB))]>; + [(set f32:$RT, (any_uint_to_fp i32:$RB))]>; let isCompare = 1 in { def EFSCMPEQ : EFXForm_3<718, (outs crrc:$crD), (ins spe4rc:$RA, spe4rc:$RB), diff --git a/llvm/lib/Target/PowerPC/PPCInstrVSX.td b/llvm/lib/Target/PowerPC/PPCInstrVSX.td --- a/llvm/lib/Target/PowerPC/PPCInstrVSX.td +++ b/llvm/lib/Target/PowerPC/PPCInstrVSX.td @@ -2423,6 +2423,15 @@ (and v4i32:$B, v4i32:$C))), (v4i32 (XXSEL $A, $B, $C))>; +def : Pat<(f64 (PPCstrict_fcfid f64:$A)), + (f64 (XSCVSXDDP f64:$A))>; +def : Pat<(f64 (PPCstrict_fcfidu f64:$A)), + (f64 (XSCVUXDDP f64:$A))>; +def : Pat<(f32 (PPCstrict_fcfids f64:$A)), + (f32 (XSCVSXDSP f64:$A))>; +def : Pat<(f32 (PPCstrict_fcfidus f64:$A)), + (f32 (XSCVUXDSP f64:$A))>; + // Additional fnmsub pattern for PPC specific ISD opcode def : Pat<(PPCfnmsub f64:$A, f64:$B, f64:$C), (XSNMSUBADP $C, $A, $B)>; @@ -3543,25 +3552,25 @@ def : Pat<(PPCfnmsub f128:$A, f128:$B, (fneg f128:$C)), (XSNMADDQP $C, $A, $B)>; -def : Pat<(f128 (sint_to_fp i64:$src)), +def : Pat<(f128 (any_sint_to_fp i64:$src)), (f128 (XSCVSDQP (COPY_TO_REGCLASS $src, VFRC)))>; -def : Pat<(f128 (sint_to_fp (i64 (PPCmfvsr f64:$src)))), +def : Pat<(f128 (any_sint_to_fp (i64 (PPCmfvsr f64:$src)))), (f128 (XSCVSDQP $src))>; -def : Pat<(f128 (sint_to_fp (i32 (PPCmfvsr f64:$src)))), +def : Pat<(f128 (any_sint_to_fp (i32 (PPCmfvsr f64:$src)))), (f128 (XSCVSDQP (VEXTSW2Ds $src)))>; -def : Pat<(f128 (uint_to_fp i64:$src)), +def : Pat<(f128 (any_uint_to_fp i64:$src)), (f128 (XSCVUDQP (COPY_TO_REGCLASS $src, VFRC)))>; -def : Pat<(f128 (uint_to_fp (i64 (PPCmfvsr f64:$src)))), +def : Pat<(f128 (any_uint_to_fp (i64 (PPCmfvsr f64:$src)))), (f128 (XSCVUDQP $src))>; // Convert (Un)Signed Word -> QP. -def : Pat<(f128 (sint_to_fp i32:$src)), +def : Pat<(f128 (any_sint_to_fp i32:$src)), (f128 (XSCVSDQP (MTVSRWA $src)))>; -def : Pat<(f128 (sint_to_fp (i32 (load xoaddr:$src)))), +def : Pat<(f128 (any_sint_to_fp (i32 (load xoaddr:$src)))), (f128 (XSCVSDQP (LIWAX xoaddr:$src)))>; -def : Pat<(f128 (uint_to_fp i32:$src)), +def : Pat<(f128 (any_uint_to_fp i32:$src)), (f128 (XSCVUDQP (MTVSRWZ $src)))>; -def : Pat<(f128 (uint_to_fp (i32 (load xoaddr:$src)))), +def : Pat<(f128 (any_uint_to_fp (i32 (load xoaddr:$src)))), (f128 (XSCVUDQP (LIWZX xoaddr:$src)))>; // Pattern for matching Vector HP -> Vector SP intrinsic. Defined as a diff --git a/llvm/test/CodeGen/PowerPC/fp-strict-conv-f128.ll b/llvm/test/CodeGen/PowerPC/fp-strict-conv-f128.ll --- a/llvm/test/CodeGen/PowerPC/fp-strict-conv-f128.ll +++ b/llvm/test/CodeGen/PowerPC/fp-strict-conv-f128.ll @@ -27,6 +27,16 @@ declare i128 @llvm.experimental.constrained.fptosi.i128.f128(fp128, metadata) declare i128 @llvm.experimental.constrained.fptoui.i128.f128(fp128, metadata) +declare fp128 @llvm.experimental.constrained.sitofp.f128.i32(i32, metadata, metadata) +declare fp128 @llvm.experimental.constrained.sitofp.f128.i64(i64, metadata, metadata) +declare fp128 @llvm.experimental.constrained.uitofp.f128.i32(i32, metadata, metadata) +declare fp128 @llvm.experimental.constrained.uitofp.f128.i64(i64, metadata, metadata) + +declare ppc_fp128 @llvm.experimental.constrained.sitofp.ppcf128.i32(i32, metadata, metadata) +declare ppc_fp128 @llvm.experimental.constrained.sitofp.ppcf128.i64(i64, metadata, metadata) +declare ppc_fp128 @llvm.experimental.constrained.uitofp.ppcf128.i32(i32, metadata, metadata) +declare ppc_fp128 @llvm.experimental.constrained.uitofp.ppcf128.i64(i64, metadata, metadata) + define i128 @q_to_i128(fp128 %m) #0 { ; P8-LABEL: q_to_i128: ; P8: # %bb.0: # %entry @@ -842,4 +852,212 @@ ret i32 %conv } +define fp128 @i32_to_q(i32 signext %m) #0 { +; P8-LABEL: i32_to_q: +; P8: # %bb.0: # %entry +; P8-NEXT: mflr r0 +; P8-NEXT: std r0, 16(r1) +; P8-NEXT: stdu r1, -112(r1) +; P8-NEXT: .cfi_def_cfa_offset 112 +; P8-NEXT: .cfi_offset lr, 16 +; P8-NEXT: bl __floatsikf +; P8-NEXT: nop +; P8-NEXT: addi r1, r1, 112 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: i32_to_q: +; P9: # %bb.0: # %entry +; P9-NEXT: mtvsrwa v2, r3 +; P9-NEXT: xscvsdqp v2, v2 +; P9-NEXT: blr +; +; NOVSX-LABEL: i32_to_q: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: mflr r0 +; NOVSX-NEXT: std r0, 16(r1) +; NOVSX-NEXT: stdu r1, -32(r1) +; NOVSX-NEXT: .cfi_def_cfa_offset 32 +; NOVSX-NEXT: .cfi_offset lr, 16 +; NOVSX-NEXT: bl __floatsikf +; NOVSX-NEXT: nop +; NOVSX-NEXT: addi r1, r1, 32 +; NOVSX-NEXT: ld r0, 16(r1) +; NOVSX-NEXT: mtlr r0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: i32_to_q: +; SPE: # %bb.0: # %entry +; SPE-NEXT: mflr r0 +; SPE-NEXT: stw r0, 4(r1) +; SPE-NEXT: stwu r1, -16(r1) +; SPE-NEXT: .cfi_def_cfa_offset 16 +; SPE-NEXT: .cfi_offset lr, 4 +; SPE-NEXT: bl __floatsikf +; SPE-NEXT: lwz r0, 20(r1) +; SPE-NEXT: addi r1, r1, 16 +; SPE-NEXT: mtlr r0 +; SPE-NEXT: blr +entry: + %conv = tail call fp128 @llvm.experimental.constrained.sitofp.f128.i32(i32 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret fp128 %conv +} + +define fp128 @i64_to_q(i64 %m) #0 { +; P8-LABEL: i64_to_q: +; P8: # %bb.0: # %entry +; P8-NEXT: mflr r0 +; P8-NEXT: std r0, 16(r1) +; P8-NEXT: stdu r1, -112(r1) +; P8-NEXT: .cfi_def_cfa_offset 112 +; P8-NEXT: .cfi_offset lr, 16 +; P8-NEXT: bl __floatdikf +; P8-NEXT: nop +; P8-NEXT: addi r1, r1, 112 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: i64_to_q: +; P9: # %bb.0: # %entry +; P9-NEXT: mtvsrd v2, r3 +; P9-NEXT: xscvsdqp v2, v2 +; P9-NEXT: blr +; +; NOVSX-LABEL: i64_to_q: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: mflr r0 +; NOVSX-NEXT: std r0, 16(r1) +; NOVSX-NEXT: stdu r1, -32(r1) +; NOVSX-NEXT: .cfi_def_cfa_offset 32 +; NOVSX-NEXT: .cfi_offset lr, 16 +; NOVSX-NEXT: bl __floatdikf +; NOVSX-NEXT: nop +; NOVSX-NEXT: addi r1, r1, 32 +; NOVSX-NEXT: ld r0, 16(r1) +; NOVSX-NEXT: mtlr r0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: i64_to_q: +; SPE: # %bb.0: # %entry +; SPE-NEXT: mflr r0 +; SPE-NEXT: stw r0, 4(r1) +; SPE-NEXT: stwu r1, -16(r1) +; SPE-NEXT: .cfi_def_cfa_offset 16 +; SPE-NEXT: .cfi_offset lr, 4 +; SPE-NEXT: bl __floatdikf +; SPE-NEXT: lwz r0, 20(r1) +; SPE-NEXT: addi r1, r1, 16 +; SPE-NEXT: mtlr r0 +; SPE-NEXT: blr +entry: + %conv = tail call fp128 @llvm.experimental.constrained.sitofp.f128.i64(i64 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret fp128 %conv +} + +define fp128 @u32_to_q(i32 zeroext %m) #0 { +; P8-LABEL: u32_to_q: +; P8: # %bb.0: # %entry +; P8-NEXT: mflr r0 +; P8-NEXT: std r0, 16(r1) +; P8-NEXT: stdu r1, -112(r1) +; P8-NEXT: .cfi_def_cfa_offset 112 +; P8-NEXT: .cfi_offset lr, 16 +; P8-NEXT: bl __floatunsikf +; P8-NEXT: nop +; P8-NEXT: addi r1, r1, 112 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: u32_to_q: +; P9: # %bb.0: # %entry +; P9-NEXT: mtvsrwz v2, r3 +; P9-NEXT: xscvudqp v2, v2 +; P9-NEXT: blr +; +; NOVSX-LABEL: u32_to_q: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: mflr r0 +; NOVSX-NEXT: std r0, 16(r1) +; NOVSX-NEXT: stdu r1, -32(r1) +; NOVSX-NEXT: .cfi_def_cfa_offset 32 +; NOVSX-NEXT: .cfi_offset lr, 16 +; NOVSX-NEXT: bl __floatunsikf +; NOVSX-NEXT: nop +; NOVSX-NEXT: addi r1, r1, 32 +; NOVSX-NEXT: ld r0, 16(r1) +; NOVSX-NEXT: mtlr r0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: u32_to_q: +; SPE: # %bb.0: # %entry +; SPE-NEXT: mflr r0 +; SPE-NEXT: stw r0, 4(r1) +; SPE-NEXT: stwu r1, -16(r1) +; SPE-NEXT: .cfi_def_cfa_offset 16 +; SPE-NEXT: .cfi_offset lr, 4 +; SPE-NEXT: bl __floatunsikf +; SPE-NEXT: lwz r0, 20(r1) +; SPE-NEXT: addi r1, r1, 16 +; SPE-NEXT: mtlr r0 +; SPE-NEXT: blr +entry: + %conv = tail call fp128 @llvm.experimental.constrained.uitofp.f128.i32(i32 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret fp128 %conv +} + +define fp128 @u64_to_q(i64 %m) #0 { +; P8-LABEL: u64_to_q: +; P8: # %bb.0: # %entry +; P8-NEXT: mflr r0 +; P8-NEXT: std r0, 16(r1) +; P8-NEXT: stdu r1, -112(r1) +; P8-NEXT: .cfi_def_cfa_offset 112 +; P8-NEXT: .cfi_offset lr, 16 +; P8-NEXT: bl __floatundikf +; P8-NEXT: nop +; P8-NEXT: addi r1, r1, 112 +; P8-NEXT: ld r0, 16(r1) +; P8-NEXT: mtlr r0 +; P8-NEXT: blr +; +; P9-LABEL: u64_to_q: +; P9: # %bb.0: # %entry +; P9-NEXT: mtvsrd v2, r3 +; P9-NEXT: xscvudqp v2, v2 +; P9-NEXT: blr +; +; NOVSX-LABEL: u64_to_q: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: mflr r0 +; NOVSX-NEXT: std r0, 16(r1) +; NOVSX-NEXT: stdu r1, -32(r1) +; NOVSX-NEXT: .cfi_def_cfa_offset 32 +; NOVSX-NEXT: .cfi_offset lr, 16 +; NOVSX-NEXT: bl __floatundikf +; NOVSX-NEXT: nop +; NOVSX-NEXT: addi r1, r1, 32 +; NOVSX-NEXT: ld r0, 16(r1) +; NOVSX-NEXT: mtlr r0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: u64_to_q: +; SPE: # %bb.0: # %entry +; SPE-NEXT: mflr r0 +; SPE-NEXT: stw r0, 4(r1) +; SPE-NEXT: stwu r1, -16(r1) +; SPE-NEXT: .cfi_def_cfa_offset 16 +; SPE-NEXT: .cfi_offset lr, 4 +; SPE-NEXT: bl __floatundikf +; SPE-NEXT: lwz r0, 20(r1) +; SPE-NEXT: addi r1, r1, 16 +; SPE-NEXT: mtlr r0 +; SPE-NEXT: blr +entry: + %conv = tail call fp128 @llvm.experimental.constrained.uitofp.f128.i64(i64 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret fp128 %conv +} + attributes #0 = { strictfp } diff --git a/llvm/test/CodeGen/PowerPC/fp-strict-conv.ll b/llvm/test/CodeGen/PowerPC/fp-strict-conv.ll --- a/llvm/test/CodeGen/PowerPC/fp-strict-conv.ll +++ b/llvm/test/CodeGen/PowerPC/fp-strict-conv.ll @@ -20,6 +20,16 @@ declare i64 @llvm.experimental.constrained.fptoui.i64.f32(float, metadata) declare i32 @llvm.experimental.constrained.fptoui.i32.f32(float, metadata) +declare double @llvm.experimental.constrained.sitofp.f64.i32(i32, metadata, metadata) +declare double @llvm.experimental.constrained.sitofp.f64.i64(i64, metadata, metadata) +declare double @llvm.experimental.constrained.uitofp.f64.i32(i32, metadata, metadata) +declare double @llvm.experimental.constrained.uitofp.f64.i64(i64, metadata, metadata) + +declare float @llvm.experimental.constrained.sitofp.f32.i64(i64, metadata, metadata) +declare float @llvm.experimental.constrained.sitofp.f32.i32(i32, metadata, metadata) +declare float @llvm.experimental.constrained.uitofp.f32.i32(i32, metadata, metadata) +declare float @llvm.experimental.constrained.uitofp.f32.i64(i64, metadata, metadata) + define i32 @d_to_i32(double %m) #0 { ; CHECK-LABEL: d_to_i32: ; CHECK: # %bb.0: # %entry @@ -253,4 +263,238 @@ ret i32 %conv } +define double @i32_to_d(i32 signext %m) #0 { +; CHECK-LABEL: i32_to_d: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprwz f0, r3 +; CHECK-NEXT: xscvsxddp f1, f0 +; CHECK-NEXT: blr +; +; NOVSX-LABEL: i32_to_d: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: addi r4, r1, -4 +; NOVSX-NEXT: stw r3, -4(r1) +; NOVSX-NEXT: lfiwax f0, 0, r4 +; NOVSX-NEXT: fcfid f1, f0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: i32_to_d: +; SPE: # %bb.0: # %entry +; SPE-NEXT: efdcfsi r4, r3 +; SPE-NEXT: evmergehi r3, r4, r4 +; SPE-NEXT: # kill: def $r4 killed $r4 killed $s4 +; SPE-NEXT: # kill: def $r3 killed $r3 killed $s3 +; SPE-NEXT: blr +entry: + %conv = tail call double @llvm.experimental.constrained.sitofp.f64.i32(i32 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret double %conv +} + +define double @i64_to_d(i64 %m) #0 { +; CHECK-LABEL: i64_to_d: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprd f0, r3 +; CHECK-NEXT: xscvsxddp f1, f0 +; CHECK-NEXT: blr +; +; NOVSX-LABEL: i64_to_d: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: std r3, -8(r1) +; NOVSX-NEXT: lfd f0, -8(r1) +; NOVSX-NEXT: fcfid f1, f0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: i64_to_d: +; SPE: # %bb.0: # %entry +; SPE-NEXT: mflr r0 +; SPE-NEXT: stw r0, 4(r1) +; SPE-NEXT: stwu r1, -16(r1) +; SPE-NEXT: .cfi_def_cfa_offset 16 +; SPE-NEXT: .cfi_offset lr, 4 +; SPE-NEXT: bl __floatdidf +; SPE-NEXT: evmergelo r4, r3, r4 +; SPE-NEXT: evmergehi r3, r4, r4 +; SPE-NEXT: lwz r0, 20(r1) +; SPE-NEXT: # kill: def $r3 killed $r3 killed $s3 +; SPE-NEXT: # kill: def $r4 killed $r4 killed $s4 +; SPE-NEXT: addi r1, r1, 16 +; SPE-NEXT: mtlr r0 +; SPE-NEXT: blr +entry: + %conv = tail call double @llvm.experimental.constrained.sitofp.f64.i64(i64 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret double %conv +} + +define double @u32_to_d(i32 zeroext %m) #0 { +; CHECK-LABEL: u32_to_d: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprwz f0, r3 +; CHECK-NEXT: xscvuxddp f1, f0 +; CHECK-NEXT: blr +; +; NOVSX-LABEL: u32_to_d: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: addi r4, r1, -4 +; NOVSX-NEXT: stw r3, -4(r1) +; NOVSX-NEXT: lfiwzx f0, 0, r4 +; NOVSX-NEXT: fcfidu f1, f0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: u32_to_d: +; SPE: # %bb.0: # %entry +; SPE-NEXT: efdcfui r4, r3 +; SPE-NEXT: evmergehi r3, r4, r4 +; SPE-NEXT: # kill: def $r4 killed $r4 killed $s4 +; SPE-NEXT: # kill: def $r3 killed $r3 killed $s3 +; SPE-NEXT: blr +entry: + %conv = tail call double @llvm.experimental.constrained.uitofp.f64.i32(i32 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret double %conv +} + +define double @u64_to_d(i64 %m) #0 { +; CHECK-LABEL: u64_to_d: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprd f0, r3 +; CHECK-NEXT: xscvuxddp f1, f0 +; CHECK-NEXT: blr +; +; NOVSX-LABEL: u64_to_d: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: std r3, -8(r1) +; NOVSX-NEXT: lfd f0, -8(r1) +; NOVSX-NEXT: fcfidu f1, f0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: u64_to_d: +; SPE: # %bb.0: # %entry +; SPE-NEXT: mflr r0 +; SPE-NEXT: stw r0, 4(r1) +; SPE-NEXT: stwu r1, -16(r1) +; SPE-NEXT: .cfi_def_cfa_offset 16 +; SPE-NEXT: .cfi_offset lr, 4 +; SPE-NEXT: bl __floatundidf +; SPE-NEXT: evmergelo r4, r3, r4 +; SPE-NEXT: evmergehi r3, r4, r4 +; SPE-NEXT: lwz r0, 20(r1) +; SPE-NEXT: # kill: def $r3 killed $r3 killed $s3 +; SPE-NEXT: # kill: def $r4 killed $r4 killed $s4 +; SPE-NEXT: addi r1, r1, 16 +; SPE-NEXT: mtlr r0 +; SPE-NEXT: blr +entry: + %conv = tail call double @llvm.experimental.constrained.uitofp.f64.i64(i64 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret double %conv +} + +define float @i32_to_f(i32 signext %m) #0 { +; CHECK-LABEL: i32_to_f: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprwz f0, r3 +; CHECK-NEXT: xscvsxdsp f1, f0 +; CHECK-NEXT: blr +; +; NOVSX-LABEL: i32_to_f: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: addi r4, r1, -4 +; NOVSX-NEXT: stw r3, -4(r1) +; NOVSX-NEXT: lfiwax f0, 0, r4 +; NOVSX-NEXT: fcfids f1, f0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: i32_to_f: +; SPE: # %bb.0: # %entry +; SPE-NEXT: efscfsi r3, r3 +; SPE-NEXT: blr +entry: + %conv = tail call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %conv +} + +define float @i64_to_f(i64 %m) #0 { +; CHECK-LABEL: i64_to_f: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprd f0, r3 +; CHECK-NEXT: xscvsxdsp f1, f0 +; CHECK-NEXT: blr +; +; NOVSX-LABEL: i64_to_f: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: std r3, -8(r1) +; NOVSX-NEXT: lfd f0, -8(r1) +; NOVSX-NEXT: fcfids f1, f0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: i64_to_f: +; SPE: # %bb.0: # %entry +; SPE-NEXT: mflr r0 +; SPE-NEXT: stw r0, 4(r1) +; SPE-NEXT: stwu r1, -16(r1) +; SPE-NEXT: .cfi_def_cfa_offset 16 +; SPE-NEXT: .cfi_offset lr, 4 +; SPE-NEXT: bl __floatdisf +; SPE-NEXT: lwz r0, 20(r1) +; SPE-NEXT: addi r1, r1, 16 +; SPE-NEXT: mtlr r0 +; SPE-NEXT: blr +entry: + %conv = tail call float @llvm.experimental.constrained.sitofp.f32.i64(i64 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %conv +} + +define float @u32_to_f(i32 zeroext %m) #0 { +; CHECK-LABEL: u32_to_f: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprwz f0, r3 +; CHECK-NEXT: xscvuxdsp f1, f0 +; CHECK-NEXT: blr +; +; NOVSX-LABEL: u32_to_f: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: addi r4, r1, -4 +; NOVSX-NEXT: stw r3, -4(r1) +; NOVSX-NEXT: lfiwzx f0, 0, r4 +; NOVSX-NEXT: fcfidus f1, f0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: u32_to_f: +; SPE: # %bb.0: # %entry +; SPE-NEXT: efscfui r3, r3 +; SPE-NEXT: blr +entry: + %conv = tail call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %conv +} + +define float @u64_to_f(i64 %m) #0 { +; CHECK-LABEL: u64_to_f: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mtfprd f0, r3 +; CHECK-NEXT: xscvuxdsp f1, f0 +; CHECK-NEXT: blr +; +; NOVSX-LABEL: u64_to_f: +; NOVSX: # %bb.0: # %entry +; NOVSX-NEXT: std r3, -8(r1) +; NOVSX-NEXT: lfd f0, -8(r1) +; NOVSX-NEXT: fcfidus f1, f0 +; NOVSX-NEXT: blr +; +; SPE-LABEL: u64_to_f: +; SPE: # %bb.0: # %entry +; SPE-NEXT: mflr r0 +; SPE-NEXT: stw r0, 4(r1) +; SPE-NEXT: stwu r1, -16(r1) +; SPE-NEXT: .cfi_def_cfa_offset 16 +; SPE-NEXT: .cfi_offset lr, 4 +; SPE-NEXT: bl __floatundisf +; SPE-NEXT: lwz r0, 20(r1) +; SPE-NEXT: addi r1, r1, 16 +; SPE-NEXT: mtlr r0 +; SPE-NEXT: blr +entry: + %conv = tail call float @llvm.experimental.constrained.uitofp.f32.i64(i64 %m, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %conv +} + attributes #0 = { strictfp }