summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h')
-rw-r--r--3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h358
1 files changed, 172 insertions, 186 deletions
diff --git a/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h b/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h
index 164b26c1dea..94a76f04818 100644
--- a/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h
+++ b/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.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_X86OPCODE_P_H_INCLUDED
#define ASMJIT_X86_X86OPCODE_P_H_INCLUDED
@@ -32,85 +14,66 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
//! \addtogroup asmjit_x86
//! \{
-// ============================================================================
-// [asmjit::x86::Opcode]
-// ============================================================================
-
//! Helper class to store and manipulate X86 opcodes.
//!
-//! The first 8 least significant bits describe the opcode byte as defined in
-//! ISA manuals, all other bits describe other properties like prefixes, see
-//! `Opcode::Bits` for more information.
+//! The first 8 least significant bits describe the opcode byte as defined in ISA manuals, all other bits
+//! describe other properties like prefixes, see `Opcode::Bits` for more information.
struct Opcode {
uint32_t v;
//! Describes a meaning of all bits of AsmJit's 32-bit opcode value.
//!
- //! This schema is AsmJit specific and has been designed to allow encoding of
- //! all X86 instructions available. X86, MMX, and SSE+ instructions always use
- //! `MM` and `PP` fields, which are encoded to corresponding prefixes needed
- //! by X86 or SIMD instructions. AVX+ instructions embed `MMMMM` and `PP` fields
- //! in a VEX prefix, and AVX-512 instructions embed `MM` and `PP` in EVEX prefix.
+ //! This schema is AsmJit specific and has been designed to allow encoding of all X86 instructions available. X86,
+ //! MMX, and SSE+ instructions always use `MM` and `PP` fields, which are encoded to corresponding prefixes needed
+ //! by X86 or SIMD instructions. AVX+ instructions embed `MMMMM` and `PP` fields in a VEX prefix, and AVX-512
+ //! instructions embed `MM` and `PP` in EVEX prefix.
//!
- //! The instruction opcode definition uses 1 or 2 bytes as an opcode value. 1
- //! byte is needed by most of the instructions, 2 bytes are only used by legacy
- //! X87-FPU instructions. This means that a second byte is free to by used by
- //! instructions encoded by using VEX and/or EVEX prefix.
+ //! The instruction opcode definition uses 1 or 2 bytes as an opcode value. 1 byte is needed by most of the
+ //! instructions, 2 bytes are only used by legacy X87-FPU instructions. This means that a second byte is free to
+ //! by used by instructions encoded by using VEX and/or EVEX prefix.
//!
//! The fields description:
//!
- //! - `MM` field is used to encode prefixes needed by the instruction or as
- //! a part of VEX/EVEX prefix. Described as `mm` and `mmmmm` in instruction
- //! manuals.
+ //! - `MM` field is used to encode prefixes needed by the instruction or as a part of VEX/EVEX prefix. Described as
+ //! `mm` and `mmmmm` in instruction manuals.
//!
- //! NOTE: Since `MM` field is defined as `mmmmm` (5 bits), but only 2 least
- //! significant bits are used by VEX and EVEX prefixes, and additional 4th
- //! bit is used by XOP prefix, AsmJit uses the 3rd and 5th bit for it's own
- //! purposes. These bits will probably never be used in future encodings as
- //! AVX512 uses only `000mm` from `mmmmm`.
+ //! NOTE: Since `MM` field is defined as `mmmmm` (5 bits), but only 2 least significant bits are used by VEX and
+ //! EVEX prefixes, and additional 4th bit is used by XOP prefix, AsmJit uses the 3rd and 5th bit for it's own
+ //! purposes. These bits will probably never be used in future encodings as AVX512 uses only `000mm` from `mmmmm`.
//!
- //! - `PP` field is used to encode prefixes needed by the instruction or as a
- //! part of VEX/EVEX prefix. Described as `pp` in instruction manuals.
+ //! - `PP` field is used to encode prefixes needed by the instruction or as a part of VEX/EVEX prefix. Described as
+ //! `pp` in instruction manuals.
//!
- //! - `LL` field is used exclusively by AVX+ and AVX512+ instruction sets. It
- //! describes vector size, which is `L.128` for XMM register, `L.256` for
- //! for YMM register, and `L.512` for ZMM register. The `LL` field is omitted
- //! in case that instruction supports multiple vector lengths, however, if the
- //! instruction requires specific `L` value it must be specified as a part of
- //! the opcode.
+ //! - `LL` field is used exclusively by AVX+ and AVX512+ instruction sets. It describes vector size, which is `L.128`
+ //! for XMM register, `L.256` for for YMM register, and `L.512` for ZMM register. The `LL` field is omitted in case
+ //! that instruction supports multiple vector lengths, however, if the instruction requires specific `L` value it
+ //! must be specified as a part of the opcode.
//!
//! NOTE: `LL` having value `11` is not defined yet.
//!
- //! - `W` field is the most complicated. It was added by 64-bit architecture
- //! to promote default operation width (instructions that perform 32-bit
- //! operation by default require to override the width to 64-bit explicitly).
- //! There is nothing wrong on this, however, some instructions introduced
- //! implicit `W` override, for example a `cdqe` instruction is basically a
- //! `cwde` instruction with overridden `W` (set to 1). There are some others
- //! in the base X86 instruction set. More recent instruction sets started
- //! using `W` field more often:
+ //! - `W` field is the most complicated. It was added by 64-bit architecture to promote default operation width
+ //! (instructions that perform 32-bit operation by default require to override the width to 64-bit explicitly).
+ //! There is nothing wrong on this, however, some instructions introduced implicit `W` override, for example a
+ //! `cdqe` instruction is basically a `cwde` instruction with overridden `W` (set to 1). There are some others
+ //! in the base X86 instruction set. More recent instruction sets started using `W` field more often:
//!
- //! - AVX instructions started using `W` field as an extended opcode for FMA,
- //! GATHER, PERM, and other instructions. It also uses `W` field to override
- //! the default operation width in instructions like `vmovq`.
+ //! - AVX instructions started using `W` field as an extended opcode for FMA, GATHER, PERM, and other instructions.
+ //! It also uses `W` field to override the default operation width in instructions like `vmovq`.
//!
- //! - AVX-512 instructions started using `W` field as an extended opcode for
- //! all new instructions. This wouldn't have been an issue if the `W` field
- //! of AVX-512 have matched AVX, but this is not always the case.
+ //! - AVX-512 instructions started using `W` field as an extended opcode for all new instructions. This wouldn't
+ //! have been an issue if the `W` field of AVX-512 have matched AVX, but this is not always the case.
//!
//! - `O` field is an extended opcode field (3 bits) embedded in ModR/M BYTE.
//!
- //! - `CDSHL` and `CDTT` fields describe 'compressed-displacement'. `CDSHL` is
- //! defined for each instruction that is AVX-512 encodable (EVEX) and contains
- //! a base N shift (base shift to perform the calculation). The `CDTT` field
- //! is derived from instruction specification and describes additional shift
- //! to calculate the final `CDSHL` that will be used in SIB byte.
+ //! - `CDSHL` and `CDTT` fields describe 'compressed-displacement'. `CDSHL` is defined for each instruction that is
+ //! AVX-512 encodable (EVEX) and contains a base N shift (base shift to perform the calculation). The `CDTT` field
+ //! is derived from instruction specification and describes additional shift to calculate the final `CDSHL` that
+ //! will be used in SIB byte.
//!
- //! \note Don't reorder any fields here, the shifts and masks were defined
- //! carefully to make encoding of X86 instructions fast, especially to construct
- //! REX, VEX, and EVEX prefixes in the most efficient way. Changing values defined
- //! by these enums many cause AsmJit to emit invalid binary representations of
- //! instructions passed to `x86::Assembler::_emit`.
+ //! \note Don't reorder any fields here, the shifts and masks were defined carefully to make encoding of X86
+ //! instructions fast, especially to construct REX, VEX, and EVEX prefixes in the most efficient way. Changing
+ //! values defined by these enums many cause AsmJit to emit invalid binary representations of instructions passed to
+ //! `x86::Assembler::_emit`.
enum Bits : uint32_t {
// MM & VEX & EVEX & XOP
// ---------------------
@@ -119,22 +82,15 @@ struct Opcode {
// * Part of a legacy opcode (prefixes emitted before the main opcode byte).
// * `MMMMM` field in VEX|EVEX|XOP instruction.
//
- // AVX reserves 5 bits for `MMMMM` field, however AVX instructions only use
- // 2 bits and XOP 3 bits. AVX-512 shrinks `MMMMM` field into `MM` so it's
- // safe to assume that bits [4:2] of `MM` field won't be used in future
- // extensions, which will most probably use EVEX encoding. AsmJit divides
- // MM field into this layout:
+ // AVX reserves 5 bits for `MMMMM` field, however AVX instructions only use 2 bits and XOP 3 bits. AVX-512 shrinks
+ // `MMMMM` field into `MMM` so it's safe to use [4:3] bits of `MMMMM` field for internal payload.
+ //
+ // AsmJit divides MMMMM field into this layout:
//
- // [1:0] - Used to describe 0F, 0F38 and 0F3A legacy prefix bytes and
- // 2 bits of MM field.
- // [2] - Used to force 3-BYTE VEX prefix, but then cleared to zero before
- // the prefix is emitted. This bit is not used by any instruction
- // so it can be used for any purpose by AsmJit. Also, this bit is
- // used as an extension to `MM` field describing 0F|0F38|0F3A to also
- // describe 0F01 as used by some legacy instructions (instructions
- // not using VEX/EVEX prefix).
- // [3] - Required by XOP instructions, so we use this bit also to indicate
- // that this is a XOP opcode.
+ // [2:0] - Used to describe 0F, 0F38 and 0F3A legacy prefix bytes and 3 bits of MMMMM field for XOP/AVX/AVX512.
+ // [3] - Required by XOP instructions, so we use this bit also to indicate that this is a XOP opcode.
+ // [4] - Used to force EVEX prefix - this bit is not used by any X86 instruction yet, so AsmJit uses it to
+ // describe EVEX only instructions or sets its bit when user uses InstOptions::kX86_Evex to force EVEX.
kMM_Shift = 8,
kMM_Mask = 0x1Fu << kMM_Shift,
kMM_00 = 0x00u << kMM_Shift,
@@ -143,11 +99,12 @@ struct Opcode {
kMM_0F3A = 0x03u << kMM_Shift, // Described also as XOP.M3 in AMD manuals.
kMM_0F01 = 0x04u << kMM_Shift, // AsmJit way to describe 0F01 (never VEX/EVEX).
- // `XOP` field is only used to force XOP prefix instead of VEX3 prefix. We
- // know that only XOP encoding uses bit 0b1000 of MM field and that no VEX
- // and EVEX instruction uses such bit, so we can use this bit to force XOP
- // prefix to be emitted instead of VEX3 prefix. See `x86VEXPrefix` defined
- // in `x86assembler.cpp`.
+ kMM_MAP5 = 0x05u << kMM_Shift, // EVEX.MAP5.
+ kMM_MAP6 = 0x06u << kMM_Shift, // EVEX.MAP6.
+
+ // `XOP` field is only used to force XOP prefix instead of VEX3 prefix. We know XOP encodings always use 0b1000
+ // bit of MM field and that no VEX and EVEX instruction use such bit yet, so we can use this bit to force XOP
+ // prefix to be emitted instead of VEX3 prefix. See `x86VEXPrefix` defined in `x86assembler.cpp`.
kMM_XOP08 = 0x08u << kMM_Shift, // XOP.M8.
kMM_XOP09 = 0x09u << kMM_Shift, // XOP.M9.
kMM_XOP0A = 0x0Au << kMM_Shift, // XOP.MA.
@@ -155,21 +112,17 @@ struct Opcode {
kMM_IsXOP_Shift= kMM_Shift + 3,
kMM_IsXOP = kMM_XOP08,
- // NOTE: Force VEX3 allows to force to emit VEX3 instead of VEX2 in some
- // cases (similar to forcing REX prefix). Force EVEX will force emitting
- // EVEX prefix instead of VEX2|VEX3. EVEX-only instructions will have
- // ForceEvex always set, however. instructions that can be encoded by
- // either VEX or EVEX prefix should not have ForceEvex set.
-
- kMM_ForceVex3 = 0x04u << kMM_Shift, // Force 3-BYTE VEX prefix.
+ // NOTE: Force VEX3 allows to force to emit VEX3 instead of VEX2 in some cases (similar to forcing REX prefix).
+ // Force EVEX will force emitting EVEX prefix instead of VEX2|VEX3. EVEX-only instructions will have ForceEvex
+ // always set, however. instructions that can be encoded by either VEX or EVEX prefix should not have ForceEvex
+ // set.
kMM_ForceEvex = 0x10u << kMM_Shift, // Force 4-BYTE EVEX prefix.
// FPU_2B - Second-Byte of the Opcode used by FPU
// ----------------------------------------------
//
- // Second byte opcode. This BYTE is ONLY used by FPU instructions and
- // collides with 3 bits from `MM` and 5 bits from 'CDSHL' and 'CDTT'.
- // It's fine as FPU and AVX512 flags are never used at the same time.
+ // Second byte opcode. This BYTE is ONLY used by FPU instructions and collides with 3 bits from `MM` and 5 bits
+ // from 'CDSHL' and 'CDTT'. It's fine as FPU and AVX512 flags are never used at the same time.
kFPU_2B_Shift = 10,
kFPU_2B_Mask = 0xFF << kFPU_2B_Shift,
@@ -203,8 +156,8 @@ struct Opcode {
// Compressed displacement tuple-type (specific to AsmJit).
//
- // Since we store the base offset independently of CDTT we can simplify the
- // number of 'TUPLE_TYPE' groups significantly and just handle special cases.
+ // Since we store the base offset independently of CDTT we can simplify the number of 'TUPLE_TYPE' groups
+ // significantly and just handle special cases.
kCDTT_Shift = 16,
kCDTT_Mask = 0x3u << kCDTT_Shift,
kCDTT_None = 0x0u << kCDTT_Shift, // Does nothing.
@@ -216,10 +169,12 @@ struct Opcode {
kCDTT__ = kCDTT_None,
kCDTT_FV = kCDTT_ByLL,
kCDTT_HV = kCDTT_ByLL,
+ kCDTT_QV = kCDTT_ByLL,
kCDTT_FVM = kCDTT_ByLL,
kCDTT_T1S = kCDTT_None,
kCDTT_T1F = kCDTT_None,
kCDTT_T1_4X = kCDTT_None,
+ kCDTT_T4X = kCDTT_None, // Alias to have only 3 letters.
kCDTT_T2 = kCDTT_None,
kCDTT_T4 = kCDTT_None,
kCDTT_T8 = kCDTT_None,
@@ -228,37 +183,53 @@ struct Opcode {
kCDTT_OVM = kCDTT_ByLL,
kCDTT_128 = kCDTT_None,
- kCDTT_T4X = kCDTT_T1_4X, // Alias to have only 3 letters.
+ // `O` Field in ModR/M (??:xxx:???)
+ // --------------------------------
- // `O` Field in MorR/M
- // -------------------
+ kModO_Shift = 18,
+ kModO_Mask = 0x7u << kModO_Shift,
- kO_Shift = 18,
- kO_Mask = 0x7u << kO_Shift,
+ kModO__ = 0x0u,
+ kModO_0 = 0x0u << kModO_Shift,
+ kModO_1 = 0x1u << kModO_Shift,
+ kModO_2 = 0x2u << kModO_Shift,
+ kModO_3 = 0x3u << kModO_Shift,
+ kModO_4 = 0x4u << kModO_Shift,
+ kModO_5 = 0x5u << kModO_Shift,
+ kModO_6 = 0x6u << kModO_Shift,
+ kModO_7 = 0x7u << kModO_Shift,
- kO__ = 0x0u,
- kO_0 = 0x0u << kO_Shift,
- kO_1 = 0x1u << kO_Shift,
- kO_2 = 0x2u << kO_Shift,
- kO_3 = 0x3u << kO_Shift,
- kO_4 = 0x4u << kO_Shift,
- kO_5 = 0x5u << kO_Shift,
- kO_6 = 0x6u << kO_Shift,
- kO_7 = 0x7u << kO_Shift,
+ // `RM` Field in ModR/M (??:???:xxx)
+ // ---------------------------------
+ //
+ // Second data field used by ModR/M byte. This is only used by few instructions that use OPCODE+MOD/RM where both
+ // values in Mod/RM are part of the opcode.
+
+ kModRM_Shift = 13,
+ kModRM_Mask = 0x7u << kModRM_Shift,
+
+ kModRM__ = 0x0u,
+ kModRM_0 = 0x0u << kModRM_Shift,
+ kModRM_1 = 0x1u << kModRM_Shift,
+ kModRM_2 = 0x2u << kModRM_Shift,
+ kModRM_3 = 0x3u << kModRM_Shift,
+ kModRM_4 = 0x4u << kModRM_Shift,
+ kModRM_5 = 0x5u << kModRM_Shift,
+ kModRM_6 = 0x6u << kModRM_Shift,
+ kModRM_7 = 0x7u << kModRM_Shift,
// `PP` Field
// ----------
//
- // These fields are stored deliberately right after each other as it makes
- // it easier to construct VEX prefix from the opcode value stored in the
- // instruction database.
+ // These fields are stored deliberately right after each other as it makes it easier to construct VEX prefix from
+ // the opcode value stored in the instruction database.
//
// Two meanings:
// * "PP" field in AVX/XOP/AVX-512 instruction.
// * Mandatory Prefix in legacy encoding.
//
- // AVX reserves 2 bits for `PP` field, but AsmJit extends the storage by 1
- // more bit that is used to emit 9B prefix for some X87-FPU instructions.
+ // AVX reserves 2 bits for `PP` field, but AsmJit extends the storage by 1 more bit that is used to emit 9B prefix
+ // for some X87-FPU instructions.
kPP_Shift = 21,
kPP_VEXMask = 0x03u << kPP_Shift, // PP field mask used by VEX/EVEX.
@@ -273,9 +244,8 @@ struct Opcode {
// REX|VEX|EVEX B|X|R|W Bits
// -------------------------
//
- // NOTE: REX.[B|X|R] are never stored within the opcode itself, they are
- // reserved by AsmJit are are added dynamically to the opcode to represent
- // [REX|VEX|EVEX].[B|X|R] bits. REX.W can be stored in DB as it's sometimes
+ // NOTE: REX.[B|X|R] are never stored within the opcode itself, they are reserved by AsmJit are are added
+ // dynamically to the opcode to represent [REX|VEX|EVEX].[B|X|R] bits. REX.W can be stored in DB as it's sometimes
// part of the opcode itself.
// These must be binary compatible with instruction options.
@@ -310,11 +280,9 @@ struct Opcode {
// `L` or `LL` field in AVX/XOP/AVX-512
// ------------------------------------
//
- // VEX/XOP prefix can only use the first bit `L.128` or `L.256`. EVEX prefix
- // prefix makes it possible to use also `L.512`.
- //
- // If the instruction set manual describes an instruction by `LIG` it means
- // that the `L` field is ignored and AsmJit defaults to `0` in such case.
+ // VEX/XOP prefix can only use the first bit `L.128` or `L.256`. EVEX prefix prefix makes it possible to use also
+ // `L.512`. If the instruction set manual describes an instruction by `LIG` it means that the `L` field is ignored
+ // and AsmJit defaults to `0` in such case.
kLL_Shift = 29,
kLL_Mask = 0x3u << kLL_Shift,
@@ -333,20 +301,31 @@ struct Opcode {
k000F00 = kPP_00 | kMM_0F, // '0F'
k000F01 = kPP_00 | kMM_0F01, // '0F01'
k000F0F = kPP_00 | kMM_0F, // '0F0F' - 3DNOW, equal to 0x0F, must have special encoding to take effect.
- k000F38 = kPP_00 | kMM_0F38, // '0F38'
- k000F3A = kPP_00 | kMM_0F3A, // '0F3A'
+ k000F38 = kPP_00 | kMM_0F38, // 'NP.0F38'
+ k000F3A = kPP_00 | kMM_0F3A, // 'NP.0F3A'
+ k00MAP5 = kPP_00 | kMM_MAP5, // 'NP.MAP5'
+ k00MAP6 = kPP_00 | kMM_MAP6, // 'NP.MAP5'
k660000 = kPP_66 | kMM_00, // '66'
- k660F00 = kPP_66 | kMM_0F, // '660F'
- k660F38 = kPP_66 | kMM_0F38, // '660F38'
- k660F3A = kPP_66 | kMM_0F3A, // '660F3A'
+ k660F00 = kPP_66 | kMM_0F, // '66.0F'
+ k660F01 = kPP_66 | kMM_0F01, // '66.0F01'
+ k660F38 = kPP_66 | kMM_0F38, // '66.0F38'
+ k660F3A = kPP_66 | kMM_0F3A, // '66.0F3A'
+ k66MAP5 = kPP_66 | kMM_MAP5, // '66.MAP5'
+ k66MAP6 = kPP_66 | kMM_MAP6, // '66.MAP5'
kF20000 = kPP_F2 | kMM_00, // 'F2'
- kF20F00 = kPP_F2 | kMM_0F, // 'F20F'
- kF20F38 = kPP_F2 | kMM_0F38, // 'F20F38'
- kF20F3A = kPP_F2 | kMM_0F3A, // 'F20F3A'
+ kF20F00 = kPP_F2 | kMM_0F, // 'F2.0F'
+ kF20F01 = kPP_F2 | kMM_0F01, // 'F2.0F01'
+ kF20F38 = kPP_F2 | kMM_0F38, // 'F2.0F38'
+ kF20F3A = kPP_F2 | kMM_0F3A, // 'F2.0F3A'
+ kF2MAP5 = kPP_F2 | kMM_MAP5, // 'F2.MAP5'
+ kF2MAP6 = kPP_F2 | kMM_MAP6, // 'F2.MAP5'
kF30000 = kPP_F3 | kMM_00, // 'F3'
- kF30F00 = kPP_F3 | kMM_0F, // 'F30F'
- kF30F38 = kPP_F3 | kMM_0F38, // 'F30F38'
- kF30F3A = kPP_F3 | kMM_0F3A, // 'F30F3A'
+ kF30F00 = kPP_F3 | kMM_0F, // 'F3.0F'
+ kF30F01 = kPP_F3 | kMM_0F01, // 'F3.0F01'
+ kF30F38 = kPP_F3 | kMM_0F38, // 'F3.0F38'
+ kF30F3A = kPP_F3 | kMM_0F3A, // 'F3.0F3A'
+ kF3MAP5 = kPP_F3 | kMM_MAP5, // 'F3.MAP5'
+ kF3MAP6 = kPP_F3 | kMM_MAP6, // 'F3.MAP5'
kFPU_00 = kPP_00 | kMM_00, // '__' (FPU)
kFPU_9B = kPP_9B | kMM_00, // '9B' (FPU)
kXOP_M8 = kPP_00 | kMM_XOP08, // 'M8' (XOP)
@@ -354,31 +333,30 @@ struct Opcode {
kXOP_MA = kPP_00 | kMM_XOP0A // 'MA' (XOP)
};
- // --------------------------------------------------------------------------
- // [Opcode Builder]
- // --------------------------------------------------------------------------
+ // Opcode Builder
+ // --------------
- ASMJIT_INLINE uint32_t get() const noexcept { return v; }
+ inline uint32_t get() const noexcept { return v; }
- ASMJIT_INLINE bool hasW() const noexcept { return (v & kW) != 0; }
- ASMJIT_INLINE bool has66h() const noexcept { return (v & kPP_66) != 0; }
+ inline bool hasW() const noexcept { return (v & kW) != 0; }
+ inline bool has66h() const noexcept { return (v & kPP_66) != 0; }
- ASMJIT_INLINE Opcode& add(uint32_t x) noexcept { return operator+=(x); }
+ inline Opcode& add(uint32_t x) noexcept { return operator+=(x); }
- ASMJIT_INLINE Opcode& add66h() noexcept { return operator|=(kPP_66); }
+ inline Opcode& add66h() noexcept { return operator|=(kPP_66); }
template<typename T>
- ASMJIT_INLINE Opcode& add66hIf(T exp) noexcept { return operator|=(uint32_t(exp) << kPP_Shift); }
+ inline Opcode& add66hIf(T exp) noexcept { return operator|=(uint32_t(exp) << kPP_Shift); }
template<typename T>
- ASMJIT_INLINE Opcode& add66hBySize(T size) noexcept { return add66hIf(size == 2); }
+ inline Opcode& add66hBySize(T size) noexcept { return add66hIf(size == 2); }
- ASMJIT_INLINE Opcode& addW() noexcept { return operator|=(kW); }
+ inline Opcode& addW() noexcept { return operator|=(kW); }
template<typename T>
- ASMJIT_INLINE Opcode& addWIf(T exp) noexcept { return operator|=(uint32_t(exp) << kW_Shift); }
+ inline Opcode& addWIf(T exp) noexcept { return operator|=(uint32_t(exp) << kW_Shift); }
template<typename T>
- ASMJIT_INLINE Opcode& addWBySize(T size) noexcept { return addWIf(size == 8); }
+ inline Opcode& addWBySize(T size) noexcept { return addWIf(size == 8); }
template<typename T>
- ASMJIT_INLINE Opcode& addPrefixBySize(T size) noexcept {
+ inline Opcode& addPrefixBySize(T size) noexcept {
static const uint32_t mask[16] = {
0, // #0
0, // #1 -> nothing (already handled or not possible)
@@ -394,7 +372,7 @@ struct Opcode {
}
template<typename T>
- ASMJIT_INLINE Opcode& addArithBySize(T size) noexcept {
+ inline Opcode& addArithBySize(T size) noexcept {
static const uint32_t mask[16] = {
0, // #0
0, // #1 -> nothing
@@ -409,37 +387,45 @@ struct Opcode {
return operator|=(mask[size & 0xF]);
}
- //! Extract `O` field from the opcode.
- ASMJIT_INLINE uint32_t extractO() const noexcept {
- return (v >> kO_Shift) & 0x07;
+ inline Opcode& forceEvex() noexcept { return operator|=(kMM_ForceEvex); }
+ template<typename T>
+ inline Opcode& forceEvexIf(T exp) noexcept { return operator|=(uint32_t(exp) << Support::ConstCTZ<uint32_t(kMM_ForceEvex)>::value); }
+
+ //! Extract `O` field (R) from the opcode (specified as /0..7 in instruction manuals).
+ inline uint32_t extractModO() const noexcept {
+ return (v >> kModO_Shift) & 0x07;
+ }
+
+ //! Extract `RM` field (RM) from the opcode (usually specified as another opcode value).
+ inline uint32_t extractModRM() const noexcept {
+ return (v >> kModRM_Shift) & 0x07;
}
//! Extract `REX` prefix from opcode combined with `options`.
- ASMJIT_INLINE uint32_t extractRex(uint32_t options) const noexcept {
- // kREX was designed in a way that when shifted there will be no bytes
- // set except REX.[B|X|R|W]. The returned value forms a real REX prefix byte.
- // This case should be unit-tested as well.
- return (v | options) >> kREX_Shift;
+ inline uint32_t extractRex(InstOptions options) const noexcept {
+ // kREX was designed in a way that when shifted there will be no bytes set except REX.[B|X|R|W].
+ // The returned value forms a real REX prefix byte. This case should be unit-tested as well.
+ return (v | uint32_t(options)) >> kREX_Shift;
}
- ASMJIT_INLINE uint32_t extractLLMM(uint32_t options) const noexcept {
- uint32_t x = v & (kLL_Mask | kMM_Mask);
- uint32_t y = options & (Inst::kOptionVex3 | Inst::kOptionEvex);
- return (x | y) >> kMM_Shift;
+ inline uint32_t extractLLMMMMM(InstOptions options) const noexcept {
+ uint32_t llMmmmm = uint32_t(v & (kLL_Mask | kMM_Mask));
+ uint32_t vexEvex = uint32_t(options & InstOptions::kX86_Evex);
+ return (llMmmmm | vexEvex) >> kMM_Shift;
}
- ASMJIT_INLINE Opcode& operator=(uint32_t x) noexcept { v = x; return *this; }
- ASMJIT_INLINE Opcode& operator+=(uint32_t x) noexcept { v += x; return *this; }
- ASMJIT_INLINE Opcode& operator-=(uint32_t x) noexcept { v -= x; return *this; }
- ASMJIT_INLINE Opcode& operator&=(uint32_t x) noexcept { v &= x; return *this; }
- ASMJIT_INLINE Opcode& operator|=(uint32_t x) noexcept { v |= x; return *this; }
- ASMJIT_INLINE Opcode& operator^=(uint32_t x) noexcept { v ^= x; return *this; }
-
- ASMJIT_INLINE uint32_t operator&(uint32_t x) const noexcept { return v & x; }
- ASMJIT_INLINE uint32_t operator|(uint32_t x) const noexcept { return v | x; }
- ASMJIT_INLINE uint32_t operator^(uint32_t x) const noexcept { return v ^ x; }
- ASMJIT_INLINE uint32_t operator<<(uint32_t x) const noexcept { return v << x; }
- ASMJIT_INLINE uint32_t operator>>(uint32_t x) const noexcept { return v >> x; }
+ inline Opcode& operator=(uint32_t x) noexcept { v = x; return *this; }
+ inline Opcode& operator+=(uint32_t x) noexcept { v += x; return *this; }
+ inline Opcode& operator-=(uint32_t x) noexcept { v -= x; return *this; }
+ inline Opcode& operator&=(uint32_t x) noexcept { v &= x; return *this; }
+ inline Opcode& operator|=(uint32_t x) noexcept { v |= x; return *this; }
+ inline Opcode& operator^=(uint32_t x) noexcept { v ^= x; return *this; }
+
+ inline uint32_t operator&(uint32_t x) const noexcept { return v & x; }
+ inline uint32_t operator|(uint32_t x) const noexcept { return v | x; }
+ inline uint32_t operator^(uint32_t x) const noexcept { return v ^ x; }
+ inline uint32_t operator<<(uint32_t x) const noexcept { return v << x; }
+ inline uint32_t operator>>(uint32_t x) const noexcept { return v >> x; }
};
//! \}