diff options
Diffstat (limited to 'llvm/lib/Target/Mips/MipsISelLowering.cpp')
-rw-r--r-- | llvm/lib/Target/Mips/MipsISelLowering.cpp | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp index f4effae6d37..786add66d0c 100644 --- a/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -46,6 +46,10 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { case MipsISD::FPBrcond : return "MipsISD::FPBrcond"; case MipsISD::FPCmp : return "MipsISD::FPCmp"; case MipsISD::FPRound : return "MipsISD::FPRound"; + case MipsISD::MAdd : return "MipsISD::MAdd"; + case MipsISD::MAddu : return "MipsISD::MAddu"; + case MipsISD::MSub : return "MipsISD::MSub"; + case MipsISD::MSubu : return "MipsISD::MSubu"; default : return NULL; } } @@ -154,6 +158,9 @@ MipsTargetLowering(MipsTargetMachine &TM) if (!Subtarget->hasSwap()) setOperationAction(ISD::BSWAP, MVT::i32, Expand); + setTargetDAGCombine(ISD::ADDE); + setTargetDAGCombine(ISD::SUBE); + setStackPointerRegisterToSaveRestore(Mips::SP); computeRegisterProperties(); } @@ -167,6 +174,194 @@ unsigned MipsTargetLowering::getFunctionAlignment(const Function *) const { return 2; } +// SelectMadd - +// Transforms a subgraph in CurDAG if the following pattern is found: +// (addc multLo, Lo0), (adde multHi, Hi0), +// where, +// multHi/Lo: product of multiplication +// Lo0: initial value of Lo register +// Hi0: initial value of Hi register +// Return true if mattern matching was successful. +static bool SelectMadd(SDNode* ADDENode, SelectionDAG* CurDAG) { + // ADDENode's second operand must be a flag output of an ADDC node in order + // for the matching to be successful. + SDNode* ADDCNode = ADDENode->getOperand(2).getNode(); + + if (ADDCNode->getOpcode() != ISD::ADDC) + return false; + + SDValue MultHi = ADDENode->getOperand(0); + SDValue MultLo = ADDCNode->getOperand(0); + SDNode* MultNode = MultHi.getNode(); + unsigned MultOpc = MultHi.getOpcode(); + + // MultHi and MultLo must be generated by the same node, + if (MultLo.getNode() != MultNode) + return false; + + // and it must be a multiplication. + if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI) + return false; + + // MultLo amd MultHi must be the first and second output of MultNode + // respectively. + if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0) + return false; + + // Transform this to a MADD only if ADDENode and ADDCNode are the only users + // of the values of MultNode, in which case MultNode will be removed in later + // phases. + // If there exist users other than ADDENode or ADDCNode, this function returns + // here, which will result in MultNode being mapped to a single MULT + // instruction node rather than a pair of MULT and MADD instructions being + // produced. + if (!MultHi.hasOneUse() || !MultLo.hasOneUse()) + return false; + + SDValue Chain = CurDAG->getEntryNode(); + DebugLoc dl = ADDENode->getDebugLoc(); + + // create MipsMAdd(u) node + MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MAddu : MipsISD::MAdd; + + SDValue MAdd = CurDAG->getNode(MultOpc, dl, + MVT::Glue, + MultNode->getOperand(0),// Factor 0 + MultNode->getOperand(1),// Factor 1 + ADDCNode->getOperand(1),// Lo0 + ADDENode->getOperand(1));// Hi0 + + // create CopyFromReg nodes + SDValue CopyFromLo = CurDAG->getCopyFromReg(Chain, dl, Mips::LO, MVT::i32, + MAdd); + SDValue CopyFromHi = CurDAG->getCopyFromReg(CopyFromLo.getValue(1), dl, + Mips::HI, MVT::i32, + CopyFromLo.getValue(2)); + + // replace uses of adde and addc here + if (!SDValue(ADDCNode, 0).use_empty()) + CurDAG->ReplaceAllUsesOfValueWith(SDValue(ADDCNode, 0), CopyFromLo); + + if (!SDValue(ADDENode, 0).use_empty()) + CurDAG->ReplaceAllUsesOfValueWith(SDValue(ADDENode, 0), CopyFromHi); + + return true; +} + +// SelectMsub - +// Transforms a subgraph in CurDAG if the following pattern is found: +// (addc Lo0, multLo), (sube Hi0, multHi), +// where, +// multHi/Lo: product of multiplication +// Lo0: initial value of Lo register +// Hi0: initial value of Hi register +// Return true if mattern matching was successful. +static bool SelectMsub(SDNode* SUBENode, SelectionDAG* CurDAG) { + // SUBENode's second operand must be a flag output of an SUBC node in order + // for the matching to be successful. + SDNode* SUBCNode = SUBENode->getOperand(2).getNode(); + + if (SUBCNode->getOpcode() != ISD::SUBC) + return false; + + SDValue MultHi = SUBENode->getOperand(1); + SDValue MultLo = SUBCNode->getOperand(1); + SDNode* MultNode = MultHi.getNode(); + unsigned MultOpc = MultHi.getOpcode(); + + // MultHi and MultLo must be generated by the same node, + if (MultLo.getNode() != MultNode) + return false; + + // and it must be a multiplication. + if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI) + return false; + + // MultLo amd MultHi must be the first and second output of MultNode + // respectively. + if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0) + return false; + + // Transform this to a MSUB only if SUBENode and SUBCNode are the only users + // of the values of MultNode, in which case MultNode will be removed in later + // phases. + // If there exist users other than SUBENode or SUBCNode, this function returns + // here, which will result in MultNode being mapped to a single MULT + // instruction node rather than a pair of MULT and MSUB instructions being + // produced. + if (!MultHi.hasOneUse() || !MultLo.hasOneUse()) + return false; + + SDValue Chain = CurDAG->getEntryNode(); + DebugLoc dl = SUBENode->getDebugLoc(); + + // create MipsSub(u) node + MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MSubu : MipsISD::MSub; + + SDValue MSub = CurDAG->getNode(MultOpc, dl, + MVT::Glue, + MultNode->getOperand(0),// Factor 0 + MultNode->getOperand(1),// Factor 1 + SUBCNode->getOperand(0),// Lo0 + SUBENode->getOperand(0));// Hi0 + + // create CopyFromReg nodes + SDValue CopyFromLo = CurDAG->getCopyFromReg(Chain, dl, Mips::LO, MVT::i32, + MSub); + SDValue CopyFromHi = CurDAG->getCopyFromReg(CopyFromLo.getValue(1), dl, + Mips::HI, MVT::i32, + CopyFromLo.getValue(2)); + + // replace uses of sube and subc here + if (!SDValue(SUBCNode, 0).use_empty()) + CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBCNode, 0), CopyFromLo); + + if (!SDValue(SUBENode, 0).use_empty()) + CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBENode, 0), CopyFromHi); + + return true; +} + +static SDValue PerformADDECombine(SDNode *N, SelectionDAG& DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget* Subtarget) { + if (DCI.isBeforeLegalize()) + return SDValue(); + + if (Subtarget->isMips32() && SelectMadd(N, &DAG)) + return SDValue(N, 0); + + return SDValue(); +} + +static SDValue PerformSUBECombine(SDNode *N, SelectionDAG& DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget* Subtarget) { + if (DCI.isBeforeLegalize()) + return SDValue(); + + if (Subtarget->isMips32() && SelectMsub(N, &DAG)) + return SDValue(N, 0); + + return SDValue(); +} + +SDValue MipsTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) + const { + SelectionDAG &DAG = DCI.DAG; + unsigned opc = N->getOpcode(); + + switch (opc) { + default: break; + case ISD::ADDE: + return PerformADDECombine(N, DAG, DCI, Subtarget); + case ISD::SUBE: + return PerformSUBECombine(N, DAG, DCI, Subtarget); + } + + return SDValue(); +} + SDValue MipsTargetLowering:: LowerOperation(SDValue Op, SelectionDAG &DAG) const { |