// AsmJit - Machine code generation for C++
//
//  * Official AsmJit Home Page: https://asmjit.com
//  * Official Github Repository: https://github.com/asmjit/asmjit
//
// Copyright (c) 2008-2020 The AsmJit Authors
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would be
//    appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
//    misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.

#ifndef ASMJIT_X86_X86INSTDB_H_INCLUDED
#define ASMJIT_X86_X86INSTDB_H_INCLUDED

#include "../x86/x86globals.h"

ASMJIT_BEGIN_SUB_NAMESPACE(x86)

//! \addtogroup asmjit_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.
};

static constexpr uint32_t modeFromArch(uint32_t arch) noexcept {
  return arch == Environment::kArchX86 ? kModeX86 :
         arch == Environment::kArchX64 ? kModeX64 : kModeNone;
}

// ============================================================================
// [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.
  kOpTmm                  = 0x00008000u, //!< Operand can be 0..8192-bit TMM register.
  kOpAllRegs              = 0x0000FFFFu, //!< 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.
  kMemOpTMem              = 0x8000u      //!< Operand is a sib_mem (ADX memory operand).
};

// ============================================================================
// [asmjit::x86::InstDB::Flags]
// ============================================================================

//! Instruction flags (X86).
//!
//! Details about instruction encoding, operation, features, and some limitations.
enum Flags : uint32_t {
  kFlagNone               = 0x00000000u, //!< No flags.

  // Instruction Family
  // ------------------
  //
  // Instruction family information.

  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).

  // Prefixes and Encoding Flags
  // ---------------------------
  //
  // These describe optional X86 prefixes that can be used to change the instruction's operation.

  kFlagTsib               = 0x00000800u, //!< Instruction uses TSIB (or SIB_MEM) encoding (MODRM followed by SIB).
  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).
  kFlagPreferEvex         = 0x00200000u, //!< EVEX encoding is preferred over VEX encoding (AVX515_VNNI vs AVX_VNNI).

  // FPU Flags
  // ---------
  //
  // Used to tell the encoder which memory operand sizes are encodable.

  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).

  // 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
};

// ============================================================================
// [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
};

// ============================================================================
// [asmjit::x86::InstDB::InstSignature / OpSignature]
// ============================================================================

//! 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).
//!
//! Contains a sequence of operands' combinations and other metadata that defines
//! a single instruction. This data is used by instruction validator.
struct InstSignature {
  //! Count of operands in `opIndex` (0..6).
  uint8_t opCount : 3;
  //! Architecture modes supported (X86 / X64).
  uint8_t modes : 2;
  //! Number of implicit operands.
  uint8_t implicit : 3;
  //! Reserved for future use.
  uint8_t reserved;
  //! Indexes to `OpSignature` table.
  uint8_t operands[Globals::kMaxOpCount];
};

ASMJIT_VARAPI const InstSignature _instSignatureTable[];

// ============================================================================
// [asmjit::x86::InstDB::CommonInfo]
// ============================================================================

//! Instruction common information (X86)
//!
//! Aggregated information shared across one or more instruction.
struct CommonInfo {
  //! Instruction flags.
  uint32_t _flags;
  //! 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;
  //! Specifies what happens if all source operands share the same register.
  uint32_t _singleRegCase : 2;
  //! Reserved for future use.
  uint32_t _reserved : 11;

  // --------------------------------------------------------------------------
  // [Accessors]
  // --------------------------------------------------------------------------

  //! 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; }

