clang 23.0.0git
PrimType.h
Go to the documentation of this file.
1//===--- PrimType.h - Types for the constexpr VM ----------------*- 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// Defines the VM types and helpers operating on types.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_TYPE_H
14#define LLVM_CLANG_AST_INTERP_TYPE_H
15
16#include "llvm/Support/raw_ostream.h"
17#include <climits>
18#include <cstddef>
19#include <cstdint>
20
21namespace clang {
22namespace interp {
23
24class Pointer;
25class Boolean;
26class Floating;
27class MemberPointer;
28class FixedPoint;
29template <bool Signed> class IntegralAP;
30template <bool Signed> class Char;
31template <unsigned Bits, bool Signed> class Integral;
32
33/// Enumeration of the primitive types of the VM.
51
52constexpr bool isIntegerOrBoolType(PrimType T) { return T <= PT_Bool; }
53constexpr bool isIntegerType(PrimType T) { return T <= PT_IntAPS; }
54
55inline constexpr bool isPtrType(PrimType T) {
56 return T == PT_Ptr || T == PT_MemberPtr;
57}
58
59inline constexpr bool isSignedType(PrimType T) {
60 switch (T) {
61 case PT_Sint8:
62 case PT_Sint16:
63 case PT_Sint32:
64 case PT_Sint64:
65 return true;
66 default:
67 return false;
68 }
69 return false;
70}
71
72// Like std::optional<PrimType>, but only sizeof(PrimType).
73class OptPrimType final {
74 static constexpr uint8_t None = 0xFF;
75 uint8_t V = None;
76
77public:
78 OptPrimType() = default;
79 OptPrimType(std::nullopt_t) {}
80 OptPrimType(PrimType T) : V(static_cast<unsigned>(T)) {}
81
82 explicit constexpr operator bool() const { return V != None; }
84 assert(operator bool());
85 return static_cast<PrimType>(V);
86 }
87
89 if (operator bool())
90 return static_cast<PrimType>(V);
91 return PT;
92 }
93
94 bool operator==(PrimType PT) const {
95 if (!operator bool())
96 return false;
97 return V == static_cast<unsigned>(PT);
98 }
99 bool operator==(OptPrimType OPT) const { return V == OPT.V; }
100 bool operator!=(PrimType PT) const { return !(*this == PT); }
101 bool operator!=(OptPrimType OPT) const { return V != OPT.V; }
102};
103static_assert(sizeof(OptPrimType) == sizeof(PrimType));
104
111
112inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
113 interp::CastKind CK) {
114 switch (CK) {
116 OS << "reinterpret_cast";
117 break;
119 OS << "reinterpret_like";
120 break;
122 OS << "volatile";
123 break;
125 OS << "dynamic";
126 break;
127 }
128 return OS;
129}
130
131template <typename T> constexpr bool needsAlloc() {
132 return std::is_same_v<T, IntegralAP<false>> ||
133 std::is_same_v<T, IntegralAP<true>> || std::is_same_v<T, Floating> ||
134 std::is_same_v<T, MemberPointer>;
135}
136constexpr bool needsAlloc(PrimType T) {
137 return T == PT_IntAP || T == PT_IntAPS || T == PT_Float || T == PT_MemberPtr;
138}
139
140template <typename T> constexpr bool isIntegralOrPointer() {
141 return std::is_same_v<T, Integral<16, false>> ||
142 std::is_same_v<T, Integral<16, true>> ||
143 std::is_same_v<T, Integral<32, false>> ||
144 std::is_same_v<T, Integral<32, true>> ||
145 std::is_same_v<T, Integral<64, false>> ||
146 std::is_same_v<T, Integral<64, true>>;
147}
148
149/// Mapping from primitive types to their representation.
150template <PrimType T> struct PrimConv;
151template <> struct PrimConv<PT_Sint8> {
152 using T = Char<true>;
153};
154template <> struct PrimConv<PT_Uint8> {
155 using T = Char<false>;
156};
157template <> struct PrimConv<PT_Sint16> {
159};
160template <> struct PrimConv<PT_Uint16> {
162};
163template <> struct PrimConv<PT_Sint32> {
165};
166template <> struct PrimConv<PT_Uint32> {
168};
169template <> struct PrimConv<PT_Sint64> {
171};
172template <> struct PrimConv<PT_Uint64> {
174};
175template <> struct PrimConv<PT_IntAP> {
177};
178template <> struct PrimConv<PT_IntAPS> {
180};
181template <> struct PrimConv<PT_Float> {
182 using T = Floating;
183};
184template <> struct PrimConv<PT_Bool> {
185 using T = Boolean;
186};
187template <> struct PrimConv<PT_Ptr> {
188 using T = Pointer;
189};
190template <> struct PrimConv<PT_MemberPtr> {
192};
193template <> struct PrimConv<PT_FixedPoint> {
194 using T = FixedPoint;
195};
196
197/// Returns the size of a primitive type in bytes.
198size_t primSize(PrimType Type);
199
200/// Aligns a size to the pointer alignment.
201constexpr size_t align(size_t Size) {
202 return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *);
203}
204
205constexpr bool aligned(uintptr_t Value) { return Value == align(Value); }
206static_assert(aligned(sizeof(void *)));
207
208static inline bool aligned(const void *P) {
209 return aligned(reinterpret_cast<uintptr_t>(P));
210}
211
212} // namespace interp
213} // namespace clang
214
215/// Helper macro to simplify type switches.
216/// The macro implicitly exposes a type T in the scope of the inner block.
217#define TYPE_SWITCH_CASE(Name, B) \
218 case Name: { \
219 using T = PrimConv<Name>::T; \
220 B; \
221 break; \
222 }
223#define TYPE_SWITCH(Expr, B) \
224 do { \
225 switch (Expr) { \
226 TYPE_SWITCH_CASE(PT_Sint8, B) \
227 TYPE_SWITCH_CASE(PT_Uint8, B) \
228 TYPE_SWITCH_CASE(PT_Sint16, B) \
229 TYPE_SWITCH_CASE(PT_Uint16, B) \
230 TYPE_SWITCH_CASE(PT_Sint32, B) \
231 TYPE_SWITCH_CASE(PT_Uint32, B) \
232 TYPE_SWITCH_CASE(PT_Sint64, B) \
233 TYPE_SWITCH_CASE(PT_Uint64, B) \
234 TYPE_SWITCH_CASE(PT_IntAP, B) \
235 TYPE_SWITCH_CASE(PT_IntAPS, B) \
236 TYPE_SWITCH_CASE(PT_Float, B) \
237 TYPE_SWITCH_CASE(PT_Bool, B) \
238 TYPE_SWITCH_CASE(PT_Ptr, B) \
239 TYPE_SWITCH_CASE(PT_MemberPtr, B) \
240 TYPE_SWITCH_CASE(PT_FixedPoint, B) \
241 } \
242 } while (0)
243
244#define INT_TYPE_SWITCH(Expr, B) \
245 do { \
246 switch (Expr) { \
247 TYPE_SWITCH_CASE(PT_Sint8, B) \
248 TYPE_SWITCH_CASE(PT_Uint8, B) \
249 TYPE_SWITCH_CASE(PT_Sint16, B) \
250 TYPE_SWITCH_CASE(PT_Uint16, B) \
251 TYPE_SWITCH_CASE(PT_Sint32, B) \
252 TYPE_SWITCH_CASE(PT_Uint32, B) \
253 TYPE_SWITCH_CASE(PT_Sint64, B) \
254 TYPE_SWITCH_CASE(PT_Uint64, B) \
255 TYPE_SWITCH_CASE(PT_IntAP, B) \
256 TYPE_SWITCH_CASE(PT_IntAPS, B) \
257 TYPE_SWITCH_CASE(PT_Bool, B) \
258 default: \
259 llvm_unreachable("Not an integer value"); \
260 } \
261 } while (0)
262
263#define FIXED_SIZE_INT_TYPE_SWITCH(Expr, B) \
264 do { \
265 switch (Expr) { \
266 TYPE_SWITCH_CASE(PT_Sint8, B) \
267 TYPE_SWITCH_CASE(PT_Uint8, B) \
268 TYPE_SWITCH_CASE(PT_Sint16, B) \
269 TYPE_SWITCH_CASE(PT_Uint16, B) \
270 TYPE_SWITCH_CASE(PT_Sint32, B) \
271 TYPE_SWITCH_CASE(PT_Uint32, B) \
272 TYPE_SWITCH_CASE(PT_Sint64, B) \
273 TYPE_SWITCH_CASE(PT_Uint64, B) \
274 default: \
275 llvm_unreachable("Not an integer value"); \
276 } \
277 } while (0)
278
279#define INT_TYPE_SWITCH_NO_BOOL(Expr, B) \
280 do { \
281 switch (Expr) { \
282 TYPE_SWITCH_CASE(PT_Sint8, B) \
283 TYPE_SWITCH_CASE(PT_Uint8, B) \
284 TYPE_SWITCH_CASE(PT_Sint16, B) \
285 TYPE_SWITCH_CASE(PT_Uint16, B) \
286 TYPE_SWITCH_CASE(PT_Sint32, B) \
287 TYPE_SWITCH_CASE(PT_Uint32, B) \
288 TYPE_SWITCH_CASE(PT_Sint64, B) \
289 TYPE_SWITCH_CASE(PT_Uint64, B) \
290 TYPE_SWITCH_CASE(PT_IntAP, B) \
291 TYPE_SWITCH_CASE(PT_IntAPS, B) \
292 default: \
293 llvm_unreachable("Not an integer value"); \
294 } \
295 } while (0)
296
297#define TYPE_SWITCH_ALLOC(Expr, B) \
298 do { \
299 switch (Expr) { \
300 TYPE_SWITCH_CASE(PT_Float, B) \
301 TYPE_SWITCH_CASE(PT_IntAP, B) \
302 TYPE_SWITCH_CASE(PT_IntAPS, B) \
303 TYPE_SWITCH_CASE(PT_MemberPtr, B) \
304 default:; \
305 } \
306 } while (0)
307
308#endif
The base class of the type hierarchy.
Definition TypeBase.h:1866
Wrapper around boolean types.
Definition Boolean.h:25
Wrapper around fixed point types.
Definition FixedPoint.h:23
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition Floating.h:35
If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition IntegralAP.h:36
Wrapper around numeric types.
Definition Integral.h:69
OptPrimType(std::nullopt_t)
Definition PrimType.h:79
bool operator!=(PrimType PT) const
Definition PrimType.h:100
PrimType operator*() const
Definition PrimType.h:83
bool operator==(OptPrimType OPT) const
Definition PrimType.h:99
bool operator!=(OptPrimType OPT) const
Definition PrimType.h:101
PrimType value_or(PrimType PT) const
Definition PrimType.h:88
bool operator==(PrimType PT) const
Definition PrimType.h:94
A pointer to a memory block, live or dead.
Definition Pointer.h:97
constexpr bool isSignedType(PrimType T)
Definition PrimType.h:59
constexpr bool aligned(uintptr_t Value)
Definition PrimType.h:205
constexpr bool isIntegralOrPointer()
Definition PrimType.h:140
constexpr bool isPtrType(PrimType T)
Definition PrimType.h:55
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition PrimType.h:201
constexpr bool isIntegerOrBoolType(PrimType T)
Definition PrimType.h:52
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
Definition Boolean.h:153
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:34
constexpr bool needsAlloc()
Definition PrimType.h:131
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition PrimType.cpp:24
constexpr bool isIntegerType(PrimType T)
Definition PrimType.h:53
The JSON file list parser is used to communicate input to InstallAPI.
__UINTPTR_TYPE__ uintptr_t
An unsigned integer type with the property that any valid pointer to void can be converted to this ty...
Mapping from primitive types to their representation.
Definition PrimType.h:150