Fix divmod libcall lowering. Convert to {S|U}DIVREM first and then expand the node to a libcall. rdar://9280991

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@129633 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2011-04-16 03:08:26 +00:00
parent 86837e8745
commit 65279cb9bd
2 changed files with 96 additions and 71 deletions

View File

@ -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);

View File

@ -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