diff options
author | Jordan Rose <jordan_rose@apple.com> | 2014-03-07 19:19:56 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2014-03-07 19:19:56 +0000 |
commit | bc3b24269eabf6e9e54598c82ede3c741d8a6e61 (patch) | |
tree | 05263dec97561e85f08186e318bd8b84b517f290 | |
parent | fac248734708670e898b814f88f5f262da774de3 (diff) | |
download | llvm-bc3b24269eabf6e9e54598c82ede3c741d8a6e61.tar.gz llvm-bc3b24269eabf6e9e54598c82ede3c741d8a6e61.tar.bz2 llvm-bc3b24269eabf6e9e54598c82ede3c741d8a6e61.tar.xz |
[ADT] Update PointerIntPair to handle pointer types with more than 31 bits free.
Previously, the assertions in PointerIntPair would try to calculate the value
(1 << NumLowBitsAvailable); the inferred type here is 'int', so if there were
more than 31 bits available we'd get a shift overflow.
Also, add a rudimentary unit test file for PointerIntPair.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@203273 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/ADT/PointerIntPair.h | 14 | ||||
-rw-r--r-- | unittests/ADT/CMakeLists.txt | 1 | ||||
-rw-r--r-- | unittests/ADT/PointerIntPairTest.cpp | 74 |
3 files changed, 84 insertions, 5 deletions
diff --git a/include/llvm/ADT/PointerIntPair.h b/include/llvm/ADT/PointerIntPair.h index a5a684744b..313abf3a14 100644 --- a/include/llvm/ADT/PointerIntPair.h +++ b/include/llvm/ADT/PointerIntPair.h @@ -17,6 +17,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include <cassert> +#include <limits> namespace llvm { @@ -41,6 +42,9 @@ template <typename PointerTy, unsigned IntBits, typename IntType=unsigned, typename PtrTraits = PointerLikeTypeTraits<PointerTy> > class PointerIntPair { intptr_t Value; + static_assert(PtrTraits::NumLowBitsAvailable < + std::numeric_limits<uintptr_t>::digits, + "cannot use a pointer type that has all bits free"); enum : uintptr_t { /// PointerBitMask - The bits that come from the pointer. PointerBitMask = @@ -79,7 +83,7 @@ public: void setPointer(PointerTy PtrVal) { intptr_t PtrWord = reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal)); - assert((PtrWord & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 && + assert((PtrWord & ~PointerBitMask) == 0 && "Pointer is not sufficiently aligned"); // Preserve all low bits, just update the pointer. Value = PtrWord | (Value & ~PointerBitMask); @@ -87,7 +91,7 @@ public: void setInt(IntType IntVal) { intptr_t IntWord = static_cast<intptr_t>(IntVal); - assert(IntWord < (1 << IntBits) && "Integer too large for field"); + assert((IntWord & ~IntMask) == 0 && "Integer too large for field"); // Preserve all bits other than the ones we are updating. Value &= ~ShiftedIntMask; // Remove integer field. @@ -97,7 +101,7 @@ public: void initWithPointer(PointerTy PtrVal) { intptr_t PtrWord = reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal)); - assert((PtrWord & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 && + assert((PtrWord & ~PointerBitMask) == 0 && "Pointer is not sufficiently aligned"); Value = PtrWord; } @@ -105,10 +109,10 @@ public: void setPointerAndInt(PointerTy PtrVal, IntType IntVal) { intptr_t PtrWord = reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(PtrVal)); - assert((PtrWord & ((1 << PtrTraits::NumLowBitsAvailable)-1)) == 0 && + assert((PtrWord & ~PointerBitMask) == 0 && "Pointer is not sufficiently aligned"); intptr_t IntWord = static_cast<intptr_t>(IntVal); - assert(IntWord < (1 << IntBits) && "Integer too large for field"); + assert((IntWord & ~IntMask) == 0 && "Integer too large for field"); Value = PtrWord | (IntWord << IntShift); } diff --git a/unittests/ADT/CMakeLists.txt b/unittests/ADT/CMakeLists.txt index 88e8186f33..66e2d20ef7 100644 --- a/unittests/ADT/CMakeLists.txt +++ b/unittests/ADT/CMakeLists.txt @@ -24,6 +24,7 @@ set(ADTSources OptionalTest.cpp OwningPtrTest.cpp PackedVectorTest.cpp + PointerIntPairTest.cpp PointerUnionTest.cpp SCCIteratorTest.cpp SmallPtrSetTest.cpp diff --git a/unittests/ADT/PointerIntPairTest.cpp b/unittests/ADT/PointerIntPairTest.cpp new file mode 100644 index 0000000000..3da31e7dfe --- /dev/null +++ b/unittests/ADT/PointerIntPairTest.cpp @@ -0,0 +1,74 @@ +//===- llvm/unittest/ADT/PointerIntPairTest.cpp - Unit tests --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/ADT/PointerIntPair.h" +#include <limits> +using namespace llvm; + +namespace { + +// Test fixture +class PointerIntPairTest : public testing::Test { +}; + +TEST_F(PointerIntPairTest, GetSet) { + PointerIntPair<PointerIntPairTest *, 2> Pair{this, 1U}; + EXPECT_EQ(this, Pair.getPointer()); + EXPECT_EQ(1U, Pair.getInt()); + + Pair.setInt(2); + EXPECT_EQ(this, Pair.getPointer()); + EXPECT_EQ(2U, Pair.getInt()); + + Pair.setPointer(nullptr); + EXPECT_EQ(nullptr, Pair.getPointer()); + EXPECT_EQ(2U, Pair.getInt()); + + Pair.setPointerAndInt(this, 3U); + EXPECT_EQ(this, Pair.getPointer()); + EXPECT_EQ(3U, Pair.getInt()); +} + +TEST_F(PointerIntPairTest, DefaultInitialize) { + PointerIntPair<PointerIntPairTest *, 2> Pair; + EXPECT_EQ(nullptr, Pair.getPointer()); + EXPECT_EQ(0U, Pair.getInt()); +} + +TEST_F(PointerIntPairTest, ManyUnusedBits) { + // In real code this would be a word-sized integer limited to 31 bits. + struct Fixnum31 { + uintptr_t Value; + }; + class FixnumPointerTraits { + public: + static inline void *getAsVoidPointer(Fixnum31 Num) { + return reinterpret_cast<void *>(Num.Value << NumLowBitsAvailable); + } + static inline Fixnum31 getFromVoidPointer(void *P) { + // In real code this would assert that the value is in range. + return { reinterpret_cast<uintptr_t>(P) >> NumLowBitsAvailable }; + } + enum { NumLowBitsAvailable = std::numeric_limits<uintptr_t>::digits - 31 }; + }; + + PointerIntPair<Fixnum31, 1, bool, FixnumPointerTraits> pair; + EXPECT_EQ((uintptr_t)0, pair.getPointer().Value); + EXPECT_EQ(false, pair.getInt()); + + pair.setPointerAndInt({ 0x7FFFFFFF }, true ); + EXPECT_EQ((uintptr_t)0x7FFFFFFF, pair.getPointer().Value); + EXPECT_EQ(true, pair.getInt()); + + EXPECT_EQ(FixnumPointerTraits::NumLowBitsAvailable - 1, + PointerLikeTypeTraits<decltype(pair)>::NumLowBitsAvailable); +} + +} // end anonymous namespace |