forked from OSchip/llvm-project
Fix divmod libcall lowering. Convert to {S|U}DIVREM first and then expand the node to a libcall. rdar://9280991
llvm-svn: 129633
This commit is contained in:
parent
c715e724de
commit
b14ce09fca
|
@ -158,7 +158,7 @@ private:
|
|||
RTLIB::Libcall Call_I32,
|
||||
RTLIB::Libcall Call_I64,
|
||||
RTLIB::Libcall Call_I128);
|
||||
SDValue ExpandDivRemLibCall(SDNode *Node, bool isSigned, bool isDIV);
|
||||
void ExpandDivRemLibCall(SDNode *Node, SmallVectorImpl<SDValue> &Results);
|
||||
|
||||
SDValue EmitStackConvert(SDValue SrcOp, EVT SlotVT, EVT DestVT, DebugLoc dl);
|
||||
SDValue ExpandBUILD_VECTOR(SDNode *Node);
|
||||
|
@ -2121,10 +2121,9 @@ SDValue SelectionDAGLegalize::ExpandIntLibCall(SDNode* Node, bool isSigned,
|
|||
return ExpandLibCall(LC, Node, isSigned);
|
||||
}
|
||||
|
||||
/// ExpandDivRemLibCall - Issue libcalls to __{u}divmod to compute div / rem
|
||||
/// pairs.
|
||||
SDValue SelectionDAGLegalize::ExpandDivRemLibCall(SDNode *Node, bool isSigned,
|
||||
bool isDIV) {
|
||||
/// isDivRemLibcallAvailable - Return true if divmod libcall is available.
|
||||
static bool isDivRemLibcallAvailable(SDNode *Node, bool isSigned,
|
||||
const TargetLowering &TLI) {
|
||||
RTLIB::Libcall LC;
|
||||
switch (Node->getValueType(0).getSimpleVT().SimpleTy) {
|
||||
default: assert(0 && "Unexpected request for libcall!");
|
||||
|
@ -2135,17 +2134,18 @@ SDValue SelectionDAGLegalize::ExpandDivRemLibCall(SDNode *Node, bool isSigned,
|
|||
case MVT::i128: LC= isSigned ? RTLIB::SDIVREM_I128:RTLIB::UDIVREM_I128; break;
|
||||
}
|
||||
|
||||
if (!TLI.getLibcallName(LC))
|
||||
return SDValue();
|
||||
return TLI.getLibcallName(LC) != 0;
|
||||
}
|
||||
|
||||
// Only issue divrem libcall if both quotient and remainder are needed.
|
||||
/// UseDivRem - Only issue divrem libcall if both quotient and remainder are
|
||||
/// needed.
|
||||
static bool UseDivRem(SDNode *Node, bool isSigned, bool isDIV) {
|
||||
unsigned OtherOpcode = 0;
|
||||
if (isSigned) {
|
||||
if (isSigned)
|
||||
OtherOpcode = isDIV ? ISD::SREM : ISD::SDIV;
|
||||
} else {
|
||||
else
|
||||
OtherOpcode = isDIV ? ISD::UREM : ISD::UDIV;
|
||||
}
|
||||
SDNode *OtherNode = 0;
|
||||
|
||||
SDValue Op0 = Node->getOperand(0);
|
||||
SDValue Op1 = Node->getOperand(1);
|
||||
for (SDNode::use_iterator UI = Op0.getNode()->use_begin(),
|
||||
|
@ -2155,32 +2155,28 @@ SDValue SelectionDAGLegalize::ExpandDivRemLibCall(SDNode *Node, bool isSigned,
|
|||
continue;
|
||||
if (User->getOpcode() == OtherOpcode &&
|
||||
User->getOperand(0) == Op0 &&
|
||||
User->getOperand(1) == Op1) {
|
||||
OtherNode = User;
|
||||
break;
|
||||
}
|
||||
User->getOperand(1) == Op1)
|
||||
return true;
|
||||
}
|
||||
if (!OtherNode)
|
||||
return SDValue();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the libcall is already generated, no need to issue it again.
|
||||
DenseMap<SDValue, SDValue>::iterator I
|
||||
= LegalizedNodes.find(SDValue(OtherNode,0));
|
||||
if (I != LegalizedNodes.end()) {
|
||||
OtherNode = I->second.getNode();
|
||||
SDNode *Chain = OtherNode->getOperand(0).getNode();
|
||||
for (SDNode::use_iterator UI = Chain->use_begin(), UE = Chain->use_end();
|
||||
UI != UE; ++UI) {
|
||||
SDNode *User = *UI;
|
||||
if (User == OtherNode)
|
||||
continue;
|
||||
if (isDIV) {
|
||||
assert(User->getOpcode() == ISD::CopyFromReg);
|
||||
} else {
|
||||
assert(User->getOpcode() == ISD::LOAD);
|
||||
}
|
||||
return SDValue(User, 0);
|
||||
}
|
||||
/// ExpandDivRemLibCall - Issue libcalls to __{u}divmod to compute div / rem
|
||||
/// pairs.
|
||||
void
|
||||
SelectionDAGLegalize::ExpandDivRemLibCall(SDNode *Node,
|
||||
SmallVectorImpl<SDValue> &Results) {
|
||||
unsigned Opcode = Node->getOpcode();
|
||||
bool isSigned = Opcode == ISD::SDIVREM;
|
||||
|
||||
RTLIB::Libcall LC;
|
||||
switch (Node->getValueType(0).getSimpleVT().SimpleTy) {
|
||||
default: assert(0 && "Unexpected request for libcall!");
|
||||
case MVT::i8: LC= isSigned ? RTLIB::SDIVREM_I8 : RTLIB::UDIVREM_I8; break;
|
||||
case MVT::i16: LC= isSigned ? RTLIB::SDIVREM_I16 : RTLIB::UDIVREM_I16; break;
|
||||
case MVT::i32: LC= isSigned ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32; break;
|
||||
case MVT::i64: LC= isSigned ? RTLIB::SDIVREM_I64 : RTLIB::UDIVREM_I64; break;
|
||||
case MVT::i128: LC= isSigned ? RTLIB::SDIVREM_I128:RTLIB::UDIVREM_I128; break;
|
||||
}
|
||||
|
||||
// The input chain to this libcall is the entry node of the function.
|
||||
|
@ -2228,7 +2224,8 @@ SDValue SelectionDAGLegalize::ExpandDivRemLibCall(SDNode *Node, bool isSigned,
|
|||
// Remainder is loaded back from the stack frame.
|
||||
SDValue Rem = DAG.getLoad(RetVT, dl, LastCALLSEQ_END, FIPtr,
|
||||
MachinePointerInfo(), false, false, 0);
|
||||
return isDIV ? CallInfo.first : Rem;
|
||||
Results.push_back(CallInfo.first);
|
||||
Results.push_back(Rem);
|
||||
}
|
||||
|
||||
/// ExpandLegalINT_TO_FP - This function is responsible for legalizing a
|
||||
|
@ -3204,28 +3201,25 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node,
|
|||
unsigned DivRemOpc = isSigned ? ISD::SDIVREM : ISD::UDIVREM;
|
||||
Tmp2 = Node->getOperand(0);
|
||||
Tmp3 = Node->getOperand(1);
|
||||
if (TLI.isOperationLegalOrCustom(DivRemOpc, VT)) {
|
||||
if (TLI.isOperationLegalOrCustom(DivRemOpc, VT) ||
|
||||
(isDivRemLibcallAvailable(Node, isSigned, TLI) &&
|
||||
UseDivRem(Node, isSigned, false))) {
|
||||
Tmp1 = DAG.getNode(DivRemOpc, dl, VTs, Tmp2, Tmp3).getValue(1);
|
||||
} else if (TLI.isOperationLegalOrCustom(DivOpc, VT)) {
|
||||
// X % Y -> X-X/Y*Y
|
||||
Tmp1 = DAG.getNode(DivOpc, dl, VT, Tmp2, Tmp3);
|
||||
Tmp1 = DAG.getNode(ISD::MUL, dl, VT, Tmp1, Tmp3);
|
||||
Tmp1 = DAG.getNode(ISD::SUB, dl, VT, Tmp2, Tmp1);
|
||||
} else if (isSigned) {
|
||||
Tmp1 = ExpandDivRemLibCall(Node, true, false);
|
||||
if (!Tmp1.getNode())
|
||||
Tmp1 = ExpandIntLibCall(Node, true,
|
||||
RTLIB::SREM_I8,
|
||||
RTLIB::SREM_I16, RTLIB::SREM_I32,
|
||||
RTLIB::SREM_I64, RTLIB::SREM_I128);
|
||||
} else {
|
||||
Tmp1 = ExpandDivRemLibCall(Node, false, false);
|
||||
if (!Tmp1.getNode())
|
||||
Tmp1 = ExpandIntLibCall(Node, false,
|
||||
RTLIB::UREM_I8,
|
||||
RTLIB::UREM_I16, RTLIB::UREM_I32,
|
||||
RTLIB::UREM_I64, RTLIB::UREM_I128);
|
||||
}
|
||||
} else if (isSigned)
|
||||
Tmp1 = ExpandIntLibCall(Node, true,
|
||||
RTLIB::SREM_I8,
|
||||
RTLIB::SREM_I16, RTLIB::SREM_I32,
|
||||
RTLIB::SREM_I64, RTLIB::SREM_I128);
|
||||
else
|
||||
Tmp1 = ExpandIntLibCall(Node, false,
|
||||
RTLIB::UREM_I8,
|
||||
RTLIB::UREM_I16, RTLIB::UREM_I32,
|
||||
RTLIB::UREM_I64, RTLIB::UREM_I128);
|
||||
Results.push_back(Tmp1);
|
||||
break;
|
||||
}
|
||||
|
@ -3235,26 +3229,21 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node,
|
|||
unsigned DivRemOpc = isSigned ? ISD::SDIVREM : ISD::UDIVREM;
|
||||
EVT VT = Node->getValueType(0);
|
||||
SDVTList VTs = DAG.getVTList(VT, VT);
|
||||
if (TLI.isOperationLegalOrCustom(DivRemOpc, VT))
|
||||
if (TLI.isOperationLegalOrCustom(DivRemOpc, VT) ||
|
||||
(isDivRemLibcallAvailable(Node, isSigned, TLI) &&
|
||||
UseDivRem(Node, isSigned, true)))
|
||||
Tmp1 = DAG.getNode(DivRemOpc, dl, VTs, Node->getOperand(0),
|
||||
Node->getOperand(1));
|
||||
else if (isSigned) {
|
||||
Tmp1 = ExpandDivRemLibCall(Node, true, true);
|
||||
if (!Tmp1.getNode()) {
|
||||
Tmp1 = ExpandIntLibCall(Node, true,
|
||||
RTLIB::SDIV_I8,
|
||||
RTLIB::SDIV_I16, RTLIB::SDIV_I32,
|
||||
RTLIB::SDIV_I64, RTLIB::SDIV_I128);
|
||||
}
|
||||
} else {
|
||||
Tmp1 = ExpandDivRemLibCall(Node, false, true);
|
||||
if (!Tmp1.getNode()) {
|
||||
Tmp1 = ExpandIntLibCall(Node, false,
|
||||
RTLIB::UDIV_I8,
|
||||
RTLIB::UDIV_I16, RTLIB::UDIV_I32,
|
||||
RTLIB::UDIV_I64, RTLIB::UDIV_I128);
|
||||
}
|
||||
}
|
||||
else if (isSigned)
|
||||
Tmp1 = ExpandIntLibCall(Node, true,
|
||||
RTLIB::SDIV_I8,
|
||||
RTLIB::SDIV_I16, RTLIB::SDIV_I32,
|
||||
RTLIB::SDIV_I64, RTLIB::SDIV_I128);
|
||||
else
|
||||
Tmp1 = ExpandIntLibCall(Node, false,
|
||||
RTLIB::UDIV_I8,
|
||||
RTLIB::UDIV_I16, RTLIB::UDIV_I32,
|
||||
RTLIB::UDIV_I64, RTLIB::UDIV_I128);
|
||||
Results.push_back(Tmp1);
|
||||
break;
|
||||
}
|
||||
|
@ -3271,6 +3260,11 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node,
|
|||
Results.push_back(Tmp1.getValue(1));
|
||||
break;
|
||||
}
|
||||
case ISD::SDIVREM:
|
||||
case ISD::UDIVREM:
|
||||
// Expand into divrem libcall
|
||||
ExpandDivRemLibCall(Node, Results);
|
||||
break;
|
||||
case ISD::MUL: {
|
||||
EVT VT = Node->getValueType(0);
|
||||
SDVTList VTs = DAG.getVTList(VT, VT);
|
||||
|
|
|
@ -25,3 +25,34 @@ entry:
|
|||
store i32 %rem, i32* %arrayidx6, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; rdar://9280991
|
||||
@flags = external unnamed_addr global i32
|
||||
@tabsize = external unnamed_addr global i32
|
||||
|
||||
define void @do_indent(i32 %cols) nounwind {
|
||||
entry:
|
||||
; CHECK: do_indent:
|
||||
%0 = load i32* @flags, align 4
|
||||
%1 = and i32 %0, 67108864
|
||||
%2 = icmp eq i32 %1, 0
|
||||
br i1 %2, label %bb1, label %bb
|
||||
|
||||
bb:
|
||||
; CHECK: bl ___divmodsi4
|
||||
%3 = load i32* @tabsize, align 4
|
||||
%4 = srem i32 %cols, %3
|
||||
%5 = sdiv i32 %cols, %3
|
||||
%6 = tail call i32 @llvm.objectsize.i32(i8* null, i1 false)
|
||||
%7 = tail call i8* @__memset_chk(i8* null, i32 9, i32 %5, i32 %6) nounwind
|
||||
br label %bb1
|
||||
|
||||
bb1:
|
||||
%line_indent_len.0 = phi i32 [ %4, %bb ], [ 0, %entry ]
|
||||
%8 = getelementptr inbounds i8* null, i32 %line_indent_len.0
|
||||
store i8 0, i8* %8, align 1
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @llvm.objectsize.i32(i8*, i1) nounwind readnone
|
||||
declare i8* @__memset_chk(i8*, i32, i32, i32) nounwind
|
||||
|
|
Loading…
Reference in New Issue