diff options
author | Chris Lattner <clattner@nondot.org> | 2021-09-09 16:20:25 -0700 |
---|---|---|
committer | Chris Lattner <clattner@nondot.org> | 2021-09-09 22:43:54 -0700 |
commit | 704a39569346401e96a6a3978ddc490dfa828ccc (patch) | |
tree | e1a478506950c7b0ae058478cdff80b43a204964 /llvm/unittests/ADT/APIntTest.cpp | |
parent | 7f793b102c9a11eddcf247da8043a3556581e7c1 (diff) | |
download | llvm-704a39569346401e96a6a3978ddc490dfa828ccc.zip llvm-704a39569346401e96a6a3978ddc490dfa828ccc.tar.gz llvm-704a39569346401e96a6a3978ddc490dfa828ccc.tar.bz2 |
[APInt] Enable APInt to support zero bit integers.
Motivation: APInt not supporting zero bit values leads to
a lot of special cases in various bits of code, particularly
when using APInt as a bit vector (where you want to start with
zero bits and then concat on more. This is particularly
challenging in the CIRCT project, where the absence of zero-bit
ConstantOp forces duplication of ops and makes instcombine-like
logic far more complicated.
Approach: zero bit integers are weird. There are two reasonable
approaches: either make it illegal to do general arithmetic on
them (e.g. sign extends), or treat them as as implicitly having
a zero value. This patch takes the conservative approach, which
enables their use in bitvector applications.
Differential Revision: https://reviews.llvm.org/D109555
Diffstat (limited to 'llvm/unittests/ADT/APIntTest.cpp')
-rw-r--r-- | llvm/unittests/ADT/APIntTest.cpp | 76 |
1 files changed, 75 insertions, 1 deletions
diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp index 74e0c46..0f8f462 100644 --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -1422,7 +1422,6 @@ TEST(APIntTest, Log2) { #ifdef GTEST_HAS_DEATH_TEST #ifndef NDEBUG TEST(APIntTest, StringDeath) { - EXPECT_DEATH((void)APInt(0, "", 0), "Bitwidth too small"); EXPECT_DEATH((void)APInt(32, "", 0), "Invalid string length"); EXPECT_DEATH((void)APInt(32, "0", 0), "Radix should be 2, 8, 10, 16, or 36!"); EXPECT_DEATH((void)APInt(32, "", 10), "Invalid string length"); @@ -2908,4 +2907,79 @@ TEST(APIntTest, SignbitZeroChecks) { EXPECT_FALSE(APInt(8, 1).isNonPositive()); } +TEST(APIntTest, ZeroWidth) { + // Zero width Constructors. + auto ZW = APInt::getZeroWidth(); + EXPECT_EQ(0U, ZW.getBitWidth()); + EXPECT_EQ(0U, APInt(0, ArrayRef<uint64_t>({0, 1, 2})).getBitWidth()); + EXPECT_EQ(0U, APInt(0, "0", 10).getBitWidth()); + + // Default constructor is single bit wide. + EXPECT_EQ(1U, APInt().getBitWidth()); + + // Copy ctor (move is down below). + APInt ZW2(ZW); + EXPECT_EQ(0U, ZW2.getBitWidth()); + // Assignment + ZW = ZW2; + EXPECT_EQ(0U, ZW.getBitWidth()); + + // Methods like getLowBitsSet work with zero bits. + EXPECT_EQ(0U, APInt::getLowBitsSet(0, 0).getBitWidth()); + EXPECT_EQ(0U, APInt::getSplat(0, ZW).getBitWidth()); + + // Logical operators. + ZW |= ZW2; + ZW &= ZW2; + ZW ^= ZW2; + ZW |= 42; // These ignore high bits of the literal. + ZW &= 42; + ZW ^= 42; + EXPECT_EQ(1, ZW.isIntN(0)); + + // Modulo Arithmetic. Divide/Rem aren't defined on division by zero, so they + // aren't supported. + ZW += ZW2; + ZW -= ZW2; + ZW *= ZW2; + + // Logical Shifts and rotates, the amount must be <= bitwidth. + ZW <<= 0; + ZW.lshrInPlace(0); + (void)ZW.rotl(0); + (void)ZW.rotr(0); + + // Comparisons. + EXPECT_EQ(1, ZW == ZW); + EXPECT_EQ(0, ZW != ZW); + EXPECT_EQ(0, ZW.ult(ZW)); + + // Mutations. + ZW.setBitsWithWrap(0, 0); + ZW.setBits(0, 0); + ZW.clearAllBits(); + ZW.flipAllBits(); + + // Leading, trailing, ctpop, etc + EXPECT_EQ(0U, ZW.countLeadingZeros()); + EXPECT_EQ(0U, ZW.countLeadingOnes()); + EXPECT_EQ(0U, ZW.countPopulation()); + EXPECT_EQ(0U, ZW.reverseBits().getBitWidth()); + EXPECT_EQ(0U, ZW.getHiBits(0).getBitWidth()); + EXPECT_EQ(0U, ZW.getLoBits(0).getBitWidth()); + EXPECT_EQ(0, ZW.zext(4)); + EXPECT_EQ(0U, APInt(4, 3).trunc(0).getBitWidth()); + + SmallString<42> STR; + ZW.toStringUnsigned(STR); + EXPECT_EQ("0", STR); + + // Move ctor (keep at the end of the method since moves are destructive). + APInt MZW1(std::move(ZW)); + EXPECT_EQ(0U, MZW1.getBitWidth()); + // Move Assignment + MZW1 = std::move(ZW2); + EXPECT_EQ(0U, MZW1.getBitWidth()); +} + } // end anonymous namespace |