  //! Tests whether the instruction is FPU instruction.
  inline bool isFpu() const noexcept { return hasFlag(kFlagFpu); }
  //! Tests whether the instruction is MMX/3DNOW instruction that accesses MMX registers (includes EMMS and FEMMS).
  inline bool isMmx() const noexcept { return hasFlag(kFlagMmx); }
  //! Tests whether the instruction is SSE|AVX|AVX512 instruction that accesses XMM|YMM|ZMM registers.
  inline bool isVec() const noexcept { return hasFlag(kFlagVec); }
  //! 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; }
  //! Tests whether the instruction is AVX+ (FMA included) instruction that accesses XMM|YMM|ZMM registers.
  inline 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); }
  //! Tests whether the instruction can be prefixed with REP (REPE|REPZ) prefix.
  inline bool hasRepPrefix() const noexcept { return hasFlag(kFlagRep); }
  //! Tests whether the instruction can be prefixed with XACQUIRE prefix.
  inline bool hasXAcquirePrefix() const noexcept { return hasFlag(kFlagXAcquire); }
  //! Tests whether the instruction can be prefixed with XRELEASE prefix.
  inline bool hasXReleasePrefix() const noexcept { return hasFlag(kFlagXRelease); }

  //! Tests whether the rep prefix is supported by the instruction, but ignored (has no effect).
  inline bool isRepIgnored() const noexcept { return hasFlag(kFlagRepIgnored); }
  //! Tests whether the instruction uses MIB.
  inline bool isMibOp() const noexcept { return hasFlag(kFlagMib); }
  //! Tests whether the instruction uses VSIB.
  inline bool isVsibOp() const noexcept { return hasFlag(kFlagVsib); }
  //! Tests whether the instruction uses TSIB (AMX, instruction requires MOD+SIB).
  inline bool isTsibOp() const noexcept { return hasFlag(kFlagTsib); }
  //! Tests whether the instruction uses VEX (can be set together with EVEX if both are encodable).
  inline bool isVex() const noexcept { return hasFlag(kFlagVex); }
  //! Tests whether the instruction uses EVEX (can be set together with VEX if both are encodable).
  inline bool isEvex() const noexcept { return hasFlag(kFlagEvex); }
  //! 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); }

  //! Tests whether the instruction should prefer EVEX prefix instead of VEX prefix.
  inline bool preferEvex() const noexcept { return hasFlag(kFlagPreferEvex); }

  //! Tests whether the instruction supports AVX512 masking {k}.
  inline bool hasAvx512K() const noexcept { return hasFlag(kFlagAvx512K); }
  //! Tests whether the instruction supports AVX512 zeroing {k}{z}.
  inline bool hasAvx512Z() const noexcept { return hasFlag(kFlagAvx512Z); }
  //! Tests whether the instruction supports AVX512 embedded-rounding {er}.
  inline bool hasAvx512ER() const noexcept { return hasFlag(kFlagAvx512ER); }
  //! Tests whether the instruction supports AVX512 suppress-all-exceptions {sae}.
  inline bool hasAvx512SAE() const noexcept { return hasFlag(kFlagAvx512SAE); }
  //! Tests whether the instruction supports AVX512 broadcast (either 32-bit or 64-bit).
  inline bool hasAvx512B() const noexcept { return hasFlag(kFlagAvx512B32 | kFlagAvx512B64); }
  //! Tests whether the instruction supports AVX512 broadcast (32-bit).
  inline bool hasAvx512B32() const noexcept { return hasFlag(kFlagAvx512B32); }
  //! Tests whether the instruction supports AVX512 broadcast (64-bit).
  inline bool hasAvx512B64() const noexcept { return hasFlag(kFlagAvx512B64); }

  inline uint32_t signatureIndex() const noexcept { return _iSignatureIndex; }
  inline uint32_t signatureCount() const noexcept { return _iSignatureCount; }

  inline const InstSignature* signatureData() const noexcept { return _instSignatureTable + _iSignatureIndex; }
  inline const InstSignature* signatureEnd() const noexcept { return _instSignatureTable + _iSignatureIndex + _iSignatureCount; }

  //! Returns the control-flow type of the instruction.
  inline uint32_t controlType() const noexcept { return _controlType; }

  inline uint32_t singleRegCase() const noexcept { return _singleRegCase; }
};

ASMJIT_VARAPI const CommonInfo _commonInfoTable[];

// ============================================================================
// [asmjit::x86::InstDB::InstInfo]
// ============================================================================

