1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

Improve div/rem node handling on mips. Patch by Akira Hatanaka

llvm-svn: 127034
This commit is contained in:
Bruno Cardoso Lopes 2011-03-04 21:03:24 +00:00
parent 1deaf83a77
commit 52c64a2eb3
5 changed files with 131 additions and 34 deletions

View File

@ -362,20 +362,18 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) {
/// Mul/Div with two results
case ISD::SDIVREM:
case ISD::UDIVREM:
break;
case ISD::SMUL_LOHI:
case ISD::UMUL_LOHI: {
SDValue Op1 = Node->getOperand(0);
SDValue Op2 = Node->getOperand(1);
unsigned Op;
if (Opcode == ISD::UMUL_LOHI || Opcode == ISD::SMUL_LOHI)
Op = (Opcode == ISD::UMUL_LOHI ? Mips::MULTu : Mips::MULT);
else
Op = (Opcode == ISD::UDIVREM ? Mips::DIVu : Mips::DIV);
Op = (Opcode == ISD::UMUL_LOHI ? Mips::MULTu : Mips::MULT);
SDNode *MulDiv = CurDAG->getMachineNode(Op, dl, MVT::Glue, Op1, Op2);
SDNode *Mul = CurDAG->getMachineNode(Op, dl, MVT::Glue, Op1, Op2);
SDValue InFlag = SDValue(MulDiv, 0);
SDValue InFlag = SDValue(Mul, 0);
SDNode *Lo = CurDAG->getMachineNode(Mips::MFLO, dl, MVT::i32,
MVT::Glue, InFlag);
InFlag = SDValue(Lo,1);
@ -415,23 +413,8 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) {
case ISD::SREM:
case ISD::UREM:
case ISD::SDIV:
case ISD::UDIV: {
SDValue Op1 = Node->getOperand(0);
SDValue Op2 = Node->getOperand(1);
unsigned Op, MOp;
if (Opcode == ISD::SDIV || Opcode == ISD::UDIV) {
Op = (Opcode == ISD::SDIV ? Mips::DIV : Mips::DIVu);
MOp = Mips::MFLO;
} else {
Op = (Opcode == ISD::SREM ? Mips::DIV : Mips::DIVu);
MOp = Mips::MFHI;
}
SDNode *Node = CurDAG->getMachineNode(Op, dl, MVT::Glue, Op1, Op2);
SDValue InFlag = SDValue(Node, 0);
return CurDAG->getMachineNode(MOp, dl, MVT::i32, InFlag);
}
case ISD::UDIV:
break;
// Get target GOT address.
case ISD::GLOBAL_OFFSET_TABLE:

View File

@ -50,6 +50,8 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const {
case MipsISD::MAddu : return "MipsISD::MAddu";
case MipsISD::MSub : return "MipsISD::MSub";
case MipsISD::MSubu : return "MipsISD::MSubu";
case MipsISD::DivRem : return "MipsISD::DivRem";
case MipsISD::DivRemU : return "MipsISD::DivRemU";
default : return NULL;
}
}
@ -110,6 +112,11 @@ MipsTargetLowering(MipsTargetMachine &TM)
setOperationAction(ISD::AND, MVT::i32, Custom);
setOperationAction(ISD::OR, MVT::i32, Custom);
setOperationAction(ISD::SDIV, MVT::i32, Expand);
setOperationAction(ISD::SREM, MVT::i32, Expand);
setOperationAction(ISD::UDIV, MVT::i32, Expand);
setOperationAction(ISD::UREM, MVT::i32, Expand);
// Operations not directly supported by Mips.
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
setOperationAction(ISD::BR_CC, MVT::Other, Expand);
@ -163,6 +170,8 @@ MipsTargetLowering(MipsTargetMachine &TM)
setTargetDAGCombine(ISD::ADDE);
setTargetDAGCombine(ISD::SUBE);
setTargetDAGCombine(ISD::SDIVREM);
setTargetDAGCombine(ISD::UDIVREM);
setStackPointerRegisterToSaveRestore(Mips::SP);
computeRegisterProperties();
@ -349,6 +358,40 @@ static SDValue PerformSUBECombine(SDNode *N, SelectionDAG& DAG,
return SDValue();
}
static SDValue PerformDivRemCombine(SDNode *N, SelectionDAG& DAG,
TargetLowering::DAGCombinerInfo &DCI,
const MipsSubtarget* Subtarget) {
if (DCI.isBeforeLegalizeOps())
return SDValue();
unsigned opc = N->getOpcode() == ISD::SDIVREM ? MipsISD::DivRem :
MipsISD::DivRemU;
DebugLoc dl = N->getDebugLoc();
SDValue DivRem = DAG.getNode(opc, dl, MVT::Glue,
N->getOperand(0), N->getOperand(1));
SDValue InChain = DAG.getEntryNode();
SDValue InGlue = DivRem;
// insert MFLO
if (N->hasAnyUseOfValue(0)) {
SDValue CopyFromLo = DAG.getCopyFromReg(InChain, dl, Mips::LO, MVT::i32,
InGlue);
DAG.ReplaceAllUsesOfValueWith(SDValue(N, 0), CopyFromLo);
InChain = CopyFromLo.getValue(1);
InGlue = CopyFromLo.getValue(2);
}
// insert MFHI
if (N->hasAnyUseOfValue(1)) {
SDValue CopyFromHi = DAG.getCopyFromReg(InChain, dl,
Mips::HI, MVT::i32, InGlue);
DAG.ReplaceAllUsesOfValueWith(SDValue(N, 1), CopyFromHi);
}
return SDValue();
}
SDValue MipsTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI)
const {
SelectionDAG &DAG = DCI.DAG;
@ -360,6 +403,9 @@ SDValue MipsTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI)
return PerformADDECombine(N, DAG, DCI, Subtarget);
case ISD::SUBE:
return PerformSUBECombine(N, DAG, DCI, Subtarget);
case ISD::SDIVREM:
case ISD::UDIVREM:
return PerformDivRemCombine(N, DAG, DCI, Subtarget);
}
return SDValue();

