diff options
Diffstat (limited to '3rdparty/asmjit/src/asmjit/core/inst.h')
-rw-r--r-- | 3rdparty/asmjit/src/asmjit/core/inst.h | 853 |
1 files changed, 551 insertions, 302 deletions
diff --git a/3rdparty/asmjit/src/asmjit/core/inst.h b/3rdparty/asmjit/src/asmjit/core/inst.h index e34f93c87f1..a653fe8e4cc 100644 --- a/3rdparty/asmjit/src/asmjit/core/inst.h +++ b/3rdparty/asmjit/src/asmjit/core/inst.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_CORE_INST_H_INCLUDED #define ASMJIT_CORE_INST_H_INCLUDED @@ -34,20 +16,203 @@ ASMJIT_BEGIN_NAMESPACE //! \addtogroup asmjit_instruction_db //! \{ -// ============================================================================ -// [asmjit::BaseInst] -// ============================================================================ +//! Describes an instruction id and modifiers used together with the id. +//! +//! Each architecture has a set of valid instructions indexed from 0. Instruction with 0 id is, however, a special +//! instruction that describes a "no instruction" or "invalid instruction". Different architectures can assign a. +//! different instruction to the same id, each architecture typically has its own instructions indexed from 1. +//! +//! Instruction identifiers listed by architecture: +//! +//! - \ref x86::Inst (X86 and X86_64) +//! - \ref a64::Inst (AArch64) +typedef uint32_t InstId; + +//! Instruction id parts. +//! +//! A mask that specifies a bit-layout of \ref InstId. +enum class InstIdParts : uint32_t { + // Common Masks + // ------------ + + //! Real id without any modifiers (always 16 least significant bits). + kRealId = 0x0000FFFFu, + //! Instruction is abstract (or virtual, IR, etc...). + kAbstract = 0x80000000u, + + // ARM Specific + // ------------ + + //! AArch32 first data type, used by ASIMD instructions (`inst.dt.dt2`). + kA32_DT = 0x000F0000u, + //! AArch32 second data type, used by ASIMD instructions (`inst.dt.dt2`). + kA32_DT2 = 0x00F00000u, + //! AArch32/AArch64 condition code. + kARM_Cond = 0x78000000u +}; + +//! Instruction options. +//! +//! Instruction options complement instruction identifier and attributes. +enum class InstOptions : uint32_t { + //! No options. + kNone = 0, + + //! Used internally by emitters for handling errors and rare cases. + kReserved = 0x00000001u, + + //! Prevents following a jump during compilation (Compiler). + kUnfollow = 0x00000002u, + + //! Overwrite the destination operand(s) (Compiler). + //! + //! Hint that is important for register liveness analysis. It tells the compiler that the destination operand will + //! be overwritten now or by adjacent instructions. Compiler knows when a register is completely overwritten by a + //! single instruction, for example you don't have to mark "movaps" or "pxor x, x", however, if a pair of + //! instructions is used and the first of them doesn't completely overwrite the content of the destination, + //! Compiler fails to mark that register as dead. + //! + //! X86 Specific + //! ------------ + //! + //! - All instructions that always overwrite at least the size of the register the virtual-register uses, for + //! example "mov", "movq", "movaps" don't need the overwrite option to be used - conversion, shuffle, and + //! other miscellaneous instructions included. + //! + //! - All instructions that clear the destination register if all operands are the same, for example "xor x, x", + //! "pcmpeqb x x", etc... + //! + //! - Consecutive instructions that partially overwrite the variable until there is no old content require + //! `BaseCompiler::overwrite()` to be used. Some examples (not always the best use cases thought): + //! + //! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa + //! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa + //! - `mov al, ?` followed by `and ax, 0xFF` + //! - `mov al, ?` followed by `mov ah, al` + //! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1` + //! + //! - If the allocated virtual register is used temporarily for scalar operations. For example if you allocate a + //! full vector like `x86::Compiler::newXmm()` and then use that vector for scalar operations you should use + //! `overwrite()` directive: + //! + //! - `sqrtss x, y` - only LO element of `x` is changed, if you don't + //! use HI elements, use `compiler.overwrite().sqrtss(x, y)`. + kOverwrite = 0x00000004u, + + //! Emit short-form of the instruction. + kShortForm = 0x00000010u, + //! Emit long-form of the instruction. + kLongForm = 0x00000020u, + + //! Conditional jump is likely to be taken. + kTaken = 0x00000040u, + //! Conditional jump is unlikely to be taken. + kNotTaken = 0x00000080u, + + // X86 & X64 Options + // ----------------- + + //! Use ModMR instead of ModRM if applicable. + kX86_ModMR = 0x00000100u, + //! Use ModRM instead of ModMR if applicable. + kX86_ModRM = 0x00000200u, + //! Use 3-byte VEX prefix if possible (AVX) (must be 0x00000400). + kX86_Vex3 = 0x00000400u, + //! Use VEX prefix when both VEX|EVEX prefixes are available (HINT: AVX_VNNI). + kX86_Vex = 0x00000800u, + //! Use 4-byte EVEX prefix if possible (AVX-512) (must be 0x00001000). + kX86_Evex = 0x00001000u, + + //! LOCK prefix (lock-enabled instructions only). + kX86_Lock = 0x00002000u, + //! REP prefix (string instructions only). + kX86_Rep = 0x00004000u, + //! REPNE prefix (string instructions only). + kX86_Repne = 0x00008000u, + + //! XACQUIRE prefix (only allowed instructions). + kX86_XAcquire = 0x00010000u, + //! XRELEASE prefix (only allowed instructions). + kX86_XRelease = 0x00020000u, + + //! AVX-512: embedded-rounding {er} and implicit {sae}. + kX86_ER = 0x00040000u, + //! AVX-512: suppress-all-exceptions {sae}. + kX86_SAE = 0x00080000u, + //! AVX-512: round-to-nearest (even) {rn-sae} (bits 00). + kX86_RN_SAE = 0x00000000u, + //! AVX-512: round-down (toward -inf) {rd-sae} (bits 01). + kX86_RD_SAE = 0x00200000u, + //! AVX-512: round-up (toward +inf) {ru-sae} (bits 10). + kX86_RU_SAE = 0x00400000u, + //! AVX-512: round-toward-zero (truncate) {rz-sae} (bits 11). + kX86_RZ_SAE = 0x00600000u, + //! AVX-512: Use zeroing {k}{z} instead of merging {k}. + kX86_ZMask = 0x00800000u, + + //! AVX-512: Mask to get embedded rounding bits (2 bits). + kX86_ERMask = kX86_RZ_SAE, + //! AVX-512: Mask of all possible AVX-512 options except EVEX prefix flag. + kX86_AVX512Mask = 0x00FC0000u, + + //! Force REX.B and/or VEX.B field (X64 only). + kX86_OpCodeB = 0x01000000u, + //! Force REX.X and/or VEX.X field (X64 only). + kX86_OpCodeX = 0x02000000u, + //! Force REX.R and/or VEX.R field (X64 only). + kX86_OpCodeR = 0x04000000u, + //! Force REX.W and/or VEX.W field (X64 only). + kX86_OpCodeW = 0x08000000u, + //! Force REX prefix (X64 only). + kX86_Rex = 0x40000000u, + //! Invalid REX prefix (set by X86 or when AH|BH|CH|DH regs are used on X64). + kX86_InvalidRex = 0x80000000u +}; +ASMJIT_DEFINE_ENUM_FLAGS(InstOptions) + +//! Instruction control flow. +enum class InstControlFlow : uint32_t { + //! Regular instruction. + kRegular = 0u, + //! Unconditional jump. + kJump = 1u, + //! Conditional jump (branch). + kBranch = 2u, + //! Function call. + kCall = 3u, + //! Function return. + kReturn = 4u, + + //! Maximum value of `InstType`. + kMaxValue = kReturn +}; + +//! Hint that is used when both input operands to the instruction are the same. +//! +//! Provides hints to the instruction RW query regarding special cases in which two or more operands are the same +//! registers. This is required by instructions such as XOR, AND, OR, SUB, etc... These hints will influence the +//! RW operations query. +enum class InstSameRegHint : uint8_t { + //! No special handling. + kNone = 0, + //! Operands become read-only, the operation doesn't change the content - `X & X` and similar. + kRO = 1, + //! Operands become write-only, the content of the input(s) don't matter - `X ^ X`, `X - X`, and similar. + kWO = 2 +}; -//! Instruction id, options, and extraReg in a single structure. This structure -//! exists mainly to simplify analysis and validation API that requires `BaseInst` -//! and `Operand[]` array. +//! Instruction id, options, and extraReg in a single structure. This structure exists mainly to simplify analysis +//! and validation API that requires `BaseInst` and `Operand[]` array. class BaseInst { public: - //! Instruction id, see \ref BaseInst::Id or {arch-specific}::Inst::Id. - uint32_t _id; - //! Instruction options, see \ref BaseInst::Options or {arch-specific}::Inst::Options. - uint32_t _options; - //! Extra register used by instruction (either REP register or AVX-512 selector). + //! \name Members + //! \{ + + //! Instruction id with modifiers. + InstId _id; + //! Instruction options. + InstOptions _options; + //! Extra register used by the instruction (either REP register or AVX-512 selector). RegOnly _extraReg; enum Id : uint32_t { @@ -57,154 +222,272 @@ public: kIdAbstract = 0x80000000u }; - enum Options : uint32_t { - //! Used internally by emitters for handling errors and rare cases. - kOptionReserved = 0x00000001u, - - //! Prevents following a jump during compilation (BaseCompiler). - kOptionUnfollow = 0x00000010u, - - //! Overwrite the destination operand(s) (BaseCompiler). - //! - //! Hint that is important for register liveness analysis. It tells the - //! compiler that the destination operand will be overwritten now or by - //! adjacent instructions. BaseCompiler knows when a register is completely - //! overwritten by a single instruction, for example you don't have to - //! mark "movaps" or "pxor x, x", however, if a pair of instructions is - //! used and the first of them doesn't completely overwrite the content - //! of the destination, BaseCompiler fails to mark that register as dead. - //! - //! X86 Specific - //! ------------ - //! - //! - All instructions that always overwrite at least the size of the - //! register the virtual-register uses , for example "mov", "movq", - //! "movaps" don't need the overwrite option to be used - conversion, - //! shuffle, and other miscellaneous instructions included. - //! - //! - All instructions that clear the destination register if all operands - //! are the same, for example "xor x, x", "pcmpeqb x x", etc... - //! - //! - Consecutive instructions that partially overwrite the variable until - //! there is no old content require `BaseCompiler::overwrite()` to be used. - //! Some examples (not always the best use cases thought): - //! - //! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa - //! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa - //! - `mov al, ?` followed by `and ax, 0xFF` - //! - `mov al, ?` followed by `mov ah, al` - //! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1` - //! - //! - If allocated variable is used temporarily for scalar operations. For - //! example if you allocate a full vector like `x86::Compiler::newXmm()` - //! and then use that vector for scalar operations you should use - //! `overwrite()` directive: - //! - //! - `sqrtss x, y` - only LO element of `x` is changed, if you don't - //! use HI elements, use `compiler.overwrite().sqrtss(x, y)`. - kOptionOverwrite = 0x00000020u, - - //! Emit short-form of the instruction. - kOptionShortForm = 0x00000040u, - //! Emit long-form of the instruction. - kOptionLongForm = 0x00000080u, - - //! Conditional jump is likely to be taken. - kOptionTaken = 0x00000100u, - //! Conditional jump is unlikely to be taken. - kOptionNotTaken = 0x00000200u - }; - - //! Control type. - enum ControlType : uint32_t { - //! No control type (doesn't jump). - kControlNone = 0u, - //! Unconditional jump. - kControlJump = 1u, - //! Conditional jump (branch). - kControlBranch = 2u, - //! Function call. - kControlCall = 3u, - //! Function return. - kControlReturn = 4u - }; + //! \} //! \name Construction & Destruction //! \{ //! Creates a new BaseInst instance with `id` and `options` set. //! - //! Default values of `id` and `options` are zero, which means none instruciton. - //! Such instruction is guaranteed to never exist for any architecture supported - //! by AsmJit. - inline explicit BaseInst(uint32_t id = 0, uint32_t options = 0) noexcept - : _id(id), + //! Default values of `id` and `options` are zero, which means 'none' instruction. Such instruction is guaranteed + //! to never exist for any architecture supported by AsmJit. + ASMJIT_INLINE_NODEBUG explicit BaseInst(InstId instId = 0, InstOptions options = InstOptions::kNone) noexcept + : _id(instId), _options(options), _extraReg() {} - inline BaseInst(uint32_t id, uint32_t options, const RegOnly& extraReg) noexcept - : _id(id), + ASMJIT_INLINE_NODEBUG BaseInst(InstId instId, InstOptions options, const RegOnly& extraReg) noexcept + : _id(instId), _options(options), _extraReg(extraReg) {} - inline BaseInst(uint32_t id, uint32_t options, const BaseReg& extraReg) noexcept - : _id(id), + ASMJIT_INLINE_NODEBUG BaseInst(InstId instId, InstOptions options, const BaseReg& extraReg) noexcept + : _id(instId), _options(options), _extraReg { extraReg.signature(), extraReg.id() } {} //! \} - //! \name Instruction ID + //! \name Instruction id and modifiers //! \{ - //! Returns the instruction id. - inline uint32_t id() const noexcept { return _id; } - //! Sets the instruction id to the given `id`. - inline void setId(uint32_t id) noexcept { _id = id; } - //! Resets the instruction id to zero, see \ref kIdNone. - inline void resetId() noexcept { _id = 0; } + //! Returns the instruction id with modifiers. + ASMJIT_INLINE_NODEBUG InstId id() const noexcept { return _id; } + //! Sets the instruction id and modiiers from `id`. + ASMJIT_INLINE_NODEBUG void setId(InstId id) noexcept { _id = id; } + //! Resets the instruction id and modifiers to zero, see \ref kIdNone. + ASMJIT_INLINE_NODEBUG void resetId() noexcept { _id = 0; } + + //! Returns a real instruction id that doesn't contain any modifiers. + ASMJIT_INLINE_NODEBUG InstId realId() const noexcept { return _id & uint32_t(InstIdParts::kRealId); } + + template<InstIdParts kPart> + ASMJIT_INLINE_NODEBUG uint32_t getInstIdPart() const noexcept { + return (uint32_t(_id) & uint32_t(kPart)) >> Support::ConstCTZ<uint32_t(kPart)>::value; + } + + template<InstIdParts kPart> + ASMJIT_INLINE_NODEBUG void setInstIdPart(uint32_t value) noexcept { + _id = (_id & ~uint32_t(kPart)) | (value << Support::ConstCTZ<uint32_t(kPart)>::value); + } //! \} //! \name Instruction Options //! \{ - inline uint32_t options() const noexcept { return _options; } - inline bool hasOption(uint32_t option) const noexcept { return (_options & option) != 0; } - inline void setOptions(uint32_t options) noexcept { _options = options; } - inline void addOptions(uint32_t options) noexcept { _options |= options; } - inline void clearOptions(uint32_t options) noexcept { _options &= ~options; } - inline void resetOptions() noexcept { _options = 0; } + ASMJIT_INLINE_NODEBUG InstOptions options() const noexcept { return _options; } + ASMJIT_INLINE_NODEBUG bool hasOption(InstOptions option) const noexcept { return Support::test(_options, option); } + ASMJIT_INLINE_NODEBUG void setOptions(InstOptions options) noexcept { _options = options; } + ASMJIT_INLINE_NODEBUG void addOptions(InstOptions options) noexcept { _options |= options; } + ASMJIT_INLINE_NODEBUG void clearOptions(InstOptions options) noexcept { _options &= ~options; } + ASMJIT_INLINE_NODEBUG void resetOptions() noexcept { _options = InstOptions::kNone; } //! \} //! \name Extra Register //! \{ - inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); } - inline RegOnly& extraReg() noexcept { return _extraReg; } - inline const RegOnly& extraReg() const noexcept { return _extraReg; } - inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); } - inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); } - inline void resetExtraReg() noexcept { _extraReg.reset(); } + ASMJIT_INLINE_NODEBUG bool hasExtraReg() const noexcept { return _extraReg.isReg(); } + ASMJIT_INLINE_NODEBUG RegOnly& extraReg() noexcept { return _extraReg; } + ASMJIT_INLINE_NODEBUG const RegOnly& extraReg() const noexcept { return _extraReg; } + ASMJIT_INLINE_NODEBUG void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); } + ASMJIT_INLINE_NODEBUG void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); } + ASMJIT_INLINE_NODEBUG void resetExtraReg() noexcept { _extraReg.reset(); } + + //! \} + + //! \name ARM Specific + //! \{ + + ASMJIT_INLINE_NODEBUG arm::CondCode armCondCode() const noexcept { return (arm::CondCode)getInstIdPart<InstIdParts::kARM_Cond>(); } + ASMJIT_INLINE_NODEBUG void setArmCondCode(arm::CondCode cc) noexcept { setInstIdPart<InstIdParts::kARM_Cond>(uint32_t(cc)); } + + ASMJIT_INLINE_NODEBUG a32::DataType armDt() const noexcept { return (a32::DataType)getInstIdPart<InstIdParts::kA32_DT>(); } + ASMJIT_INLINE_NODEBUG a32::DataType armDt2() const noexcept { return (a32::DataType)getInstIdPart<InstIdParts::kA32_DT2>(); } + + //! \} + + //! \name Statics + //! \{ + + static ASMJIT_INLINE_NODEBUG constexpr InstId composeARMInstId(uint32_t id, arm::CondCode cc) noexcept { + return id | (uint32_t(cc) << Support::ConstCTZ<uint32_t(InstIdParts::kARM_Cond)>::value); + } + + static ASMJIT_INLINE_NODEBUG constexpr InstId composeARMInstId(uint32_t id, a32::DataType dt, arm::CondCode cc = arm::CondCode::kAL) noexcept { + return id | (uint32_t(dt) << Support::ConstCTZ<uint32_t(InstIdParts::kA32_DT)>::value) + | (uint32_t(cc) << Support::ConstCTZ<uint32_t(InstIdParts::kARM_Cond)>::value); + } + + static ASMJIT_INLINE_NODEBUG constexpr InstId composeARMInstId(uint32_t id, a32::DataType dt, a32::DataType dt2, arm::CondCode cc = arm::CondCode::kAL) noexcept { + return id | (uint32_t(dt) << Support::ConstCTZ<uint32_t(InstIdParts::kA32_DT)>::value) + | (uint32_t(dt2) << Support::ConstCTZ<uint32_t(InstIdParts::kA32_DT2)>::value) + | (uint32_t(cc) << Support::ConstCTZ<uint32_t(InstIdParts::kARM_Cond)>::value); + } + + static ASMJIT_INLINE_NODEBUG constexpr InstId extractRealId(uint32_t id) noexcept { + return id & uint32_t(InstIdParts::kRealId); + } + + static ASMJIT_INLINE_NODEBUG constexpr arm::CondCode extractARMCondCode(uint32_t id) noexcept { + return (arm::CondCode)((uint32_t(id) & uint32_t(InstIdParts::kARM_Cond)) >> Support::ConstCTZ<uint32_t(InstIdParts::kARM_Cond)>::value); + } //! \} }; -// ============================================================================ -// [asmjit::OpRWInfo] -// ============================================================================ +//! CPU read/write flags used by \ref InstRWInfo. +//! +//! These flags can be used to get a basic overview about CPU specifics flags used by instructions. +enum class CpuRWFlags : uint32_t { + //! No flags. + kNone = 0x00000000u, + + // Common RW Flags (0x000000FF) + // ---------------------------- + + //! Signed overflow flag. + kOF = 0x00000001u, + //! Carry flag. + kCF = 0x00000002u, + //! Zero and/or equality flag (1 if zero/equal). + kZF = 0x00000004u, + //! Sign flag (negative/sign, if set). + kSF = 0x00000008u, + + // X86 Specific RW Flags + // ---------------------------------- + + //! Carry flag (X86, X86_64). + kX86_CF = kCF, + //! Overflow flag (X86, X86_64). + kX86_OF = kOF, + //! Sign flag (X86, X86_64). + kX86_SF = kSF, + //! Zero flag (X86, X86_64). + kX86_ZF = kZF, + + //! Adjust flag (X86, X86_64). + kX86_AF = 0x00000100u, + //! Parity flag (X86, X86_64). + kX86_PF = 0x00000200u, + //! Direction flag (X86, X86_64). + kX86_DF = 0x00000400u, + //! Interrupt enable flag (X86, X86_64). + kX86_IF = 0x00000800u, + + //! Alignment check flag (X86, X86_64). + kX86_AC = 0x00001000u, + + //! FPU C0 status flag (X86, X86_64). + kX86_C0 = 0x00010000u, + //! FPU C1 status flag (X86, X86_64). + kX86_C1 = 0x00020000u, + //! FPU C2 status flag (X86, X86_64). + kX86_C2 = 0x00040000u, + //! FPU C3 status flag (X86, X86_64). + kX86_C3 = 0x00080000u, + + // ARM Specific RW Flags + // ---------------------------------- + + kARM_V = kOF, + kARM_C = kCF, + kARM_Z = kZF, + kARM_N = kSF, + kARM_Q = 0x00000100u, + kARM_GE = 0x00000200u +}; +ASMJIT_DEFINE_ENUM_FLAGS(CpuRWFlags) + +//! Operand read/write flags describe how the operand is accessed and some additional features. +enum class OpRWFlags : uint32_t { + //! No flags. + kNone = 0, + + //! Operand is read. + kRead = 0x00000001u, + + //! Operand is written. + kWrite = 0x00000002u, + + //! Operand is both read and written. + kRW = 0x00000003u, + + //! Register operand can be replaced by a memory operand. + kRegMem = 0x00000004u, + + //! The register must be allocated to the index of the previous register + 1. + //! + //! This flag is used by all architectures to describe instructions that use consecutive registers, where only the + //! first one is encoded in the instruction, and the others are just a sequence that starts with the first one. On + //! X86/X86_64 architecture this is used by instructions such as V4FMADDPS, V4FMADDSS, V4FNMADDPS, V4FNMADDSS, + //! VP4DPWSSD, VP4DPWSSDS, VP2INTERSECTD, and VP2INTERSECTQ. On ARM/AArch64 this is used by vector load and store + //! instructions that can load or store multiple registers at once. + kConsecutive = 0x00000008u, + + //! The `extendByteMask()` represents a zero extension. + kZExt = 0x00000010u, + + //! The register must have assigned a unique physical ID, which cannot be assigned to any other register. + kUnique = 0x00000080u, + + //! Register operand must use \ref OpRWInfo::physId(). + kRegPhysId = 0x00000100u, + //! Base register of a memory operand must use \ref OpRWInfo::physId(). + kMemPhysId = 0x00000200u, + + //! This memory operand is only used to encode registers and doesn't access memory. + //! + //! X86 Specific + //! ------------ + //! + //! Instructions that use such feature include BNDLDX, BNDSTX, and LEA. + kMemFake = 0x000000400u, + + //! Base register of the memory operand will be read. + kMemBaseRead = 0x00001000u, + //! Base register of the memory operand will be written. + kMemBaseWrite = 0x00002000u, + //! Base register of the memory operand will be read & written. + kMemBaseRW = 0x00003000u, + + //! Index register of the memory operand will be read. + kMemIndexRead = 0x00004000u, + //! Index register of the memory operand will be written. + kMemIndexWrite = 0x00008000u, + //! Index register of the memory operand will be read & written. + kMemIndexRW = 0x0000C000u, + + //! Base register of the memory operand will be modified before the operation. + kMemBasePreModify = 0x00010000u, + //! Base register of the memory operand will be modified after the operation. + kMemBasePostModify = 0x00020000u +}; +ASMJIT_DEFINE_ENUM_FLAGS(OpRWFlags) + +// Don't remove these asserts. Read/Write flags are used extensively +// by Compiler and they must always be compatible with constants below. +static_assert(uint32_t(OpRWFlags::kRead) == 0x1, "OpRWFlags::kRead flag must be 0x1"); +static_assert(uint32_t(OpRWFlags::kWrite) == 0x2, "OpRWFlags::kWrite flag must be 0x2"); +static_assert(uint32_t(OpRWFlags::kRegMem) == 0x4, "OpRWFlags::kRegMem flag must be 0x4"); //! Read/Write information related to a single operand, used by \ref InstRWInfo. struct OpRWInfo { - //! Read/Write flags, see \ref OpRWInfo::Flags. - uint32_t _opFlags; + //! \name Members + //! \{ + + //! Read/Write flags. + OpRWFlags _opFlags; //! Physical register index, if required. uint8_t _physId; //! Size of a possible memory operand that can replace a register operand. uint8_t _rmSize; + //! If non-zero, then this is a consecutive lead register, and the value describes how many registers follow. + uint8_t _consecutiveLeadCount; //! Reserved for future use. - uint8_t _reserved[2]; + uint8_t _reserved[1]; //! Read bit-mask where each bit represents one byte read from Reg/Mem. uint64_t _readByteMask; //! Write bit-mask where each bit represents one byte written to Reg/Mem. @@ -212,84 +495,32 @@ struct OpRWInfo { //! Zero/Sign extend bit-mask where each bit represents one byte written to Reg/Mem. uint64_t _extendByteMask; - //! Flags describe how the operand is accessed and some additional information. - enum Flags : uint32_t { - //! Operand is read. - kRead = 0x00000001u, - - //! Operand is written. - kWrite = 0x00000002u, - - //! Operand is both read and written. - kRW = 0x00000003u, - - //! Register operand can be replaced by a memory operand. - kRegMem = 0x00000004u, - - //! The `extendByteMask()` represents a zero extension. - kZExt = 0x00000010u, - - //! Register operand must use \ref physId(). - kRegPhysId = 0x00000100u, - //! Base register of a memory operand must use \ref physId(). - kMemPhysId = 0x00000200u, - - //! This memory operand is only used to encode registers and doesn't access memory. - //! - //! X86 Specific - //! ------------ - //! - //! Instructions that use such feature include BNDLDX, BNDSTX, and LEA. - kMemFake = 0x000000400u, - - //! Base register of the memory operand will be read. - kMemBaseRead = 0x00001000u, - //! Base register of the memory operand will be written. - kMemBaseWrite = 0x00002000u, - //! Base register of the memory operand will be read & written. - kMemBaseRW = 0x00003000u, - - //! Index register of the memory operand will be read. - kMemIndexRead = 0x00004000u, - //! Index register of the memory operand will be written. - kMemIndexWrite = 0x00008000u, - //! Index register of the memory operand will be read & written. - kMemIndexRW = 0x0000C000u, - - //! Base register of the memory operand will be modified before the operation. - kMemBasePreModify = 0x00010000u, - //! Base register of the memory operand will be modified after the operation. - kMemBasePostModify = 0x00020000u - }; - - // Don't remove these asserts. Read/Write flags are used extensively - // by Compiler and they must always be compatible with constants below. - static_assert(kRead == 0x1, "OpRWInfo::kRead flag must be 0x1"); - static_assert(kWrite == 0x2, "OpRWInfo::kWrite flag must be 0x2"); - static_assert(kRegMem == 0x4, "OpRWInfo::kRegMem flag must be 0x4"); + //! \} //! \name Reset //! \{ //! Resets this operand information to all zeros. - inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + ASMJIT_INLINE_NODEBUG void reset() noexcept { *this = OpRWInfo{}; } //! Resets this operand info (resets all members) and set common information //! to the given `opFlags`, `regSize`, and possibly `physId`. - inline void reset(uint32_t opFlags, uint32_t regSize, uint32_t physId = BaseReg::kIdBad) noexcept { + inline void reset(OpRWFlags opFlags, uint32_t regSize, uint32_t physId = BaseReg::kIdBad) noexcept { _opFlags = opFlags; _physId = uint8_t(physId); - _rmSize = uint8_t((opFlags & kRegMem) ? regSize : uint32_t(0)); + _rmSize = Support::test(opFlags, OpRWFlags::kRegMem) ? uint8_t(regSize) : uint8_t(0); + _consecutiveLeadCount = 0; _resetReserved(); - uint64_t mask = Support::lsbMask<uint64_t>(regSize); - _readByteMask = opFlags & kRead ? mask : uint64_t(0); - _writeByteMask = opFlags & kWrite ? mask : uint64_t(0); + uint64_t mask = Support::lsbMask<uint64_t>(Support::min<uint32_t>(regSize, 64)); + + _readByteMask = Support::test(opFlags, OpRWFlags::kRead) ? mask : uint64_t(0); + _writeByteMask = Support::test(opFlags, OpRWFlags::kWrite) ? mask : uint64_t(0); _extendByteMask = 0; } - inline void _resetReserved() noexcept { - memset(_reserved, 0, sizeof(_reserved)); + ASMJIT_INLINE_NODEBUG void _resetReserved() noexcept { + _reserved[0] = 0; } //! \} @@ -297,73 +528,81 @@ struct OpRWInfo { //! \name Operand Flags //! \{ - //! Returns operand flags, see \ref Flags. - inline uint32_t opFlags() const noexcept { return _opFlags; } + //! Returns operand flags. + ASMJIT_INLINE_NODEBUG OpRWFlags opFlags() const noexcept { return _opFlags; } //! Tests whether operand flags contain the given `flag`. - inline bool hasOpFlag(uint32_t flag) const noexcept { return (_opFlags & flag) != 0; } + ASMJIT_INLINE_NODEBUG bool hasOpFlag(OpRWFlags flag) const noexcept { return Support::test(_opFlags, flag); } //! Adds the given `flags` to operand flags. - inline void addOpFlags(uint32_t flags) noexcept { _opFlags |= flags; } + ASMJIT_INLINE_NODEBUG void addOpFlags(OpRWFlags flags) noexcept { _opFlags |= flags; } //! Removes the given `flags` from operand flags. - inline void clearOpFlags(uint32_t flags) noexcept { _opFlags &= ~flags; } + ASMJIT_INLINE_NODEBUG void clearOpFlags(OpRWFlags flags) noexcept { _opFlags &= ~flags; } //! Tests whether this operand is read from. - inline bool isRead() const noexcept { return hasOpFlag(kRead); } + ASMJIT_INLINE_NODEBUG bool isRead() const noexcept { return hasOpFlag(OpRWFlags::kRead); } //! Tests whether this operand is written to. - inline bool isWrite() const noexcept { return hasOpFlag(kWrite); } + ASMJIT_INLINE_NODEBUG bool isWrite() const noexcept { return hasOpFlag(OpRWFlags::kWrite); } //! Tests whether this operand is both read and write. - inline bool isReadWrite() const noexcept { return (_opFlags & kRW) == kRW; } + ASMJIT_INLINE_NODEBUG bool isReadWrite() const noexcept { return (_opFlags & OpRWFlags::kRW) == OpRWFlags::kRW; } //! Tests whether this operand is read only. - inline bool isReadOnly() const noexcept { return (_opFlags & kRW) == kRead; } + ASMJIT_INLINE_NODEBUG bool isReadOnly() const noexcept { return (_opFlags & OpRWFlags::kRW) == OpRWFlags::kRead; } //! Tests whether this operand is write only. - inline bool isWriteOnly() const noexcept { return (_opFlags & kRW) == kWrite; } + ASMJIT_INLINE_NODEBUG bool isWriteOnly() const noexcept { return (_opFlags & OpRWFlags::kRW) == OpRWFlags::kWrite; } + + //! Returns the type of a lead register, which is followed by consecutive registers. + ASMJIT_INLINE_NODEBUG uint32_t consecutiveLeadCount() const noexcept { return _consecutiveLeadCount; } //! Tests whether this operand is Reg/Mem //! //! Reg/Mem operands can use either register or memory. - inline bool isRm() const noexcept { return hasOpFlag(kRegMem); } + ASMJIT_INLINE_NODEBUG bool isRm() const noexcept { return hasOpFlag(OpRWFlags::kRegMem); } //! Tests whether the operand will be zero extended. - inline bool isZExt() const noexcept { return hasOpFlag(kZExt); } + ASMJIT_INLINE_NODEBUG bool isZExt() const noexcept { return hasOpFlag(OpRWFlags::kZExt); } + + //! Tests whether the operand must have allocated a unique physical id that cannot be shared with other register + //! operands. + ASMJIT_INLINE_NODEBUG bool isUnique() const noexcept { return hasOpFlag(OpRWFlags::kUnique); } //! \} //! \name Memory Flags //! \{ - //! Tests whether this is a fake memory operand, which is only used, because - //! of encoding. Fake memory operands do not access any memory, they are only - //! used to encode registers. - inline bool isMemFake() const noexcept { return hasOpFlag(kMemFake); } + //! Tests whether this is a fake memory operand, which is only used, because of encoding. Fake memory operands do + //! not access any memory, they are only used to encode registers. + ASMJIT_INLINE_NODEBUG bool isMemFake() const noexcept { return hasOpFlag(OpRWFlags::kMemFake); } + //! Tests whether the instruction's memory BASE register is used. + ASMJIT_INLINE_NODEBUG bool isMemBaseUsed() const noexcept { return hasOpFlag(OpRWFlags::kMemBaseRW); } //! Tests whether the instruction reads from its BASE registers. - inline bool isMemBaseRead() const noexcept { return hasOpFlag(kMemBaseRead); } + ASMJIT_INLINE_NODEBUG bool isMemBaseRead() const noexcept { return hasOpFlag(OpRWFlags::kMemBaseRead); } //! Tests whether the instruction writes to its BASE registers. - inline bool isMemBaseWrite() const noexcept { return hasOpFlag(kMemBaseWrite); } + ASMJIT_INLINE_NODEBUG bool isMemBaseWrite() const noexcept { return hasOpFlag(OpRWFlags::kMemBaseWrite); } //! Tests whether the instruction reads and writes from/to its BASE registers. - inline bool isMemBaseReadWrite() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseRW; } + ASMJIT_INLINE_NODEBUG bool isMemBaseReadWrite() const noexcept { return (_opFlags & OpRWFlags::kMemBaseRW) == OpRWFlags::kMemBaseRW; } //! Tests whether the instruction only reads from its BASE registers. - inline bool isMemBaseReadOnly() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseRead; } + ASMJIT_INLINE_NODEBUG bool isMemBaseReadOnly() const noexcept { return (_opFlags & OpRWFlags::kMemBaseRW) == OpRWFlags::kMemBaseRead; } //! Tests whether the instruction only writes to its BASE registers. - inline bool isMemBaseWriteOnly() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseWrite; } + ASMJIT_INLINE_NODEBUG bool isMemBaseWriteOnly() const noexcept { return (_opFlags & OpRWFlags::kMemBaseRW) == OpRWFlags::kMemBaseWrite; } - //! Tests whether the instruction modifies the BASE register before it uses - //! it to calculate the target address. - inline bool isMemBasePreModify() const noexcept { return hasOpFlag(kMemBasePreModify); } - //! Tests whether the instruction modifies the BASE register after it uses - //! it to calculate the target address. - inline bool isMemBasePostModify() const noexcept { return hasOpFlag(kMemBasePostModify); } + //! Tests whether the instruction modifies the BASE register before it uses it to calculate the target address. + ASMJIT_INLINE_NODEBUG bool isMemBasePreModify() const noexcept { return hasOpFlag(OpRWFlags::kMemBasePreModify); } + //! Tests whether the instruction modifies the BASE register after it uses it to calculate the target address. + ASMJIT_INLINE_NODEBUG bool isMemBasePostModify() const noexcept { return hasOpFlag(OpRWFlags::kMemBasePostModify); } + //! Tests whether the instruction's memory INDEX register is used. + ASMJIT_INLINE_NODEBUG bool isMemIndexUsed() const noexcept { return hasOpFlag(OpRWFlags::kMemIndexRW); } //! Tests whether the instruction reads the INDEX registers. - inline bool isMemIndexRead() const noexcept { return hasOpFlag(kMemIndexRead); } + ASMJIT_INLINE_NODEBUG bool isMemIndexRead() const noexcept { return hasOpFlag(OpRWFlags::kMemIndexRead); } //! Tests whether the instruction writes to its INDEX registers. - inline bool isMemIndexWrite() const noexcept { return hasOpFlag(kMemIndexWrite); } + ASMJIT_INLINE_NODEBUG bool isMemIndexWrite() const noexcept { return hasOpFlag(OpRWFlags::kMemIndexWrite); } //! Tests whether the instruction reads and writes from/to its INDEX registers. - inline bool isMemIndexReadWrite() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexRW; } + ASMJIT_INLINE_NODEBUG bool isMemIndexReadWrite() const noexcept { return (_opFlags & OpRWFlags::kMemIndexRW) == OpRWFlags::kMemIndexRW; } //! Tests whether the instruction only reads from its INDEX registers. - inline bool isMemIndexReadOnly() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexRead; } + ASMJIT_INLINE_NODEBUG bool isMemIndexReadOnly() const noexcept { return (_opFlags & OpRWFlags::kMemIndexRW) == OpRWFlags::kMemIndexRead; } //! Tests whether the instruction only writes to its INDEX registers. - inline bool isMemIndexWriteOnly() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexWrite; } + ASMJIT_INLINE_NODEBUG bool isMemIndexWriteOnly() const noexcept { return (_opFlags & OpRWFlags::kMemIndexRW) == OpRWFlags::kMemIndexWrite; } //! \} @@ -373,11 +612,11 @@ struct OpRWInfo { //! Returns a physical id of the register that is fixed for this operand. //! //! Returns \ref BaseReg::kIdBad if any register can be used. - inline uint32_t physId() const noexcept { return _physId; } + ASMJIT_INLINE_NODEBUG uint32_t physId() const noexcept { return _physId; } //! Tests whether \ref physId() would return a valid physical register id. - inline bool hasPhysId() const noexcept { return _physId != BaseReg::kIdBad; } + ASMJIT_INLINE_NODEBUG bool hasPhysId() const noexcept { return _physId != BaseReg::kIdBad; } //! Sets physical register id, which would be fixed for this operand. - inline void setPhysId(uint32_t physId) noexcept { _physId = uint8_t(physId); } + ASMJIT_INLINE_NODEBUG void setPhysId(uint32_t physId) noexcept { _physId = uint8_t(physId); } //! \} @@ -385,9 +624,9 @@ struct OpRWInfo { //! \{ //! Returns Reg/Mem size of the operand. - inline uint32_t rmSize() const noexcept { return _rmSize; } + ASMJIT_INLINE_NODEBUG uint32_t rmSize() const noexcept { return _rmSize; } //! Sets Reg/Mem size of the operand. - inline void setRmSize(uint32_t rmSize) noexcept { _rmSize = uint8_t(rmSize); } + ASMJIT_INLINE_NODEBUG void setRmSize(uint32_t rmSize) noexcept { _rmSize = uint8_t(rmSize); } //! \} @@ -395,88 +634,104 @@ struct OpRWInfo { //! \{ //! Returns read mask. - inline uint64_t readByteMask() const noexcept { return _readByteMask; } + ASMJIT_INLINE_NODEBUG uint64_t readByteMask() const noexcept { return _readByteMask; } //! Returns write mask. - inline uint64_t writeByteMask() const noexcept { return _writeByteMask; } + ASMJIT_INLINE_NODEBUG uint64_t writeByteMask() const noexcept { return _writeByteMask; } //! Returns extend mask. - inline uint64_t extendByteMask() const noexcept { return _extendByteMask; } + ASMJIT_INLINE_NODEBUG uint64_t extendByteMask() const noexcept { return _extendByteMask; } //! Sets read mask. - inline void setReadByteMask(uint64_t mask) noexcept { _readByteMask = mask; } + ASMJIT_INLINE_NODEBUG void setReadByteMask(uint64_t mask) noexcept { _readByteMask = mask; } //! Sets write mask. - inline void setWriteByteMask(uint64_t mask) noexcept { _writeByteMask = mask; } - //! Sets externd mask. - inline void setExtendByteMask(uint64_t mask) noexcept { _extendByteMask = mask; } + ASMJIT_INLINE_NODEBUG void setWriteByteMask(uint64_t mask) noexcept { _writeByteMask = mask; } + //! Sets extend mask. + ASMJIT_INLINE_NODEBUG void setExtendByteMask(uint64_t mask) noexcept { _extendByteMask = mask; } //! \} }; -// ============================================================================ -// [asmjit::InstRWInfo] -// ============================================================================ +//! Flags used by \ref InstRWInfo. +enum class InstRWFlags : uint32_t { + //! No flags. + kNone = 0x00000000u, + + //! Describes a move operation. + //! + //! This flag is used by RA to eliminate moves that are guaranteed to be moves only. + kMovOp = 0x00000001u +}; +ASMJIT_DEFINE_ENUM_FLAGS(InstRWFlags) //! Read/Write information of an instruction. struct InstRWInfo { + //! \name Members + //! \{ + //! Instruction flags (there are no flags at the moment, this field is reserved). - uint32_t _instFlags; - //! Mask of CPU flags read. - uint32_t _readFlags; - //! Mask of CPU flags written. - uint32_t _writeFlags; + InstRWFlags _instFlags; + //! CPU flags read. + CpuRWFlags _readFlags; + //! CPU flags written. + CpuRWFlags _writeFlags; //! Count of operands. uint8_t _opCount; //! CPU feature required for replacing register operand with memory operand. uint8_t _rmFeature; //! Reserved for future use. uint8_t _reserved[18]; - //! Read/Write onfo of extra register (rep{} or kz{}). + //! Read/Write info of extra register (rep{} or kz{}). OpRWInfo _extraReg; //! Read/Write info of instruction operands. OpRWInfo _operands[Globals::kMaxOpCount]; + //! \} + //! \name Commons //! \{ //! Resets this RW information to all zeros. - inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + ASMJIT_INLINE_NODEBUG void reset() noexcept { *this = InstRWInfo{}; } //! \} //! \name Instruction Flags - //! //! \{ - inline uint32_t instFlags() const noexcept { return _instFlags; } - inline bool hasInstFlag(uint32_t flag) const noexcept { return (_instFlags & flag) != 0; } + //! Returns flags associated with the instruction, see \ref InstRWFlags. + ASMJIT_INLINE_NODEBUG InstRWFlags instFlags() const noexcept { return _instFlags; } - //! } + //! Tests whether the instruction flags contain `flag`. + ASMJIT_INLINE_NODEBUG bool hasInstFlag(InstRWFlags flag) const noexcept { return Support::test(_instFlags, flag); } - //! \name CPU Flags Read/Write Information + //! Tests whether the instruction flags contain \ref InstRWFlags::kMovOp. + ASMJIT_INLINE_NODEBUG bool isMovOp() const noexcept { return hasInstFlag(InstRWFlags::kMovOp); } + + //! \} + + //! \name CPU Flags Information //! \{ - //! Returns read flags of the instruction. - inline uint32_t readFlags() const noexcept { return _readFlags; } - //! Returns write flags of the instruction. - inline uint32_t writeFlags() const noexcept { return _writeFlags; } + //! Returns a mask of CPU flags read. + ASMJIT_INLINE_NODEBUG CpuRWFlags readFlags() const noexcept { return _readFlags; } + //! Returns a mask of CPU flags written. + ASMJIT_INLINE_NODEBUG CpuRWFlags writeFlags() const noexcept { return _writeFlags; } //! \} //! \name Reg/Mem Information //! \{ - //! Returns the CPU feature required to replace a register operand with memory - //! operand. If the returned feature is zero (none) then this instruction - //! either doesn't provide memory operand combination or there is no extra - //! CPU feature required. + //! Returns the CPU feature required to replace a register operand with memory operand. If the returned feature is + //! zero (none) then this instruction either doesn't provide memory operand combination or there is no extra CPU + //! feature required. //! //! X86 Specific //! ------------ //! - //! Some AVX+ instructions may require extra features for replacing registers - //! with memory operands, for example VPSLLDQ instruction only supports - //! 'reg/reg/imm' combination on AVX/AVX2 capable CPUs and requires AVX-512 for - //! 'reg/mem/imm' combination. - inline uint32_t rmFeature() const noexcept { return _rmFeature; } + //! Some AVX+ instructions may require extra features for replacing registers with memory operands, for example + //! VPSLLDQ instruction only supports `vpslldq reg, reg, imm` combination on AVX/AVX2 capable CPUs and requires + //! AVX-512 for `vpslldq reg, mem, imm` combination. + ASMJIT_INLINE_NODEBUG uint32_t rmFeature() const noexcept { return _rmFeature; } //! \} @@ -484,10 +739,10 @@ struct InstRWInfo { //! \{ //! Returns RW information of extra register operand (extraReg). - inline const OpRWInfo& extraReg() const noexcept { return _extraReg; } + ASMJIT_INLINE_NODEBUG const OpRWInfo& extraReg() const noexcept { return _extraReg; } //! Returns RW information of all instruction's operands. - inline const OpRWInfo* operands() const noexcept { return _operands; } + ASMJIT_INLINE_NODEBUG const OpRWInfo* operands() const noexcept { return _operands; } //! Returns RW information of the operand at the given `index`. inline const OpRWInfo& operand(size_t index) const noexcept { @@ -496,54 +751,48 @@ struct InstRWInfo { } //! Returns the number of operands this instruction has. - inline uint32_t opCount() const noexcept { return _opCount; } + ASMJIT_INLINE_NODEBUG uint32_t opCount() const noexcept { return _opCount; } //! \} }; -// ============================================================================ -// [asmjit::InstAPI] -// ============================================================================ - -//! Instruction API. -namespace InstAPI { - //! Validation flags that can be used with \ref InstAPI::validate(). -enum ValidationFlags : uint32_t { +enum class ValidationFlags : uint32_t { + //! No flags. + kNone = 0, //! Allow virtual registers in the instruction. - kValidationFlagVirtRegs = 0x01u + kEnableVirtRegs = 0x01u }; +ASMJIT_DEFINE_ENUM_FLAGS(ValidationFlags) + +//! Instruction API. +namespace InstAPI { #ifndef ASMJIT_NO_TEXT -//! Appends the name of the instruction specified by `instId` and `instOptions` -//! into the `output` string. +//! Appends the name of the instruction specified by `instId` and `instOptions` into the `output` string. //! -//! \note Instruction options would only affect instruction prefix & suffix, -//! other options would be ignored. If `instOptions` is zero then only raw -//! instruction name (without any additional text) will be appended. -ASMJIT_API Error instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept; - -//! Parses an instruction name in the given string `s`. Length is specified -//! by `len` argument, which can be `SIZE_MAX` if `s` is known to be null -//! terminated. +//! \note Instruction options would only affect instruction prefix & suffix, other options would be ignored. +//! If `instOptions` is zero then only raw instruction name (without any additional text) will be appended. +ASMJIT_API Error instIdToString(Arch arch, InstId instId, String& output) noexcept; + +//! Parses an instruction name in the given string `s`. Length is specified by `len` argument, which can be +//! `SIZE_MAX` if `s` is known to be null terminated. //! -//! Returns the parsed instruction id or \ref BaseInst::kIdNone if no such -//! instruction exists. -ASMJIT_API uint32_t stringToInstId(uint32_t arch, const char* s, size_t len) noexcept; +//! Returns the parsed instruction id or \ref BaseInst::kIdNone if no such instruction exists. +ASMJIT_API InstId stringToInstId(Arch arch, const char* s, size_t len) noexcept; #endif // !ASMJIT_NO_TEXT #ifndef ASMJIT_NO_VALIDATION -//! Validates the given instruction considering the validation `flags`, see -//! \ref ValidationFlags. -ASMJIT_API Error validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags = 0) noexcept; +//! Validates the given instruction considering the given `validationFlags`. +ASMJIT_API Error validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags = ValidationFlags::kNone) noexcept; #endif // !ASMJIT_NO_VALIDATION #ifndef ASMJIT_NO_INTROSPECTION //! Gets Read/Write information of the given instruction. -ASMJIT_API Error queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept; +ASMJIT_API Error queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept; //! Gets CPU features required by the given instruction. -ASMJIT_API Error queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept; +ASMJIT_API Error queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept; #endif // !ASMJIT_NO_INTROSPECTION } // {InstAPI} |