forked from OSchip/llvm-project
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:
parent
a99c35702d
commit
f97cb15aee
|
@ -644,8 +644,9 @@ SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) {
|
|||
EVT SmallVT = LHS.getValueType();
|
||||
|
||||
// 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
|
||||
// the result to see if the overflow happened.
|
||||
// input to the larger type, do the multiply (checking if it overflows),
|
||||
// then also check the high bits of the result to see if overflow happened
|
||||
// there.
|
||||
if (N->getOpcode() == ISD::SMULO) {
|
||||
LHS = SExtPromotedInteger(LHS);
|
||||
RHS = SExtPromotedInteger(RHS);
|
||||
|
@ -653,24 +654,31 @@ SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) {
|
|||
LHS = ZExtPromotedInteger(LHS);
|
||||
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
|
||||
// zero/sign-extend the low part.
|
||||
// Overflow occurred if it occurred in the larger type, or if the high part
|
||||
// of the result does not zero/sign-extend the low part. Check this second
|
||||
// possibility first.
|
||||
SDValue Overflow;
|
||||
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,
|
||||
DAG.getIntPtrConstant(SmallVT.getSizeInBits()));
|
||||
Overflow = DAG.getSetCC(DL, N->getValueType(1), Hi,
|
||||
DAG.getConstant(0, Hi.getValueType()), ISD::SETNE);
|
||||
} 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(),
|
||||
Mul, DAG.getValueType(SmallVT));
|
||||
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.
|
||||
ReplaceValueWith(SDValue(N, 1), Overflow);
|
||||
return Mul;
|
||||
|
|
|
@ -67,3 +67,17 @@ entry:
|
|||
; CHECK: mull
|
||||
; 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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue