diff options
Diffstat (limited to 'llvm/lib/Target/Mips/MipsSEISelLowering.cpp')
-rw-r--r-- | llvm/lib/Target/Mips/MipsSEISelLowering.cpp | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp index 70ba985f3ef..a4fcffbf519 100644 --- a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp @@ -15,6 +15,7 @@ #include "MipsTargetMachine.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetInstrInfo.h" @@ -79,6 +80,9 @@ MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::MUL, MVT::i64, Custom); } + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom); + setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom); + setOperationAction(ISD::SDIVREM, MVT::i32, Custom); setOperationAction(ISD::UDIVREM, MVT::i32, Custom); setOperationAction(ISD::SDIVREM, MVT::i64, Custom); @@ -125,6 +129,8 @@ SDValue MipsSETargetLowering::LowerOperation(SDValue Op, case ISD::MUL: return lowerMulDiv(Op, MipsISD::Mult, true, false, DAG); case ISD::SDIVREM: return lowerMulDiv(Op, MipsISD::DivRem, true, true, DAG); case ISD::UDIVREM: return lowerMulDiv(Op, MipsISD::DivRemU, true, true, DAG); + case ISD::INTRINSIC_WO_CHAIN: return lowerINTRINSIC_WO_CHAIN(Op, DAG); + case ISD::INTRINSIC_W_CHAIN: return lowerINTRINSIC_W_CHAIN(Op, DAG); } return MipsTargetLowering::LowerOperation(Op, DAG); @@ -389,6 +395,171 @@ SDValue MipsSETargetLowering::lowerMulDiv(SDValue Op, unsigned NewOpc, return DAG.getMergeValues(Vals, 2, DL); } + +static SDValue initAccumulator(SDValue In, DebugLoc DL, SelectionDAG &DAG) { + SDValue InLo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, In, + DAG.getConstant(0, MVT::i32)); + SDValue InHi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, In, + DAG.getConstant(1, MVT::i32)); + return DAG.getNode(MipsISD::InsertLOHI, DL, MVT::Untyped, InLo, InHi); +} + +static SDValue extractLOHI(SDValue Op, DebugLoc DL, SelectionDAG &DAG) { + SDValue Lo = DAG.getNode(MipsISD::ExtractLOHI, DL, MVT::i32, Op, + DAG.getConstant(Mips::sub_lo, MVT::i32)); + SDValue Hi = DAG.getNode(MipsISD::ExtractLOHI, DL, MVT::i32, Op, + DAG.getConstant(Mips::sub_hi, MVT::i32)); + return DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Lo, Hi); +} + +// This function expands mips intrinsic nodes which have 64-bit input operands +// or output values. +// +// out64 = intrinsic-node in64 +// => +// lo = copy (extract-element (in64, 0)) +// hi = copy (extract-element (in64, 1)) +// mips-specific-node +// v0 = copy lo +// v1 = copy hi +// out64 = merge-values (v0, v1) +// +static SDValue lowerDSPIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) { + DebugLoc DL = Op.getDebugLoc(); + bool HasChainIn = Op->getOperand(0).getValueType() == MVT::Other; + SmallVector<SDValue, 3> Ops; + unsigned OpNo = 0; + + // See if Op has a chain input. + if (HasChainIn) + Ops.push_back(Op->getOperand(OpNo++)); + + // The next operand is the intrinsic opcode. + assert(Op->getOperand(OpNo).getOpcode() == ISD::TargetConstant); + + // See if the next operand has type i64. + SDValue Opnd = Op->getOperand(++OpNo), In64; + + if (Opnd.getValueType() == MVT::i64) + In64 = initAccumulator(Opnd, DL, DAG); + else + Ops.push_back(Opnd); + + // Push the remaining operands. + for (++OpNo ; OpNo < Op->getNumOperands(); ++OpNo) + Ops.push_back(Op->getOperand(OpNo)); + + // Add In64 to the end of the list. + if (In64.getNode()) + Ops.push_back(In64); + + // Scan output. + SmallVector<EVT, 2> ResTys; + + for (SDNode::value_iterator I = Op->value_begin(), E = Op->value_end(); + I != E; ++I) + ResTys.push_back((*I == MVT::i64) ? MVT::Untyped : *I); + + // Create node. + SDValue Val = DAG.getNode(Opc, DL, ResTys, &Ops[0], Ops.size()); + SDValue Out = (ResTys[0] == MVT::Untyped) ? extractLOHI(Val, DL, DAG) : Val; + + if (!HasChainIn) + return Out; + + assert(Val->getValueType(1) == MVT::Other); + SDValue Vals[] = { Out, SDValue(Val.getNode(), 1) }; + return DAG.getMergeValues(Vals, 2, DL); +} + +SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, + SelectionDAG &DAG) const { + switch (cast<ConstantSDNode>(Op->getOperand(0))->getZExtValue()) { + default: + return SDValue(); + case Intrinsic::mips_shilo: + return lowerDSPIntr(Op, DAG, MipsISD::SHILO); + case Intrinsic::mips_dpau_h_qbl: + return lowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBL); + case Intrinsic::mips_dpau_h_qbr: + return lowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBR); + case Intrinsic::mips_dpsu_h_qbl: + return lowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBL); + case Intrinsic::mips_dpsu_h_qbr: + return lowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBR); + case Intrinsic::mips_dpa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPA_W_PH); + case Intrinsic::mips_dps_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPS_W_PH); + case Intrinsic::mips_dpax_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAX_W_PH); + case Intrinsic::mips_dpsx_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSX_W_PH); + case Intrinsic::mips_mulsa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::MULSA_W_PH); + case Intrinsic::mips_mult: + return lowerDSPIntr(Op, DAG, MipsISD::Mult); + case Intrinsic::mips_multu: + return lowerDSPIntr(Op, DAG, MipsISD::Multu); + case Intrinsic::mips_madd: + return lowerDSPIntr(Op, DAG, MipsISD::MAdd); + case Intrinsic::mips_maddu: + return lowerDSPIntr(Op, DAG, MipsISD::MAddu); + case Intrinsic::mips_msub: + return lowerDSPIntr(Op, DAG, MipsISD::MSub); + case Intrinsic::mips_msubu: + return lowerDSPIntr(Op, DAG, MipsISD::MSubu); + } +} + +SDValue MipsSETargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, + SelectionDAG &DAG) const { + switch (cast<ConstantSDNode>(Op->getOperand(1))->getZExtValue()) { + default: + return SDValue(); + case Intrinsic::mips_extp: + return lowerDSPIntr(Op, DAG, MipsISD::EXTP); + case Intrinsic::mips_extpdp: + return lowerDSPIntr(Op, DAG, MipsISD::EXTPDP); + case Intrinsic::mips_extr_w: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_W); + case Intrinsic::mips_extr_r_w: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_R_W); + case Intrinsic::mips_extr_rs_w: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_RS_W); + case Intrinsic::mips_extr_s_h: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_S_H); + case Intrinsic::mips_mthlip: + return lowerDSPIntr(Op, DAG, MipsISD::MTHLIP); + case Intrinsic::mips_mulsaq_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::MULSAQ_S_W_PH); + case Intrinsic::mips_maq_s_w_phl: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHL); + case Intrinsic::mips_maq_s_w_phr: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHR); + case Intrinsic::mips_maq_sa_w_phl: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHL); + case Intrinsic::mips_maq_sa_w_phr: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHR); + case Intrinsic::mips_dpaq_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQ_S_W_PH); + case Intrinsic::mips_dpsq_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQ_S_W_PH); + case Intrinsic::mips_dpaq_sa_l_w: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQ_SA_L_W); + case Intrinsic::mips_dpsq_sa_l_w: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQ_SA_L_W); + case Intrinsic::mips_dpaqx_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQX_S_W_PH); + case Intrinsic::mips_dpaqx_sa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQX_SA_W_PH); + case Intrinsic::mips_dpsqx_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQX_S_W_PH); + case Intrinsic::mips_dpsqx_sa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQX_SA_W_PH); + } +} + MachineBasicBlock * MipsSETargetLowering:: emitBPOSGE32(MachineInstr *MI, MachineBasicBlock *BB) const{ // $bb: |