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