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:
parent
1deaf83a77
commit
52c64a2eb3
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -62,7 +62,11 @@ namespace llvm {
|
||||
MAdd,
|
||||
MAddu,
|
||||
MSub,
|
||||
MSubu
|
||||
MSubu,
|
||||
|
||||
// DivRem(u)
|
||||
DivRem,
|
||||
DivRemU
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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">;
|
||||
|
51
test/CodeGen/Mips/divrem.ll
Normal file
51
test/CodeGen/Mips/divrem.ll
Normal 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}
|
Loading…
x
Reference in New Issue
Block a user