Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #ifndef ASMJIT_CORE_TYPE_H_INCLUDED
8 : #define ASMJIT_CORE_TYPE_H_INCLUDED
9 :
10 : #include "globals.h"
11 : #include "support.h"
12 :
13 : ASMJIT_BEGIN_NAMESPACE
14 :
15 : //! \addtogroup asmjit_core
16 : //! \{
17 :
18 : //! Type identifier provides a minimalist type system used across AsmJit library.
19 : //!
20 : //! This is an additional information that can be used to describe a value-type of physical or virtual register. It's
21 : //! used mostly by BaseCompiler to describe register representation (the group of data stored in the register and the
22 : //! width used) and it's also used by APIs that allow to describe and work with function signatures.
23 : enum class TypeId : uint8_t {
24 : //! Void type.
25 : kVoid = 0,
26 :
27 : _kBaseStart = 32,
28 : _kBaseEnd = 44,
29 :
30 : _kIntStart = 32,
31 : _kIntEnd = 41,
32 :
33 : //! Abstract signed integer type that has a native size.
34 : kIntPtr = 32,
35 : //! Abstract unsigned integer type that has a native size.
36 : kUIntPtr = 33,
37 :
38 : //! 8-bit signed integer type.
39 : kInt8 = 34,
40 : //! 8-bit unsigned integer type.
41 : kUInt8 = 35,
42 : //! 16-bit signed integer type.
43 : kInt16 = 36,
44 : //! 16-bit unsigned integer type.
45 : kUInt16 = 37,
46 : //! 32-bit signed integer type.
47 : kInt32 = 38,
48 : //! 32-bit unsigned integer type.
49 : kUInt32 = 39,
50 : //! 64-bit signed integer type.
51 : kInt64 = 40,
52 : //! 64-bit unsigned integer type.
53 : kUInt64 = 41,
54 :
55 : _kFloatStart = 42,
56 : _kFloatEnd = 44,
57 :
58 : //! 32-bit floating point type.
59 : kFloat32 = 42,
60 : //! 64-bit floating point type.
61 : kFloat64 = 43,
62 : //! 80-bit floating point type.
63 : kFloat80 = 44,
64 :
65 : _kMaskStart = 45,
66 : _kMaskEnd = 48,
67 :
68 : //! 8-bit opmask register (K).
69 : kMask8 = 45,
70 : //! 16-bit opmask register (K).
71 : kMask16 = 46,
72 : //! 32-bit opmask register (K).
73 : kMask32 = 47,
74 : //! 64-bit opmask register (K).
75 : kMask64 = 48,
76 :
77 : _kMmxStart = 49,
78 : _kMmxEnd = 50,
79 :
80 : //! 64-bit MMX register only used for 32 bits.
81 : kMmx32 = 49,
82 : //! 64-bit MMX register.
83 : kMmx64 = 50,
84 :
85 : _kVec32Start = 51,
86 : _kVec32End = 60,
87 :
88 : kInt8x4 = 51,
89 : kUInt8x4 = 52,
90 : kInt16x2 = 53,
91 : kUInt16x2 = 54,
92 : kInt32x1 = 55,
93 : kUInt32x1 = 56,
94 : kFloat32x1 = 59,
95 :
96 : _kVec64Start = 61,
97 : _kVec64End = 70,
98 :
99 : kInt8x8 = 61,
100 : kUInt8x8 = 62,
101 : kInt16x4 = 63,
102 : kUInt16x4 = 64,
103 : kInt32x2 = 65,
104 : kUInt32x2 = 66,
105 : kInt64x1 = 67,
106 : kUInt64x1 = 68,
107 : kFloat32x2 = 69,
108 : kFloat64x1 = 70,
109 :
110 : _kVec128Start = 71,
111 : _kVec128End = 80,
112 :
113 : kInt8x16 = 71,
114 : kUInt8x16 = 72,
115 : kInt16x8 = 73,
116 : kUInt16x8 = 74,
117 : kInt32x4 = 75,
118 : kUInt32x4 = 76,
119 : kInt64x2 = 77,
120 : kUInt64x2 = 78,
121 : kFloat32x4 = 79,
122 : kFloat64x2 = 80,
123 :
124 : _kVec256Start = 81,
125 : _kVec256End = 90,
126 :
127 : kInt8x32 = 81,
128 : kUInt8x32 = 82,
129 : kInt16x16 = 83,
130 : kUInt16x16 = 84,
131 : kInt32x8 = 85,
132 : kUInt32x8 = 86,
133 : kInt64x4 = 87,
134 : kUInt64x4 = 88,
135 : kFloat32x8 = 89,
136 : kFloat64x4 = 90,
137 :
138 : _kVec512Start = 91,
139 : _kVec512End = 100,
140 :
141 : kInt8x64 = 91,
142 : kUInt8x64 = 92,
143 : kInt16x32 = 93,
144 : kUInt16x32 = 94,
145 : kInt32x16 = 95,
146 : kUInt32x16 = 96,
147 : kInt64x8 = 97,
148 : kUInt64x8 = 98,
149 : kFloat32x16 = 99,
150 : kFloat64x8 = 100,
151 :
152 : kLastAssigned = kFloat64x8,
153 :
154 : kMaxValue = 255
155 : };
156 : ASMJIT_DEFINE_ENUM_COMPARE(TypeId)
157 :
158 : //! Type identifier utilities.
159 : namespace TypeUtils {
160 :
161 : struct TypeData {
162 : TypeId scalarOf[uint32_t(TypeId::kMaxValue) + 1];
163 : uint8_t sizeOf[uint32_t(TypeId::kMaxValue) + 1];
164 : };
165 : ASMJIT_VARAPI const TypeData _typeData;
166 :
167 : //! Returns the scalar type of `typeId`.
168 50201 : static inline TypeId scalarOf(TypeId typeId) noexcept { return _typeData.scalarOf[uint32_t(typeId)]; }
169 :
170 : //! Returns the size [in bytes] of `typeId`.
171 547554 : static inline uint32_t sizeOf(TypeId typeId) noexcept { return _typeData.sizeOf[uint32_t(typeId)]; }
172 :
173 : //! Tests whether a given type `typeId` is between `a` and `b`.
174 : static inline constexpr bool isBetween(TypeId typeId, TypeId a, TypeId b) noexcept {
175 714518 : return Support::isBetween(uint32_t(typeId), uint32_t(a), uint32_t(b));
176 : }
177 :
178 : //! Tests whether a given type `typeId` is \ref TypeId::kVoid.
179 : static inline constexpr bool isVoid(TypeId typeId) noexcept { return typeId == TypeId::kVoid; }
180 : //! Tests whether a given type `typeId` is a valid non-void type.
181 273777 : static inline constexpr bool isValid(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kIntStart, TypeId::_kVec512End); }
182 : //! Tests whether a given type `typeId` is scalar (has no vector part).
183 : static inline constexpr bool isScalar(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kBaseStart, TypeId::_kBaseEnd); }
184 : //! Tests whether a given type `typeId` is abstract, which means that its size depends on register size.
185 273777 : static inline constexpr bool isAbstract(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kIntPtr, TypeId::kUIntPtr); }
186 :
187 : //! Tests whether a given type is a scalar integer (signed or unsigned) of any size.
188 9873 : static inline constexpr bool isInt(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kIntStart, TypeId::_kIntEnd); }
189 : //! Tests whether a given type is a scalar 8-bit integer (signed).
190 : static inline constexpr bool isInt8(TypeId typeId) noexcept { return typeId == TypeId::kInt8; }
191 : //! Tests whether a given type is a scalar 8-bit integer (unsigned).
192 : static inline constexpr bool isUInt8(TypeId typeId) noexcept { return typeId == TypeId::kUInt8; }
193 : //! Tests whether a given type is a scalar 16-bit integer (signed).
194 : static inline constexpr bool isInt16(TypeId typeId) noexcept { return typeId == TypeId::kInt16; }
195 : //! Tests whether a given type is a scalar 16-bit integer (unsigned).
196 : static inline constexpr bool isUInt16(TypeId typeId) noexcept { return typeId == TypeId::kUInt16; }
197 : //! Tests whether a given type is a scalar 32-bit integer (signed).
198 : static inline constexpr bool isInt32(TypeId typeId) noexcept { return typeId == TypeId::kInt32; }
199 : //! Tests whether a given type is a scalar 32-bit integer (unsigned).
200 : static inline constexpr bool isUInt32(TypeId typeId) noexcept { return typeId == TypeId::kUInt32; }
201 : //! Tests whether a given type is a scalar 64-bit integer (signed).
202 : static inline constexpr bool isInt64(TypeId typeId) noexcept { return typeId == TypeId::kInt64; }
203 : //! Tests whether a given type is a scalar 64-bit integer (unsigned).
204 : static inline constexpr bool isUInt64(TypeId typeId) noexcept { return typeId == TypeId::kUInt64; }
205 :
206 : static inline constexpr bool isGp8(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt8, TypeId::kUInt8); }
207 : static inline constexpr bool isGp16(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt16, TypeId::kUInt16); }
208 : static inline constexpr bool isGp32(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt32, TypeId::kUInt32); }
209 : static inline constexpr bool isGp64(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt64, TypeId::kUInt64); }
210 :
211 : //! Tests whether a given type is a scalar floating point of any size.
212 9685 : static inline constexpr bool isFloat(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kFloatStart, TypeId::_kFloatEnd); }
213 : //! Tests whether a given type is a scalar 32-bit float.
214 : static inline constexpr bool isFloat32(TypeId typeId) noexcept { return typeId == TypeId::kFloat32; }
215 : //! Tests whether a given type is a scalar 64-bit float.
216 : static inline constexpr bool isFloat64(TypeId typeId) noexcept { return typeId == TypeId::kFloat64; }
217 : //! Tests whether a given type is a scalar 80-bit float.
218 : static inline constexpr bool isFloat80(TypeId typeId) noexcept { return typeId == TypeId::kFloat80; }
219 :
220 0 : static inline constexpr bool isMask(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kMaskStart, TypeId::_kMaskEnd); }
221 : static inline constexpr bool isMask8(TypeId typeId) noexcept { return typeId == TypeId::kMask8; }
222 : static inline constexpr bool isMask16(TypeId typeId) noexcept { return typeId == TypeId::kMask16; }
223 : static inline constexpr bool isMask32(TypeId typeId) noexcept { return typeId == TypeId::kMask32; }
224 : static inline constexpr bool isMask64(TypeId typeId) noexcept { return typeId == TypeId::kMask64; }
225 :
226 0 : static inline constexpr bool isMmx(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kMmxStart, TypeId::_kMmxEnd); }
227 : static inline constexpr bool isMmx32(TypeId typeId) noexcept { return typeId == TypeId::kMmx32; }
228 : static inline constexpr bool isMmx64(TypeId typeId) noexcept { return typeId == TypeId::kMmx64; }
229 :
230 0 : static inline constexpr bool isVec(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec32Start, TypeId::_kVec512End); }
231 50201 : static inline constexpr bool isVec32(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec32Start, TypeId::_kVec32End); }
232 50201 : static inline constexpr bool isVec64(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec64Start, TypeId::_kVec64End); }
233 0 : static inline constexpr bool isVec128(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec128Start, TypeId::_kVec128End); }
234 : static inline constexpr bool isVec256(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec256Start, TypeId::_kVec256End); }
235 : static inline constexpr bool isVec512(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec512Start, TypeId::_kVec512End); }
236 :
237 : //! \cond
238 : enum TypeCategory : uint32_t {
239 : kTypeCategoryUnknown = 0,
240 : kTypeCategoryEnum = 1,
241 : kTypeCategoryIntegral = 2,
242 : kTypeCategoryFloatingPoint = 3,
243 : kTypeCategoryFunction = 4
244 : };
245 :
246 : template<typename T, TypeCategory kCategory>
247 : struct TypeIdOfT_ByCategory {}; // Fails if not specialized.
248 :
249 : template<typename T>
250 : struct TypeIdOfT_ByCategory<T, kTypeCategoryIntegral> {
251 : enum : uint32_t {
252 : kTypeId = uint32_t(
253 : (sizeof(T) == 1 && std::is_signed<T>::value) ? TypeId::kInt8 :
254 : (sizeof(T) == 1 && !std::is_signed<T>::value) ? TypeId::kUInt8 :
255 : (sizeof(T) == 2 && std::is_signed<T>::value) ? TypeId::kInt16 :
256 : (sizeof(T) == 2 && !std::is_signed<T>::value) ? TypeId::kUInt16 :
257 : (sizeof(T) == 4 && std::is_signed<T>::value) ? TypeId::kInt32 :
258 : (sizeof(T) == 4 && !std::is_signed<T>::value) ? TypeId::kUInt32 :
259 : (sizeof(T) == 8 && std::is_signed<T>::value) ? TypeId::kInt64 :
260 : (sizeof(T) == 8 && !std::is_signed<T>::value) ? TypeId::kUInt64 : TypeId::kVoid)
261 : };
262 : };
263 :
264 : template<typename T>
265 : struct TypeIdOfT_ByCategory<T, kTypeCategoryFloatingPoint> {
266 : enum : uint32_t {
267 : kTypeId = uint32_t(
268 : (sizeof(T) == 4 ) ? TypeId::kFloat32 :
269 : (sizeof(T) == 8 ) ? TypeId::kFloat64 :
270 : (sizeof(T) >= 10) ? TypeId::kFloat80 : TypeId::kVoid)
271 : };
272 : };
273 :
274 : template<typename T>
275 : struct TypeIdOfT_ByCategory<T, kTypeCategoryEnum>
276 : : public TypeIdOfT_ByCategory<typename std::underlying_type<T>::type, kTypeCategoryIntegral> {};
277 :
278 : template<typename T>
279 : struct TypeIdOfT_ByCategory<T, kTypeCategoryFunction> {
280 : enum : uint32_t {
281 : kTypeId = uint32_t(TypeId::kUIntPtr)
282 : };
283 : };
284 : //! \endcond
285 :
286 : //! TypeIdOfT<> template allows to get a TypeId from a C++ type `T`.
287 : #ifdef _DOXYGEN
288 : template<typename T>
289 : struct TypeIdOfT {
290 : //! TypeId of C++ type `T`.
291 : static constexpr TypeId kTypeId = _TypeIdDeducedAtCompileTime_;
292 : };
293 : #else
294 : template<typename T>
295 : struct TypeIdOfT
296 : : public TypeIdOfT_ByCategory<T,
297 : std::is_enum<T>::value ? kTypeCategoryEnum :
298 : std::is_integral<T>::value ? kTypeCategoryIntegral :
299 : std::is_floating_point<T>::value ? kTypeCategoryFloatingPoint :
300 : std::is_function<T>::value ? kTypeCategoryFunction : kTypeCategoryUnknown> {};
301 : #endif
302 :
303 : //! \cond
304 : template<typename T>
305 : struct TypeIdOfT<T*> {
306 : enum : uint32_t {
307 : kTypeId = uint32_t(TypeId::kUIntPtr)
308 : };
309 : };
310 :
311 : template<typename T>
312 : struct TypeIdOfT<T&> {
313 : enum : uint32_t {
314 : kTypeId = uint32_t(TypeId::kUIntPtr)
315 : };
316 : };
317 : //! \endcond
318 :
319 : //! Returns a corresponding \ref TypeId of `T` type.
320 : template<typename T>
321 : static inline constexpr TypeId typeIdOfT() noexcept { return TypeId(TypeIdOfT<T>::kTypeId); }
322 :
323 : //! Returns offset needed to convert a `kIntPtr` and `kUIntPtr` TypeId into a type that matches `registerSize`
324 : //! (general-purpose register size). If you find such TypeId it's then only about adding the offset to it.
325 : //!
326 : //! For example:
327 : //!
328 : //! ```
329 : //! uint32_t registerSize = /* 4 or 8 */;
330 : //! uint32_t deabstractDelta = TypeUtils::deabstractDeltaOfSize(registerSize);
331 : //!
332 : //! TypeId typeId = 'some type-id';
333 : //!
334 : //! // Normalize some typeId into a non-abstract typeId.
335 : //! if (TypeUtils::isAbstract(typeId)) typeId += deabstractDelta;
336 : //!
337 : //! // The same, but by using TypeUtils::deabstract() function.
338 : //! typeId = TypeUtils::deabstract(typeId, deabstractDelta);
339 : //! ```
340 : static inline constexpr uint32_t deabstractDeltaOfSize(uint32_t registerSize) noexcept {
341 : return registerSize >= 8 ? uint32_t(TypeId::kInt64) - uint32_t(TypeId::kIntPtr)
342 : : uint32_t(TypeId::kInt32) - uint32_t(TypeId::kIntPtr);
343 : }
344 :
345 : //! Deabstracts a given `typeId` into a native type by using `deabstractDelta`, which was previously
346 : //! calculated by calling \ref deabstractDeltaOfSize() with a target native register size.
347 47004 : static inline constexpr TypeId deabstract(TypeId typeId, uint32_t deabstractDelta) noexcept {
348 188 : return isAbstract(typeId) ? TypeId(uint32_t(typeId) + deabstractDelta) : typeId;
349 : }
350 :
351 : static inline constexpr TypeId scalarToVector(TypeId scalarTypeId, TypeId vecStartId) noexcept {
352 0 : return TypeId(uint32_t(vecStartId) + uint32_t(scalarTypeId) - uint32_t(TypeId::kInt8));
353 : }
354 :
355 : } // {TypeUtils}
356 :
357 : //! Provides type identifiers that can be used in templates instead of native types.
358 : namespace Type {
359 :
360 : //! bool as C++ type-name.
361 : struct Bool {};
362 : //! int8_t as C++ type-name.
363 : struct Int8 {};
364 : //! uint8_t as C++ type-name.
365 : struct UInt8 {};
366 : //! int16_t as C++ type-name.
367 : struct Int16 {};
368 : //! uint16_t as C++ type-name.
369 : struct UInt16 {};
370 : //! int32_t as C++ type-name.
371 : struct Int32 {};
372 : //! uint32_t as C++ type-name.
373 : struct UInt32 {};
374 : //! int64_t as C++ type-name.
375 : struct Int64 {};
376 : //! uint64_t as C++ type-name.
377 : struct UInt64 {};
378 : //! intptr_t as C++ type-name.
379 : struct IntPtr {};
380 : //! uintptr_t as C++ type-name.
381 : struct UIntPtr {};
382 : //! float as C++ type-name.
383 : struct Float32 {};
384 : //! double as C++ type-name.
385 : struct Float64 {};
386 :
387 : } // {Type}
388 :
389 : //! \cond
390 : #define ASMJIT_DEFINE_TYPE_ID(T, TYPE_ID) \
391 : namespace TypeUtils { \
392 : template<> \
393 : struct TypeIdOfT<T> { \
394 : enum : uint32_t { \
395 : kTypeId = uint32_t(TYPE_ID) \
396 : }; \
397 : }; \
398 : }
399 :
400 : ASMJIT_DEFINE_TYPE_ID(void , TypeId::kVoid);
401 : ASMJIT_DEFINE_TYPE_ID(Type::Bool , TypeId::kUInt8);
402 : ASMJIT_DEFINE_TYPE_ID(Type::Int8 , TypeId::kInt8);
403 : ASMJIT_DEFINE_TYPE_ID(Type::UInt8 , TypeId::kUInt8);
404 : ASMJIT_DEFINE_TYPE_ID(Type::Int16 , TypeId::kInt16);
405 : ASMJIT_DEFINE_TYPE_ID(Type::UInt16 , TypeId::kUInt16);
406 : ASMJIT_DEFINE_TYPE_ID(Type::Int32 , TypeId::kInt32);
407 : ASMJIT_DEFINE_TYPE_ID(Type::UInt32 , TypeId::kUInt32);
408 : ASMJIT_DEFINE_TYPE_ID(Type::Int64 , TypeId::kInt64);
409 : ASMJIT_DEFINE_TYPE_ID(Type::UInt64 , TypeId::kUInt64);
410 : ASMJIT_DEFINE_TYPE_ID(Type::IntPtr , TypeId::kIntPtr);
411 : ASMJIT_DEFINE_TYPE_ID(Type::UIntPtr, TypeId::kUIntPtr);
412 : ASMJIT_DEFINE_TYPE_ID(Type::Float32, TypeId::kFloat32);
413 : ASMJIT_DEFINE_TYPE_ID(Type::Float64, TypeId::kFloat64);
414 : //! \endcond
415 :
416 : //! \}
417 :
418 : ASMJIT_END_NAMESPACE
419 :
420 : #endif // ASMJIT_CORE_TYPE_H_INCLUDED
421 :
422 : #endif // __PLUMED_HAS_ASMJIT
|