1 //===- llvm/ADT/PointerIntPair.h - Pair for pointer and int -----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file defines the PointerIntPair class. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_ADT_POINTERINTPAIR_H 15 #define LLVM_ADT_POINTERINTPAIR_H 16 17 #include "llvm/Support/Compiler.h" 18 #include "llvm/Support/PointerLikeTypeTraits.h" 19 #include "llvm/Support/type_traits.h" 20 #include <cassert> 21 #include <cstdint> 22 #include <cstring> 23 #include <limits> 24 25 namespace llvm { 26 27 namespace detail { 28 template <typename Ptr> struct PunnedPointer { 29 static_assert(sizeof(Ptr) == sizeof(intptr_t), ""); 30 31 // Asserts that allow us to let the compiler implement the destructor and 32 // copy/move constructors 33 static_assert(std::is_trivially_destructible<Ptr>::value, ""); 34 static_assert(std::is_trivially_copy_constructible<Ptr>::value, ""); 35 static_assert(std::is_trivially_move_constructible<Ptr>::value, ""); 36 37 explicit constexpr PunnedPointer(intptr_t i = 0) { *this = i; } 38 asIntPunnedPointer39 constexpr intptr_t asInt() const { 40 intptr_t R = 0; 41 std::memcpy(&R, Data, sizeof(R)); 42 return R; 43 } 44 intptr_tPunnedPointer45 constexpr operator intptr_t() const { return asInt(); } 46 47 constexpr PunnedPointer &operator=(intptr_t V) { 48 std::memcpy(Data, &V, sizeof(Data)); 49 return *this; 50 } 51 getPointerAddressPunnedPointer52 Ptr *getPointerAddress() { return reinterpret_cast<Ptr *>(Data); } getPointerAddressPunnedPointer53 const Ptr *getPointerAddress() const { return reinterpret_cast<Ptr *>(Data); } 54 55 private: 56 alignas(Ptr) unsigned char Data[sizeof(Ptr)]; 57 }; 58 } // namespace detail 59 60 template <typename T, typename Enable> struct DenseMapInfo; 61 template <typename PointerT, unsigned IntBits, typename PtrTraits> 62 struct PointerIntPairInfo; 63 64 /// PointerIntPair - This class implements a pair of a pointer and small 65 /// integer. It is designed to represent this in the space required by one 66 /// pointer by bitmangling the integer into the low part of the pointer. This 67 /// can only be done for small integers: typically up to 3 bits, but it depends 68 /// on the number of bits available according to PointerLikeTypeTraits for the 69 /// type. 70 /// 71 /// Note that PointerIntPair always puts the IntVal part in the highest bits 72 /// possible. For example, PointerIntPair<void*, 1, bool> will put the bit for 73 /// the bool into bit #2, not bit #0, which allows the low two bits to be used 74 /// for something else. For example, this allows: 75 /// PointerIntPair<PointerIntPair<void*, 1, bool>, 1, bool> 76 /// ... and the two bools will land in different bits. 77 template <typename PointerTy, unsigned IntBits, typename IntType = unsigned, 78 typename PtrTraits = PointerLikeTypeTraits<PointerTy>, 79 typename Info = PointerIntPairInfo<PointerTy, IntBits, PtrTraits>> 80 class PointerIntPair { 81 // Used by MSVC visualizer and generally helpful for debugging/visualizing. 82 using InfoTy = Info; 83 detail::PunnedPointer<PointerTy> Value; 84 85 public: 86 constexpr PointerIntPair() = default; 87 PointerIntPair(PointerTy PtrVal,IntType IntVal)88 PointerIntPair(PointerTy PtrVal, IntType IntVal) { 89 setPointerAndInt(PtrVal, IntVal); 90 } 91 PointerIntPair(PointerTy PtrVal)92 explicit PointerIntPair(PointerTy PtrVal) { initWithPointer(PtrVal); } 93 getPointer()94 PointerTy getPointer() const { return Info::getPointer(Value); } 95 getInt()96 IntType getInt() const { return (IntType)Info::getInt(Value); } 97 setPointer(PointerTy PtrVal)98 void setPointer(PointerTy PtrVal) & { 99 Value = Info::updatePointer(Value, PtrVal); 100 } 101 setInt(IntType IntVal)102 void setInt(IntType IntVal) & { 103 Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal)); 104 } 105 initWithPointer(PointerTy PtrVal)106 void initWithPointer(PointerTy PtrVal) & { 107 Value = Info::updatePointer(0, PtrVal); 108 } 109 setPointerAndInt(PointerTy PtrVal,IntType IntVal)110 void setPointerAndInt(PointerTy PtrVal, IntType IntVal) & { 111 Value = Info::updateInt(Info::updatePointer(0, PtrVal), 112 static_cast<intptr_t>(IntVal)); 113 } 114 getAddrOfPointer()115 PointerTy const *getAddrOfPointer() const { 116 return const_cast<PointerIntPair *>(this)->getAddrOfPointer(); 117 } 118 getAddrOfPointer()119 PointerTy *getAddrOfPointer() { 120 assert(Value == reinterpret_cast<intptr_t>(getPointer()) && 121 "Can only return the address if IntBits is cleared and " 122 "PtrTraits doesn't change the pointer"); 123 return Value.getPointerAddress(); 124 } 125 getOpaqueValue()126 void *getOpaqueValue() const { 127 return reinterpret_cast<void *>(Value.asInt()); 128 } 129 setFromOpaqueValue(void * Val)130 void setFromOpaqueValue(void *Val) & { 131 Value = reinterpret_cast<intptr_t>(Val); 132 } 133 getFromOpaqueValue(void * V)134 static PointerIntPair getFromOpaqueValue(void *V) { 135 PointerIntPair P; 136 P.setFromOpaqueValue(V); 137 return P; 138 } 139 140 // Allow PointerIntPairs to be created from const void * if and only if the 141 // pointer type could be created from a const void *. getFromOpaqueValue(const void * V)142 static PointerIntPair getFromOpaqueValue(const void *V) { 143 (void)PtrTraits::getFromVoidPointer(V); 144 return getFromOpaqueValue(const_cast<void *>(V)); 145 } 146 147 bool operator==(const PointerIntPair &RHS) const { 148 return Value == RHS.Value; 149 } 150 151 bool operator!=(const PointerIntPair &RHS) const { 152 return Value != RHS.Value; 153 } 154 155 bool operator<(const PointerIntPair &RHS) const { return Value < RHS.Value; } 156 bool operator>(const PointerIntPair &RHS) const { return Value > RHS.Value; } 157 158 bool operator<=(const PointerIntPair &RHS) const { 159 return Value <= RHS.Value; 160 } 161 162 bool operator>=(const PointerIntPair &RHS) const { 163 return Value >= RHS.Value; 164 } 165 }; 166 167 template <typename PointerT, unsigned IntBits, typename PtrTraits> 168 struct PointerIntPairInfo { 169 static_assert(PtrTraits::NumLowBitsAvailable < 170 std::numeric_limits<uintptr_t>::digits, 171 "cannot use a pointer type that has all bits free"); 172 static_assert(IntBits <= PtrTraits::NumLowBitsAvailable, 173 "PointerIntPair with integer size too large for pointer"); 174 enum MaskAndShiftConstants : uintptr_t { 175 /// PointerBitMask - The bits that come from the pointer. 176 PointerBitMask = 177 ~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable) - 1), 178 179 /// IntShift - The number of low bits that we reserve for other uses, and 180 /// keep zero. 181 IntShift = (uintptr_t)PtrTraits::NumLowBitsAvailable - IntBits, 182 183 /// IntMask - This is the unshifted mask for valid bits of the int type. 184 IntMask = (uintptr_t)(((intptr_t)1 << IntBits) - 1), 185 186 // ShiftedIntMask - This is the bits for the integer shifted in place. 187 ShiftedIntMask = (uintptr_t)(IntMask << IntShift) 188 }; 189 getPointerPointerIntPairInfo190 static PointerT getPointer(intptr_t Value) { 191 return PtrTraits::getFromVoidPointer( 192 reinterpret_cast<void *>(Value & PointerBitMask)); 193 } 194 getIntPointerIntPairInfo195 static intptr_t getInt(intptr_t Value) { 196 return (Value >> IntShift) & IntMask; 197 } 198 updatePointerPointerIntPairInfo199 static intptr_t updatePointer(intptr_t OrigValue, PointerT Ptr) { 200 intptr_t PtrWord = 201 reinterpret_cast<intptr_t>(PtrTraits::getAsVoidPointer(Ptr)); 202 assert((PtrWord & ~PointerBitMask) == 0 && 203 "Pointer is not sufficiently aligned"); 204 // Preserve all low bits, just update the pointer. 205 return PtrWord | (OrigValue & ~PointerBitMask); 206 } 207 updateIntPointerIntPairInfo208 static intptr_t updateInt(intptr_t OrigValue, intptr_t Int) { 209 assert((Int & ~IntMask) == 0 && "Integer too large for field"); 210 211 // Preserve all bits other than the ones we are updating. 212 return (OrigValue & ~ShiftedIntMask) | Int << IntShift; 213 } 214 }; 215 216 // Provide specialization of DenseMapInfo for PointerIntPair. 217 template <typename PointerTy, unsigned IntBits, typename IntType> 218 struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType>, void> { 219 using Ty = PointerIntPair<PointerTy, IntBits, IntType>; 220 221 static Ty getEmptyKey() { 222 uintptr_t Val = static_cast<uintptr_t>(-1); 223 Val <<= PointerLikeTypeTraits<Ty>::NumLowBitsAvailable; 224 return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val)); 225 } 226 227 static Ty getTombstoneKey() { 228 uintptr_t Val = static_cast<uintptr_t>(-2); 229 Val <<= PointerLikeTypeTraits<PointerTy>::NumLowBitsAvailable; 230 return Ty::getFromOpaqueValue(reinterpret_cast<void *>(Val)); 231 } 232 233 static unsigned getHashValue(Ty V) { 234 uintptr_t IV = reinterpret_cast<uintptr_t>(V.getOpaqueValue()); 235 return unsigned(IV) ^ unsigned(IV >> 9); 236 } 237 238 static bool isEqual(const Ty &LHS, const Ty &RHS) { return LHS == RHS; } 239 }; 240 241 // Teach SmallPtrSet that PointerIntPair is "basically a pointer". 242 template <typename PointerTy, unsigned IntBits, typename IntType, 243 typename PtrTraits> 244 struct PointerLikeTypeTraits< 245 PointerIntPair<PointerTy, IntBits, IntType, PtrTraits>> { 246 static inline void * 247 getAsVoidPointer(const PointerIntPair<PointerTy, IntBits, IntType> &P) { 248 return P.getOpaqueValue(); 249 } 250 251 static inline PointerIntPair<PointerTy, IntBits, IntType> 252 getFromVoidPointer(void *P) { 253 return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P); 254 } 255 256 static inline PointerIntPair<PointerTy, IntBits, IntType> 257 getFromVoidPointer(const void *P) { 258 return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P); 259 } 260 261 static constexpr int NumLowBitsAvailable = 262 PtrTraits::NumLowBitsAvailable - IntBits; 263 }; 264 265 // Allow structured bindings on PointerIntPair. 266 template <std::size_t I, typename PointerTy, unsigned IntBits, typename IntType, 267 typename PtrTraits, typename Info> 268 decltype(auto) 269 get(const PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info> &Pair) { 270 static_assert(I < 2); 271 if constexpr (I == 0) 272 return Pair.getPointer(); 273 else 274 return Pair.getInt(); 275 } 276 277 } // end namespace llvm 278 279 namespace std { 280 template <typename PointerTy, unsigned IntBits, typename IntType, 281 typename PtrTraits, typename Info> 282 struct tuple_size< 283 llvm::PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>> 284 : std::integral_constant<std::size_t, 2> {}; 285 286 template <std::size_t I, typename PointerTy, unsigned IntBits, typename IntType, 287 typename PtrTraits, typename Info> 288 struct tuple_element< 289 I, llvm::PointerIntPair<PointerTy, IntBits, IntType, PtrTraits, Info>> 290 : std::conditional<I == 0, PointerTy, IntType> {}; 291 } // namespace std 292 293 #endif // LLVM_ADT_POINTERINTPAIR_H 294