Moved calling conventions to globals.h

Fixed #128
This commit is contained in:
kobalicek
2016-04-16 14:43:52 +02:00
parent f7ddd38777
commit 9fc1dbfdcd
9 changed files with 501 additions and 430 deletions

View File

@@ -23,366 +23,6 @@ namespace asmjit {
//! \addtogroup asmjit_base //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================
// [asmjit::CallConv]
// ============================================================================
//! Function calling convention.
//!
//! Calling convention is a scheme that defines how function arguments are
//! passed and how the return value handled. In assembler programming it's
//! always needed to comply with function calling conventions, because even
//! small inconsistency can cause undefined behavior or application's crash.
//!
//! Platform Independent Conventions
//! --------------------------------
//!
//! - `kCallConvHost` - Should match the current C++ compiler native calling
//! convention.
//!
//! X86/X64 Specific Conventions
//! ----------------------------
//!
//! List of calling conventions for 32-bit x86 mode:
//! - `kCallConvX86CDecl` - Calling convention for C runtime.
//! - `kCallConvX86StdCall` - Calling convention for WinAPI functions.
//! - `kCallConvX86MsThisCall` - Calling convention for C++ members under
//! Windows (produced by MSVC and all MSVC compatible compilers).
//! - `kCallConvX86MsFastCall` - Fastest calling convention that can be used
//! by MSVC compiler.
//! - `kCallConvX86BorlandFastCall` - Borland fastcall convention.
//! - `kCallConvX86GccFastCall` - GCC fastcall convention (2 register arguments).
//! - `kCallConvX86GccRegParm1` - GCC regparm(1) convention.
//! - `kCallConvX86GccRegParm2` - GCC regparm(2) convention.
//! - `kCallConvX86GccRegParm3` - GCC regparm(3) convention.
//!
//! List of calling conventions for 64-bit x86 mode (x64):
//! - `kCallConvX64Win` - Windows 64-bit calling convention (WIN64 ABI).
//! - `kCallConvX64Unix` - Unix 64-bit calling convention (AMD64 ABI).
//!
//! ARM Specific Conventions
//! ------------------------
//!
//! List of ARM calling conventions:
//! - `kCallConvArm32SoftFP` - Legacy calling convention, floating point
//! arguments are passed via GP registers.
//! - `kCallConvArm32HardFP` - Modern calling convention, uses VFP registers
//! to pass floating point arguments.
ASMJIT_ENUM(CallConv) {
//! Calling convention is invalid (can't be used).
kCallConvNone = 0,
// --------------------------------------------------------------------------
// [X86]
// --------------------------------------------------------------------------
//! X86 `__cdecl` calling convention (used by C runtime and libraries).
//!
//! Compatible across MSVC and GCC.
//!
//! Arguments direction:
//! - Right to left.
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86CDecl = 1,
//! X86 `__stdcall` calling convention (used mostly by WinAPI).
//!
//! Compatible across MSVC and GCC.
//!
//! Arguments direction:
//! - Right to left.
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86StdCall = 2,
//! X86 `__thiscall` calling convention (MSVC/Intel specific).
//!
//! This is MSVC (and Intel) specific calling convention used when targetting
//! Windows platform for C++ class methods. Implicit `this` pointer (defined
//! as the first argument) is stored in `ecx` register instead of storing it
//! on the stack.
//!
//! This calling convention is implicitly used by MSVC for class functions.
//!
//! C++ class functions that have variable number of arguments use `__cdecl`
//! calling convention instead.
//!
//! Arguments direction:
//! - Right to left (except for the first argument passed in `ecx`).
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86MsThisCall = 3,
//! X86 `__fastcall` convention (MSVC/Intel specific).
//!
//! The first two arguments (evaluated from the left to the right) are passed
//! in `ecx` and `edx` registers, all others on the stack from the right to
//! the left.
//!
//! Arguments direction:
//! - Right to left (except for the first two integers passed in `ecx` and `edx`).
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
//!
//! NOTE: This calling convention differs from GCC's one.
kCallConvX86MsFastCall = 4,
//! X86 `__fastcall` convention (Borland specific).
//!
//! The first two arguments (evaluated from the left to the right) are passed
//! in `ecx` and `edx` registers, all others on the stack from the left to
//! the right.
//!
//! Arguments direction:
//! - Left to right (except for the first two integers passed in `ecx` and `edx`).
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
//!
//! NOTE: Arguments on the stack are in passed in left to right order, which
//! is really Borland specific, all other `__fastcall` calling conventions
//! use right to left order.
kCallConvX86BorlandFastCall = 5,
//! X86 `__fastcall` convention (GCC specific).
//!
//! The first two arguments (evaluated from the left to the right) are passed
//! in `ecx` and `edx` registers, all others on the stack from the right to
//! the left.
//!
//! Arguments direction:
//! - Right to left (except for the first two integers passed in `ecx` and `edx`).
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
//!
//! NOTE: This calling convention should be compatible with `kCallConvX86MsFastCall`.
kCallConvX86GccFastCall = 6,
//! X86 `regparm(1)` convention (GCC specific).
//!
//! The first argument (evaluated from the left to the right) is passed in
//! `eax` register, all others on the stack from the right to the left.
//!
//! Arguments direction:
//! - Right to left (except for the first integer passed in `eax`).
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86GccRegParm1 = 7,
//! X86 `regparm(2)` convention (GCC specific).
//!
//! The first two arguments (evaluated from the left to the right) are passed
//! in `ecx` and `edx` registers, all others on the stack from the right to
//! the left.
//!
//! Arguments direction:
//! - Right to left (except for the first two integers passed in `ecx` and `edx`).
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86GccRegParm2 = 8,
//! X86 `regparm(3)` convention (GCC specific).
//!
//! Three first parameters (evaluated from left-to-right) are in
//! EAX:EDX:ECX registers, all others on the stack in right-to-left direction.
//!
//! Arguments direction:
//! - Right to left (except for the first three integers passed in `ecx`,
//! `edx`, and `ecx`).
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86GccRegParm3 = 9,
// --------------------------------------------------------------------------
// [X64]
// --------------------------------------------------------------------------
//! X64 calling convention used by Windows platform (WIN64-ABI).
//!
//! The first 4 arguments are passed in the following registers:
//! - 1. 32/64-bit integer in `rcx` and floating point argument in `xmm0`
//! - 2. 32/64-bit integer in `rdx` and floating point argument in `xmm1`
//! - 3. 32/64-bit integer in `r8` and floating point argument in `xmm2`
//! - 4. 32/64-bit integer in `r9` and floating point argument in `xmm3`
//!
//! If one or more argument from the first four doesn't match the list above
//! it is simply skipped. WIN64-ABI is very specific about this.
//!
//! All other arguments are pushed on the stack from the right to the left.
//! Stack has to be aligned by 16 bytes, always. There is also a 32-byte
//! shadow space on the stack that can be used to save up to four 64-bit
//! registers.
//!
//! Arguments direction:
//! - Right to left (except for all parameters passed in registers).
//!
//! Stack cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `rax`.
//! - Floating point - `xmm0`.
//!
//! Stack is always aligned to 16 bytes.
//!
//! More information about this calling convention can be found on MSDN
//! <http://msdn.microsoft.com/en-us/library/9b372w95.aspx>.
kCallConvX64Win = 10,
//! X64 calling convention used by Unix platforms (AMD64-ABI).
//!
//! First six 32 or 64-bit integer arguments are passed in `rdi`, `rsi`,
//! `rdx`, `rcx`, `r8`, and `r9` registers. First eight floating point or xmm
//! arguments are passed in `xmm0`, `xmm1`, `xmm2`, `xmm3`, `xmm4`, `xmm5`,
//! `xmm6`, and `xmm7` registers.
//!
//! There is also a red zene below the stack pointer that can be used by the
//! function. The red zone is typically from [rsp-128] to [rsp-8], however,
//! red zone can also be disabled.
//!
//! Arguments direction:
//! - Right to left (except for all arguments passed in registers).
//!
//! Stack cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `rax`.
//! - Floating point - `xmm0`.
//!
//! Stack is always aligned to 16 bytes.
kCallConvX64Unix = 11,
// --------------------------------------------------------------------------
// [ARM]
// --------------------------------------------------------------------------
kCallConvArm32SoftFP = 16,
kCallConvArm32HardFP = 17,
// --------------------------------------------------------------------------
// [Internal]
// --------------------------------------------------------------------------
//! \internal
_kCallConvX86Start = 1,
//! \internal
_kCallConvX86End = 9,
//! \internal
_kCallConvX64Start = 10,
//! \internal
_kCallConvX64End = 11,
//! \internal
_kCallConvArmStart = 16,
//! \internal
_kCallConvArmEnd = 17,
// --------------------------------------------------------------------------
// [Host]
// --------------------------------------------------------------------------
#if defined(ASMJIT_DOCGEN)
//! Default calling convention based on the current compiler's settings.
//!
//! NOTE: This should be always the same as `kCallConvHostCDecl`, but some
//! compilers allow to override the default calling convention. Overriding
//! is not detected at the moment.
kCallConvHost = DETECTED_AT_COMPILE_TIME,
//! Default C calling convention based on the current compiler's settings.
kCallConvHostCDecl = DETECTED_AT_COMPILE_TIME,
//! Compatibility for `__stdcall` calling convention.
//!
//! NOTE: This enumeration is always set to a value which is compatible with
//! the current compiler's `__stdcall` calling convention. In 64-bit mode
//! there is no such convention and the value is mapped to `kCallConvX64Win`
//! or `kCallConvX64Unix`, depending on the host architecture.
kCallConvHostStdCall = DETECTED_AT_COMPILE_TIME,
//! Compatibility for `__fastcall` calling convention.
//!
//! NOTE: This enumeration is always set to a value which is compatible with
//! the current compiler's `__fastcall` calling convention. In 64-bit mode
//! there is no such convention and the value is mapped to `kCallConvX64Win`
//! or `kCallConvX64Unix`, depending on the host architecture.
kCallConvHostFastCall = DETECTED_AT_COMPILE_TIME
#elif ASMJIT_ARCH_X86
// X86 Host Support.
kCallConvHost = kCallConvX86CDecl,
kCallConvHostCDecl = kCallConvX86CDecl,
kCallConvHostStdCall = kCallConvX86StdCall,
kCallConvHostFastCall =
ASMJIT_CC_MSC ? kCallConvX86MsFastCall :
ASMJIT_CC_GCC ? kCallConvX86GccFastCall :
ASMJIT_CC_CLANG ? kCallConvX86GccFastCall :
ASMJIT_CC_CODEGEAR ? kCallConvX86BorlandFastCall : kCallConvNone
#elif ASMJIT_ARCH_X64
// X64 Host Support.
kCallConvHost = ASMJIT_OS_WINDOWS ? kCallConvX64Win : kCallConvX64Unix,
// These don't exist in 64-bit mode.
kCallConvHostCDecl = kCallConvHost,
kCallConvHostStdCall = kCallConvHost,
kCallConvHostFastCall = kCallConvHost
#elif ASMJIT_ARCH_ARM32
# if defined(__SOFTFP__)
kCallConvHost = kCallConvArm32SoftFP,
# else
kCallConvHost = kCallConvArm32HardFP,
# endif
// These don't exist on ARM.
kCallConvHostCDecl = kCallConvHost,
kCallConvHostStdCall = kCallConvHost,
kCallConvHostFastCall = kCallConvHost
#else
# error "[asmjit] Couldn't determine the target's calling convention."
#endif
};
// ============================================================================ // ============================================================================
// [asmjit::FuncHint] // [asmjit::FuncHint]
// ============================================================================ // ============================================================================
@@ -654,16 +294,16 @@ struct FuncInOut {
// [Accessors] // [Accessors]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE uint32_t getVarType() const { return _varType; } ASMJIT_INLINE uint32_t getVarType() const noexcept { return _varType; }
ASMJIT_INLINE bool hasRegIndex() const { return _regIndex != kInvalidReg; } ASMJIT_INLINE bool hasRegIndex() const noexcept { return _regIndex != kInvalidReg; }
ASMJIT_INLINE uint32_t getRegIndex() const { return _regIndex; } ASMJIT_INLINE uint32_t getRegIndex() const noexcept { return _regIndex; }
ASMJIT_INLINE bool hasStackOffset() const { return _stackOffset != kFuncStackInvalid; } ASMJIT_INLINE bool hasStackOffset() const noexcept { return _stackOffset != kFuncStackInvalid; }
ASMJIT_INLINE int32_t getStackOffset() const { return static_cast<int32_t>(_stackOffset); } ASMJIT_INLINE int32_t getStackOffset() const noexcept { return static_cast<int32_t>(_stackOffset); }
//! Get whether the argument / return value is assigned. //! Get whether the argument / return value is assigned.
ASMJIT_INLINE bool isSet() const { ASMJIT_INLINE bool isSet() const noexcept {
return (_regIndex != kInvalidReg) | (_stackOffset != kFuncStackInvalid); return (_regIndex != kInvalidReg) | (_stackOffset != kFuncStackInvalid);
} }
@@ -672,7 +312,7 @@ struct FuncInOut {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Reset the function argument to "unassigned state". //! Reset the function argument to "unassigned state".
ASMJIT_INLINE void reset() { _packed = 0xFFFFFFFFU; } ASMJIT_INLINE void reset() noexcept { _packed = 0xFFFFFFFFU; }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -712,7 +352,7 @@ struct FuncPrototype {
ASMJIT_INLINE void setup( ASMJIT_INLINE void setup(
uint32_t callConv, uint32_t callConv,
uint32_t ret, uint32_t ret,
const uint32_t* args, uint32_t numArgs) { const uint32_t* args, uint32_t numArgs) noexcept {
ASMJIT_ASSERT(callConv <= 0xFF); ASMJIT_ASSERT(callConv <= 0xFF);
ASMJIT_ASSERT(numArgs <= 0xFF); ASMJIT_ASSERT(numArgs <= 0xFF);
@@ -731,21 +371,21 @@ struct FuncPrototype {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get the function's calling convention. //! Get the function's calling convention.
ASMJIT_INLINE uint32_t getCallConv() const { return _callConv; } ASMJIT_INLINE uint32_t getCallConv() const noexcept { return _callConv; }
//! Get the variable arguments `...` index, `kFuncNoVarArgs` if none. //! Get the variable arguments `...` index, `kFuncNoVarArgs` if none.
ASMJIT_INLINE uint32_t getVarArgs() const { return _varArgs; } ASMJIT_INLINE uint32_t getVarArgs() const noexcept { return _varArgs; }
//! Get the number of function arguments. //! Get the number of function arguments.
ASMJIT_INLINE uint32_t getNumArgs() const { return _numArgs; } ASMJIT_INLINE uint32_t getNumArgs() const noexcept { return _numArgs; }
//! Get the return value type. //! Get the return value type.
ASMJIT_INLINE uint32_t getRet() const { return _ret; } ASMJIT_INLINE uint32_t getRet() const noexcept { return _ret; }
//! Get the type of the argument at index `i`. //! Get the type of the argument at index `i`.
ASMJIT_INLINE uint32_t getArg(uint32_t i) const { ASMJIT_INLINE uint32_t getArg(uint32_t i) const noexcept {
ASMJIT_ASSERT(i < _numArgs); ASMJIT_ASSERT(i < _numArgs);
return _args[i]; return _args[i];
} }
//! Get the array of function arguments' types. //! Get the array of function arguments' types.
ASMJIT_INLINE const uint32_t* getArgs() const { return _args; } ASMJIT_INLINE const uint32_t* getArgs() const noexcept { return _args; }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -771,7 +411,7 @@ struct FuncBuilderX : public FuncPrototype {
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE FuncBuilderX(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilderX(uint32_t callConv = kCallConvHost) noexcept {
setup(callConv, kInvalidVar, _builderArgList, 0); setup(callConv, kInvalidVar, _builderArgList, 0);
} }
@@ -779,36 +419,36 @@ struct FuncBuilderX : public FuncPrototype {
// [Accessors] // [Accessors]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE void setCallConv(uint32_t callConv) { ASMJIT_INLINE void setCallConv(uint32_t callConv) noexcept {
ASMJIT_ASSERT(callConv <= 0xFF); ASMJIT_ASSERT(callConv <= 0xFF);
_callConv = static_cast<uint8_t>(callConv); _callConv = static_cast<uint8_t>(callConv);
} }
//! Set the return type to `retType`. //! Set the return type to `retType`.
ASMJIT_INLINE void setRet(uint32_t retType) { ASMJIT_INLINE void setRet(uint32_t retType) noexcept {
_ret = retType; _ret = retType;
} }
//! Set the return type based on `T`. //! Set the return type based on `T`.
template<typename T> template<typename T>
ASMJIT_INLINE void setRetT() { setRet(TypeId<T>::kId); } ASMJIT_INLINE void setRetT() noexcept { setRet(TypeId<T>::kId); }
//! Set the argument at index `i` to the `type` //! Set the argument at index `i` to the `type`
ASMJIT_INLINE void setArg(uint32_t i, uint32_t type) { ASMJIT_INLINE void setArg(uint32_t i, uint32_t type) noexcept {
ASMJIT_ASSERT(i < _numArgs); ASMJIT_ASSERT(i < _numArgs);
_builderArgList[i] = type; _builderArgList[i] = type;
} }
//! Set the argument at index `i` to the type based on `T`. //! Set the argument at index `i` to the type based on `T`.
template<typename T> template<typename T>
ASMJIT_INLINE void setArgT(uint32_t i) { setArg(i, TypeId<T>::kId); } ASMJIT_INLINE void setArgT(uint32_t i) noexcept { setArg(i, TypeId<T>::kId); }
//! Append an argument of `type` to the function prototype. //! Append an argument of `type` to the function prototype.
ASMJIT_INLINE void addArg(uint32_t type) { ASMJIT_INLINE void addArg(uint32_t type) noexcept {
ASMJIT_ASSERT(_numArgs < kFuncArgCount); ASMJIT_ASSERT(_numArgs < kFuncArgCount);
_builderArgList[_numArgs++] = type; _builderArgList[_numArgs++] = type;
} }
//! Append an argument of type based on `T` to the function prototype. //! Append an argument of type based on `T` to the function prototype.
template<typename T> template<typename T>
ASMJIT_INLINE void addArgT() { addArg(TypeId<T>::kId); } ASMJIT_INLINE void addArgT() noexcept { addArg(TypeId<T>::kId); }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -823,7 +463,7 @@ struct FuncBuilderX : public FuncPrototype {
//! Function prototype (no args). //! Function prototype (no args).
template<typename RET> template<typename RET>
struct FuncBuilder0 : public FuncPrototype { struct FuncBuilder0 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder0(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder0(uint32_t callConv = kCallConvHost) noexcept {
setup(callConv, T(RET), nullptr, 0); setup(callConv, T(RET), nullptr, 0);
} }
}; };
@@ -831,7 +471,7 @@ struct FuncBuilder0 : public FuncPrototype {
//! Function prototype (1 argument). //! Function prototype (1 argument).
template<typename RET, typename P0> template<typename RET, typename P0>
struct FuncBuilder1 : public FuncPrototype { struct FuncBuilder1 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder1(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder1(uint32_t callConv = kCallConvHost) noexcept {
static const uint32_t args[] = { T(P0) }; static const uint32_t args[] = { T(P0) };
setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args));
} }
@@ -840,7 +480,7 @@ struct FuncBuilder1 : public FuncPrototype {
//! Function prototype (2 arguments). //! Function prototype (2 arguments).
template<typename RET, typename P0, typename P1> template<typename RET, typename P0, typename P1>
struct FuncBuilder2 : public FuncPrototype { struct FuncBuilder2 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder2(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder2(uint32_t callConv = kCallConvHost) noexcept {
static const uint32_t args[] = { T(P0), T(P1) }; static const uint32_t args[] = { T(P0), T(P1) };
setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args));
} }
@@ -849,7 +489,7 @@ struct FuncBuilder2 : public FuncPrototype {
//! Function prototype (3 arguments). //! Function prototype (3 arguments).
template<typename RET, typename P0, typename P1, typename P2> template<typename RET, typename P0, typename P1, typename P2>
struct FuncBuilder3 : public FuncPrototype { struct FuncBuilder3 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder3(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder3(uint32_t callConv = kCallConvHost) noexcept {
static const uint32_t args[] = { T(P0), T(P1), T(P2) }; static const uint32_t args[] = { T(P0), T(P1), T(P2) };
setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args));
} }
@@ -858,7 +498,7 @@ struct FuncBuilder3 : public FuncPrototype {
//! Function prototype (4 arguments). //! Function prototype (4 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3> template<typename RET, typename P0, typename P1, typename P2, typename P3>
struct FuncBuilder4 : public FuncPrototype { struct FuncBuilder4 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder4(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder4(uint32_t callConv = kCallConvHost) noexcept {
static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3) }; static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3) };
setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args));
} }
@@ -867,7 +507,7 @@ struct FuncBuilder4 : public FuncPrototype {
//! Function prototype (5 arguments). //! Function prototype (5 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4> template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4>
struct FuncBuilder5 : public FuncPrototype { struct FuncBuilder5 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder5(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder5(uint32_t callConv = kCallConvHost) noexcept {
static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4) }; static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4) };
setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args));
} }
@@ -876,7 +516,7 @@ struct FuncBuilder5 : public FuncPrototype {
//! Function prototype (6 arguments). //! Function prototype (6 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5> template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
struct FuncBuilder6 : public FuncPrototype { struct FuncBuilder6 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder6(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder6(uint32_t callConv = kCallConvHost) noexcept {
static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5) }; static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5) };
setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args));
} }
@@ -885,7 +525,7 @@ struct FuncBuilder6 : public FuncPrototype {
//! Function prototype (7 arguments). //! Function prototype (7 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6> template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
struct FuncBuilder7 : public FuncPrototype { struct FuncBuilder7 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder7(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder7(uint32_t callConv = kCallConvHost) noexcept {
static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6) }; static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6) };
setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args));
} }
@@ -894,7 +534,7 @@ struct FuncBuilder7 : public FuncPrototype {
//! Function prototype (8 arguments). //! Function prototype (8 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7> template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
struct FuncBuilder8 : public FuncPrototype { struct FuncBuilder8 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder8(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder8(uint32_t callConv = kCallConvHost) noexcept {
static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7) }; static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7) };
setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args));
} }
@@ -903,7 +543,7 @@ struct FuncBuilder8 : public FuncPrototype {
//! Function prototype (9 arguments). //! Function prototype (9 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8> template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
struct FuncBuilder9 : public FuncPrototype { struct FuncBuilder9 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder9(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder9(uint32_t callConv = kCallConvHost) noexcept {
static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7), T(P8) }; static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7), T(P8) };
setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args));
} }
@@ -912,7 +552,7 @@ struct FuncBuilder9 : public FuncPrototype {
//! Function prototype (10 arguments). //! Function prototype (10 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9> template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9>
struct FuncBuilder10 : public FuncPrototype { struct FuncBuilder10 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder10(uint32_t callConv = kCallConvHost) { ASMJIT_INLINE FuncBuilder10(uint32_t callConv = kCallConvHost) noexcept {
static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7), T(P8), T(P9) }; static const uint32_t args[] = { T(P0), T(P1), T(P2), T(P3), T(P4), T(P5), T(P6), T(P7), T(P8), T(P9) };
setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args)); setup(callConv, T(RET), args, ASMJIT_ARRAY_SIZE(args));
} }
@@ -930,10 +570,10 @@ struct FuncDecl {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get the function's calling convention, see `CallConv`. //! Get the function's calling convention, see `CallConv`.
ASMJIT_INLINE uint32_t getCallConv() const { return _callConv; } ASMJIT_INLINE uint32_t getCallConv() const noexcept { return _callConv; }
//! Get whether the callee pops the stack. //! Get whether the callee pops the stack.
ASMJIT_INLINE uint32_t getCalleePopsStack() const { return _calleePopsStack; } ASMJIT_INLINE uint32_t getCalleePopsStack() const noexcept { return _calleePopsStack; }
//! Get direction of arguments passed on the stack. //! Get direction of arguments passed on the stack.
//! //!
@@ -941,50 +581,50 @@ struct FuncDecl {
//! //!
//! \note This is related to used calling convention, it's not affected by //! \note This is related to used calling convention, it's not affected by
//! number of function arguments or their types. //! number of function arguments or their types.
ASMJIT_INLINE uint32_t getDirection() const { return _direction; } ASMJIT_INLINE uint32_t getArgsDirection() const noexcept { return _argsDirection; }
//! Get stack size needed for function arguments passed on the stack. //! Get stack size needed for function arguments passed on the stack.
ASMJIT_INLINE uint32_t getArgStackSize() const { return _argStackSize; } ASMJIT_INLINE uint32_t getArgStackSize() const noexcept { return _argStackSize; }
//! Get size of "Red Zone". //! Get size of "Red Zone".
ASMJIT_INLINE uint32_t getRedZoneSize() const { return _redZoneSize; } ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _redZoneSize; }
//! Get size of "Spill Zone". //! Get size of "Spill Zone".
ASMJIT_INLINE uint32_t getSpillZoneSize() const { return _spillZoneSize; } ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _spillZoneSize; }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Accessors - Arguments and Return] // [Accessors - Arguments and Return]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get whether the function has a return value. //! Get whether the function has a return value.
ASMJIT_INLINE bool hasRet() const { return _retCount != 0; } ASMJIT_INLINE bool hasRet() const noexcept { return _retCount != 0; }
//! Get count of function return values. //! Get count of function return values.
ASMJIT_INLINE uint32_t getRetCount() const { return _retCount; } ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _retCount; }
//! Get function return value. //! Get function return value.
ASMJIT_INLINE FuncInOut& getRet(uint32_t index = kFuncRetLo) { return _rets[index]; } ASMJIT_INLINE FuncInOut& getRet(uint32_t index = kFuncRetLo) noexcept { return _rets[index]; }
//! Get function return value. //! Get function return value.
ASMJIT_INLINE const FuncInOut& getRet(uint32_t index = kFuncRetLo) const { return _rets[index]; } ASMJIT_INLINE const FuncInOut& getRet(uint32_t index = kFuncRetLo) const noexcept { return _rets[index]; }
//! Get the number of function arguments. //! Get the number of function arguments.
ASMJIT_INLINE uint32_t getNumArgs() const { return _numArgs; } ASMJIT_INLINE uint32_t getNumArgs() const noexcept { return _numArgs; }
//! Get function arguments array. //! Get function arguments array.
ASMJIT_INLINE FuncInOut* getArgs() { return _args; } ASMJIT_INLINE FuncInOut* getArgs() noexcept { return _args; }
//! Get function arguments array (const). //! Get function arguments array (const).
ASMJIT_INLINE const FuncInOut* getArgs() const { return _args; } ASMJIT_INLINE const FuncInOut* getArgs() const noexcept { return _args; }
//! Get function argument at index `index`. //! Get function argument at index `index`.
ASMJIT_INLINE FuncInOut& getArg(size_t index) { ASMJIT_INLINE FuncInOut& getArg(size_t index) noexcept {
ASMJIT_ASSERT(index < kFuncArgCountLoHi); ASMJIT_ASSERT(index < kFuncArgCountLoHi);
return _args[index]; return _args[index];
} }
//! Get function argument at index `index`. //! Get function argument at index `index`.
ASMJIT_INLINE const FuncInOut& getArg(size_t index) const { ASMJIT_INLINE const FuncInOut& getArg(size_t index) const noexcept {
ASMJIT_ASSERT(index < kFuncArgCountLoHi); ASMJIT_ASSERT(index < kFuncArgCountLoHi);
return _args[index]; return _args[index];
} }
ASMJIT_INLINE void resetArg(size_t index) { ASMJIT_INLINE void resetArg(size_t index) noexcept {
ASMJIT_ASSERT(index < kFuncArgCountLoHi); ASMJIT_ASSERT(index < kFuncArgCountLoHi);
_args[index].reset(); _args[index].reset();
} }
@@ -998,7 +638,7 @@ struct FuncDecl {
//! Whether a callee pops stack. //! Whether a callee pops stack.
uint8_t _calleePopsStack : 1; uint8_t _calleePopsStack : 1;
//! Direction for arguments passed on the stack, see `FuncDir`. //! Direction for arguments passed on the stack, see `FuncDir`.
uint8_t _direction : 1; uint8_t _argsDirection : 1;
//! Reserved #0 (alignment). //! Reserved #0 (alignment).
uint8_t _reserved0 : 6; uint8_t _reserved0 : 6;

View File

@@ -44,7 +44,7 @@ char* StringBuilder::prepare(uint32_t op, size_t len) noexcept {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
if (op == kStringOpSet) { if (op == kStringOpSet) {
// We don't care here, but we can't return a nullptr pointer since it indicates // We don't care here, but we can't return a NULL pointer since it indicates
// failure in memory allocation. // failure in memory allocation.
if (len == 0) { if (len == 0) {
if (_data != StringBuilder_empty) if (_data != StringBuilder_empty)

View File

@@ -57,9 +57,9 @@ static const char* findPackedString(const char* p, uint32_t id, uint32_t maxId)
} }
#endif // ASMJIT_DISABLE_TEXT #endif // ASMJIT_DISABLE_TEXT
const char* DebugUtils::errorAsString(Error e) noexcept { const char* DebugUtils::errorAsString(Error err) noexcept {
#if !defined(ASMJIT_DISABLE_TEXT) #if !defined(ASMJIT_DISABLE_TEXT)
return findPackedString(errorMessages, e, kErrorCount); return findPackedString(errorMessages, err, kErrorCount);
#else #else
static const char noMessage[] = ""; static const char noMessage[] = "";
return noMessage; return noMessage;

View File

@@ -110,6 +110,366 @@ ASMJIT_ENUM(ArchId) {
#endif #endif
}; };
// ============================================================================
// [asmjit::CallConv]
// ============================================================================
//! Function calling convention.
//!
//! Calling convention is a scheme that defines how function arguments are
//! passed and how the return value handled. In assembler programming it's
//! always needed to comply with function calling conventions, because even
//! small inconsistency can cause undefined behavior or application's crash.
//!
//! Platform Independent Conventions
//! --------------------------------
//!
//! - `kCallConvHost` - Should match the current C++ compiler native calling
//! convention.
//!
//! X86/X64 Specific Conventions
//! ----------------------------
//!
//! List of calling conventions for 32-bit x86 mode:
//! - `kCallConvX86CDecl` - Calling convention for C runtime.
//! - `kCallConvX86StdCall` - Calling convention for WinAPI functions.
//! - `kCallConvX86MsThisCall` - Calling convention for C++ members under
//! Windows (produced by MSVC and all MSVC compatible compilers).
//! - `kCallConvX86MsFastCall` - Fastest calling convention that can be used
//! by MSVC compiler.
//! - `kCallConvX86BorlandFastCall` - Borland fastcall convention.
//! - `kCallConvX86GccFastCall` - GCC fastcall convention (2 register arguments).
//! - `kCallConvX86GccRegParm1` - GCC regparm(1) convention.
//! - `kCallConvX86GccRegParm2` - GCC regparm(2) convention.
//! - `kCallConvX86GccRegParm3` - GCC regparm(3) convention.
//!
//! List of calling conventions for 64-bit x86 mode (x64):
//! - `kCallConvX64Win` - Windows 64-bit calling convention (WIN64 ABI).
//! - `kCallConvX64Unix` - Unix 64-bit calling convention (AMD64 ABI).
//!
//! ARM Specific Conventions
//! ------------------------
//!
//! List of ARM calling conventions:
//! - `kCallConvArm32SoftFP` - Legacy calling convention, floating point
//! arguments are passed via GP registers.
//! - `kCallConvArm32HardFP` - Modern calling convention, uses VFP registers
//! to pass floating point arguments.
ASMJIT_ENUM(CallConv) {
//! Calling convention is invalid (can't be used).
kCallConvNone = 0,
// --------------------------------------------------------------------------
// [X86]
// --------------------------------------------------------------------------
//! X86 `__cdecl` calling convention (used by C runtime and libraries).
//!
//! Compatible across MSVC and GCC.
//!
//! Arguments direction:
//! - Right to left.
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86CDecl = 1,
//! X86 `__stdcall` calling convention (used mostly by WinAPI).
//!
//! Compatible across MSVC and GCC.
//!
//! Arguments direction:
//! - Right to left.
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86StdCall = 2,
//! X86 `__thiscall` calling convention (MSVC/Intel specific).
//!
//! This is MSVC (and Intel) specific calling convention used when targeting
//! Windows platform for C++ class methods. Implicit `this` pointer (defined
//! as the first argument) is stored in `ecx` register instead of storing it
//! on the stack.
//!
//! This calling convention is implicitly used by MSVC for class functions.
//!
//! C++ class functions that have variable number of arguments use `__cdecl`
//! calling convention instead.
//!
//! Arguments direction:
//! - Right to left (except for the first argument passed in `ecx`).
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86MsThisCall = 3,
//! X86 `__fastcall` convention (MSVC/Intel specific).
//!
//! The first two arguments (evaluated from the left to the right) are passed
//! in `ecx` and `edx` registers, all others on the stack from the right to
//! the left.
//!
//! Arguments direction:
//! - Right to left (except for the first two integers passed in `ecx` and `edx`).
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
//!
//! NOTE: This calling convention differs from GCC's one.
kCallConvX86MsFastCall = 4,
//! X86 `__fastcall` convention (Borland specific).
//!
//! The first two arguments (evaluated from the left to the right) are passed
//! in `ecx` and `edx` registers, all others on the stack from the left to
//! the right.
//!
//! Arguments direction:
//! - Left to right (except for the first two integers passed in `ecx` and `edx`).
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
//!
//! NOTE: Arguments on the stack are in passed in left to right order, which
//! is really Borland specific, all other `__fastcall` calling conventions
//! use right to left order.
kCallConvX86BorlandFastCall = 5,
//! X86 `__fastcall` convention (GCC specific).
//!
//! The first two arguments (evaluated from the left to the right) are passed
//! in `ecx` and `edx` registers, all others on the stack from the right to
//! the left.
//!
//! Arguments direction:
//! - Right to left (except for the first two integers passed in `ecx` and `edx`).
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
//!
//! NOTE: This calling convention should be compatible with `kCallConvX86MsFastCall`.
kCallConvX86GccFastCall = 6,
//! X86 `regparm(1)` convention (GCC specific).
//!
//! The first argument (evaluated from the left to the right) is passed in
//! `eax` register, all others on the stack from the right to the left.
//!
//! Arguments direction:
//! - Right to left (except for the first integer passed in `eax`).
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86GccRegParm1 = 7,
//! X86 `regparm(2)` convention (GCC specific).
//!
//! The first two arguments (evaluated from the left to the right) are passed
//! in `ecx` and `edx` registers, all others on the stack from the right to
//! the left.
//!
//! Arguments direction:
//! - Right to left (except for the first two integers passed in `ecx` and `edx`).
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86GccRegParm2 = 8,
//! X86 `regparm(3)` convention (GCC specific).
//!
//! Three first parameters (evaluated from left-to-right) are in
//! EAX:EDX:ECX registers, all others on the stack in right-to-left direction.
//!
//! Arguments direction:
//! - Right to left (except for the first three integers passed in `ecx`,
//! `edx`, and `ecx`).
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `eax:edx` registers.
//! - Floating point - `fp0` register.
kCallConvX86GccRegParm3 = 9,
// --------------------------------------------------------------------------
// [X64]
// --------------------------------------------------------------------------
//! X64 calling convention used by Windows platform (WIN64-ABI).
//!
//! The first 4 arguments are passed in the following registers:
//! - 1. 32/64-bit integer in `rcx` and floating point argument in `xmm0`
//! - 2. 32/64-bit integer in `rdx` and floating point argument in `xmm1`
//! - 3. 32/64-bit integer in `r8` and floating point argument in `xmm2`
//! - 4. 32/64-bit integer in `r9` and floating point argument in `xmm3`
//!
//! If one or more argument from the first four doesn't match the list above
//! it is simply skipped. WIN64-ABI is very specific about this.
//!
//! All other arguments are pushed on the stack from the right to the left.
//! Stack has to be aligned by 16 bytes, always. There is also a 32-byte
//! shadow space on the stack that can be used to save up to four 64-bit
//! registers.
//!
//! Arguments direction:
//! - Right to left (except for all parameters passed in registers).
//!
//! Stack cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `rax`.
//! - Floating point - `xmm0`.
//!
//! Stack is always aligned to 16 bytes.
//!
//! More information about this calling convention can be found on MSDN
//! <http://msdn.microsoft.com/en-us/library/9b372w95.aspx>.
kCallConvX64Win = 10,
//! X64 calling convention used by Unix platforms (AMD64-ABI).
//!
//! First six 32 or 64-bit integer arguments are passed in `rdi`, `rsi`,
//! `rdx`, `rcx`, `r8`, and `r9` registers. First eight floating point or xmm
//! arguments are passed in `xmm0`, `xmm1`, `xmm2`, `xmm3`, `xmm4`, `xmm5`,
//! `xmm6`, and `xmm7` registers.
//!
//! There is also a red zene below the stack pointer that can be used by the
//! function. The red zone is typically from [rsp-128] to [rsp-8], however,
//! red zone can also be disabled.
//!
//! Arguments direction:
//! - Right to left (except for all arguments passed in registers).
//!
//! Stack cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - `rax`.
//! - Floating point - `xmm0`.
//!
//! Stack is always aligned to 16 bytes.
kCallConvX64Unix = 11,
// --------------------------------------------------------------------------
// [ARM]
// --------------------------------------------------------------------------
kCallConvArm32SoftFP = 16,
kCallConvArm32HardFP = 17,
// --------------------------------------------------------------------------
// [Internal]
// --------------------------------------------------------------------------
//! \internal
_kCallConvX86Start = 1,
//! \internal
_kCallConvX86End = 9,
//! \internal
_kCallConvX64Start = 10,
//! \internal
_kCallConvX64End = 11,
//! \internal
_kCallConvArmStart = 16,
//! \internal
_kCallConvArmEnd = 17,
// --------------------------------------------------------------------------
// [Host]
// --------------------------------------------------------------------------
#if defined(ASMJIT_DOCGEN)
//! Default calling convention based on the current compiler's settings.
//!
//! NOTE: This should be always the same as `kCallConvHostCDecl`, but some
//! compilers allow to override the default calling convention. Overriding
//! is not detected at the moment.
kCallConvHost = DETECTED_AT_COMPILE_TIME,
//! Default C calling convention based on the current compiler's settings.
kCallConvHostCDecl = DETECTED_AT_COMPILE_TIME,
//! Compatibility for `__stdcall` calling convention.
//!
//! NOTE: This enumeration is always set to a value which is compatible with
//! the current compiler's `__stdcall` calling convention. In 64-bit mode
//! there is no such convention and the value is mapped to `kCallConvX64Win`
//! or `kCallConvX64Unix`, depending on the host architecture.
kCallConvHostStdCall = DETECTED_AT_COMPILE_TIME,
//! Compatibility for `__fastcall` calling convention.
//!
//! NOTE: This enumeration is always set to a value which is compatible with
//! the current compiler's `__fastcall` calling convention. In 64-bit mode
//! there is no such convention and the value is mapped to `kCallConvX64Win`
//! or `kCallConvX64Unix`, depending on the host architecture.
kCallConvHostFastCall = DETECTED_AT_COMPILE_TIME
#elif ASMJIT_ARCH_X86
// X86 Host Support.
kCallConvHost = kCallConvX86CDecl,
kCallConvHostCDecl = kCallConvX86CDecl,
kCallConvHostStdCall = kCallConvX86StdCall,
kCallConvHostFastCall =
ASMJIT_CC_MSC ? kCallConvX86MsFastCall :
ASMJIT_CC_GCC ? kCallConvX86GccFastCall :
ASMJIT_CC_CLANG ? kCallConvX86GccFastCall :
ASMJIT_CC_CODEGEAR ? kCallConvX86BorlandFastCall : kCallConvNone
#elif ASMJIT_ARCH_X64
// X64 Host Support.
kCallConvHost = ASMJIT_OS_WINDOWS ? kCallConvX64Win : kCallConvX64Unix,
// These don't exist in 64-bit mode.
kCallConvHostCDecl = kCallConvHost,
kCallConvHostStdCall = kCallConvHost,
kCallConvHostFastCall = kCallConvHost
#elif ASMJIT_ARCH_ARM32
# if defined(__SOFTFP__)
kCallConvHost = kCallConvArm32SoftFP,
# else
kCallConvHost = kCallConvArm32HardFP,
# endif
// These don't exist on ARM.
kCallConvHostCDecl = kCallConvHost,
kCallConvHostStdCall = kCallConvHost,
kCallConvHostFastCall = kCallConvHost
#else
# error "[asmjit] Couldn't determine the target's calling convention."
#endif
};
// ============================================================================ // ============================================================================
// [asmjit::ErrorCode] // [asmjit::ErrorCode]
// ============================================================================ // ============================================================================
@@ -216,8 +576,8 @@ static const _NoInit NoInit = {};
namespace DebugUtils { namespace DebugUtils {
//! Get a printable version of AsmJit `Error` code. //! Get a printable version of `asmjit::Error` value.
ASMJIT_API const char* errorAsString(Error code) noexcept; ASMJIT_API const char* errorAsString(Error err) noexcept;
//! \addtogroup asmjit_base //! \addtogroup asmjit_base
//! \{ //! \{

View File

@@ -558,6 +558,7 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE uint32_t readU16xLE(const void* p) noexcept { 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)) { if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
return static_cast<uint32_t>(static_cast<const uint16_t*>(p)[0]); return static_cast<uint32_t>(static_cast<const uint16_t*>(p)[0]);
} }
@@ -570,6 +571,7 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE uint32_t readU16xBE(const void* p) noexcept { 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)) { if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
return static_cast<uint32_t>(static_cast<const uint16_t*>(p)[0]); return static_cast<uint32_t>(static_cast<const uint16_t*>(p)[0]);
} }
@@ -587,6 +589,7 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE int32_t readI16xLE(const void* p) noexcept { 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)) { if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
return static_cast<int32_t>(static_cast<const int16_t*>(p)[0]); return static_cast<int32_t>(static_cast<const int16_t*>(p)[0]);
} }
@@ -599,6 +602,7 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE int32_t readI16xBE(const void* p) noexcept { 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)) { if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
return static_cast<int32_t>(static_cast<const int16_t*>(p)[0]); return static_cast<int32_t>(static_cast<const int16_t*>(p)[0]);
} }
@@ -634,6 +638,7 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE uint32_t readU32xLE(const void* p) noexcept { 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) { if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) {
uint32_t x = static_cast<const uint32_t*>(p)[0]; uint32_t x = static_cast<const uint32_t*>(p)[0];
return ASMJIT_ARCH_LE ? x : byteswap32(x); return ASMJIT_ARCH_LE ? x : byteswap32(x);
@@ -647,6 +652,7 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE uint32_t readU32xBE(const void* p) noexcept { 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) { if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) {
uint32_t x = static_cast<const uint32_t*>(p)[0]; uint32_t x = static_cast<const uint32_t*>(p)[0];
return ASMJIT_ARCH_BE ? x : byteswap32(x); return ASMJIT_ARCH_BE ? x : byteswap32(x);
@@ -698,24 +704,26 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE uint64_t readU64xLE(const void* p) noexcept { 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)) { if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) {
return static_cast<const uint64_t*>(p)[0]; return static_cast<const uint64_t*>(p)[0];
} }
else { else {
uint32_t x = readU32xLE<Alignment>(static_cast<const uint8_t*>(p) + 0); uint32_t x = readU32xLE<Alignment / 2U>(static_cast<const uint8_t*>(p) + 0);
uint32_t y = readU32xLE<Alignment>(static_cast<const uint8_t*>(p) + 4); 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); return static_cast<uint64_t>(x) + (static_cast<uint64_t>(y) << 32);
} }
} }
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE uint64_t readU64xBE(const void* p) noexcept { 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)) { if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) {
return static_cast<const uint64_t*>(p)[0]; return static_cast<const uint64_t*>(p)[0];
} }
else { else {
uint32_t x = readU32xLE<Alignment>(static_cast<const uint8_t*>(p) + 0); uint32_t x = readU32xLE<Alignment / 2U>(static_cast<const uint8_t*>(p) + 0);
uint32_t y = readU32xLE<Alignment>(static_cast<const uint8_t*>(p) + 4); 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); return (static_cast<uint64_t>(x) << 32) + static_cast<uint64_t>(y);
} }
} }
@@ -772,6 +780,7 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE void writeU16xLE(void* p, uint32_t x) noexcept { 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)) { if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
static_cast<uint16_t*>(p)[0] = static_cast<uint16_t>(x & 0xFFFFU); static_cast<uint16_t*>(p)[0] = static_cast<uint16_t>(x & 0xFFFFU);
} }
@@ -783,6 +792,7 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE void writeU16xBE(void* p, uint32_t x) noexcept { 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)) { if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_16 || Alignment >= 2)) {
static_cast<uint16_t*>(p)[0] = static_cast<uint16_t>(x & 0xFFFFU); static_cast<uint16_t*>(p)[0] = static_cast<uint16_t>(x & 0xFFFFU);
} }
@@ -835,6 +845,7 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE void writeU32xLE(void* p, uint32_t x) noexcept { 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) { if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) {
static_cast<uint32_t*>(p)[0] = ASMJIT_ARCH_LE ? x : byteswap32(x); static_cast<uint32_t*>(p)[0] = ASMJIT_ARCH_LE ? x : byteswap32(x);
} }
@@ -846,6 +857,7 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE void writeU32xBE(void* p, uint32_t x) noexcept { 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) { if (ASMJIT_ARCH_UNALIGNED_32 || Alignment >= 4) {
static_cast<uint32_t*>(p)[0] = ASMJIT_ARCH_BE ? x : byteswap32(x); static_cast<uint32_t*>(p)[0] = ASMJIT_ARCH_BE ? x : byteswap32(x);
} }
@@ -898,23 +910,25 @@ struct Utils {
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE void writeU64xLE(void* p, uint64_t x) noexcept { 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)) { if (ASMJIT_ARCH_LE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) {
static_cast<uint64_t*>(p)[0] = x; static_cast<uint64_t*>(p)[0] = x;
} }
else { else {
writeU32xLE<Alignment>(static_cast<uint8_t*>(p) + 0, static_cast<uint32_t>(x >> 32)); writeU32xLE<Alignment / 2U>(static_cast<uint8_t*>(p) + 0, static_cast<uint32_t>(x >> 32));
writeU32xLE<Alignment>(static_cast<uint8_t*>(p) + 4, static_cast<uint32_t>(x & 0xFFFFFFFFU)); writeU32xLE<Alignment / 2U>(static_cast<uint8_t*>(p) + 4, static_cast<uint32_t>(x & 0xFFFFFFFFU));
} }
} }
template<unsigned int Alignment> template<unsigned int Alignment>
static ASMJIT_INLINE void writeU64xBE(void* p, uint64_t x) noexcept { 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)) { if (ASMJIT_ARCH_BE && (ASMJIT_ARCH_UNALIGNED_64 || Alignment >= 8)) {
static_cast<uint64_t*>(p)[0] = x; static_cast<uint64_t*>(p)[0] = x;
} }
else { else {
writeU32xBE<Alignment>(static_cast<uint8_t*>(p) + 0, static_cast<uint32_t>(x & 0xFFFFFFFFU)); writeU32xBE<Alignment / 2U>(static_cast<uint8_t*>(p) + 0, static_cast<uint32_t>(x & 0xFFFFFFFFU));
writeU32xBE<Alignment>(static_cast<uint8_t*>(p) + 4, static_cast<uint32_t>(x >> 32)); writeU32xBE<Alignment / 2U>(static_cast<uint8_t*>(p) + 4, static_cast<uint32_t>(x >> 32));
} }
} }

