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 | |
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 | |
78 | constexpr bool isIntegralType(PrimType T) { return T <= PT_FixedPoint; } |
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 | } |
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(Size: Value); } |
144 | static_assert(aligned(Value: sizeof(void *))); |
145 | |
146 | static inline bool aligned(const void *P) { |
147 | return aligned(Value: 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 | |