mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-21 14:50:44 +00:00
1358 lines
50 KiB
C++
1358 lines
50 KiB
C++
// [AsmJit]
|
|
// Complete x86/x64 JIT and Remote Assembler for C++.
|
|
//
|
|
// [License]
|
|
// Zlib - See LICENSE.md file in the package.
|
|
|
|
// [Guard]
|
|
#ifndef _ASMJIT_BASE_UTILS_H
|
|
#define _ASMJIT_BASE_UTILS_H
|
|
|
|
// [Dependencies]
|
|
#include "../base/globals.h"
|
|
|
|
#if ASMJIT_CC_MSC_GE(14, 0, 0)
|
|
# include <intrin.h>
|
|
#endif // ASMJIT_OS_WINDOWS
|
|
|
|
// [Api-Begin]
|
|
#include "../asmjit_apibegin.h"
|
|
|
|
namespace asmjit {
|
|
|
|
//! \addtogroup asmjit_base
|
|
//! \{
|
|
|
|
// ============================================================================
|
|
// [asmjit::IntTraits]
|
|
// ============================================================================
|
|
|
|
//! \internal
|
|
//! \{
|
|
template<size_t Size, int IsSigned>
|
|
struct IntTraitsPrivate {}; // Let it fail if not specialized!
|
|
|
|
template<> struct IntTraitsPrivate<1, 0> { typedef int IntType; typedef int8_t SignedType; typedef uint8_t UnsignedType; };
|
|
template<> struct IntTraitsPrivate<1, 1> { typedef int IntType; typedef int8_t SignedType; typedef uint8_t UnsignedType; };
|
|
|
|
template<> struct IntTraitsPrivate<2, 0> { typedef int IntType; typedef int16_t SignedType; typedef uint16_t UnsignedType; };
|
|
template<> struct IntTraitsPrivate<2, 1> { typedef int IntType; typedef int16_t SignedType; typedef uint16_t UnsignedType; };
|
|
|
|
template<> struct IntTraitsPrivate<4, 0> { typedef int64_t IntType; typedef int32_t SignedType; typedef uint32_t UnsignedType; };
|
|
template<> struct IntTraitsPrivate<4, 1> { typedef int IntType; typedef int32_t SignedType; typedef uint32_t UnsignedType; };
|
|
|
|
template<> struct IntTraitsPrivate<8, 0> { typedef int64_t IntType; typedef int64_t SignedType; typedef uint64_t UnsignedType; };
|
|
template<> struct IntTraitsPrivate<8, 1> { typedef int64_t IntType; typedef int64_t SignedType; typedef uint64_t UnsignedType; };
|
|
|
|
//! \internal
|
|
template<typename T>
|
|
struct IntTraits {
|
|
enum {
|
|
kIsSigned = static_cast<T>(~static_cast<T>(0)) < static_cast<T>(0),
|
|
kIsUnsigned = !kIsSigned,
|
|
kIs8Bit = sizeof(T) == 1,
|
|
kIs16Bit = sizeof(T) == 2,
|
|
kIs32Bit = sizeof(T) == 4,
|
|
kIs64Bit = sizeof(T) == 8,
|
|
kIsIntPtr = sizeof(T) == sizeof(intptr_t)
|
|
};
|
|
|
|
typedef typename IntTraitsPrivate<sizeof(T), kIsSigned>::IntType IntType;
|
|
typedef typename IntTraitsPrivate<sizeof(T), kIsSigned>::SignedType SignedType;
|
|
typedef typename IntTraitsPrivate<sizeof(T), kIsSigned>::UnsignedType UnsignedType;
|
|
|
|
//! Get a minimum value of `T`.
|
|
static ASMJIT_INLINE T minValue() noexcept {
|
|
return kIsSigned ? T((~static_cast<UnsignedType>(0) >> 1) + static_cast<UnsignedType>(1)) : T(0);
|
|
}
|
|
|
|
//! Get a maximum value of `T`.
|
|
static ASMJIT_INLINE T maxValue() noexcept {
|
|
return kIsSigned ? T(~static_cast<UnsignedType>(0) >> 1) : ~T(0);
|
|
}
|
|
};
|
|
|
|
//! \}
|
|
|
|
// ============================================================================
|
|
// [asmjit::Utils]
|
|
// ============================================================================
|
|
|
|
//! AsmJit utilities - integer, string, etc...
|
|
namespace Utils {
|
|
// --------------------------------------------------------------------------
|
|
// [Float <-> Int]
|
|
// --------------------------------------------------------------------------
|
|
|
|
//! \internal
|
|
union FloatBits {
|
|
int32_t i;
|
|
float f;
|
|
};
|
|
|
|
//! \internal
|
|
union DoubleBits {
|
|
int64_t i;
|
|
double d;
|
|
};
|
|
|
|
//! Bit-cast `float` to a 32-bit integer.
|
|
static ASMJIT_INLINE int32_t floatAsInt(float f) noexcept { FloatBits m; m.f = f; return m.i; }
|
|
//! Bit-cast 32-bit integer to `float`.
|
|
static ASMJIT_INLINE float intAsFloat(int32_t i) noexcept { FloatBits m; m.i = i; return m.f; }
|
|
|
|
//! Bit-cast `double` to a 64-bit integer.
|
|
static ASMJIT_INLINE int64_t doubleAsInt(double d) noexcept { DoubleBits m; m.d = d; return m.i; }
|
|
//! Bit-cast 64-bit integer to `double`.
|
|
static ASMJIT_INLINE double intAsDouble(int64_t i) noexcept { DoubleBits m; m.i = i; return m.d; }
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Pack / Unpack]
|
|
// --------------------------------------------------------------------------
|
|
|
|
//! Pack four 8-bit integer into a 32-bit integer as it is an array of `{b0,b1,b2,b3}`.
|
|
static ASMJIT_INLINE uint32_t pack32_4x8(uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) noexcept {
|
|
return ASMJIT_PACK32_4x8(b0, b1, b2, b3);
|
|
}
|
|
|
|
//! Pack two 32-bit integer into a 64-bit integer as it is an array of `{u0,u1}`.
|
|
static ASMJIT_INLINE uint64_t pack64_2x32(uint32_t u0, uint32_t u1) noexcept {
|
|
return ASMJIT_ARCH_LE ? (static_cast<uint64_t>(u1) << 32) + u0
|
|
: (static_cast<uint64_t>(u0) << 32) + u1;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Position of byte (in bit-shift)]
|
|
// --------------------------------------------------------------------------
|
|
|
|
static ASMJIT_INLINE uint32_t byteShiftOfDWordStruct(uint32_t index) noexcept {
|
|
if (ASMJIT_ARCH_LE)
|
|
return index * 8;
|
|
else
|
|
return (sizeof(uint32_t) - 1 - index) * 8;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Lower/Upper]
|
|
// --------------------------------------------------------------------------
|
|
|
|
template<typename T>
|
|
static ASMJIT_INLINE T toLower(T c) noexcept { return c ^ (static_cast<T>(c >= T('A') && c <= T('Z')) << 5); }
|
|
template<typename T>
|
|
static ASMJIT_INLINE T toUpper(T c) noexcept { return c ^ (static_cast<T>(c >= T('a') && c <= T('z')) << 5); }
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Hash]
|
|
// --------------------------------------------------------------------------
|
|
|
|
// \internal
|
|
static ASMJIT_INLINE uint32_t hashRound(uint32_t hash, uint32_t c) noexcept { return hash * 65599 + c; }
|
|
|
|
// Get a hash of the given string `str` of `len` length. Length must be valid
|
|
// as this function doesn't check for a null terminator and allows it in the
|
|
// middle of the string.
|
|
static ASMJIT_INLINE uint32_t hashString(const char* str, size_t len) noexcept {
|
|
uint32_t hVal = 0;
|
|
for (uint32_t i = 0; i < len; i++)
|
|
hVal = hashRound(hVal, str[i]);
|
|
return hVal;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Swap]
|
|
// --------------------------------------------------------------------------
|
|
|
|
template<typename T>
|
|
static ASMJIT_INLINE void swap(T& a, T& b) noexcept {
|
|
T tmp = a;
|
|
a = b;
|
|
b = tmp;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [InInterval]
|
|
// --------------------------------------------------------------------------
|
|
|
|
//! Get whether `x` is greater than or equal to `a` and lesses than or equal to `b`.
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool inInterval(T x, T a, T b) noexcept {
|
|
return x >= a && x <= b;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [AsInt]
|
|
// --------------------------------------------------------------------------
|
|
|
|
//! Map an integer `x` of type `T` to `int` or `int64_t` depending on the
|
|
//! type. Used internally by AsmJit to dispatch arguments that can be of
|
|
//! arbitrary integer type into a function argument that is either `int` or
|
|
//! `int64_t`.
|
|
template<typename T>
|
|
static ASMJIT_INLINE typename IntTraits<T>::IntType asInt(T x) noexcept {
|
|
return static_cast<typename IntTraits<T>::IntType>(x);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [IsInt / IsUInt]
|
|
// --------------------------------------------------------------------------
|
|
|
|
//! Get whether the given integer `x` can be casted to a 4-bit signed integer.
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool isInt4(T x) noexcept {
|
|
typedef typename IntTraits<T>::SignedType SignedType;
|
|
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
|
|
|
if (IntTraits<T>::kIsSigned)
|
|
return inInterval<SignedType>(SignedType(x), -8, 7);
|
|
else
|
|
return UnsignedType(x) <= UnsignedType(7U);
|
|
}
|
|
|
|
//! Get whether the given integer `x` can be casted to an 8-bit signed integer.
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool isInt8(T x) noexcept {
|
|
typedef typename IntTraits<T>::SignedType SignedType;
|
|
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
|
|
|
if (IntTraits<T>::kIsSigned)
|
|
return sizeof(T) <= 1 || inInterval<SignedType>(SignedType(x), -128, 127);
|
|
else
|
|
return UnsignedType(x) <= UnsignedType(127U);
|
|
}
|
|
|
|
//! Get whether the given integer `x` can be casted to a 16-bit signed integer.
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool isInt16(T x) noexcept {
|
|
typedef typename IntTraits<T>::SignedType SignedType;
|
|
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
|
|
|
if (IntTraits<T>::kIsSigned)
|
|
return sizeof(T) <= 2 || inInterval<SignedType>(SignedType(x), -32768, 32767);
|
|
else
|
|
return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(32767U);
|
|
}
|
|
|
|
//! Get whether the given integer `x` can be casted to a 32-bit signed integer.
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool isInt32(T x) noexcept {
|
|
typedef typename IntTraits<T>::SignedType SignedType;
|
|
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
|
|
|
if (IntTraits<T>::kIsSigned)
|
|
return sizeof(T) <= 4 || inInterval<SignedType>(SignedType(x), -2147483647 - 1, 2147483647);
|
|
else
|
|
return sizeof(T) <= 2 || UnsignedType(x) <= UnsignedType(2147483647U);
|
|
}
|
|
|
|
//! Get whether the given integer `x` can be casted to a 4-bit unsigned integer.
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool isUInt4(T x) noexcept {
|
|
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
|
|
|
if (IntTraits<T>::kIsSigned)
|
|
return x >= T(0) && x <= T(15);
|
|
else
|
|
return UnsignedType(x) <= UnsignedType(15U);
|
|
}
|
|
|
|
//! Get whether the given integer `x` can be casted to an 8-bit unsigned integer.
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool isUInt8(T x) noexcept {
|
|
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
|
|
|
if (IntTraits<T>::kIsSigned)
|
|
return x >= T(0) && (sizeof(T) <= 1 ? true : x <= T(255));
|
|
else
|
|
return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(255U);
|
|
}
|
|
|
|
//! Get whether the given integer `x` can be casted to a 12-bit unsigned integer (ARM specific).
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool isUInt12(T x) noexcept {
|
|
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
|
|
|
if (IntTraits<T>::kIsSigned)
|
|
return x >= T(0) && (sizeof(T) <= 1 ? true : x <= T(4095));
|
|
else
|
|
return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(4095U);
|
|
}
|
|
|
|
//! Get whether the given integer `x` can be casted to a 16-bit unsigned integer.
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool isUInt16(T x) noexcept {
|
|
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
|
|
|
if (IntTraits<T>::kIsSigned)
|
|
return x >= T(0) && (sizeof(T) <= 2 ? true : x <= T(65535));
|
|
else
|
|
return sizeof(T) <= 2 || UnsignedType(x) <= UnsignedType(65535U);
|
|
}
|
|
|
|
//! Get whether the given integer `x` can be casted to a 32-bit unsigned integer.
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool isUInt32(T x) noexcept {
|
|
typedef typename IntTraits<T>::UnsignedType UnsignedType;
|
|
|
|
if (IntTraits<T>::kIsSigned)
|
|
return x >= T(0) && (sizeof(T) <= 4 ? true : x <= T(4294967295U));
|
|
else
|
|
return sizeof(T) <= 4 || UnsignedType(x) <= UnsignedType(4294967295U);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [IsPowerOf2]
|
|
// --------------------------------------------------------------------------
|
|
|
|
//! Get whether the `n` value is a power of two (only one bit is set).
|
|
template<typename T>
|
|
static ASMJIT_INLINE bool isPowerOf2(T n) noexcept {
|
|
return n != 0 && (n & (n - 1)) == 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Mask]
|
|
// --------------------------------------------------------------------------
|
|
|
|
//! Generate a bit-mask that has `x` bit set.
|
|
static ASMJIT_INLINE uint32_t mask(uint32_t x) noexcept {
|
|
ASMJIT_ASSERT(x < 32);
|
|
return static_cast<uint32_t>(1) << x;
|
|
}
|
|
|
|
//! Generate a bit-mask that has `x0` and `x1` bits set.
|
|
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1) noexcept {
|
|
return mask(x0) | mask(x1);
|
|
}
|
|
|
|
//! Generate a bit-mask that has `x0`, `x1` and `x2` bits set.
|
|
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2) noexcept {
|
|
return mask(x0, x1) | mask(x2);
|
|
}
|
|
|
|
//! Generate a bit-mask that has `x0`, `x1`, `x2` and `x3` bits set.
|
|
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) noexcept {
|
|
return mask(x0, x1) | mask(x2, x3);
|
|
}
|
|
|
|
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3` and `x4` bits set.
|
|
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4) noexcept {
|
|
return mask(x0, x1) | mask(x2, x3) | mask(x4);
|
|
}
|
|
|
|
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4` and `x5` bits set.
|
|
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5) noexcept {
|
|
return mask(x0, x1) | mask(x2, x3) | mask(x4, x5);
|
|
}
|
|
|
|
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5` and `x6` bits set.
|
|
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6) noexcept {
|
|
return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6);
|
|
}
|
|
|
|
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6` and `x7` bits set.
|
|
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) noexcept {
|
|
return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6, x7);
|
|
}
|
|
|
|
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7` and `x8` bits set.
|
|
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8) noexcept {
|
|
return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6, x7) | mask(x8);
|
|
}
|
|
|
|
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7`, `x8` and `x9` bits set.
|
|
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8, uint32_t x9) noexcept {
|
|
return mask(x0, x1) | mask(x2, x3) | mask(x4, x5) | mask(x6, x7) | mask(x8, x9);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Bits]
|
|
// --------------------------------------------------------------------------
|
|
|
|
//! Generate a bit-mask that has `x` least significant bits set.
|
|
static ASMJIT_INLINE uint32_t bits(uint32_t x) noexcept {
|
|
// Shifting more bits than the type has results in undefined behavior. In
|
|
// such case asmjit trashes the result by ORing with `overflow` mask, which
|
|
// discards the undefined value returned by the shift.
|
|
uint32_t overflow = static_cast<uint32_t>(
|
|
-static_cast<int32_t>(x >= sizeof(uint32_t) * 8));
|
|
|
|
return ((static_cast<uint32_t>(1) << x) - 1U) | overflow;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [HasBit]
|
|
// --------------------------------------------------------------------------
|
|
|
|
//! Get whether `x` has bit `n` set.
|
|
template<typename T, typename Index>
|
|
static ASMJIT_INLINE bool hasBit(T x, Index n) noexcept {
|
|
return (x & (static_cast<T>(1) << n)) != 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [BitCount]
|
|
// --------------------------------------------------------------------------
|
|
|
|
static ASMJIT_INLINE uint32_t bitCountSlow(uint32_t x) noexcept {
|
|
// From: http://graphics.stanford.edu/~seander/bithacks.html
|
|
x = x - ((x >> 1) & 0x55555555U);
|
|
x = (x & 0x33333333U) + ((x >> 2) & 0x33333333U);
|
|
return (((x + (x >> 4)) & 0x0F0F0F0FU) * 0x01010101U) >> 24;
|
|
}
|
|
|
|
//! Get count of bits in `x`.
|
|
static ASMJIT_INLINE uint32_t bitCount(uint32_t x) noexcept {
|
|
#if ASMJIT_CC_GCC || ASMJIT_CC_CLANG
|
|
return __builtin_popcount(x);
|
|
#else
|
|
return bitCountSlow(x);
|
|
#endif
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [FirstBitOf]
|
|
// --------------------------------------------------------------------------
|
|
|
|
template<uint64_t In>
|
|
struct FirstBitOfTImpl {
|
|
enum {
|
|
_shift = (In & ASMJIT_UINT64_C(0x0000FFFFFFFFFFFF)) == 0 ? 48 :
|
|
(In & ASMJIT_UINT64_C(0x00000000FFFFFFFF)) == 0 ? 32 :
|
|
(In & ASMJIT_UINT64_C(0x000000000000FFFF)) == 0 ? 16 : 0,
|
|
|
|
kValue = ((In >> _shift) & 0x0001) ? (_shift + 0) :
|
|
((In >> _shift) & 0x0002) ? (_shift + 1) :
|
|
((In >> _shift) & 0x0004) ? (_shift + 2) :
|
|
((In >> _shift) & 0x0008) ? (_shift + 3) :
|
|
((In >> _shift) & 0x0010) ? (_shift + 4) :
|
|
((In >> _shift) & 0x0020) ? (_shift + 5) :
|
|
((In >> _shift) & 0x0040) ? (_shift + 6) :
|
|
((In >> _shift) & 0x0080) ? (_shift + 7) :
|
|
((In >> _shift) & 0x0100) ? (_shift + 8) :
|
|
((In >> _shift) & 0x0200) ? (_shift + 9) :
|
|
((In >> _shift) & 0x0400) ? (_shift + 10) :
|
|
((In >> _shift) & 0x0800) ? (_shift + 11) :
|
|
((In >> _shift) & 0x1000) ? (_shift + 12) :
|
|
((In >> _shift) & 0x2000) ? (_shift + 13) :
|
|
((In >> _shift) & 0x4000) ? (_shift + 14) :
|
|
((In >> _shift) & 0x8000) ? (_shift + 15) : 0
|
|
};
|
|
};
|
|
|
|
template<>
|
|
struct FirstBitOfTImpl<0> {};
|
|
|
|
template<uint64_t In>
|
|
static ASMJIT_INLINE uint32_t firstBitOfT() noexcept { return FirstBitOfTImpl<In>::kValue; }
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [FindFirstBit]
|
|
// --------------------------------------------------------------------------
|
|
|
|
//! \internal
|
|
static ASMJIT_INLINE uint32_t findFirstBitSlow(uint32_t mask) noexcept {
|
|
// This is a reference (slow) implementation of `findFirstBit()`, used when
|
|
// we don't have a C++ compiler support. The implementation speed has been
|
|
// improved to check for 2 bits per iteration.
|
|
uint32_t i = 1;
|
|
|
|
while (mask != 0) {
|
|
uint32_t two = mask & 0x3;
|
|
if (two != 0x0)
|
|
return i - (two & 0x1);
|
|
|
|
i += 2;
|
|
mask >>= 2;
|
|
}
|
|
|
|
return 0xFFFFFFFFU;
|
|
}
|
|
|
|
//! Find a first bit in `mask`.
|
|
static ASMJIT_INLINE uint32_t findFirstBit(uint32_t mask) noexcept {
|
|
#if ASMJIT_CC_MSC_GE(14, 0, 0) && (ASMJIT_ARCH_X86 || ASMJIT_ARCH_ARM32 || \
|
|
ASMJIT_ARCH_X64 || ASMJIT_ARCH_ARM64)
|
|
DWORD i;
|
|
if (_BitScanForward(&i, mask))
|
|
return static_cast<uint32_t>(i);
|
|
else
|
|
return 0xFFFFFFFFU;
|
|
#elif ASMJIT_CC_GCC_GE(3, 4, 6) || ASMJIT_CC_CLANG
|
|
if (mask)
|
|
return __builtin_ctz(mask);
|
|
else
|
|
return 0xFFFFFFFFU;
|
|
#else
|
|
return findFirstBitSlow(mask);
|
|
#endif
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Misc]
|
|
// --------------------------------------------------------------------------
|
|
|
|
static ASMJIT_INLINE uint32_t keepNOnesFromRight(uint32_t mask, uint32_t nBits) noexcept {
|
|
uint32_t m = 0x1;
|
|
|
|
do {
|
|
nBits -= (mask & m) != 0;
|
|
m <<= 1;
|
|
if (nBits == 0) {
|
|
m -= 1;
|
|
mask &= m;
|
|
break;
|
|
}
|
|
} while (m);
|
|
|
|
return mask;
|
|
}
|
|
|
|
static ASMJIT_INLINE uint32_t indexNOnesFromRight(uint8_t* dst, uint32_t mask, uint32_t nBits) noexcept {
|
|
uint32_t totalBits = nBits;
|
|
uint8_t i = 0;
|
|
uint32_t m = 0x1;
|
|
|
|
do {
|
|
if (mask & m) {
|
|
*dst++ = i;
|
|
if (--nBits == 0)
|
|
break;
|
|
}
|
|
|
|
m <<= 1;
|
|
i++;
|
|
} while (m);
|
|
|
|
return totalBits - nBits;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Alignment]
|
|
// --------------------------------------------------------------------------
|
|
|
|
template<typename X, typename Y>
|
|
static ASMJIT_INLINE bool isAligned(X base, Y alignment) noexcept {
|
|
typedef typename IntTraitsPrivate<sizeof(X), 0>::UnsignedType U;
|
|
return ((U)base % (U)alignment) == 0;
|
|
}
|
|
|
|
template<typename X, typename Y>
|
|
static ASMJIT_INLINE X alignTo(X x, Y alignment) noexcept {
|
|
typedef typename IntTraitsPrivate<sizeof(X), 0>::UnsignedType U;
|
|
return (X)( ((U)x + (U)(alignment - 1)) & ~(static_cast<U>(alignment) - 1) );
|
|
}
|
|
|
|
//! Get delta required to align `base` to `alignment`.
|
|
template<typename X, typename Y>
|
|
static ASMJIT_INLINE X alignDiff(X base, Y alignment) noexcept {
|
|
return alignTo(base, alignment) - base;
|
|
}
|
|
|
|
template<typename T>
|
|
static ASMJIT_INLINE T alignToPowerOf2(T base) noexcept {
|
|
// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.
|
|
base -= 1;
|
|
|
|
#if defined(_MSC_VER)
|
|
# pragma warning(push)
|
|
# pragma warning(disable: 4293)
|
|
#endif // _MSC_VER
|
|
|
|
base = base | (base >> 1);
|
|
base = base | (base >> 2);
|
|
base = base | (base >> 4);
|
|
|
|
// 8/16/32 constants are multiplied by the condition to prevent a compiler
|
|
// complaining about the 'shift count >= type width' (GCC).
|
|
if (sizeof(T) >= 2) base = base | (base >> ( 8 * (sizeof(T) >= 2))); // Base >> 8.
|
|
if (sizeof(T) >= 4) base = base | (base >> (16 * (sizeof(T) >= 4))); // Base >> 16.
|
|
if (sizeof(T) >= 8) base = base | (base >> (32 * (sizeof(T) >= 8))); // Base >> 32.
|
|
|
|
#if defined(_MSC_VER)
|
|
# pragma warning(pop)
|
|
#endif // _MSC_VER
|
|
|
|
return base + 1;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [String]
|
|
// --------------------------------------------------------------------------
|
|
|
|
static ASMJIT_INLINE size_t strLen(const char* s, size_t maxlen) noexcept {
|
|
size_t i;
|
|
for (i = 0; i < maxlen; i++)
|
|
if (!s[i])
|
|
break;
|
|
return i;
|
|
}
|
|
|
|
static ASMJIT_INLINE const char* findPackedString(const char* p, uint32_t id) noexcept {
|
|
uint32_t i = 0;
|
|
while (i < id) {
|
|
while (p[0])
|
|
p++;
|
|
p++;
|
|
i++;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
//! \internal
|
|
//!
|
|
//! Compare two instruction names.
|
|
//!
|
|
//! `a` is a null terminated instruction name from `???InstDB::nameData[]` table.
|
|
//! `b` is a non-null terminated instruction name passed to `???Inst::getIdByName()`.
|
|
static ASMJIT_INLINE int cmpInstName(const char* a, const char* b, size_t len) noexcept {
|
|
for (size_t i = 0; i < len; i++) {
|
|
int c = static_cast<int>(static_cast<uint8_t>(a[i])) -
|
|
static_cast<int>(static_cast<uint8_t>(b[i])) ;
|
|
if (c != 0) return c;
|
|
}
|
|
|
|
return static_cast<int>(a[len]);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [BSwap]
|
|
// --------------------------------------------------------------------------
|
|
|
|
static ASMJIT_INLINE uint32_t byteswap32(uint32_t x) noexcept {
|
|
#if ASMJIT_CC_MSC
|
|
return static_cast<uint32_t>(_byteswap_ulong(x));
|
|
#elif ASMJIT_CC_GCC_GE(4, 3, 0) || ASMJIT_CC_CLANG_GE(2, 6, 0)
|
|
return __builtin_bswap32(x);
|
|
#else
|
|
uint32_t y = x & 0x00FFFF00U;
|
|
x = (x << 24) + (x >> 24);
|
|
y = (y << 8) + (y >> 8);
|
|
return x + (y & 0x00FFFF00U);
|
|
#endif
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [ReadMem]
|
|
// --------------------------------------------------------------------------
|
|
|
|
static ASMJIT_INLINE uint32_t readU8(const void* p) noexcept {
|
|
return static_cast<uint32_t>(static_cast<const uint8_t*>(p)[0]);
|
|
}
|
|
|
|
static ASMJIT_INLINE int32_t readI8(const void* p) noexcept {
|
|
return static_cast<int32_t>(static_cast<const int8_t*>(p)[0]);
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE uint32_t readU16xLE(const void* p) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
|
|
return static_cast<uint32_t>(static_cast<const uint16_t*>(p)[0]);
|
|
}
|
|
else {
|
|
uint32_t x = static_cast<uint32_t>(static_cast<const uint8_t*>(p)[0]);
|
|
uint32_t y = static_cast<uint32_t>(static_cast<const uint8_t*>(p)[1]);
|
|
return x + (y << 8);
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE uint32_t readU16xBE(const void* p) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
|
|
return static_cast<uint32_t>(static_cast<const uint16_t*>(p)[0]);
|
|
}
|
|
else {
|
|
uint32_t x = static_cast<uint32_t>(static_cast<const uint8_t*>(p)[0]);
|
|
uint32_t y = static_cast<uint32_t>(static_cast<const uint8_t*>(p)[1]);
|
|
return (x << 8) + y;
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE uint32_t readU16x(const void* p) noexcept {
|
|
return ASMJIT_ARCH_LE ? readU16xLE<Alignment>(p) : readU16xBE<Alignment>(p);
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE int32_t readI16xLE(const void* p) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
|
|
return static_cast<int32_t>(static_cast<const int16_t*>(p)[0]);
|
|
}
|
|
else {
|
|
int32_t x = static_cast<int32_t>(static_cast<const uint8_t*>(p)[0]);
|
|
int32_t y = static_cast<int32_t>(static_cast<const int8_t*>(p)[1]);
|
|
return x + (y << 8);
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE int32_t readI16xBE(const void* p) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
|
|
return static_cast<int32_t>(static_cast<const int16_t*>(p)[0]);
|
|
}
|
|
else {
|
|
int32_t x = static_cast<int32_t>(static_cast<const int8_t*>(p)[0]);
|
|
int32_t y = static_cast<int32_t>(static_cast<const uint8_t*>(p)[1]);
|
|
return (x << 8) + y;
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE int32_t readI16x(const void* p) noexcept {
|
|
return ASMJIT_ARCH_LE ? readI16xLE<Alignment>(p) : readI16xBE<Alignment>(p);
|
|
}
|
|
|
|
static ASMJIT_INLINE uint32_t readU16aLE(const void* p) noexcept { return readU16xLE<2>(p); }
|
|
static ASMJIT_INLINE uint32_t readU16uLE(const void* p) noexcept { return readU16xLE<0>(p); }
|
|
|
|
static ASMJIT_INLINE uint32_t readU16aBE(const void* p) noexcept { return readU16xBE<2>(p); }
|
|
static ASMJIT_INLINE uint32_t readU16uBE(const void* p) noexcept { return readU16xBE<0>(p); }
|
|
|
|
static ASMJIT_INLINE uint32_t readU16a(const void* p) noexcept { return readU16x<2>(p); }
|
|
static ASMJIT_INLINE uint32_t readU16u(const void* p) noexcept { return readU16x<0>(p); }
|
|
|
|
static ASMJIT_INLINE int32_t readI16aLE(const void* p) noexcept { return readI16xLE<2>(p); }
|
|
static ASMJIT_INLINE int32_t readI16uLE(const void* p) noexcept { return readI16xLE<0>(p); }
|
|
|
|
static ASMJIT_INLINE int32_t readI16aBE(const void* p) noexcept { return readI16xBE<2>(p); }
|
|
static ASMJIT_INLINE int32_t readI16uBE(const void* p) noexcept { return readI16xBE<0>(p); }
|
|
|
|
static ASMJIT_INLINE int32_t readI16a(const void* p) noexcept { return readI16x<2>(p); }
|
|
static ASMJIT_INLINE int32_t readI16u(const void* p) noexcept { return readI16x<0>(p); }
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE uint32_t readU32xLE(const void* p) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) {
|
|
uint32_t x = static_cast<const uint32_t*>(p)[0];
|
|
return ASMJIT_ARCH_LE ? x : byteswap32(x);
|
|
}
|
|
else {
|
|
uint32_t x = readU16xLE<Alignment>(static_cast<const uint8_t*>(p) + 0);
|
|
uint32_t y = readU16xLE<Alignment>(static_cast<const uint8_t*>(p) + 2);
|
|
return x + (y << 16);
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE uint32_t readU32xBE(const void* p) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) {
|
|
uint32_t x = static_cast<const uint32_t*>(p)[0];
|
|
return ASMJIT_ARCH_BE ? x : byteswap32(x);
|
|
}
|
|
else {
|
|
uint32_t x = readU16xBE<Alignment>(static_cast<const uint8_t*>(p) + 0);
|
|
uint32_t y = readU16xBE<Alignment>(static_cast<const uint8_t*>(p) + 2);
|
|
return (x << 16) + y;
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE uint32_t readU32x(const void* p) noexcept {
|
|
return ASMJIT_ARCH_LE ? readU32xLE<Alignment>(p) : readU32xBE<Alignment>(p);
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE int32_t readI32xLE(const void* p) noexcept {
|
|
return static_cast<int32_t>(readU32xLE<Alignment>(p));
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE int32_t readI32xBE(const void* p) noexcept {
|
|
return static_cast<int32_t>(readU32xBE<Alignment>(p));
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE int32_t readI32x(const void* p) noexcept {
|
|
return ASMJIT_ARCH_LE ? readI32xLE<Alignment>(p) : readI32xBE<Alignment>(p);
|
|
}
|
|
|
|
static ASMJIT_INLINE uint32_t readU32a(const void* p) noexcept { return readU32x<4>(p); }
|
|
static ASMJIT_INLINE uint32_t readU32u(const void* p) noexcept { return readU32x<0>(p); }
|
|
|
|
static ASMJIT_INLINE uint32_t readU32aLE(const void* p) noexcept { return readU32xLE<4>(p); }
|
|
static ASMJIT_INLINE uint32_t readU32uLE(const void* p) noexcept { return readU32xLE<0>(p); }
|
|
|
|
static ASMJIT_INLINE uint32_t readU32aBE(const void* p) noexcept { return readU32xBE<4>(p); }
|
|
static ASMJIT_INLINE uint32_t readU32uBE(const void* p) noexcept { return readU32xBE<0>(p); }
|
|
|
|
static ASMJIT_INLINE int32_t readI32a(const void* p) noexcept { return readI32x<4>(p); }
|
|
static ASMJIT_INLINE int32_t readI32u(const void* p) noexcept { return readI32x<0>(p); }
|
|
|
|
static ASMJIT_INLINE int32_t readI32aLE(const void* p) noexcept { return readI32xLE<4>(p); }
|
|
static ASMJIT_INLINE int32_t readI32uLE(const void* p) noexcept { return readI32xLE<0>(p); }
|
|
|
|
static ASMJIT_INLINE int32_t readI32aBE(const void* p) noexcept { return readI32xBE<4>(p); }
|
|
static ASMJIT_INLINE int32_t readI32uBE(const void* p) noexcept { return readI32xBE<0>(p); }
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE uint64_t readU64xLE(const void* p) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) {
|
|
return static_cast<const uint64_t*>(p)[0];
|
|
}
|
|
else {
|
|
uint32_t x = readU32xLE<Alignment / 2U>(static_cast<const uint8_t*>(p) + 0);
|
|
uint32_t y = readU32xLE<Alignment / 2U>(static_cast<const uint8_t*>(p) + 4);
|
|
return static_cast<uint64_t>(x) + (static_cast<uint64_t>(y) << 32);
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE uint64_t readU64xBE(const void* p) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) {
|
|
return static_cast<const uint64_t*>(p)[0];
|
|
}
|
|
else {
|
|
uint32_t x = readU32xLE<Alignment / 2U>(static_cast<const uint8_t*>(p) + 0);
|
|
uint32_t y = readU32xLE<Alignment / 2U>(static_cast<const uint8_t*>(p) + 4);
|
|
return (static_cast<uint64_t>(x) << 32) + static_cast<uint64_t>(y);
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE uint64_t readU64x(const void* p) noexcept {
|
|
return ASMJIT_ARCH_LE ? readU64xLE<Alignment>(p) : readU64xBE<Alignment>(p);
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE int64_t readI64xLE(const void* p) noexcept {
|
|
return static_cast<int64_t>(readU64xLE<Alignment>(p));
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE int64_t readI64xBE(const void* p) noexcept {
|
|
return static_cast<int64_t>(readU64xBE<Alignment>(p));
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE int64_t readI64x(const void* p) noexcept {
|
|
return ASMJIT_ARCH_LE ? readI64xLE<Alignment>(p) : readI64xBE<Alignment>(p);
|
|
}
|
|
|
|
static ASMJIT_INLINE uint64_t readU64a(const void* p) noexcept { return readU64x<8>(p); }
|
|
static ASMJIT_INLINE uint64_t readU64u(const void* p) noexcept { return readU64x<0>(p); }
|
|
|
|
static ASMJIT_INLINE uint64_t readU64aLE(const void* p) noexcept { return readU64xLE<8>(p); }
|
|
static ASMJIT_INLINE uint64_t readU64uLE(const void* p) noexcept { return readU64xLE<0>(p); }
|
|
|
|
static ASMJIT_INLINE uint64_t readU64aBE(const void* p) noexcept { return readU64xBE<8>(p); }
|
|
static ASMJIT_INLINE uint64_t readU64uBE(const void* p) noexcept { return readU64xBE<0>(p); }
|
|
|
|
static ASMJIT_INLINE int64_t readI64a(const void* p) noexcept { return readI64x<8>(p); }
|
|
static ASMJIT_INLINE int64_t readI64u(const void* p) noexcept { return readI64x<0>(p); }
|
|
|
|
static ASMJIT_INLINE int64_t readI64aLE(const void* p) noexcept { return readI64xLE<8>(p); }
|
|
static ASMJIT_INLINE int64_t readI64uLE(const void* p) noexcept { return readI64xLE<0>(p); }
|
|
|
|
static ASMJIT_INLINE int64_t readI64aBE(const void* p) noexcept { return readI64xBE<8>(p); }
|
|
static ASMJIT_INLINE int64_t readI64uBE(const void* p) noexcept { return readI64xBE<0>(p); }
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [WriteMem]
|
|
// --------------------------------------------------------------------------
|
|
|
|
static ASMJIT_INLINE void writeU8(void* p, uint32_t x) noexcept {
|
|
static_cast<uint8_t*>(p)[0] = static_cast<uint8_t>(x & 0xFFU);
|
|
}
|
|
|
|
static ASMJIT_INLINE void writeI8(void* p, int32_t x) noexcept {
|
|
static_cast<uint8_t*>(p)[0] = static_cast<uint8_t>(x & 0xFF);
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeU16xLE(void* p, uint32_t x) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
|
|
static_cast<uint16_t*>(p)[0] = static_cast<uint16_t>(x & 0xFFFFU);
|
|
}
|
|
else {
|
|
static_cast<uint8_t*>(p)[0] = static_cast<uint8_t>((x ) & 0xFFU);
|
|
static_cast<uint8_t*>(p)[1] = static_cast<uint8_t>((x >> 8) & 0xFFU);
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeU16xBE(void* p, uint32_t x) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
|
|
static_cast<uint16_t*>(p)[0] = static_cast<uint16_t>(x & 0xFFFFU);
|
|
}
|
|
else {
|
|
static_cast<uint8_t*>(p)[0] = static_cast<uint8_t>((x >> 8) & 0xFFU);
|
|
static_cast<uint8_t*>(p)[1] = static_cast<uint8_t>((x ) & 0xFFU);
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeU16x(void* p, uint32_t x) noexcept {
|
|
if (ASMJIT_ARCH_LE)
|
|
writeU16xLE<Alignment>(p, x);
|
|
else
|
|
writeU16xBE<Alignment>(p, x);
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeI16xLE(void* p, int32_t x) noexcept {
|
|
writeU16xLE<Alignment>(p, static_cast<uint32_t>(x));
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeI16xBE(void* p, int32_t x) noexcept {
|
|
writeU16xBE<Alignment>(p, static_cast<uint32_t>(x));
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeI16x(void* p, int32_t x) noexcept {
|
|
writeU16x<Alignment>(p, static_cast<uint32_t>(x));
|
|
}
|
|
|
|
static ASMJIT_INLINE void writeU16aLE(void* p, uint32_t x) noexcept { writeU16xLE<2>(p, x); }
|
|
static ASMJIT_INLINE void writeU16uLE(void* p, uint32_t x) noexcept { writeU16xLE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeU16aBE(void* p, uint32_t x) noexcept { writeU16xBE<2>(p, x); }
|
|
static ASMJIT_INLINE void writeU16uBE(void* p, uint32_t x) noexcept { writeU16xBE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeU16a(void* p, uint32_t x) noexcept { writeU16x<2>(p, x); }
|
|
static ASMJIT_INLINE void writeU16u(void* p, uint32_t x) noexcept { writeU16x<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeI16aLE(void* p, int32_t x) noexcept { writeI16xLE<2>(p, x); }
|
|
static ASMJIT_INLINE void writeI16uLE(void* p, int32_t x) noexcept { writeI16xLE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeI16aBE(void* p, int32_t x) noexcept { writeI16xBE<2>(p, x); }
|
|
static ASMJIT_INLINE void writeI16uBE(void* p, int32_t x) noexcept { writeI16xBE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeI16a(void* p, int32_t x) noexcept { writeI16x<2>(p, x); }
|
|
static ASMJIT_INLINE void writeI16u(void* p, int32_t x) noexcept { writeI16x<0>(p, x); }
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeU32xLE(void* p, uint32_t x) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) {
|
|
static_cast<uint32_t*>(p)[0] = ASMJIT_ARCH_LE ? x : byteswap32(x);
|
|
}
|
|
else {
|
|
writeU16xLE<Alignment>(static_cast<uint8_t*>(p) + 0, x >> 16);
|
|
writeU16xLE<Alignment>(static_cast<uint8_t*>(p) + 2, x);
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeU32xBE(void* p, uint32_t x) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) {
|
|
static_cast<uint32_t*>(p)[0] = ASMJIT_ARCH_BE ? x : byteswap32(x);
|
|
}
|
|
else {
|
|
writeU16xBE<Alignment>(static_cast<uint8_t*>(p) + 0, x);
|
|
writeU16xBE<Alignment>(static_cast<uint8_t*>(p) + 2, x >> 16);
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeU32x(void* p, uint32_t x) noexcept {
|
|
if (ASMJIT_ARCH_LE)
|
|
writeU32xLE<Alignment>(p, x);
|
|
else
|
|
writeU32xBE<Alignment>(p, x);
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeI32xLE(void* p, int32_t x) noexcept {
|
|
writeU32xLE<Alignment>(p, static_cast<uint32_t>(x));
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeI32xBE(void* p, int32_t x) noexcept {
|
|
writeU32xBE<Alignment>(p, static_cast<uint32_t>(x));
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeI32x(void* p, int32_t x) noexcept {
|
|
writeU32x<Alignment>(p, static_cast<uint32_t>(x));
|
|
}
|
|
|
|
static ASMJIT_INLINE void writeU32aLE(void* p, uint32_t x) noexcept { writeU32xLE<4>(p, x); }
|
|
static ASMJIT_INLINE void writeU32uLE(void* p, uint32_t x) noexcept { writeU32xLE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeU32aBE(void* p, uint32_t x) noexcept { writeU32xBE<4>(p, x); }
|
|
static ASMJIT_INLINE void writeU32uBE(void* p, uint32_t x) noexcept { writeU32xBE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeU32a(void* p, uint32_t x) noexcept { writeU32x<4>(p, x); }
|
|
static ASMJIT_INLINE void writeU32u(void* p, uint32_t x) noexcept { writeU32x<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeI32aLE(void* p, int32_t x) noexcept { writeI32xLE<4>(p, x); }
|
|
static ASMJIT_INLINE void writeI32uLE(void* p, int32_t x) noexcept { writeI32xLE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeI32aBE(void* p, int32_t x) noexcept { writeI32xBE<4>(p, x); }
|
|
static ASMJIT_INLINE void writeI32uBE(void* p, int32_t x) noexcept { writeI32xBE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeI32a(void* p, int32_t x) noexcept { writeI32x<4>(p, x); }
|
|
static ASMJIT_INLINE void writeI32u(void* p, int32_t x) noexcept { writeI32x<0>(p, x); }
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeU64xLE(void* p, uint64_t x) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) {
|
|
static_cast<uint64_t*>(p)[0] = x;
|
|
}
|
|
else {
|
|
writeU32xLE<Alignment / 2U>(static_cast<uint8_t*>(p) + 0, static_cast<uint32_t>(x >> 32));
|
|
writeU32xLE<Alignment / 2U>(static_cast<uint8_t*>(p) + 4, static_cast<uint32_t>(x & 0xFFFFFFFFU));
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeU64xBE(void* p, uint64_t x) noexcept {
|
|
ASMJIT_ASSUME_ALIGNED(p, Alignment > 1 ? Alignment : 1U);
|
|
if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) {
|
|
static_cast<uint64_t*>(p)[0] = x;
|
|
}
|
|
else {
|
|
writeU32xBE<Alignment / 2U>(static_cast<uint8_t*>(p) + 0, static_cast<uint32_t>(x & 0xFFFFFFFFU));
|
|
writeU32xBE<Alignment / 2U>(static_cast<uint8_t*>(p) + 4, static_cast<uint32_t>(x >> 32));
|
|
}
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeU64x(void* p, uint64_t x) noexcept {
|
|
if (ASMJIT_ARCH_LE)
|
|
writeU64xLE<Alignment>(p, x);
|
|
else
|
|
writeU64xBE<Alignment>(p, x);
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeI64xLE(void* p, int64_t x) noexcept {
|
|
writeU64xLE<Alignment>(p, static_cast<uint64_t>(x));
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeI64xBE(void* p, int64_t x) noexcept {
|
|
writeU64xBE<Alignment>(p, static_cast<uint64_t>(x));
|
|
}
|
|
|
|
template<unsigned int Alignment>
|
|
static ASMJIT_INLINE void writeI64x(void* p, int64_t x) noexcept {
|
|
writeU64x<Alignment>(p, static_cast<uint64_t>(x));
|
|
}
|
|
|
|
static ASMJIT_INLINE void writeU64aLE(void* p, uint64_t x) noexcept { writeU64xLE<8>(p, x); }
|
|
static ASMJIT_INLINE void writeU64uLE(void* p, uint64_t x) noexcept { writeU64xLE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeU64aBE(void* p, uint64_t x) noexcept { writeU64xBE<8>(p, x); }
|
|
static ASMJIT_INLINE void writeU64uBE(void* p, uint64_t x) noexcept { writeU64xBE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeU64a(void* p, uint64_t x) noexcept { writeU64x<8>(p, x); }
|
|
static ASMJIT_INLINE void writeU64u(void* p, uint64_t x) noexcept { writeU64x<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeI64aLE(void* p, int64_t x) noexcept { writeI64xLE<8>(p, x); }
|
|
static ASMJIT_INLINE void writeI64uLE(void* p, int64_t x) noexcept { writeI64xLE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeI64aBE(void* p, int64_t x) noexcept { writeI64xBE<8>(p, x); }
|
|
static ASMJIT_INLINE void writeI64uBE(void* p, int64_t x) noexcept { writeI64xBE<0>(p, x); }
|
|
|
|
static ASMJIT_INLINE void writeI64a(void* p, int64_t x) noexcept { writeI64x<8>(p, x); }
|
|
static ASMJIT_INLINE void writeI64u(void* p, int64_t x) noexcept { writeI64x<0>(p, x); }
|
|
} // Utils namespace
|
|
|
|
// ============================================================================
|
|
// [asmjit::UInt64]
|
|
// ============================================================================
|
|
|
|
union UInt64 {
|
|
// --------------------------------------------------------------------------
|
|
// [Construction / Destruction]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE UInt64 fromUInt64(uint64_t val) noexcept {
|
|
UInt64 data;
|
|
data.setUInt64(val);
|
|
return data;
|
|
}
|
|
|
|
ASMJIT_INLINE UInt64 fromUInt64(const UInt64& val) noexcept {
|
|
UInt64 data;
|
|
data.setUInt64(val);
|
|
return data;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Reset]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE void reset() noexcept {
|
|
if (ASMJIT_ARCH_64BIT) {
|
|
u64 = 0;
|
|
}
|
|
else {
|
|
u32[0] = 0;
|
|
u32[1] = 0;
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Accessors]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE uint64_t getUInt64() const noexcept {
|
|
return u64;
|
|
}
|
|
|
|
ASMJIT_INLINE UInt64& setUInt64(uint64_t val) noexcept {
|
|
u64 = val;
|
|
return *this;
|
|
}
|
|
|
|
ASMJIT_INLINE UInt64& setUInt64(const UInt64& val) noexcept {
|
|
if (ASMJIT_ARCH_64BIT) {
|
|
u64 = val.u64;
|
|
}
|
|
else {
|
|
u32[0] = val.u32[0];
|
|
u32[1] = val.u32[1];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
ASMJIT_INLINE UInt64& setPacked_2x32(uint32_t u0, uint32_t u1) noexcept {
|
|
if (ASMJIT_ARCH_64BIT) {
|
|
u64 = Utils::pack64_2x32(u0, u1);
|
|
}
|
|
else {
|
|
u32[0] = u0;
|
|
u32[1] = u1;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Add]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE UInt64& add(uint64_t val) noexcept {
|
|
u64 += val;
|
|
return *this;
|
|
}
|
|
|
|
ASMJIT_INLINE UInt64& add(const UInt64& val) noexcept {
|
|
if (ASMJIT_ARCH_64BIT) {
|
|
u64 += val.u64;
|
|
}
|
|
else {
|
|
u32[0] += val.u32[0];
|
|
u32[1] += val.u32[1];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Sub]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE UInt64& sub(uint64_t val) noexcept {
|
|
u64 -= val;
|
|
return *this;
|
|
}
|
|
|
|
ASMJIT_INLINE UInt64& sub(const UInt64& val) noexcept {
|
|
if (ASMJIT_ARCH_64BIT) {
|
|
u64 -= val.u64;
|
|
}
|
|
else {
|
|
u32[0] -= val.u32[0];
|
|
u32[1] -= val.u32[1];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [And]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE UInt64& and_(uint64_t val) noexcept {
|
|
u64 &= val;
|
|
return *this;
|
|
}
|
|
|
|
ASMJIT_INLINE UInt64& and_(const UInt64& val) noexcept {
|
|
if (ASMJIT_ARCH_64BIT) {
|
|
u64 &= val.u64;
|
|
}
|
|
else {
|
|
u32[0] &= val.u32[0];
|
|
u32[1] &= val.u32[1];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [AndNot]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE UInt64& andNot(uint64_t val) noexcept {
|
|
u64 &= ~val;
|
|
return *this;
|
|
}
|
|
|
|
ASMJIT_INLINE UInt64& andNot(const UInt64& val) noexcept {
|
|
if (ASMJIT_ARCH_64BIT) {
|
|
u64 &= ~val.u64;
|
|
}
|
|
else {
|
|
u32[0] &= ~val.u32[0];
|
|
u32[1] &= ~val.u32[1];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Or]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE UInt64& or_(uint64_t val) noexcept {
|
|
u64 |= val;
|
|
return *this;
|
|
}
|
|
|
|
ASMJIT_INLINE UInt64& or_(const UInt64& val) noexcept {
|
|
if (ASMJIT_ARCH_64BIT) {
|
|
u64 |= val.u64;
|
|
}
|
|
else {
|
|
u32[0] |= val.u32[0];
|
|
u32[1] |= val.u32[1];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Xor]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE UInt64& xor_(uint64_t val) noexcept {
|
|
u64 ^= val;
|
|
return *this;
|
|
}
|
|
|
|
ASMJIT_INLINE UInt64& xor_(const UInt64& val) noexcept {
|
|
if (ASMJIT_ARCH_64BIT) {
|
|
u64 ^= val.u64;
|
|
}
|
|
else {
|
|
u32[0] ^= val.u32[0];
|
|
u32[1] ^= val.u32[1];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Eq]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE bool isZero() const noexcept {
|
|
if (ASMJIT_ARCH_64BIT)
|
|
return u64 == 0;
|
|
else
|
|
return (u32[0] | u32[1]) == 0;
|
|
}
|
|
|
|
ASMJIT_INLINE bool isNonZero() const noexcept {
|
|
if (ASMJIT_ARCH_64BIT)
|
|
return u64 != 0;
|
|
else
|
|
return (u32[0] | u32[1]) != 0;
|
|
}
|
|
|
|
ASMJIT_INLINE bool eq(uint64_t val) const noexcept {
|
|
return u64 == val;
|
|
}
|
|
|
|
ASMJIT_INLINE bool eq(const UInt64& val) const noexcept {
|
|
if (ASMJIT_ARCH_64BIT)
|
|
return u64 == val.u64;
|
|
else
|
|
return u32[0] == val.u32[0] && u32[1] == val.u32[1];
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Operator Overload]
|
|
// --------------------------------------------------------------------------
|
|
|
|
ASMJIT_INLINE UInt64& operator+=(uint64_t val) noexcept { return add(val); }
|
|
ASMJIT_INLINE UInt64& operator+=(const UInt64& val) noexcept { return add(val); }
|
|
|
|
ASMJIT_INLINE UInt64& operator-=(uint64_t val) noexcept { return sub(val); }
|
|
ASMJIT_INLINE UInt64& operator-=(const UInt64& val) noexcept { return sub(val); }
|
|
|
|
ASMJIT_INLINE UInt64& operator&=(uint64_t val) noexcept { return and_(val); }
|
|
ASMJIT_INLINE UInt64& operator&=(const UInt64& val) noexcept { return and_(val); }
|
|
|
|
ASMJIT_INLINE UInt64& operator|=(uint64_t val) noexcept { return or_(val); }
|
|
ASMJIT_INLINE UInt64& operator|=(const UInt64& val) noexcept { return or_(val); }
|
|
|
|
ASMJIT_INLINE UInt64& operator^=(uint64_t val) noexcept { return xor_(val); }
|
|
ASMJIT_INLINE UInt64& operator^=(const UInt64& val) noexcept { return xor_(val); }
|
|
|
|
ASMJIT_INLINE bool operator==(uint64_t val) const noexcept { return eq(val); }
|
|
ASMJIT_INLINE bool operator==(const UInt64& val) const noexcept { return eq(val); }
|
|
|
|
ASMJIT_INLINE bool operator!=(uint64_t val) const noexcept { return !eq(val); }
|
|
ASMJIT_INLINE bool operator!=(const UInt64& val) const noexcept { return !eq(val); }
|
|
|
|
ASMJIT_INLINE bool operator<(uint64_t val) const noexcept { return u64 < val; }
|
|
ASMJIT_INLINE bool operator<(const UInt64& val) const noexcept { return u64 < val.u64; }
|
|
|
|
ASMJIT_INLINE bool operator<=(uint64_t val) const noexcept { return u64 <= val; }
|
|
ASMJIT_INLINE bool operator<=(const UInt64& val) const noexcept { return u64 <= val.u64; }
|
|
|
|
ASMJIT_INLINE bool operator>(uint64_t val) const noexcept { return u64 > val; }
|
|
ASMJIT_INLINE bool operator>(const UInt64& val) const noexcept { return u64 > val.u64; }
|
|
|
|
ASMJIT_INLINE bool operator>=(uint64_t val) const noexcept { return u64 >= val; }
|
|
ASMJIT_INLINE bool operator>=(const UInt64& val) const noexcept { return u64 >= val.u64; }
|
|
|
|
// --------------------------------------------------------------------------
|
|
// [Members]
|
|
// --------------------------------------------------------------------------
|
|
|
|
int8_t i8[8]; //!< 8-bit signed integer (8x).
|
|
uint8_t u8[8]; //!< 8-bit unsigned integer (8x).
|
|
|
|
int16_t i16[4]; //!< 16-bit signed integer (4x).
|
|
uint16_t u16[4]; //!< 16-bit unsigned integer (4x).
|
|
|
|
int32_t i32[2]; //!< 32-bit signed integer (2x).
|
|
uint32_t u32[2]; //!< 32-bit unsigned integer (2x).
|
|
|
|
int64_t i64; //!< 64-bit signed integer.
|
|
uint64_t u64; //!< 64-bit unsigned integer.
|
|
|
|
float f32[2]; //!< 32-bit floating point (2x).
|
|
double f64; //!< 64-bit floating point.
|
|
|
|
#if ASMJIT_ARCH_LE
|
|
struct { float f32Lo, f32Hi; };
|
|
struct { int32_t i32Lo, i32Hi; };
|
|
struct { uint32_t u32Lo, u32Hi; };
|
|
#else
|
|
struct { float f32Hi, f32Lo; };
|
|
struct { int32_t i32Hi, i32Lo; };
|
|
struct { uint32_t u32Hi, u32Lo; };
|
|
#endif // ASMJIT_ARCH_LE
|
|
};
|
|
|
|
//! \}
|
|
|
|
} // asmjit namespace
|
|
|
|
// [Api-End]
|
|
#include "../asmjit_apiend.h"
|
|
|
|
// [Guard]
|
|
#endif // _ASMJIT_BASE_UTILS_H
|