forked from OSchip/llvm-project
[APInt] Fix 1-bit edge case in smul_ov()
The sdiv used to check for overflow can itself overflow if the LHS is signed min and the RHS is -1. The code tried to account for this by also checking the commuted version. However, for 1-bit values, signed min and -1 are the same value, so both divisions overflow. As such, the overflow for -1 * -1 was not detected (which results in -1 rather than 1 for 1-bit values). Fix this by explicitly checking for this case instead. Noticed while adding exhaustive test coverage for smul_ov(), which is also part of this commit.
This commit is contained in:
parent
2c941fa2f9
commit
492a4a428f
|
@ -1952,8 +1952,9 @@ APInt APInt::sdiv_ov(const APInt &RHS, bool &Overflow) const {
|
||||||
APInt APInt::smul_ov(const APInt &RHS, bool &Overflow) const {
|
APInt APInt::smul_ov(const APInt &RHS, bool &Overflow) const {
|
||||||
APInt Res = *this * RHS;
|
APInt Res = *this * RHS;
|
||||||
|
|
||||||
if (*this != 0 && RHS != 0)
|
if (RHS != 0)
|
||||||
Overflow = Res.sdiv(RHS) != *this || Res.sdiv(*this) != RHS;
|
Overflow = Res.sdiv(RHS) != *this ||
|
||||||
|
(isMinSignedValue() && RHS.isAllOnes());
|
||||||
else
|
else
|
||||||
Overflow = false;
|
Overflow = false;
|
||||||
return Res;
|
return Res;
|
||||||
|
|
|
@ -2729,9 +2729,24 @@ TEST(APIntTest, umul_ov) {
|
||||||
for (unsigned Bits = 1; Bits <= 5; ++Bits)
|
for (unsigned Bits = 1; Bits <= 5; ++Bits)
|
||||||
for (unsigned A = 0; A != 1u << Bits; ++A)
|
for (unsigned A = 0; A != 1u << Bits; ++A)
|
||||||
for (unsigned B = 0; B != 1u << Bits; ++B) {
|
for (unsigned B = 0; B != 1u << Bits; ++B) {
|
||||||
APInt C = APInt(Bits, A).umul_ov(APInt(Bits, B), Overflow);
|
APInt N1 = APInt(Bits, A), N2 = APInt(Bits, B);
|
||||||
APInt D = APInt(2 * Bits, A) * APInt(2 * Bits, B);
|
APInt Narrow = N1.umul_ov(N2, Overflow);
|
||||||
EXPECT_TRUE(D.getHiBits(Bits).isNullValue() != Overflow);
|
APInt Wide = N1.zext(2 * Bits) * N2.zext(2 * Bits);
|
||||||
|
EXPECT_EQ(Wide.trunc(Bits), Narrow);
|
||||||
|
EXPECT_EQ(Narrow.zext(2 * Bits) != Wide, Overflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(APIntTest, smul_ov) {
|
||||||
|
for (unsigned Bits = 1; Bits <= 5; ++Bits)
|
||||||
|
for (unsigned A = 0; A != 1u << Bits; ++A)
|
||||||
|
for (unsigned B = 0; B != 1u << Bits; ++B) {
|
||||||
|
bool Overflow;
|
||||||
|
APInt N1 = APInt(Bits, A), N2 = APInt(Bits, B);
|
||||||
|
APInt Narrow = N1.smul_ov(N2, Overflow);
|
||||||
|
APInt Wide = N1.sext(2 * Bits) * N2.sext(2 * Bits);
|
||||||
|
EXPECT_EQ(Wide.trunc(Bits), Narrow);
|
||||||
|
EXPECT_EQ(Narrow.sext(2 * Bits) != Wide, Overflow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue