LLVM 24.0.0git
PointerUnion.h
Go to the documentation of this file.
1//===- llvm/ADT/PointerUnion.h - Pointer Type Union -------------*- 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 PointerUnion class, which is a discriminated union of
11/// pointer types.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_ADT_POINTERUNION_H
16#define LLVM_ADT_POINTERUNION_H
17
20#include "llvm/ADT/STLExtras.h"
23#include <algorithm>
24#include <array>
25#include <cassert>
26#include <cstddef>
27#include <cstdint>
28#include <optional>
29
30namespace llvm {
31
33
34/// Determine the number of bits required to store values in [0, NumValues).
35/// This is ceil(log2(NumValues)).
36constexpr int bitsRequired(unsigned NumValues) {
37 return NumValues == 0 ? 0 : llvm::bit_width_constexpr(NumValues - 1);
38}
39
40template <typename... Ts> constexpr int lowBitsAvailable() {
41 return std::min(
43}
44
45/// True if all types have enough low bits for a fixed-width tag.
46template <typename... PTs> constexpr bool useFixedWidthTags() {
47 return lowBitsAvailable<PTs...>() >= bitsRequired(sizeof...(PTs));
48}
49
50/// True if types are in non-decreasing NumLowBitsAvailable order.
51// TODO: Switch to llvm::is_sorted when it becomes constexpr.
52template <typename... PTs> constexpr bool typesInNonDecreasingBitOrder() {
54 for (size_t I = 1; I < sizeof...(PTs); ++I)
55 if (Bits[I] < Bits[I - 1])
56 return false;
57 return true;
58}
59
60/// Tag descriptor for one type in the union.
61struct TagEntry {
62 uintptr_t Value; // Bit pattern stored in the low bits.
63 uintptr_t Mask; // Mask covering all tag bits for this entry.
64};
65
66/// Compute fixed-width tag table (all types have enough bits for the tag).
67/// For example, with 4 types and 3 available bits, the tag is 2 bits wide
68/// (values 0-3) and each entry has the same mask of 0x3.
69template <typename... PTs>
70constexpr std::array<TagEntry, sizeof...(PTs)> computeFixedTags() {
71 constexpr size_t N = sizeof...(PTs);
72 constexpr uintptr_t TagMask = (uintptr_t(1) << bitsRequired(N)) - 1;
73 std::array<TagEntry, N> Result = {};
74 for (size_t I = 0; I < N; ++I) {
75 Result[I].Value = uintptr_t(I);
76 Result[I].Mask = TagMask;
77 }
78 return Result;
79}
80
81/// Compute variable-width tag table, or return std::nullopt if the types
82/// don't fit. Types must be in non-decreasing NumLowBitsAvailable order.
83/// Groups types by available bits into tiers; each non-final tier reserves
84/// its highest code as an escape prefix.
85///
86/// Example with 3 tiers (2-bit, 3-bit, 5-bit types):
87/// Tier 0 (2 bits): codes 0b00, 0b01, 0b10; escape = 0b11
88/// Tier 1 (3 bits): codes 0b011, escape = 0b111
89/// Tier 2 (5 bits): codes 0b00111, 0b01111, 0b10111, 0b11111
90template <typename... PTs>
91constexpr std::optional<std::array<TagEntry, sizeof...(PTs)>>
93 constexpr size_t N = sizeof...(PTs);
94 std::array<TagEntry, N> Result = {};
96 uintptr_t EscapePrefix = 0;
97 int PrevBits = 0;
98 size_t I = 0;
99 // Walk tiers (groups of types with the same NumLowBitsAvailable). For each
100 // tier, assign tag values using the new bits introduced by this tier,
101 // prefixed by the accumulated escape codes from previous tiers. Non-final
102 // tiers reserve their highest code as an escape to the next tier.
103 while (I < N) {
104 int TierBits = Bits[I];
105 if (TierBits < PrevBits)
106 return std::nullopt;
107 int NewBits = TierBits - PrevBits;
108 size_t TierEnd = I;
109 while (TierEnd < N && Bits[TierEnd] == TierBits)
110 ++TierEnd;
111 bool IsLastTier = (TierEnd == N);
112 size_t TypesInTier = TierEnd - I;
113 size_t Capacity =
114 IsLastTier ? (size_t(1) << NewBits) : ((size_t(1) << NewBits) - 1);
115 if (TypesInTier > Capacity)
116 return std::nullopt;
117 for (size_t J = 0; J < TypesInTier; ++J) {
118 Result[I + J].Value = EscapePrefix | (uintptr_t(J) << PrevBits);
119 Result[I + J].Mask = (uintptr_t(1) << TierBits) - 1;
120 }
121 uintptr_t EscapeCode = (uintptr_t(1) << NewBits) - 1;
122 EscapePrefix |= EscapeCode << PrevBits;
123 PrevBits = TierBits;
124 I = TierEnd;
125 }
126 return Result;
127}
128
129/// CRTP base that generates non-template constructors and assignment operators
130/// for each type in the union. Non-template constructors allow implicit
131/// conversions (derived-to-base, non-const-to-const).
132template <typename Derived, int Idx, typename... Types>
134
135template <typename Derived, int Idx> class PointerUnionMembers<Derived, Idx> {
136protected:
139
140 template <typename To, typename From, typename Enable>
141 friend struct ::llvm::CastInfo;
142 template <typename> friend struct ::llvm::PointerLikeTypeTraits;
143};
144
145template <typename Derived, int Idx, typename Type, typename... Types>
146class PointerUnionMembers<Derived, Idx, Type, Types...>
147 : public PointerUnionMembers<Derived, Idx + 1, Types...> {
148 using Base = PointerUnionMembers<Derived, Idx + 1, Types...>;
149
150public:
151 using Base::Base;
153
154 PointerUnionMembers(Type V) { this->Val = Derived::encode(V); }
155
156 using Base::operator=;
157 Derived &operator=(Type V) {
158 this->Val = Derived::encode(V);
159 return static_cast<Derived &>(*this);
160 }
161};
162
163} // end namespace pointer_union_detail
164
165/// A discriminated union of two or more pointer types, with the discriminator
166/// in the low bits of the pointer.
167///
168/// This implementation is extremely efficient in space due to leveraging the
169/// low bits of the pointer, while exposing a natural and type-safe API.
170///
171/// When all types have enough alignment for a fixed-width tag,
172/// the tag is placed in the high end of the available low bits, leaving spare
173/// low bits for nesting in PointerIntPair or SmallPtrSet. When types have
174/// heterogeneous alignment, a variable-length escape-encoded tag
175/// is used; in that case, types must be listed in non-decreasing
176/// NumLowBitsAvailable order.
177///
178/// Common use patterns would be something like this:
179/// PointerUnion<int*, float*> P;
180/// P = (int*)0;
181/// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0"
182/// X = P.get<int*>(); // ok.
183/// Y = P.get<float*>(); // runtime assertion failure.
184/// Z = P.get<double*>(); // compile time failure.
185/// P = (float*)0;
186/// Y = P.get<float*>(); // ok.
187/// X = P.get<int*>(); // runtime assertion failure.
188/// PointerUnion<int*, int*> Q; // compile time failure.
189template <typename... PTs>
191 : public pointer_union_detail::PointerUnionMembers<PointerUnion<PTs...>, 0,
192 PTs...> {
193 static_assert(sizeof...(PTs) > 0, "PointerUnion must have at least one type");
194 static_assert(TypesAreDistinct<PTs...>::value,
195 "PointerUnion alternative types cannot be repeated");
196
197 using Base = typename PointerUnion::PointerUnionMembers;
198 using First = TypeAtIndex<0, PTs...>;
199
200 template <typename, int, typename...>
202 template <typename To, typename From, typename Enable> friend struct CastInfo;
203 template <typename> friend struct PointerLikeTypeTraits;
204
205 // These are constexpr functions rather than static constexpr data members
206 // so that alignof() on potentially incomplete types is not evaluated at
207 // class-definition time.
208
209 static constexpr bool useFixedWidthTags() {
211 }
212
213 static constexpr int minLowBitsAvailable() {
215 }
216
217 static constexpr int tagBits() {
218 return pointer_union_detail::bitsRequired(sizeof...(PTs));
219 }
220
221 /// When using fixed-width tags, the tag is shifted to the high end of the
222 /// available low bits so that the lowest bits remain free for nesting. With
223 /// variable-width encoding mode, the tag starts at bit 0.
224 static constexpr int tagShift() {
225 return useFixedWidthTags() ? (minLowBitsAvailable() - tagBits()) : 0;
226 }
227
228 using TagTable = std::array<pointer_union_detail::TagEntry, sizeof...(PTs)>;
229
230 /// Returns the tag lookup table for this union's encoding scheme.
231 static constexpr TagTable getTagTable() {
232 if constexpr (useFixedWidthTags()) {
234 } else {
235 static_assert(
237 "Variable-width PointerUnion types must be in non-decreasing "
238 "NumLowBitsAvailable order");
239 constexpr auto Table =
241 static_assert(Table.has_value(),
242 "Too many types for the available low bits");
243 return *Table;
244 }
245 }
246
247 // Variable-width isNull: check membership in the sparse set of tag values.
248 // A single threshold comparison does not work here because lower-tier
249 // non-null pointers can encode to values below higher-tier thresholds.
250 template <size_t... Is>
251 static constexpr bool isNullVariableImpl(uintptr_t V,
252 std::index_sequence<Is...>) {
253 constexpr TagTable Table = getTagTable();
254 static_assert(tagShift() == 0,
255 "isNullVariableImpl assumes tag starts at bit 0");
256 return ((V == Table[Is].Value) || ...);
257 }
258
259 template <typename T> static uintptr_t encode(T V) {
260 constexpr TagTable Table = getTagTable();
261 constexpr int Shift = tagShift();
262 constexpr size_t Idx = FirstIndexOfType<T, PTs...>::value;
263 static_assert(Table[0].Value == 0,
264 "First type must have tag value 0 for getAddrOfPtr1");
265 uintptr_t PtrInt = reinterpret_cast<uintptr_t>(
267 assert((PtrInt & (Table[Idx].Mask << Shift)) == 0 &&
268 "Pointer low bits collide with tag");
269 return PtrInt | (Table[Idx].Value << Shift);
270 }
271
272public:
273 PointerUnion() = default;
274 PointerUnion(std::nullptr_t) : PointerUnion() {}
275 using Base::Base;
276 using Base::operator=;
277
278 /// Assignment from nullptr clears the union, resetting to the first type.
279 const PointerUnion &operator=(std::nullptr_t) {
280 this->Val = uintptr_t(0);
281 return *this;
282 }
283
284 /// Test if the pointer held in the union is null, regardless of
285 /// which type it is.
286 bool isNull() const {
287 if constexpr (useFixedWidthTags()) {
288 return (static_cast<uintptr_t>(this->Val.asInt()) >>
289 minLowBitsAvailable()) == 0;
290 } else {
291 return isNullVariableImpl(static_cast<uintptr_t>(this->Val.asInt()),
292 std::index_sequence_for<PTs...>{});
293 }
294 }
295
296 explicit operator bool() const { return !isNull(); }
297
298 /// Returns the current pointer if it is of the specified pointer type,
299 /// otherwise returns null.
300 template <typename T> inline T dyn_cast() const {
301 return llvm::dyn_cast_if_present<T>(*this);
302 }
303
304 /// If the union is set to the first pointer type get an address pointing to
305 /// it.
306 First const *getAddrOfPtr1() const {
307 return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
308 }
309
310 /// If the union is set to the first pointer type get an address pointing to
311 /// it.
312 First *getAddrOfPtr1() {
313 static_assert(FirstIndexOfType<First, PTs...>::value == 0,
314 "First type must have tag value 0 for getAddrOfPtr1");
315 assert(isa<First>(*this) && "Val is not the first pointer");
316 // tag == 0 for first type, so asInt() is the raw pointer value.
317 assert(
319 reinterpret_cast<void *>(this->Val.asInt()) &&
320 "Can't get the address because PointerLikeTypeTraits changes the ptr");
321 return const_cast<First *>(
322 reinterpret_cast<const First *>(this->Val.getPointerAddress()));
323 }
324
325 void *getOpaqueValue() const {
326 return reinterpret_cast<void *>(this->Val.asInt());
327 }
328
329 static inline PointerUnion getFromOpaqueValue(void *VP) {
330 PointerUnion V;
331 V.Val = reinterpret_cast<intptr_t>(VP);
332 return V;
333 }
334
335 friend bool operator==(PointerUnion lhs, PointerUnion rhs) {
336 return lhs.getOpaqueValue() == rhs.getOpaqueValue();
337 }
338
339 friend bool operator!=(PointerUnion lhs, PointerUnion rhs) {
340 return lhs.getOpaqueValue() != rhs.getOpaqueValue();
341 }
342
343 friend bool operator<(PointerUnion lhs, PointerUnion rhs) {
344 return lhs.getOpaqueValue() < rhs.getOpaqueValue();
345 }
346};
347
348// Specialization of CastInfo for PointerUnion.
349template <typename To, typename... PTs>
350struct CastInfo<To, PointerUnion<PTs...>>
351 : public DefaultDoCastIfPossible<To, PointerUnion<PTs...>,
352 CastInfo<To, PointerUnion<PTs...>>> {
353 using From = PointerUnion<PTs...>;
354
355 static inline bool isPossible(From &F) {
356 constexpr std::array<pointer_union_detail::TagEntry, sizeof...(PTs)> Table =
357 From::getTagTable();
358 constexpr int Shift = From::tagShift();
359 constexpr size_t Idx = FirstIndexOfType<To, PTs...>::value;
360 auto V = reinterpret_cast<uintptr_t>(F.getOpaqueValue());
361 constexpr uintptr_t TagMask = Table[Idx].Mask << Shift;
362 constexpr uintptr_t TagValue = Table[Idx].Value << Shift;
363 return (V & TagMask) == TagValue;
364 }
365
366 static To doCast(From &F) {
367 assert(isPossible(F) && "cast to an incompatible type!");
368 constexpr std::array<pointer_union_detail::TagEntry, sizeof...(PTs)> Table =
369 From::getTagTable();
370 constexpr int Shift = From::tagShift();
371 constexpr size_t Idx = FirstIndexOfType<To, PTs...>::value;
372 constexpr uintptr_t PtrMask = ~(uintptr_t(Table[Idx].Mask) << Shift);
373 void *Ptr = reinterpret_cast<void *>(
374 reinterpret_cast<uintptr_t>(F.getOpaqueValue()) & PtrMask);
376 }
377
378 static inline To castFailed() { return To(); }
379};
380
381template <typename To, typename... PTs>
382struct CastInfo<To, const PointerUnion<PTs...>>
383 : public ConstStrippingForwardingCast<To, const PointerUnion<PTs...>,
384 CastInfo<To, PointerUnion<PTs...>>> {
385};
386
387// Teach SmallPtrSet that PointerUnion is "basically a pointer".
388// Spare low bits below the tag are available for nesting.
389// This specialization is only instantiated when used (lazy), so
390// PointerLikeTypeTraits<PTs> / alignof() are not evaluated for
391// incomplete types.
392template <typename... PTs> struct PointerLikeTypeTraits<PointerUnion<PTs...>> {
393 using Union = PointerUnion<PTs...>;
394
395 static inline void *getAsVoidPointer(const Union &P) {
396 return P.getOpaqueValue();
397 }
398
399 static inline Union getFromVoidPointer(void *P) {
401 }
402
403 // The number of bits available are the min of the pointer types minus the
404 // bits needed for the discriminator.
405 static constexpr int NumLowBitsAvailable = Union::tagShift();
406};
407
408// Teach DenseMap how to use PointerUnions as keys.
409template <typename... PTs> struct DenseMapInfo<PointerUnion<PTs...>> {
410 using Union = PointerUnion<PTs...>;
411
412 static unsigned getHashValue(const Union &UnionVal) {
413 auto Key = reinterpret_cast<uintptr_t>(UnionVal.getOpaqueValue());
415 }
416
417 static bool isEqual(const Union &LHS, const Union &RHS) {
418 return LHS == RHS;
419 }
420};
421
422} // end namespace llvm
423
424#endif // LLVM_ADT_POINTERUNION_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
This file defines DenseMapInfo traits for DenseMap.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define T
#define P(N)
This file defines the PointerIntPair class.
This file contains some templates that are useful if you are working with the STL at all.
Value * RHS
Value * LHS
A discriminated union of two or more pointer types, with the discriminator in the low bits of the poi...
PointerUnion()=default
bool isNull() const
Test if the pointer held in the union is null, regardless of which type it is.
friend bool operator==(PointerUnion lhs, PointerUnion rhs)
friend bool operator!=(PointerUnion lhs, PointerUnion rhs)
friend bool operator<(PointerUnion lhs, PointerUnion rhs)
T dyn_cast() const
Returns the current pointer if it is of the specified pointer type, otherwise returns null.
First const * getAddrOfPtr1() const
If the union is set to the first pointer type get an address pointing to it.
friend class pointer_union_detail::PointerUnionMembers
void * getOpaqueValue() const
friend struct PointerLikeTypeTraits
PointerUnion(std::nullptr_t)
const PointerUnion & operator=(std::nullptr_t)
Assignment from nullptr clears the union, resetting to the first type.
First * getAddrOfPtr1()
If the union is set to the first pointer type get an address pointing to it.
static PointerUnion getFromOpaqueValue(void *VP)
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
CRTP base that generates non-template constructors and assignment operators for each type in the unio...
constexpr int bitsRequired(unsigned NumValues)
Determine the number of bits required to store values in [0, NumValues).
constexpr bool typesInNonDecreasingBitOrder()
True if types are in non-decreasing NumLowBitsAvailable order.
constexpr std::array< TagEntry, sizeof...(PTs)> computeFixedTags()
Compute fixed-width tag table (all types have enough bits for the tag).
constexpr int lowBitsAvailable()
constexpr bool useFixedWidthTags()
True if all types have enough low bits for a fixed-width tag.
constexpr std::optional< std::array< TagEntry, sizeof...(PTs)> > computeExtendedTags()
Compute variable-width tag table, or return std::nullopt if the types don't fit.
This is an optimization pass for GlobalISel generic memory operations.
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
Definition Casting.h:732
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
std::tuple_element_t< I, std::tuple< Ts... > > TypeAtIndex
Find the type at a given index in a list of types.
Definition STLExtras.h:158
constexpr int bit_width_constexpr(T Value)
Returns the number of bits needed to represent Value if Value is nonzero.
Definition bit.h:337
#define N
This struct provides a method for customizing the way a cast is performed.
Definition Casting.h:476
static bool isPossible(const From &f)
Definition Casting.h:254
Provides a cast trait that strips const from types to make it easier to implement a const-version of ...
Definition Casting.h:388
This cast trait just provides the default implementation of doCastIfPossible to make CastInfo special...
Definition Casting.h:309
static unsigned getHashValue(const Union &UnionVal)
static bool isEqual(const Union &LHS, const Union &RHS)
An information struct used to provide DenseMap with the various necessary components for a given valu...
Find the first index where a type appears in a list of types.
Definition STLExtras.h:147
A traits type that is used to handle pointer types and things that are just wrappers for pointers as ...
Determine if all types in Ts are distinct.
Definition STLExtras.h:130
Tag descriptor for one type in the union.