forked from OSchip/llvm-project
Add some generic expansion logic for SMULO and UMULO. Fixes UMULO
support for x86, and UMULO/SMULO for many architectures, including PPC (PR4201), ARM, and Cell. The resulting expansion isn't perfect, but it's not bad. llvm-svn: 73477
This commit is contained in:
parent
48021d15d6
commit
abfad5d61e
|
@ -2768,6 +2768,53 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node,
|
||||||
ISD::SETULT : ISD::SETUGT));
|
ISD::SETULT : ISD::SETUGT));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ISD::UMULO:
|
||||||
|
case ISD::SMULO: {
|
||||||
|
MVT VT = Node->getValueType(0);
|
||||||
|
SDValue LHS = Node->getOperand(0);
|
||||||
|
SDValue RHS = Node->getOperand(1);
|
||||||
|
SDValue BottomHalf;
|
||||||
|
SDValue TopHalf;
|
||||||
|
static unsigned Ops[2][3] =
|
||||||
|
{ { ISD::MULHU, ISD::UMUL_LOHI, ISD::ZERO_EXTEND },
|
||||||
|
{ ISD::MULHS, ISD::SMUL_LOHI, ISD::SIGN_EXTEND }};
|
||||||
|
bool isSigned = Node->getOpcode() == ISD::SMULO;
|
||||||
|
if (TLI.isOperationLegalOrCustom(Ops[isSigned][0], VT)) {
|
||||||
|
BottomHalf = DAG.getNode(ISD::MUL, dl, VT, LHS, RHS);
|
||||||
|
TopHalf = DAG.getNode(Ops[isSigned][0], dl, VT, LHS, RHS);
|
||||||
|
} else if (TLI.isOperationLegalOrCustom(Ops[isSigned][1], VT)) {
|
||||||
|
BottomHalf = DAG.getNode(Ops[isSigned][1], dl, DAG.getVTList(VT, VT), LHS,
|
||||||
|
RHS);
|
||||||
|
TopHalf = BottomHalf.getValue(1);
|
||||||
|
} else if (TLI.isTypeLegal(MVT::getIntegerVT(VT.getSizeInBits() * 2))) {
|
||||||
|
MVT WideVT = MVT::getIntegerVT(VT.getSizeInBits() * 2);
|
||||||
|
LHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, LHS);
|
||||||
|
RHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, RHS);
|
||||||
|
Tmp1 = DAG.getNode(ISD::MUL, dl, WideVT, LHS, RHS);
|
||||||
|
BottomHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Tmp1,
|
||||||
|
DAG.getIntPtrConstant(0));
|
||||||
|
TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Tmp1,
|
||||||
|
DAG.getIntPtrConstant(1));
|
||||||
|
} else {
|
||||||
|
// FIXME: We should be able to fall back to a libcall with an illegal
|
||||||
|
// type in some cases cases.
|
||||||
|
// Also, we can fall back to a division in some cases, but that's a big
|
||||||
|
// performance hit in the general case.
|
||||||
|
assert(0 && "Don't know how to expand this operation yet!");
|
||||||
|
}
|
||||||
|
if (isSigned) {
|
||||||
|
Tmp1 = DAG.getConstant(VT.getSizeInBits() - 1, TLI.getShiftAmountTy());
|
||||||
|
Tmp1 = DAG.getNode(ISD::SRA, dl, VT, BottomHalf, Tmp1);
|
||||||
|
TopHalf = DAG.getSetCC(dl, TLI.getSetCCResultType(VT), TopHalf, Tmp1,
|
||||||
|
ISD::SETNE);
|
||||||
|
} else {
|
||||||
|
TopHalf = DAG.getSetCC(dl, TLI.getSetCCResultType(VT), TopHalf,
|
||||||
|
DAG.getConstant(0, VT), ISD::SETNE);
|
||||||
|
}
|
||||||
|
Results.push_back(BottomHalf);
|
||||||
|
Results.push_back(TopHalf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ISD::BUILD_PAIR: {
|
case ISD::BUILD_PAIR: {
|
||||||
MVT PairTy = Node->getValueType(0);
|
MVT PairTy = Node->getValueType(0);
|
||||||
Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, dl, PairTy, Node->getOperand(0));
|
Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, dl, PairTy, Node->getOperand(0));
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
; RUN: llvm-as < %s | llc -march=cellspu
|
||||||
|
|
||||||
|
declare {i16, i1} @llvm.smul.with.overflow.i16(i16 %a, i16 %b)
|
||||||
|
define i1 @a(i16 %x) zeroext nounwind {
|
||||||
|
%res = call {i16, i1} @llvm.smul.with.overflow.i16(i16 %x, i16 3)
|
||||||
|
%obil = extractvalue {i16, i1} %res, 1
|
||||||
|
ret i1 %obil
|
||||||
|
}
|
||||||
|
|
||||||
|
declare {i16, i1} @llvm.umul.with.overflow.i16(i16 %a, i16 %b)
|
||||||
|
define i1 @b(i16 %x) zeroext nounwind {
|
||||||
|
%res = call {i16, i1} @llvm.umul.with.overflow.i16(i16 %x, i16 3)
|
||||||
|
%obil = extractvalue {i16, i1} %res, 1
|
||||||
|
ret i1 %obil
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
; RUN: llvm-as < %s | llc -march=ppc32
|
||||||
|
|
||||||
|
declare {i32, i1} @llvm.umul.with.overflow.i32(i32 %a, i32 %b)
|
||||||
|
define i1 @a(i32 %x) zeroext nounwind {
|
||||||
|
%res = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 3)
|
||||||
|
%obil = extractvalue {i32, i1} %res, 1
|
||||||
|
ret i1 %obil
|
||||||
|
}
|
||||||
|
|
||||||
|
declare {i32, i1} @llvm.smul.with.overflow.i32(i32 %a, i32 %b)
|
||||||
|
define i1 @b(i32 %x) zeroext nounwind {
|
||||||
|
%res = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %x, i32 3)
|
||||||
|
%obil = extractvalue {i32, i1} %res, 1
|
||||||
|
ret i1 %obil
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
; RUN: llvm-as < %s | llc -march=x86 | grep "\\\\\\\<mul"
|
||||||
|
|
||||||
|
declare {i32, i1} @llvm.umul.with.overflow.i32(i32 %a, i32 %b)
|
||||||
|
define i1 @a(i32 %x) zeroext nounwind {
|
||||||
|
%res = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 3)
|
||||||
|
%obil = extractvalue {i32, i1} %res, 1
|
||||||
|
ret i1 %obil
|
||||||
|
}
|
Loading…
Reference in New Issue