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 | |
80 | /// Mapping from primitive types to their representation. |
81 | template <PrimType T> struct PrimConv; |
82 | template <> struct PrimConv<PT_Sint8> { |
83 | using T = Integral<8, true>; |
84 | }; |
85 | template <> struct PrimConv<PT_Uint8> { |
86 | using T = Integral<8, false>; |
87 | }; |
88 | template <> struct PrimConv<PT_Sint16> { |
89 | using T = Integral<16, true>; |
90 | }; |
91 | template <> struct PrimConv<PT_Uint16> { |
92 | using T = Integral<16, false>; |
93 | }; |
94 | template <> struct PrimConv<PT_Sint32> { |
95 | using T = Integral<32, true>; |
96 | }; |
97 | template <> struct PrimConv<PT_Uint32> { |
98 | using T = Integral<32, false>; |
99 | }; |
100 | template <> struct PrimConv<PT_Sint64> { |
101 | using T = Integral<64, true>; |
102 | }; |
103 | template <> struct PrimConv<PT_Uint64> { |
104 | using T = Integral<64, false>; |
105 | }; |
106 | template <> struct PrimConv<PT_IntAP> { |
107 | using T = IntegralAP<false>; |
108 | }; |
109 | template <> struct PrimConv<PT_IntAPS> { |
110 | using T = IntegralAP<true>; |
111 | }; |
112 | template <> struct PrimConv<PT_Float> { |
113 | using T = Floating; |
114 | }; |
115 | template <> struct PrimConv<PT_Bool> { |
116 | using T = Boolean; |
117 | }; |
118 | template <> struct PrimConv<PT_Ptr> { |
119 | using T = Pointer; |
120 | }; |
121 | template <> struct PrimConv<PT_MemberPtr> { |
122 | using T = MemberPointer; |
123 | }; |
124 | template <> struct PrimConv<PT_FixedPoint> { |
125 | using T = FixedPoint; |
126 | }; |
127 | |
128 | /// Returns the size of a primitive type in bytes. |
129 | size_t primSize(PrimType Type); |
130 | |
131 | /// Aligns a size to the pointer alignment. |
132 | constexpr size_t align(size_t Size) { |
133 | return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *); |
134 | } |
135 | |
136 | constexpr bool aligned(uintptr_t Value) { return Value == align(Size: Value); } |
137 | static_assert(aligned(Value: sizeof(void *))); |
138 | |
139 | static inline bool aligned(const void *P) { |
140 | return aligned(Value: reinterpret_cast<uintptr_t>(P)); |
141 | } |
142 | |
143 | } // namespace interp |
144 | } // namespace clang |
145 | |
146 | /// Helper macro to simplify type switches. |
147 | /// The macro implicitly exposes a type T in the scope of the inner block. |
148 | #define TYPE_SWITCH_CASE(Name, B) \ |
149 | case Name: { \ |
150 | using T = PrimConv<Name>::T; \ |
151 | B; \ |
152 | break; \ |
153 | } |
154 | #define TYPE_SWITCH(Expr, B) \ |
155 | do { \ |
156 | switch (Expr) { \ |
157 | TYPE_SWITCH_CASE(PT_Sint8, B) \ |
158 | TYPE_SWITCH_CASE(PT_Uint8, B) \ |
159 | TYPE_SWITCH_CASE(PT_Sint16, B) \ |
160 | TYPE_SWITCH_CASE(PT_Uint16, B) \ |
161 | TYPE_SWITCH_CASE(PT_Sint32, B) \ |
162 | TYPE_SWITCH_CASE(PT_Uint32, B) \ |
163 | TYPE_SWITCH_CASE(PT_Sint64, B) \ |
164 | TYPE_SWITCH_CASE(PT_Uint64, B) \ |
165 | TYPE_SWITCH_CASE(PT_IntAP, B) \ |
166 | TYPE_SWITCH_CASE(PT_IntAPS, B) \ |
167 | TYPE_SWITCH_CASE(PT_Float, B) \ |
168 | TYPE_SWITCH_CASE(PT_Bool, B) \ |
169 | TYPE_SWITCH_CASE(PT_Ptr, B) \ |
170 | TYPE_SWITCH_CASE(PT_MemberPtr, B) \ |
171 | TYPE_SWITCH_CASE(PT_FixedPoint, B) \ |
172 | } \ |
173 | } while (0) |
174 | |
175 | #define INT_TYPE_SWITCH(Expr, B) \ |
176 | do { \ |
177 | switch (Expr) { \ |
178 | TYPE_SWITCH_CASE(PT_Sint8, B) \ |
179 | TYPE_SWITCH_CASE(PT_Uint8, B) \ |
180 | TYPE_SWITCH_CASE(PT_Sint16, B) \ |
181 | TYPE_SWITCH_CASE(PT_Uint16, B) \ |
182 | TYPE_SWITCH_CASE(PT_Sint32, B) \ |
183 | TYPE_SWITCH_CASE(PT_Uint32, B) \ |
184 | TYPE_SWITCH_CASE(PT_Sint64, B) \ |
185 | TYPE_SWITCH_CASE(PT_Uint64, B) \ |
186 | TYPE_SWITCH_CASE(PT_IntAP, B) \ |
187 | TYPE_SWITCH_CASE(PT_IntAPS, B) \ |
188 | TYPE_SWITCH_CASE(PT_Bool, B) \ |
189 | default: \ |
190 | llvm_unreachable("Not an integer value"); \ |
191 | } \ |
192 | } while (0) |
193 | |
194 | #define INT_TYPE_SWITCH_NO_BOOL(Expr, B) \ |
195 | do { \ |
196 | switch (Expr) { \ |
197 | TYPE_SWITCH_CASE(PT_Sint8, B) \ |
198 | TYPE_SWITCH_CASE(PT_Uint8, B) \ |
199 | TYPE_SWITCH_CASE(PT_Sint16, B) \ |
200 | TYPE_SWITCH_CASE(PT_Uint16, B) \ |
201 | TYPE_SWITCH_CASE(PT_Sint32, B) \ |
202 | TYPE_SWITCH_CASE(PT_Uint32, B) \ |
203 | TYPE_SWITCH_CASE(PT_Sint64, B) \ |
204 | TYPE_SWITCH_CASE(PT_Uint64, B) \ |
205 | TYPE_SWITCH_CASE(PT_IntAP, B) \ |
206 | TYPE_SWITCH_CASE(PT_IntAPS, B) \ |
207 | default: \ |
208 | llvm_unreachable("Not an integer value"); \ |
209 | } \ |
210 | } while (0) |
211 | |
212 | #define COMPOSITE_TYPE_SWITCH(Expr, B, D) \ |
213 | do { \ |
214 | switch (Expr) { \ |
215 | TYPE_SWITCH_CASE(PT_Ptr, B) \ |
216 | default: { \ |
217 | D; \ |
218 | break; \ |
219 | } \ |
220 | } \ |
221 | } while (0) |
222 | #endif |
223 | |