From fd76e3ca8abc2ea83e6c603a8ac4abc5e4eb2953 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Tue, 7 Mar 2017 05:36:19 +0000 Subject: [PATCH] [APInt] Add rvalue reference support to and, or, xor operations to allow their memory allocation to be reused when possible This extends an earlier change that did similar for add and sub operations. With this first patch we lose the fastpath for the single word case as operator&= and friends don't support it. This can be added there if we think that's important. I had to change some functions in the APInt class since the operator overloads were moved out of the class and can't be used inside the class now. The getBitsSet change collides with another outstanding patch to implement it with setBits. But I didn't want to make this patch dependent on that series. I've also removed the Or, And, Xor functions which were rarely or never used. I already commited two changes to remove the only uses of Or that existed. Differential Revision: https://reviews.llvm.org/D30612 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297121 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/APInt.h | 81 +++++++++++++----------------- lib/Support/APInt.cpp | 25 --------- unittests/ADT/APIntTest.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 71 deletions(-) diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h index 8656ef2cdf4..e37df98ce1e 100644 --- a/include/llvm/ADT/APInt.h +++ b/include/llvm/ADT/APInt.h @@ -196,15 +196,6 @@ class LLVM_NODISCARD APInt { /// out-of-line slow case for shl APInt shlSlowCase(unsigned shiftAmt) const; - /// out-of-line slow case for operator& - APInt AndSlowCase(const APInt &RHS) const; - - /// out-of-line slow case for operator| - APInt OrSlowCase(const APInt &RHS) const; - - /// out-of-line slow case for operator^ - APInt XorSlowCase(const APInt &RHS) const; - /// out-of-line slow case for operator= APInt &AssignSlowCase(const APInt &RHS); @@ -782,42 +773,6 @@ public: /// \name Binary Operators /// @{ - /// \brief Bitwise AND operator. - /// - /// Performs a bitwise AND operation on *this and RHS. - /// - /// \returns An APInt value representing the bitwise AND of *this and RHS. - APInt operator&(const APInt &RHS) const { - assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) - return APInt(getBitWidth(), VAL & RHS.VAL); - return AndSlowCase(RHS); - } - - /// \brief Bitwise OR operator. - /// - /// Performs a bitwise OR operation on *this and RHS. - /// - /// \returns An APInt value representing the bitwise OR of *this and RHS. - APInt operator|(const APInt &RHS) const { - assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) - return APInt(getBitWidth(), VAL | RHS.VAL); - return OrSlowCase(RHS); - } - - /// \brief Bitwise XOR operator. - /// - /// Performs a bitwise XOR operation on *this and RHS. - /// - /// \returns An APInt value representing the bitwise XOR of *this and RHS. - APInt operator^(const APInt &RHS) const { - assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); - if (isSingleWord()) - return APInt(BitWidth, VAL ^ RHS.VAL); - return XorSlowCase(RHS); - } - /// \brief Multiplication operator. /// /// Multiplies this APInt by RHS and returns the result. @@ -1143,7 +1098,11 @@ public: /// This operation tests if there are any pairs of corresponding bits /// between this APInt and RHS that are both set. - bool intersects(const APInt &RHS) const { return (*this & RHS) != 0; } + bool intersects(const APInt &RHS) const { + APInt temp(*this); + temp &= RHS; + return temp != 0; + } /// @} /// \name Resizing Operators @@ -1771,6 +1730,16 @@ inline APInt operator~(APInt v) { return v; } +inline APInt operator&(APInt a, const APInt &b) { + a &= b; + return a; +} + +inline APInt operator&(const APInt &a, APInt &&b) { + b &= a; + return std::move(b); +} + inline APInt operator&(APInt a, uint64_t RHS) { a &= RHS; return a; @@ -1781,6 +1750,16 @@ inline APInt operator&(uint64_t LHS, APInt b) { return b; } +inline APInt operator|(APInt a, const APInt &b) { + a |= b; + return a; +} + +inline APInt operator|(const APInt &a, APInt &&b) { + b |= a; + return std::move(b); +} + inline APInt operator|(APInt a, uint64_t RHS) { a |= RHS; return a; @@ -1791,6 +1770,16 @@ inline APInt operator|(uint64_t LHS, APInt b) { return b; } +inline APInt operator^(APInt a, const APInt &b) { + a ^= b; + return a; +} + +inline APInt operator^(const APInt &a, APInt &&b) { + b ^= a; + return std::move(b); +} + inline APInt operator^(APInt a, uint64_t RHS) { a ^= RHS; return a; diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 30c9cb71637..e0418dd9e2c 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -461,31 +461,6 @@ APInt& APInt::operator^=(const APInt& RHS) { return *this; } -APInt APInt::AndSlowCase(const APInt& RHS) const { - unsigned numWords = getNumWords(); - uint64_t* val = getMemory(numWords); - for (unsigned i = 0; i < numWords; ++i) - val[i] = pVal[i] & RHS.pVal[i]; - return APInt(val, getBitWidth()); -} - -APInt APInt::OrSlowCase(const APInt& RHS) const { - unsigned numWords = getNumWords(); - uint64_t *val = getMemory(numWords); - for (unsigned i = 0; i < numWords; ++i) - val[i] = pVal[i] | RHS.pVal[i]; - return APInt(val, getBitWidth()); -} - -APInt APInt::XorSlowCase(const APInt& RHS) const { - unsigned numWords = getNumWords(); - uint64_t *val = getMemory(numWords); - for (unsigned i = 0; i < numWords; ++i) - val[i] = pVal[i] ^ RHS.pVal[i]; - - return APInt(val, getBitWidth()); -} - APInt APInt::operator*(const APInt& RHS) const { assert(BitWidth == RHS.BitWidth && "Bit widths must be the same"); if (isSingleWord()) diff --git a/unittests/ADT/APIntTest.cpp b/unittests/ADT/APIntTest.cpp index ea1eb54bfc9..ed6f41e3b7d 100644 --- a/unittests/ADT/APIntTest.cpp +++ b/unittests/ADT/APIntTest.cpp @@ -761,6 +761,126 @@ TEST(APIntTest, rvalue_arithmetic) { } } +TEST(APIntTest, rvalue_bitwise) { + // Test all combinations of lvalue/rvalue lhs/rhs of and/or/xor + + // Lamdba to return an APInt by value, but also provide the raw value of the + // allocated data. + auto getRValue = [](const char *HexString, uint64_t const *&RawData) { + APInt V(129, HexString, 16); + RawData = V.getRawData(); + return V; + }; + + APInt Ten(129, "A", 16); + APInt Twelve(129, "C", 16); + + const uint64_t *RawDataL = nullptr; + const uint64_t *RawDataR = nullptr; + + { + // 12 & 10 = 8 + APInt AndLL = Ten & Twelve; + EXPECT_EQ(AndLL, 0x8); + + APInt AndLR = Ten & getRValue("C", RawDataR); + EXPECT_EQ(AndLR, 0x8); + EXPECT_EQ(AndLR.getRawData(), RawDataR); + + APInt AndRL = getRValue("A", RawDataL) & Twelve; + EXPECT_EQ(AndRL, 0x8); + EXPECT_EQ(AndRL.getRawData(), RawDataL); + + APInt AndRR = getRValue("A", RawDataL) & getRValue("C", RawDataR); + EXPECT_EQ(AndRR, 0x8); + EXPECT_EQ(AndRR.getRawData(), RawDataR); + + // LValue's and constants + APInt AndLK = Ten & 0xc; + EXPECT_EQ(AndLK, 0x8); + + APInt AndKL = 0xa & Twelve; + EXPECT_EQ(AndKL, 0x8); + + // RValue's and constants + APInt AndRK = getRValue("A", RawDataL) & 0xc; + EXPECT_EQ(AndRK, 0x8); + EXPECT_EQ(AndRK.getRawData(), RawDataL); + + APInt AndKR = 0xa & getRValue("C", RawDataR); + EXPECT_EQ(AndKR, 0x8); + EXPECT_EQ(AndKR.getRawData(), RawDataR); + } + + { + // 12 | 10 = 14 + APInt OrLL = Ten | Twelve; + EXPECT_EQ(OrLL, 0xe); + + APInt OrLR = Ten | getRValue("C", RawDataR); + EXPECT_EQ(OrLR, 0xe); + EXPECT_EQ(OrLR.getRawData(), RawDataR); + + APInt OrRL = getRValue("A", RawDataL) | Twelve; + EXPECT_EQ(OrRL, 0xe); + EXPECT_EQ(OrRL.getRawData(), RawDataL); + + APInt OrRR = getRValue("A", RawDataL) | getRValue("C", RawDataR); + EXPECT_EQ(OrRR, 0xe); + EXPECT_EQ(OrRR.getRawData(), RawDataR); + + // LValue's and constants + APInt OrLK = Ten | 0xc; + EXPECT_EQ(OrLK, 0xe); + + APInt OrKL = 0xa | Twelve; + EXPECT_EQ(OrKL, 0xe); + + // RValue's and constants + APInt OrRK = getRValue("A", RawDataL) | 0xc; + EXPECT_EQ(OrRK, 0xe); + EXPECT_EQ(OrRK.getRawData(), RawDataL); + + APInt OrKR = 0xa | getRValue("C", RawDataR); + EXPECT_EQ(OrKR, 0xe); + EXPECT_EQ(OrKR.getRawData(), RawDataR); + } + + { + // 12 ^ 10 = 6 + APInt XorLL = Ten ^ Twelve; + EXPECT_EQ(XorLL, 0x6); + + APInt XorLR = Ten ^ getRValue("C", RawDataR); + EXPECT_EQ(XorLR, 0x6); + EXPECT_EQ(XorLR.getRawData(), RawDataR); + + APInt XorRL = getRValue("A", RawDataL) ^ Twelve; + EXPECT_EQ(XorRL, 0x6); + EXPECT_EQ(XorRL.getRawData(), RawDataL); + + APInt XorRR = getRValue("A", RawDataL) ^ getRValue("C", RawDataR); + EXPECT_EQ(XorRR, 0x6); + EXPECT_EQ(XorRR.getRawData(), RawDataR); + + // LValue's and constants + APInt XorLK = Ten ^ 0xc; + EXPECT_EQ(XorLK, 0x6); + + APInt XorKL = 0xa ^ Twelve; + EXPECT_EQ(XorKL, 0x6); + + // RValue's and constants + APInt XorRK = getRValue("A", RawDataL) ^ 0xc; + EXPECT_EQ(XorRK, 0x6); + EXPECT_EQ(XorRK.getRawData(), RawDataL); + + APInt XorKR = 0xa ^ getRValue("C", RawDataR); + EXPECT_EQ(XorKR, 0x6); + EXPECT_EQ(XorKR.getRawData(), RawDataR); + } +} + TEST(APIntTest, rvalue_invert) { // Lamdba to return an APInt by value, but also provide the raw value of the // allocated data. -- 2.11.0