View File

@ -62,7 +62,11 @@ namespace llvm {
MAdd,
MAddu,
MSub,
MSubu
MSubu,
// DivRem(u)
DivRem,
DivRemU
};
}

View File

@ -30,7 +30,9 @@ def SDT_MipsMAddMSub : SDTypeProfile<0, 4,
[SDTCisVT<0, i32>, SDTCisSameAs<0, 1>,
SDTCisSameAs<1, 2>,
SDTCisSameAs<2, 3>]>;
def SDT_MipsDivRem : SDTypeProfile<0, 2,
[SDTCisVT<0, i32>,
SDTCisSameAs<0, 1>]>;
// Call
def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink,
@ -67,6 +69,12 @@ def MipsMSub : SDNode<"MipsISD::MSub", SDT_MipsMAddMSub,
def MipsMSubu : SDNode<"MipsISD::MSubu", SDT_MipsMAddMSub,
[SDNPOptInGlue, SDNPOutGlue]>;
// DivRem(u) nodes
def MipsDivRem : SDNode<"MipsISD::DivRem", SDT_MipsDivRem,
[SDNPOutGlue]>;
def MipsDivRemU : SDNode<"MipsISD::DivRemU", SDT_MipsDivRem,
[SDNPOutGlue]>;
//===----------------------------------------------------------------------===//
// Mips Instruction Predicate Definitions.
//===----------------------------------------------------------------------===//
@ -283,9 +291,16 @@ let isCall=1, hasDelaySlot=1,
}
// Mul, Div
class MulDiv<bits<6> func, string instr_asm, InstrItinClass itin>:
FR<0x00, func, (outs), (ins CPURegs:$a, CPURegs:$b),
!strconcat(instr_asm, "\t$a, $b"), [], itin>;
let Defs = [HI, LO] in {
class Mul<bits<6> func, string instr_asm, InstrItinClass itin>:
FR<0x00, func, (outs), (ins CPURegs:$a, CPURegs:$b),
!strconcat(instr_asm, "\t$a, $b"), [], itin>;
class Div<SDNode op, bits<6> func, string instr_asm, InstrItinClass itin>:
FR<0x00, func, (outs), (ins CPURegs:$a, CPURegs:$b),
!strconcat(instr_asm, "\t$$zero, $a, $b"),
[(op CPURegs:$a, CPURegs:$b)], itin>;
}
// Move from Hi/Lo
class MoveFromLOHI<bits<6> func, string instr_asm>:
@ -452,12 +467,10 @@ let isReturn=1, isTerminator=1, hasDelaySlot=1,
"jr\t$target", [(MipsRet CPURegs:$target)], IIBranch>;
/// Multiply and Divide Instructions.
let Defs = [HI, LO] in {
def MULT : MulDiv<0x18, "mult", IIImul>;
def MULTu : MulDiv<0x19, "multu", IIImul>;
def DIV : MulDiv<0x1a, "div", IIIdiv>;
def DIVu : MulDiv<0x1b, "divu", IIIdiv>;
}
def MULT : Mul<0x18, "mult", IIImul>;
def MULTu : Mul<0x19, "multu", IIImul>;
def SDIV : Div<MipsDivRem, 0x1a, "div", IIIdiv>;
def UDIV : Div<MipsDivRemU, 0x1b, "divu", IIIdiv>;
let Defs = [HI] in
def MTHI : MoveToLOHI<0x11, "mthi">;

View File

@ -0,0 +1,51 @@
; RUN: llc -march=mips < %s | FileCheck %s
; CHECK: div $zero,
define i32 @sdiv1(i32 %a0, i32 %a1) nounwind readnone {
entry:
%div = sdiv i32 %a0, %a1
ret i32 %div
}
; CHECK: div $zero,
define i32 @srem1(i32 %a0, i32 %a1) nounwind readnone {
entry:
%rem = srem i32 %a0, %a1
ret i32 %rem
}
; CHECK: divu $zero,
define i32 @udiv1(i32 %a0, i32 %a1) nounwind readnone {
entry:
%div = udiv i32 %a0, %a1
ret i32 %div
}
; CHECK: divu $zero,
define i32 @urem1(i32 %a0, i32 %a1) nounwind readnone {
entry:
%rem = urem i32 %a0, %a1
ret i32 %rem
}
; CHECK: div $zero,
define i32 @sdivrem1(i32 %a0, i32 %a1, i32* nocapture %r) nounwind {
entry:
%rem = srem i32 %a0, %a1
store i32 %rem, i32* %r, align 4, !tbaa !0
%div = sdiv i32 %a0, %a1
ret i32 %div
}
; CHECK: divu $zero,
define i32 @udivrem1(i32 %a0, i32 %a1, i32* nocapture %r) nounwind {
entry:
%rem = urem i32 %a0, %a1
store i32 %rem, i32* %r, align 4, !tbaa !0
%div = udiv i32 %a0, %a1
ret i32 %div
}
!0 = metadata !{metadata !"int", metadata !1}
!1 = metadata !{metadata !"omnipotent char", metadata !2}
!2 = metadata !{metadata !"Simple C/C++ TBAA", null}