diff --git a/include/llvm/ADT/BitVector.h b/include/llvm/ADT/BitVector.h index 9c046efaadd..45108c8cc51 100644 --- a/include/llvm/ADT/BitVector.h +++ b/include/llvm/ADT/BitVector.h @@ -95,6 +95,9 @@ public: delete[] Bits; } + /// empty - Tests whether there are no bits in this bitvector. + bool empty() const { return Size == 0; } + /// size - Returns the number of bits in this bitvector. unsigned size() const { return Size; } @@ -341,6 +344,12 @@ public: return *this; } + void swap(BitVector &RHS) { + std::swap(Bits, RHS.Bits); + std::swap(Size, RHS.Size); + std::swap(Capacity, RHS.Capacity); + } + private: unsigned NumBitWords(unsigned S) const { return (S + BITWORD_SIZE-1) / BITWORD_SIZE; @@ -406,4 +415,13 @@ inline BitVector operator^(const BitVector &LHS, const BitVector &RHS) { } } // End llvm namespace + +namespace std { + /// Implement std::swap in terms of BitVector swap. + inline void + swap(llvm::BitVector &LHS, llvm::BitVector &RHS) { + LHS.swap(RHS); + } +} + #endif diff --git a/include/llvm/ADT/SmallBitVector.h b/include/llvm/ADT/SmallBitVector.h new file mode 100644 index 00000000000..e2420e049b4 --- /dev/null +++ b/include/llvm/ADT/SmallBitVector.h @@ -0,0 +1,373 @@ +//===- llvm/ADT/SmallBitVector.h - 'Normally small' bit vectors -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SmallBitVector class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SMALLBITVECTOR_H +#define LLVM_ADT_SMALLBITVECTOR_H + +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/MathExtras.h" +#include + +namespace llvm { + +/// SmallBitVector - This is a 'bitvector' (really, a variable-sized bit array), +/// optimized for the case when the array is small. It contains one +/// pointer-sized field, which is directly used as a plain collection of bits +/// when possible, or as a pointer to a larger heap-allocated array when +/// necessary. This allows normal "small" cases to be fast without losing +/// generality for large inputs. +/// +class SmallBitVector { + // TODO: In "large" mode, a pointer to a BitVector is used, leading to an + // unnecessary level of indirection. It would be more efficient to use a + // pointer to memory containing size, allocation size, and the array of bits. + PointerIntPair X; + + // The number of bits in this class. + static const size_t NumBaseBits = sizeof(X) * CHAR_BIT; + + // One bit is used to discriminate between small and large mode. The + // remaining bits are used for the small-mode representation. + static const size_t SmallNumRawBits = NumBaseBits - 1; + + // A few more bits are used to store the size of the bit set in small mode. + // Theoretically this is a ceil-log2. These bits are encoded in the most + // significant bits of the raw bits. + static const size_t SmallNumSizeBits = (NumBaseBits == 32 ? 5 : + NumBaseBits == 64 ? 6 : + SmallNumRawBits); + + // The remaining bits are used to store the actual set in small mode. + static const size_t SmallNumDataBits = SmallNumRawBits - SmallNumSizeBits; + + bool isSmall() const { + return X.getInt(); + } + + void switchToSmall(uintptr_t NewSmallBits, size_t NewSize) { + X.setInt(true); + setSmallSize(NewSize); + setSmallBits(NewSmallBits); + } + + void switchToLarge(BitVector *BV) { + X.setInt(false); + X.setPointer(BV); + } + + // Return all the bits used for the "small" representation; this includes + // bits for the size as well as the element bits. + uintptr_t getSmallRawBits() const { + return reinterpret_cast(X.getPointer()) >> 1; + } + + void setSmallRawBits(uintptr_t NewRawBits) { + return X.setPointer(reinterpret_cast(NewRawBits << 1)); + } + + // Return the size. + size_t getSmallSize() const { + return getSmallRawBits() >> SmallNumDataBits; + } + + void setSmallSize(size_t Size) { + setSmallRawBits(getSmallBits() | (Size << SmallNumDataBits)); + } + + // Return the element bits. + uintptr_t getSmallBits() const { + return getSmallRawBits() & ~(~uintptr_t(0) << SmallNumDataBits); + } + + void setSmallBits(uintptr_t NewBits) { + setSmallRawBits((getSmallRawBits() & (~uintptr_t(0) << SmallNumDataBits)) | + (NewBits & ~(~uintptr_t(0) << getSmallSize()))); + } + +public: + /// SmallBitVector default ctor - Creates an empty bitvector. + SmallBitVector() : X(0, 1) {} + + /// SmallBitVector ctor - Creates a bitvector of specified number of bits. All + /// bits are initialized to the specified value. + explicit SmallBitVector(unsigned s, bool t = false) : X(0, 1) { + if (s <= SmallNumRawBits) + switchToSmall(t ? ~uintptr_t(0) : 0, s); + else + switchToLarge(new BitVector(s, t)); + } + + /// SmallBitVector copy ctor. + SmallBitVector(const SmallBitVector &RHS) { + if (RHS.isSmall()) + X = RHS.X; + else + switchToLarge(new BitVector(*RHS.X.getPointer())); + } + + ~SmallBitVector() { + if (!isSmall()) + delete X.getPointer(); + } + + /// empty - Tests whether there are no bits in this bitvector. + bool empty() const { + return isSmall() ? getSmallSize() == 0 : X.getPointer()->empty(); + } + + /// size - Returns the number of bits in this bitvector. + size_t size() const { + return isSmall() ? getSmallSize() : X.getPointer()->size(); + } + + /// count - Returns the number of bits which are set. + unsigned count() const { + if (isSmall()) { + uintptr_t Bits = getSmallBits(); + if (sizeof(uintptr_t) * CHAR_BIT == 32) + return CountPopulation_32(Bits); + if (sizeof(uintptr_t) * CHAR_BIT == 64) + return CountPopulation_64(Bits); + assert(0 && "Unsupported!"); + } + return X.getPointer()->count(); + } + + /// any - Returns true if any bit is set. + bool any() const { + if (isSmall()) + return getSmallBits() != 0; + return X.getPointer()->any(); + } + + /// none - Returns true if none of the bits are set. + bool none() const { + if (isSmall()) + return getSmallBits() == 0; + return X.getPointer()->none(); + } + + /// find_first - Returns the index of the first set bit, -1 if none + /// of the bits are set. + int find_first() const { + if (isSmall()) { + uintptr_t Bits = getSmallBits(); + if (sizeof(uintptr_t) * CHAR_BIT == 32) + return CountTrailingZeros_32(Bits); + if (sizeof(uintptr_t) * CHAR_BIT == 64) + return CountTrailingZeros_64(Bits); + assert(0 && "Unsupported!"); + } + return X.getPointer()->find_first(); + } + + /// find_next - Returns the index of the next set bit following the + /// "Prev" bit. Returns -1 if the next set bit is not found. + int find_next(unsigned Prev) const { + if (isSmall()) { + uintptr_t Bits = getSmallBits(); + // Mask off previous bits. + Bits &= ~uintptr_t(0) << Prev; + if (sizeof(uintptr_t) * CHAR_BIT == 32) + return CountTrailingZeros_32(Bits); + if (sizeof(uintptr_t) * CHAR_BIT == 64) + return CountTrailingZeros_64(Bits); + assert(0 && "Unsupported!"); + } + return X.getPointer()->find_next(Prev); + } + + /// clear - Clear all bits. + void clear() { + if (!isSmall()) + delete X.getPointer(); + switchToSmall(0, 0); + } + + /// resize - Grow or shrink the bitvector. + void resize(unsigned N, bool t = false) { + if (!isSmall()) { + X.getPointer()->resize(N, t); + } else if (getSmallSize() >= N) { + setSmallSize(N); + setSmallBits(getSmallBits()); + } else { + BitVector *BV = new BitVector(N, t); + uintptr_t OldBits = getSmallBits(); + for (size_t i = 0, e = getSmallSize(); i != e; ++i) + (*BV)[i] = (OldBits >> i) & 1; + switchToLarge(BV); + } + } + + void reserve(unsigned N) { + if (isSmall()) { + if (N > SmallNumDataBits) { + uintptr_t OldBits = getSmallRawBits(); + size_t SmallSize = getSmallSize(); + BitVector *BV = new BitVector(SmallSize); + for (size_t i = 0; i < SmallSize; ++i) + if ((OldBits >> i) & 1) + BV->set(i); + BV->reserve(N); + switchToLarge(BV); + } + } else { + X.getPointer()->reserve(N); + } + } + + // Set, reset, flip + SmallBitVector &set() { + if (isSmall()) + setSmallBits(~uintptr_t(0)); + else + X.getPointer()->set(); + return *this; + } + + SmallBitVector &set(unsigned Idx) { + if (isSmall()) + setSmallBits(getSmallBits() | (uintptr_t(1) << Idx)); + else + X.getPointer()->set(Idx); + return *this; + } + + SmallBitVector &reset() { + if (isSmall()) + setSmallBits(0); + else + X.getPointer()->reset(); + return *this; + } + + SmallBitVector &reset(unsigned Idx) { + if (isSmall()) + setSmallBits(getSmallBits() & ~(uintptr_t(1) << Idx)); + else + X.getPointer()->reset(Idx); + return *this; + } + + SmallBitVector &flip() { + if (isSmall()) + setSmallBits(~getSmallBits()); + else + X.getPointer()->flip(); + return *this; + } + + SmallBitVector &flip(unsigned Idx) { + if (isSmall()) + setSmallBits(getSmallBits() ^ (uintptr_t(1) << Idx)); + else + X.getPointer()->flip(Idx); + return *this; + } + + // No argument flip. + SmallBitVector operator~() const { + return SmallBitVector(*this).flip(); + } + + // Indexing. + // TODO: Add an index operator which returns a "reference" (proxy class). + bool operator[](unsigned Idx) const { + assert(Idx < size() && "Out-of-bounds Bit access."); + if (isSmall()) + return ((getSmallBits() >> Idx) & 1) != 0; + return X.getPointer()->operator[](Idx); + } + + bool test(unsigned Idx) const { + return (*this)[Idx]; + } + + // Comparison operators. + bool operator==(const SmallBitVector &RHS) const { + if (size() != RHS.size()) + return false; + if (isSmall()) + return getSmallBits() == RHS.getSmallBits(); + else + return *X.getPointer() == *RHS.X.getPointer(); + } + + bool operator!=(const SmallBitVector &RHS) const { + return !(*this == RHS); + } + + // Intersection, union, disjoint union. + BitVector &operator&=(const SmallBitVector &RHS); // TODO: implement + + BitVector &operator|=(const SmallBitVector &RHS); // TODO: implement + + BitVector &operator^=(const SmallBitVector &RHS); // TODO: implement + + // Assignment operator. + const SmallBitVector &operator=(const SmallBitVector &RHS) { + if (isSmall()) { + if (RHS.isSmall()) + X = RHS.X; + else + switchToLarge(new BitVector(*RHS.X.getPointer())); + } else { + if (!RHS.isSmall()) + *X.getPointer() = *RHS.X.getPointer(); + else { + delete X.getPointer(); + X = RHS.X; + } + } + return *this; + } + + void swap(SmallBitVector &RHS) { + std::swap(X, RHS.X); + } +}; + +inline SmallBitVector +operator&(const SmallBitVector &LHS, const SmallBitVector &RHS) { + SmallBitVector Result(LHS); + Result &= RHS; + return Result; +} + +inline SmallBitVector +operator|(const SmallBitVector &LHS, const SmallBitVector &RHS) { + SmallBitVector Result(LHS); + Result |= RHS; + return Result; +} + +inline SmallBitVector +operator^(const SmallBitVector &LHS, const SmallBitVector &RHS) { + SmallBitVector Result(LHS); + Result ^= RHS; + return Result; +} + +} // End llvm namespace + +namespace std { + /// Implement std::swap in terms of BitVector swap. + inline void + swap(llvm::SmallBitVector &LHS, llvm::SmallBitVector &RHS) { + LHS.swap(RHS); + } +} + +#endif diff --git a/unittests/ADT/BitVectorTest.cpp b/unittests/ADT/BitVectorTest.cpp new file mode 100644 index 00000000000..534828192c0 --- /dev/null +++ b/unittests/ADT/BitVectorTest.cpp @@ -0,0 +1,140 @@ +//===- llvm/unittest/ADT/BitVectorTest.cpp - BitVector tests --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/BitVector.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(BitVectorTest, TrivialOperation) { + BitVector Vec; + EXPECT_EQ(0U, Vec.count()); + EXPECT_EQ(0U, Vec.size()); + EXPECT_FALSE(Vec.any()); + EXPECT_TRUE(Vec.none()); + EXPECT_TRUE(Vec.empty()); + + Vec.resize(5, true); + EXPECT_EQ(5U, Vec.count()); + EXPECT_EQ(5U, Vec.size()); + EXPECT_TRUE(Vec.any()); + EXPECT_FALSE(Vec.none()); + EXPECT_FALSE(Vec.empty()); + + Vec.resize(11); + EXPECT_EQ(5U, Vec.count()); + EXPECT_EQ(11U, Vec.size()); + EXPECT_TRUE(Vec.any()); + EXPECT_FALSE(Vec.none()); + EXPECT_FALSE(Vec.empty()); + + BitVector Inv = ~Vec; + EXPECT_EQ(6U, Inv.count()); + EXPECT_EQ(11U, Inv.size()); + EXPECT_TRUE(Inv.any()); + EXPECT_FALSE(Inv.none()); + EXPECT_FALSE(Inv.empty()); + + EXPECT_FALSE(Inv == Vec); + EXPECT_TRUE(Inv != Vec); + Vec = ~Vec; + EXPECT_TRUE(Inv == Vec); + EXPECT_FALSE(Inv != Vec); + + // Add some "interesting" data to Vec. + Vec.resize(23, true); + Vec.resize(25, false); + Vec.resize(26, true); + Vec.resize(29, false); + Vec.resize(33, true); + Vec.resize(61, false); + unsigned Count = 0; + for (unsigned i = Vec.find_first(); i != -1u; i = Vec.find_next(i)) { + ++Count; + EXPECT_TRUE(Vec[i]); + EXPECT_TRUE(Vec.test(i)); + } + EXPECT_EQ(Count, Vec.count()); + EXPECT_EQ(Count, 23u); + EXPECT_FALSE(Vec[0]); + EXPECT_TRUE(Vec[32]); + EXPECT_FALSE(Vec[60]); + + BitVector Copy = Vec; + BitVector Alt(3, false); + Alt.resize(6, true); + std::swap(Alt, Vec); + EXPECT_TRUE(Copy == Alt); + EXPECT_TRUE(Vec.size() == 6); + EXPECT_TRUE(Vec.count() == 3); + EXPECT_TRUE(Vec.find_first() == 3); + std::swap(Copy, Vec); + + // Add some more "interesting" data. + Vec.resize(68, true); + Vec.resize(78, false); + Vec.resize(89, true); + Vec.resize(90, false); + Vec.resize(91, true); + Vec.resize(130, false); + Count = 0; + for (unsigned i = Vec.find_first(); i != -1u; i = Vec.find_next(i)) { + ++Count; + EXPECT_TRUE(Vec[i]); + EXPECT_TRUE(Vec.test(i)); + } + EXPECT_EQ(Count, Vec.count()); + EXPECT_EQ(Count, 42u); + EXPECT_FALSE(Vec[0]); + EXPECT_TRUE(Vec[32]); + EXPECT_FALSE(Vec[60]); + EXPECT_FALSE(Vec[129]); + + Vec.flip(60); + EXPECT_TRUE(Vec[60]); + EXPECT_EQ(Count + 1, Vec.count()); + Vec.flip(60); + EXPECT_FALSE(Vec[60]); + EXPECT_EQ(Count, Vec.count()); + + Vec.reset(32); + EXPECT_FALSE(Vec[32]); + EXPECT_EQ(Count - 1, Vec.count()); + Vec.set(32); + EXPECT_TRUE(Vec[32]); + EXPECT_EQ(Count, Vec.count()); + + Vec.flip(); + EXPECT_EQ(Vec.size() - Count, Vec.count()); + + Vec.reset(); + EXPECT_EQ(0U, Vec.count()); + EXPECT_EQ(130U, Vec.size()); + EXPECT_FALSE(Vec.any()); + EXPECT_TRUE(Vec.none()); + EXPECT_FALSE(Vec.empty()); + + Inv = ~BitVector(); + EXPECT_EQ(0U, Inv.count()); + EXPECT_EQ(0U, Inv.size()); + EXPECT_FALSE(Inv.any()); + EXPECT_TRUE(Inv.none()); + EXPECT_TRUE(Inv.empty()); + + Vec.clear(); + EXPECT_EQ(0U, Vec.count()); + EXPECT_EQ(0U, Vec.size()); + EXPECT_FALSE(Vec.any()); + EXPECT_TRUE(Vec.none()); + EXPECT_TRUE(Vec.empty()); +} + +} diff --git a/unittests/ADT/SmallBitVectorTest.cpp b/unittests/ADT/SmallBitVectorTest.cpp new file mode 100644 index 00000000000..a5c60dec9ba --- /dev/null +++ b/unittests/ADT/SmallBitVectorTest.cpp @@ -0,0 +1,140 @@ +//===- llvm/unittest/ADT/SmallBitVectorTest.cpp - SmallBitVector tests ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallBitVector.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(SmallBitVectorTest, TrivialOperation) { + SmallBitVector Vec; + EXPECT_EQ(0U, Vec.count()); + EXPECT_EQ(0U, Vec.size()); + EXPECT_FALSE(Vec.any()); + EXPECT_TRUE(Vec.none()); + EXPECT_TRUE(Vec.empty()); + + Vec.resize(5, true); + EXPECT_EQ(5U, Vec.count()); + EXPECT_EQ(5U, Vec.size()); + EXPECT_TRUE(Vec.any()); + EXPECT_FALSE(Vec.none()); + EXPECT_FALSE(Vec.empty()); + + Vec.resize(11); + EXPECT_EQ(5U, Vec.count()); + EXPECT_EQ(11U, Vec.size()); + EXPECT_TRUE(Vec.any()); + EXPECT_FALSE(Vec.none()); + EXPECT_FALSE(Vec.empty()); + + SmallBitVector Inv = ~Vec; + EXPECT_EQ(6U, Inv.count()); + EXPECT_EQ(11U, Inv.size()); + EXPECT_TRUE(Inv.any()); + EXPECT_FALSE(Inv.none()); + EXPECT_FALSE(Inv.empty()); + + EXPECT_FALSE(Inv == Vec); + EXPECT_TRUE(Inv != Vec); + Vec = ~Vec; + EXPECT_TRUE(Inv == Vec); + EXPECT_FALSE(Inv != Vec); + + // Add some "interesting" data to Vec. + Vec.resize(23, true); + Vec.resize(25, false); + Vec.resize(26, true); + Vec.resize(29, false); + Vec.resize(33, true); + Vec.resize(61, false); + unsigned Count = 0; + for (unsigned i = Vec.find_first(); i != -1u; i = Vec.find_next(i)) { + ++Count; + EXPECT_TRUE(Vec[i]); + EXPECT_TRUE(Vec.test(i)); + } + EXPECT_EQ(Count, Vec.count()); + EXPECT_EQ(Count, 23u); + EXPECT_FALSE(Vec[0]); + EXPECT_TRUE(Vec[32]); + EXPECT_FALSE(Vec[60]); + + SmallBitVector Copy = Vec; + SmallBitVector Alt(3, false); + Alt.resize(6, true); + std::swap(Alt, Vec); + EXPECT_TRUE(Copy == Alt); + EXPECT_TRUE(Vec.size() == 6); + EXPECT_TRUE(Vec.count() == 3); + EXPECT_TRUE(Vec.find_first() == 3); + std::swap(Copy, Vec); + + // Add some more "interesting" data. + Vec.resize(68, true); + Vec.resize(78, false); + Vec.resize(89, true); + Vec.resize(90, false); + Vec.resize(91, true); + Vec.resize(130, false); + Count = 0; + for (unsigned i = Vec.find_first(); i != -1u; i = Vec.find_next(i)) { + ++Count; + EXPECT_TRUE(Vec[i]); + EXPECT_TRUE(Vec.test(i)); + } + EXPECT_EQ(Count, Vec.count()); + EXPECT_EQ(Count, 42u); + EXPECT_FALSE(Vec[0]); + EXPECT_TRUE(Vec[32]); + EXPECT_FALSE(Vec[60]); + EXPECT_FALSE(Vec[129]); + + Vec.flip(60); + EXPECT_TRUE(Vec[60]); + EXPECT_EQ(Count + 1, Vec.count()); + Vec.flip(60); + EXPECT_FALSE(Vec[60]); + EXPECT_EQ(Count, Vec.count()); + + Vec.reset(32); + EXPECT_FALSE(Vec[32]); + EXPECT_EQ(Count - 1, Vec.count()); + Vec.set(32); + EXPECT_TRUE(Vec[32]); + EXPECT_EQ(Count, Vec.count()); + + Vec.flip(); + EXPECT_EQ(Vec.size() - Count, Vec.count()); + + Vec.reset(); + EXPECT_EQ(0U, Vec.count()); + EXPECT_EQ(130U, Vec.size()); + EXPECT_FALSE(Vec.any()); + EXPECT_TRUE(Vec.none()); + EXPECT_FALSE(Vec.empty()); + + Inv = ~SmallBitVector(); + EXPECT_EQ(0U, Inv.count()); + EXPECT_EQ(0U, Inv.size()); + EXPECT_FALSE(Inv.any()); + EXPECT_TRUE(Inv.none()); + EXPECT_TRUE(Inv.empty()); + + Vec.clear(); + EXPECT_EQ(0U, Vec.count()); + EXPECT_EQ(0U, Vec.size()); + EXPECT_FALSE(Vec.any()); + EXPECT_TRUE(Vec.none()); + EXPECT_TRUE(Vec.empty()); +} + +}