diff options
| author | Nikita Popov <nikita.ppv@gmail.com> | 2021-10-16 20:25:18 +0200 | 
|---|---|---|
| committer | Nikita Popov <nikita.ppv@gmail.com> | 2021-10-16 20:31:04 +0200 | 
| commit | 492a4a428f77556d413c2179fad9ba4ae6d130b9 (patch) | |
| tree | fc71652970ed308e9d3e136e89c9230195fa57cc /llvm/unittests/ADT/APIntTest.cpp | |
| parent | 2c941fa2f9b9a93b42bdddc810a817b02a937b55 (diff) | |
| download | llvm-492a4a428f77556d413c2179fad9ba4ae6d130b9.zip llvm-492a4a428f77556d413c2179fad9ba4ae6d130b9.tar.gz llvm-492a4a428f77556d413c2179fad9ba4ae6d130b9.tar.bz2 | |
[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.
Diffstat (limited to 'llvm/unittests/ADT/APIntTest.cpp')
| -rw-r--r-- | llvm/unittests/ADT/APIntTest.cpp | 21 | 
1 files changed, 18 insertions, 3 deletions
| diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp index 83bbc5e..58c17b4 100644 --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -2729,9 +2729,24 @@ TEST(APIntTest, umul_ov) {    for (unsigned Bits = 1; Bits <= 5; ++Bits)      for (unsigned A = 0; A != 1u << Bits; ++A)        for (unsigned B = 0; B != 1u << Bits; ++B) { -        APInt C = APInt(Bits, A).umul_ov(APInt(Bits, B), Overflow); -        APInt D = APInt(2 * Bits, A) * APInt(2 * Bits, B); -        EXPECT_TRUE(D.getHiBits(Bits).isNullValue() != Overflow); +        APInt N1 = APInt(Bits, A), N2 = APInt(Bits, B); +        APInt Narrow = N1.umul_ov(N2, 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);        }  } | 
