diff options
Diffstat (limited to '3rdparty/asmjit/src/asmjit/x86/x86instdb.h')
-rw-r--r-- | 3rdparty/asmjit/src/asmjit/x86/x86instdb.h | 734 |
1 files changed, 416 insertions, 318 deletions
diff --git a/3rdparty/asmjit/src/asmjit/x86/x86instdb.h b/3rdparty/asmjit/src/asmjit/x86/x86instdb.h index 6bc2af5000a..2bf7d148957 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86instdb.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86instdb.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_X86INSTDB_H_INCLUDED #define ASMJIT_X86_X86INSTDB_H_INCLUDED @@ -34,428 +16,544 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! Instruction database (X86). namespace InstDB { -// ============================================================================ -// [asmjit::x86::InstDB::Mode] -// ============================================================================ - -//! Describes which mode is supported by an instruction or instruction signature. -enum Mode : uint32_t { - kModeNone = 0x00u, //!< Invalid. - kModeX86 = 0x01u, //!< X86 mode supported. - kModeX64 = 0x02u, //!< X64 mode supported. - kModeAny = 0x03u //!< Both X86 and X64 modes supported. +//! Describes which operation mode is supported by an instruction. +enum class Mode : uint8_t { + //! Invalid mode. + kNone = 0x00u, + //! X86 mode supported. + kX86 = 0x01u, + //! X64 mode supported. + kX64 = 0x02u, + //! Both X86 and X64 modes supported. + kAny = 0x03u }; +ASMJIT_DEFINE_ENUM_FLAGS(Mode) -static constexpr uint32_t modeFromArch(uint32_t arch) noexcept { - return arch == Environment::kArchX86 ? kModeX86 : - arch == Environment::kArchX64 ? kModeX64 : kModeNone; +//! Converts architecture to operation mode, see \ref Mode. +static ASMJIT_INLINE_NODEBUG constexpr Mode modeFromArch(Arch arch) noexcept { + return arch == Arch::kX86 ? Mode::kX86 : + arch == Arch::kX64 ? Mode::kX64 : Mode::kNone; } -// ============================================================================ -// [asmjit::x86::InstDB::OpFlags] -// ============================================================================ - -//! Operand flags (X86). -enum OpFlags : uint32_t { - kOpNone = 0x00000000u, //!< No flags. - - kOpGpbLo = 0x00000001u, //!< Operand can be low 8-bit GPB register. - kOpGpbHi = 0x00000002u, //!< Operand can be high 8-bit GPB register. - kOpGpw = 0x00000004u, //!< Operand can be 16-bit GPW register. - kOpGpd = 0x00000008u, //!< Operand can be 32-bit GPD register. - kOpGpq = 0x00000010u, //!< Operand can be 64-bit GPQ register. - kOpXmm = 0x00000020u, //!< Operand can be 128-bit XMM register. - kOpYmm = 0x00000040u, //!< Operand can be 256-bit YMM register. - kOpZmm = 0x00000080u, //!< Operand can be 512-bit ZMM register. - kOpMm = 0x00000100u, //!< Operand can be 64-bit MM register. - kOpKReg = 0x00000200u, //!< Operand can be 64-bit K register. - kOpSReg = 0x00000400u, //!< Operand can be SReg (segment register). - kOpCReg = 0x00000800u, //!< Operand can be CReg (control register). - kOpDReg = 0x00001000u, //!< Operand can be DReg (debug register). - kOpSt = 0x00002000u, //!< Operand can be 80-bit ST register (X87). - kOpBnd = 0x00004000u, //!< Operand can be 128-bit BND register. - kOpAllRegs = 0x00007FFFu, //!< Combination of all possible registers. - - kOpI4 = 0x00010000u, //!< Operand can be unsigned 4-bit immediate. - kOpU4 = 0x00020000u, //!< Operand can be unsigned 4-bit immediate. - kOpI8 = 0x00040000u, //!< Operand can be signed 8-bit immediate. - kOpU8 = 0x00080000u, //!< Operand can be unsigned 8-bit immediate. - kOpI16 = 0x00100000u, //!< Operand can be signed 16-bit immediate. - kOpU16 = 0x00200000u, //!< Operand can be unsigned 16-bit immediate. - kOpI32 = 0x00400000u, //!< Operand can be signed 32-bit immediate. - kOpU32 = 0x00800000u, //!< Operand can be unsigned 32-bit immediate. - kOpI64 = 0x01000000u, //!< Operand can be signed 64-bit immediate. - kOpU64 = 0x02000000u, //!< Operand can be unsigned 64-bit immediate. - kOpAllImm = 0x03FF0000u, //!< Operand can be any immediate. - - kOpMem = 0x04000000u, //!< Operand can be a scalar memory pointer. - kOpVm = 0x08000000u, //!< Operand can be a vector memory pointer. - - kOpRel8 = 0x10000000u, //!< Operand can be relative 8-bit displacement. - kOpRel32 = 0x20000000u, //!< Operand can be relative 32-bit displacement. - - kOpImplicit = 0x80000000u //!< Operand is implicit. -}; - -// ============================================================================ -// [asmjit::x86::InstDB::MemFlags] -// ============================================================================ - -//! Memory operand flags (X86). -enum MemFlags : uint32_t { - // NOTE: Instruction uses either scalar or vector memory operands, they never - // collide. This allows us to share bits between "M" and "Vm" enums. - - kMemOpAny = 0x0001u, //!< Operand can be any scalar memory pointer. - kMemOpM8 = 0x0002u, //!< Operand can be an 8-bit memory pointer. - kMemOpM16 = 0x0004u, //!< Operand can be a 16-bit memory pointer. - kMemOpM32 = 0x0008u, //!< Operand can be a 32-bit memory pointer. - kMemOpM48 = 0x0010u, //!< Operand can be a 48-bit memory pointer (FAR pointers only). - kMemOpM64 = 0x0020u, //!< Operand can be a 64-bit memory pointer. - kMemOpM80 = 0x0040u, //!< Operand can be an 80-bit memory pointer. - kMemOpM128 = 0x0080u, //!< Operand can be a 128-bit memory pointer. - kMemOpM256 = 0x0100u, //!< Operand can be a 256-bit memory pointer. - kMemOpM512 = 0x0200u, //!< Operand can be a 512-bit memory pointer. - kMemOpM1024 = 0x0400u, //!< Operand can be a 1024-bit memory pointer. - - kMemOpVm32x = 0x0002u, //!< Operand can be a vm32x (vector) pointer. - kMemOpVm32y = 0x0004u, //!< Operand can be a vm32y (vector) pointer. - kMemOpVm32z = 0x0008u, //!< Operand can be a vm32z (vector) pointer. - kMemOpVm64x = 0x0020u, //!< Operand can be a vm64x (vector) pointer. - kMemOpVm64y = 0x0040u, //!< Operand can be a vm64y (vector) pointer. - kMemOpVm64z = 0x0080u, //!< Operand can be a vm64z (vector) pointer. - - kMemOpBaseOnly = 0x0800u, //!< Only memory base is allowed (no index, no offset). - kMemOpDs = 0x1000u, //!< Implicit memory operand's DS segment. - kMemOpEs = 0x2000u, //!< Implicit memory operand's ES segment. - - kMemOpMib = 0x4000u //!< Operand must be MIB (base+index) pointer. +//! Operand signature flags used by \ref OpSignature. +enum class OpFlags : uint64_t { + //! No operand flags. + kNone = 0u, + + kRegGpbLo = 0x0000000000000001u, //!< Operand can be low 8-bit GPB register. + kRegGpbHi = 0x0000000000000002u, //!< Operand can be high 8-bit GPB register. + kRegGpw = 0x0000000000000004u, //!< Operand can be 16-bit GPW register. + kRegGpd = 0x0000000000000008u, //!< Operand can be 32-bit GPD register. + kRegGpq = 0x0000000000000010u, //!< Operand can be 64-bit GPQ register. + kRegXmm = 0x0000000000000020u, //!< Operand can be 128-bit XMM register. + kRegYmm = 0x0000000000000040u, //!< Operand can be 256-bit YMM register. + kRegZmm = 0x0000000000000080u, //!< Operand can be 512-bit ZMM register. + kRegMm = 0x0000000000000100u, //!< Operand can be 64-bit MM register. + kRegKReg = 0x0000000000000200u, //!< Operand can be 64-bit K register. + kRegSReg = 0x0000000000000400u, //!< Operand can be SReg (segment register). + kRegCReg = 0x0000000000000800u, //!< Operand can be CReg (control register). + kRegDReg = 0x0000000000001000u, //!< Operand can be DReg (debug register). + kRegSt = 0x0000000000002000u, //!< Operand can be 80-bit ST register (X87). + kRegBnd = 0x0000000000004000u, //!< Operand can be 128-bit BND register. + kRegTmm = 0x0000000000008000u, //!< Operand can be 0..8192-bit TMM register. + kRegMask = 0x000000000000FFFFu, //!< Mask of all possible register types. + + kMemUnspecified = 0x0000000000040000u, //!< Operand can be a scalar memory pointer without size. + kMem8 = 0x0000000000080000u, //!< Operand can be an 8-bit memory pointer. + kMem16 = 0x0000000000100000u, //!< Operand can be a 16-bit memory pointer. + kMem32 = 0x0000000000200000u, //!< Operand can be a 32-bit memory pointer. + kMem48 = 0x0000000000400000u, //!< Operand can be a 48-bit memory pointer (FAR pointers only). + kMem64 = 0x0000000000800000u, //!< Operand can be a 64-bit memory pointer. + kMem80 = 0x0000000001000000u, //!< Operand can be an 80-bit memory pointer. + kMem128 = 0x0000000002000000u, //!< Operand can be a 128-bit memory pointer. + kMem256 = 0x0000000004000000u, //!< Operand can be a 256-bit memory pointer. + kMem512 = 0x0000000008000000u, //!< Operand can be a 512-bit memory pointer. + kMem1024 = 0x0000000010000000u, //!< Operand can be a 1024-bit memory pointer. + kMemMask = 0x000000001FFC0000u, //!< Mask of all possible scalar memory types. + + kVm32x = 0x0000000040000000u, //!< Operand can be a vm32x (vector) pointer. + kVm32y = 0x0000000080000000u, //!< Operand can be a vm32y (vector) pointer. + kVm32z = 0x0000000100000000u, //!< Operand can be a vm32z (vector) pointer. + kVm64x = 0x0000000200000000u, //!< Operand can be a vm64x (vector) pointer. + kVm64y = 0x0000000400000000u, //!< Operand can be a vm64y (vector) pointer. + kVm64z = 0x0000000800000000u, //!< Operand can be a vm64z (vector) pointer. + kVmMask = 0x0000000FC0000000u, //!< Mask of all possible vector memory types. + + kImmI4 = 0x0000001000000000u, //!< Operand can be signed 4-bit immediate. + kImmU4 = 0x0000002000000000u, //!< Operand can be unsigned 4-bit immediate. + kImmI8 = 0x0000004000000000u, //!< Operand can be signed 8-bit immediate. + kImmU8 = 0x0000008000000000u, //!< Operand can be unsigned 8-bit immediate. + kImmI16 = 0x0000010000000000u, //!< Operand can be signed 16-bit immediate. + kImmU16 = 0x0000020000000000u, //!< Operand can be unsigned 16-bit immediate. + kImmI32 = 0x0000040000000000u, //!< Operand can be signed 32-bit immediate. + kImmU32 = 0x0000080000000000u, //!< Operand can be unsigned 32-bit immediate. + kImmI64 = 0x0000100000000000u, //!< Operand can be signed 64-bit immediate. + kImmU64 = 0x0000200000000000u, //!< Operand can be unsigned 64-bit immediate. + kImmMask = 0x00003FF000000000u, //!< Mask of all immediate types. + + kRel8 = 0x0000400000000000u, //!< Operand can be relative 8-bit displacement. + kRel32 = 0x0000800000000000u, //!< Operand can be relative 32-bit displacement. + kRelMask = 0x0000C00000000000u, //!< Mask of all relative displacement types. + + kFlagMemBase = 0x0001000000000000u, //!< Flag: Only memory base is allowed (no index, no offset). + kFlagMemDs = 0x0002000000000000u, //!< Flag: Implicit memory operand's DS segment. + kFlagMemEs = 0x0004000000000000u, //!< Flag: Implicit memory operand's ES segment. + + kFlagMib = 0x0008000000000000u, //!< Flag: Operand is MIB (base+index) pointer. + kFlagTMem = 0x0010000000000000u, //!< Flag: Operand is TMEM (sib_mem), AMX memory pointer. + + kFlagImplicit = 0x0080000000000000u, //!< Flag: Operand is implicit. + kFlagMask = 0x009F000000000000u, //!< Mask of all flags. + + //! Contains mask of all registers, memory operands, immediate operands, and displacement operands. + kOpMask = kRegMask | kMemMask | kVmMask | kImmMask | kRelMask }; +ASMJIT_DEFINE_ENUM_FLAGS(OpFlags) -// ============================================================================ -// [asmjit::x86::InstDB::Flags] -// ============================================================================ - -//! Instruction flags (X86). +//! Operand signature. //! -//! Details about instruction encoding, operation, features, and some limitations. -enum Flags : uint32_t { - kFlagNone = 0x00000000u, //!< No flags. - - // Instruction Family - // ------------------ - // - // Instruction family information. +//! Contains all possible operand combinations, memory size information, and a fixed register id (or `BaseReg::kIdBad` +//! if fixed id isn't required). +struct OpSignature { + //! \name Members + //! \{ - kFlagFpu = 0x00000100u, //!< Instruction that accesses FPU registers. - kFlagMmx = 0x00000200u, //!< Instruction that accesses MMX registers (including 3DNOW and GEODE) and EMMS. - kFlagVec = 0x00000400u, //!< Instruction that accesses XMM registers (SSE, AVX, AVX512). + uint64_t _flags : 56; + uint64_t _regMask : 8; - // Prefixes and Encoding Flags - // --------------------------- - // - // These describe optional X86 prefixes that can be used to change the instruction's operation. + //! \} - kFlagRep = 0x00001000u, //!< Instruction can be prefixed with using the REP(REPE) or REPNE prefix. - kFlagRepIgnored = 0x00002000u, //!< Instruction ignores REP|REPNE prefixes, but they are accepted. - kFlagLock = 0x00004000u, //!< Instruction can be prefixed with using the LOCK prefix. - kFlagXAcquire = 0x00008000u, //!< Instruction can be prefixed with using the XACQUIRE prefix. - kFlagXRelease = 0x00010000u, //!< Instruction can be prefixed with using the XRELEASE prefix. - kFlagMib = 0x00020000u, //!< Instruction uses MIB (BNDLDX|BNDSTX) to encode two registers. - kFlagVsib = 0x00040000u, //!< Instruction uses VSIB instead of legacy SIB. - kFlagVex = 0x00080000u, //!< Instruction can be encoded by VEX|XOP (AVX|AVX2|BMI|XOP|...). - kFlagEvex = 0x00100000u, //!< Instruction can be encoded by EVEX (AVX512). + //! \name Accessors + //! \{ - // FPU Flags - // --------- - // - // Used to tell the encoder which memory operand sizes are encodable. + //! Returns operand signature flags. + inline OpFlags flags() const noexcept { return (OpFlags)_flags; } - kFlagFpuM16 = 0x00200000u, //!< FPU instruction can address `word_ptr` (shared with M80). - kFlagFpuM32 = 0x00400000u, //!< FPU instruction can address `dword_ptr`. - kFlagFpuM64 = 0x00800000u, //!< FPU instruction can address `qword_ptr`. - kFlagFpuM80 = 0x00200000u, //!< FPU instruction can address `tword_ptr` (shared with M16). + //! Tests whether the given `flag` is set. + inline bool hasFlag(OpFlags flag) const noexcept { return (_flags & uint64_t(flag)) != 0; } - // AVX and AVX515 Flags - // -------------------- - // - // If both `kFlagPrefixVex` and `kFlagPrefixEvex` flags are specified it - // means that the instructions can be encoded by either VEX or EVEX prefix. - // In that case AsmJit checks global options and also instruction options - // to decide whether to emit VEX or EVEX prefix. - - kFlagAvx512_ = 0x00000000u, //!< Internally used in tables, has no meaning. - kFlagAvx512K = 0x01000000u, //!< Supports masking {k1..k7}. - kFlagAvx512Z = 0x02000000u, //!< Supports zeroing {z}, must be used together with `kAvx512k`. - kFlagAvx512ER = 0x04000000u, //!< Supports 'embedded-rounding' {er} with implicit {sae}, - kFlagAvx512SAE = 0x08000000u, //!< Supports 'suppress-all-exceptions' {sae}. - kFlagAvx512B32 = 0x10000000u, //!< Supports 32-bit broadcast 'b32'. - kFlagAvx512B64 = 0x20000000u, //!< Supports 64-bit broadcast 'b64'. - kFlagAvx512T4X = 0x80000000u, //!< Operates on a vector of consecutive registers (AVX512_4FMAPS and AVX512_4VNNIW). - - // Combinations used by instruction tables to make AVX512 definitions more compact. - kFlagAvx512KZ = kFlagAvx512K | kFlagAvx512Z, - kFlagAvx512ER_SAE = kFlagAvx512ER | kFlagAvx512SAE, - kFlagAvx512KZ_SAE = kFlagAvx512KZ | kFlagAvx512SAE, - kFlagAvx512KZ_SAE_B32 = kFlagAvx512KZ_SAE | kFlagAvx512B32, - kFlagAvx512KZ_SAE_B64 = kFlagAvx512KZ_SAE | kFlagAvx512B64, - - kFlagAvx512KZ_ER_SAE = kFlagAvx512KZ | kFlagAvx512ER_SAE, - kFlagAvx512KZ_ER_SAE_B32 = kFlagAvx512KZ_ER_SAE | kFlagAvx512B32, - kFlagAvx512KZ_ER_SAE_B64 = kFlagAvx512KZ_ER_SAE | kFlagAvx512B64, - - kFlagAvx512K_B32 = kFlagAvx512K | kFlagAvx512B32, - kFlagAvx512K_B64 = kFlagAvx512K | kFlagAvx512B64, - kFlagAvx512KZ_B32 = kFlagAvx512KZ | kFlagAvx512B32, - kFlagAvx512KZ_B64 = kFlagAvx512KZ | kFlagAvx512B64 -}; + //! Tests whether this signature contains at least one register operand of any type. + inline bool hasReg() const noexcept { return hasFlag(OpFlags::kRegMask); } + //! Tests whether this signature contains at least one scalar memory operand of any type. + inline bool hasMem() const noexcept { return hasFlag(OpFlags::kMemMask); } + //! Tests whether this signature contains at least one vector memory operand of any type. + inline bool hasVm() const noexcept { return hasFlag(OpFlags::kVmMask); } + //! Tests whether this signature contains at least one immediate operand of any type. + inline bool hasImm() const noexcept { return hasFlag(OpFlags::kImmMask); } + //! Tests whether this signature contains at least one relative displacement operand of any type. + inline bool hasRel() const noexcept { return hasFlag(OpFlags::kRelMask); } -// ============================================================================ -// [asmjit::x86::InstDB::SingleRegCase] -// ============================================================================ - -enum SingleRegCase : uint32_t { - //! No special handling. - kSingleRegNone = 0, - //! Operands become read-only - `REG & REG` and similar. - kSingleRegRO = 1, - //! Operands become write-only - `REG ^ REG` and similar. - kSingleRegWO = 2 -}; + //! Tests whether the operand is implicit. + inline bool isImplicit() const noexcept { return hasFlag(OpFlags::kFlagImplicit); } -// ============================================================================ -// [asmjit::x86::InstDB::InstSignature / OpSignature] -// ============================================================================ + //! Returns a physical register mask. + inline RegMask regMask() const noexcept { return _regMask; } -//! Operand signature (X86). -//! -//! Contains all possible operand combinations, memory size information, and -//! a fixed register id (or `BaseReg::kIdBad` if fixed id isn't required). -struct OpSignature { - //! Operand flags. - uint32_t opFlags; - //! Memory flags. - uint16_t memFlags; - //! Extra flags. - uint8_t extFlags; - //! Mask of possible register IDs. - uint8_t regMask; + //! \} }; ASMJIT_VARAPI const OpSignature _opSignatureTable[]; -//! Instruction signature (X86). +//! Instruction signature. //! -//! Contains a sequence of operands' combinations and other metadata that defines -//! a single instruction. This data is used by instruction validator. +//! Contains a sequence of operands' combinations and other metadata that defines a single instruction. This data is +//! used by instruction validator. struct InstSignature { + //! \name Members + //! \{ + //! Count of operands in `opIndex` (0..6). - uint8_t opCount : 3; + uint8_t _opCount : 3; //! Architecture modes supported (X86 / X64). - uint8_t modes : 2; + uint8_t _mode : 2; //! Number of implicit operands. - uint8_t implicit : 3; + uint8_t _implicitOpCount : 3; //! Reserved for future use. - uint8_t reserved; + uint8_t _reserved; //! Indexes to `OpSignature` table. - uint8_t operands[Globals::kMaxOpCount]; + uint8_t _opSignatureIndexes[Globals::kMaxOpCount]; + + //! \} + + //! \name Accessors + //! \{ + + //! Returns instruction operation mode. + inline Mode mode() const noexcept { return (Mode)_mode; } + //! Tests whether the instruction supports the given operating mode. + inline bool supportsMode(Mode mode) const noexcept { return (uint8_t(_mode) & uint8_t(mode)) != 0; } + + //! Returns the number of operands of this signature. + inline uint32_t opCount() const noexcept { return _opCount; } + //! Returns the number of implicit operands this signature has. + inline uint32_t implicitOpCount() const noexcept { return _implicitOpCount; } + //! Tests whether this instruction signature has at least one implicit operand. + inline bool hasImplicitOperands() const noexcept { return _implicitOpCount != 0; } + + //! Returns indexes to \ref _opSignatureTable for each operand of the instruction. + //! + //! \note The returned array always provides indexes for all operands (see \ref Globals::kMaxOpCount) even if the + //! instruction provides less operands. Undefined operands have always index of zero. + inline const uint8_t* opSignatureIndexes() const noexcept { return _opSignatureIndexes; } + + //! Returns index to \ref _opSignatureTable, corresponding to the requested operand `index` of the instruction. + inline uint8_t opSignatureIndex(size_t index) const noexcept { + ASMJIT_ASSERT(index < Globals::kMaxOpCount); + return _opSignatureIndexes[index]; + } + + //! Returns \ref OpSignature corresponding to the requested operand `index` of the instruction. + inline const OpSignature& opSignature(size_t index) const noexcept { + ASMJIT_ASSERT(index < Globals::kMaxOpCount); + return _opSignatureTable[_opSignatureIndexes[index]]; + } + + //! \} }; ASMJIT_VARAPI const InstSignature _instSignatureTable[]; -// ============================================================================ -// [asmjit::x86::InstDB::CommonInfo] -// ============================================================================ +//! Instruction flags. +//! +//! Details about instruction encoding, operation, features, and some limitations. +enum class InstFlags : uint32_t { + //! No flags. + kNone = 0x00000000u, + + // Instruction Family + // ------------------ + // + // Instruction family information. + + //! Instruction that accesses FPU registers. + kFpu = 0x00000100u, + //! Instruction that accesses MMX registers (including 3DNOW and GEODE) and EMMS. + kMmx = 0x00000200u, + //! Instruction that accesses XMM registers (SSE, AVX, AVX512). + kVec = 0x00000400u, + + // FPU Flags + // --------- + // + // Used to tell the encoder which memory operand sizes are encodable. + + //! FPU instruction can address `word_ptr` (shared with M80). + kFpuM16 = 0x00000800u, + //! FPU instruction can address `dword_ptr`. + kFpuM32 = 0x00001000u, + //! FPU instruction can address `qword_ptr`. + kFpuM64 = 0x00002000u, + //! FPU instruction can address `tword_ptr` (shared with M16). + kFpuM80 = 0x00000800u, + + // Prefixes and Encoding Flags + // --------------------------- + // + // These describe optional X86 prefixes that can be used to change the instruction's operation. -//! Instruction common information (X86) + //! Instruction can be prefixed with using the REP(REPE) or REPNE prefix. + kRep = 0x00004000u, + //! Rep prefix is accepted, but it has no effect other than being emitted with the instruction (as an extra byte). + kRepIgnored = 0x00008000u, + //! Instruction can be prefixed with using the LOCK prefix. + kLock = 0x00010000u, + //! Instruction can be prefixed with using the XACQUIRE prefix. + kXAcquire = 0x00020000u, + //! Instruction can be prefixed with using the XRELEASE prefix. + kXRelease = 0x00040000u, + //! Instruction uses MIB (BNDLDX|BNDSTX) to encode two registers. + kMib = 0x00080000u, + //! Instruction uses VSIB instead of legacy SIB. + kVsib = 0x00100000u, + //! Instruction uses TSIB (or SIB_MEM) encoding (MODRM followed by SIB). + kTsib = 0x00200000u, + + // If both `kPrefixVex` and `kPrefixEvex` flags are specified it means that the instructions can be encoded + // by either VEX or EVEX prefix. In that case AsmJit checks global options and also instruction options to decide + // whether to emit VEX or EVEX prefix. + + //! Instruction can be encoded by VEX|XOP (AVX|AVX2|BMI|XOP|...). + kVex = 0x00400000u, + //! Instruction can be encoded by EVEX (AVX512). + kEvex = 0x00800000u, + //! EVEX encoding is preferred over VEX encoding (AVX515_VNNI vs AVX_VNNI). + kPreferEvex = 0x01000000u, + //! EVEX and VEX signatures are compatible. + kEvexCompat = 0x02000000u, + //! EVEX instruction requires K register in the first operand (compare instructions). + kEvexKReg = 0x04000000u, + //! EVEX instruction requires two operands and K register as a selector (gather instructions). + kEvexTwoOp = 0x08000000u, + //! VEX instruction that can be transformed to a compatible EVEX instruction. + kEvexTransformable = 0x10000000u, + + // Other Flags + // ----------- + + //! Instruction uses consecutive registers. + //! + //! Used by V4FMADDPS, V4FMADDSS, V4FNMADDPS, V4FNMADDSS, VP4DPWSSD, VP4DPWSSDS, VP2INTERSECTD, and VP2INTERSECTQ + //! instructions + kConsecutiveRegs = 0x20000000u +}; +ASMJIT_DEFINE_ENUM_FLAGS(InstFlags) + +//! AVX-512 flags. +enum class Avx512Flags : uint32_t { + //! No AVX-512 flags. + kNone = 0, + + //! Internally used in tables, has no meaning. + k_ = 0x00000000u, + //! Supports masking {k1..k7}. + kK = 0x00000001u, + //! Supports zeroing {z}, must be used together with `kAvx512k`. + kZ = 0x00000002u, + //! Supports 'embedded-rounding' {er} with implicit {sae}, + kER = 0x00000004u, + //! Supports 'suppress-all-exceptions' {sae}. + kSAE = 0x00000008u, + //! Supports 16-bit broadcast 'b16'. + kB16 = 0x00000010u, + //! Supports 32-bit broadcast 'b32'. + kB32 = 0x00000020u, + //! Supports 64-bit broadcast 'b64'. + kB64 = 0x00000040u, + //! Operates on a vector of consecutive registers (AVX512_4FMAPS and AVX512_4VNNIW). + kT4X = 0x00000080u, + + //! Implicit zeroing if {k} masking is used. Using {z} is not valid in this case as it's implicit. + kImplicitZ = 0x00000100, +}; +ASMJIT_DEFINE_ENUM_FLAGS(Avx512Flags) + +//! Instruction common information. //! //! Aggregated information shared across one or more instruction. struct CommonInfo { //! Instruction flags. uint32_t _flags; + //! Reserved for future use. + uint32_t _avx512Flags : 11; //! First `InstSignature` entry in the database. uint32_t _iSignatureIndex : 11; //! Number of relevant `ISignature` entries. uint32_t _iSignatureCount : 5; - //! Control type, see `ControlType`. - uint32_t _controlType : 3; + //! Instruction control flow category, see \ref InstControlFlow. + uint32_t _controlFlow : 3; //! Specifies what happens if all source operands share the same register. - uint32_t _singleRegCase : 2; - //! Reserved for future use. - uint32_t _reserved : 11; + uint32_t _sameRegHint : 2; + + //! \name Accessors + //! \{ - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- + //! Returns instruction flags. + ASMJIT_INLINE_NODEBUG InstFlags flags() const noexcept { return (InstFlags)_flags; } + //! Tests whether the instruction has a `flag`. + ASMJIT_INLINE_NODEBUG bool hasFlag(InstFlags flag) const noexcept { return Support::test(_flags, flag); } - //! Returns instruction flags, see `InstInfo::Flags`. - inline uint32_t flags() const noexcept { return _flags; } - //! Tests whether the instruction has a `flag`, see `InstInfo::Flags`. - inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + //! Returns instruction AVX-512 flags. + ASMJIT_INLINE_NODEBUG Avx512Flags avx512Flags() const noexcept { return (Avx512Flags)_avx512Flags; } + //! Tests whether the instruction has an AVX-512 `flag`. + ASMJIT_INLINE_NODEBUG bool hasAvx512Flag(Avx512Flags flag) const noexcept { return Support::test(_avx512Flags, flag); } //! Tests whether the instruction is FPU instruction. - inline bool isFpu() const noexcept { return hasFlag(kFlagFpu); } + ASMJIT_INLINE_NODEBUG bool isFpu() const noexcept { return hasFlag(InstFlags::kFpu); } //! Tests whether the instruction is MMX/3DNOW instruction that accesses MMX registers (includes EMMS and FEMMS). - inline bool isMmx() const noexcept { return hasFlag(kFlagMmx); } + ASMJIT_INLINE_NODEBUG bool isMmx() const noexcept { return hasFlag(InstFlags::kMmx); } //! Tests whether the instruction is SSE|AVX|AVX512 instruction that accesses XMM|YMM|ZMM registers. - inline bool isVec() const noexcept { return hasFlag(kFlagVec); } + ASMJIT_INLINE_NODEBUG bool isVec() const noexcept { return hasFlag(InstFlags::kVec); } //! Tests whether the instruction is SSE+ (SSE4.2, AES, SHA included) instruction that accesses XMM registers. - inline bool isSse() const noexcept { return (flags() & (kFlagVec | kFlagVex | kFlagEvex)) == kFlagVec; } + ASMJIT_INLINE_NODEBUG bool isSse() const noexcept { return (flags() & (InstFlags::kVec | InstFlags::kVex | InstFlags::kEvex)) == InstFlags::kVec; } //! Tests whether the instruction is AVX+ (FMA included) instruction that accesses XMM|YMM|ZMM registers. - inline bool isAvx() const noexcept { return isVec() && isVexOrEvex(); } + ASMJIT_INLINE_NODEBUG bool isAvx() const noexcept { return isVec() && isVexOrEvex(); } //! Tests whether the instruction can be prefixed with LOCK prefix. - inline bool hasLockPrefix() const noexcept { return hasFlag(kFlagLock); } + ASMJIT_INLINE_NODEBUG bool hasLockPrefix() const noexcept { return hasFlag(InstFlags::kLock); } //! Tests whether the instruction can be prefixed with REP (REPE|REPZ) prefix. - inline bool hasRepPrefix() const noexcept { return hasFlag(kFlagRep); } + ASMJIT_INLINE_NODEBUG bool hasRepPrefix() const noexcept { return hasFlag(InstFlags::kRep); } //! Tests whether the instruction can be prefixed with XACQUIRE prefix. - inline bool hasXAcquirePrefix() const noexcept { return hasFlag(kFlagXAcquire); } + ASMJIT_INLINE_NODEBUG bool hasXAcquirePrefix() const noexcept { return hasFlag(InstFlags::kXAcquire); } //! Tests whether the instruction can be prefixed with XRELEASE prefix. - inline bool hasXReleasePrefix() const noexcept { return hasFlag(kFlagXRelease); } + ASMJIT_INLINE_NODEBUG bool hasXReleasePrefix() const noexcept { return hasFlag(InstFlags::kXRelease); } //! Tests whether the rep prefix is supported by the instruction, but ignored (has no effect). - inline bool isRepIgnored() const noexcept { return hasFlag(kFlagRepIgnored); } + ASMJIT_INLINE_NODEBUG bool isRepIgnored() const noexcept { return hasFlag(InstFlags::kRepIgnored); } //! Tests whether the instruction uses MIB. - inline bool isMibOp() const noexcept { return hasFlag(kFlagMib); } + ASMJIT_INLINE_NODEBUG bool isMibOp() const noexcept { return hasFlag(InstFlags::kMib); } //! Tests whether the instruction uses VSIB. - inline bool isVsibOp() const noexcept { return hasFlag(kFlagVsib); } + ASMJIT_INLINE_NODEBUG bool isVsibOp() const noexcept { return hasFlag(InstFlags::kVsib); } + //! Tests whether the instruction uses TSIB (AMX, instruction requires MOD+SIB). + ASMJIT_INLINE_NODEBUG bool isTsibOp() const noexcept { return hasFlag(InstFlags::kTsib); } //! Tests whether the instruction uses VEX (can be set together with EVEX if both are encodable). - inline bool isVex() const noexcept { return hasFlag(kFlagVex); } + ASMJIT_INLINE_NODEBUG bool isVex() const noexcept { return hasFlag(InstFlags::kVex); } //! Tests whether the instruction uses EVEX (can be set together with VEX if both are encodable). - inline bool isEvex() const noexcept { return hasFlag(kFlagEvex); } + ASMJIT_INLINE_NODEBUG bool isEvex() const noexcept { return hasFlag(InstFlags::kEvex); } //! Tests whether the instruction uses EVEX (can be set together with VEX if both are encodable). - inline bool isVexOrEvex() const noexcept { return hasFlag(kFlagVex | kFlagEvex); } + ASMJIT_INLINE_NODEBUG bool isVexOrEvex() const noexcept { return hasFlag(InstFlags::kVex | InstFlags::kEvex); } + + //! Tests whether the instruction should prefer EVEX prefix instead of VEX prefix. + ASMJIT_INLINE_NODEBUG bool preferEvex() const noexcept { return hasFlag(InstFlags::kPreferEvex); } + + ASMJIT_INLINE_NODEBUG bool isEvexCompatible() const noexcept { return hasFlag(InstFlags::kEvexCompat); } + ASMJIT_INLINE_NODEBUG bool isEvexKRegOnly() const noexcept { return hasFlag(InstFlags::kEvexKReg); } + ASMJIT_INLINE_NODEBUG bool isEvexTwoOpOnly() const noexcept { return hasFlag(InstFlags::kEvexTwoOp); } + ASMJIT_INLINE_NODEBUG bool isEvexTransformable() const noexcept { return hasFlag(InstFlags::kEvexTransformable); } //! Tests whether the instruction supports AVX512 masking {k}. - inline bool hasAvx512K() const noexcept { return hasFlag(kFlagAvx512K); } + ASMJIT_INLINE_NODEBUG bool hasAvx512K() const noexcept { return hasAvx512Flag(Avx512Flags::kK); } //! Tests whether the instruction supports AVX512 zeroing {k}{z}. - inline bool hasAvx512Z() const noexcept { return hasFlag(kFlagAvx512Z); } + ASMJIT_INLINE_NODEBUG bool hasAvx512Z() const noexcept { return hasAvx512Flag(Avx512Flags::kZ); } //! Tests whether the instruction supports AVX512 embedded-rounding {er}. - inline bool hasAvx512ER() const noexcept { return hasFlag(kFlagAvx512ER); } + ASMJIT_INLINE_NODEBUG bool hasAvx512ER() const noexcept { return hasAvx512Flag(Avx512Flags::kER); } //! Tests whether the instruction supports AVX512 suppress-all-exceptions {sae}. - inline bool hasAvx512SAE() const noexcept { return hasFlag(kFlagAvx512SAE); } + ASMJIT_INLINE_NODEBUG bool hasAvx512SAE() const noexcept { return hasAvx512Flag(Avx512Flags::kSAE); } //! Tests whether the instruction supports AVX512 broadcast (either 32-bit or 64-bit). - inline bool hasAvx512B() const noexcept { return hasFlag(kFlagAvx512B32 | kFlagAvx512B64); } + ASMJIT_INLINE_NODEBUG bool hasAvx512B() const noexcept { return hasAvx512Flag(Avx512Flags::kB16 | Avx512Flags::kB32 | Avx512Flags::kB64); } + //! Tests whether the instruction supports AVX512 broadcast (16-bit). + ASMJIT_INLINE_NODEBUG bool hasAvx512B16() const noexcept { return hasAvx512Flag(Avx512Flags::kB16); } //! Tests whether the instruction supports AVX512 broadcast (32-bit). - inline bool hasAvx512B32() const noexcept { return hasFlag(kFlagAvx512B32); } + ASMJIT_INLINE_NODEBUG bool hasAvx512B32() const noexcept { return hasAvx512Flag(Avx512Flags::kB32); } //! Tests whether the instruction supports AVX512 broadcast (64-bit). - inline bool hasAvx512B64() const noexcept { return hasFlag(kFlagAvx512B64); } + ASMJIT_INLINE_NODEBUG bool hasAvx512B64() const noexcept { return hasAvx512Flag(Avx512Flags::kB64); } - inline uint32_t signatureIndex() const noexcept { return _iSignatureIndex; } - inline uint32_t signatureCount() const noexcept { return _iSignatureCount; } + // Returns the size of the broadcast - either 2, 4, or 8, or 0 if broadcast is not supported. + ASMJIT_INLINE_NODEBUG uint32_t broadcastSize() const noexcept { + constexpr uint32_t kShift = Support::ConstCTZ<uint32_t(Avx512Flags::kB16)>::value; + return (uint32_t(_avx512Flags) & uint32_t(Avx512Flags::kB16 | Avx512Flags::kB32 | Avx512Flags::kB64)) >> (kShift - 1); + } - inline const InstSignature* signatureData() const noexcept { return _instSignatureTable + _iSignatureIndex; } - inline const InstSignature* signatureEnd() const noexcept { return _instSignatureTable + _iSignatureIndex + _iSignatureCount; } + ASMJIT_INLINE_NODEBUG uint32_t signatureIndex() const noexcept { return _iSignatureIndex; } + ASMJIT_INLINE_NODEBUG uint32_t signatureCount() const noexcept { return _iSignatureCount; } - //! Returns the control-flow type of the instruction. - inline uint32_t controlType() const noexcept { return _controlType; } + ASMJIT_INLINE_NODEBUG const InstSignature* signatureData() const noexcept { return _instSignatureTable + _iSignatureIndex; } + ASMJIT_INLINE_NODEBUG const InstSignature* signatureEnd() const noexcept { return _instSignatureTable + _iSignatureIndex + _iSignatureCount; } - inline uint32_t singleRegCase() const noexcept { return _singleRegCase; } + //! Returns a control flow category of the instruction. + ASMJIT_INLINE_NODEBUG InstControlFlow controlFlow() const noexcept { return (InstControlFlow)_controlFlow; } + + //! Returns a hint that can be used when both inputs are the same register. + ASMJIT_INLINE_NODEBUG InstSameRegHint sameRegHint() const noexcept { return (InstSameRegHint)_sameRegHint; } + + //! \} }; ASMJIT_VARAPI const CommonInfo _commonInfoTable[]; -// ============================================================================ -// [asmjit::x86::InstDB::InstInfo] -// ============================================================================ - -//! Instruction information (X86). +//! Instruction information. struct InstInfo { - //! Index to `_nameData`. - uint32_t _nameDataIndex : 14; - //! Index to `_commonInfoTable`. + //! Reserved for future use. + uint32_t _reserved : 14; + //! Index to \ref _commonInfoTable. uint32_t _commonInfoIndex : 10; - //! Index to `InstDB::_commonInfoTableB`. - uint32_t _commonInfoIndexB : 8; + //! Index to \ref _additionalInfoTable. + uint32_t _additionalInfoIndex : 8; - //! Instruction encoding, see `InstDB::EncodingId`. + //! Instruction encoding (internal encoding identifier used by \ref Assembler). uint8_t _encoding; - //! Main opcode value (0.255). + //! Main opcode value (0..255). uint8_t _mainOpcodeValue; - //! Index to `InstDB::_mainOpcodeTable` that is combined with `_mainOpcodeValue` - //! to form the final opcode. + //! Index to \ref _mainOpcodeTable` that is combined with \ref _mainOpcodeValue to form the final opcode. uint8_t _mainOpcodeIndex; - //! Index to `InstDB::_altOpcodeTable` that contains a full alternative opcode. + //! Index to \ref _altOpcodeTable that contains a full alternative opcode. uint8_t _altOpcodeIndex; - // -------------------------------------------------------------------------- - // [Accessors] - // -------------------------------------------------------------------------- + //! \name Accessors + //! \{ - //! Returns common information, see `CommonInfo`. - inline const CommonInfo& commonInfo() const noexcept { return _commonInfoTable[_commonInfoIndex]; } + //! Returns common information, see \ref CommonInfo. + ASMJIT_INLINE_NODEBUG const CommonInfo& commonInfo() const noexcept { return _commonInfoTable[_commonInfoIndex]; } - //! Tests whether the instruction has flag `flag`, see `Flags`. - inline bool hasFlag(uint32_t flag) const noexcept { return commonInfo().hasFlag(flag); } - //! Returns instruction flags, see `Flags`. - inline uint32_t flags() const noexcept { return commonInfo().flags(); } + //! Returns instruction flags, see \ref InstFlags. + ASMJIT_INLINE_NODEBUG InstFlags flags() const noexcept { return commonInfo().flags(); } + //! Tests whether the instruction has flag `flag`, see \ref InstFlags. + ASMJIT_INLINE_NODEBUG bool hasFlag(InstFlags flag) const noexcept { return commonInfo().hasFlag(flag); } + + //! Returns instruction AVX-512 flags, see \ref Avx512Flags. + ASMJIT_INLINE_NODEBUG Avx512Flags avx512Flags() const noexcept { return commonInfo().avx512Flags(); } + //! Tests whether the instruction has an AVX-512 `flag`, see \ref Avx512Flags. + ASMJIT_INLINE_NODEBUG bool hasAvx512Flag(Avx512Flags flag) const noexcept { return commonInfo().hasAvx512Flag(flag); } //! Tests whether the instruction is FPU instruction. - inline bool isFpu() const noexcept { return commonInfo().isFpu(); } + ASMJIT_INLINE_NODEBUG bool isFpu() const noexcept { return commonInfo().isFpu(); } //! Tests whether the instruction is MMX/3DNOW instruction that accesses MMX registers (includes EMMS and FEMMS). - inline bool isMmx() const noexcept { return commonInfo().isMmx(); } + ASMJIT_INLINE_NODEBUG bool isMmx() const noexcept { return commonInfo().isMmx(); } //! Tests whether the instruction is SSE|AVX|AVX512 instruction that accesses XMM|YMM|ZMM registers. - inline bool isVec() const noexcept { return commonInfo().isVec(); } + ASMJIT_INLINE_NODEBUG bool isVec() const noexcept { return commonInfo().isVec(); } //! Tests whether the instruction is SSE+ (SSE4.2, AES, SHA included) instruction that accesses XMM registers. - inline bool isSse() const noexcept { return commonInfo().isSse(); } + ASMJIT_INLINE_NODEBUG bool isSse() const noexcept { return commonInfo().isSse(); } //! Tests whether the instruction is AVX+ (FMA included) instruction that accesses XMM|YMM|ZMM registers. - inline bool isAvx() const noexcept { return commonInfo().isAvx(); } + ASMJIT_INLINE_NODEBUG bool isAvx() const noexcept { return commonInfo().isAvx(); } //! Tests whether the instruction can be prefixed with LOCK prefix. - inline bool hasLockPrefix() const noexcept { return commonInfo().hasLockPrefix(); } + ASMJIT_INLINE_NODEBUG bool hasLockPrefix() const noexcept { return commonInfo().hasLockPrefix(); } //! Tests whether the instruction can be prefixed with REP (REPE|REPZ) prefix. - inline bool hasRepPrefix() const noexcept { return commonInfo().hasRepPrefix(); } + ASMJIT_INLINE_NODEBUG bool hasRepPrefix() const noexcept { return commonInfo().hasRepPrefix(); } //! Tests whether the instruction can be prefixed with XACQUIRE prefix. - inline bool hasXAcquirePrefix() const noexcept { return commonInfo().hasXAcquirePrefix(); } + ASMJIT_INLINE_NODEBUG bool hasXAcquirePrefix() const noexcept { return commonInfo().hasXAcquirePrefix(); } //! Tests whether the instruction can be prefixed with XRELEASE prefix. - inline bool hasXReleasePrefix() const noexcept { return commonInfo().hasXReleasePrefix(); } + ASMJIT_INLINE_NODEBUG bool hasXReleasePrefix() const noexcept { return commonInfo().hasXReleasePrefix(); } //! Tests whether the rep prefix is supported by the instruction, but ignored (has no effect). - inline bool isRepIgnored() const noexcept { return commonInfo().isRepIgnored(); } + ASMJIT_INLINE_NODEBUG bool isRepIgnored() const noexcept { return commonInfo().isRepIgnored(); } //! Tests whether the instruction uses MIB. - inline bool isMibOp() const noexcept { return hasFlag(kFlagMib); } + ASMJIT_INLINE_NODEBUG bool isMibOp() const noexcept { return hasFlag(InstFlags::kMib); } //! Tests whether the instruction uses VSIB. - inline bool isVsibOp() const noexcept { return hasFlag(kFlagVsib); } + ASMJIT_INLINE_NODEBUG bool isVsibOp() const noexcept { return hasFlag(InstFlags::kVsib); } //! Tests whether the instruction uses VEX (can be set together with EVEX if both are encodable). - inline bool isVex() const noexcept { return hasFlag(kFlagVex); } + ASMJIT_INLINE_NODEBUG bool isVex() const noexcept { return hasFlag(InstFlags::kVex); } //! Tests whether the instruction uses EVEX (can be set together with VEX if both are encodable). - inline bool isEvex() const noexcept { return hasFlag(kFlagEvex); } + ASMJIT_INLINE_NODEBUG bool isEvex() const noexcept { return hasFlag(InstFlags::kEvex); } //! Tests whether the instruction uses EVEX (can be set together with VEX if both are encodable). - inline bool isVexOrEvex() const noexcept { return hasFlag(kFlagVex | kFlagEvex); } + ASMJIT_INLINE_NODEBUG bool isVexOrEvex() const noexcept { return hasFlag(InstFlags::kVex | InstFlags::kEvex); } + + ASMJIT_INLINE_NODEBUG bool isEvexCompatible() const noexcept { return hasFlag(InstFlags::kEvexCompat); } + ASMJIT_INLINE_NODEBUG bool isEvexKRegOnly() const noexcept { return hasFlag(InstFlags::kEvexKReg); } + ASMJIT_INLINE_NODEBUG bool isEvexTwoOpOnly() const noexcept { return hasFlag(InstFlags::kEvexTwoOp); } + ASMJIT_INLINE_NODEBUG bool isEvexTransformable() const noexcept { return hasFlag(InstFlags::kEvexTransformable); } //! Tests whether the instruction supports AVX512 masking {k}. - inline bool hasAvx512K() const noexcept { return hasFlag(kFlagAvx512K); } + ASMJIT_INLINE_NODEBUG bool hasAvx512K() const noexcept { return hasAvx512Flag(Avx512Flags::kK); } //! Tests whether the instruction supports AVX512 zeroing {k}{z}. - inline bool hasAvx512Z() const noexcept { return hasFlag(kFlagAvx512Z); } + ASMJIT_INLINE_NODEBUG bool hasAvx512Z() const noexcept { return hasAvx512Flag(Avx512Flags::kZ); } //! Tests whether the instruction supports AVX512 embedded-rounding {er}. - inline bool hasAvx512ER() const noexcept { return hasFlag(kFlagAvx512ER); } + ASMJIT_INLINE_NODEBUG bool hasAvx512ER() const noexcept { return hasAvx512Flag(Avx512Flags::kER); } //! Tests whether the instruction supports AVX512 suppress-all-exceptions {sae}. - inline bool hasAvx512SAE() const noexcept { return hasFlag(kFlagAvx512SAE); } + ASMJIT_INLINE_NODEBUG bool hasAvx512SAE() const noexcept { return hasAvx512Flag(Avx512Flags::kSAE); } //! Tests whether the instruction supports AVX512 broadcast (either 32-bit or 64-bit). - inline bool hasAvx512B() const noexcept { return hasFlag(kFlagAvx512B32 | kFlagAvx512B64); } + ASMJIT_INLINE_NODEBUG bool hasAvx512B() const noexcept { return hasAvx512Flag(Avx512Flags::kB16 | Avx512Flags::kB32 | Avx512Flags::kB64); } + //! Tests whether the instruction supports AVX512 broadcast (16-bit). + ASMJIT_INLINE_NODEBUG bool hasAvx512B16() const noexcept { return hasAvx512Flag(Avx512Flags::kB16); } //! Tests whether the instruction supports AVX512 broadcast (32-bit). - inline bool hasAvx512B32() const noexcept { return hasFlag(kFlagAvx512B32); } + ASMJIT_INLINE_NODEBUG bool hasAvx512B32() const noexcept { return hasAvx512Flag(Avx512Flags::kB32); } //! Tests whether the instruction supports AVX512 broadcast (64-bit). - inline bool hasAvx512B64() const noexcept { return hasFlag(kFlagAvx512B64); } + ASMJIT_INLINE_NODEBUG bool hasAvx512B64() const noexcept { return hasAvx512Flag(Avx512Flags::kB64); } - //! Gets the control-flow type of the instruction. - inline uint32_t controlType() const noexcept { return commonInfo().controlType(); } - inline uint32_t singleRegCase() const noexcept { return commonInfo().singleRegCase(); } + //! Returns a control flow category of the instruction. + ASMJIT_INLINE_NODEBUG InstControlFlow controlFlow() const noexcept { return commonInfo().controlFlow(); } + //! Returns a hint that can be used when both inputs are the same register. + ASMJIT_INLINE_NODEBUG InstSameRegHint sameRegHint() const noexcept { return commonInfo().sameRegHint(); } - inline uint32_t signatureIndex() const noexcept { return commonInfo().signatureIndex(); } - inline uint32_t signatureCount() const noexcept { return commonInfo().signatureCount(); } + ASMJIT_INLINE_NODEBUG uint32_t signatureIndex() const noexcept { return commonInfo().signatureIndex(); } + ASMJIT_INLINE_NODEBUG uint32_t signatureCount() const noexcept { return commonInfo().signatureCount(); } - inline const InstSignature* signatureData() const noexcept { return commonInfo().signatureData(); } - inline const InstSignature* signatureEnd() const noexcept { return commonInfo().signatureEnd(); } + ASMJIT_INLINE_NODEBUG const InstSignature* signatureData() const noexcept { return commonInfo().signatureData(); } + ASMJIT_INLINE_NODEBUG const InstSignature* signatureEnd() const noexcept { return commonInfo().signatureEnd(); } + + //! \} }; ASMJIT_VARAPI const InstInfo _instInfoTable[]; -inline const InstInfo& infoById(uint32_t instId) noexcept { +static inline const InstInfo& infoById(InstId instId) noexcept { ASMJIT_ASSERT(Inst::isDefinedId(instId)); return _instInfoTable[instId]; } +//! \cond INTERNAL +static_assert(sizeof(OpSignature) == 8, "InstDB::OpSignature must be 8 bytes long"); +//! \endcond + } // {InstDB} //! \} |