llvm.org GIT mirror llvm / ca4af1a
[ADT] Add an abstraction for embedding an integer within a pointer-like type. This makes it easy and safe to use a set of flags as one elmenet of a tagged union with pointers. There is quite a bit of code that has historically done this by casting arbitrary integers to "pointers" and assuming that this was safe and reliable. It is neither, and has started to rear its head by triggering safety asserts in various abstractions like PointerLikeTypeTraits when the integers chosen are invariably poor choices for *some* platform and *some* situation. Not to mention the (hopefully unlikely) prospect of one of these integers actually getting allocated! With this, it will be straightforward to build type safe abstractions like this without being error prone. The abstraction itself is also remarkably simple thanks to the implicit conversion. This use case and pattern was also independently created by the folks working on Swift, and they're going to incrementally add any missing functionality they find. Differential Revision: http://reviews.llvm.org/D15844 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257284 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 3 years ago
3 changed file(s) with 150 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //===- llvm/ADT/PointerEmbeddedInt.h ----------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_ADT_POINTEREMBEDDEDINT_H
10 #define LLVM_ADT_POINTEREMBEDDEDINT_H
11
12 #include "llvm/ADT/DenseMapInfo.h"
13 #include "llvm/Support/PointerLikeTypeTraits.h"
14 #include
15
16 namespace llvm {
17
18 /// Utility to embed an integer into a pointer-like type. This is specifically
19 /// intended to allow embedding integers where fewer bits are required than
20 /// exist in a pointer, and the integer can participate in abstractions along
21 /// side other pointer-like types. For example it can be placed into a \c
22 /// PointerSumType or \c PointerUnion.
23 ///
24 /// Note that much like pointers, an integer value of zero has special utility
25 /// due to boolean conversions. For example, a non-null value can be tested for
26 /// in the above abstractions without testing the particular active member.
27 /// Also, the default constructed value zero initializes the integer.
28 template
29 class PointerEmbeddedInt {
30 uintptr_t Value;
31
32 static_assert(Bits < sizeof(Value) * CHAR_BIT,
33 "Cannot embed more bits than we have in a pointer!");
34
35 enum : uintptr_t {
36 // We shift as many zeros into the value as we can while preserving the
37 // number of bits desired for the integer.
38 Shift = sizeof(Value) * CHAR_BIT - Bits,
39
40 // We also want to be able to mask out the preserved bits for asserts.
41 Mask = static_cast(-1) << Bits
42 };
43
44 friend class PointerLikeTypeTraits;
45
46 explicit PointerEmbeddedInt(uintptr_t Value) : Value(Value) {}
47
48 public:
49 PointerEmbeddedInt() : Value(0) {}
50
51 PointerEmbeddedInt(IntT I) : Value(static_cast(I) << Shift) {
52 assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
53 }
54
55 PointerEmbeddedInt &operator=(IntT I) {
56 assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
57 Value = static_cast(I) << Shift;
58 }
59
60 // Note that this imilict conversion additionally allows all of the basic
61 // comparison operators to work transparently, etc.
62 operator IntT() const { return static_cast(Value >> Shift); }
63 };
64
65 // Provide pointer like traits to support use with pointer unions and sum
66 // types.
67 template
68 class PointerLikeTypeTraits> {
69 typedef PointerEmbeddedInt T;
70
71 public:
72 static inline void *getAsVoidPointer(const T &P) {
73 return reinterpret_cast(P.Value);
74 }
75 static inline T getFromVoidPointer(void *P) {
76 return T(reinterpret_cast(P));
77 }
78 static inline T getFromVoidPointer(const void *P) {
79 return T(reinterpret_cast(P));
80 }
81
82 enum { NumLowBitsAvailable = T::Shift };
83 };
84
85 // Teach DenseMap how to use PointerEmbeddedInt objects as keys if the Int type
86 // itself can be a key.
87 template
88 struct DenseMapInfo> {
89 typedef PointerEmbeddedInt T;
90
91 typedef DenseMapInfo IntInfo;
92
93 static inline T getEmptyKey() { return IntInfo::getEmptyKey(); }
94 static inline T getTombstoneKey() { return IntInfo::getTombstoneKey(); }
95 static unsigned getHashValue(const T &Arg) {
96 return IntInfo::getHashValue(Arg);
97 }
98 static bool isEqual(const T &LHS, const T &RHS) { return LHS == RHS; }
99 };
100 }
101
102 #endif
2424 MapVectorTest.cpp
2525 OptionalTest.cpp
2626 PackedVectorTest.cpp
27 PointerEmbeddedIntTest.cpp
2728 PointerIntPairTest.cpp
2829 PointerSumTypeTest.cpp
2930 PointerUnionTest.cpp
0 //===- llvm/unittest/ADT/PointerEmbeddedIntTest.cpp -----------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "gtest/gtest.h"
10 #include "llvm/ADT/PointerEmbeddedInt.h"
11 using namespace llvm;
12
13 namespace {
14
15 TEST(PointerEmbeddedIntTest, Basic) {
16 PointerEmbeddedInt I = 42, J = 43;
17
18 EXPECT_EQ(42, I);
19 EXPECT_EQ(43, I + 1);
20 EXPECT_EQ(sizeof(uintptr_t) * CHAR_BIT - CHAR_BIT,
21 PointerLikeTypeTraits::NumLowBitsAvailable);
22
23 EXPECT_FALSE(I == J);
24 EXPECT_TRUE(I != J);
25 EXPECT_TRUE(I < J);
26 EXPECT_FALSE(I > J);
27 EXPECT_TRUE(I <= J);
28 EXPECT_FALSE(I >= J);
29
30 EXPECT_FALSE(I == 43);
31 EXPECT_TRUE(I != 43);
32 EXPECT_TRUE(I < 43);
33 EXPECT_FALSE(I > 43);
34 EXPECT_TRUE(I <= 43);
35 EXPECT_FALSE(I >= 43);
36
37 EXPECT_FALSE(42 == J);
38 EXPECT_TRUE(42 != J);
39 EXPECT_TRUE(42 < J);
40 EXPECT_FALSE(42 > J);
41 EXPECT_TRUE(42 <= J);
42 EXPECT_FALSE(42 >= J);
43 }
44
45 } // end anonymous namespace