1 // AsmJit - Machine code generation for C++
2 //
3 // * Official AsmJit Home Page: https://asmjit.com
4 // * Official Github Repository: https://github.com/asmjit/asmjit
5 //
6 // Copyright (c) 2008-2020 The AsmJit Authors
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 // claim that you wrote the original software. If you use this software
18 // in a product, an acknowledgment in the product documentation would be
19 // appreciated but is not required.
20 // 2. Altered source versions must be plainly marked as such, and must not be
21 // misrepresented as being the original software.
22 // 3. This notice may not be removed or altered from any source distribution.
23
24 #ifndef ASMJIT_CORE_TYPE_H_INCLUDED
25 #define ASMJIT_CORE_TYPE_H_INCLUDED
26
27 #include "../core/globals.h"
28
29 ASMJIT_BEGIN_NAMESPACE
30
31 //! \addtogroup asmjit_core
32 //! \{
33
34 // ============================================================================
35 // [asmjit::Type]
36 // ============================================================================
37
38 //! Provides a minimalist type-system that is used by Asmjit library.
39 namespace Type {
40
41 //! TypeId.
42 //!
43 //! This is an additional information that can be used to describe a value-type
44 //! of physical or virtual register. it's used mostly by BaseCompiler to describe
45 //! register representation (the group of data stored in the register and the
46 //! width used) and it's also used by APIs that allow to describe and work with
47 //! function signatures.
48 enum Id : uint32_t {
49 kIdVoid = 0, //!< Void type.
50
51 _kIdBaseStart = 32,
52 _kIdBaseEnd = 44,
53
54 _kIdIntStart = 32,
55 _kIdIntEnd = 41,
56
57 kIdIntPtr = 32, //!< Abstract signed integer type that has a native size.
58 kIdUIntPtr = 33, //!< Abstract unsigned integer type that has a native size.
59
60 kIdI8 = 34, //!< 8-bit signed integer type.
61 kIdU8 = 35, //!< 8-bit unsigned integer type.
62 kIdI16 = 36, //!< 16-bit signed integer type.
63 kIdU16 = 37, //!< 16-bit unsigned integer type.
64 kIdI32 = 38, //!< 32-bit signed integer type.
65 kIdU32 = 39, //!< 32-bit unsigned integer type.
66 kIdI64 = 40, //!< 64-bit signed integer type.
67 kIdU64 = 41, //!< 64-bit unsigned integer type.
68
69 _kIdFloatStart = 42,
70 _kIdFloatEnd = 44,
71
72 kIdF32 = 42, //!< 32-bit floating point type.
73 kIdF64 = 43, //!< 64-bit floating point type.
74 kIdF80 = 44, //!< 80-bit floating point type.
75
76 _kIdMaskStart = 45,
77 _kIdMaskEnd = 48,
78
79 kIdMask8 = 45, //!< 8-bit opmask register (K).
80 kIdMask16 = 46, //!< 16-bit opmask register (K).
81 kIdMask32 = 47, //!< 32-bit opmask register (K).
82 kIdMask64 = 48, //!< 64-bit opmask register (K).
83
84 _kIdMmxStart = 49,
85 _kIdMmxEnd = 50,
86
87 kIdMmx32 = 49, //!< 64-bit MMX register only used for 32 bits.
88 kIdMmx64 = 50, //!< 64-bit MMX register.
89
90 _kIdVec32Start = 51,
91 _kIdVec32End = 60,
92
93 kIdI8x4 = 51,
94 kIdU8x4 = 52,
95 kIdI16x2 = 53,
96 kIdU16x2 = 54,
97 kIdI32x1 = 55,
98 kIdU32x1 = 56,
99 kIdF32x1 = 59,
100
101 _kIdVec64Start = 61,
102 _kIdVec64End = 70,
103
104 kIdI8x8 = 61,
105 kIdU8x8 = 62,
106 kIdI16x4 = 63,
107 kIdU16x4 = 64,
108 kIdI32x2 = 65,
109 kIdU32x2 = 66,
110 kIdI64x1 = 67,
111 kIdU64x1 = 68,
112 kIdF32x2 = 69,
113 kIdF64x1 = 70,
114
115 _kIdVec128Start = 71,
116 _kIdVec128End = 80,
117
118 kIdI8x16 = 71,
119 kIdU8x16 = 72,
120 kIdI16x8 = 73,
121 kIdU16x8 = 74,
122 kIdI32x4 = 75,
123 kIdU32x4 = 76,
124 kIdI64x2 = 77,
125 kIdU64x2 = 78,
126 kIdF32x4 = 79,
127 kIdF64x2 = 80,
128
129 _kIdVec256Start = 81,
130 _kIdVec256End = 90,
131
132 kIdI8x32 = 81,
133 kIdU8x32 = 82,
134 kIdI16x16 = 83,
135 kIdU16x16 = 84,
136 kIdI32x8 = 85,
137 kIdU32x8 = 86,
138 kIdI64x4 = 87,
139 kIdU64x4 = 88,
140 kIdF32x8 = 89,
141 kIdF64x4 = 90,
142
143 _kIdVec512Start = 91,
144 _kIdVec512End = 100,
145
146 kIdI8x64 = 91,
147 kIdU8x64 = 92,
148 kIdI16x32 = 93,
149 kIdU16x32 = 94,
150 kIdI32x16 = 95,
151 kIdU32x16 = 96,
152 kIdI64x8 = 97,
153 kIdU64x8 = 98,
154 kIdF32x16 = 99,
155 kIdF64x8 = 100,
156
157 kIdCount = 101,
158 kIdMax = 255
159 };
160
161 struct TypeData {
162 uint8_t baseOf[kIdMax + 1];
163 uint8_t sizeOf[kIdMax + 1];
164 };
165 ASMJIT_VARAPI const TypeData _typeData;
166
isVoid(uint32_t typeId)167 static constexpr bool isVoid(uint32_t typeId) noexcept { return typeId == 0; }
isValid(uint32_t typeId)168 static constexpr bool isValid(uint32_t typeId) noexcept { return typeId >= _kIdIntStart && typeId <= _kIdVec512End; }
isBase(uint32_t typeId)169 static constexpr bool isBase(uint32_t typeId) noexcept { return typeId >= _kIdBaseStart && typeId <= _kIdBaseEnd; }
isAbstract(uint32_t typeId)170 static constexpr bool isAbstract(uint32_t typeId) noexcept { return typeId >= kIdIntPtr && typeId <= kIdUIntPtr; }
171
isInt(uint32_t typeId)172 static constexpr bool isInt(uint32_t typeId) noexcept { return typeId >= _kIdIntStart && typeId <= _kIdIntEnd; }
isInt8(uint32_t typeId)173 static constexpr bool isInt8(uint32_t typeId) noexcept { return typeId == kIdI8; }
isUInt8(uint32_t typeId)174 static constexpr bool isUInt8(uint32_t typeId) noexcept { return typeId == kIdU8; }
isInt16(uint32_t typeId)175 static constexpr bool isInt16(uint32_t typeId) noexcept { return typeId == kIdI16; }
isUInt16(uint32_t typeId)176 static constexpr bool isUInt16(uint32_t typeId) noexcept { return typeId == kIdU16; }
isInt32(uint32_t typeId)177 static constexpr bool isInt32(uint32_t typeId) noexcept { return typeId == kIdI32; }
isUInt32(uint32_t typeId)178 static constexpr bool isUInt32(uint32_t typeId) noexcept { return typeId == kIdU32; }
isInt64(uint32_t typeId)179 static constexpr bool isInt64(uint32_t typeId) noexcept { return typeId == kIdI64; }
isUInt64(uint32_t typeId)180 static constexpr bool isUInt64(uint32_t typeId) noexcept { return typeId == kIdU64; }
181
isGp8(uint32_t typeId)182 static constexpr bool isGp8(uint32_t typeId) noexcept { return typeId >= kIdI8 && typeId <= kIdU8; }
isGp16(uint32_t typeId)183 static constexpr bool isGp16(uint32_t typeId) noexcept { return typeId >= kIdI16 && typeId <= kIdU16; }
isGp32(uint32_t typeId)184 static constexpr bool isGp32(uint32_t typeId) noexcept { return typeId >= kIdI32 && typeId <= kIdU32; }
isGp64(uint32_t typeId)185 static constexpr bool isGp64(uint32_t typeId) noexcept { return typeId >= kIdI64 && typeId <= kIdU64; }
186
isFloat(uint32_t typeId)187 static constexpr bool isFloat(uint32_t typeId) noexcept { return typeId >= _kIdFloatStart && typeId <= _kIdFloatEnd; }
isFloat32(uint32_t typeId)188 static constexpr bool isFloat32(uint32_t typeId) noexcept { return typeId == kIdF32; }
isFloat64(uint32_t typeId)189 static constexpr bool isFloat64(uint32_t typeId) noexcept { return typeId == kIdF64; }
isFloat80(uint32_t typeId)190 static constexpr bool isFloat80(uint32_t typeId) noexcept { return typeId == kIdF80; }
191
isMask(uint32_t typeId)192 static constexpr bool isMask(uint32_t typeId) noexcept { return typeId >= _kIdMaskStart && typeId <= _kIdMaskEnd; }
isMask8(uint32_t typeId)193 static constexpr bool isMask8(uint32_t typeId) noexcept { return typeId == kIdMask8; }
isMask16(uint32_t typeId)194 static constexpr bool isMask16(uint32_t typeId) noexcept { return typeId == kIdMask16; }
isMask32(uint32_t typeId)195 static constexpr bool isMask32(uint32_t typeId) noexcept { return typeId == kIdMask32; }
isMask64(uint32_t typeId)196 static constexpr bool isMask64(uint32_t typeId) noexcept { return typeId == kIdMask64; }
197
isMmx(uint32_t typeId)198 static constexpr bool isMmx(uint32_t typeId) noexcept { return typeId >= _kIdMmxStart && typeId <= _kIdMmxEnd; }
isMmx32(uint32_t typeId)199 static constexpr bool isMmx32(uint32_t typeId) noexcept { return typeId == kIdMmx32; }
isMmx64(uint32_t typeId)200 static constexpr bool isMmx64(uint32_t typeId) noexcept { return typeId == kIdMmx64; }
201
isVec(uint32_t typeId)202 static constexpr bool isVec(uint32_t typeId) noexcept { return typeId >= _kIdVec32Start && typeId <= _kIdVec512End; }
isVec32(uint32_t typeId)203 static constexpr bool isVec32(uint32_t typeId) noexcept { return typeId >= _kIdVec32Start && typeId <= _kIdVec32End; }
isVec64(uint32_t typeId)204 static constexpr bool isVec64(uint32_t typeId) noexcept { return typeId >= _kIdVec64Start && typeId <= _kIdVec64End; }
isVec128(uint32_t typeId)205 static constexpr bool isVec128(uint32_t typeId) noexcept { return typeId >= _kIdVec128Start && typeId <= _kIdVec128End; }
isVec256(uint32_t typeId)206 static constexpr bool isVec256(uint32_t typeId) noexcept { return typeId >= _kIdVec256Start && typeId <= _kIdVec256End; }
isVec512(uint32_t typeId)207 static constexpr bool isVec512(uint32_t typeId) noexcept { return typeId >= _kIdVec512Start && typeId <= _kIdVec512End; }
208
209 //! \cond
210 enum TypeCategory : uint32_t {
211 kTypeCategoryUnknown = 0,
212 kTypeCategoryEnum = 1,
213 kTypeCategoryIntegral = 2,
214 kTypeCategoryFloatingPoint = 3,
215 kTypeCategoryFunction = 4
216 };
217
218 template<typename T, uint32_t Category>
219 struct IdOfT_ByCategory {}; // Fails if not specialized.
220
221 template<typename T>
222 struct IdOfT_ByCategory<T, kTypeCategoryIntegral> {
223 enum : uint32_t {
224 kTypeId = (sizeof(T) == 1 && std::is_signed<T>::value) ? kIdI8 :
225 (sizeof(T) == 1 && !std::is_signed<T>::value) ? kIdU8 :
226 (sizeof(T) == 2 && std::is_signed<T>::value) ? kIdI16 :
227 (sizeof(T) == 2 && !std::is_signed<T>::value) ? kIdU16 :
228 (sizeof(T) == 4 && std::is_signed<T>::value) ? kIdI32 :
229 (sizeof(T) == 4 && !std::is_signed<T>::value) ? kIdU32 :
230 (sizeof(T) == 8 && std::is_signed<T>::value) ? kIdI64 :
231 (sizeof(T) == 8 && !std::is_signed<T>::value) ? kIdU64 : kIdVoid
232 };
233 };
234
235 template<typename T>
236 struct IdOfT_ByCategory<T, kTypeCategoryFloatingPoint> {
237 enum : uint32_t {
238 kTypeId = (sizeof(T) == 4 ) ? kIdF32 :
239 (sizeof(T) == 8 ) ? kIdF64 :
240 (sizeof(T) >= 10) ? kIdF80 : kIdVoid
241 };
242 };
243
244 template<typename T>
245 struct IdOfT_ByCategory<T, kTypeCategoryEnum>
246 : public IdOfT_ByCategory<typename std::underlying_type<T>::type, kTypeCategoryIntegral> {};
247
248 template<typename T>
249 struct IdOfT_ByCategory<T, kTypeCategoryFunction> {
250 enum: uint32_t { kTypeId = kIdUIntPtr };
251 };
252 //! \endcond
253
254 //! IdOfT<> template allows to get a TypeId from a C++ type `T`.
255 template<typename T>
256 struct IdOfT
257 #ifdef _DOXYGEN
258 //! TypeId of C++ type `T`.
259 static constexpr uint32_t kTypeId = _TypeIdDeducedAtCompileTime_;
260 #else
261 : public IdOfT_ByCategory<T,
262 std::is_enum<T>::value ? kTypeCategoryEnum :
263 std::is_integral<T>::value ? kTypeCategoryIntegral :
264 std::is_floating_point<T>::value ? kTypeCategoryFloatingPoint :
265 std::is_function<T>::value ? kTypeCategoryFunction : kTypeCategoryUnknown>
266 #endif
267 {};
268
269 //! \cond
270 template<typename T>
271 struct IdOfT<T*> { enum : uint32_t { kTypeId = kIdUIntPtr }; };
272
273 template<typename T>
274 struct IdOfT<T&> { enum : uint32_t { kTypeId = kIdUIntPtr }; };
275 //! \endcond
276
277 static inline uint32_t baseOf(uint32_t typeId) noexcept {
278 ASMJIT_ASSERT(typeId <= kIdMax);
279 return _typeData.baseOf[typeId];
280 }
281
282 static inline uint32_t sizeOf(uint32_t typeId) noexcept {
283 ASMJIT_ASSERT(typeId <= kIdMax);
284 return _typeData.sizeOf[typeId];
285 }
286
287 //! Returns offset needed to convert a `kIntPtr` and `kUIntPtr` TypeId
288 //! into a type that matches `registerSize` (general-purpose register size).
289 //! If you find such TypeId it's then only about adding the offset to it.
290 //!
291 //! For example:
292 //!
293 //! ```
294 //! uint32_t registerSize = '4' or '8';
295 //! uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize);
296 //!
297 //! uint32_t typeId = 'some type-id';
298 //!
299 //! // Normalize some typeId into a non-abstract typeId.
300 //! if (Type::isAbstract(typeId)) typeId += deabstractDelta;
301 //!
302 //! // The same, but by using Type::deabstract() function.
303 //! typeId = Type::deabstract(typeId, deabstractDelta);
304 //! ```
305 static constexpr uint32_t deabstractDeltaOfSize(uint32_t registerSize) noexcept {
306 return registerSize >= 8 ? kIdI64 - kIdIntPtr : kIdI32 - kIdIntPtr;
307 }
308
309 static constexpr uint32_t deabstract(uint32_t typeId, uint32_t deabstractDelta) noexcept {
310 return isAbstract(typeId) ? typeId + deabstractDelta : typeId;
311 }
312
313 //! bool as C++ type-name.
314 struct Bool {};
315 //! int8_t as C++ type-name.
316 struct I8 {};
317 //! uint8_t as C++ type-name.
318 struct U8 {};
319 //! int16_t as C++ type-name.
320 struct I16 {};
321 //! uint16_t as C++ type-name.
322 struct U16 {};
323 //! int32_t as C++ type-name.
324 struct I32 {};
325 //! uint32_t as C++ type-name.
326 struct U32 {};
327 //! int64_t as C++ type-name.
328 struct I64 {};
329 //! uint64_t as C++ type-name.
330 struct U64 {};
331 //! intptr_t as C++ type-name.
332 struct IPtr {};
333 //! uintptr_t as C++ type-name.
334 struct UPtr {};
335 //! float as C++ type-name.
336 struct F32 {};
337 //! double as C++ type-name.
338 struct F64 {};
339
340 } // {Type}
341
342 // ============================================================================
343 // [ASMJIT_DEFINE_TYPE_ID]
344 // ============================================================================
345
346 //! \cond
347 #define ASMJIT_DEFINE_TYPE_ID(T, TYPE_ID) \
348 namespace Type { \
349 template<> \
350 struct IdOfT<T> { \
351 enum : uint32_t { kTypeId = TYPE_ID }; \
352 }; \
353 }
354
355 ASMJIT_DEFINE_TYPE_ID(void, kIdVoid);
356 ASMJIT_DEFINE_TYPE_ID(Bool, kIdU8);
357 ASMJIT_DEFINE_TYPE_ID(I8 , kIdI8);
358 ASMJIT_DEFINE_TYPE_ID(U8 , kIdU8);
359 ASMJIT_DEFINE_TYPE_ID(I16 , kIdI16);
360 ASMJIT_DEFINE_TYPE_ID(U16 , kIdU16);
361 ASMJIT_DEFINE_TYPE_ID(I32 , kIdI32);
362 ASMJIT_DEFINE_TYPE_ID(U32 , kIdU32);
363 ASMJIT_DEFINE_TYPE_ID(I64 , kIdI64);
364 ASMJIT_DEFINE_TYPE_ID(U64 , kIdU64);
365 ASMJIT_DEFINE_TYPE_ID(IPtr, kIdIntPtr);
366 ASMJIT_DEFINE_TYPE_ID(UPtr, kIdUIntPtr);
367 ASMJIT_DEFINE_TYPE_ID(F32 , kIdF32);
368 ASMJIT_DEFINE_TYPE_ID(F64 , kIdF64);
369 //! \endcond
370
371 //! \}
372
373 ASMJIT_END_NAMESPACE
374
375 #endif // ASMJIT_CORE_TYPE_H_INCLUDED
376