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 @@ -63,9 +63,14 @@ /// unsigned integers and single-precision outputs. FCFIDU, FCFIDS, FCFIDUS, + /// FCTI[DW] - The FCTID and FCTIW instructions, taking an f32 or f64 + /// operand, producing an f64 value containing the integer representation + /// of that FP value, rounded using the current rounding mode. + FCTID, FCTIW, + /// FCTI[D,W]Z - The FCTIDZ and FCTIWZ instructions, taking an f32 or f64 /// operand, producing an f64 value containing the integer representation - /// of that FP value. + /// of that FP value, rounding it toward zero. FCTIDZ, FCTIWZ, /// Newer FCTI[D,W]UZ floating-point-to-integer conversion instructions for @@ -993,6 +998,8 @@ void spliceIntoChain(SDValue ResChain, SDValue NewResChain, SelectionDAG &DAG) const; + SDValue getPPCISDNodeForFP_TO_INT(SDValue Op, SelectionDAG &DAG, + const SDLoc &dl) const; void LowerFP_TO_INTForReuse(SDValue Op, ReuseLoadInfo &RLI, SelectionDAG &DAG, const SDLoc &dl) const; SDValue LowerFP_TO_INTDirectMove(SDValue Op, SelectionDAG &DAG, 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 @@ -405,6 +405,16 @@ setOperationAction(ISD::BITCAST, MVT::i32, Expand); setOperationAction(ISD::BITCAST, MVT::i64, Expand); setOperationAction(ISD::BITCAST, MVT::f64, Expand); + + if (Subtarget.hasFPCVT() && TM.Options.UnsafeFPMath) { + if (isPPC64) { + setOperationAction(ISD::LLRINT, MVT::f32, Custom); + setOperationAction(ISD::LLRINT, MVT::f64, Custom); + } + + setOperationAction(ISD::LRINT, MVT::f32, Custom); + setOperationAction(ISD::LRINT, MVT::f64, Custom); + } } // We cannot sextinreg(i1). Expand to shifts. @@ -1343,6 +1353,8 @@ case PPCISD::FCFIDU: return "PPCISD::FCFIDU"; case PPCISD::FCFIDS: return "PPCISD::FCFIDS"; case PPCISD::FCFIDUS: return "PPCISD::FCFIDUS"; + case PPCISD::FCTID: return "PPCISD::FCTID"; + case PPCISD::FCTIW: return "PPCISD::FCTIW"; case PPCISD::FCTIDZ: return "PPCISD::FCTIDZ"; case PPCISD::FCTIWZ: return "PPCISD::FCTIWZ"; case PPCISD::FCTIDUZ: return "PPCISD::FCTIDUZ"; @@ -7577,32 +7589,55 @@ return Op; } +SDValue PPCTargetLowering::getPPCISDNodeForFP_TO_INT(SDValue Op, + SelectionDAG &DAG, + const SDLoc &dl) const { + assert(Op.getOperand(0).getValueType().isFloatingPoint()); + SDValue Src = Op.getOperand(0); + + if (Src.getValueType() == MVT::f32) + Src = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f64, Src); + + MVT::SimpleValueType Ty = Op.getSimpleValueType().SimpleTy; + assert((Ty == MVT::i32 || Ty == MVT::i64) && + "SimpleValueType for operand must be 32- or 64-bit integer."); + + unsigned Opc = Op.getOpcode(); + unsigned PPCOpc; + + switch (Opc) { + default: + llvm_unreachable("Got invalid ISD node in FP_TO_INT custom expander!"); + case ISD::FP_TO_SINT: + PPCOpc = Ty == MVT::i32 ? PPCISD::FCTIWZ : PPCISD::FCTIDZ; + break; + case ISD::FP_TO_UINT: + if (Subtarget.hasFPCVT()) + PPCOpc = Ty == MVT::i32 ? PPCISD::FCTIWUZ : PPCISD::FCTIDUZ; + else if (Ty == MVT::i32) + PPCOpc = PPCISD::FCTIDZ; + else + llvm_unreachable("i64 FP_TO_UINT is supported only with FPCVT"); + break; + case ISD::LRINT: + assert(Subtarget.hasFPCVT() && + "Custom expander for LRINT only supported with FPCVT"); + PPCOpc = Ty == MVT::i32 ? PPCISD::FCTIW : PPCISD::FCTID; + break; + case ISD::LLRINT: + assert(Subtarget.hasFPCVT() && Subtarget.has64BitSupport() && + "Custom expander for LLRINT only supported on 64-bit with FPCVT"); + PPCOpc = PPCISD::FCTID; + break; + } + + return DAG.getNode(PPCOpc, dl, MVT::f64, Src); +} + void PPCTargetLowering::LowerFP_TO_INTForReuse(SDValue Op, ReuseLoadInfo &RLI, SelectionDAG &DAG, const SDLoc &dl) const { - assert(Op.getOperand(0).getValueType().isFloatingPoint()); - SDValue Src = Op.getOperand(0); - if (Src.getValueType() == MVT::f32) - Src = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f64, Src); - - SDValue Tmp; - switch (Op.getSimpleValueType().SimpleTy) { - default: llvm_unreachable("Unhandled FP_TO_INT type in custom expander!"); - case MVT::i32: - Tmp = DAG.getNode( - Op.getOpcode() == ISD::FP_TO_SINT - ? PPCISD::FCTIWZ - : (Subtarget.hasFPCVT() ? PPCISD::FCTIWUZ : PPCISD::FCTIDZ), - dl, MVT::f64, Src); - break; - case MVT::i64: - assert((Op.getOpcode() == ISD::FP_TO_SINT || Subtarget.hasFPCVT()) && - "i64 FP_TO_UINT is supported only with FPCVT"); - Tmp = DAG.getNode(Op.getOpcode()==ISD::FP_TO_SINT ? PPCISD::FCTIDZ : - PPCISD::FCTIDUZ, - dl, MVT::f64, Src); - break; - } + SDValue Tmp = getPPCISDNodeForFP_TO_INT(Op, DAG, dl); // Convert the FP value to an int value through memory. bool i32Stack = Op.getValueType() == MVT::i32 && Subtarget.hasSTFIWX() && @@ -7643,33 +7678,8 @@ SDValue PPCTargetLowering::LowerFP_TO_INTDirectMove(SDValue Op, SelectionDAG &DAG, const SDLoc &dl) const { - assert(Op.getOperand(0).getValueType().isFloatingPoint()); - SDValue Src = Op.getOperand(0); - - if (Src.getValueType() == MVT::f32) - Src = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f64, Src); - - SDValue Tmp; - switch (Op.getSimpleValueType().SimpleTy) { - default: llvm_unreachable("Unhandled FP_TO_INT type in custom expander!"); - case MVT::i32: - Tmp = DAG.getNode( - Op.getOpcode() == ISD::FP_TO_SINT - ? PPCISD::FCTIWZ - : (Subtarget.hasFPCVT() ? PPCISD::FCTIWUZ : PPCISD::FCTIDZ), - dl, MVT::f64, Src); - Tmp = DAG.getNode(PPCISD::MFVSR, dl, MVT::i32, Tmp); - break; - case MVT::i64: - assert((Op.getOpcode() == ISD::FP_TO_SINT || Subtarget.hasFPCVT()) && - "i64 FP_TO_UINT is supported only with FPCVT"); - Tmp = DAG.getNode(Op.getOpcode()==ISD::FP_TO_SINT ? PPCISD::FCTIDZ : - PPCISD::FCTIDUZ, - dl, MVT::f64, Src); - Tmp = DAG.getNode(PPCISD::MFVSR, dl, MVT::i64, Tmp); - break; - } - return Tmp; + SDValue Tmp = getPPCISDNodeForFP_TO_INT(Op, DAG, dl); + return DAG.getNode(PPCISD::MFVSR, dl, Op.getSimpleValueType().SimpleTy, Tmp); } SDValue PPCTargetLowering::LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG, @@ -10354,6 +10364,8 @@ case ISD::STORE: return LowerSTORE(Op, DAG); case ISD::TRUNCATE: return LowerTRUNCATE(Op, DAG); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); + case ISD::LRINT: + case ISD::LLRINT: case ISD::FP_TO_UINT: case ISD::FP_TO_SINT: return LowerFP_TO_INT(Op, DAG, SDLoc(Op)); case ISD::UINT_TO_FP: 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 @@ -1318,7 +1318,7 @@ [(set f64:$frD, (PPCfcfid f64:$frB))]>, isPPC64; defm FCTID : XForm_26r<63, 814, (outs f8rc:$frD), (ins f8rc:$frB), "fctid", "$frD, $frB", IIC_FPGeneral, - []>, isPPC64; + [(set f64:$frD, (PPCfctid f64:$frB))]>, isPPC64; defm FCTIDU : XForm_26r<63, 942, (outs f8rc:$frD), (ins f8rc:$frB), "fctidu", "$frD, $frB", IIC_FPGeneral, []>, isPPC64; 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 @@ -128,6 +128,8 @@ def PPCfcfidu : SDNode<"PPCISD::FCFIDU", SDTFPUnaryOp, []>; def PPCfcfids : SDNode<"PPCISD::FCFIDS", SDTFPRoundOp, []>; def PPCfcfidus: SDNode<"PPCISD::FCFIDUS", SDTFPRoundOp, []>; +def PPCfctid : SDNode<"PPCISD::FCTID", SDTFPUnaryOp, []>; +def PPCfctiw : SDNode<"PPCISD::FCTIW", SDTFPUnaryOp, []>; def PPCfctidz : SDNode<"PPCISD::FCTIDZ", SDTFPUnaryOp, []>; def PPCfctiwz : SDNode<"PPCISD::FCTIWZ", SDTFPUnaryOp, []>; def PPCfctiduz: SDNode<"PPCISD::FCTIDUZ",SDTFPUnaryOp, []>; @@ -2466,7 +2468,7 @@ let hasSideEffects = 0 in { defm FCTIW : XForm_26r<63, 14, (outs f8rc:$frD), (ins f8rc:$frB), "fctiw", "$frD, $frB", IIC_FPGeneral, - []>; + [(set f64:$frD, (PPCfctiw f64:$frB))]>; defm FCTIWU : XForm_26r<63, 142, (outs f8rc:$frD), (ins f8rc:$frB), "fctiwu", "$frD, $frB", IIC_FPGeneral, []>; diff --git a/llvm/test/CodeGen/PowerPC/llrint-conv.ll b/llvm/test/CodeGen/PowerPC/llrint-conv.ll --- a/llvm/test/CodeGen/PowerPC/llrint-conv.ll +++ b/llvm/test/CodeGen/PowerPC/llrint-conv.ll @@ -1,7 +1,17 @@ -; RUN: llc < %s -mtriple=powerpc64le | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le \ +; RUN: --enable-unsafe-fp-math < %s | FileCheck --check-prefix=CHECK-FAST %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64 --enable-unsafe-fp-math \ +; RUN: -mcpu=pwr7 < %s | FileCheck --check-prefix=CHECK-FAST-PWR7 %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64 --enable-unsafe-fp-math \ +; RUN: -mattr=-fpcvt,-direct-move < %s \ +; RUN: | FileCheck --check-prefix=CHECK-FAST-NOFPCVT %s ; CHECK-LABEL: testmsws: ; CHECK: bl llrintf +; CHECK-FAST: fctid 0, 1 +; CHECK-FAST-PWR7: fctid 0, 1 +; CHECK-FAST-NOFPCVT: bl llrintf define signext i32 @testmsws(float %x) { entry: %0 = tail call i64 @llvm.llrint.f32(float %x) @@ -11,6 +21,9 @@ ; CHECK-LABEL: testmsxs: ; CHECK: bl llrintf +; CHECK-FAST: fctid 0, 1 +; CHECK-FAST-PWR7: fctid 0, 1 +; CHECK-FAST-NOFPCVT: bl llrintf define i64 @testmsxs(float %x) { entry: %0 = tail call i64 @llvm.llrint.f32(float %x) @@ -19,6 +32,9 @@ ; CHECK-LABEL: testmswd: ; CHECK: bl llrint +; CHECK-FAST: fctid 0, 1 +; CHECK-FAST-PWR7: fctid 0, 1 +; CHECK-FAST-NOFPCVT: bl llrint define signext i32 @testmswd(double %x) { entry: %0 = tail call i64 @llvm.llrint.f64(double %x) @@ -28,6 +44,9 @@ ; CHECK-LABEL: testmsxd: ; CHECK: bl llrint +; CHECK-FAST: fctid 0, 1 +; CHECK-FAST-PWR7: fctid 0, 1 +; CHECK-FAST-NOFPCVT: bl llrint define i64 @testmsxd(double %x) { entry: %0 = tail call i64 @llvm.llrint.f64(double %x) @@ -36,6 +55,9 @@ ; CHECK-LABEL: testmswl: ; CHECK: bl llrintl +; CHECK-FAST: bl llrintl +; CHECK-FAST-PWR7: bl llrintl +; CHECK-FAST-NOFPCVT: bl llrintl define signext i32 @testmswl(ppc_fp128 %x) { entry: %0 = tail call i64 @llvm.llrint.ppcf128(ppc_fp128 %x) @@ -45,6 +67,9 @@ ; CHECK-LABEL: testmsll: ; CHECK: bl llrintl +; CHECK-FAST: bl llrintl +; CHECK-FAST-PWR7: bl llrintl +; CHECK-FAST-NOFPCVT: bl llrintl define i64 @testmsll(ppc_fp128 %x) { entry: %0 = tail call i64 @llvm.llrint.ppcf128(ppc_fp128 %x) diff --git a/llvm/test/CodeGen/PowerPC/lrint-conv.ll b/llvm/test/CodeGen/PowerPC/lrint-conv.ll --- a/llvm/test/CodeGen/PowerPC/lrint-conv.ll +++ b/llvm/test/CodeGen/PowerPC/lrint-conv.ll @@ -1,7 +1,17 @@ -; RUN: llc < %s -mtriple=powerpc64le | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le \ +; RUN: --enable-unsafe-fp-math < %s | FileCheck --check-prefix=CHECK-FAST %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64 --enable-unsafe-fp-math \ +; RUN: -mcpu=pwr7 < %s | FileCheck --check-prefix=CHECK-FAST-PWR7 %s +; RUN: llc -verify-machineinstrs -mtriple=powerpc64 --enable-unsafe-fp-math \ +; RUN: -mattr=-fpcvt,-direct-move < %s \ +; RUN: | FileCheck --check-prefix=CHECK-FAST-NOFPCVT %s ; CHECK-LABEL: testmsws: ; CHECK: bl lrintf +; CHECK-FAST: fctid 0, 1 +; CHECK-FAST-PWR7: fctid 0, 1 +; CHECK-FAST-NOFPCVT: bl lrintf define signext i32 @testmsws(float %x) { entry: %0 = tail call i64 @llvm.lrint.i64.f32(float %x) @@ -11,6 +21,9 @@ ; CHECK-LABEL: testmsxs: ; CHECK: bl lrintf +; CHECK-FAST: fctid 0, 1 +; CHECK-FAST-PWR7: fctid 0, 1 +; CHECK-FAST-NOFPCVT: bl lrintf define i64 @testmsxs(float %x) { entry: %0 = tail call i64 @llvm.lrint.i64.f32(float %x) @@ -19,6 +32,9 @@ ; CHECK-LABEL: testmswd: ; CHECK: bl lrint +; CHECK-FAST: fctid 0, 1 +; CHECK-FAST-PWR7: fctid 0, 1 +; CHECK-FAST-NOFPCVT: bl lrint define signext i32 @testmswd(double %x) { entry: %0 = tail call i64 @llvm.lrint.i64.f64(double %x) @@ -28,6 +44,9 @@ ; CHECK-LABEL: testmsxd: ; CHECK: bl lrint +; CHECK-FAST: fctid 0, 1 +; CHECK-FAST-PWR7: fctid 0, 1 +; CHECK-FAST-NOFPCVT: bl lrint define i64 @testmsxd(double %x) { entry: %0 = tail call i64 @llvm.lrint.i64.f64(double %x) @@ -36,6 +55,9 @@ ; CHECK-LABEL: testmswl: ; CHECK: bl lrintl +; CHECK-FAST: bl lrintl +; CHECK-FAST-PWR7: bl lrintl +; CHECK-FAST-NOFPCVT: bl lrintl define signext i32 @testmswl(ppc_fp128 %x) { entry: %0 = tail call i64 @llvm.lrint.i64.ppcf128(ppc_fp128 %x) @@ -45,6 +67,9 @@ ; CHECK-LABEL: testmsll: ; CHECK: bl lrintl +; CHECK-FAST: bl lrintl +; CHECK-FAST-PWR7: bl lrintl +; CHECK-FAST-NOFPCVT: bl lrintl define i64 @testmsll(ppc_fp128 %x) { entry: %0 = tail call i64 @llvm.lrint.i64.ppcf128(ppc_fp128 %x)