View File

@@ -401,11 +401,13 @@
# define ASMJIT_CC_HAS_ALIGNAS (__has_extension(__cxx_alignas__)) # define ASMJIT_CC_HAS_ALIGNAS (__has_extension(__cxx_alignas__))
# define ASMJIT_CC_HAS_ALIGNOF (__has_extension(__cxx_alignof__)) # define ASMJIT_CC_HAS_ALIGNOF (__has_extension(__cxx_alignof__))
# define ASMJIT_CC_HAS_ASSUME (0) # define ASMJIT_CC_HAS_ASSUME (0)
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (__has_attribute(__aligned__)) # define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (__has_attribute(__aligned__))
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(__always_inline__)) # define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(__always_inline__))
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (__has_attribute(__noinline__)) # define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (__has_attribute(__noinline__))
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (__has_attribute(__noreturn__)) # define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (__has_attribute(__noreturn__))
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (__has_builtin(__builtin_assume)) # define ASMJIT_CC_HAS_BUILTIN_ASSUME (__has_builtin(__builtin_assume))
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (__has_builtin(__builtin_assume_aligned))
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (__has_builtin(__builtin_expect)) # define ASMJIT_CC_HAS_BUILTIN_EXPECT (__has_builtin(__builtin_expect))
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (__has_builtin(__builtin_unreachable)) # define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (__has_builtin(__builtin_unreachable))
# define ASMJIT_CC_HAS_CONSTEXPR (__has_extension(__cxx_constexpr__)) # define ASMJIT_CC_HAS_CONSTEXPR (__has_extension(__cxx_constexpr__))
@@ -434,6 +436,7 @@
# define ASMJIT_CC_HAS_ALIGNAS (0) # define ASMJIT_CC_HAS_ALIGNAS (0)
# define ASMJIT_CC_HAS_ALIGNOF (0) # define ASMJIT_CC_HAS_ALIGNOF (0)
# define ASMJIT_CC_HAS_ASSUME (0) # define ASMJIT_CC_HAS_ASSUME (0)
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0)
# define ASMJIT_CC_HAS_CONSTEXPR (0) # define ASMJIT_CC_HAS_CONSTEXPR (0)
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_CODEGEAR >= 0x0610) # define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0) # define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0)
@@ -464,11 +467,13 @@
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_GCC_CXX0X) # define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_GCC_CXX0X)
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_GCC_CXX0X) # define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_GCC_CXX0X)
# define ASMJIT_CC_HAS_ASSUME (0) # define ASMJIT_CC_HAS_ASSUME (0)
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_GCC_GE(2, 7, 0)) # define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_GCC_GE(2, 7, 0))
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_GCC_GE(4, 4, 0) && !ASMJIT_CC_MINGW) # define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_GCC_GE(4, 4, 0) && !ASMJIT_CC_MINGW)
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_GCC_GE(3, 4, 0) && !ASMJIT_CC_MINGW) # define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_GCC_GE(3, 4, 0) && !ASMJIT_CC_MINGW)
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_GCC_GE(2, 5, 0)) # define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_GCC_GE(2, 5, 0))
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0) # define ASMJIT_CC_HAS_BUILTIN_ASSUME (0)
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (ASMJIT_CC_GCC_GE(4, 7, 0))
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (1) # define ASMJIT_CC_HAS_BUILTIN_EXPECT (1)
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_GCC_CXX0X) # define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_GCC_CXX0X)
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_GCC_CXX0X) # define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_GCC_CXX0X)
@@ -497,6 +502,7 @@
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_MSC_GE(19, 0, 0)) # define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_MSC_GE(19, 0, 0)) # define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_ASSUME (1) # define ASMJIT_CC_HAS_ASSUME (1)
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0)
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_MSC_GE(19, 0, 0)) # define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (1) # define ASMJIT_CC_HAS_DECLSPEC_ALIGN (1)
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (1) # define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (1)
@@ -532,6 +538,7 @@
#if !ASMJIT_CC_HAS_BUILTIN #if !ASMJIT_CC_HAS_BUILTIN
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0) # define ASMJIT_CC_HAS_BUILTIN_ASSUME (0)
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (0)
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (0) # define ASMJIT_CC_HAS_BUILTIN_EXPECT (0)
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (0) # define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (0)
#endif #endif
@@ -719,6 +726,18 @@
#endif #endif
// [@CC_ASSUME}@] // [@CC_ASSUME}@]
// [@CC_ASSUME_ALIGNED{@]
// \def ASMJIT_ASSUME_ALIGNED(p, alignment)
// Assume that the pointer 'p' is aligned to at least 'alignment' bytes.
#if ASMJIT_CC_HAS_ASSUME_ALIGNED
# define ASMJIT_ASSUME_ALIGNED(p, alignment) __assume_aligned(p, alignment)
#elif ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED
# define ASMJIT_ASSUME_ALIGNED(p, alignment) p = __builtin_assume_aligned(p, alignment)
#else
# define ASMJIT_ASSUME_ALIGNED(p, alignment) ((void)0)
#endif
// [@CC_ASSUME_ALIGNED}@]
// [@CC_EXPECT{@] // [@CC_EXPECT{@]
// \def ASMJIT_LIKELY(exp) // \def ASMJIT_LIKELY(exp)
// Expression exp is likely to be true. // Expression exp is likely to be true.

