Fix PR13991: legalizing an overflowing multiplication operation is harder than

the add/sub case since in the case of multiplication you also have to check that
the operation in the larger type did not overflow.

llvm-svn: 165017
This commit is contained in:
Duncan Sands 2012-10-02 15:03:49 +00:00
parent a99c35702d
commit f97cb15aee
2 changed files with 29 additions and 7 deletions

View File

@ -644,8 +644,9 @@ SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) {
EVT SmallVT = LHS.getValueType(); EVT SmallVT = LHS.getValueType();
// To determine if the result overflowed in a larger type, we extend the // To determine if the result overflowed in a larger type, we extend the
// input to the larger type, do the multiply, then check the high bits of // input to the larger type, do the multiply (checking if it overflows),
// the result to see if the overflow happened. // then also check the high bits of the result to see if overflow happened
// there.
if (N->getOpcode() == ISD::SMULO) { if (N->getOpcode() == ISD::SMULO) {
LHS = SExtPromotedInteger(LHS); LHS = SExtPromotedInteger(LHS);
RHS = SExtPromotedInteger(RHS); RHS = SExtPromotedInteger(RHS);
@ -653,24 +654,31 @@ SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) {
LHS = ZExtPromotedInteger(LHS); LHS = ZExtPromotedInteger(LHS);
RHS = ZExtPromotedInteger(RHS); RHS = ZExtPromotedInteger(RHS);
} }
SDValue Mul = DAG.getNode(ISD::MUL, DL, LHS.getValueType(), LHS, RHS); SDVTList VTs = DAG.getVTList(LHS.getValueType(), N->getValueType(1));
SDValue Mul = DAG.getNode(N->getOpcode(), DL, VTs, LHS, RHS);
// Overflow occurred iff the high part of the result does not // Overflow occurred if it occurred in the larger type, or if the high part
// zero/sign-extend the low part. // of the result does not zero/sign-extend the low part. Check this second
// possibility first.
SDValue Overflow; SDValue Overflow;
if (N->getOpcode() == ISD::UMULO) { if (N->getOpcode() == ISD::UMULO) {
// Unsigned overflow occurred iff the high part is non-zero. // Unsigned overflow occurred if the high part is non-zero.
SDValue Hi = DAG.getNode(ISD::SRL, DL, Mul.getValueType(), Mul, SDValue Hi = DAG.getNode(ISD::SRL, DL, Mul.getValueType(), Mul,
DAG.getIntPtrConstant(SmallVT.getSizeInBits())); DAG.getIntPtrConstant(SmallVT.getSizeInBits()));
Overflow = DAG.getSetCC(DL, N->getValueType(1), Hi, Overflow = DAG.getSetCC(DL, N->getValueType(1), Hi,
DAG.getConstant(0, Hi.getValueType()), ISD::SETNE); DAG.getConstant(0, Hi.getValueType()), ISD::SETNE);
} else { } else {
// Signed overflow occurred iff the high part does not sign extend the low. // Signed overflow occurred if the high part does not sign extend the low.
SDValue SExt = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Mul.getValueType(), SDValue SExt = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Mul.getValueType(),
Mul, DAG.getValueType(SmallVT)); Mul, DAG.getValueType(SmallVT));
Overflow = DAG.getSetCC(DL, N->getValueType(1), SExt, Mul, ISD::SETNE); Overflow = DAG.getSetCC(DL, N->getValueType(1), SExt, Mul, ISD::SETNE);
} }
// The only other way for overflow to occur is if the multiplication in the
// larger type itself overflowed.
Overflow = DAG.getNode(ISD::OR, DL, N->getValueType(1), Overflow,
SDValue(Mul.getNode(), 1));
// Use the calculated overflow everywhere. // Use the calculated overflow everywhere.
ReplaceValueWith(SDValue(N, 1), Overflow); ReplaceValueWith(SDValue(N, 1), Overflow);
return Mul; return Mul;

View File

@ -67,3 +67,17 @@ entry:
; CHECK: mull ; CHECK: mull
; CHECK-NEXT: ret ; CHECK-NEXT: ret
} }
declare { i63, i1 } @llvm.smul.with.overflow.i63(i63, i63) nounwind readnone
define i1 @test5() nounwind {
entry:
%res = call { i63, i1 } @llvm.smul.with.overflow.i63(i63 4, i63 4611686018427387903)
%sum = extractvalue { i63, i1 } %res, 0
%overflow = extractvalue { i63, i1 } %res, 1
ret i1 %overflow
; Was returning false, should return true (not constant folded yet though).
; PR13991
; CHECK: test5:
; CHECK-NOT: xorb
}