LCOV - code coverage report
Current view: top level - asmjit - x86opcode_p.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 14 20 70.0 %
Date: 2026-11-05 10:19:06 Functions: 0 0 -

          Line data    Source code
       1             : #ifdef __PLUMED_HAS_ASMJIT
       2             : // This file is part of AsmJit project <https://asmjit.com>
       3             : //
       4             : // See asmjit.h or LICENSE.md for license and copyright information
       5             : // SPDX-License-Identifier: Zlib
       6             : 
       7             : #ifndef ASMJIT_X86_X86OPCODE_P_H_INCLUDED
       8             : #define ASMJIT_X86_X86OPCODE_P_H_INCLUDED
       9             : 
      10             : #include "x86globals.h"
      11             : 
      12             : ASMJIT_BEGIN_SUB_NAMESPACE(x86)
      13             : 
      14             : //! \cond INTERNAL
      15             : //! \addtogroup asmjit_x86
      16             : //! \{
      17             : 
      18             : //! Helper class to store and manipulate X86 opcodes.
      19             : //!
      20             : //! The first 8 least significant bits describe the opcode byte as defined in ISA manuals, all other bits
      21             : //! describe other properties like prefixes, see `Opcode::Bits` for more information.
      22             : struct Opcode {
      23             :   uint32_t v;
      24             : 
      25             :   //! Describes a meaning of all bits of AsmJit's 32-bit opcode value.
      26             :   //!
      27             :   //! This schema is AsmJit specific and has been designed to allow encoding of all X86 instructions available. X86,
      28             :   //! MMX, and SSE+ instructions always use `MM` and `PP` fields, which are encoded to corresponding prefixes needed
      29             :   //! by X86 or SIMD instructions. AVX+ instructions embed `MMMMM` and `PP` fields in a VEX prefix, and AVX-512
      30             :   //! instructions embed `MM` and `PP` in EVEX prefix.
      31             :   //!
      32             :   //! The instruction opcode definition uses 1 or 2 bytes as an opcode value. 1 byte is needed by most of the
      33             :   //! instructions, 2 bytes are only used by legacy X87-FPU instructions. This means that a second byte is free to
      34             :   //! by used by instructions encoded by using VEX and/or EVEX prefix.
      35             :   //!
      36             :   //! The fields description:
      37             :   //!
      38             :   //! - `MM` field is used to encode prefixes needed by the instruction or as a part of VEX/EVEX prefix. Described as
      39             :   //!   `mm` and `mmmmm` in instruction manuals.
      40             :   //!
      41             :   //!   NOTE: Since `MM` field is defined as `mmmmm` (5 bits), but only 2 least significant bits are used by VEX and
      42             :   //!   EVEX prefixes, and additional 4th bit is used by XOP prefix, AsmJit uses the 3rd and 5th bit for it's own
      43             :   //!   purposes. These bits will probably never be used in future encodings as AVX512 uses only `000mm` from `mmmmm`.
      44             :   //!
      45             :   //! - `PP` field is used to encode prefixes needed by the instruction or as a part of VEX/EVEX prefix. Described as
      46             :   //!   `pp` in instruction manuals.
      47             :   //!
      48             :   //! - `LL` field is used exclusively by AVX+ and AVX512+ instruction sets. It describes vector size, which is `L.128`
      49             :   //!   for XMM register, `L.256` for for YMM register, and `L.512` for ZMM register. The `LL` field is omitted in case
      50             :   //!   that instruction supports multiple vector lengths, however, if the instruction requires specific `L` value it
      51             :   //!   must be specified as a part of the opcode.
      52             :   //!
      53             :   //!   NOTE: `LL` having value `11` is not defined yet.
      54             :   //!
      55             :   //! - `W` field is the most complicated. It was added by 64-bit architecture to promote default operation width
      56             :   //!   (instructions that perform 32-bit operation by default require to override the width to 64-bit explicitly).
      57             :   //!   There is nothing wrong on this, however, some instructions introduced implicit `W` override, for example a
      58             :   //!   `cdqe` instruction is basically a `cwde` instruction with overridden `W` (set to 1). There are some others
      59             :   //!   in the base X86 instruction set. More recent instruction sets started using `W` field more often:
      60             :   //!
      61             :   //!   - AVX instructions started using `W` field as an extended opcode for FMA, GATHER, PERM, and other instructions.
      62             :   //!     It also uses `W` field to override the default operation width in instructions like `vmovq`.
      63             :   //!
      64             :   //!   - AVX-512 instructions started using `W` field as an extended opcode for all new instructions. This wouldn't
      65             :   //!     have been an issue if the `W` field of AVX-512 have matched AVX, but this is not always the case.
      66             :   //!
      67             :   //! - `O` field is an extended opcode field (3 bits) embedded in ModR/M BYTE.
      68             :   //!
      69             :   //! - `CDSHL` and `CDTT` fields describe 'compressed-displacement'. `CDSHL` is defined for each instruction that is
      70             :   //!   AVX-512 encodable (EVEX) and contains a base N shift (base shift to perform the calculation). The `CDTT` field
      71             :   //!   is derived from instruction specification and describes additional shift to calculate the final `CDSHL` that
      72             :   //!   will be used in SIB byte.
      73             :   //!
      74             :   //! \note Don't reorder any fields here, the shifts and masks were defined carefully to make encoding of X86
      75             :   //! instructions fast, especially to construct REX, VEX, and EVEX prefixes in the most efficient way. Changing
      76             :   //! values defined by these enums many cause AsmJit to emit invalid binary representations of instructions passed to
      77             :   //! `x86::Assembler::_emit`.
      78             :   enum Bits : uint32_t {
      79             :     // MM & VEX & EVEX & XOP
      80             :     // ---------------------
      81             :     //
      82             :     // Two meanings:
      83             :     //  * Part of a legacy opcode (prefixes emitted before the main opcode byte).
      84             :     //  * `MMMMM` field in VEX|EVEX|XOP instruction.
      85             :     //
      86             :     // AVX reserves 5 bits for `MMMMM` field, however AVX instructions only use 2 bits and XOP 3 bits. AVX-512 shrinks
      87             :     // `MMMMM` field into `MMM` so it's safe to use [4:3] bits of `MMMMM` field for internal payload.
      88             :     //
      89             :     // AsmJit divides MMMMM field into this layout:
      90             :     //
      91             :     // [2:0] - Used to describe 0F, 0F38 and 0F3A legacy prefix bytes and 3 bits of MMMMM field for XOP/AVX/AVX512.
      92             :     // [3]   - Required by XOP instructions, so we use this bit also to indicate that this is a XOP opcode.
      93             :     // [4]   - Used to force EVEX prefix - this bit is not used by any X86 instruction yet, so AsmJit uses it to
      94             :     //         describe EVEX only instructions or sets its bit when user uses InstOptions::kX86_Evex to force EVEX.
      95             :     kMM_Shift      = 8,
      96             :     kMM_Mask       = 0x1Fu << kMM_Shift,
      97             :     kMM_00         = 0x00u << kMM_Shift,
      98             :     kMM_0F         = 0x01u << kMM_Shift,
      99             :     kMM_0F38       = 0x02u << kMM_Shift,
     100             :     kMM_0F3A       = 0x03u << kMM_Shift,   // Described also as XOP.M3 in AMD manuals.
     101             :     kMM_0F01       = 0x04u << kMM_Shift,   // AsmJit way to describe 0F01 (never VEX/EVEX).
     102             : 
     103             :     kMM_MAP5       = 0x05u << kMM_Shift,   // EVEX.MAP5.
     104             :     kMM_MAP6       = 0x06u << kMM_Shift,   // EVEX.MAP6.
     105             : 
     106             :     // `XOP` field is only used to force XOP prefix instead of VEX3 prefix. We know XOP encodings always use 0b1000
     107             :     // bit of MM field and that no VEX and EVEX instruction use such bit yet, so we can use this bit to force XOP
     108             :     // prefix to be emitted instead of VEX3 prefix. See `x86VEXPrefix` defined in `x86assembler.cpp`.
     109             :     kMM_XOP08      = 0x08u << kMM_Shift,   // XOP.M8.
     110             :     kMM_XOP09      = 0x09u << kMM_Shift,   // XOP.M9.
     111             :     kMM_XOP0A      = 0x0Au << kMM_Shift,   // XOP.MA.
     112             : 
     113             :     kMM_IsXOP_Shift= kMM_Shift + 3,
     114             :     kMM_IsXOP      = kMM_XOP08,
     115             : 
     116             :     // NOTE: Force VEX3 allows to force to emit VEX3 instead of VEX2 in some cases (similar to forcing REX prefix).
     117             :     // Force EVEX will force emitting EVEX prefix instead of VEX2|VEX3. EVEX-only instructions will have ForceEvex
     118             :     // always set, however. instructions that can be encoded by either VEX or EVEX prefix should not have ForceEvex
     119             :     // set.
     120             :     kMM_ForceEvex  = 0x10u << kMM_Shift,   // Force 4-BYTE EVEX prefix.
     121             : 
     122             :     // FPU_2B - Second-Byte of the Opcode used by FPU
     123             :     // ----------------------------------------------
     124             :     //
     125             :     // Second byte opcode. This BYTE is ONLY used by FPU instructions and collides with 3 bits from `MM` and 5 bits
     126             :     // from 'CDSHL' and 'CDTT'. It's fine as FPU and AVX512 flags are never used at the same time.
     127             :     kFPU_2B_Shift  = 10,
     128             :     kFPU_2B_Mask   = 0xFF << kFPU_2B_Shift,
     129             : 
     130             :     // CDSHL & CDTT
     131             :     // ------------
     132             :     //
     133             :     // Compressed displacement bits.
     134             :     //
     135             :     // Each opcode defines the base size (N) shift:
     136             :     //   [0]: BYTE  (1 byte).
     137             :     //   [1]: WORD  (2 bytes).
     138             :     //   [2]: DWORD (4 bytes - float/int32).
     139             :     //   [3]: QWORD (8 bytes - double/int64).
     140             :     //   [4]: OWORD (16 bytes - used by FV|FVM|M128).
     141             :     //
     142             :     // Which is then scaled by the instruction's TT (TupleType) into possible:
     143             :     //   [5]: YWORD (32 bytes)
     144             :     //   [6]: ZWORD (64 bytes)
     145             :     //
     146             :     // These bits are then adjusted before calling EmitModSib or EmitModVSib.
     147             :     kCDSHL_Shift   = 13,
     148             :     kCDSHL_Mask    = 0x7u << kCDSHL_Shift,
     149             : 
     150             :     kCDSHL__       = 0x0u << kCDSHL_Shift, // Base element size not used.
     151             :     kCDSHL_0       = 0x0u << kCDSHL_Shift, // N << 0.
     152             :     kCDSHL_1       = 0x1u << kCDSHL_Shift, // N << 1.
     153             :     kCDSHL_2       = 0x2u << kCDSHL_Shift, // N << 2.
     154             :     kCDSHL_3       = 0x3u << kCDSHL_Shift, // N << 3.
     155             :     kCDSHL_4       = 0x4u << kCDSHL_Shift, // N << 4.
     156             :     kCDSHL_5       = 0x5u << kCDSHL_Shift, // N << 5.
     157             : 
     158             :     // Compressed displacement tuple-type (specific to AsmJit).
     159             :     //
     160             :     // Since we store the base offset independently of CDTT we can simplify the number of 'TUPLE_TYPE' groups
     161             :     // significantly and just handle special cases.
     162             :     kCDTT_Shift    = 16,
     163             :     kCDTT_Mask     = 0x3u << kCDTT_Shift,
     164             :     kCDTT_None     = 0x0u << kCDTT_Shift,  // Does nothing.
     165             :     kCDTT_ByLL     = 0x1u << kCDTT_Shift,  // Scales by LL (1x 2x 4x).
     166             :     kCDTT_T1W      = 0x2u << kCDTT_Shift,  // Used to add 'W' to the shift.
     167             :     kCDTT_DUP      = 0x3u << kCDTT_Shift,  // Special 'VMOVDDUP' case.
     168             : 
     169             :     // Aliases that match names used in instruction manuals.
     170             :     kCDTT__        = kCDTT_None,
     171             :     kCDTT_FV       = kCDTT_ByLL,
     172             :     kCDTT_HV       = kCDTT_ByLL,
     173             :     kCDTT_QV       = kCDTT_ByLL,
     174             :     kCDTT_FVM      = kCDTT_ByLL,
     175             :     kCDTT_T1S      = kCDTT_None,
     176             :     kCDTT_T1F      = kCDTT_None,
     177             :     kCDTT_T1_4X    = kCDTT_None,
     178             :     kCDTT_T4X      = kCDTT_None,           // Alias to have only 3 letters.
     179             :     kCDTT_T2       = kCDTT_None,
     180             :     kCDTT_T4       = kCDTT_None,
     181             :     kCDTT_T8       = kCDTT_None,
     182             :     kCDTT_HVM      = kCDTT_ByLL,
     183             :     kCDTT_QVM      = kCDTT_ByLL,
     184             :     kCDTT_OVM      = kCDTT_ByLL,
     185             :     kCDTT_128      = kCDTT_None,
     186             : 
     187             :     // `O` Field in ModR/M (??:xxx:???)
     188             :     // --------------------------------
     189             : 
     190             :     kModO_Shift    = 18,
     191             :     kModO_Mask     = 0x7u << kModO_Shift,
     192             : 
     193             :     kModO__        = 0x0u,
     194             :     kModO_0        = 0x0u << kModO_Shift,
     195             :     kModO_1        = 0x1u << kModO_Shift,
     196             :     kModO_2        = 0x2u << kModO_Shift,
     197             :     kModO_3        = 0x3u << kModO_Shift,
     198             :     kModO_4        = 0x4u << kModO_Shift,
     199             :     kModO_5        = 0x5u << kModO_Shift,
     200             :     kModO_6        = 0x6u << kModO_Shift,
     201             :     kModO_7        = 0x7u << kModO_Shift,
     202             : 
     203             :     // `RM` Field in ModR/M (??:???:xxx)
     204             :     // ---------------------------------
     205             :     //
     206             :     // Second data field used by ModR/M byte. This is only used by few instructions that use OPCODE+MOD/RM where both
     207             :     // values in Mod/RM are part of the opcode.
     208             : 
     209             :     kModRM_Shift    = 13,
     210             :     kModRM_Mask     = 0x7u << kModRM_Shift,
     211             : 
     212             :     kModRM__        = 0x0u,
     213             :     kModRM_0        = 0x0u << kModRM_Shift,
     214             :     kModRM_1        = 0x1u << kModRM_Shift,
     215             :     kModRM_2        = 0x2u << kModRM_Shift,
     216             :     kModRM_3        = 0x3u << kModRM_Shift,
     217             :     kModRM_4        = 0x4u << kModRM_Shift,
     218             :     kModRM_5        = 0x5u << kModRM_Shift,
     219             :     kModRM_6        = 0x6u << kModRM_Shift,
     220             :     kModRM_7        = 0x7u << kModRM_Shift,
     221             : 
     222             :     // `PP` Field
     223             :     // ----------
     224             :     //
     225             :     // These fields are stored deliberately right after each other as it makes it easier to construct VEX prefix from
     226             :     // the opcode value stored in the instruction database.
     227             :     //
     228             :     // Two meanings:
     229             :     //   * "PP" field in AVX/XOP/AVX-512 instruction.
     230             :     //   * Mandatory Prefix in legacy encoding.
     231             :     //
     232             :     // AVX reserves 2 bits for `PP` field, but AsmJit extends the storage by 1 more bit that is used to emit 9B prefix
     233             :     // for some X87-FPU instructions.
     234             : 
     235             :     kPP_Shift      = 21,
     236             :     kPP_VEXMask    = 0x03u << kPP_Shift,   // PP field mask used by VEX/EVEX.
     237             :     kPP_FPUMask    = 0x07u << kPP_Shift,   // Mask used by EMIT_PP, also includes '0x9B'.
     238             :     kPP_00         = 0x00u << kPP_Shift,
     239             :     kPP_66         = 0x01u << kPP_Shift,
     240             :     kPP_F3         = 0x02u << kPP_Shift,
     241             :     kPP_F2         = 0x03u << kPP_Shift,
     242             : 
     243             :     kPP_9B         = 0x07u << kPP_Shift,   // AsmJit specific to emit FPU's '9B' byte.
     244             : 
     245             :     // REX|VEX|EVEX B|X|R|W Bits
     246             :     // -------------------------
     247             :     //
     248             :     // NOTE: REX.[B|X|R] are never stored within the opcode itself, they are reserved by AsmJit are are added
     249             :     // dynamically to the opcode to represent [REX|VEX|EVEX].[B|X|R] bits. REX.W can be stored in DB as it's sometimes
     250             :     // part of the opcode itself.
     251             : 
     252             :     // These must be binary compatible with instruction options.
     253             :     kREX_Shift     = 24,
     254             :     kREX_Mask      = 0x0Fu << kREX_Shift,
     255             :     kB             = 0x01u << kREX_Shift,  // Never stored in DB, used by encoder.
     256             :     kX             = 0x02u << kREX_Shift,  // Never stored in DB, used by encoder.
     257             :     kR             = 0x04u << kREX_Shift,  // Never stored in DB, used by encoder.
     258             :     kW             = 0x08u << kREX_Shift,
     259             :     kW_Shift       = kREX_Shift + 3,
     260             : 
     261             :     kW__           = 0u << kW_Shift,       // REX.W/VEX.W is unspecified.
     262             :     kW_x           = 0u << kW_Shift,       // REX.W/VEX.W is based on instruction operands.
     263             :     kW_I           = 0u << kW_Shift,       // REX.W/VEX.W is ignored (WIG).
     264             :     kW_0           = 0u << kW_Shift,       // REX.W/VEX.W is 0 (W0).
     265             :     kW_1           = 1u << kW_Shift,       // REX.W/VEX.W is 1 (W1).
     266             : 
     267             :     // EVEX.W Field
     268             :     // ------------
     269             :     //
     270             :     // `W` field used by EVEX instruction encoding.
     271             : 
     272             :     kEvex_W_Shift  = 28,
     273             :     kEvex_W_Mask   = 1u << kEvex_W_Shift,
     274             : 
     275             :     kEvex_W__      = 0u << kEvex_W_Shift,  // EVEX.W is unspecified (not EVEX instruction).
     276             :     kEvex_W_x      = 0u << kEvex_W_Shift,  // EVEX.W is based on instruction operands.
     277             :     kEvex_W_I      = 0u << kEvex_W_Shift,  // EVEX.W is ignored (WIG).
     278             :     kEvex_W_0      = 0u << kEvex_W_Shift,  // EVEX.W is 0 (W0).
     279             :     kEvex_W_1      = 1u << kEvex_W_Shift,  // EVEX.W is 1 (W1).
     280             : 
     281             :     // `L` or `LL` field in AVX/XOP/AVX-512
     282             :     // ------------------------------------
     283             :     //
     284             :     // VEX/XOP prefix can only use the first bit `L.128` or `L.256`. EVEX prefix prefix makes it possible to use also
     285             :     // `L.512`. If the instruction set manual describes an instruction by `LIG` it means that the `L` field is ignored
     286             :     // and AsmJit defaults to `0` in such case.
     287             :     kLL_Shift      = 29,
     288             :     kLL_Mask       = 0x3u << kLL_Shift,
     289             : 
     290             :     kLL__          = 0x0u << kLL_Shift,    // LL is unspecified.
     291             :     kLL_x          = 0x0u << kLL_Shift,    // LL is based on instruction operands.
     292             :     kLL_I          = 0x0u << kLL_Shift,    // LL is ignored (LIG).
     293             :     kLL_0          = 0x0u << kLL_Shift,    // LL is 0 (L.128).
     294             :     kLL_1          = 0x1u << kLL_Shift,    // LL is 1 (L.256).
     295             :     kLL_2          = 0x2u << kLL_Shift,    // LL is 2 (L.512).
     296             : 
     297             :     // Opcode Combinations
     298             :     // -------------------
     299             : 
     300             :     k0      = 0,                           // '__' (no prefix, used internally).
     301             :     k000000 = kPP_00 | kMM_00,             // '__' (no prefix, to be the same width as others).
     302             :     k000F00 = kPP_00 | kMM_0F,             // '0F'
     303             :     k000F01 = kPP_00 | kMM_0F01,           // '0F01'
     304             :     k000F0F = kPP_00 | kMM_0F,             // '0F0F' - 3DNOW, equal to 0x0F, must have special encoding to take effect.
     305             :     k000F38 = kPP_00 | kMM_0F38,           // 'NP.0F38'
     306             :     k000F3A = kPP_00 | kMM_0F3A,           // 'NP.0F3A'
     307             :     k00MAP5 = kPP_00 | kMM_MAP5,           // 'NP.MAP5'
     308             :     k00MAP6 = kPP_00 | kMM_MAP6,           // 'NP.MAP5'
     309             :     k660000 = kPP_66 | kMM_00,             // '66'
     310             :     k660F00 = kPP_66 | kMM_0F,             // '66.0F'
     311             :     k660F01 = kPP_66 | kMM_0F01,           // '66.0F01'
     312             :     k660F38 = kPP_66 | kMM_0F38,           // '66.0F38'
     313             :     k660F3A = kPP_66 | kMM_0F3A,           // '66.0F3A'
     314             :     k66MAP5 = kPP_66 | kMM_MAP5,           // '66.MAP5'
     315             :     k66MAP6 = kPP_66 | kMM_MAP6,           // '66.MAP5'
     316             :     kF20000 = kPP_F2 | kMM_00,             // 'F2'
     317             :     kF20F00 = kPP_F2 | kMM_0F,             // 'F2.0F'
     318             :     kF20F01 = kPP_F2 | kMM_0F01,           // 'F2.0F01'
     319             :     kF20F38 = kPP_F2 | kMM_0F38,           // 'F2.0F38'
     320             :     kF20F3A = kPP_F2 | kMM_0F3A,           // 'F2.0F3A'
     321             :     kF2MAP5 = kPP_F2 | kMM_MAP5,           // 'F2.MAP5'
     322             :     kF2MAP6 = kPP_F2 | kMM_MAP6,           // 'F2.MAP5'
     323             :     kF30000 = kPP_F3 | kMM_00,             // 'F3'
     324             :     kF30F00 = kPP_F3 | kMM_0F,             // 'F3.0F'
     325             :     kF30F01 = kPP_F3 | kMM_0F01,           // 'F3.0F01'
     326             :     kF30F38 = kPP_F3 | kMM_0F38,           // 'F3.0F38'
     327             :     kF30F3A = kPP_F3 | kMM_0F3A,           // 'F3.0F3A'
     328             :     kF3MAP5 = kPP_F3 | kMM_MAP5,           // 'F3.MAP5'
     329             :     kF3MAP6 = kPP_F3 | kMM_MAP6,           // 'F3.MAP5'
     330             :     kFPU_00 = kPP_00 | kMM_00,             // '__' (FPU)
     331             :     kFPU_9B = kPP_9B | kMM_00,             // '9B' (FPU)
     332             :     kXOP_M8 = kPP_00 | kMM_XOP08,          // 'M8' (XOP)
     333             :     kXOP_M9 = kPP_00 | kMM_XOP09,          // 'M9' (XOP)
     334             :     kXOP_MA = kPP_00 | kMM_XOP0A           // 'MA' (XOP)
     335             :   };
     336             : 
     337             :   // Opcode Builder
     338             :   // --------------
     339             : 
     340             :   inline uint32_t get() const noexcept { return v; }
     341             : 
     342             :   inline bool hasW() const noexcept { return (v & kW) != 0; }
     343             :   inline bool has66h() const noexcept { return (v & kPP_66) != 0; }
     344             : 
     345             :   inline Opcode& add(uint32_t x) noexcept { return operator+=(x); }
     346             : 
     347             :   inline Opcode& add66h() noexcept { return operator|=(kPP_66); }
     348             :   template<typename T>
     349           0 :   inline Opcode& add66hIf(T exp) noexcept { return operator|=(uint32_t(exp) << kPP_Shift); }
     350             :   template<typename T>
     351           0 :   inline Opcode& add66hBySize(T size) noexcept { return add66hIf(size == 2); }
     352             : 
     353             :   inline Opcode& addW() noexcept { return operator|=(kW); }
     354             :   template<typename T>
     355        9980 :   inline Opcode& addWIf(T exp) noexcept { return operator|=(uint32_t(exp) << kW_Shift); }
     356             :   template<typename T>
     357        9980 :   inline Opcode& addWBySize(T size) noexcept { return addWIf(size == 8); }
     358             : 
     359             :   template<typename T>
     360             :   inline Opcode& addPrefixBySize(T size) noexcept {
     361             :     static const uint32_t mask[16] = {
     362             :       0,          // #0
     363             :       0,          // #1 -> nothing (already handled or not possible)
     364             :       kPP_66,     // #2 -> 66H
     365             :       0,          // #3
     366             :       0,          // #4 -> nothing
     367             :       0,          // #5
     368             :       0,          // #6
     369             :       0,          // #7
     370             :       kW          // #8 -> REX.W
     371             :     };
     372       88236 :     return operator|=(mask[size & 0xF]);
     373             :   }
     374             : 
     375             :   template<typename T>
     376             :   inline Opcode& addArithBySize(T size) noexcept {
     377             :     static const uint32_t mask[16] = {
     378             :       0,          // #0
     379             :       0,          // #1 -> nothing
     380             :       1 | kPP_66, // #2 -> NOT_BYTE_OP(1) and 66H
     381             :       0,          // #3
     382             :       1,          // #4 -> NOT_BYTE_OP(1)
     383             :       0,          // #5
     384             :       0,          // #6
     385             :       0,          // #7
     386             :       1 | kW      // #8 -> NOT_BYTE_OP(1) and REX.W
     387             :     };
     388          20 :     return operator|=(mask[size & 0xF]);
     389             :   }
     390             : 
     391           0 :   inline Opcode& forceEvex() noexcept { return operator|=(kMM_ForceEvex); }
     392             :   template<typename T>
     393        1970 :   inline Opcode& forceEvexIf(T exp) noexcept { return operator|=(uint32_t(exp) << Support::ConstCTZ<uint32_t(kMM_ForceEvex)>::value); }
     394             : 
     395             :   //! Extract `O` field (R) from the opcode (specified as /0..7 in instruction manuals).
     396             :   inline uint32_t extractModO() const noexcept {
     397      392009 :     return (v >> kModO_Shift) & 0x07;
     398             :   }
     399             : 
     400             :   //! Extract `RM` field (RM) from the opcode (usually specified as another opcode value).
     401             :   inline uint32_t extractModRM() const noexcept {
     402           0 :     return (v >> kModRM_Shift) & 0x07;
     403             :   }
     404             : 
     405             :   //! Extract `REX` prefix from opcode combined with `options`.
     406             :   inline uint32_t extractRex(InstOptions options) const noexcept {
     407             :     // kREX was designed in a way that when shifted there will be no bytes set except REX.[B|X|R|W].
     408             :     // The returned value forms a real REX prefix byte. This case should be unit-tested as well.
     409      135367 :     return (v | uint32_t(options)) >> kREX_Shift;
     410             :   }
     411             : 
     412             :   inline uint32_t extractLLMMMMM(InstOptions options) const noexcept {
     413      256642 :     uint32_t llMmmmm = uint32_t(v & (kLL_Mask | kMM_Mask));
     414             :     uint32_t vexEvex = uint32_t(options & InstOptions::kX86_Evex);
     415      256642 :     return (llMmmmm | vexEvex) >> kMM_Shift;
     416             :   }
     417             : 
     418             :   inline Opcode& operator=(uint32_t x) noexcept { v = x; return *this; }
     419      125728 :   inline Opcode& operator+=(uint32_t x) noexcept { v += x; return *this; }
     420           0 :   inline Opcode& operator-=(uint32_t x) noexcept { v -= x; return *this; }
     421      142085 :   inline Opcode& operator&=(uint32_t x) noexcept { v &= x; return *this; }
     422      490225 :   inline Opcode& operator|=(uint32_t x) noexcept { v |= x; return *this; }
     423             :   inline Opcode& operator^=(uint32_t x) noexcept { v ^= x; return *this; }
     424             : 
     425           0 :   inline uint32_t operator&(uint32_t x) const noexcept { return v & x; }
     426             :   inline uint32_t operator|(uint32_t x) const noexcept { return v | x; }
     427             :   inline uint32_t operator^(uint32_t x) const noexcept { return v ^ x; }
     428        2610 :   inline uint32_t operator<<(uint32_t x) const noexcept { return v << x; }
     429      256642 :   inline uint32_t operator>>(uint32_t x) const noexcept { return v >> x; }
     430             : };
     431             : 
     432             : //! \}
     433             : //! \endcond
     434             : 
     435             : ASMJIT_END_SUB_NAMESPACE
     436             : 
     437             : #endif // ASMJIT_X86_X86OPCODE_P_H_INCLUDED
     438             : 
     439             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16