View File

@@ -408,7 +408,13 @@ Error X86Assembler::align(uint32_t alignMode, uint32_t offset) noexcept {
"%s.align %u\n", _logger->getIndentation(), static_cast<unsigned int>(offset)); "%s.align %u\n", _logger->getIndentation(), static_cast<unsigned int>(offset));
#endif // !ASMJIT_DISABLE_LOGGER #endif // !ASMJIT_DISABLE_LOGGER
if (alignMode > kAlignZero || offset <= 1 || !Utils::isPowerOf2(offset) || offset > 64) if (alignMode > kAlignZero)
return setLastError(kErrorInvalidArgument);
if (offset <= 1)
return kErrorOk;
if (!Utils::isPowerOf2(offset) || offset > 64)
return setLastError(kErrorInvalidArgument); return setLastError(kErrorInvalidArgument);
uint32_t i = static_cast<uint32_t>(Utils::alignDiff<size_t>(getOffset(), offset)); uint32_t i = static_cast<uint32_t>(Utils::alignDiff<size_t>(getOffset(), offset));

View File

@@ -63,7 +63,7 @@ static uint32_t X86FuncDecl_initConv(X86FuncDecl* self, uint32_t arch, uint32_t
self->_callConv = static_cast<uint8_t>(callConv); self->_callConv = static_cast<uint8_t>(callConv);
self->_calleePopsStack = false; self->_calleePopsStack = false;
self->_direction = kFuncDirRTL; self->_argsDirection = kFuncDirRTL;
self->_passed.reset(); self->_passed.reset();
self->_preserved.reset(); self->_preserved.reset();
@@ -103,7 +103,7 @@ static uint32_t X86FuncDecl_initConv(X86FuncDecl* self, uint32_t arch, uint32_t
case kCallConvX86BorlandFastCall: case kCallConvX86BorlandFastCall:
self->_calleePopsStack = true; self->_calleePopsStack = true;
self->_direction = kFuncDirLTR; self->_argsDirection = kFuncDirLTR;
self->_passed.set(kX86RegClassGp, Utils::mask(R(Ax), R(Dx), R(Cx))); self->_passed.set(kX86RegClassGp, Utils::mask(R(Ax), R(Dx), R(Cx)));
self->_passedOrderGp[0] = R(Ax); self->_passedOrderGp[0] = R(Ax);
self->_passedOrderGp[1] = R(Dx); self->_passedOrderGp[1] = R(Dx);
@@ -347,7 +347,7 @@ static Error X86FuncDecl_initFunc(X86FuncDecl* self, uint32_t arch,
int32_t iEnd = -1; int32_t iEnd = -1;
int32_t iStep = -1; int32_t iStep = -1;
if (self->_direction == kFuncDirLTR) { if (self->_argsDirection == kFuncDirLTR) {
iStart = 0; iStart = 0;
iEnd = static_cast<int32_t>(numArgs); iEnd = static_cast<int32_t>(numArgs);
iStep = 1; iStep = 1;
@@ -518,7 +518,7 @@ void X86FuncDecl::reset() {
_callConv = kCallConvNone; _callConv = kCallConvNone;
_calleePopsStack = false; _calleePopsStack = false;
_direction = kFuncDirRTL; _argsDirection = kFuncDirRTL;
_reserved0 = 0; _reserved0 = 0;
_numArgs = 0; _numArgs = 0;

View File

@@ -175,6 +175,33 @@ struct X86Test_AlignBase : public X86Test {
bool _naked; bool _naked;
}; };
// ============================================================================
// [X86Test_AlignNone]
// ============================================================================
struct X86Test_AlignNone : public X86Test {
X86Test_AlignNone() : X86Test("[Align] None") {}
static void add(PodVector<X86Test*>& tests) {
tests.append(new X86Test_AlignNone());
}
virtual void compile(X86Compiler& c) {
c.addFunc(FuncBuilder0<void>(kCallConvHost));
c.align(kAlignCode, 0);
c.align(kAlignCode, 1);
c.endFunc();
}
virtual bool run(void* _func, StringBuilder& result, StringBuilder& expect) {
typedef void (*Func)(void);
Func func = asmjit_cast<Func>(_func);
func();
return true;
}
};
// ============================================================================ // ============================================================================
// [X86Test_JumpCross] // [X86Test_JumpCross]
// ============================================================================ // ============================================================================
@@ -2685,11 +2712,15 @@ struct X86Test_CallMisc5 : public X86Test {
virtual void compile(X86Compiler& c) { virtual void compile(X86Compiler& c) {
X86FuncNode* func = c.addFunc(FuncBuilder0<int>(kCallConvHost)); X86FuncNode* func = c.addFunc(FuncBuilder0<int>(kCallConvHost));
X86GpVar pFn = c.newIntPtr("pFn");
X86GpVar vars[16]; X86GpVar vars[16];
uint32_t i, regCount = c.getRegCount().getGp(); uint32_t i, regCount = c.getRegCount().getGp();
ASMJIT_ASSERT(regCount <= ASMJIT_ARRAY_SIZE(vars)); ASMJIT_ASSERT(regCount <= ASMJIT_ARRAY_SIZE(vars));
c.mov(pFn, imm_ptr(calledFunc));
c.spill(pFn);
for (i = 0; i < regCount; i++) { for (i = 0; i < regCount; i++) {
if (i == kX86RegIndexBp || i == kX86RegIndexSp) if (i == kX86RegIndexBp || i == kX86RegIndexSp)
continue; continue;
@@ -2699,7 +2730,7 @@ struct X86Test_CallMisc5 : public X86Test {
c.mov(vars[i], 1); c.mov(vars[i], 1);
} }
X86CallNode* call = c.call(imm_ptr(calledFunc), FuncBuilder0<void>(kCallConvHost)); X86CallNode* call = c.call(pFn, FuncBuilder0<void>(kCallConvHost));
for (i = 1; i < regCount; i++) { for (i = 1; i < regCount; i++) {
if (vars[i].isInitialized()) if (vars[i].isInitialized())
@@ -2939,7 +2970,7 @@ struct X86Test_MiscUnfollow : public X86Test {
// NOTE: Fastcall calling convention is the most appropriate here, as all // NOTE: Fastcall calling convention is the most appropriate here, as all
// arguments will be passed in registers and there won't be any stack // arguments will be passed in registers and there won't be any stack
// misalignment when we call the `handler()`. This was failing on OSX // misalignment when we call the `handler()`. This was failing on OSX
// when targetting 32-bit. // when targeting 32-bit.
c.addFunc(FuncBuilder2<void, int, void*>(kCallConvHostFastCall)); c.addFunc(FuncBuilder2<void, int, void*>(kCallConvHostFastCall));
X86GpVar a = c.newInt32("a"); X86GpVar a = c.newInt32("a");
@@ -3023,6 +3054,7 @@ X86TestSuite::X86TestSuite() :
// Align. // Align.
ADD_TEST(X86Test_AlignBase); ADD_TEST(X86Test_AlignBase);
ADD_TEST(X86Test_AlignNone);
// Jump. // Jump.
ADD_TEST(X86Test_JumpCross); ADD_TEST(X86Test_JumpCross);