diff options
Diffstat (limited to 'src/asmjit/x86/x86operand.h')
-rw-r--r-- | src/asmjit/x86/x86operand.h | 723 |
1 files changed, 336 insertions, 387 deletions
diff --git a/src/asmjit/x86/x86operand.h b/src/asmjit/x86/x86operand.h index 917c0f9..bfd09bd 100644 --- a/src/asmjit/x86/x86operand.h +++ b/src/asmjit/x86/x86operand.h @@ -1,25 +1,7 @@ -// AsmJit - Machine code generation for C++ +// This file is part of AsmJit project <https://asmjit.com> // -// * Official AsmJit Home Page: https://asmjit.com -// * Official Github Repository: https://github.com/asmjit/asmjit -// -// Copyright (c) 2008-2020 The AsmJit Authors -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib #ifndef ASMJIT_X86_X86OPERAND_H_INCLUDED #define ASMJIT_X86_X86OPERAND_H_INCLUDED @@ -31,62 +13,9 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) -#define ASMJIT_MEM_PTR(FUNC, SIZE) \ - static constexpr Mem FUNC(const Gp& base, int32_t offset = 0) noexcept { \ - return Mem(base, offset, SIZE); \ - } \ - static constexpr Mem FUNC(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ - return Mem(base, index, shift, offset, SIZE); \ - } \ - static constexpr Mem FUNC(const Gp& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ - return Mem(base, index, shift, offset, SIZE); \ - } \ - static constexpr Mem FUNC(const Label& base, int32_t offset = 0) noexcept { \ - return Mem(base, offset, SIZE); \ - } \ - static constexpr Mem FUNC(const Label& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ - return Mem(base, index, shift, offset, SIZE); \ - } \ - static constexpr Mem FUNC(const Rip& rip_, int32_t offset = 0) noexcept { \ - return Mem(rip_, offset, SIZE); \ - } \ - static constexpr Mem FUNC(uint64_t base) noexcept { \ - return Mem(base, SIZE); \ - } \ - static constexpr Mem FUNC(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE); \ - } \ - static constexpr Mem FUNC(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE); \ - } \ - \ - static constexpr Mem FUNC##_abs(uint64_t base) noexcept { \ - return Mem(base, SIZE, Mem::kSignatureMemAbs); \ - } \ - static constexpr Mem FUNC##_abs(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, Mem::kSignatureMemAbs); \ - } \ - static constexpr Mem FUNC##_abs(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, Mem::kSignatureMemAbs); \ - } \ - \ - static constexpr Mem FUNC##_rel(uint64_t base) noexcept { \ - return Mem(base, SIZE, Mem::kSignatureMemRel); \ - } \ - static constexpr Mem FUNC##_rel(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, Mem::kSignatureMemRel); \ - } \ - static constexpr Mem FUNC##_rel(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, Mem::kSignatureMemRel); \ - } - //! \addtogroup asmjit_x86 //! \{ -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - class Reg; class Mem; @@ -111,40 +40,35 @@ class Bnd; class Tmm; class Rip; -// ============================================================================ -// [asmjit::x86::Reg] -// ============================================================================ - //! Register traits (X86). //! -//! Register traits contains information about a particular register type. It's -//! used by asmjit to setup register information on-the-fly and to populate -//! tables that contain register information (this way it's possible to change +//! Register traits contains information about a particular register type. It's used by asmjit to setup register +//! information on-the-fly and to populate tables that contain register information (this way it's possible to change //! register types and groups without having to reorder these tables). -template<uint32_t REG_TYPE> +template<RegType kRegType> struct RegTraits : public BaseRegTraits {}; //! \cond -// <--------------------+-----+-------------------------+------------------------+---+---+----------------+ -// | Reg | Reg-Type | Reg-Group |Sz |Cnt| TypeId | -// <--------------------+-----+-------------------------+------------------------+---+---+----------------+ -ASMJIT_DEFINE_REG_TRAITS(GpbLo, BaseReg::kTypeGp8Lo , BaseReg::kGroupGp , 1 , 16, Type::kIdI8 ); -ASMJIT_DEFINE_REG_TRAITS(GpbHi, BaseReg::kTypeGp8Hi , BaseReg::kGroupGp , 1 , 4 , Type::kIdI8 ); -ASMJIT_DEFINE_REG_TRAITS(Gpw , BaseReg::kTypeGp16 , BaseReg::kGroupGp , 2 , 16, Type::kIdI16 ); -ASMJIT_DEFINE_REG_TRAITS(Gpd , BaseReg::kTypeGp32 , BaseReg::kGroupGp , 4 , 16, Type::kIdI32 ); -ASMJIT_DEFINE_REG_TRAITS(Gpq , BaseReg::kTypeGp64 , BaseReg::kGroupGp , 8 , 16, Type::kIdI64 ); -ASMJIT_DEFINE_REG_TRAITS(Xmm , BaseReg::kTypeVec128 , BaseReg::kGroupVec , 16, 32, Type::kIdI32x4 ); -ASMJIT_DEFINE_REG_TRAITS(Ymm , BaseReg::kTypeVec256 , BaseReg::kGroupVec , 32, 32, Type::kIdI32x8 ); -ASMJIT_DEFINE_REG_TRAITS(Zmm , BaseReg::kTypeVec512 , BaseReg::kGroupVec , 64, 32, Type::kIdI32x16); -ASMJIT_DEFINE_REG_TRAITS(Mm , BaseReg::kTypeOther0 , BaseReg::kGroupOther0 , 8 , 8 , Type::kIdMmx64 ); -ASMJIT_DEFINE_REG_TRAITS(KReg , BaseReg::kTypeOther1 , BaseReg::kGroupOther1 , 0 , 8 , Type::kIdVoid ); -ASMJIT_DEFINE_REG_TRAITS(SReg , BaseReg::kTypeCustom + 0, BaseReg::kGroupVirt + 0, 2 , 7 , Type::kIdVoid ); -ASMJIT_DEFINE_REG_TRAITS(CReg , BaseReg::kTypeCustom + 1, BaseReg::kGroupVirt + 1, 0 , 16, Type::kIdVoid ); -ASMJIT_DEFINE_REG_TRAITS(DReg , BaseReg::kTypeCustom + 2, BaseReg::kGroupVirt + 2, 0 , 16, Type::kIdVoid ); -ASMJIT_DEFINE_REG_TRAITS(St , BaseReg::kTypeCustom + 3, BaseReg::kGroupVirt + 3, 10, 8 , Type::kIdF80 ); -ASMJIT_DEFINE_REG_TRAITS(Bnd , BaseReg::kTypeCustom + 4, BaseReg::kGroupVirt + 4, 16, 4 , Type::kIdVoid ); -ASMJIT_DEFINE_REG_TRAITS(Tmm , BaseReg::kTypeCustom + 5, BaseReg::kGroupVirt + 5, 0 , 8 , Type::kIdVoid ); -ASMJIT_DEFINE_REG_TRAITS(Rip , BaseReg::kTypeIP , BaseReg::kGroupVirt + 6, 0 , 1 , Type::kIdVoid ); +// <--------------------+-----+-------------------------+------------------------+---+---+------------------+ +// | Reg | Reg-Type | Reg-Group |Sz |Cnt| TypeId | +// <--------------------+-----+-------------------------+------------------------+---+---+------------------+ +ASMJIT_DEFINE_REG_TRAITS(Rip , RegType::kX86_Rip , RegGroup::kX86_Rip , 0 , 1 , TypeId::kVoid ); +ASMJIT_DEFINE_REG_TRAITS(GpbLo, RegType::kX86_GpbLo , RegGroup::kGp , 1 , 16, TypeId::kInt8 ); +ASMJIT_DEFINE_REG_TRAITS(GpbHi, RegType::kX86_GpbHi , RegGroup::kGp , 1 , 4 , TypeId::kInt8 ); +ASMJIT_DEFINE_REG_TRAITS(Gpw , RegType::kX86_Gpw , RegGroup::kGp , 2 , 16, TypeId::kInt16 ); +ASMJIT_DEFINE_REG_TRAITS(Gpd , RegType::kX86_Gpd , RegGroup::kGp , 4 , 16, TypeId::kInt32 ); +ASMJIT_DEFINE_REG_TRAITS(Gpq , RegType::kX86_Gpq , RegGroup::kGp , 8 , 16, TypeId::kInt64 ); +ASMJIT_DEFINE_REG_TRAITS(Xmm , RegType::kX86_Xmm , RegGroup::kVec , 16, 32, TypeId::kInt32x4 ); +ASMJIT_DEFINE_REG_TRAITS(Ymm , RegType::kX86_Ymm , RegGroup::kVec , 32, 32, TypeId::kInt32x8 ); +ASMJIT_DEFINE_REG_TRAITS(Zmm , RegType::kX86_Zmm , RegGroup::kVec , 64, 32, TypeId::kInt32x16); +ASMJIT_DEFINE_REG_TRAITS(KReg , RegType::kX86_KReg , RegGroup::kX86_K , 0 , 8 , TypeId::kVoid ); +ASMJIT_DEFINE_REG_TRAITS(Mm , RegType::kX86_Mm , RegGroup::kX86_MM , 8 , 8 , TypeId::kMmx64 ); +ASMJIT_DEFINE_REG_TRAITS(SReg , RegType::kX86_SReg , RegGroup::kX86_SReg , 2 , 7 , TypeId::kVoid ); +ASMJIT_DEFINE_REG_TRAITS(CReg , RegType::kX86_CReg , RegGroup::kX86_CReg , 0 , 16, TypeId::kVoid ); +ASMJIT_DEFINE_REG_TRAITS(DReg , RegType::kX86_DReg , RegGroup::kX86_DReg , 0 , 16, TypeId::kVoid ); +ASMJIT_DEFINE_REG_TRAITS(St , RegType::kX86_St , RegGroup::kX86_St , 10, 8 , TypeId::kFloat80 ); +ASMJIT_DEFINE_REG_TRAITS(Bnd , RegType::kX86_Bnd , RegGroup::kX86_Bnd , 16, 4 , TypeId::kVoid ); +ASMJIT_DEFINE_REG_TRAITS(Tmm , RegType::kX86_Tmm , RegGroup::kX86_Tmm , 0 , 8 , TypeId::kVoid ); //! \endcond //! Register (X86). @@ -152,160 +76,84 @@ class Reg : public BaseReg { public: ASMJIT_DEFINE_ABSTRACT_REG(Reg, BaseReg) - //! Register type. - enum RegType : uint32_t { - //! No register type or invalid register. - kTypeNone = BaseReg::kTypeNone, - - //! Low GPB register (AL, BL, CL, DL, ...). - kTypeGpbLo = BaseReg::kTypeGp8Lo, - //! High GPB register (AH, BH, CH, DH only). - kTypeGpbHi = BaseReg::kTypeGp8Hi, - //! GPW register. - kTypeGpw = BaseReg::kTypeGp16, - //! GPD register. - kTypeGpd = BaseReg::kTypeGp32, - //! GPQ register (64-bit). - kTypeGpq = BaseReg::kTypeGp64, - //! XMM register (SSE+). - kTypeXmm = BaseReg::kTypeVec128, - //! YMM register (AVX+). - kTypeYmm = BaseReg::kTypeVec256, - //! ZMM register (AVX512+). - kTypeZmm = BaseReg::kTypeVec512, - //! MMX register. - kTypeMm = BaseReg::kTypeOther0, - //! K register (AVX512+). - kTypeKReg = BaseReg::kTypeOther1, - //! Instruction pointer (EIP, RIP). - kTypeRip = BaseReg::kTypeIP, - //! Segment register (None, ES, CS, SS, DS, FS, GS). - kTypeSReg = BaseReg::kTypeCustom + 0, - //! Control register (CR). - kTypeCReg = BaseReg::kTypeCustom + 1, - //! Debug register (DR). - kTypeDReg = BaseReg::kTypeCustom + 2, - //! FPU (x87) register. - kTypeSt = BaseReg::kTypeCustom + 3, - //! Bound register (BND). - kTypeBnd = BaseReg::kTypeCustom + 4, - //! TMM register (AMX_TILE) - kTypeTmm = BaseReg::kTypeCustom + 5, - - //! Count of register types. - kTypeCount = BaseReg::kTypeCustom + 6 - }; - - //! Register group. - enum RegGroup : uint32_t { - //! GP register group or none (universal). - kGroupGp = BaseReg::kGroupGp, - //! XMM|YMM|ZMM register group (universal). - kGroupVec = BaseReg::kGroupVec, - //! MMX register group (legacy). - kGroupMm = BaseReg::kGroupOther0, - //! K register group. - kGroupKReg = BaseReg::kGroupOther1, - - // These are not managed by Compiler nor used by Func-API: - - //! Segment register group. - kGroupSReg = BaseReg::kGroupVirt+0, - //! Control register group. - kGroupCReg = BaseReg::kGroupVirt+1, - //! Debug register group. - kGroupDReg = BaseReg::kGroupVirt+2, - //! FPU register group. - kGroupSt = BaseReg::kGroupVirt+3, - //! Bound register group. - kGroupBnd = BaseReg::kGroupVirt+4, - //! TMM register group. - kGroupTmm = BaseReg::kGroupVirt+5, - //! Instruction pointer (IP). - kGroupRip = BaseReg::kGroupVirt+6, - - //! Count of all register groups. - kGroupCount - }; - //! Tests whether the register is a GPB register (8-bit). - constexpr bool isGpb() const noexcept { return size() == 1; } + inline constexpr bool isGpb() const noexcept { return size() == 1; } //! Tests whether the register is a low GPB register (8-bit). - constexpr bool isGpbLo() const noexcept { return hasBaseSignature(RegTraits<kTypeGpbLo>::kSignature); } + inline constexpr bool isGpbLo() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_GpbLo>::kSignature); } //! Tests whether the register is a high GPB register (8-bit). - constexpr bool isGpbHi() const noexcept { return hasBaseSignature(RegTraits<kTypeGpbHi>::kSignature); } + inline constexpr bool isGpbHi() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_GpbHi>::kSignature); } //! Tests whether the register is a GPW register (16-bit). - constexpr bool isGpw() const noexcept { return hasBaseSignature(RegTraits<kTypeGpw>::kSignature); } + inline constexpr bool isGpw() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Gpw>::kSignature); } //! Tests whether the register is a GPD register (32-bit). - constexpr bool isGpd() const noexcept { return hasBaseSignature(RegTraits<kTypeGpd>::kSignature); } + inline constexpr bool isGpd() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Gpd>::kSignature); } //! Tests whether the register is a GPQ register (64-bit). - constexpr bool isGpq() const noexcept { return hasBaseSignature(RegTraits<kTypeGpq>::kSignature); } + inline constexpr bool isGpq() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Gpq>::kSignature); } //! Tests whether the register is an XMM register (128-bit). - constexpr bool isXmm() const noexcept { return hasBaseSignature(RegTraits<kTypeXmm>::kSignature); } + inline constexpr bool isXmm() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Xmm>::kSignature); } //! Tests whether the register is a YMM register (256-bit). - constexpr bool isYmm() const noexcept { return hasBaseSignature(RegTraits<kTypeYmm>::kSignature); } + inline constexpr bool isYmm() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Ymm>::kSignature); } //! Tests whether the register is a ZMM register (512-bit). - constexpr bool isZmm() const noexcept { return hasBaseSignature(RegTraits<kTypeZmm>::kSignature); } + inline constexpr bool isZmm() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Zmm>::kSignature); } //! Tests whether the register is an MMX register (64-bit). - constexpr bool isMm() const noexcept { return hasBaseSignature(RegTraits<kTypeMm>::kSignature); } + inline constexpr bool isMm() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Mm>::kSignature); } //! Tests whether the register is a K register (64-bit). - constexpr bool isKReg() const noexcept { return hasBaseSignature(RegTraits<kTypeKReg>::kSignature); } + inline constexpr bool isKReg() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_KReg>::kSignature); } //! Tests whether the register is a segment register. - constexpr bool isSReg() const noexcept { return hasBaseSignature(RegTraits<kTypeSReg>::kSignature); } + inline constexpr bool isSReg() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_SReg>::kSignature); } //! Tests whether the register is a control register. - constexpr bool isCReg() const noexcept { return hasBaseSignature(RegTraits<kTypeCReg>::kSignature); } + inline constexpr bool isCReg() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_CReg>::kSignature); } //! Tests whether the register is a debug register. - constexpr bool isDReg() const noexcept { return hasBaseSignature(RegTraits<kTypeDReg>::kSignature); } + inline constexpr bool isDReg() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_DReg>::kSignature); } //! Tests whether the register is an FPU register (80-bit). - constexpr bool isSt() const noexcept { return hasBaseSignature(RegTraits<kTypeSt>::kSignature); } + inline constexpr bool isSt() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_St>::kSignature); } //! Tests whether the register is a bound register. - constexpr bool isBnd() const noexcept { return hasBaseSignature(RegTraits<kTypeBnd>::kSignature); } + inline constexpr bool isBnd() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Bnd>::kSignature); } //! Tests whether the register is a TMM register. - constexpr bool isTmm() const noexcept { return hasBaseSignature(RegTraits<kTypeTmm>::kSignature); } + inline constexpr bool isTmm() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Tmm>::kSignature); } //! Tests whether the register is RIP. - constexpr bool isRip() const noexcept { return hasBaseSignature(RegTraits<kTypeRip>::kSignature); } + inline constexpr bool isRip() const noexcept { return hasBaseSignature(RegTraits<RegType::kX86_Rip>::kSignature); } - template<uint32_t REG_TYPE> + template<RegType REG_TYPE> inline void setRegT(uint32_t rId) noexcept { - setSignature(RegTraits<REG_TYPE>::kSignature); + setSignature(OperandSignature(RegTraits<REG_TYPE>::kSignature)); setId(rId); } - inline void setTypeAndId(uint32_t rType, uint32_t rId) noexcept { - ASMJIT_ASSERT(rType < kTypeCount); - setSignature(signatureOf(rType)); - setId(rId); + inline void setTypeAndId(RegType type, uint32_t id) noexcept { + setSignature(signatureOf(type)); + setId(id); } - static inline uint32_t groupOf(uint32_t rType) noexcept { return _archTraits[Environment::kArchX86].regTypeToGroup(rType); } - static inline uint32_t typeIdOf(uint32_t rType) noexcept { return _archTraits[Environment::kArchX86].regTypeToTypeId(rType); } - static inline uint32_t signatureOf(uint32_t rType) noexcept { return _archTraits[Environment::kArchX86].regTypeToSignature(rType); } + static inline RegGroup groupOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kX86).regTypeToGroup(type); } + static inline TypeId typeIdOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kX86).regTypeToTypeId(type); } + static inline OperandSignature signatureOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kX86).regTypeToSignature(type); } - template<uint32_t REG_TYPE> - static inline uint32_t groupOfT() noexcept { return RegTraits<REG_TYPE>::kGroup; } + template<RegType REG_TYPE> + static inline RegGroup groupOfT() noexcept { return RegGroup(RegTraits<REG_TYPE>::kGroup); } - template<uint32_t REG_TYPE> - static inline uint32_t typeIdOfT() noexcept { return RegTraits<REG_TYPE>::kTypeId; } + template<RegType REG_TYPE> + static inline TypeId typeIdOfT() noexcept { return TypeId(RegTraits<REG_TYPE>::kTypeId); } - template<uint32_t REG_TYPE> - static inline uint32_t signatureOfT() noexcept { return RegTraits<REG_TYPE>::kSignature; } + template<RegType REG_TYPE> + static inline OperandSignature signatureOfT() noexcept { return OperandSignature(RegTraits<REG_TYPE>::kSignature); } - static inline uint32_t signatureOfVecByType(uint32_t typeId) noexcept { - return typeId <= Type::_kIdVec128End ? RegTraits<kTypeXmm>::kSignature : - typeId <= Type::_kIdVec256End ? RegTraits<kTypeYmm>::kSignature : RegTraits<kTypeZmm>::kSignature; + static inline OperandSignature signatureOfVecByType(TypeId typeId) noexcept { + return OperandSignature(typeId <= TypeId::_kVec128End ? uint32_t(RegTraits<RegType::kX86_Xmm>::kSignature) : + typeId <= TypeId::_kVec256End ? uint32_t(RegTraits<RegType::kX86_Ymm>::kSignature) : + uint32_t(RegTraits<RegType::kX86_Zmm>::kSignature)); } - static inline uint32_t signatureOfVecBySize(uint32_t size) noexcept { - return size <= 16 ? RegTraits<kTypeXmm>::kSignature : - size <= 32 ? RegTraits<kTypeYmm>::kSignature : RegTraits<kTypeZmm>::kSignature; + static inline OperandSignature signatureOfVecBySize(uint32_t size) noexcept { + return OperandSignature(size <= 16 ? uint32_t(RegTraits<RegType::kX86_Xmm>::kSignature) : + size <= 32 ? uint32_t(RegTraits<RegType::kX86_Ymm>::kSignature) : + uint32_t(RegTraits<RegType::kX86_Zmm>::kSignature)); } //! Tests whether the `op` operand is either a low or high 8-bit GPB register. static inline bool isGpb(const Operand_& op) noexcept { // Check operand type, register group, and size. Not interested in register type. - const uint32_t kSgn = (Operand::kOpReg << kSignatureOpTypeShift) | - (1 << kSignatureSizeShift ) ; - return (op.signature() & (kSignatureOpTypeMask | kSignatureSizeMask)) == kSgn; + return op.signature().subset(Signature::kOpTypeMask | Signature::kRegGroupMask | Signature::kSizeMask) == + (Signature::fromOpType(OperandType::kReg) | Signature::fromRegGroup(RegGroup::kGp) | Signature::fromSize(1)); } static inline bool isGpbLo(const Operand_& op) noexcept { return op.as<Reg>().isGpbLo(); } @@ -353,9 +201,8 @@ public: //! Physical id (X86). //! - //! \note Register indexes have been reduced to only support general purpose - //! registers. There is no need to have enumerations with number suffix that - //! expands to the exactly same value as the suffix value itself. + //! \note Register indexes have been reduced to only support general purpose registers. There is no need to + //! have enumerations with number suffix that expands to the exactly same value as the suffix value itself. enum Id : uint32_t { kIdAx = 0, //!< Physical id of AL|AH|AX|EAX|RAX registers. kIdCx = 1, //!< Physical id of CL|CH|CX|ECX|RCX registers. @@ -402,13 +249,13 @@ class Vec : public Reg { //! Casts this register to a register that has half the size (or XMM if it's already XMM). inline Vec half() const noexcept { - return Vec::fromSignatureAndId(type() == kTypeZmm ? signatureOfT<kTypeYmm>() : signatureOfT<kTypeXmm>(), id()); + return Vec(type() == RegType::kX86_Zmm ? signatureOfT<RegType::kX86_Ymm>() : signatureOfT<RegType::kX86_Xmm>(), id()); } }; //! Segment register (X86). class SReg : public Reg { - ASMJIT_DEFINE_FINAL_REG(SReg, Reg, RegTraits<kTypeSReg>) + ASMJIT_DEFINE_FINAL_REG(SReg, Reg, RegTraits<RegType::kX86_SReg>) //! X86 segment id. enum Id : uint32_t { @@ -429,11 +276,9 @@ class SReg : public Reg { //! Count of X86 segment registers supported by AsmJit. //! - //! \note X86 architecture has 6 segment registers - ES, CS, SS, DS, FS, GS. - //! X64 architecture lowers them down to just FS and GS. AsmJit supports 7 - //! segment registers - all addressable in both X86 and X64 modes and one - //! extra called `SReg::kIdNone`, which is AsmJit specific and means that - //! there is no segment register specified. + //! \note X86 architecture has 6 segment registers - ES, CS, SS, DS, FS, GS. X64 architecture lowers them down to + //! just FS and GS. AsmJit supports 7 segment registers - all addressable in both X86 and X64 modes and one extra + //! called `SReg::kIdNone`, which is AsmJit specific and means that there is no segment register specified. kIdCount = 7 }; }; @@ -441,53 +286,53 @@ class SReg : public Reg { //! GPB low or high register (X86). class Gpb : public Gp { ASMJIT_DEFINE_ABSTRACT_REG(Gpb, Gp) }; //! GPB low register (X86). -class GpbLo : public Gpb { ASMJIT_DEFINE_FINAL_REG(GpbLo, Gpb, RegTraits<kTypeGpbLo>) }; +class GpbLo : public Gpb { ASMJIT_DEFINE_FINAL_REG(GpbLo, Gpb, RegTraits<RegType::kX86_GpbLo>) }; //! GPB high register (X86). -class GpbHi : public Gpb { ASMJIT_DEFINE_FINAL_REG(GpbHi, Gpb, RegTraits<kTypeGpbHi>) }; +class GpbHi : public Gpb { ASMJIT_DEFINE_FINAL_REG(GpbHi, Gpb, RegTraits<RegType::kX86_GpbHi>) }; //! GPW register (X86). -class Gpw : public Gp { ASMJIT_DEFINE_FINAL_REG(Gpw, Gp, RegTraits<kTypeGpw>) }; +class Gpw : public Gp { ASMJIT_DEFINE_FINAL_REG(Gpw, Gp, RegTraits<RegType::kX86_Gpw>) }; //! GPD register (X86). -class Gpd : public Gp { ASMJIT_DEFINE_FINAL_REG(Gpd, Gp, RegTraits<kTypeGpd>) }; +class Gpd : public Gp { ASMJIT_DEFINE_FINAL_REG(Gpd, Gp, RegTraits<RegType::kX86_Gpd>) }; //! GPQ register (X86_64). -class Gpq : public Gp { ASMJIT_DEFINE_FINAL_REG(Gpq, Gp, RegTraits<kTypeGpq>) }; +class Gpq : public Gp { ASMJIT_DEFINE_FINAL_REG(Gpq, Gp, RegTraits<RegType::kX86_Gpq>) }; //! 128-bit XMM register (SSE+). class Xmm : public Vec { - ASMJIT_DEFINE_FINAL_REG(Xmm, Vec, RegTraits<kTypeXmm>) + ASMJIT_DEFINE_FINAL_REG(Xmm, Vec, RegTraits<RegType::kX86_Xmm>) //! Casts this register to a register that has half the size (XMM). inline Xmm half() const noexcept { return Xmm(id()); } }; //! 256-bit YMM register (AVX+). class Ymm : public Vec { - ASMJIT_DEFINE_FINAL_REG(Ymm, Vec, RegTraits<kTypeYmm>) + ASMJIT_DEFINE_FINAL_REG(Ymm, Vec, RegTraits<RegType::kX86_Ymm>) //! Casts this register to a register that has half the size (XMM). inline Xmm half() const noexcept { return Xmm(id()); } }; //! 512-bit ZMM register (AVX512+). class Zmm : public Vec { - ASMJIT_DEFINE_FINAL_REG(Zmm, Vec, RegTraits<kTypeZmm>) + ASMJIT_DEFINE_FINAL_REG(Zmm, Vec, RegTraits<RegType::kX86_Zmm>) //! Casts this register to a register that has half the size (YMM). inline Ymm half() const noexcept { return Ymm(id()); } }; //! 64-bit MMX register (MMX+). -class Mm : public Reg { ASMJIT_DEFINE_FINAL_REG(Mm, Reg, RegTraits<kTypeMm>) }; +class Mm : public Reg { ASMJIT_DEFINE_FINAL_REG(Mm, Reg, RegTraits<RegType::kX86_Mm>) }; //! 64-bit K register (AVX512+). -class KReg : public Reg { ASMJIT_DEFINE_FINAL_REG(KReg, Reg, RegTraits<kTypeKReg>) }; +class KReg : public Reg { ASMJIT_DEFINE_FINAL_REG(KReg, Reg, RegTraits<RegType::kX86_KReg>) }; //! 32-bit or 64-bit control register (X86). -class CReg : public Reg { ASMJIT_DEFINE_FINAL_REG(CReg, Reg, RegTraits<kTypeCReg>) }; +class CReg : public Reg { ASMJIT_DEFINE_FINAL_REG(CReg, Reg, RegTraits<RegType::kX86_CReg>) }; //! 32-bit or 64-bit debug register (X86). -class DReg : public Reg { ASMJIT_DEFINE_FINAL_REG(DReg, Reg, RegTraits<kTypeDReg>) }; +class DReg : public Reg { ASMJIT_DEFINE_FINAL_REG(DReg, Reg, RegTraits<RegType::kX86_DReg>) }; //! 80-bit FPU register (X86). -class St : public Reg { ASMJIT_DEFINE_FINAL_REG(St, Reg, RegTraits<kTypeSt>) }; +class St : public Reg { ASMJIT_DEFINE_FINAL_REG(St, Reg, RegTraits<RegType::kX86_St>) }; //! 128-bit BND register (BND+). -class Bnd : public Reg { ASMJIT_DEFINE_FINAL_REG(Bnd, Reg, RegTraits<kTypeBnd>) }; +class Bnd : public Reg { ASMJIT_DEFINE_FINAL_REG(Bnd, Reg, RegTraits<RegType::kX86_Bnd>) }; //! 8192-bit TMM register (AMX). -class Tmm : public Reg { ASMJIT_DEFINE_FINAL_REG(Tmm, Reg, RegTraits<kTypeTmm>) }; +class Tmm : public Reg { ASMJIT_DEFINE_FINAL_REG(Tmm, Reg, RegTraits<RegType::kX86_Tmm>) }; //! RIP register (X86). -class Rip : public Reg { ASMJIT_DEFINE_FINAL_REG(Rip, Reg, RegTraits<kTypeRip>) }; +class Rip : public Reg { ASMJIT_DEFINE_FINAL_REG(Rip, Reg, RegTraits<RegType::kX86_Rip>) }; //! \cond inline GpbLo Gp::r8() const noexcept { return GpbLo(id()); } @@ -809,13 +654,12 @@ static constexpr Rip rip = Rip(0); using namespace regs; #endif -// ============================================================================ -// [asmjit::x86::Mem] -// ============================================================================ - -//! Memory operand. +//! Memory operand specific to X86 and X86_64 architecture. class Mem : public BaseMem { public: + //! \name Constants + //! \{ + //! Additional bits of operand's signature used by `x86::Mem`. enum AdditionalBits : uint32_t { // Memory address type (2 bits). @@ -840,85 +684,111 @@ public: }; //! Address type. - enum AddrType : uint32_t { + enum class AddrType : uint32_t { //! Default address type, Assembler will select the best type when necessary. - kAddrTypeDefault = 0, + kDefault = 0, //! Absolute address type. - kAddrTypeAbs = 1, + kAbs = 1, //! Relative address type. - kAddrTypeRel = 2 + kRel = 2, + + //! Maximum value of `AddrType`. + kMaxValue = kRel }; //! Memory broadcast type. - enum Broadcast : uint32_t { - //! Broadcast {1to1}. - kBroadcast1To1 = 0, + enum class Broadcast : uint32_t { + //! No broadcast (regular memory operand). + kNone = 0, //! Broadcast {1to2}. - kBroadcast1To2 = 1, + k1To2 = 1, //! Broadcast {1to4}. - kBroadcast1To4 = 2, + k1To4 = 2, //! Broadcast {1to8}. - kBroadcast1To8 = 3, + k1To8 = 3, //! Broadcast {1to16}. - kBroadcast1To16 = 4, + k1To16 = 4, //! Broadcast {1to32}. - kBroadcast1To32 = 5, + k1To32 = 5, //! Broadcast {1to64}. - kBroadcast1To64 = 6 - }; + k1To64 = 6, - //! \cond - //! Shortcuts. - enum SignatureMem : uint32_t { - kSignatureMemAbs = kAddrTypeAbs << kSignatureMemAddrTypeShift, - kSignatureMemRel = kAddrTypeRel << kSignatureMemAddrTypeShift + //! Maximum value of `Broadcast`. + kMaxValue = k1To64 }; - //! \endcond - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- + //! \} + + //! \name Construction & Destruction + //! \{ //! Creates a default `Mem` operand that points to [0]. - constexpr Mem() noexcept + inline constexpr Mem() noexcept : BaseMem() {} - constexpr Mem(const Mem& other) noexcept + inline constexpr Mem(const Mem& other) noexcept : BaseMem(other) {} - //! \cond INTERNAL - //! - //! A constructor used internally to create `Mem` operand from `Decomposed` data. - constexpr explicit Mem(const Decomposed& d) noexcept - : BaseMem(d) {} - //! \endcond - - constexpr Mem(const Label& base, int32_t off, uint32_t size = 0, uint32_t flags = 0) noexcept - : BaseMem(Decomposed { Label::kLabelTag, base.id(), 0, 0, off, size, flags }) {} - - constexpr Mem(const Label& base, const BaseReg& index, uint32_t shift, int32_t off, uint32_t size = 0, uint32_t flags = 0) noexcept - : BaseMem(Decomposed { Label::kLabelTag, base.id(), index.type(), index.id(), off, size, flags | (shift << kSignatureMemShiftValueShift) }) {} - - constexpr Mem(const BaseReg& base, int32_t off, uint32_t size = 0, uint32_t flags = 0) noexcept - : BaseMem(Decomposed { base.type(), base.id(), 0, 0, off, size, flags }) {} - - constexpr Mem(const BaseReg& base, const BaseReg& index, uint32_t shift, int32_t off, uint32_t size = 0, uint32_t flags = 0) noexcept - : BaseMem(Decomposed { base.type(), base.id(), index.type(), index.id(), off, size, flags | (shift << kSignatureMemShiftValueShift) }) {} + inline explicit Mem(Globals::NoInit_) noexcept + : BaseMem(Globals::NoInit) {} - constexpr explicit Mem(uint64_t base, uint32_t size = 0, uint32_t flags = 0) noexcept - : BaseMem(Decomposed { 0, uint32_t(base >> 32), 0, 0, int32_t(uint32_t(base & 0xFFFFFFFFu)), size, flags }) {} + inline constexpr Mem(const Signature& signature, uint32_t baseId, uint32_t indexId, int32_t offset) noexcept + : BaseMem(signature, baseId, indexId, offset) {} + + inline constexpr Mem(const Label& base, int32_t off, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + : BaseMem(Signature::fromOpType(OperandType::kMem) | + Signature::fromMemBaseType(RegType::kLabelTag) | + Signature::fromSize(size) | + signature, base.id(), 0, off) {} + + inline constexpr Mem(const Label& base, const BaseReg& index, uint32_t shift, int32_t off, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + : BaseMem(Signature::fromOpType(OperandType::kMem) | + Signature::fromMemBaseType(RegType::kLabelTag) | + Signature::fromMemIndexType(index.type()) | + Signature::fromValue<kSignatureMemShiftValueMask>(shift) | + Signature::fromSize(size) | + signature, base.id(), index.id(), off) {} + + inline constexpr Mem(const BaseReg& base, int32_t off, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + : BaseMem(Signature::fromOpType(OperandType::kMem) | + Signature::fromMemBaseType(base.type()) | + Signature::fromSize(size) | + signature, base.id(), 0, off) {} + + inline constexpr Mem(const BaseReg& base, const BaseReg& index, uint32_t shift, int32_t off, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + : BaseMem(Signature::fromOpType(OperandType::kMem) | + Signature::fromMemBaseType(base.type()) | + Signature::fromMemIndexType(index.type()) | + Signature::fromValue<kSignatureMemShiftValueMask>(shift) | + Signature::fromSize(size) | + signature, base.id(), index.id(), off) {} + + inline constexpr explicit Mem(uint64_t base, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + : BaseMem(Signature::fromOpType(OperandType::kMem) | + Signature::fromSize(size) | + signature, uint32_t(base >> 32), 0, int32_t(uint32_t(base & 0xFFFFFFFFu))) {} + + inline constexpr Mem(uint64_t base, const BaseReg& index, uint32_t shift = 0, uint32_t size = 0, Signature signature = OperandSignature(0)) noexcept + : BaseMem(Signature::fromOpType(OperandType::kMem) | + Signature::fromMemIndexType(index.type()) | + Signature::fromValue<kSignatureMemShiftValueMask>(shift) | + Signature::fromSize(size) | + signature, uint32_t(base >> 32), index.id(), int32_t(uint32_t(base & 0xFFFFFFFFu))) {} + + //! \} + + //! \name Overloaded Operators + //! \{ - constexpr Mem(uint64_t base, const BaseReg& index, uint32_t shift = 0, uint32_t size = 0, uint32_t flags = 0) noexcept - : BaseMem(Decomposed { 0, uint32_t(base >> 32), index.type(), index.id(), int32_t(uint32_t(base & 0xFFFFFFFFu)), size, flags | (shift << kSignatureMemShiftValueShift) }) {} + inline Mem& operator=(const Mem& other) noexcept = default; - constexpr Mem(Globals::Init_, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) noexcept - : BaseMem(Globals::Init, u0, u1, u2, u3) {} + //! \} - inline explicit Mem(Globals::NoInit_) noexcept - : BaseMem(Globals::NoInit) {} + //! \name Clone + //! \{ //! Clones the memory operand. - constexpr Mem clone() const noexcept { return Mem(*this); } + inline constexpr Mem clone() const noexcept { return Mem(*this); } //! Creates a new copy of this memory operand adjusted by `off`. inline Mem cloneAdjusted(int64_t off) const noexcept { @@ -927,6 +797,15 @@ public: return result; } + inline constexpr Mem cloneBroadcasted(Broadcast b) const noexcept { + return Mem((_signature & ~Signature(kSignatureMemBroadcastMask)) | Signature::fromValue<kSignatureMemBroadcastMask>(b), _baseId, _data[0], int32_t(_data[1])); + } + + //! \} + + //! \name Base & Index + //! \{ + //! Converts memory `baseType` and `baseId` to `x86::Reg` instance. //! //! The memory must have a valid base register otherwise the result will be wrong. @@ -937,18 +816,6 @@ public: //! The memory must have a valid index register otherwise the result will be wrong. inline Reg indexReg() const noexcept { return Reg::fromTypeAndId(indexType(), indexId()); } - constexpr Mem _1to1() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To1 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } - constexpr Mem _1to2() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To2 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } - constexpr Mem _1to4() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To4 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } - constexpr Mem _1to8() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To8 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } - constexpr Mem _1to16() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To16 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } - constexpr Mem _1to32() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To32 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } - constexpr Mem _1to64() const noexcept { return Mem(Globals::Init, (_signature & ~kSignatureMemBroadcastMask) | (kBroadcast1To64 << kSignatureMemBroadcastShift), _baseId, _data[0], _data[1]); } - - // -------------------------------------------------------------------------- - // [Mem] - // -------------------------------------------------------------------------- - using BaseMem::setIndex; inline void setIndex(const BaseReg& index, uint32_t shift) noexcept { @@ -956,134 +823,220 @@ public: setShift(shift); } - //! Returns the address type (see \ref AddrType) of the memory operand. + //! \} + + //! \name Address Type + //! \{ + + //! Returns the address type of the memory operand. //! - //! By default, address type of newly created memory operands is always \ref kAddrTypeDefault. - constexpr uint32_t addrType() const noexcept { return _getSignaturePart<kSignatureMemAddrTypeMask>(); } - //! Sets the address type to `addrType`, see \ref AddrType. - inline void setAddrType(uint32_t addrType) noexcept { _setSignaturePart<kSignatureMemAddrTypeMask>(addrType); } - //! Resets the address type to \ref kAddrTypeDefault. - inline void resetAddrType() noexcept { _setSignaturePart<kSignatureMemAddrTypeMask>(0); } - - //! Tests whether the address type is \ref kAddrTypeAbs. - constexpr bool isAbs() const noexcept { return addrType() == kAddrTypeAbs; } - //! Sets the address type to \ref kAddrTypeAbs. - inline void setAbs() noexcept { setAddrType(kAddrTypeAbs); } - - //! Tests whether the address type is \ref kAddrTypeRel. - constexpr bool isRel() const noexcept { return addrType() == kAddrTypeRel; } - //! Sets the address type to \ref kAddrTypeRel. - inline void setRel() noexcept { setAddrType(kAddrTypeRel); } + //! By default, address type of newly created memory operands is always \ref AddrType::kDefault. + inline constexpr AddrType addrType() const noexcept { return (AddrType)_signature.getField<kSignatureMemAddrTypeMask>(); } + //! Sets the address type to `addrType`. + inline void setAddrType(AddrType addrType) noexcept { _signature.setField<kSignatureMemAddrTypeMask>(uint32_t(addrType)); } + //! Resets the address type to \ref AddrType::kDefault. + inline void resetAddrType() noexcept { _signature.setField<kSignatureMemAddrTypeMask>(uint32_t(AddrType::kDefault)); } + + //! Tests whether the address type is \ref AddrType::kAbs. + inline constexpr bool isAbs() const noexcept { return addrType() == AddrType::kAbs; } + //! Sets the address type to \ref AddrType::kAbs. + inline void setAbs() noexcept { setAddrType(AddrType::kAbs); } + + //! Tests whether the address type is \ref AddrType::kRel. + inline constexpr bool isRel() const noexcept { return addrType() == AddrType::kRel; } + //! Sets the address type to \ref AddrType::kRel. + inline void setRel() noexcept { setAddrType(AddrType::kRel); } + + //! \} + + //! \name Segment + //! \{ //! Tests whether the memory operand has a segment override. - constexpr bool hasSegment() const noexcept { return _hasSignaturePart<kSignatureMemSegmentMask>(); } + inline constexpr bool hasSegment() const noexcept { return _signature.hasField<kSignatureMemSegmentMask>(); } //! Returns the associated segment override as `SReg` operand. - constexpr SReg segment() const noexcept { return SReg(segmentId()); } + inline constexpr SReg segment() const noexcept { return SReg(segmentId()); } //! Returns segment override register id, see `SReg::Id`. - constexpr uint32_t segmentId() const noexcept { return _getSignaturePart<kSignatureMemSegmentMask>(); } + inline constexpr uint32_t segmentId() const noexcept { return _signature.getField<kSignatureMemSegmentMask>(); } //! Sets the segment override to `seg`. inline void setSegment(const SReg& seg) noexcept { setSegment(seg.id()); } //! Sets the segment override to `id`. - inline void setSegment(uint32_t rId) noexcept { _setSignaturePart<kSignatureMemSegmentMask>(rId); } + inline void setSegment(uint32_t rId) noexcept { _signature.setField<kSignatureMemSegmentMask>(rId); } //! Resets the segment override. - inline void resetSegment() noexcept { _setSignaturePart<kSignatureMemSegmentMask>(0); } + inline void resetSegment() noexcept { _signature.setField<kSignatureMemSegmentMask>(0); } + + //! \} + + //! \name Shift + //! \{ //! Tests whether the memory operand has shift (aka scale) value. - constexpr bool hasShift() const noexcept { return _hasSignaturePart<kSignatureMemShiftValueMask>(); } + inline constexpr bool hasShift() const noexcept { return _signature.hasField<kSignatureMemShiftValueMask>(); } //! Returns the memory operand's shift (aka scale) value. - constexpr uint32_t shift() const noexcept { return _getSignaturePart<kSignatureMemShiftValueMask>(); } + inline constexpr uint32_t shift() const noexcept { return _signature.getField<kSignatureMemShiftValueMask>(); } //! Sets the memory operand's shift (aka scale) value. - inline void setShift(uint32_t shift) noexcept { _setSignaturePart<kSignatureMemShiftValueMask>(shift); } + inline void setShift(uint32_t shift) noexcept { _signature.setField<kSignatureMemShiftValueMask>(shift); } //! Resets the memory operand's shift (aka scale) value to zero. - inline void resetShift() noexcept { _setSignaturePart<kSignatureMemShiftValueMask>(0); } + inline void resetShift() noexcept { _signature.setField<kSignatureMemShiftValueMask>(0); } + + //! \} + + //! \name Broadcast + //! \{ //! Tests whether the memory operand has broadcast {1tox}. - constexpr bool hasBroadcast() const noexcept { return _hasSignaturePart<kSignatureMemBroadcastMask>(); } + inline constexpr bool hasBroadcast() const noexcept { return _signature.hasField<kSignatureMemBroadcastMask>(); } //! Returns the memory operand's broadcast. - constexpr uint32_t getBroadcast() const noexcept { return _getSignaturePart<kSignatureMemBroadcastMask>(); } + inline constexpr Broadcast getBroadcast() const noexcept { return (Broadcast)_signature.getField<kSignatureMemBroadcastMask>(); } //! Sets the memory operand's broadcast. - inline void setBroadcast(uint32_t bcst) noexcept { _setSignaturePart<kSignatureMemBroadcastMask>(bcst); } + inline void setBroadcast(Broadcast b) noexcept { _signature.setField<kSignatureMemBroadcastMask>(uint32_t(b)); } //! Resets the memory operand's broadcast to none. - inline void resetBroadcast() noexcept { _setSignaturePart<kSignatureMemBroadcastMask>(0); } - - // -------------------------------------------------------------------------- - // [Operator Overload] - // -------------------------------------------------------------------------- - - inline Mem& operator=(const Mem& other) noexcept = default; + inline void resetBroadcast() noexcept { _signature.setField<kSignatureMemBroadcastMask>(0); } + + //! Returns a new `Mem` without a broadcast (the possible broadcast is cleared). + inline constexpr Mem _1to1() const noexcept { return cloneBroadcasted(Broadcast::kNone); } + //! Returns a new `Mem` with {1to2} broadcast (AVX-512). + inline constexpr Mem _1to2() const noexcept { return cloneBroadcasted(Broadcast::k1To2); } + //! Returns a new `Mem` with {1to4} broadcast (AVX-512). + inline constexpr Mem _1to4() const noexcept { return cloneBroadcasted(Broadcast::k1To4); } + //! Returns a new `Mem` with {1to8} broadcast (AVX-512). + inline constexpr Mem _1to8() const noexcept { return cloneBroadcasted(Broadcast::k1To8); } + //! Returns a new `Mem` with {1to16} broadcast (AVX-512). + inline constexpr Mem _1to16() const noexcept { return cloneBroadcasted(Broadcast::k1To16); } + //! Returns a new `Mem` with {1to32} broadcast (AVX-512). + inline constexpr Mem _1to32() const noexcept { return cloneBroadcasted(Broadcast::k1To32); } + //! Returns a new `Mem` with {1to64} broadcast (AVX-512). + inline constexpr Mem _1to64() const noexcept { return cloneBroadcasted(Broadcast::k1To64); } + + //! \} }; //! Creates `[base.reg + offset]` memory operand. -static constexpr Mem ptr(const Gp& base, int32_t offset = 0, uint32_t size = 0) noexcept { +static inline constexpr Mem ptr(const Gp& base, int32_t offset = 0, uint32_t size = 0) noexcept { return Mem(base, offset, size); } //! Creates `[base.reg + (index << shift) + offset]` memory operand (scalar index). -static constexpr Mem ptr(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0, uint32_t size = 0) noexcept { +static inline constexpr Mem ptr(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0, uint32_t size = 0) noexcept { return Mem(base, index, shift, offset, size); } //! Creates `[base.reg + (index << shift) + offset]` memory operand (vector index). -static constexpr Mem ptr(const Gp& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0, uint32_t size = 0) noexcept { +static inline constexpr Mem ptr(const Gp& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0, uint32_t size = 0) noexcept { return Mem(base, index, shift, offset, size); } //! Creates `[base + offset]` memory operand. -static constexpr Mem ptr(const Label& base, int32_t offset = 0, uint32_t size = 0) noexcept { +static inline constexpr Mem ptr(const Label& base, int32_t offset = 0, uint32_t size = 0) noexcept { return Mem(base, offset, size); } //! Creates `[base + (index << shift) + offset]` memory operand. -static constexpr Mem ptr(const Label& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0, uint32_t size = 0) noexcept { +static inline constexpr Mem ptr(const Label& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0, uint32_t size = 0) noexcept { return Mem(base, index, shift, offset, size); } //! Creates `[base + (index << shift) + offset]` memory operand. -static constexpr Mem ptr(const Label& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0, uint32_t size = 0) noexcept { +static inline constexpr Mem ptr(const Label& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0, uint32_t size = 0) noexcept { return Mem(base, index, shift, offset, size); } //! Creates `[rip + offset]` memory operand. -static constexpr Mem ptr(const Rip& rip_, int32_t offset = 0, uint32_t size = 0) noexcept { +static inline constexpr Mem ptr(const Rip& rip_, int32_t offset = 0, uint32_t size = 0) noexcept { return Mem(rip_, offset, size); } //! Creates `[base]` absolute memory operand. -static constexpr Mem ptr(uint64_t base, uint32_t size = 0) noexcept { +static inline constexpr Mem ptr(uint64_t base, uint32_t size = 0) noexcept { return Mem(base, size); } //! Creates `[base + (index.reg << shift)]` absolute memory operand. -static constexpr Mem ptr(uint64_t base, const Reg& index, uint32_t shift = 0, uint32_t size = 0) noexcept { +static inline constexpr Mem ptr(uint64_t base, const Reg& index, uint32_t shift = 0, uint32_t size = 0) noexcept { return Mem(base, index, shift, size); } //! Creates `[base + (index.reg << shift)]` absolute memory operand. -static constexpr Mem ptr(uint64_t base, const Vec& index, uint32_t shift = 0, uint32_t size = 0) noexcept { +static inline constexpr Mem ptr(uint64_t base, const Vec& index, uint32_t shift = 0, uint32_t size = 0) noexcept { return Mem(base, index, shift, size); } //! Creates `[base]` absolute memory operand (absolute). -static constexpr Mem ptr_abs(uint64_t base, uint32_t size = 0) noexcept { - return Mem(base, size, Mem::kSignatureMemAbs); +static inline constexpr Mem ptr_abs(uint64_t base, uint32_t size = 0) noexcept { + return Mem(base, size, OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kAbs)); } //! Creates `[base + (index.reg << shift)]` absolute memory operand (absolute). -static constexpr Mem ptr_abs(uint64_t base, const Reg& index, uint32_t shift = 0, uint32_t size = 0) noexcept { - return Mem(base, index, shift, size, Mem::kSignatureMemAbs); +static inline constexpr Mem ptr_abs(uint64_t base, const Reg& index, uint32_t shift = 0, uint32_t size = 0) noexcept { + return Mem(base, index, shift, size, OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kAbs)); } //! Creates `[base + (index.reg << shift)]` absolute memory operand (absolute). -static constexpr Mem ptr_abs(uint64_t base, const Vec& index, uint32_t shift = 0, uint32_t size = 0) noexcept { - return Mem(base, index, shift, size, Mem::kSignatureMemAbs); +static inline constexpr Mem ptr_abs(uint64_t base, const Vec& index, uint32_t shift = 0, uint32_t size = 0) noexcept { + return Mem(base, index, shift, size, OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kAbs)); } //! Creates `[base]` relative memory operand (relative). -static constexpr Mem ptr_rel(uint64_t base, uint32_t size = 0) noexcept { - return Mem(base, size, Mem::kSignatureMemRel); +static inline constexpr Mem ptr_rel(uint64_t base, uint32_t size = 0) noexcept { + return Mem(base, size, OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kRel)); } //! Creates `[base + (index.reg << shift)]` relative memory operand (relative). -static constexpr Mem ptr_rel(uint64_t base, const Reg& index, uint32_t shift = 0, uint32_t size = 0) noexcept { - return Mem(base, index, shift, size, Mem::kSignatureMemRel); +static inline constexpr Mem ptr_rel(uint64_t base, const Reg& index, uint32_t shift = 0, uint32_t size = 0) noexcept { + return Mem(base, index, shift, size, OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kRel)); } //! Creates `[base + (index.reg << shift)]` relative memory operand (relative). -static constexpr Mem ptr_rel(uint64_t base, const Vec& index, uint32_t shift = 0, uint32_t size = 0) noexcept { - return Mem(base, index, shift, size, Mem::kSignatureMemRel); +static inline constexpr Mem ptr_rel(uint64_t base, const Vec& index, uint32_t shift = 0, uint32_t size = 0) noexcept { + return Mem(base, index, shift, size, OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kRel)); } +#define ASMJIT_MEM_PTR(FUNC, SIZE) \ + static constexpr Mem FUNC(const Gp& base, int32_t offset = 0) noexcept { \ + return Mem(base, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ + return Mem(base, index, shift, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Gp& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ + return Mem(base, index, shift, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Label& base, int32_t offset = 0) noexcept { \ + return Mem(base, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Label& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ + return Mem(base, index, shift, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Rip& rip_, int32_t offset = 0) noexcept { \ + return Mem(rip_, offset, SIZE); \ + } \ + static constexpr Mem FUNC(uint64_t base) noexcept { \ + return Mem(base, SIZE); \ + } \ + static constexpr Mem FUNC(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE); \ + } \ + static constexpr Mem FUNC(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE); \ + } \ + \ + static constexpr Mem FUNC##_abs(uint64_t base) noexcept { \ + return Mem(base, SIZE, \ + OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kAbs)); \ + } \ + static constexpr Mem FUNC##_abs(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, \ + OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kAbs)); \ + } \ + static constexpr Mem FUNC##_abs(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, \ + OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kAbs)); \ + } \ + \ + static constexpr Mem FUNC##_rel(uint64_t base) noexcept { \ + return Mem(base, SIZE, \ + OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kRel)); \ + } \ + static constexpr Mem FUNC##_rel(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, \ + OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kRel)); \ + } \ + static constexpr Mem FUNC##_rel(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, \ + OperandSignature::fromValue<Mem::kSignatureMemAddrTypeMask>(Mem::AddrType::kRel)); \ + } + // Definition of memory operand constructors that use platform independent naming. ASMJIT_MEM_PTR(ptr_8, 1) ASMJIT_MEM_PTR(ptr_16, 2) @@ -1110,27 +1063,23 @@ ASMJIT_MEM_PTR(xmmword_ptr, 16) ASMJIT_MEM_PTR(ymmword_ptr, 32) ASMJIT_MEM_PTR(zmmword_ptr, 64) +#undef ASMJIT_MEM_PTR + //! \} ASMJIT_END_SUB_NAMESPACE -// ============================================================================ -// [asmjit::Type::IdOfT<x86::Reg>] -// ============================================================================ - //! \cond INTERNAL ASMJIT_BEGIN_NAMESPACE -ASMJIT_DEFINE_TYPE_ID(x86::Gpb, kIdI8); -ASMJIT_DEFINE_TYPE_ID(x86::Gpw, kIdI16); -ASMJIT_DEFINE_TYPE_ID(x86::Gpd, kIdI32); -ASMJIT_DEFINE_TYPE_ID(x86::Gpq, kIdI64); -ASMJIT_DEFINE_TYPE_ID(x86::Mm , kIdMmx64); -ASMJIT_DEFINE_TYPE_ID(x86::Xmm, kIdI32x4); -ASMJIT_DEFINE_TYPE_ID(x86::Ymm, kIdI32x8); -ASMJIT_DEFINE_TYPE_ID(x86::Zmm, kIdI32x16); +ASMJIT_DEFINE_TYPE_ID(x86::Gpb, TypeId::kInt8); +ASMJIT_DEFINE_TYPE_ID(x86::Gpw, TypeId::kInt16); +ASMJIT_DEFINE_TYPE_ID(x86::Gpd, TypeId::kInt32); +ASMJIT_DEFINE_TYPE_ID(x86::Gpq, TypeId::kInt64); +ASMJIT_DEFINE_TYPE_ID(x86::Mm , TypeId::kMmx64); +ASMJIT_DEFINE_TYPE_ID(x86::Xmm, TypeId::kInt32x4); +ASMJIT_DEFINE_TYPE_ID(x86::Ymm, TypeId::kInt32x8); +ASMJIT_DEFINE_TYPE_ID(x86::Zmm, TypeId::kInt32x16); ASMJIT_END_NAMESPACE //! \endcond -#undef ASMJIT_MEM_PTR - #endif // ASMJIT_X86_X86OPERAND_H_INCLUDED |