[llvm-commits] [llvm] r123760 - in /llvm/trunk: lib/Target/Mips/MipsISelLowering.cpp lib/Target/Mips/MipsISelLowering.h lib/Target/Mips/MipsInstrInfo.td test/CodeGen/Mips/madd-msub.ll
Bruno Cardoso Lopes
bruno.cardoso at gmail.com
Tue Jan 18 11:29:17 PST 2011
Author: bruno
Date: Tue Jan 18 13:29:17 2011
New Revision: 123760
URL: http://llvm.org/viewvc/llvm-project?rev=123760&view=rev
Log:
Add support for mips32 madd and msub instructions. Patch by Akira Hatanaka
Added:
llvm/trunk/test/CodeGen/Mips/madd-msub.ll
Modified:
llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp
llvm/trunk/lib/Target/Mips/MipsISelLowering.h
llvm/trunk/lib/Target/Mips/MipsInstrInfo.td
Modified: llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp?rev=123760&r1=123759&r2=123760&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp Tue Jan 18 13:29:17 2011
@@ -46,6 +46,10 @@
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 @@
if (!Subtarget->hasSwap())
setOperationAction(ISD::BSWAP, MVT::i32, Expand);
+ setTargetDAGCombine(ISD::ADDE);
+ setTargetDAGCombine(ISD::SUBE);
+
setStackPointerRegisterToSaveRestore(Mips::SP);
computeRegisterProperties();
}
@@ -167,6 +174,194 @@
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
{
Modified: llvm/trunk/lib/Target/Mips/MipsISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsISelLowering.h?rev=123760&r1=123759&r2=123760&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsISelLowering.h (original)
+++ llvm/trunk/lib/Target/Mips/MipsISelLowering.h Tue Jan 18 13:29:17 2011
@@ -56,7 +56,13 @@
FPRound,
// Return
- Ret
+ Ret,
+
+ // MAdd/Sub nodes
+ MAdd,
+ MAddu,
+ MSub,
+ MSubu
};
}
@@ -80,6 +86,8 @@
/// getFunctionAlignment - Return the Log2 alignment of this function.
virtual unsigned getFunctionAlignment(const Function *F) const;
+
+ virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const;
private:
// Subtarget Info
const MipsSubtarget *Subtarget;
Modified: llvm/trunk/lib/Target/Mips/MipsInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsInstrInfo.td?rev=123760&r1=123759&r2=123760&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsInstrInfo.td (original)
+++ llvm/trunk/lib/Target/Mips/MipsInstrInfo.td Tue Jan 18 13:29:17 2011
@@ -26,6 +26,11 @@
SDTCisInt<4>]>;
def SDT_MipsCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>;
def SDT_MipsCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
+def SDT_MipsMAddMSub : SDTypeProfile<0, 4,
+ [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>,
+ SDTCisSameAs<1, 2>,
+ SDTCisSameAs<2, 3>]>;
+
// Call
def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink,
@@ -52,6 +57,16 @@
// Select Condition Code
def MipsSelectCC : SDNode<"MipsISD::SelectCC", SDT_MipsSelectCC>;
+// MAdd*/MSub* nodes
+def MipsMAdd : SDNode<"MipsISD::MAdd", SDT_MipsMAddMSub,
+ [SDNPOptInGlue, SDNPOutGlue]>;
+def MipsMAddu : SDNode<"MipsISD::MAddu", SDT_MipsMAddMSub,
+ [SDNPOptInGlue, SDNPOutGlue]>;
+def MipsMSub : SDNode<"MipsISD::MSub", SDT_MipsMAddMSub,
+ [SDNPOptInGlue, SDNPOutGlue]>;
+def MipsMSubu : SDNode<"MipsISD::MSubu", SDT_MipsMAddMSub,
+ [SDNPOptInGlue, SDNPOutGlue]>;
+
//===----------------------------------------------------------------------===//
// Mips Instruction Predicate Definitions.
//===----------------------------------------------------------------------===//
@@ -147,10 +162,11 @@
!strconcat(instr_asm, "\t$dst, $b, $c"), [], IIAlu>;
// Arithmetic Multiply ADD/SUB
-let rd=0 in
-class MArithR<bits<6> func, string instr_asm> :
- FR<0x1c, func, (outs CPURegs:$rs), (ins CPURegs:$rt),
- !strconcat(instr_asm, "\t$rs, $rt"), [], IIImul>;
+let rd = 0, shamt = 0, Defs = [HI, LO], Uses = [HI, LO] in
+class MArithR<bits<6> func, string instr_asm, SDNode op> :
+ FR<0x1c, func, (outs), (ins CPURegs:$rs, CPURegs:$rt),
+ !strconcat(instr_asm, "\t$rs, $rt"),
+ [(op CPURegs:$rs, CPURegs:$rt, LO, HI)], IIImul>;
// Logical
class LogicR<bits<6> func, string instr_asm, SDNode OpNode>:
@@ -488,11 +504,11 @@
// can be matched. It's similar to Sparc LEA_ADDRi
def LEA_ADDiu : EffectiveAddress<"addiu\t$dst, ${addr:stackloc}">;
-// MADD*/MSUB* are not part of MipsI either.
-//def MADD : MArithR<0x00, "madd">;
-//def MADDU : MArithR<0x01, "maddu">;
-//def MSUB : MArithR<0x04, "msub">;
-//def MSUBU : MArithR<0x05, "msubu">;
+// MADD*/MSUB*
+def MADD : MArithR<0, "madd", MipsMAdd>;
+def MADDU : MArithR<1, "maddu", MipsMAddu>;
+def MSUB : MArithR<4, "msub", MipsMSub>;
+def MSUBU : MArithR<5, "msubu", MipsMSubu>;
// MUL is a assembly macro in the current used ISAs. In recent ISA's
// it is a real instruction.
Added: llvm/trunk/test/CodeGen/Mips/madd-msub.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/madd-msub.ll?rev=123760&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/madd-msub.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/madd-msub.ll Tue Jan 18 13:29:17 2011
@@ -0,0 +1,65 @@
+; RUN: llc -march=mips -mcpu=4ke < %s | FileCheck %s
+
+; CHECK: madd $5, $4
+define i64 @madd1(i32 %a, i32 %b, i32 %c) nounwind readnone {
+entry:
+ %conv = sext i32 %a to i64
+ %conv2 = sext i32 %b to i64
+ %mul = mul nsw i64 %conv2, %conv
+ %conv4 = sext i32 %c to i64
+ %add = add nsw i64 %mul, %conv4
+ ret i64 %add
+}
+
+; CHECK: maddu $5, $4
+define i64 @madd2(i32 %a, i32 %b, i32 %c) nounwind readnone {
+entry:
+ %conv = zext i32 %a to i64
+ %conv2 = zext i32 %b to i64
+ %mul = mul nsw i64 %conv2, %conv
+ %conv4 = zext i32 %c to i64
+ %add = add nsw i64 %mul, %conv4
+ ret i64 %add
+}
+
+; CHECK: madd $5, $4
+define i64 @madd3(i32 %a, i32 %b, i64 %c) nounwind readnone {
+entry:
+ %conv = sext i32 %a to i64
+ %conv2 = sext i32 %b to i64
+ %mul = mul nsw i64 %conv2, %conv
+ %add = add nsw i64 %mul, %c
+ ret i64 %add
+}
+
+; CHECK: msub $5, $4
+define i64 @msub1(i32 %a, i32 %b, i32 %c) nounwind readnone {
+entry:
+ %conv = sext i32 %c to i64
+ %conv2 = sext i32 %a to i64
+ %conv4 = sext i32 %b to i64
+ %mul = mul nsw i64 %conv4, %conv2
+ %sub = sub nsw i64 %conv, %mul
+ ret i64 %sub
+}
+
+; CHECK: msubu $5, $4
+define i64 @msub2(i32 %a, i32 %b, i32 %c) nounwind readnone {
+entry:
+ %conv = zext i32 %c to i64
+ %conv2 = zext i32 %a to i64
+ %conv4 = zext i32 %b to i64
+ %mul = mul nsw i64 %conv4, %conv2
+ %sub = sub nsw i64 %conv, %mul
+ ret i64 %sub
+}
+
+; CHECK: msub $5, $4
+define i64 @msub3(i32 %a, i32 %b, i64 %c) nounwind readnone {
+entry:
+ %conv = sext i32 %a to i64
+ %conv3 = sext i32 %b to i64
+ %mul = mul nsw i64 %conv3, %conv
+ %sub = sub nsw i64 %c, %mul
+ ret i64 %sub
+}
More information about the llvm-commits
mailing list