//! Instruction information (X86).
struct InstInfo {
  //! Index to \ref _nameData.
  uint32_t _nameDataIndex : 14;
  //! Index to \ref _commonInfoTable.
  uint32_t _commonInfoIndex : 10;
  //! Index to \ref _commonInfoTableB.
  uint32_t _commonInfoIndexB : 8;

  //! Instruction encoding (internal encoding identifier used by \ref Assembler).
  uint8_t _encoding;
  //! Main opcode value (0..255).
  uint8_t _mainOpcodeValue;
  //! Index to \ref _mainOpcodeTable` that is combined with \ref _mainOpcodeValue
  //! to form the final opcode.
  uint8_t _mainOpcodeIndex;
  //! Index to \ref _altOpcodeTable that contains a full alternative opcode.
  uint8_t _altOpcodeIndex;

  // --------------------------------------------------------------------------
  // [Accessors]
  // --------------------------------------------------------------------------

  //! Returns common information, see `CommonInfo`.
  inline 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(); }

  //! Tests whether the instruction is FPU instruction.
  inline 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(); }
  //! Tests whether the instruction is SSE|AVX|AVX512 instruction that accesses XMM|YMM|ZMM registers.
  inline 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(); }
  //! Tests whether the instruction is AVX+ (FMA included) instruction that accesses XMM|YMM|ZMM registers.
  inline 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(); }
  //! Tests whether the instruction can be prefixed with REP (REPE|REPZ) prefix.
  inline 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(); }
  //! Tests whether the instruction can be prefixed with XRELEASE prefix.
  inline 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(); }
  //! Tests whether the instruction uses MIB.
  inline bool isMibOp() const noexcept { return hasFlag(kFlagMib); }
  //! Tests whether the instruction uses VSIB.
  inline bool isVsibOp() const noexcept { return hasFlag(kFlagVsib); }
  //! Tests whether the instruction uses VEX (can be set together with EVEX if both are encodable).
  inline bool isVex() const noexcept { return hasFlag(kFlagVex); }
  //! Tests whether the instruction uses EVEX (can be set together with VEX if both are encodable).
  inline bool isEvex() const noexcept { return hasFlag(kFlagEvex); }
  //! 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); }

  //! Tests whether the instruction supports AVX512 masking {k}.
  inline bool hasAvx512K() const noexcept { return hasFlag(kFlagAvx512K); }
  //! Tests whether the instruction supports AVX512 zeroing {k}{z}.
  inline bool hasAvx512Z() const noexcept { return hasFlag(kFlagAvx512Z); }
  //! Tests whether the instruction supports AVX512 embedded-rounding {er}.
  inline bool hasAvx512ER() const noexcept { return hasFlag(kFlagAvx512ER); }
  //! Tests whether the instruction supports AVX512 suppress-all-exceptions {sae}.
  inline bool hasAvx512SAE() const noexcept { return hasFlag(kFlagAvx512SAE); }
  //! Tests whether the instruction supports AVX512 broadcast (either 32-bit or 64-bit).
  inline bool hasAvx512B() const noexcept { return hasFlag(kFlagAvx512B32 | kFlagAvx512B64); }
  //! Tests whether the instruction supports AVX512 broadcast (32-bit).
  inline bool hasAvx512B32() const noexcept { return hasFlag(kFlagAvx512B32); }
  //! Tests whether the instruction supports AVX512 broadcast (64-bit).
  inline bool hasAvx512B64() const noexcept { return hasFlag(kFlagAvx512B64); }

  //! 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(); }

  inline uint32_t signatureIndex() const noexcept { return commonInfo().signatureIndex(); }
  inline 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_VARAPI const InstInfo _instInfoTable[];

static inline const InstInfo& infoById(uint32_t instId) noexcept {
  ASMJIT_ASSERT(Inst::isDefinedId(instId));
  return _instInfoTable[instId];
}

} // {InstDB}

//! \}

ASMJIT_END_SUB_NAMESPACE

#endif // ASMJIT_X86_X86INSTDB_H_INCLUDED
