LLVM 20.0.0git
PointerUnion.h
Go to the documentation of this file.
1//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- 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 <cassert>
25#include <cstddef>
26#include <cstdint>
27
28namespace llvm {
29
30namespace pointer_union_detail {
31 /// Determine the number of bits required to store integers with values < n.
32 /// This is ceil(log2(n)).
33 constexpr int bitsRequired(unsigned n) {
34 return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0;
35 }
36
37 template <typename... Ts> constexpr int lowBitsAvailable() {
38 return std::min<int>({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...});
39 }
40
41 /// Find the first type in a list of types.
42 template <typename T, typename...> struct GetFirstType {
43 using type = T;
44 };
45
46 /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
47 /// for the template arguments.
48 template <typename ...PTs> class PointerUnionUIntTraits {
49 public:
50 static inline void *getAsVoidPointer(void *P) { return P; }
51 static inline void *getFromVoidPointer(void *P) { return P; }
52 static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>();
53 };
54
55 template <typename Derived, typename ValTy, int I, typename ...Types>
57
58 template <typename Derived, typename ValTy, int I>
59 class PointerUnionMembers<Derived, ValTy, I> {
60 protected:
61 ValTy Val;
63 PointerUnionMembers(ValTy Val) : Val(Val) {}
64
65 friend struct PointerLikeTypeTraits<Derived>;
66 };
67
68 template <typename Derived, typename ValTy, int I, typename Type,
69 typename ...Types>
70 class PointerUnionMembers<Derived, ValTy, I, Type, Types...>
71 : public PointerUnionMembers<Derived, ValTy, I + 1, Types...> {
72 using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>;
73 public:
74 using Base::Base;
77 : Base(ValTy(const_cast<void *>(
78 PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
79 I)) {}
80
81 using Base::operator=;
82 Derived &operator=(Type V) {
83 this->Val = ValTy(
85 I);
86 return static_cast<Derived &>(*this);
87 };
88 };
89}
90
91// This is a forward declaration of CastInfoPointerUnionImpl
92// Refer to its definition below for further details
93template <typename... PTs> struct CastInfoPointerUnionImpl;
94/// A discriminated union of two or more pointer types, with the discriminator
95/// in the low bit of the pointer.
96///
97/// This implementation is extremely efficient in space due to leveraging the
98/// low bits of the pointer, while exposing a natural and type-safe API.
99///
100/// Common use patterns would be something like this:
101/// PointerUnion<int*, float*> P;
102/// P = (int*)0;
103/// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0"
104/// X = P.get<int*>(); // ok.
105/// Y = P.get<float*>(); // runtime assertion failure.
106/// Z = P.get<double*>(); // compile time failure.
107/// P = (float*)0;
108/// Y = P.get<float*>(); // ok.
109/// X = P.get<int*>(); // runtime assertion failure.
110/// PointerUnion<int*, int*> Q; // compile time failure.
111template <typename... PTs>
114 PointerUnion<PTs...>,
115 PointerIntPair<
116 void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int,
117 pointer_union_detail::PointerUnionUIntTraits<PTs...>>,
118 0, PTs...> {
119 static_assert(TypesAreDistinct<PTs...>::value,
120 "PointerUnion alternative types cannot be repeated");
121 // The first type is special because we want to directly cast a pointer to a
122 // default-initialized union to a pointer to the first type. But we don't
123 // want PointerUnion to be a 'template <typename First, typename ...Rest>'
124 // because it's much more convenient to have a name for the whole pack. So
125 // split off the first type here.
126 using First = TypeAtIndex<0, PTs...>;
127 using Base = typename PointerUnion::PointerUnionMembers;
128
129 /// This is needed to give the CastInfo implementation below access
130 /// to protected members.
131 /// Refer to its definition for further details.
132 friend struct CastInfoPointerUnionImpl<PTs...>;
133
134public:
135 PointerUnion() = default;
136
137 PointerUnion(std::nullptr_t) : PointerUnion() {}
138 using Base::Base;
139
140 /// Test if the pointer held in the union is null, regardless of
141 /// which type it is.
142 bool isNull() const { return !this->Val.getPointer(); }
143
144 explicit operator bool() const { return !isNull(); }
145
146 // FIXME: Replace the uses of is(), get() and dyn_cast() with
147 // isa<T>, cast<T> and the llvm::dyn_cast<T>
148
149 /// Test if the Union currently holds the type matching T.
150 template <typename T>
151 [[deprecated("Use isa instead")]]
152 inline bool is() const {
153 return isa<T>(*this);
154 }
155
156 /// Returns the value of the specified pointer type.
157 ///
158 /// If the specified pointer type is incorrect, assert.
159 template <typename T>
160 [[deprecated("Use cast instead")]]
161 inline T get() const {
162 assert(isa<T>(*this) && "Invalid accessor called");
163 return cast<T>(*this);
164 }
165
166 /// Returns the current pointer if it is of the specified pointer type,
167 /// otherwise returns null.
168 template <typename T> inline T dyn_cast() const {
169 return llvm::dyn_cast_if_present<T>(*this);
170 }
171
172 /// If the union is set to the first pointer type get an address pointing to
173 /// it.
174 First const *getAddrOfPtr1() const {
175 return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
176 }
177
178 /// If the union is set to the first pointer type get an address pointing to
179 /// it.
180 First *getAddrOfPtr1() {
181 assert(isa<First>(*this) && "Val is not the first pointer");
182 assert(
184 this->Val.getPointer() &&
185 "Can't get the address because PointerLikeTypeTraits changes the ptr");
186 return const_cast<First *>(
187 reinterpret_cast<const First *>(this->Val.getAddrOfPointer()));
188 }
189
190 /// Assignment from nullptr which just clears the union.
191 const PointerUnion &operator=(std::nullptr_t) {
192 this->Val.initWithPointer(nullptr);
193 return *this;
194 }
195
196 /// Assignment from elements of the union.
197 using Base::operator=;
198
199 void *getOpaqueValue() const { return this->Val.getOpaqueValue(); }
200 static inline PointerUnion getFromOpaqueValue(void *VP) {
201 PointerUnion V;
202 V.Val = decltype(V.Val)::getFromOpaqueValue(VP);
203 return V;
204 }
205};
206
207template <typename ...PTs>
209 return lhs.getOpaqueValue() == rhs.getOpaqueValue();
210}
211
212template <typename ...PTs>
214 return lhs.getOpaqueValue() != rhs.getOpaqueValue();
215}
216
217template <typename ...PTs>
219 return lhs.getOpaqueValue() < rhs.getOpaqueValue();
220}
221
222/// We can't (at least, at this moment with C++14) declare CastInfo
223/// as a friend of PointerUnion like this:
224/// ```
225/// template<typename To>
226/// friend struct CastInfo<To, PointerUnion<PTs...>>;
227/// ```
228/// The compiler complains 'Partial specialization cannot be declared as a
229/// friend'.
230/// So we define this struct to be a bridge between CastInfo and
231/// PointerUnion.
232template <typename... PTs> struct CastInfoPointerUnionImpl {
233 using From = PointerUnion<PTs...>;
234
235 template <typename To> static inline bool isPossible(From &F) {
236 return F.Val.getInt() == FirstIndexOfType<To, PTs...>::value;
237 }
238
239 template <typename To> static To doCast(From &F) {
240 assert(isPossible<To>(F) && "cast to an incompatible type!");
241 return PointerLikeTypeTraits<To>::getFromVoidPointer(F.Val.getPointer());
242 }
243};
244
245// Specialization of CastInfo for PointerUnion
246template <typename To, typename... PTs>
247struct CastInfo<To, PointerUnion<PTs...>>
248 : public DefaultDoCastIfPossible<To, PointerUnion<PTs...>,
249 CastInfo<To, PointerUnion<PTs...>>> {
250 using From = PointerUnion<PTs...>;
252
253 static inline bool isPossible(From &f) {
254 return Impl::template isPossible<To>(f);
255 }
256
257 static To doCast(From &f) { return Impl::template doCast<To>(f); }
258
259 static inline To castFailed() { return To(); }
260};
261
262template <typename To, typename... PTs>
263struct CastInfo<To, const PointerUnion<PTs...>>
264 : public ConstStrippingForwardingCast<To, const PointerUnion<PTs...>,
265 CastInfo<To, PointerUnion<PTs...>>> {
266};
267
268// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
269// # low bits available = min(PT1bits,PT2bits)-1.
270template <typename ...PTs>
272 static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) {
273 return P.getOpaqueValue();
274 }
275
276 static inline PointerUnion<PTs...> getFromVoidPointer(void *P) {
278 }
279
280 // The number of bits available are the min of the pointer types minus the
281 // bits needed for the discriminator.
282 static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype(
283 PointerUnion<PTs...>::Val)>::NumLowBitsAvailable;
284};
285
286// Teach DenseMap how to use PointerUnions as keys.
287template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> {
288 using Union = PointerUnion<PTs...>;
289 using FirstInfo =
290 DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>;
291
292 static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); }
293
294 static inline Union getTombstoneKey() {
295 return Union(FirstInfo::getTombstoneKey());
296 }
297
298 static unsigned getHashValue(const Union &UnionVal) {
299 intptr_t key = (intptr_t)UnionVal.getOpaqueValue();
301 }
302
303 static bool isEqual(const Union &LHS, const Union &RHS) {
304 return LHS == RHS;
305 }
306};
307
308} // end namespace llvm
309
310#endif // LLVM_ADT_POINTERUNION_H
aarch64 promote const
RelocType Type
Definition: COFFYAML.cpp:410
Given that RA is a live value
This file defines DenseMapInfo traits for DenseMap.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
#define T
#define P(N)
This file defines the PointerIntPair class.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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 bit of the poin...
Definition: PointerUnion.h:118
PointerUnion()=default
bool isNull() const
Test if the pointer held in the union is null, regardless of which type it is.
Definition: PointerUnion.h:142
T get() const
Returns the value of the specified pointer type.
Definition: PointerUnion.h:161
T dyn_cast() const
Returns the current pointer if it is of the specified pointer type, otherwise returns null.
Definition: PointerUnion.h:168
First const * getAddrOfPtr1() const
If the union is set to the first pointer type get an address pointing to it.
Definition: PointerUnion.h:174
bool is() const
Test if the Union currently holds the type matching T.
Definition: PointerUnion.h:152
void * getOpaqueValue() const
Definition: PointerUnion.h:199
PointerUnion(std::nullptr_t)
Definition: PointerUnion.h:137
const PointerUnion & operator=(std::nullptr_t)
Assignment from nullptr which just clears the union.
Definition: PointerUnion.h:191
First * getAddrOfPtr1()
If the union is set to the first pointer type get an address pointing to it.
Definition: PointerUnion.h:180
static PointerUnion getFromOpaqueValue(void *VP)
Definition: PointerUnion.h:200
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
Provide PointerLikeTypeTraits for void* that is used by PointerUnion for the template arguments.
Definition: PointerUnion.h:48
constexpr int bitsRequired(unsigned n)
Determine the number of bits required to store integers with values < n.
Definition: PointerUnion.h:33
constexpr int lowBitsAvailable()
Definition: PointerUnion.h:37
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool operator<(int64_t V1, const APSInt &V2)
Definition: APSInt.h:361
bool operator!=(uint64_t V1, const APInt &V2)
Definition: APInt.h:2082
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
std::tuple_element_t< I, std::tuple< Ts... > > TypeAtIndex
Find the type at a given index in a list of types.
Definition: STLExtras.h:179
We can't (at least, at this moment with C++14) declare CastInfo as a friend of PointerUnion like this...
Definition: PointerUnion.h:232
static bool isPossible(From &F)
Definition: PointerUnion.h:235
This struct provides a method for customizing the way a cast is performed.
Definition: Casting.h:476
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)
Definition: PointerUnion.h:298
static bool isEqual(const Union &LHS, const Union &RHS)
Definition: PointerUnion.h:303
An information struct used to provide DenseMap with the various necessary components for a given valu...
Definition: DenseMapInfo.h:52
Find the first index where a type appears in a list of types.
Definition: STLExtras.h:168
static PointerUnion< PTs... > getFromVoidPointer(void *P)
Definition: PointerUnion.h:276
static void * getAsVoidPointer(const PointerUnion< PTs... > &P)
Definition: PointerUnion.h:272
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:156
Find the first type in a list of types.
Definition: PointerUnion.h:42