forked from OSchip/llvm-project
Add support for mips32 madd and msub instructions. Patch by Akira Hatanaka
llvm-svn: 123760
This commit is contained in:
parent
e84389bf68
commit
4dc73fa075
|
@ -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
|
||||
{
|
||||
|
|
|
@ -56,7 +56,13 @@ namespace llvm {
|
|||
FPRound,
|
||||
|
||||
// Return
|
||||
Ret
|
||||
Ret,
|
||||
|
||||
// MAdd/Sub nodes
|
||||
MAdd,
|
||||
MAddu,
|
||||
MSub,
|
||||
MSubu
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -80,6 +86,8 @@ namespace llvm {
|
|||
|
||||
/// 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;
|
||||
|
|
|
@ -26,6 +26,11 @@ def SDT_MipsCMov : SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>,
|
|||
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 @@ def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeqEnd,
|
|||
// 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 @@ class ArithOverflowI<bits<6> op, string instr_asm, SDNode OpNode,
|
|||
!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 @@ let addr=0 in
|
|||
// 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.
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue