You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
376 lines
13 KiB
376 lines
13 KiB
// AsmJit - Machine code generation for C++
|
|
//
|
|
// * Official AsmJit Home Page: https://asmjit.com
|
|
// * Official Github Repository: https://github.com/asmjit/asmjit
|
|
//
|
|
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
//
|
|
// This software is provided 'as-is', without any express or implied
|
|
// warranty. In no event will the authors be held liable for any damages
|
|
// arising from the use of this software.
|
|
//
|
|
// Permission is granted to anyone to use this software for any purpose,
|
|
// including commercial applications, and to alter it and redistribute it
|
|
// freely, subject to the following restrictions:
|
|
//
|
|
// 1. The origin of this software must not be misrepresented; you must not
|
|
// claim that you wrote the original software. If you use this software
|
|
// in a product, an acknowledgment in the product documentation would be
|
|
// appreciated but is not required.
|
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
// misrepresented as being the original software.
|
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
|
|
#ifndef ASMJIT_CORE_TYPE_H_INCLUDED
|
|
#define ASMJIT_CORE_TYPE_H_INCLUDED
|
|
|
|
#include "../core/globals.h"
|
|
|
|
ASMJIT_BEGIN_NAMESPACE
|
|
|
|
//! \addtogroup asmjit_core
|
|
//! \{
|
|
|
|
// ============================================================================
|
|
// [asmjit::Type]
|
|
// ============================================================================
|
|
|
|
//! Provides a minimalist type-system that is used by Asmjit library.
|
|
namespace Type {
|
|
|
|
//! TypeId.
|
|
//!
|
|
//! This is an additional information that can be used to describe a value-type
|
|
//! of physical or virtual register. it's used mostly by BaseCompiler to describe
|
|
//! register representation (the group of data stored in the register and the
|
|
//! width used) and it's also used by APIs that allow to describe and work with
|
|
//! function signatures.
|
|
enum Id : uint32_t {
|
|
kIdVoid = 0, //!< Void type.
|
|
|
|
_kIdBaseStart = 32,
|
|
_kIdBaseEnd = 44,
|
|
|
|
_kIdIntStart = 32,
|
|
_kIdIntEnd = 41,
|
|
|
|
kIdIntPtr = 32, //!< Abstract signed integer type that has a native size.
|
|
kIdUIntPtr = 33, //!< Abstract unsigned integer type that has a native size.
|
|
|
|
kIdI8 = 34, //!< 8-bit signed integer type.
|
|
kIdU8 = 35, //!< 8-bit unsigned integer type.
|
|
kIdI16 = 36, //!< 16-bit signed integer type.
|
|
kIdU16 = 37, //!< 16-bit unsigned integer type.
|
|
kIdI32 = 38, //!< 32-bit signed integer type.
|
|
kIdU32 = 39, //!< 32-bit unsigned integer type.
|
|
kIdI64 = 40, //!< 64-bit signed integer type.
|
|
kIdU64 = 41, //!< 64-bit unsigned integer type.
|
|
|
|
_kIdFloatStart = 42,
|
|
_kIdFloatEnd = 44,
|
|
|
|
kIdF32 = 42, //!< 32-bit floating point type.
|
|
kIdF64 = 43, //!< 64-bit floating point type.
|
|
kIdF80 = 44, //!< 80-bit floating point type.
|
|
|
|
_kIdMaskStart = 45,
|
|
_kIdMaskEnd = 48,
|
|
|
|
kIdMask8 = 45, //!< 8-bit opmask register (K).
|
|
kIdMask16 = 46, //!< 16-bit opmask register (K).
|
|
kIdMask32 = 47, //!< 32-bit opmask register (K).
|
|
kIdMask64 = 48, //!< 64-bit opmask register (K).
|
|
|
|
_kIdMmxStart = 49,
|
|
_kIdMmxEnd = 50,
|
|
|
|
kIdMmx32 = 49, //!< 64-bit MMX register only used for 32 bits.
|
|
kIdMmx64 = 50, //!< 64-bit MMX register.
|
|
|
|
_kIdVec32Start = 51,
|
|
_kIdVec32End = 60,
|
|
|
|
kIdI8x4 = 51,
|
|
kIdU8x4 = 52,
|
|
kIdI16x2 = 53,
|
|
kIdU16x2 = 54,
|
|
kIdI32x1 = 55,
|
|
kIdU32x1 = 56,
|
|
kIdF32x1 = 59,
|
|
|
|
_kIdVec64Start = 61,
|
|
_kIdVec64End = 70,
|
|
|
|
kIdI8x8 = 61,
|
|
kIdU8x8 = 62,
|
|
kIdI16x4 = 63,
|
|
kIdU16x4 = 64,
|
|
kIdI32x2 = 65,
|
|
kIdU32x2 = 66,
|
|
kIdI64x1 = 67,
|
|
kIdU64x1 = 68,
|
|
kIdF32x2 = 69,
|
|
kIdF64x1 = 70,
|
|
|
|
_kIdVec128Start = 71,
|
|
_kIdVec128End = 80,
|
|
|
|
kIdI8x16 = 71,
|
|
kIdU8x16 = 72,
|
|
kIdI16x8 = 73,
|
|
kIdU16x8 = 74,
|
|
kIdI32x4 = 75,
|
|
kIdU32x4 = 76,
|
|
kIdI64x2 = 77,
|
|
kIdU64x2 = 78,
|
|
kIdF32x4 = 79,
|
|
kIdF64x2 = 80,
|
|
|
|
_kIdVec256Start = 81,
|
|
_kIdVec256End = 90,
|
|
|
|
kIdI8x32 = 81,
|
|
kIdU8x32 = 82,
|
|
kIdI16x16 = 83,
|
|
kIdU16x16 = 84,
|
|
kIdI32x8 = 85,
|
|
kIdU32x8 = 86,
|
|
kIdI64x4 = 87,
|
|
kIdU64x4 = 88,
|
|
kIdF32x8 = 89,
|
|
kIdF64x4 = 90,
|
|
|
|
_kIdVec512Start = 91,
|
|
_kIdVec512End = 100,
|
|
|
|
kIdI8x64 = 91,
|
|
kIdU8x64 = 92,
|
|
kIdI16x32 = 93,
|
|
kIdU16x32 = 94,
|
|
kIdI32x16 = 95,
|
|
kIdU32x16 = 96,
|
|
kIdI64x8 = 97,
|
|
kIdU64x8 = 98,
|
|
kIdF32x16 = 99,
|
|
kIdF64x8 = 100,
|
|
|
|
kIdCount = 101,
|
|
kIdMax = 255
|
|
};
|
|
|
|
struct TypeData {
|
|
uint8_t baseOf[kIdMax + 1];
|
|
uint8_t sizeOf[kIdMax + 1];
|
|
};
|
|
ASMJIT_VARAPI const TypeData _typeData;
|
|
|
|
static constexpr bool isVoid(uint32_t typeId) noexcept { return typeId == 0; }
|
|
static constexpr bool isValid(uint32_t typeId) noexcept { return typeId >= _kIdIntStart && typeId <= _kIdVec512End; }
|
|
static constexpr bool isBase(uint32_t typeId) noexcept { return typeId >= _kIdBaseStart && typeId <= _kIdBaseEnd; }
|
|
static constexpr bool isAbstract(uint32_t typeId) noexcept { return typeId >= kIdIntPtr && typeId <= kIdUIntPtr; }
|
|
|
|
static constexpr bool isInt(uint32_t typeId) noexcept { return typeId >= _kIdIntStart && typeId <= _kIdIntEnd; }
|
|
static constexpr bool isInt8(uint32_t typeId) noexcept { return typeId == kIdI8; }
|
|
static constexpr bool isUInt8(uint32_t typeId) noexcept { return typeId == kIdU8; }
|
|
static constexpr bool isInt16(uint32_t typeId) noexcept { return typeId == kIdI16; }
|
|
static constexpr bool isUInt16(uint32_t typeId) noexcept { return typeId == kIdU16; }
|
|
static constexpr bool isInt32(uint32_t typeId) noexcept { return typeId == kIdI32; }
|
|
static constexpr bool isUInt32(uint32_t typeId) noexcept { return typeId == kIdU32; }
|
|
static constexpr bool isInt64(uint32_t typeId) noexcept { return typeId == kIdI64; }
|
|
static constexpr bool isUInt64(uint32_t typeId) noexcept { return typeId == kIdU64; }
|
|
|
|
static constexpr bool isGp8(uint32_t typeId) noexcept { return typeId >= kIdI8 && typeId <= kIdU8; }
|
|
static constexpr bool isGp16(uint32_t typeId) noexcept { return typeId >= kIdI16 && typeId <= kIdU16; }
|
|
static constexpr bool isGp32(uint32_t typeId) noexcept { return typeId >= kIdI32 && typeId <= kIdU32; }
|
|
static constexpr bool isGp64(uint32_t typeId) noexcept { return typeId >= kIdI64 && typeId <= kIdU64; }
|
|
|
|
static constexpr bool isFloat(uint32_t typeId) noexcept { return typeId >= _kIdFloatStart && typeId <= _kIdFloatEnd; }
|
|
static constexpr bool isFloat32(uint32_t typeId) noexcept { return typeId == kIdF32; }
|
|
static constexpr bool isFloat64(uint32_t typeId) noexcept { return typeId == kIdF64; }
|
|
static constexpr bool isFloat80(uint32_t typeId) noexcept { return typeId == kIdF80; }
|
|
|
|
static constexpr bool isMask(uint32_t typeId) noexcept { return typeId >= _kIdMaskStart && typeId <= _kIdMaskEnd; }
|
|
static constexpr bool isMask8(uint32_t typeId) noexcept { return typeId == kIdMask8; }
|
|
static constexpr bool isMask16(uint32_t typeId) noexcept { return typeId == kIdMask16; }
|
|
static constexpr bool isMask32(uint32_t typeId) noexcept { return typeId == kIdMask32; }
|
|
static constexpr bool isMask64(uint32_t typeId) noexcept { return typeId == kIdMask64; }
|
|
|
|
static constexpr bool isMmx(uint32_t typeId) noexcept { return typeId >= _kIdMmxStart && typeId <= _kIdMmxEnd; }
|
|
static constexpr bool isMmx32(uint32_t typeId) noexcept { return typeId == kIdMmx32; }
|
|
static constexpr bool isMmx64(uint32_t typeId) noexcept { return typeId == kIdMmx64; }
|
|
|
|
static constexpr bool isVec(uint32_t typeId) noexcept { return typeId >= _kIdVec32Start && typeId <= _kIdVec512End; }
|
|
static constexpr bool isVec32(uint32_t typeId) noexcept { return typeId >= _kIdVec32Start && typeId <= _kIdVec32End; }
|
|
static constexpr bool isVec64(uint32_t typeId) noexcept { return typeId >= _kIdVec64Start && typeId <= _kIdVec64End; }
|
|
static constexpr bool isVec128(uint32_t typeId) noexcept { return typeId >= _kIdVec128Start && typeId <= _kIdVec128End; }
|
|
static constexpr bool isVec256(uint32_t typeId) noexcept { return typeId >= _kIdVec256Start && typeId <= _kIdVec256End; }
|
|
static constexpr bool isVec512(uint32_t typeId) noexcept { return typeId >= _kIdVec512Start && typeId <= _kIdVec512End; }
|
|
|
|
//! \cond
|
|
enum TypeCategory : uint32_t {
|
|
kTypeCategoryUnknown = 0,
|
|
kTypeCategoryEnum = 1,
|
|
kTypeCategoryIntegral = 2,
|
|
kTypeCategoryFloatingPoint = 3,
|
|
kTypeCategoryFunction = 4
|
|
};
|
|
|
|
template<typename T, uint32_t Category>
|
|
struct IdOfT_ByCategory {}; // Fails if not specialized.
|
|
|
|
template<typename T>
|
|
struct IdOfT_ByCategory<T, kTypeCategoryIntegral> {
|
|
enum : uint32_t {
|
|
kTypeId = (sizeof(T) == 1 && std::is_signed<T>::value) ? kIdI8 :
|
|
(sizeof(T) == 1 && !std::is_signed<T>::value) ? kIdU8 :
|
|
(sizeof(T) == 2 && std::is_signed<T>::value) ? kIdI16 :
|
|
(sizeof(T) == 2 && !std::is_signed<T>::value) ? kIdU16 :
|
|
(sizeof(T) == 4 && std::is_signed<T>::value) ? kIdI32 :
|
|
(sizeof(T) == 4 && !std::is_signed<T>::value) ? kIdU32 :
|
|
(sizeof(T) == 8 && std::is_signed<T>::value) ? kIdI64 :
|
|
(sizeof(T) == 8 && !std::is_signed<T>::value) ? kIdU64 : kIdVoid
|
|
};
|
|
};
|
|
|
|
template<typename T>
|
|
struct IdOfT_ByCategory<T, kTypeCategoryFloatingPoint> {
|
|
enum : uint32_t {
|
|
kTypeId = (sizeof(T) == 4 ) ? kIdF32 :
|
|
(sizeof(T) == 8 ) ? kIdF64 :
|
|
(sizeof(T) >= 10) ? kIdF80 : kIdVoid
|
|
};
|
|
};
|
|
|
|
template<typename T>
|
|
struct IdOfT_ByCategory<T, kTypeCategoryEnum>
|
|
: public IdOfT_ByCategory<typename std::underlying_type<T>::type, kTypeCategoryIntegral> {};
|
|
|
|
template<typename T>
|
|
struct IdOfT_ByCategory<T, kTypeCategoryFunction> {
|
|
enum: uint32_t { kTypeId = kIdUIntPtr };
|
|
};
|
|
//! \endcond
|
|
|
|
//! IdOfT<> template allows to get a TypeId from a C++ type `T`.
|
|
template<typename T>
|
|
struct IdOfT
|
|
#ifdef _DOXYGEN
|
|
//! TypeId of C++ type `T`.
|
|
static constexpr uint32_t kTypeId = _TypeIdDeducedAtCompileTime_;
|
|
#else
|
|
: public IdOfT_ByCategory<T,
|
|
std::is_enum<T>::value ? kTypeCategoryEnum :
|
|
std::is_integral<T>::value ? kTypeCategoryIntegral :
|
|
std::is_floating_point<T>::value ? kTypeCategoryFloatingPoint :
|
|
std::is_function<T>::value ? kTypeCategoryFunction : kTypeCategoryUnknown>
|
|
#endif
|
|
{};
|
|
|
|
//! \cond
|
|
template<typename T>
|
|
struct IdOfT<T*> { enum : uint32_t { kTypeId = kIdUIntPtr }; };
|
|
|
|
template<typename T>
|
|
struct IdOfT<T&> { enum : uint32_t { kTypeId = kIdUIntPtr }; };
|
|
//! \endcond
|
|
|
|
static inline uint32_t baseOf(uint32_t typeId) noexcept {
|
|
ASMJIT_ASSERT(typeId <= kIdMax);
|
|
return _typeData.baseOf[typeId];
|
|
}
|
|
|
|
static inline uint32_t sizeOf(uint32_t typeId) noexcept {
|
|
ASMJIT_ASSERT(typeId <= kIdMax);
|
|
return _typeData.sizeOf[typeId];
|
|
}
|
|
|
|
//! Returns offset needed to convert a `kIntPtr` and `kUIntPtr` TypeId
|
|
//! into a type that matches `registerSize` (general-purpose register size).
|
|
//! If you find such TypeId it's then only about adding the offset to it.
|
|
//!
|
|
//! For example:
|
|
//!
|
|
//! ```
|
|
//! uint32_t registerSize = '4' or '8';
|
|
//! uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize);
|
|
//!
|
|
//! uint32_t typeId = 'some type-id';
|
|
//!
|
|
//! // Normalize some typeId into a non-abstract typeId.
|
|
//! if (Type::isAbstract(typeId)) typeId += deabstractDelta;
|
|
//!
|
|
//! // The same, but by using Type::deabstract() function.
|
|
//! typeId = Type::deabstract(typeId, deabstractDelta);
|
|
//! ```
|
|
static constexpr uint32_t deabstractDeltaOfSize(uint32_t registerSize) noexcept {
|
|
return registerSize >= 8 ? kIdI64 - kIdIntPtr : kIdI32 - kIdIntPtr;
|
|
}
|
|
|
|
static constexpr uint32_t deabstract(uint32_t typeId, uint32_t deabstractDelta) noexcept {
|
|
return isAbstract(typeId) ? typeId + deabstractDelta : typeId;
|
|
}
|
|
|
|
//! bool as C++ type-name.
|
|
struct Bool {};
|
|
//! int8_t as C++ type-name.
|
|
struct I8 {};
|
|
//! uint8_t as C++ type-name.
|
|
struct U8 {};
|
|
//! int16_t as C++ type-name.
|
|
struct I16 {};
|
|
//! uint16_t as C++ type-name.
|
|
struct U16 {};
|
|
//! int32_t as C++ type-name.
|
|
struct I32 {};
|
|
//! uint32_t as C++ type-name.
|
|
struct U32 {};
|
|
//! int64_t as C++ type-name.
|
|
struct I64 {};
|
|
//! uint64_t as C++ type-name.
|
|
struct U64 {};
|
|
//! intptr_t as C++ type-name.
|
|
struct IPtr {};
|
|
//! uintptr_t as C++ type-name.
|
|
struct UPtr {};
|
|
//! float as C++ type-name.
|
|
struct F32 {};
|
|
//! double as C++ type-name.
|
|
struct F64 {};
|
|
|
|
} // {Type}
|
|
|
|
// ============================================================================
|
|
// [ASMJIT_DEFINE_TYPE_ID]
|
|
// ============================================================================
|
|
|
|
//! \cond
|
|
#define ASMJIT_DEFINE_TYPE_ID(T, TYPE_ID) \
|
|
namespace Type { \
|
|
template<> \
|
|
struct IdOfT<T> { \
|
|
enum : uint32_t { kTypeId = TYPE_ID }; \
|
|
}; \
|
|
}
|
|
|
|
ASMJIT_DEFINE_TYPE_ID(void, kIdVoid);
|
|
ASMJIT_DEFINE_TYPE_ID(Bool, kIdU8);
|
|
ASMJIT_DEFINE_TYPE_ID(I8 , kIdI8);
|
|
ASMJIT_DEFINE_TYPE_ID(U8 , kIdU8);
|
|
ASMJIT_DEFINE_TYPE_ID(I16 , kIdI16);
|
|
ASMJIT_DEFINE_TYPE_ID(U16 , kIdU16);
|
|
ASMJIT_DEFINE_TYPE_ID(I32 , kIdI32);
|
|
ASMJIT_DEFINE_TYPE_ID(U32 , kIdU32);
|
|
ASMJIT_DEFINE_TYPE_ID(I64 , kIdI64);
|
|
ASMJIT_DEFINE_TYPE_ID(U64 , kIdU64);
|
|
ASMJIT_DEFINE_TYPE_ID(IPtr, kIdIntPtr);
|
|
ASMJIT_DEFINE_TYPE_ID(UPtr, kIdUIntPtr);
|
|
ASMJIT_DEFINE_TYPE_ID(F32 , kIdF32);
|
|
ASMJIT_DEFINE_TYPE_ID(F64 , kIdF64);
|
|
//! \endcond
|
|
|
|
//! \}
|
|
|
|
ASMJIT_END_NAMESPACE
|
|
|
|
#endif // ASMJIT_CORE_TYPE_H_INCLUDED
|