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
21 namespace clang {
22 namespace interp {
23
24 class Pointer;
25 class Boolean;
26 class Floating;
27 class FunctionPointer;
28 class MemberPointer;
29 class FixedPoint;
30 template <bool Signed> class IntegralAP;
31 template <unsigned Bits, bool Signed> class Integral;
32
33 /// Enumeration of the primitive types of the VM.
34 enum PrimType : unsigned {
35 PT_Sint8 = 0,
36 PT_Uint8 = 1,
37 PT_Sint16 = 2,
38 PT_Uint16 = 3,
39 PT_Sint32 = 4,
40 PT_Uint32 = 5,
41 PT_Sint64 = 6,
42 PT_Uint64 = 7,
43 PT_IntAP = 8,
44 PT_IntAPS = 9,
45 PT_Bool = 10,
46 PT_FixedPoint = 11,
47 PT_Float = 12,
48 PT_Ptr = 13,
49 PT_MemberPtr = 14,
50 };
51
isPtrType(PrimType T)52 inline constexpr bool isPtrType(PrimType T) {
53 return T == PT_Ptr || T == PT_MemberPtr;
54 }
55
56 enum class CastKind : uint8_t {
57 Reinterpret,
58 Volatile,
59 Dynamic,
60 };
61
62 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
63 interp::CastKind CK) {
64 switch (CK) {
65 case interp::CastKind::Reinterpret:
66 OS << "reinterpret_cast";
67 break;
68 case interp::CastKind::Volatile:
69 OS << "volatile";
70 break;
71 case interp::CastKind::Dynamic:
72 OS << "dynamic";
73 break;
74 }
75 return OS;
76 }
77
isIntegralType(PrimType T)78 constexpr bool isIntegralType(PrimType T) { return T <= PT_FixedPoint; }
needsAlloc()79 template <typename T> constexpr bool needsAlloc() {
80 return std::is_same_v<T, IntegralAP<false>> ||
81 std::is_same_v<T, IntegralAP<true>> || std::is_same_v<T, Floating>;
82 }
needsAlloc(PrimType T)83 constexpr bool needsAlloc(PrimType T) {
84 return T == PT_IntAP || T == PT_IntAPS || T == PT_Float;
85 }
86
87 /// Mapping from primitive types to their representation.
88 template <PrimType T> struct PrimConv;
89 template <> struct PrimConv<PT_Sint8> {
90 using T = Integral<8, true>;
91 };
92 template <> struct PrimConv<PT_Uint8> {
93 using T = Integral<8, false>;
94 };
95 template <> struct PrimConv<PT_Sint16> {
96 using T = Integral<16, true>;
97 };
98 template <> struct PrimConv<PT_Uint16> {
99 using T = Integral<16, false>;
100 };
101 template <> struct PrimConv<PT_Sint32> {
102 using T = Integral<32, true>;
103 };
104 template <> struct PrimConv<PT_Uint32> {
105 using T = Integral<32, false>;
106 };
107 template <> struct PrimConv<PT_Sint64> {
108 using T = Integral<64, true>;
109 };
110 template <> struct PrimConv<PT_Uint64> {
111 using T = Integral<64, false>;
112 };
113 template <> struct PrimConv<PT_IntAP> {
114 using T = IntegralAP<false>;
115 };
116 template <> struct PrimConv<PT_IntAPS> {
117 using T = IntegralAP<true>;
118 };
119 template <> struct PrimConv<PT_Float> {
120 using T = Floating;
121 };
122 template <> struct PrimConv<PT_Bool> {
123 using T = Boolean;
124 };
125 template <> struct PrimConv<PT_Ptr> {
126 using T = Pointer;
127 };
128 template <> struct PrimConv<PT_MemberPtr> {
129 using T = MemberPointer;
130 };
131 template <> struct PrimConv<PT_FixedPoint> {
132 using T = FixedPoint;
133 };
134
135 /// Returns the size of a primitive type in bytes.
136 size_t primSize(PrimType Type);
137
138 /// Aligns a size to the pointer alignment.
139 constexpr size_t align(size_t Size) {
140 return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *);
141 }
142
143 constexpr bool aligned(uintptr_t Value) { return Value == align(Value); }
144 static_assert(aligned(sizeof(void *)));
145
146 static inline bool aligned(const void *P) {
147 return aligned(reinterpret_cast<uintptr_t>(P));
148 }
149
150 } // namespace interp
151 } // namespace clang
152
153 /// Helper macro to simplify type switches.
154 /// The macro implicitly exposes a type T in the scope of the inner block.
155 #define TYPE_SWITCH_CASE(Name, B) \
156 case Name: { \
157 using T = PrimConv<Name>::T; \
158 B; \
159 break; \
160 }
161 #define TYPE_SWITCH(Expr, B) \
162 do { \
163 switch (Expr) { \
164 TYPE_SWITCH_CASE(PT_Sint8, B) \
165 TYPE_SWITCH_CASE(PT_Uint8, B) \
166 TYPE_SWITCH_CASE(PT_Sint16, B) \
167 TYPE_SWITCH_CASE(PT_Uint16, B) \
168 TYPE_SWITCH_CASE(PT_Sint32, B) \
169 TYPE_SWITCH_CASE(PT_Uint32, B) \
170 TYPE_SWITCH_CASE(PT_Sint64, B) \
171 TYPE_SWITCH_CASE(PT_Uint64, B) \
172 TYPE_SWITCH_CASE(PT_IntAP, B) \
173 TYPE_SWITCH_CASE(PT_IntAPS, B) \
174 TYPE_SWITCH_CASE(PT_Float, B) \
175 TYPE_SWITCH_CASE(PT_Bool, B) \
176 TYPE_SWITCH_CASE(PT_Ptr, B) \
177 TYPE_SWITCH_CASE(PT_MemberPtr, B) \
178 TYPE_SWITCH_CASE(PT_FixedPoint, B) \
179 } \
180 } while (0)
181
182 #define INT_TYPE_SWITCH(Expr, B) \
183 do { \
184 switch (Expr) { \
185 TYPE_SWITCH_CASE(PT_Sint8, B) \
186 TYPE_SWITCH_CASE(PT_Uint8, B) \
187 TYPE_SWITCH_CASE(PT_Sint16, B) \
188 TYPE_SWITCH_CASE(PT_Uint16, B) \
189 TYPE_SWITCH_CASE(PT_Sint32, B) \
190 TYPE_SWITCH_CASE(PT_Uint32, B) \
191 TYPE_SWITCH_CASE(PT_Sint64, B) \
192 TYPE_SWITCH_CASE(PT_Uint64, B) \
193 TYPE_SWITCH_CASE(PT_IntAP, B) \
194 TYPE_SWITCH_CASE(PT_IntAPS, B) \
195 TYPE_SWITCH_CASE(PT_Bool, B) \
196 default: \
197 llvm_unreachable("Not an integer value"); \
198 } \
199 } while (0)
200
201 #define INT_TYPE_SWITCH_NO_BOOL(Expr, B) \
202 do { \
203 switch (Expr) { \
204 TYPE_SWITCH_CASE(PT_Sint8, B) \
205 TYPE_SWITCH_CASE(PT_Uint8, B) \
206 TYPE_SWITCH_CASE(PT_Sint16, B) \
207 TYPE_SWITCH_CASE(PT_Uint16, B) \
208 TYPE_SWITCH_CASE(PT_Sint32, B) \
209 TYPE_SWITCH_CASE(PT_Uint32, B) \
210 TYPE_SWITCH_CASE(PT_Sint64, B) \
211 TYPE_SWITCH_CASE(PT_Uint64, B) \
212 TYPE_SWITCH_CASE(PT_IntAP, B) \
213 TYPE_SWITCH_CASE(PT_IntAPS, B) \
214 default: \
215 llvm_unreachable("Not an integer value"); \
216 } \
217 } while (0)
218
219 #define TYPE_SWITCH_ALLOC(Expr, B) \
220 do { \
221 switch (Expr) { \
222 TYPE_SWITCH_CASE(PT_Float, B) \
223 TYPE_SWITCH_CASE(PT_IntAP, B) \
224 TYPE_SWITCH_CASE(PT_IntAPS, B) \
225 default:; \
226 } \
227 } while (0)
228
229 #define COMPOSITE_TYPE_SWITCH(Expr, B, D) \
230 do { \
231 switch (Expr) { \
232 TYPE_SWITCH_CASE(PT_Ptr, B) \
233 default: { \
234 D; \
235 break; \
236 } \
237 } \
238 } while (0)
239 #endif
240