LCOV - code coverage report
Current view: top level - asmjit - x86assembler.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 222 1603 13.8 %
Date: 2026-11-05 10:19:06 Functions: 4 7 57.1 %

          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             : #include "api-build_p.h"
       8             : #if !defined(ASMJIT_NO_X86)
       9             : 
      10             : #include "assembler.h"
      11             : #include "codewriter_p.h"
      12             : #include "cpuinfo.h"
      13             : #include "emitterutils_p.h"
      14             : #include "formatter.h"
      15             : #include "logger.h"
      16             : #include "misc_p.h"
      17             : #include "support.h"
      18             : #include "x86assembler.h"
      19             : #include "x86emithelper_p.h"
      20             : #include "x86instapi_p.h"
      21             : #include "x86instdb_p.h"
      22             : #include "x86formatter_p.h"
      23             : #include "x86opcode_p.h"
      24             : 
      25             : ASMJIT_BEGIN_SUB_NAMESPACE(x86)
      26             : 
      27             : typedef Support::FastUInt8 FastUInt8;
      28             : 
      29             : // x86::Assembler - Constants
      30             : // ==========================
      31             : 
      32             : //! X86 bytes used to encode important prefixes.
      33             : enum X86Byte : uint32_t {
      34             :   //! 1-byte REX prefix mask.
      35             :   kX86ByteRex = 0x40,
      36             : 
      37             :   //! 1-byte REX.W component.
      38             :   kX86ByteRexW = 0x08,
      39             : 
      40             :   kX86ByteInvalidRex = 0x80,
      41             : 
      42             :   //! 2-byte VEX prefix:
      43             :   //!   - `[0]` - `0xC5`.
      44             :   //!   - `[1]` - `RvvvvLpp`.
      45             :   kX86ByteVex2 = 0xC5,
      46             : 
      47             :   //! 3-byte VEX prefix:
      48             :   //!   - `[0]` - `0xC4`.
      49             :   //!   - `[1]` - `RXBmmmmm`.
      50             :   //!   - `[2]` - `WvvvvLpp`.
      51             :   kX86ByteVex3 = 0xC4,
      52             : 
      53             :   //! 3-byte XOP prefix:
      54             :   //!   - `[0]` - `0x8F`.
      55             :   //!   - `[1]` - `RXBmmmmm`.
      56             :   //!   - `[2]` - `WvvvvLpp`.
      57             :   kX86ByteXop3 = 0x8F,
      58             : 
      59             :   //! 4-byte EVEX prefix:
      60             :   //!   - `[0]` - `0x62`.
      61             :   //!   - `[1]` - Payload0 or `P[ 7: 0]` - `[R  X  B  R' 0  m  m  m]`.
      62             :   //!   - `[2]` - Payload1 or `P[15: 8]` - `[W  v  v  v  v  1  p  p]`.
      63             :   //!   - `[3]` - Payload2 or `P[23:16]` - `[z  L' L  b  V' a  a  a]`.
      64             :   //!
      65             :   //! Payload:
      66             :   //!   - `P[ 2: 0]` - OPCODE: EVEX.mmmmm, only lowest 3 bits [2:0] used.
      67             :   //!   - `P[    3]` - ______: Must be 0.
      68             :   //!   - `P[    4]` - REG-ID: EVEX.R' - 5th bit of 'RRRRR'.
      69             :   //!   - `P[    5]` - REG-ID: EVEX.B  - 4th bit of 'BBBBB'.
      70             :   //!   - `P[    6]` - REG-ID: EVEX.X  - 5th bit of 'BBBBB' or 4th bit of 'XXXX' (with SIB).
      71             :   //!   - `P[    7]` - REG-ID: EVEX.R  - 4th bit of 'RRRRR'.
      72             :   //!   - `P[ 9: 8]` - OPCODE: EVEX.pp.
      73             :   //!   - `P[   10]` - ______: Must be 1.
      74             :   //!   - `P[14:11]` - REG-ID: 4 bits of 'VVVV'.
      75             :   //!   - `P[   15]` - OPCODE: EVEX.W.
      76             :   //!   - `P[18:16]` - REG-ID: K register k0...k7 (Merging/Zeroing Vector Ops).
      77             :   //!   - `P[   19]` - REG-ID: 5th bit of 'VVVVV'.
      78             :   //!   - `P[   20]` - OPCODE: Broadcast/Rounding Control/SAE bit.
      79             :   //!   - `P[22.21]` - OPCODE: Vector Length (L' and  L) / Rounding Control.
      80             :   //!   - `P[   23]` - OPCODE: Zeroing/Merging.
      81             :   kX86ByteEvex = 0x62
      82             : };
      83             : 
      84             : // AsmJit specific (used to encode VVVVV field in XOP/VEX/EVEX).
      85             : enum VexVVVVV : uint32_t {
      86             :   kVexVVVVVShift = 7,
      87             :   kVexVVVVVMask = 0x1F << kVexVVVVVShift
      88             : };
      89             : 
      90             : //! Instruction 2-byte/3-byte opcode prefix definition.
      91             : struct X86OpcodeMM {
      92             :   uint8_t size;
      93             :   uint8_t data[3];
      94             : };
      95             : 
      96             : //! Mandatory prefixes used to encode legacy [66, F3, F2] or [9B] byte.
      97             : static const uint8_t x86OpcodePP[8] = { 0x00, 0x66, 0xF3, 0xF2, 0x00, 0x00, 0x00, 0x9B };
      98             : 
      99             : //! Instruction 2-byte/3-byte opcode prefix data.
     100             : static const X86OpcodeMM x86OpcodeMM[] = {
     101             :   { 0, { 0x00, 0x00, 0 } }, // #00 (0b0000).
     102             :   { 1, { 0x0F, 0x00, 0 } }, // #01 (0b0001).
     103             :   { 2, { 0x0F, 0x38, 0 } }, // #02 (0b0010).
     104             :   { 2, { 0x0F, 0x3A, 0 } }, // #03 (0b0011).
     105             :   { 2, { 0x0F, 0x01, 0 } }, // #04 (0b0100).
     106             :   { 0, { 0x00, 0x00, 0 } }, // #05 (0b0101).
     107             :   { 0, { 0x00, 0x00, 0 } }, // #06 (0b0110).
     108             :   { 0, { 0x00, 0x00, 0 } }, // #07 (0b0111).
     109             :   { 0, { 0x00, 0x00, 0 } }, // #08 (0b1000).
     110             :   { 0, { 0x00, 0x00, 0 } }, // #09 (0b1001).
     111             :   { 0, { 0x00, 0x00, 0 } }, // #0A (0b1010).
     112             :   { 0, { 0x00, 0x00, 0 } }, // #0B (0b1011).
     113             :   { 0, { 0x00, 0x00, 0 } }, // #0C (0b1100).
     114             :   { 0, { 0x00, 0x00, 0 } }, // #0D (0b1101).
     115             :   { 0, { 0x00, 0x00, 0 } }, // #0E (0b1110).
     116             :   { 0, { 0x00, 0x00, 0 } }  // #0F (0b1111).
     117             : };
     118             : 
     119             : static const uint8_t x86SegmentPrefix[8] = {
     120             :   0x00, // None.
     121             :   0x26, // ES.
     122             :   0x2E, // CS.
     123             :   0x36, // SS.
     124             :   0x3E, // DS.
     125             :   0x64, // FS.
     126             :   0x65  // GS.
     127             : };
     128             : 
     129             : static const uint32_t x86OpcodePushSReg[8] = {
     130             :   Opcode::k000000 | 0x00, // None.
     131             :   Opcode::k000000 | 0x06, // Push ES.
     132             :   Opcode::k000000 | 0x0E, // Push CS.
     133             :   Opcode::k000000 | 0x16, // Push SS.
     134             :   Opcode::k000000 | 0x1E, // Push DS.
     135             :   Opcode::k000F00 | 0xA0, // Push FS.
     136             :   Opcode::k000F00 | 0xA8  // Push GS.
     137             : };
     138             : 
     139             : static const uint32_t x86OpcodePopSReg[8]  = {
     140             :   Opcode::k000000 | 0x00, // None.
     141             :   Opcode::k000000 | 0x07, // Pop ES.
     142             :   Opcode::k000000 | 0x00, // Pop CS.
     143             :   Opcode::k000000 | 0x17, // Pop SS.
     144             :   Opcode::k000000 | 0x1F, // Pop DS.
     145             :   Opcode::k000F00 | 0xA1, // Pop FS.
     146             :   Opcode::k000F00 | 0xA9  // Pop GS.
     147             : };
     148             : 
     149             : // x86::Assembler - X86MemInfo | X86VEXPrefix | X86LLByRegType | X86CDisp8Table
     150             : // ============================================================================
     151             : 
     152             : //! Memory operand's info bits.
     153             : //!
     154             : //! A lookup table that contains various information based on the BASE and INDEX information of a memory operand. This
     155             : //! is much better and safer than playing with IFs in the code and can check for errors must faster and better.
     156             : enum X86MemInfo_Enum {
     157             :   kX86MemInfo_0         = 0x00,
     158             : 
     159             :   kX86MemInfo_BaseGp    = 0x01, //!< Has BASE reg, REX.B can be 1, compatible with REX.B byte.
     160             :   kX86MemInfo_Index     = 0x02, //!< Has INDEX reg, REX.X can be 1, compatible with REX.X byte.
     161             : 
     162             :   kX86MemInfo_BaseLabel = 0x10, //!< Base is Label.
     163             :   kX86MemInfo_BaseRip   = 0x20, //!< Base is RIP.
     164             : 
     165             :   kX86MemInfo_67H_X86   = 0x40, //!< Address-size override in 32-bit mode.
     166             :   kX86MemInfo_67H_X64   = 0x80, //!< Address-size override in 64-bit mode.
     167             :   kX86MemInfo_67H_Mask  = 0xC0  //!< Contains all address-size override bits.
     168             : };
     169             : 
     170             : template<uint32_t X>
     171             : struct X86MemInfo_T {
     172             :   enum : uint32_t {
     173             :     B = (X     ) & 0x1F,
     174             :     I = (X >> 5) & 0x1F,
     175             : 
     176             :     kBase  = (B >= uint32_t(RegType::kX86_Gpw)  && B <= uint32_t(RegType::kX86_Gpq)) ? kX86MemInfo_BaseGp    :
     177             :              (B == uint32_t(RegType::kX86_Rip)                                     ) ? kX86MemInfo_BaseRip   :
     178             :              (B == uint32_t(RegType::kLabelTag)                                    ) ? kX86MemInfo_BaseLabel : 0,
     179             : 
     180             :     kIndex = (I >= uint32_t(RegType::kX86_Gpw)  && I <= uint32_t(RegType::kX86_Gpq)) ? kX86MemInfo_Index     :
     181             :              (I >= uint32_t(RegType::kX86_Xmm)  && I <= uint32_t(RegType::kX86_Zmm)) ? kX86MemInfo_Index     : 0,
     182             : 
     183             :     k67H   = (B == uint32_t(RegType::kX86_Gpw)  && I == uint32_t(RegType::kNone)   ) ? kX86MemInfo_67H_X86   :
     184             :              (B == uint32_t(RegType::kX86_Gpd)  && I == uint32_t(RegType::kNone)   ) ? kX86MemInfo_67H_X64   :
     185             :              (B == uint32_t(RegType::kNone)     && I == uint32_t(RegType::kX86_Gpw)) ? kX86MemInfo_67H_X86   :
     186             :              (B == uint32_t(RegType::kNone)     && I == uint32_t(RegType::kX86_Gpd)) ? kX86MemInfo_67H_X64   :
     187             :              (B == uint32_t(RegType::kX86_Gpw)  && I == uint32_t(RegType::kX86_Gpw)) ? kX86MemInfo_67H_X86   :
     188             :              (B == uint32_t(RegType::kX86_Gpd)  && I == uint32_t(RegType::kX86_Gpd)) ? kX86MemInfo_67H_X64   :
     189             :              (B == uint32_t(RegType::kX86_Gpw)  && I == uint32_t(RegType::kX86_Xmm)) ? kX86MemInfo_67H_X86   :
     190             :              (B == uint32_t(RegType::kX86_Gpd)  && I == uint32_t(RegType::kX86_Xmm)) ? kX86MemInfo_67H_X64   :
     191             :              (B == uint32_t(RegType::kX86_Gpw)  && I == uint32_t(RegType::kX86_Ymm)) ? kX86MemInfo_67H_X86   :
     192             :              (B == uint32_t(RegType::kX86_Gpd)  && I == uint32_t(RegType::kX86_Ymm)) ? kX86MemInfo_67H_X64   :
     193             :              (B == uint32_t(RegType::kX86_Gpw)  && I == uint32_t(RegType::kX86_Zmm)) ? kX86MemInfo_67H_X86   :
     194             :              (B == uint32_t(RegType::kX86_Gpd)  && I == uint32_t(RegType::kX86_Zmm)) ? kX86MemInfo_67H_X64   :
     195             :              (B == uint32_t(RegType::kLabelTag) && I == uint32_t(RegType::kX86_Gpw)) ? kX86MemInfo_67H_X86   :
     196             :              (B == uint32_t(RegType::kLabelTag) && I == uint32_t(RegType::kX86_Gpd)) ? kX86MemInfo_67H_X64   : 0,
     197             : 
     198             :     kValue = kBase | kIndex | k67H | 0x04 | 0x08
     199             :   };
     200             : };
     201             : 
     202             : // The result stored in the LUT is a combination of
     203             : //   - 67H - Address override prefix - depends on BASE+INDEX register types and the target architecture.
     204             : //   - REX - A possible combination of REX.[B|X|R|W] bits in REX prefix where REX.B and REX.X are possibly
     205             : //           masked out, but REX.R and REX.W are kept as is.
     206             : #define VALUE(x) X86MemInfo_T<x>::kValue
     207             : static const uint8_t x86MemInfo[] = { ASMJIT_LOOKUP_TABLE_1024(VALUE, 0) };
     208             : #undef VALUE
     209             : 
     210             : // VEX3 or XOP xor bits applied to the opcode before emitted. The index to this table is 'mmmmm' value, which
     211             : // contains all we need. This is only used by a 3 BYTE VEX and XOP prefixes, 2 BYTE VEX prefix is handled differently.
     212             : // The idea is to minimize the difference between VEX3 vs XOP when encoding VEX or XOP instruction. This should
     213             : // minimize the code required to emit such instructions and should also make it faster as we don't need any branch to
     214             : // decide between VEX3 vs XOP.
     215             : //            ____    ___
     216             : // [_OPCODE_|WvvvvLpp|RXBmmmmm|VEX3_XOP]
     217             : #define VALUE(x) ((x & 0x08) ? kX86ByteXop3 : kX86ByteVex3) | (0xF << 19) | (0x7 << 13)
     218             : static const uint32_t x86VEXPrefix[] = { ASMJIT_LOOKUP_TABLE_16(VALUE, 0) };
     219             : #undef VALUE
     220             : 
     221             : // Table that contains LL opcode field addressed by a register size / 16. It's used to propagate L.256 or L.512 when
     222             : // YMM or ZMM registers are used, respectively.
     223             : #define VALUE(x) (x & (64 >> 4)) ? Opcode::kLL_2 : \
     224             :                  (x & (32 >> 4)) ? Opcode::kLL_1 : Opcode::kLL_0
     225             : static const uint32_t x86LLBySizeDiv16[] = { ASMJIT_LOOKUP_TABLE_16(VALUE, 0) };
     226             : #undef VALUE
     227             : 
     228             : // Table that contains LL opcode field addressed by a register size / 16. It's used to propagate L.256 or L.512 when
     229             : // YMM or ZMM registers are used, respectively.
     230             : #define VALUE(x) x == uint32_t(RegType::kX86_Zmm) ? Opcode::kLL_2 : \
     231             :                  x == uint32_t(RegType::kX86_Ymm) ? Opcode::kLL_1 : Opcode::kLL_0
     232             : static const uint32_t x86LLByRegType[] = { ASMJIT_LOOKUP_TABLE_16(VALUE, 0) };
     233             : #undef VALUE
     234             : 
     235             : // Table that contains a scale (shift left) based on 'TTWLL' field and the instruction's tuple-type (TT) field. The
     236             : // scale is then applied to the BASE-N stored in each opcode to calculate the final compressed displacement used by
     237             : // all EVEX encoded instructions.
     238             : template<uint32_t X>
     239             : struct X86CDisp8SHL_T {
     240             :   enum {
     241             :     TT = (X >> 3) << Opcode::kCDTT_Shift,
     242             :     LL = (X >> 0) & 0x3,
     243             :     W  = (X >> 2) & 0x1,
     244             : 
     245             :     kValue = (TT == Opcode::kCDTT_None ? ((LL==0) ? 0 : (LL==1) ? 0   : 0  ) :
     246             :               TT == Opcode::kCDTT_ByLL ? ((LL==0) ? 0 : (LL==1) ? 1   : 2  ) :
     247             :               TT == Opcode::kCDTT_T1W  ? ((LL==0) ? W : (LL==1) ? 1+W : 2+W) :
     248             :               TT == Opcode::kCDTT_DUP  ? ((LL==0) ? 0 : (LL==1) ? 2   : 3  ) : 0) << Opcode::kCDSHL_Shift
     249             :   };
     250             : };
     251             : 
     252             : #define VALUE(x) X86CDisp8SHL_T<x>::kValue
     253             : static const uint32_t x86CDisp8SHL[] = { ASMJIT_LOOKUP_TABLE_32(VALUE, 0) };
     254             : #undef VALUE
     255             : 
     256             : // Table that contains MOD byte of a 16-bit [BASE + disp] address.
     257             : //   0xFF == Invalid.
     258             : static const uint8_t x86Mod16BaseTable[8] = {
     259             :   0xFF, // AX -> N/A.
     260             :   0xFF, // CX -> N/A.
     261             :   0xFF, // DX -> N/A.
     262             :   0x07, // BX -> 111.
     263             :   0xFF, // SP -> N/A.
     264             :   0x06, // BP -> 110.
     265             :   0x04, // SI -> 100.
     266             :   0x05  // DI -> 101.
     267             : };
     268             : 
     269             : // Table that contains MOD byte of a 16-bit [BASE + INDEX + disp] combination.
     270             : //   0xFF == Invalid.
     271             : template<uint32_t X>
     272             : struct X86Mod16BaseIndexTable_T {
     273             :   enum {
     274             :     B = X >> 3,
     275             :     I = X & 0x7,
     276             : 
     277             :     kValue = ((B == Gp::kIdBx && I == Gp::kIdSi) || (B == Gp::kIdSi && I == Gp::kIdBx)) ? 0x00 :
     278             :              ((B == Gp::kIdBx && I == Gp::kIdDi) || (B == Gp::kIdDi && I == Gp::kIdBx)) ? 0x01 :
     279             :              ((B == Gp::kIdBp && I == Gp::kIdSi) || (B == Gp::kIdSi && I == Gp::kIdBp)) ? 0x02 :
     280             :              ((B == Gp::kIdBp && I == Gp::kIdDi) || (B == Gp::kIdDi && I == Gp::kIdBp)) ? 0x03 : 0xFF
     281             :   };
     282             : };
     283             : 
     284             : #define VALUE(x) X86Mod16BaseIndexTable_T<x>::kValue
     285             : static const uint8_t x86Mod16BaseIndexTable[] = { ASMJIT_LOOKUP_TABLE_64(VALUE, 0) };
     286             : #undef VALUE
     287             : 
     288             : // x86::Assembler - Helpers
     289             : // ========================
     290             : 
     291             : static ASMJIT_FORCE_INLINE bool x86IsJmpOrCall(InstId instId) noexcept {
     292           0 :   return instId == Inst::kIdJmp || instId == Inst::kIdCall;
     293             : }
     294             : 
     295             : static ASMJIT_FORCE_INLINE bool x86IsImplicitMem(const Operand_& op, uint32_t base) noexcept {
     296           0 :   return op.isMem() && op.as<Mem>().baseId() == base && !op.as<Mem>().hasOffset();
     297             : }
     298             : 
     299             : //! Combine `regId` and `vvvvvId` into a single value (used by AVX and AVX-512).
     300             : static ASMJIT_FORCE_INLINE uint32_t x86PackRegAndVvvvv(uint32_t regId, uint32_t vvvvvId) noexcept {
     301           0 :   return regId + (vvvvvId << kVexVVVVVShift);
     302             : }
     303             : 
     304             : static ASMJIT_FORCE_INLINE uint32_t x86OpcodeLByVMem(const Operand_& op) noexcept {
     305           0 :   return x86LLByRegType[size_t(op.as<Mem>().indexType())];
     306             : }
     307             : 
     308             : static ASMJIT_FORCE_INLINE uint32_t x86OpcodeLBySize(uint32_t size) noexcept {
     309        8481 :   return x86LLBySizeDiv16[size / 16];
     310             : }
     311             : 
     312             : //! Encode MOD byte.
     313             : static ASMJIT_FORCE_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept {
     314             :   ASMJIT_ASSERT(m <= 3);
     315             :   ASMJIT_ASSERT(o <= 7);
     316             :   ASMJIT_ASSERT(rm <= 7);
     317      142105 :   return (m << 6) + (o << 3) + rm;
     318             : }
     319             : 
     320             : //! Encode SIB byte.
     321             : static ASMJIT_FORCE_INLINE uint32_t x86EncodeSib(uint32_t s, uint32_t i, uint32_t b) noexcept {
     322             :   ASMJIT_ASSERT(s <= 3);
     323             :   ASMJIT_ASSERT(i <= 7);
     324             :   ASMJIT_ASSERT(b <= 7);
     325       71131 :   return (s << 6) + (i << 3) + b;
     326             : }
     327             : 
     328             : static ASMJIT_FORCE_INLINE bool x86IsRexInvalid(uint32_t rex) noexcept {
     329             :   // Validates the following possibilities:
     330             :   //   REX == 0x00      -> OKAY (X86_32 / X86_64).
     331             :   //   REX == 0x40-0x4F -> OKAY (X86_64).
     332             :   //   REX == 0x80      -> OKAY (X86_32 mode, rex prefix not used).
     333             :   //   REX == 0x81-0xCF -> BAD  (X86_32 mode, rex prefix used).
     334      135367 :   return rex > kX86ByteInvalidRex;
     335             : }
     336             : 
     337             : static ASMJIT_FORCE_INLINE uint32_t x86GetForceEvex3MaskInLastBit(InstOptions options) noexcept {
     338             :   constexpr uint32_t kVex3Bit = Support::ConstCTZ<uint32_t(InstOptions::kX86_Vex3)>::value;
     339      256642 :   return uint32_t(options & InstOptions::kX86_Vex3) << (31 - kVex3Bit);
     340             : }
     341             : 
     342             : template<typename T>
     343           0 : static ASMJIT_FORCE_INLINE constexpr T x86SignExtendI32(T imm) noexcept { return T(int64_t(int32_t(imm & T(0xFFFFFFFF)))); }
     344             : 
     345             : static ASMJIT_FORCE_INLINE uint32_t x86AltOpcodeOf(const InstDB::InstInfo* info) noexcept {
     346       30882 :   return InstDB::_altOpcodeTable[info->_altOpcodeIndex];
     347             : }
     348             : 
     349             : // x86::Assembler - X86BufferWriter
     350             : // ================================
     351             : 
     352             : class X86BufferWriter : public CodeWriter {
     353             : public:
     354             :   ASMJIT_FORCE_INLINE explicit X86BufferWriter(Assembler* a) noexcept
     355             :     : CodeWriter(a) {}
     356             : 
     357             :   ASMJIT_FORCE_INLINE void emitPP(uint32_t opcode) noexcept {
     358      135367 :     uint32_t ppIndex = (opcode              >> Opcode::kPP_Shift) &
     359             :                        (Opcode::kPP_FPUMask >> Opcode::kPP_Shift) ;
     360           0 :     emit8If(x86OpcodePP[ppIndex], ppIndex != 0);
     361             :   }
     362             : 
     363             :   ASMJIT_FORCE_INLINE void emitMMAndOpcode(uint32_t opcode) noexcept {
     364      135367 :     uint32_t mmIndex = (opcode & Opcode::kMM_Mask) >> Opcode::kMM_Shift;
     365             :     const X86OpcodeMM& mmCode = x86OpcodeMM[mmIndex];
     366             : 
     367      135367 :     emit8If(mmCode.data[0], mmCode.size > 0);
     368      115728 :     emit8If(mmCode.data[1], mmCode.size > 1);
     369             :     emit8(opcode);
     370          20 :   }
     371             : 
     372             :   ASMJIT_FORCE_INLINE void emitSegmentOverride(uint32_t segmentId) noexcept {
     373             :     ASMJIT_ASSERT(segmentId < ASMJIT_ARRAY_SIZE(x86SegmentPrefix));
     374             : 
     375      142105 :     FastUInt8 prefix = x86SegmentPrefix[segmentId];
     376           0 :     emit8If(prefix, prefix != 0);
     377           0 :   }
     378             : 
     379             :   template<typename CondT>
     380             :   ASMJIT_FORCE_INLINE void emitAddressOverride(CondT condition) noexcept {
     381             :     emit8If(0x67, condition);
     382             :   }
     383             : 
     384             :   ASMJIT_FORCE_INLINE void emitImmByteOrDWord(uint64_t immValue, FastUInt8 immSize) noexcept {
     385      114557 :     if (!immSize)
     386             :       return;
     387             : 
     388             :     ASMJIT_ASSERT(immSize == 1 || immSize == 4);
     389             : 
     390             : #if ASMJIT_ARCH_BITS >= 64
     391             :     uint64_t imm = uint64_t(immValue);
     392             : #else
     393             :     uint32_t imm = uint32_t(immValue & 0xFFFFFFFFu);
     394             : #endif
     395             : 
     396             :     // Many instructions just use a single byte immediate, so make it fast.
     397             :     emit8(imm & 0xFFu);
     398        1724 :     if (immSize == 1) return;
     399             : 
     400           0 :     imm >>= 8;
     401             :     emit8(imm & 0xFFu);
     402           0 :     imm >>= 8;
     403             :     emit8(imm & 0xFFu);
     404           0 :     imm >>= 8;
     405             :     emit8(imm & 0xFFu);
     406             :   }
     407             : 
     408             :   ASMJIT_FORCE_INLINE void emitImmediate(uint64_t immValue, FastUInt8 immSize) noexcept {
     409             : #if ASMJIT_ARCH_BITS >= 64
     410             :     uint64_t imm = immValue;
     411      277452 :     if (immSize >= 4) {
     412             :       emit32uLE(imm & 0xFFFFFFFFu);
     413         756 :       imm >>= 32;
     414       88236 :       immSize = FastUInt8(immSize - 4u);
     415             :     }
     416             : #else
     417             :     uint32_t imm = uint32_t(immValue & 0xFFFFFFFFu);
     418             :     if (immSize >= 4) {
     419             :       emit32uLE(imm);
     420             :       imm = uint32_t(immValue >> 32);
     421             :       immSize = FastUInt8(immSize - 4u);
     422             :     }
     423             : #endif
     424             : 
     425      277452 :     if (!immSize)
     426             :       return;
     427             :     emit8(imm & 0xFFu);
     428       97869 :     imm >>= 8;
     429             : 
     430       97869 :     if (--immSize == 0)
     431             :       return;
     432             :     emit8(imm & 0xFFu);
     433       88236 :     imm >>= 8;
     434             : 
     435       88236 :     if (--immSize == 0)
     436             :       return;
     437             :     emit8(imm & 0xFFu);
     438       88236 :     imm >>= 8;
     439             : 
     440       88236 :     if (--immSize == 0)
     441             :       return;
     442             :     emit8(imm & 0xFFu);
     443             :   }
     444             : };
     445             : 
     446             : // If the operand is BPL|SPL|SIL|DIL|R8B-15B
     447             : //   - Force REX prefix
     448             : // If the operand is AH|BH|CH|DH
     449             : //   - patch its index from 0..3 to 4..7 as encoded by X86.
     450             : //   - Disallow REX prefix.
     451             : #define FIXUP_GPB(REG_OP, REG_ID)                                \
     452             :   do {                                                           \
     453             :     if (!static_cast<const Gp&>(REG_OP).isGpbHi()) {             \
     454             :       options |= (REG_ID) >= 4 ? InstOptions::kX86_Rex           \
     455             :                                : InstOptions::kNone;             \
     456             :     }                                                            \
     457             :     else {                                                       \
     458             :       options |= InstOptions::kX86_InvalidRex;                   \
     459             :       REG_ID += 4;                                               \
     460             :     }                                                            \
     461             :   } while (0)
     462             : 
     463             : #define ENC_OPS1(OP0) \
     464             :   (uint32_t(OperandType::k##OP0))
     465             : 
     466             : #define ENC_OPS2(OP0, OP1) \
     467             :   (uint32_t(OperandType::k##OP0) + \
     468             :   (uint32_t(OperandType::k##OP1) << 3))
     469             : 
     470             : #define ENC_OPS3(OP0, OP1, OP2) \
     471             :   (uint32_t(OperandType::k##OP0) + \
     472             :   (uint32_t(OperandType::k##OP1) << 3) + \
     473             :   (uint32_t(OperandType::k##OP2) << 6))
     474             : 
     475             : #define ENC_OPS4(OP0, OP1, OP2, OP3) \
     476             :   (uint32_t(OperandType::k##OP0) + \
     477             :   (uint32_t(OperandType::k##OP1) << 3) + \
     478             :   (uint32_t(OperandType::k##OP2) << 6) + \
     479             :   (uint32_t(OperandType::k##OP3) << 9))
     480             : 
     481             : // x86::Assembler - Movabs Heuristics
     482             : // ==================================
     483             : 
     484             : static ASMJIT_FORCE_INLINE uint32_t x86GetMovAbsInstSize64Bit(uint32_t regSize, InstOptions options, const Mem& rmRel) noexcept {
     485             :   uint32_t segmentPrefixSize = rmRel.segmentId() != 0;
     486           0 :   uint32_t _66hPrefixSize = regSize == 2;
     487           0 :   uint32_t rexPrefixSize = regSize == 8 || Support::test(options, InstOptions::kX86_Rex);
     488             :   uint32_t opCodeByteSize = 1;
     489             :   uint32_t immediateSize = 8;
     490             : 
     491           0 :   return segmentPrefixSize + _66hPrefixSize + rexPrefixSize + opCodeByteSize + immediateSize;
     492             : }
     493             : 
     494             : static ASMJIT_FORCE_INLINE bool x86ShouldUseMovabs(Assembler* self, X86BufferWriter& writer, uint32_t regSize, InstOptions options, const Mem& rmRel) noexcept {
     495           0 :   if (self->is32Bit()) {
     496             :     // There is no relative addressing, just decide whether to use MOV encoded with MOD R/M or absolute.
     497           0 :     return !Support::test(options, InstOptions::kX86_ModMR | InstOptions::kX86_ModMR);
     498             :   }
     499             :   else {
     500             :     // If the addressing type is REL or MOD R/M was specified then absolute mov won't be used.
     501           0 :     if (rmRel.addrType() == Mem::AddrType::kRel || Support::test(options, InstOptions::kX86_ModMR))
     502             :       return false;
     503             : 
     504             :     int64_t addrValue = rmRel.offset();
     505             :     uint64_t baseAddress = self->code()->baseAddress();
     506             : 
     507             :     // If the address type is default, it means to basically check whether relative addressing is possible. However,
     508             :     // this is only possible when the base address is known - relative encoding uses RIP+N it has to be calculated.
     509           0 :     if (rmRel.addrType() == Mem::AddrType::kDefault && baseAddress != Globals::kNoBaseAddress && !rmRel.hasSegment()) {
     510             :       uint32_t instructionSize = x86GetMovAbsInstSize64Bit(regSize, options, rmRel);
     511           0 :       uint64_t virtualOffset = uint64_t(writer.offsetFrom(self->_bufferData));
     512           0 :       uint64_t rip64 = baseAddress + self->_section->offset() + virtualOffset + instructionSize;
     513           0 :       uint64_t rel64 = uint64_t(addrValue) - rip64;
     514             : 
     515           0 :       if (Support::isInt32(int64_t(rel64)))
     516             :         return false;
     517             :     }
     518             :     else {
     519             :       if (Support::isInt32(addrValue))
     520             :         return false;
     521             :     }
     522             : 
     523           0 :     return uint64_t(addrValue) > 0xFFFFFFFFu;
     524             :   }
     525             : }
     526             : 
     527             : // x86::Assembler - Construction & Destruction
     528             : // ===========================================
     529             : 
     530       27492 : Assembler::Assembler(CodeHolder* code) noexcept : BaseAssembler() {
     531       27492 :   _archMask = (uint64_t(1) << uint32_t(Arch::kX86)) |
     532             :               (uint64_t(1) << uint32_t(Arch::kX64)) ;
     533       27492 :   assignEmitterFuncs(this);
     534             : 
     535       27492 :   if (code)
     536       27492 :     code->attach(this);
     537       27492 : }
     538       27492 : Assembler::~Assembler() noexcept {}
     539             : 
     540             : // x86::Assembler - Emit (Low-Level)
     541             : // =================================
     542             : 
     543      392009 : ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) {
     544             :   constexpr uint32_t kVSHR_W     = Opcode::kW_Shift  - 23;
     545             :   constexpr uint32_t kVSHR_PP    = Opcode::kPP_Shift - 16;
     546             :   constexpr uint32_t kVSHR_PP_EW = Opcode::kPP_Shift - 16;
     547             : 
     548             :   constexpr InstOptions kRequiresSpecialHandling =
     549             :     InstOptions::kReserved     |   // Logging/Validation/Error.
     550             :     InstOptions::kX86_Rep      |   // REP/REPE prefix.
     551             :     InstOptions::kX86_Repne    |   // REPNE prefix.
     552             :     InstOptions::kX86_Lock     |   // LOCK prefix.
     553             :     InstOptions::kX86_XAcquire |   // XACQUIRE prefix.
     554             :     InstOptions::kX86_XRelease ;   // XRELEASE prefix.
     555             : 
     556             :   Error err;
     557             : 
     558             :   Opcode opcode;                   // Instruction opcode.
     559             :   InstOptions options;             // Instruction options.
     560             :   uint32_t isign3;                 // A combined signature of first 3 operands.
     561             : 
     562             :   const Operand_* rmRel;           // Memory operand or operand that holds Label|Imm.
     563             :   uint32_t rmInfo;                 // Memory operand's info based on x86MemInfo.
     564             :   uint32_t rbReg;                  // Memory base or modRM register.
     565             :   uint32_t rxReg;                  // Memory index register.
     566             :   uint32_t opReg;                  // ModR/M opcode or register id.
     567             : 
     568             :   LabelEntry* label;               // Label entry.
     569      392009 :   RelocEntry* re = nullptr;        // Relocation entry.
     570             :   int32_t relOffset;               // Relative offset
     571             :   FastUInt8 relSize = 0;           // Relative size.
     572             :   uint8_t* memOpAOMark = nullptr;  // Marker that points before 'address-override prefix' is emitted.
     573             : 
     574             :   int64_t immValue = 0;            // Immediate value (must be 64-bit).
     575             :   FastUInt8 immSize = 0;           // Immediate size.
     576             : 
     577             :   X86BufferWriter writer(this);
     578             : 
     579      392009 :   if (instId >= Inst::_kIdCount)
     580             :     instId = 0;
     581             : 
     582             :   const InstDB::InstInfo* instInfo = &InstDB::_instInfoTable[instId];
     583             :   const InstDB::CommonInfo* commonInfo = &instInfo->commonInfo();
     584             : 
     585             :   // Signature of the first 3 operands.
     586      392009 :   isign3 = (uint32_t(o0.opType())     ) +
     587      392009 :            (uint32_t(o1.opType()) << 3) +
     588      392009 :            (uint32_t(o2.opType()) << 6);
     589             : 
     590             :   // Combine all instruction options and also check whether the instruction is valid. All options
     591             :   // that require special handling (including invalid instruction) are handled by the next branch.
     592      392009 :   options = InstOptions((instId == 0) | ((size_t)(_bufferEnd - writer.cursor()) < 16)) | instOptions() | forcedInstOptions();
     593             : 
     594             :   // Handle failure and rare cases first.
     595      392009 :   if (ASMJIT_UNLIKELY(Support::test(options, kRequiresSpecialHandling))) {
     596       27492 :     if (ASMJIT_UNLIKELY(!_code))
     597           0 :       return reportError(DebugUtils::errored(kErrorNotInitialized));
     598             : 
     599             :     // Unknown instruction.
     600       27492 :     if (ASMJIT_UNLIKELY(instId == 0))
     601           0 :       goto InvalidInstruction;
     602             : 
     603             :     // Grow request, happens rarely.
     604             :     err = writer.ensureSpace(this, 16);
     605       27492 :     if (ASMJIT_UNLIKELY(err))
     606           0 :       goto Failed;
     607             : 
     608             : #ifndef ASMJIT_NO_VALIDATION
     609             :     // Strict validation.
     610       27492 :     if (hasDiagnosticOption(DiagnosticOptions::kValidateAssembler)) {
     611             :       Operand_ opArray[Globals::kMaxOpCount];
     612             :       EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
     613             : 
     614           0 :       err = _funcs.validate(arch(), BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount, ValidationFlags::kNone);
     615           0 :       if (ASMJIT_UNLIKELY(err))
     616           0 :         goto Failed;
     617             :     }
     618             : #endif
     619             : 
     620             :     InstDB::InstFlags iFlags = instInfo->flags();
     621             : 
     622             :     // LOCK, XACQUIRE, and XRELEASE prefixes.
     623       27492 :     if (Support::test(options, InstOptions::kX86_Lock)) {
     624             :       bool xAcqRel = Support::test(options, InstOptions::kX86_XAcquire | InstOptions::kX86_XRelease);
     625             : 
     626           0 :       if (ASMJIT_UNLIKELY(!Support::test(iFlags, InstDB::InstFlags::kLock) && !xAcqRel))
     627           0 :         goto InvalidLockPrefix;
     628             : 
     629           0 :       if (xAcqRel) {
     630           0 :         if (ASMJIT_UNLIKELY(Support::test(options, InstOptions::kX86_XAcquire) && !Support::test(iFlags, InstDB::InstFlags::kXAcquire)))
     631           0 :           goto InvalidXAcquirePrefix;
     632             : 
     633           0 :         if (ASMJIT_UNLIKELY(Support::test(options, InstOptions::kX86_XRelease) && !Support::test(iFlags, InstDB::InstFlags::kXRelease)))
     634           0 :           goto InvalidXReleasePrefix;
     635             : 
     636           0 :         writer.emit8(Support::test(options, InstOptions::kX86_XAcquire) ? 0xF2 : 0xF3);
     637             :       }
     638             : 
     639             :       writer.emit8(0xF0);
     640             :     }
     641             : 
     642             :     // REP and REPNE prefixes.
     643       27492 :     if (Support::test(options, InstOptions::kX86_Rep | InstOptions::kX86_Repne)) {
     644           0 :       if (ASMJIT_UNLIKELY(!Support::test(iFlags, InstDB::InstFlags::kRep)))
     645           0 :         goto InvalidRepPrefix;
     646             : 
     647           0 :       if (ASMJIT_UNLIKELY(_extraReg.isReg() && (_extraReg.group() != RegGroup::kGp || _extraReg.id() != Gp::kIdCx)))
     648           0 :         goto InvalidRepPrefix;
     649             : 
     650           0 :       writer.emit8(Support::test(options, InstOptions::kX86_Repne) ? 0xF2 : 0xF3);
     651             :     }
     652             :   }
     653             : 
     654             :   // This sequence seems to be the fastest.
     655      392009 :   opcode = InstDB::_mainOpcodeTable[instInfo->_mainOpcodeIndex];
     656             :   opReg = opcode.extractModO();
     657             :   rbReg = 0;
     658      392009 :   opcode |= instInfo->_mainOpcodeValue;
     659             : 
     660             :   // Encoding Scope
     661             :   // --------------
     662             : 
     663             :   // How it works? Each case here represents a unique encoding of a group of instructions, which is handled
     664             :   // separately. The handlers check instruction signature, possibly register types, etc, and process this
     665             :   // information by writing some bits to opcode, opReg/rbReg, immValue/immSize, etc, and then at the end of
     666             :   // the sequence it uses goto to jump into a lower level handler, that actually encodes the instruction.
     667             : 
     668      392009 :   switch (instInfo->_encoding) {
     669           0 :     case InstDB::kEncodingNone:
     670           0 :       goto EmitDone;
     671             : 
     672             :     // Base Instructions
     673             :     // -----------------
     674             : 
     675           0 :     case InstDB::kEncodingX86Op:
     676           0 :       goto EmitX86Op;
     677             : 
     678             :     case InstDB::kEncodingX86Op_Mod11RM:
     679             :       rbReg = opcode.extractModRM();
     680           0 :       goto EmitX86R;
     681             : 
     682             :     case InstDB::kEncodingX86Op_Mod11RM_I8:
     683             :       // The first operand must be immediate, we don't care of other operands as they could be implicit.
     684           0 :       if (!o0.isImm())
     685           0 :         goto InvalidInstruction;
     686             : 
     687             :       rbReg = opcode.extractModRM();
     688           0 :       immValue = o0.as<Imm>().valueAs<uint8_t>();
     689             :       immSize = 1;
     690           0 :       goto EmitX86R;
     691             : 
     692             :     case InstDB::kEncodingX86Op_xAddr:
     693           0 :       if (ASMJIT_UNLIKELY(!o0.isReg()))
     694           0 :         goto InvalidInstruction;
     695             : 
     696           0 :       rmInfo = x86MemInfo[size_t(o0.as<Reg>().type())];
     697           0 :       writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
     698           0 :       goto EmitX86Op;
     699             : 
     700           0 :     case InstDB::kEncodingX86Op_xAX:
     701           0 :       if (isign3 == 0)
     702           0 :         goto EmitX86Op;
     703             : 
     704           0 :       if (isign3 == ENC_OPS1(Reg) && o0.id() == Gp::kIdAx)
     705           0 :         goto EmitX86Op;
     706             :       break;
     707             : 
     708           0 :     case InstDB::kEncodingX86Op_xDX_xAX:
     709           0 :       if (isign3 == 0)
     710           0 :         goto EmitX86Op;
     711             : 
     712           0 :       if (isign3 == ENC_OPS2(Reg, Reg) && o0.id() == Gp::kIdDx && o1.id() == Gp::kIdAx)
     713           0 :         goto EmitX86Op;
     714             :       break;
     715             : 
     716           0 :     case InstDB::kEncodingX86Op_MemZAX:
     717           0 :       if (isign3 == 0)
     718           0 :         goto EmitX86Op;
     719             : 
     720             :       rmRel = &o0;
     721           0 :       if (isign3 == ENC_OPS1(Mem) && x86IsImplicitMem(o0, Gp::kIdAx))
     722           0 :         goto EmitX86OpImplicitMem;
     723             : 
     724             :       break;
     725             : 
     726           0 :     case InstDB::kEncodingX86I_xAX:
     727             :       // Implicit form.
     728           0 :       if (isign3 == ENC_OPS1(Imm)) {
     729           0 :         immValue = o0.as<Imm>().valueAs<uint8_t>();
     730             :         immSize = 1;
     731           0 :         goto EmitX86Op;
     732             :       }
     733             : 
     734             :       // Explicit form.
     735           0 :       if (isign3 == ENC_OPS2(Reg, Imm) && o0.id() == Gp::kIdAx) {
     736           0 :         immValue = o1.as<Imm>().valueAs<uint8_t>();
     737             :         immSize = 1;
     738           0 :         goto EmitX86Op;
     739             :       }
     740             :       break;
     741             : 
     742             :     case InstDB::kEncodingX86M_NoMemSize:
     743           0 :       if (o0.isReg())
     744             :         opcode.addPrefixBySize(o0.size());
     745           0 :       goto CaseX86M_NoSize;
     746             : 
     747             :     case InstDB::kEncodingX86M:
     748             :       opcode.addPrefixBySize(o0.size());
     749             :       ASMJIT_FALLTHROUGH;
     750             : 
     751             :     case InstDB::kEncodingX86M_NoSize:
     752           0 : CaseX86M_NoSize:
     753             :       rbReg = o0.id();
     754           0 :       if (isign3 == ENC_OPS1(Reg))
     755           0 :         goto EmitX86R;
     756             : 
     757             :       rmRel = &o0;
     758           0 :       if (isign3 == ENC_OPS1(Mem))
     759           0 :         goto EmitX86M;
     760             :       break;
     761             : 
     762             :     case InstDB::kEncodingX86M_GPB_MulDiv:
     763           0 : CaseX86M_GPB_MulDiv:
     764             :       // Explicit form?
     765           0 :       if (isign3 > 0x7) {
     766             :         // [AX] <- [AX] div|mul r8.
     767           0 :         if (isign3 == ENC_OPS2(Reg, Reg)) {
     768           0 :           if (ASMJIT_UNLIKELY(!Reg::isGpw(o0, Gp::kIdAx) || !Reg::isGpb(o1)))
     769           0 :             goto InvalidInstruction;
     770             : 
     771             :           rbReg = o1.id();
     772           0 :           FIXUP_GPB(o1, rbReg);
     773           0 :           goto EmitX86R;
     774             :         }
     775             : 
     776             :         // [AX] <- [AX] div|mul m8.
     777           0 :         if (isign3 == ENC_OPS2(Reg, Mem)) {
     778           0 :           if (ASMJIT_UNLIKELY(!Reg::isGpw(o0, Gp::kIdAx)))
     779           0 :             goto InvalidInstruction;
     780             : 
     781             :           rmRel = &o1;
     782           0 :           goto EmitX86M;
     783             :         }
     784             : 
     785             :         // [?DX:?AX] <- [?DX:?AX] div|mul r16|r32|r64
     786           0 :         if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
     787           0 :           if (ASMJIT_UNLIKELY(o0.size() != o1.size()))
     788           0 :             goto InvalidInstruction;
     789             : 
     790             :           opcode.addArithBySize(o0.size());
     791             :           rbReg = o2.id();
     792           0 :           goto EmitX86R;
     793             :         }
     794             : 
     795             :         // [?DX:?AX] <- [?DX:?AX] div|mul m16|m32|m64
     796           0 :         if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
     797           0 :           if (ASMJIT_UNLIKELY(o0.size() != o1.size()))
     798           0 :             goto InvalidInstruction;
     799             : 
     800             :           opcode.addArithBySize(o0.size());
     801             :           rmRel = &o2;
     802           0 :           goto EmitX86M;
     803             :         }
     804             : 
     805           0 :         goto InvalidInstruction;
     806             :       }
     807             : 
     808             :       ASMJIT_FALLTHROUGH;
     809             : 
     810             :     case InstDB::kEncodingX86M_GPB:
     811           0 :       if (isign3 == ENC_OPS1(Reg)) {
     812             :         opcode.addArithBySize(o0.size());
     813             :         rbReg = o0.id();
     814             : 
     815           0 :         if (o0.size() != 1)
     816           0 :           goto EmitX86R;
     817             : 
     818           0 :         FIXUP_GPB(o0, rbReg);
     819           0 :         goto EmitX86R;
     820             :       }
     821             : 
     822           0 :       if (isign3 == ENC_OPS1(Mem)) {
     823           0 :         if (ASMJIT_UNLIKELY(o0.size() == 0))
     824           0 :           goto AmbiguousOperandSize;
     825             : 
     826             :         opcode.addArithBySize(o0.size());
     827             :         rmRel = &o0;
     828           0 :         goto EmitX86M;
     829             :       }
     830             :       break;
     831             : 
     832           0 :     case InstDB::kEncodingX86M_Only_EDX_EAX:
     833           0 :       if (isign3 == ENC_OPS3(Mem, Reg, Reg) && Reg::isGpd(o1, Gp::kIdDx) && Reg::isGpd(o2, Gp::kIdAx)) {
     834             :         rmRel = &o0;
     835           0 :         goto EmitX86M;
     836             :       }
     837             :       ASMJIT_FALLTHROUGH;
     838             : 
     839             :     case InstDB::kEncodingX86M_Only:
     840           0 :       if (isign3 == ENC_OPS1(Mem)) {
     841             :         rmRel = &o0;
     842           0 :         goto EmitX86M;
     843             :       }
     844             :       break;
     845             : 
     846           0 :     case InstDB::kEncodingX86M_Nop:
     847           0 :       if (isign3 == ENC_OPS1(None))
     848           0 :         goto EmitX86Op;
     849             : 
     850             :       // Single operand NOP instruction "0F 1F /0".
     851             :       opcode = Opcode::k000F00 | 0x1F;
     852             :       opReg = 0;
     853             : 
     854           0 :       if (isign3 == ENC_OPS1(Reg)) {
     855             :         opcode.addPrefixBySize(o0.size());
     856             :         rbReg = o0.id();
     857           0 :         goto EmitX86R;
     858             :       }
     859             : 
     860           0 :       if (isign3 == ENC_OPS1(Mem)) {
     861             :         opcode.addPrefixBySize(o0.size());
     862             :         rmRel = &o0;
     863           0 :         goto EmitX86M;
     864             :       }
     865             : 
     866             :       // Two operand NOP instruction "0F 1F /r".
     867             :       opReg = o1.id();
     868             :       opcode.addPrefixBySize(o1.size());
     869             : 
     870           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
     871             :         rbReg = o0.id();
     872           0 :         goto EmitX86R;
     873             :       }
     874             : 
     875           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
     876             :         rmRel = &o0;
     877           0 :         goto EmitX86M;
     878             :       }
     879             :       break;
     880             : 
     881           0 :     case InstDB::kEncodingX86R_FromM:
     882           0 :       if (isign3 == ENC_OPS1(Mem)) {
     883             :         rmRel = &o0;
     884             :         rbReg = o0.id();
     885           0 :         goto EmitX86RFromM;
     886             :       }
     887             :       break;
     888             : 
     889           0 :     case InstDB::kEncodingX86R32_EDX_EAX:
     890             :       // Explicit form: R32, EDX, EAX.
     891           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
     892           0 :         if (!Reg::isGpd(o1, Gp::kIdDx) || !Reg::isGpd(o2, Gp::kIdAx))
     893           0 :           goto InvalidInstruction;
     894             :         rbReg = o0.id();
     895           0 :         goto EmitX86R;
     896             :       }
     897             : 
     898             :       // Implicit form: R32.
     899           0 :       if (isign3 == ENC_OPS1(Reg)) {
     900           0 :         if (!Reg::isGpd(o0))
     901           0 :           goto InvalidInstruction;
     902             :         rbReg = o0.id();
     903           0 :         goto EmitX86R;
     904             :       }
     905             :       break;
     906             : 
     907           0 :     case InstDB::kEncodingX86R_Native:
     908           0 :       if (isign3 == ENC_OPS1(Reg)) {
     909             :         rbReg = o0.id();
     910           0 :         goto EmitX86R;
     911             :       }
     912             :       break;
     913             : 
     914             :     case InstDB::kEncodingX86Rm:
     915             :       opcode.addPrefixBySize(o0.size());
     916             :       ASMJIT_FALLTHROUGH;
     917             : 
     918           0 :     case InstDB::kEncodingX86Rm_NoSize:
     919           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
     920             :         opReg = o0.id();
     921             :         rbReg = o1.id();
     922           0 :         goto EmitX86R;
     923             :       }
     924             : 
     925           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
     926             :         opReg = o0.id();
     927             :         rmRel = &o1;
     928           0 :         goto EmitX86M;
     929             :       }
     930             :       break;
     931             : 
     932           0 :     case InstDB::kEncodingX86Rm_Raw66H:
     933             :       // We normally emit either [66|F2|F3], this instruction requires 66+[F2|F3].
     934           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
     935             :         opReg = o0.id();
     936             :         rbReg = o1.id();
     937             : 
     938           0 :         if (o0.size() == 2)
     939             :           writer.emit8(0x66);
     940             :         else
     941             :           opcode.addWBySize(o0.size());
     942           0 :         goto EmitX86R;
     943             :       }
     944             : 
     945           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
     946             :         opReg = o0.id();
     947             :         rmRel = &o1;
     948             : 
     949           0 :         if (o0.size() == 2)
     950             :           writer.emit8(0x66);
     951             :         else
     952             :           opcode.addWBySize(o0.size());
     953           0 :         goto EmitX86M;
     954             :       }
     955             :       break;
     956             : 
     957             :     case InstDB::kEncodingX86Mr:
     958             :       opcode.addPrefixBySize(o0.size());
     959             :       ASMJIT_FALLTHROUGH;
     960             : 
     961           0 :     case InstDB::kEncodingX86Mr_NoSize:
     962           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
     963             :         rbReg = o0.id();
     964             :         opReg = o1.id();
     965           0 :         goto EmitX86R;
     966             :       }
     967             : 
     968           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
     969             :         rmRel = &o0;
     970             :         opReg = o1.id();
     971           0 :         goto EmitX86M;
     972             :       }
     973             :       break;
     974             : 
     975        9980 :     case InstDB::kEncodingX86Arith:
     976             :       if (isign3 == ENC_OPS2(Reg, Reg)) {
     977             :         opcode.addArithBySize(o0.size());
     978             : 
     979           0 :         if (o0.size() != o1.size())
     980           0 :           goto OperandSizeMismatch;
     981             : 
     982             :         rbReg = o0.id();
     983             :         opReg = o1.id();
     984             : 
     985           0 :         if (o0.size() == 1) {
     986           0 :           FIXUP_GPB(o0, rbReg);
     987           0 :           FIXUP_GPB(o1, opReg);
     988             :         }
     989             : 
     990             :         // MOD/MR: The default encoding used if not instructed otherwise..
     991           0 :         if (!Support::test(options, InstOptions::kX86_ModRM))
     992           0 :           goto EmitX86R;
     993             : 
     994             :         // MOD/RM: Alternative encoding selected via instruction options.
     995             :         opcode += 2;
     996             :         std::swap(opReg, rbReg);
     997           0 :         goto EmitX86R;
     998             :       }
     999             : 
    1000             :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    1001             :         opcode += 2;
    1002             :         opcode.addArithBySize(o0.size());
    1003             : 
    1004             :         opReg = o0.id();
    1005             :         rmRel = &o1;
    1006             : 
    1007           0 :         if (o0.size() != 1)
    1008           0 :           goto EmitX86M;
    1009             : 
    1010           0 :         FIXUP_GPB(o0, opReg);
    1011           0 :         goto EmitX86M;
    1012             :       }
    1013             : 
    1014             :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    1015             :         opcode.addArithBySize(o1.size());
    1016             :         opReg = o1.id();
    1017             :         rmRel = &o0;
    1018             : 
    1019           0 :         if (o1.size() != 1)
    1020           0 :           goto EmitX86M;
    1021             : 
    1022           0 :         FIXUP_GPB(o1, opReg);
    1023           0 :         goto EmitX86M;
    1024             :       }
    1025             : 
    1026             :       // The remaining instructions use 0x80 opcode.
    1027             :       opcode = 0x80;
    1028             : 
    1029             :       if (isign3 == ENC_OPS2(Reg, Imm)) {
    1030             :         uint32_t size = o0.size();
    1031             : 
    1032             :         rbReg = o0.id();
    1033             :         immValue = o1.as<Imm>().value();
    1034             : 
    1035        9980 :         if (size == 1) {
    1036           0 :           FIXUP_GPB(o0, rbReg);
    1037             :           immSize = 1;
    1038             :         }
    1039             :         else {
    1040        9980 :           if (size == 2) {
    1041             :             opcode |= Opcode::kPP_66;
    1042             :           }
    1043        9980 :           else if (size == 4) {
    1044             :             // Sign extend so isInt8 returns the right result.
    1045             :             immValue = x86SignExtendI32<int64_t>(immValue);
    1046             :           }
    1047        9980 :           else if (size == 8) {
    1048        9980 :             bool canTransformTo32Bit = instId == Inst::kIdAnd && Support::isUInt32(immValue);
    1049             : 
    1050             :             if (!Support::isInt32(immValue)) {
    1051             :               // We would do this by default when `kOptionOptimizedForSize` is
    1052             :               // enabled, however, in this case we just force this as otherwise
    1053             :               // we would have to fail.
    1054           0 :               if (canTransformTo32Bit)
    1055             :                 size = 4;
    1056             :               else
    1057           0 :                 goto InvalidImmediate;
    1058             :             }
    1059        9980 :             else if (canTransformTo32Bit && hasEncodingOption(EncodingOptions::kOptimizeForSize)) {
    1060             :               size = 4;
    1061             :             }
    1062             : 
    1063             :             opcode.addWBySize(size);
    1064             :           }
    1065             : 
    1066        9980 :           immSize = FastUInt8(Support::min<uint32_t>(size, 4));
    1067        9224 :           if (Support::isInt8(immValue) && !Support::test(options, InstOptions::kLongForm))
    1068             :             immSize = 1;
    1069             :         }
    1070             : 
    1071             :         // Short form - AL, AX, EAX, RAX.
    1072        9980 :         if (rbReg == 0 && (size == 1 || immSize != 1) && !Support::test(options, InstOptions::kLongForm)) {
    1073             :           opcode &= Opcode::kPP_66 | Opcode::kW;
    1074           0 :           opcode |= ((opReg << 3) | (0x04 + (size != 1)));
    1075           0 :           immSize = FastUInt8(Support::min<uint32_t>(size, 4));
    1076           0 :           goto EmitX86Op;
    1077             :         }
    1078             : 
    1079        9980 :         opcode += size != 1 ? (immSize != 1 ? 1 : 3) : 0;
    1080        9980 :         goto EmitX86R;
    1081             :       }
    1082             : 
    1083             :       if (isign3 == ENC_OPS2(Mem, Imm)) {
    1084             :         uint32_t memSize = o0.size();
    1085             : 
    1086           0 :         if (ASMJIT_UNLIKELY(memSize == 0))
    1087           0 :           goto AmbiguousOperandSize;
    1088             : 
    1089             :         immValue = o1.as<Imm>().value();
    1090           0 :         immSize = FastUInt8(Support::min<uint32_t>(memSize, 4));
    1091             : 
    1092             :         // Sign extend so isInt8 returns the right result.
    1093           0 :         if (memSize == 4)
    1094             :           immValue = x86SignExtendI32<int64_t>(immValue);
    1095             : 
    1096           0 :         if (Support::isInt8(immValue) && !Support::test(options, InstOptions::kLongForm))
    1097             :           immSize = 1;
    1098             : 
    1099           0 :         opcode += memSize != 1 ? (immSize != 1 ? 1 : 3) : 0;
    1100             :         opcode.addPrefixBySize(memSize);
    1101             : 
    1102             :         rmRel = &o0;
    1103           0 :         goto EmitX86M;
    1104             :       }
    1105             :       break;
    1106             : 
    1107           0 :     case InstDB::kEncodingX86Bswap:
    1108           0 :       if (isign3 == ENC_OPS1(Reg)) {
    1109           0 :         if (ASMJIT_UNLIKELY(o0.size() == 1))
    1110           0 :           goto InvalidInstruction;
    1111             : 
    1112             :         opReg = o0.id();
    1113             :         opcode.addPrefixBySize(o0.size());
    1114           0 :         goto EmitX86OpReg;
    1115             :       }
    1116             :       break;
    1117             : 
    1118           0 :     case InstDB::kEncodingX86Bt:
    1119           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    1120             :         opcode.addPrefixBySize(o1.size());
    1121             :         opReg = o1.id();
    1122             :         rbReg = o0.id();
    1123           0 :         goto EmitX86R;
    1124             :       }
    1125             : 
    1126           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    1127             :         opcode.addPrefixBySize(o1.size());
    1128             :         opReg = o1.id();
    1129             :         rmRel = &o0;
    1130           0 :         goto EmitX86M;
    1131             :       }
    1132             : 
    1133             :       // The remaining instructions use the secondary opcode/r.
    1134             :       immValue = o1.as<Imm>().value();
    1135             :       immSize = 1;
    1136             : 
    1137             :       opcode = x86AltOpcodeOf(instInfo);
    1138             :       opcode.addPrefixBySize(o0.size());
    1139             :       opReg = opcode.extractModO();
    1140             : 
    1141           0 :       if (isign3 == ENC_OPS2(Reg, Imm)) {
    1142             :         rbReg = o0.id();
    1143           0 :         goto EmitX86R;
    1144             :       }
    1145             : 
    1146           0 :       if (isign3 == ENC_OPS2(Mem, Imm)) {
    1147           0 :         if (ASMJIT_UNLIKELY(o0.size() == 0))
    1148           0 :           goto AmbiguousOperandSize;
    1149             : 
    1150             :         rmRel = &o0;
    1151           0 :         goto EmitX86M;
    1152             :       }
    1153             :       break;
    1154             : 
    1155        9639 :     case InstDB::kEncodingX86Call:
    1156        9639 :       if (isign3 == ENC_OPS1(Reg)) {
    1157             :         rbReg = o0.id();
    1158        9639 :         goto EmitX86R;
    1159             :       }
    1160             : 
    1161             :       rmRel = &o0;
    1162           0 :       if (isign3 == ENC_OPS1(Mem))
    1163           0 :         goto EmitX86M;
    1164             : 
    1165             :       // Call with 32-bit displacement use 0xE8 opcode. Call with 8-bit displacement is not encodable so the
    1166             :       // alternative opcode field in X86DB must be zero.
    1167             :       opcode = 0xE8;
    1168             :       opReg = 0;
    1169           0 :       goto EmitJmpCall;
    1170             : 
    1171           0 :     case InstDB::kEncodingX86Cmpxchg: {
    1172             :       // Convert explicit to implicit.
    1173           0 :       if (isign3 & (0x7 << 6)) {
    1174           0 :         if (!Reg::isGp(o2) || o2.id() != Gp::kIdAx)
    1175           0 :           goto InvalidInstruction;
    1176           0 :         isign3 &= 0x3F;
    1177             :       }
    1178             : 
    1179           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    1180           0 :         if (o0.size() != o1.size())
    1181           0 :           goto OperandSizeMismatch;
    1182             : 
    1183             :         opcode.addArithBySize(o0.size());
    1184             :         rbReg = o0.id();
    1185             :         opReg = o1.id();
    1186             : 
    1187           0 :         if (o0.size() != 1)
    1188           0 :           goto EmitX86R;
    1189             : 
    1190           0 :         FIXUP_GPB(o0, rbReg);
    1191           0 :         FIXUP_GPB(o1, opReg);
    1192           0 :         goto EmitX86R;
    1193             :       }
    1194             : 
    1195           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    1196             :         opcode.addArithBySize(o1.size());
    1197             :         opReg = o1.id();
    1198             :         rmRel = &o0;
    1199             : 
    1200           0 :         if (o1.size() != 1)
    1201           0 :           goto EmitX86M;
    1202             : 
    1203           0 :         FIXUP_GPB(o1, opReg);
    1204           0 :         goto EmitX86M;
    1205             :       }
    1206             :       break;
    1207             :     }
    1208             : 
    1209           0 :     case InstDB::kEncodingX86Cmpxchg8b_16b: {
    1210             :       const Operand_& o3 = opExt[EmitterUtils::kOp3];
    1211             :       const Operand_& o4 = opExt[EmitterUtils::kOp4];
    1212             : 
    1213           0 :       if (isign3 == ENC_OPS3(Mem, Reg, Reg)) {
    1214           0 :         if (o3.isReg() && o4.isReg()) {
    1215             :           rmRel = &o0;
    1216           0 :           goto EmitX86M;
    1217             :         }
    1218             :       }
    1219             : 
    1220           0 :       if (isign3 == ENC_OPS1(Mem)) {
    1221             :         rmRel = &o0;
    1222           0 :         goto EmitX86M;
    1223             :       }
    1224             :       break;
    1225             :     }
    1226             : 
    1227             :     case InstDB::kEncodingX86Crc:
    1228             :       opReg = o0.id();
    1229             :       opcode.addWBySize(o0.size());
    1230             : 
    1231           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    1232             :         rbReg = o1.id();
    1233             : 
    1234           0 :         if (o1.size() == 1) {
    1235           0 :           FIXUP_GPB(o1, rbReg);
    1236           0 :           goto EmitX86R;
    1237             :         }
    1238             :         else {
    1239             :           // This seems to be the only exception of encoding '66F2' prefix.
    1240           0 :           if (o1.size() == 2) writer.emit8(0x66);
    1241             : 
    1242             :           opcode.add(1);
    1243           0 :           goto EmitX86R;
    1244             :         }
    1245             :       }
    1246             : 
    1247           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    1248             :         rmRel = &o1;
    1249           0 :         if (o1.size() == 0)
    1250           0 :           goto AmbiguousOperandSize;
    1251             : 
    1252             :         // This seems to be the only exception of encoding '66F2' prefix.
    1253           0 :         if (o1.size() == 2) writer.emit8(0x66);
    1254             : 
    1255           0 :         opcode += o1.size() != 1;
    1256           0 :         goto EmitX86M;
    1257             :       }
    1258             :       break;
    1259             : 
    1260           0 :     case InstDB::kEncodingX86Enter:
    1261           0 :       if (isign3 == ENC_OPS2(Imm, Imm)) {
    1262           0 :         uint32_t iw = o0.as<Imm>().valueAs<uint16_t>();
    1263           0 :         uint32_t ib = o1.as<Imm>().valueAs<uint8_t>();
    1264             : 
    1265           0 :         immValue = iw | (ib << 16);
    1266             :         immSize = 3;
    1267           0 :         goto EmitX86Op;
    1268             :       }
    1269             :       break;
    1270             : 
    1271           0 :     case InstDB::kEncodingX86Imul:
    1272             :       // First process all forms distinct of `kEncodingX86M_OptB_MulDiv`.
    1273           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    1274             :         opcode = 0x6B;
    1275             :         opcode.addPrefixBySize(o0.size());
    1276             : 
    1277             :         immValue = o2.as<Imm>().value();
    1278             :         immSize = 1;
    1279             : 
    1280           0 :         if (!Support::isInt8(immValue) || Support::test(options, InstOptions::kLongForm)) {
    1281             :           opcode -= 2;
    1282           0 :           immSize = o0.size() == 2 ? 2 : 4;
    1283             :         }
    1284             : 
    1285             :         opReg = o0.id();
    1286             :         rbReg = o1.id();
    1287             : 
    1288           0 :         goto EmitX86R;
    1289             :       }
    1290             : 
    1291           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
    1292             :         opcode = 0x6B;
    1293             :         opcode.addPrefixBySize(o0.size());
    1294             : 
    1295             :         immValue = o2.as<Imm>().value();
    1296             :         immSize = 1;
    1297             : 
    1298             :         // Sign extend so isInt8 returns the right result.
    1299           0 :         if (o0.size() == 4)
    1300             :           immValue = x86SignExtendI32<int64_t>(immValue);
    1301             : 
    1302           0 :         if (!Support::isInt8(immValue) || Support::test(options, InstOptions::kLongForm)) {
    1303             :           opcode -= 2;
    1304           0 :           immSize = o0.size() == 2 ? 2 : 4;
    1305             :         }
    1306             : 
    1307             :         opReg = o0.id();
    1308             :         rmRel = &o1;
    1309             : 
    1310           0 :         goto EmitX86M;
    1311             :       }
    1312             : 
    1313           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    1314             :         // Must be explicit 'ax, r8' form.
    1315           0 :         if (o1.size() == 1)
    1316           0 :           goto CaseX86M_GPB_MulDiv;
    1317             : 
    1318           0 :         if (o0.size() != o1.size())
    1319           0 :           goto OperandSizeMismatch;
    1320             : 
    1321             :         opReg = o0.id();
    1322             :         rbReg = o1.id();
    1323             : 
    1324             :         opcode = Opcode::k000F00 | 0xAF;
    1325             :         opcode.addPrefixBySize(o0.size());
    1326           0 :         goto EmitX86R;
    1327             :       }
    1328             : 
    1329           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    1330             :         // Must be explicit 'ax, m8' form.
    1331           0 :         if (o1.size() == 1)
    1332           0 :           goto CaseX86M_GPB_MulDiv;
    1333             : 
    1334             :         opReg = o0.id();
    1335             :         rmRel = &o1;
    1336             : 
    1337             :         opcode = Opcode::k000F00 | 0xAF;
    1338             :         opcode.addPrefixBySize(o0.size());
    1339           0 :         goto EmitX86M;
    1340             :       }
    1341             : 
    1342             :       // Shorthand to imul 'reg, reg, imm'.
    1343           0 :       if (isign3 == ENC_OPS2(Reg, Imm)) {
    1344             :         opcode = 0x6B;
    1345             :         opcode.addPrefixBySize(o0.size());
    1346             : 
    1347             :         immValue = o1.as<Imm>().value();
    1348             :         immSize = 1;
    1349             : 
    1350             :         // Sign extend so isInt8 returns the right result.
    1351           0 :         if (o0.size() == 4)
    1352             :           immValue = x86SignExtendI32<int64_t>(immValue);
    1353             : 
    1354           0 :         if (!Support::isInt8(immValue) || Support::test(options, InstOptions::kLongForm)) {
    1355             :           opcode -= 2;
    1356           0 :           immSize = o0.size() == 2 ? 2 : 4;
    1357             :         }
    1358             : 
    1359             :         opReg = rbReg = o0.id();
    1360           0 :         goto EmitX86R;
    1361             :       }
    1362             : 
    1363             :       // Try implicit form.
    1364           0 :       goto CaseX86M_GPB_MulDiv;
    1365             : 
    1366           0 :     case InstDB::kEncodingX86In:
    1367           0 :       if (isign3 == ENC_OPS2(Reg, Imm)) {
    1368           0 :         if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdAx))
    1369           0 :           goto InvalidInstruction;
    1370             : 
    1371           0 :         immValue = o1.as<Imm>().valueAs<uint8_t>();
    1372             :         immSize = 1;
    1373             : 
    1374           0 :         opcode = x86AltOpcodeOf(instInfo) + (o0.size() != 1);
    1375             :         opcode.add66hBySize(o0.size());
    1376           0 :         goto EmitX86Op;
    1377             :       }
    1378             : 
    1379           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    1380           0 :         if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdAx || o1.id() != Gp::kIdDx))
    1381           0 :           goto InvalidInstruction;
    1382             : 
    1383           0 :         opcode += o0.size() != 1;
    1384             :         opcode.add66hBySize(o0.size());
    1385           0 :         goto EmitX86Op;
    1386             :       }
    1387             :       break;
    1388             : 
    1389           0 :     case InstDB::kEncodingX86Ins:
    1390           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    1391           0 :         if (ASMJIT_UNLIKELY(!x86IsImplicitMem(o0, Gp::kIdDi) || o1.id() != Gp::kIdDx))
    1392           0 :           goto InvalidInstruction;
    1393             : 
    1394             :         uint32_t size = o0.size();
    1395           0 :         if (ASMJIT_UNLIKELY(size == 0))
    1396           0 :           goto AmbiguousOperandSize;
    1397             : 
    1398             :         rmRel = &o0;
    1399           0 :         opcode += (size != 1);
    1400             : 
    1401             :         opcode.add66hBySize(size);
    1402           0 :         goto EmitX86OpImplicitMem;
    1403             :       }
    1404             :       break;
    1405             : 
    1406           0 :     case InstDB::kEncodingX86IncDec:
    1407           0 :       if (isign3 == ENC_OPS1(Reg)) {
    1408             :         rbReg = o0.id();
    1409             : 
    1410           0 :         if (o0.size() == 1) {
    1411           0 :           FIXUP_GPB(o0, rbReg);
    1412           0 :           goto EmitX86R;
    1413             :         }
    1414             : 
    1415           0 :         if (is32Bit()) {
    1416             :           // INC r16|r32 is only encodable in 32-bit mode (collides with REX).
    1417           0 :           opcode = x86AltOpcodeOf(instInfo) + (rbReg & 0x07);
    1418             :           opcode.add66hBySize(o0.size());
    1419           0 :           goto EmitX86Op;
    1420             :         }
    1421             :         else {
    1422             :           opcode.addArithBySize(o0.size());
    1423           0 :           goto EmitX86R;
    1424             :         }
    1425             :       }
    1426             : 
    1427           0 :       if (isign3 == ENC_OPS1(Mem)) {
    1428           0 :         if (!o0.size())
    1429           0 :           goto AmbiguousOperandSize;
    1430             :         opcode.addArithBySize(o0.size());
    1431             :         rmRel = &o0;
    1432           0 :         goto EmitX86M;
    1433             :       }
    1434             :       break;
    1435             : 
    1436           0 :     case InstDB::kEncodingX86Int:
    1437           0 :       if (isign3 == ENC_OPS1(Imm)) {
    1438             :         immValue = o0.as<Imm>().value();
    1439             :         immSize = 1;
    1440           0 :         goto EmitX86Op;
    1441             :       }
    1442             :       break;
    1443             : 
    1444           0 :     case InstDB::kEncodingX86Jcc:
    1445           0 :       if (Support::test(options, InstOptions::kTaken | InstOptions::kNotTaken) && hasEncodingOption(EncodingOptions::kPredictedJumps)) {
    1446           0 :         uint8_t prefix = Support::test(options, InstOptions::kTaken) ? uint8_t(0x3E) : uint8_t(0x2E);
    1447             :         writer.emit8(prefix);
    1448             :       }
    1449             : 
    1450             :       rmRel = &o0;
    1451             :       opReg = 0;
    1452           0 :       goto EmitJmpCall;
    1453             : 
    1454           0 :     case InstDB::kEncodingX86JecxzLoop:
    1455             :       rmRel = &o0;
    1456             :       // Explicit jecxz|loop [r|e]cx, dst
    1457           0 :       if (o0.isReg()) {
    1458           0 :         if (ASMJIT_UNLIKELY(!Reg::isGp(o0, Gp::kIdCx)))
    1459           0 :           goto InvalidInstruction;
    1460             : 
    1461           0 :         writer.emitAddressOverride((is32Bit() && o0.size() == 2) || (is64Bit() && o0.size() == 4));
    1462             :         rmRel = &o1;
    1463             :       }
    1464             : 
    1465             :       opReg = 0;
    1466           0 :       goto EmitJmpCall;
    1467             : 
    1468           0 :     case InstDB::kEncodingX86Jmp:
    1469           0 :       if (isign3 == ENC_OPS1(Reg)) {
    1470             :         rbReg = o0.id();
    1471           0 :         goto EmitX86R;
    1472             :       }
    1473             : 
    1474             :       rmRel = &o0;
    1475           0 :       if (isign3 == ENC_OPS1(Mem))
    1476           0 :         goto EmitX86M;
    1477             : 
    1478             :       // Jump encoded with 32-bit displacement use 0xE9 opcode. Jump encoded with 8-bit displacement's opcode is
    1479             :       // stored as an alternative opcode.
    1480             :       opcode = 0xE9;
    1481             :       opReg = 0;
    1482           0 :       goto EmitJmpCall;
    1483             : 
    1484           0 :     case InstDB::kEncodingX86JmpRel:
    1485             :       rmRel = &o0;
    1486           0 :       goto EmitJmpCall;
    1487             : 
    1488           0 :     case InstDB::kEncodingX86LcallLjmp:
    1489           0 :       if (isign3 == ENC_OPS1(Mem)) {
    1490             :         rmRel = &o0;
    1491             :         uint32_t mSize = rmRel->size();
    1492           0 :         if (mSize == 0) {
    1493             :           mSize = registerSize();
    1494             :         }
    1495             :         else {
    1496           0 :           mSize -= 2;
    1497           0 :           if (mSize != 2 && mSize != 4 && mSize != registerSize())
    1498           0 :             goto InvalidAddress;
    1499             :         }
    1500             :         opcode.addPrefixBySize(mSize);
    1501           0 :         goto EmitX86M;
    1502             :       }
    1503             : 
    1504           0 :       if (isign3 == ENC_OPS2(Imm, Imm)) {
    1505           0 :         if (!is32Bit())
    1506           0 :           goto InvalidInstruction;
    1507             : 
    1508             :         const Imm& imm0 = o0.as<Imm>();
    1509             :         const Imm& imm1 = o1.as<Imm>();
    1510             : 
    1511           0 :         if (imm0.value() > 0xFFFFu || imm1.value() > 0xFFFFFFFFu)
    1512           0 :           goto InvalidImmediate;
    1513             : 
    1514             :         opcode = x86AltOpcodeOf(instInfo);
    1515           0 :         immValue = imm1.value() | (imm0.value() << 32);
    1516             :         immSize = 6;
    1517           0 :         goto EmitX86Op;
    1518             :       }
    1519             :       break;
    1520             : 
    1521           0 :     case InstDB::kEncodingX86Lea:
    1522           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    1523             :         opcode.addPrefixBySize(o0.size());
    1524             :         opReg = o0.id();
    1525             :         rmRel = &o1;
    1526           0 :         goto EmitX86M;
    1527             :       }
    1528             :       break;
    1529             : 
    1530       88256 :     case InstDB::kEncodingX86Mov:
    1531             :       // Reg <- Reg
    1532             :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    1533             :         // Asmjit uses segment registers indexed from 1 to 6, leaving zero as "no segment register used". We have to
    1534             :         // fix this (decrement the index of the register) when emitting MOV instructions which move to/from a segment
    1535             :         // register. The segment register is always `opReg`, because the MOV instruction uses either RM or MR encoding.
    1536             : 
    1537             :         // GP <- ??
    1538           0 :         if (Reg::isGp(o0)) {
    1539             :           rbReg = o0.id();
    1540             :           opReg = o1.id();
    1541             : 
    1542             :           // GP <- GP
    1543           0 :           if (Reg::isGp(o1)) {
    1544             :             uint32_t opSize = o0.size();
    1545           0 :             if (opSize != o1.size())
    1546           0 :               goto InvalidInstruction;
    1547             : 
    1548           0 :             if (opSize == 1) {
    1549           0 :               FIXUP_GPB(o0, rbReg);
    1550           0 :               FIXUP_GPB(o1, opReg);
    1551             :               opcode = 0x88;
    1552             : 
    1553           0 :               if (!Support::test(options, InstOptions::kX86_ModRM))
    1554           0 :                 goto EmitX86R;
    1555             : 
    1556             :               opcode += 2;
    1557             :               std::swap(opReg, rbReg);
    1558           0 :               goto EmitX86R;
    1559             :             }
    1560             :             else {
    1561             :               opcode = 0x89;
    1562             :               opcode.addPrefixBySize(opSize);
    1563             : 
    1564           0 :               if (!Support::test(options, InstOptions::kX86_ModRM))
    1565           0 :                 goto EmitX86R;
    1566             : 
    1567             :               opcode += 2;
    1568             :               std::swap(opReg, rbReg);
    1569           0 :               goto EmitX86R;
    1570             :             }
    1571             :           }
    1572             : 
    1573             :           // GP <- SReg
    1574           0 :           if (Reg::isSReg(o1)) {
    1575             :             opcode = 0x8C;
    1576             :             opcode.addPrefixBySize(o0.size());
    1577           0 :             opReg--;
    1578           0 :             goto EmitX86R;
    1579             :           }
    1580             : 
    1581             :           // GP <- CReg
    1582           0 :           if (Reg::isCReg(o1)) {
    1583             :             opcode = Opcode::k000F00 | 0x20;
    1584             : 
    1585             :             // Use `LOCK MOV` in 32-bit mode if CR8+ register is accessed (AMD extension).
    1586           0 :             if ((opReg & 0x8) && is32Bit()) {
    1587             :               writer.emit8(0xF0);
    1588           0 :               opReg &= 0x7;
    1589             :             }
    1590           0 :             goto EmitX86R;
    1591             :           }
    1592             : 
    1593             :           // GP <- DReg
    1594           0 :           if (Reg::isDReg(o1)) {
    1595             :             opcode = Opcode::k000F00 | 0x21;
    1596           0 :             goto EmitX86R;
    1597             :           }
    1598             :         }
    1599             :         else {
    1600             :           opReg = o0.id();
    1601             :           rbReg = o1.id();
    1602             : 
    1603             :           // ?? <- GP
    1604           0 :           if (!Reg::isGp(o1))
    1605           0 :             goto InvalidInstruction;
    1606             : 
    1607             :           // SReg <- GP
    1608           0 :           if (Reg::isSReg(o0)) {
    1609             :             opcode = 0x8E;
    1610             :             opcode.addPrefixBySize(o1.size());
    1611           0 :             opReg--;
    1612           0 :             goto EmitX86R;
    1613             :           }
    1614             : 
    1615             :           // CReg <- GP
    1616           0 :           if (Reg::isCReg(o0)) {
    1617             :             opcode = Opcode::k000F00 | 0x22;
    1618             : 
    1619             :             // Use `LOCK MOV` in 32-bit mode if CR8+ register is accessed (AMD extension).
    1620           0 :             if ((opReg & 0x8) && is32Bit()) {
    1621             :               writer.emit8(0xF0);
    1622           0 :               opReg &= 0x7;
    1623             :             }
    1624           0 :             goto EmitX86R;
    1625             :           }
    1626             : 
    1627             :           // DReg <- GP
    1628           0 :           if (Reg::isDReg(o0)) {
    1629             :             opcode = Opcode::k000F00 | 0x23;
    1630           0 :             goto EmitX86R;
    1631             :           }
    1632             :         }
    1633             : 
    1634           0 :         goto InvalidInstruction;
    1635             :       }
    1636             : 
    1637             :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    1638             :         opReg = o0.id();
    1639             :         rmRel = &o1;
    1640             : 
    1641             :         // SReg <- Mem
    1642          10 :         if (Reg::isSReg(o0)) {
    1643             :           opcode = 0x8E;
    1644             :           opcode.addPrefixBySize(o1.size());
    1645           0 :           opReg--;
    1646           0 :           goto EmitX86M;
    1647             :         }
    1648             :         // Reg <- Mem
    1649             :         else {
    1650             :           opcode = 0;
    1651             :           opcode.addArithBySize(o0.size());
    1652             : 
    1653             :           // Handle a special form of `mov al|ax|eax|rax, [ptr64]` that doesn't use MOD.
    1654          10 :           if (opReg == Gp::kIdAx && !rmRel->as<Mem>().hasBaseOrIndex()) {
    1655           0 :             if (x86ShouldUseMovabs(this, writer, o0.size(), options, rmRel->as<Mem>())) {
    1656             :               opcode += 0xA0;
    1657             :               immValue = rmRel->as<Mem>().offset();
    1658           0 :               goto EmitX86OpMovAbs;
    1659             :             }
    1660             :           }
    1661             : 
    1662          10 :           if (o0.size() == 1)
    1663           0 :             FIXUP_GPB(o0, opReg);
    1664             : 
    1665             :           opcode += 0x8A;
    1666          10 :           goto EmitX86M;
    1667             :         }
    1668             :       }
    1669             : 
    1670             :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    1671             :         opReg = o1.id();
    1672             :         rmRel = &o0;
    1673             : 
    1674             :         // Mem <- SReg
    1675          10 :         if (Reg::isSReg(o1)) {
    1676             :           opcode = 0x8C;
    1677             :           opcode.addPrefixBySize(o0.size());
    1678           0 :           opReg--;
    1679           0 :           goto EmitX86M;
    1680             :         }
    1681             :         // Mem <- Reg
    1682             :         else {
    1683             :           opcode = 0;
    1684             :           opcode.addArithBySize(o1.size());
    1685             : 
    1686             :           // Handle a special form of `mov [ptr64], al|ax|eax|rax` that doesn't use MOD.
    1687          10 :           if (opReg == Gp::kIdAx && !rmRel->as<Mem>().hasBaseOrIndex()) {
    1688           0 :             if (x86ShouldUseMovabs(this, writer, o1.size(), options, rmRel->as<Mem>())) {
    1689             :               opcode += 0xA2;
    1690             :               immValue = rmRel->as<Mem>().offset();
    1691           0 :               goto EmitX86OpMovAbs;
    1692             :             }
    1693             :           }
    1694             : 
    1695          10 :           if (o1.size() == 1)
    1696           0 :             FIXUP_GPB(o1, opReg);
    1697             : 
    1698             :           opcode += 0x88;
    1699          10 :           goto EmitX86M;
    1700             :         }
    1701             :       }
    1702             : 
    1703             :       if (isign3 == ENC_OPS2(Reg, Imm)) {
    1704             :         opReg = o0.id();
    1705       88236 :         immSize = FastUInt8(o0.size());
    1706             : 
    1707       88236 :         if (immSize == 1) {
    1708           0 :           FIXUP_GPB(o0, opReg);
    1709             : 
    1710             :           opcode = 0xB0;
    1711           0 :           immValue = o1.as<Imm>().valueAs<uint8_t>();
    1712           0 :           goto EmitX86OpReg;
    1713             :         }
    1714             :         else {
    1715             :           // 64-bit immediate in 64-bit mode is allowed.
    1716             :           immValue = o1.as<Imm>().value();
    1717             : 
    1718             :           // Optimize the instruction size by using a 32-bit immediate if possible.
    1719       88236 :           if (immSize == 8 && !Support::test(options, InstOptions::kLongForm)) {
    1720       88236 :             if (Support::isUInt32(immValue) && hasEncodingOption(EncodingOptions::kOptimizeForSize)) {
    1721             :               // Zero-extend by using a 32-bit GPD destination instead of a 64-bit GPQ.
    1722             :               immSize = 4;
    1723             :             }
    1724             :             else if (Support::isInt32(immValue)) {
    1725             :               // Sign-extend, uses 'C7 /0' opcode.
    1726             :               rbReg = opReg;
    1727             : 
    1728             :               opcode = Opcode::kW | 0xC7;
    1729             :               opReg = 0;
    1730             : 
    1731             :               immSize = 4;
    1732           0 :               goto EmitX86R;
    1733             :             }
    1734             :           }
    1735             : 
    1736             :           opcode = 0xB8;
    1737             :           opcode.addPrefixBySize(immSize);
    1738       88236 :           goto EmitX86OpReg;
    1739             :         }
    1740             :       }
    1741             : 
    1742             :       if (isign3 == ENC_OPS2(Mem, Imm)) {
    1743             :         uint32_t memSize = o0.size();
    1744           0 :         if (ASMJIT_UNLIKELY(memSize == 0))
    1745           0 :           goto AmbiguousOperandSize;
    1746             : 
    1747           0 :         opcode = 0xC6 + (memSize != 1);
    1748             :         opcode.addPrefixBySize(memSize);
    1749             :         opReg = 0;
    1750             :         rmRel = &o0;
    1751             : 
    1752             :         immValue = o1.as<Imm>().value();
    1753           0 :         immSize = FastUInt8(Support::min<uint32_t>(memSize, 4));
    1754           0 :         goto EmitX86M;
    1755             :       }
    1756             :       break;
    1757             : 
    1758           0 :     case InstDB::kEncodingX86Movabs:
    1759             :       // Reg <- Mem
    1760           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    1761             :         opReg = o0.id();
    1762             :         rmRel = &o1;
    1763             : 
    1764             :         opcode = 0xA0;
    1765             :         opcode.addArithBySize(o0.size());
    1766             : 
    1767           0 :         if (ASMJIT_UNLIKELY(!o0.as<Reg>().isGp()) || opReg != Gp::kIdAx)
    1768           0 :           goto InvalidInstruction;
    1769             : 
    1770           0 :         if (ASMJIT_UNLIKELY(rmRel->as<Mem>().hasBaseOrIndex()))
    1771           0 :           goto InvalidAddress;
    1772             : 
    1773           0 :         if (ASMJIT_UNLIKELY(rmRel->as<Mem>().addrType() == Mem::AddrType::kRel))
    1774           0 :           goto InvalidAddress;
    1775             : 
    1776             :         immValue = rmRel->as<Mem>().offset();
    1777           0 :         goto EmitX86OpMovAbs;
    1778             :       }
    1779             : 
    1780             :       // Mem <- Reg
    1781           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    1782             :         opReg = o1.id();
    1783             :         rmRel = &o0;
    1784             : 
    1785             :         opcode = 0xA2;
    1786             :         opcode.addArithBySize(o1.size());
    1787             : 
    1788           0 :         if (ASMJIT_UNLIKELY(!o1.as<Reg>().isGp()) || opReg != Gp::kIdAx)
    1789           0 :           goto InvalidInstruction;
    1790             : 
    1791           0 :         if (ASMJIT_UNLIKELY(rmRel->as<Mem>().hasBaseOrIndex()))
    1792           0 :           goto InvalidAddress;
    1793             : 
    1794             :         immValue = rmRel->as<Mem>().offset();
    1795           0 :         goto EmitX86OpMovAbs;
    1796             :       }
    1797             : 
    1798             :       // Reg <- Imm.
    1799           0 :       if (isign3 == ENC_OPS2(Reg, Imm)) {
    1800           0 :         if (ASMJIT_UNLIKELY(!o0.as<Reg>().isGpq()))
    1801           0 :           goto InvalidInstruction;
    1802             : 
    1803             :         opReg = o0.id();
    1804             :         opcode = 0xB8;
    1805             : 
    1806             :         immSize = 8;
    1807             :         immValue = o1.as<Imm>().value();
    1808             : 
    1809             :         opcode.addPrefixBySize(8);
    1810           0 :         goto EmitX86OpReg;
    1811             :       }
    1812             :       break;
    1813             : 
    1814             :     case InstDB::kEncodingX86MovsxMovzx:
    1815           0 :       opcode.add(o1.size() != 1);
    1816             :       opcode.addPrefixBySize(o0.size());
    1817             : 
    1818           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    1819             :         opReg = o0.id();
    1820             :         rbReg = o1.id();
    1821             : 
    1822           0 :         if (o1.size() != 1)
    1823           0 :           goto EmitX86R;
    1824             : 
    1825           0 :         FIXUP_GPB(o1, rbReg);
    1826           0 :         goto EmitX86R;
    1827             :       }
    1828             : 
    1829           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    1830             :         opReg = o0.id();
    1831             :         rmRel = &o1;
    1832           0 :         goto EmitX86M;
    1833             :       }
    1834             :       break;
    1835             : 
    1836           0 :     case InstDB::kEncodingX86MovntiMovdiri:
    1837           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    1838             :         opcode.addWIf(Reg::isGpq(o1));
    1839             : 
    1840             :         opReg = o1.id();
    1841             :         rmRel = &o0;
    1842           0 :         goto EmitX86M;
    1843             :       }
    1844             :       break;
    1845             : 
    1846           0 :     case InstDB::kEncodingX86EnqcmdMovdir64b:
    1847           0 :       if (isign3 == ENC_OPS2(Mem, Mem)) {
    1848             :         const Mem& m0 = o0.as<Mem>();
    1849             :         // This is the only required validation, the rest is handled afterwards.
    1850           0 :         if (ASMJIT_UNLIKELY(m0.baseType() != o1.as<Mem>().baseType() ||
    1851             :                             m0.hasIndex() ||
    1852             :                             m0.hasOffset() ||
    1853             :                             (m0.hasSegment() && m0.segmentId() != SReg::kIdEs)))
    1854           0 :           goto InvalidInstruction;
    1855             : 
    1856             :         // The first memory operand is passed via register, the second memory operand is RM.
    1857             :         opReg = o0.as<Mem>().baseId();
    1858             :         rmRel = &o1;
    1859           0 :         goto EmitX86M;
    1860             :       }
    1861             :       break;
    1862             : 
    1863           0 :     case InstDB::kEncodingX86Out:
    1864           0 :       if (isign3 == ENC_OPS2(Imm, Reg)) {
    1865           0 :         if (ASMJIT_UNLIKELY(o1.id() != Gp::kIdAx))
    1866           0 :           goto InvalidInstruction;
    1867             : 
    1868           0 :         opcode = x86AltOpcodeOf(instInfo) + (o1.size() != 1);
    1869             :         opcode.add66hBySize(o1.size());
    1870             : 
    1871           0 :         immValue = o0.as<Imm>().valueAs<uint8_t>();
    1872             :         immSize = 1;
    1873           0 :         goto EmitX86Op;
    1874             :       }
    1875             : 
    1876           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    1877           0 :         if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdDx || o1.id() != Gp::kIdAx))
    1878           0 :           goto InvalidInstruction;
    1879             : 
    1880           0 :         opcode.add(o1.size() != 1);
    1881             :         opcode.add66hBySize(o1.size());
    1882           0 :         goto EmitX86Op;
    1883             :       }
    1884             :       break;
    1885             : 
    1886           0 :     case InstDB::kEncodingX86Outs:
    1887           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    1888           0 :         if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdDx || !x86IsImplicitMem(o1, Gp::kIdSi)))
    1889           0 :           goto InvalidInstruction;
    1890             : 
    1891             :         uint32_t size = o1.size();
    1892           0 :         if (ASMJIT_UNLIKELY(size == 0))
    1893           0 :           goto AmbiguousOperandSize;
    1894             : 
    1895             :         rmRel = &o1;
    1896           0 :         opcode.add(size != 1);
    1897             :         opcode.add66hBySize(size);
    1898           0 :         goto EmitX86OpImplicitMem;
    1899             :       }
    1900             :       break;
    1901             : 
    1902           0 :     case InstDB::kEncodingX86Push:
    1903           0 :       if (isign3 == ENC_OPS1(Reg)) {
    1904           0 :         if (Reg::isSReg(o0)) {
    1905             :           uint32_t segment = o0.id();
    1906           0 :           if (ASMJIT_UNLIKELY(segment >= SReg::kIdCount))
    1907           0 :             goto InvalidSegment;
    1908             : 
    1909           0 :           opcode = x86OpcodePushSReg[segment];
    1910           0 :           goto EmitX86Op;
    1911             :         }
    1912             :         else {
    1913           0 :           goto CaseX86PushPop_Gp;
    1914             :         }
    1915             :       }
    1916             : 
    1917           0 :       if (isign3 == ENC_OPS1(Imm)) {
    1918             :         immValue = o0.as<Imm>().value();
    1919             :         immSize = 4;
    1920             : 
    1921           0 :         if (Support::isInt8(immValue) && !Support::test(options, InstOptions::kLongForm))
    1922             :           immSize = 1;
    1923             : 
    1924             :         opcode = immSize == 1 ? 0x6A : 0x68;
    1925           0 :         goto EmitX86Op;
    1926             :       }
    1927             :       ASMJIT_FALLTHROUGH;
    1928             : 
    1929             :     case InstDB::kEncodingX86Pop:
    1930           0 :       if (isign3 == ENC_OPS1(Reg)) {
    1931           0 :         if (Reg::isSReg(o0)) {
    1932             :           uint32_t segment = o0.id();
    1933           0 :           if (ASMJIT_UNLIKELY(segment == SReg::kIdCs || segment >= SReg::kIdCount))
    1934           0 :             goto InvalidSegment;
    1935             : 
    1936           0 :           opcode = x86OpcodePopSReg[segment];
    1937           0 :           goto EmitX86Op;
    1938             :         }
    1939             :         else {
    1940           0 : CaseX86PushPop_Gp:
    1941             :           // We allow 2 byte, 4 byte, and 8 byte register sizes, although PUSH and POP only allow 2 bytes or
    1942             :           // native size. On 64-bit we simply PUSH/POP 64-bit register even if 32-bit register was given.
    1943           0 :           if (ASMJIT_UNLIKELY(o0.size() < 2))
    1944           0 :             goto InvalidInstruction;
    1945             : 
    1946             :           opcode = x86AltOpcodeOf(instInfo);
    1947             :           opcode.add66hBySize(o0.size());
    1948             :           opReg = o0.id();
    1949           0 :           goto EmitX86OpReg;
    1950             :         }
    1951             :       }
    1952             : 
    1953           0 :       if (isign3 == ENC_OPS1(Mem)) {
    1954           0 :         if (ASMJIT_UNLIKELY(o0.size() == 0))
    1955           0 :           goto AmbiguousOperandSize;
    1956             : 
    1957           0 :         if (ASMJIT_UNLIKELY(o0.size() != 2 && o0.size() != registerSize()))
    1958           0 :           goto InvalidInstruction;
    1959             : 
    1960             :         opcode.add66hBySize(o0.size());
    1961             :         rmRel = &o0;
    1962           0 :         goto EmitX86M;
    1963             :       }
    1964             :       break;
    1965             : 
    1966       27492 :     case InstDB::kEncodingX86Ret:
    1967       27492 :       if (isign3 == 0) {
    1968             :         // 'ret' without immediate, change C2 to C3.
    1969             :         opcode.add(1);
    1970       27492 :         goto EmitX86Op;
    1971             :       }
    1972             : 
    1973           0 :       if (isign3 == ENC_OPS1(Imm)) {
    1974             :         immValue = o0.as<Imm>().value();
    1975           0 :         if (immValue == 0 && !Support::test(options, InstOptions::kLongForm)) {
    1976             :           // 'ret' without immediate, change C2 to C3.
    1977             :           opcode.add(1);
    1978           0 :           goto EmitX86Op;
    1979             :         }
    1980             :         else {
    1981             :           immSize = 2;
    1982           0 :           goto EmitX86Op;
    1983             :         }
    1984             :       }
    1985             :       break;
    1986             : 
    1987             :     case InstDB::kEncodingX86Rot:
    1988           0 :       if (o0.isReg()) {
    1989             :         opcode.addArithBySize(o0.size());
    1990             :         rbReg = o0.id();
    1991             : 
    1992           0 :         if (o0.size() == 1)
    1993           0 :           FIXUP_GPB(o0, rbReg);
    1994             : 
    1995           0 :         if (isign3 == ENC_OPS2(Reg, Reg)) {
    1996           0 :           if (ASMJIT_UNLIKELY(o1.id() != Gp::kIdCx))
    1997           0 :             goto InvalidInstruction;
    1998             : 
    1999             :           opcode += 2;
    2000           0 :           goto EmitX86R;
    2001             :         }
    2002             : 
    2003           0 :         if (isign3 == ENC_OPS2(Reg, Imm)) {
    2004           0 :           immValue = o1.as<Imm>().value() & 0xFF;
    2005             :           immSize = 0;
    2006             : 
    2007           0 :           if (immValue == 1 && !Support::test(options, InstOptions::kLongForm))
    2008           0 :             goto EmitX86R;
    2009             : 
    2010             :           opcode -= 0x10;
    2011             :           immSize = 1;
    2012           0 :           goto EmitX86R;
    2013             :         }
    2014             :       }
    2015             :       else {
    2016           0 :         if (ASMJIT_UNLIKELY(o0.size() == 0))
    2017           0 :           goto AmbiguousOperandSize;
    2018             :         opcode.addArithBySize(o0.size());
    2019             : 
    2020           0 :         if (isign3 == ENC_OPS2(Mem, Reg)) {
    2021           0 :           if (ASMJIT_UNLIKELY(o1.id() != Gp::kIdCx))
    2022           0 :             goto InvalidInstruction;
    2023             : 
    2024             :           opcode += 2;
    2025             :           rmRel = &o0;
    2026           0 :           goto EmitX86M;
    2027             :         }
    2028             : 
    2029           0 :         if (isign3 == ENC_OPS2(Mem, Imm)) {
    2030             :           rmRel = &o0;
    2031           0 :           immValue = o1.as<Imm>().value() & 0xFF;
    2032             :           immSize = 0;
    2033             : 
    2034           0 :           if (immValue == 1 && !Support::test(options, InstOptions::kLongForm))
    2035           0 :             goto EmitX86M;
    2036             : 
    2037             :           opcode -= 0x10;
    2038             :           immSize = 1;
    2039           0 :           goto EmitX86M;
    2040             :         }
    2041             :       }
    2042             :       break;
    2043             : 
    2044           0 :     case InstDB::kEncodingX86Set:
    2045           0 :       if (isign3 == ENC_OPS1(Reg)) {
    2046             :         rbReg = o0.id();
    2047           0 :         FIXUP_GPB(o0, rbReg);
    2048           0 :         goto EmitX86R;
    2049             :       }
    2050             : 
    2051           0 :       if (isign3 == ENC_OPS1(Mem)) {
    2052             :         rmRel = &o0;
    2053           0 :         goto EmitX86M;
    2054             :       }
    2055             :       break;
    2056             : 
    2057           0 :     case InstDB::kEncodingX86ShldShrd:
    2058           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    2059             :         opcode.addPrefixBySize(o0.size());
    2060             :         opReg = o1.id();
    2061             :         rbReg = o0.id();
    2062             : 
    2063             :         immValue = o2.as<Imm>().value();
    2064             :         immSize = 1;
    2065           0 :         goto EmitX86R;
    2066             :       }
    2067             : 
    2068           0 :       if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
    2069             :         opcode.addPrefixBySize(o1.size());
    2070             :         opReg = o1.id();
    2071             :         rmRel = &o0;
    2072             : 
    2073             :         immValue = o2.as<Imm>().value();
    2074             :         immSize = 1;
    2075           0 :         goto EmitX86M;
    2076             :       }
    2077             : 
    2078             :       // The following instructions use opcode + 1.
    2079             :       opcode.add(1);
    2080             : 
    2081           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    2082           0 :         if (ASMJIT_UNLIKELY(o2.id() != Gp::kIdCx))
    2083           0 :           goto InvalidInstruction;
    2084             : 
    2085             :         opcode.addPrefixBySize(o0.size());
    2086             :         opReg = o1.id();
    2087             :         rbReg = o0.id();
    2088           0 :         goto EmitX86R;
    2089             :       }
    2090             : 
    2091           0 :       if (isign3 == ENC_OPS3(Mem, Reg, Reg)) {
    2092           0 :         if (ASMJIT_UNLIKELY(o2.id() != Gp::kIdCx))
    2093           0 :           goto InvalidInstruction;
    2094             : 
    2095             :         opcode.addPrefixBySize(o1.size());
    2096             :         opReg = o1.id();
    2097             :         rmRel = &o0;
    2098           0 :         goto EmitX86M;
    2099             :       }
    2100             :       break;
    2101             : 
    2102           0 :     case InstDB::kEncodingX86StrRm:
    2103           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2104             :         rmRel = &o1;
    2105           0 :         if (ASMJIT_UNLIKELY(rmRel->as<Mem>().offsetLo32() || !Reg::isGp(o0.as<Reg>(), Gp::kIdAx)))
    2106           0 :           goto InvalidInstruction;
    2107             : 
    2108             :         uint32_t size = o0.size();
    2109           0 :         if (o1.hasSize() && ASMJIT_UNLIKELY(o1.size() != size))
    2110           0 :           goto OperandSizeMismatch;
    2111             : 
    2112             :         opcode.addArithBySize(size);
    2113           0 :         goto EmitX86OpImplicitMem;
    2114             :       }
    2115             :       break;
    2116             : 
    2117           0 :     case InstDB::kEncodingX86StrMr:
    2118           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2119             :         rmRel = &o0;
    2120           0 :         if (ASMJIT_UNLIKELY(rmRel->as<Mem>().offsetLo32() || !Reg::isGp(o1.as<Reg>(), Gp::kIdAx)))
    2121           0 :           goto InvalidInstruction;
    2122             : 
    2123             :         uint32_t size = o1.size();
    2124           0 :         if (o0.hasSize() && ASMJIT_UNLIKELY(o0.size() != size))
    2125           0 :           goto OperandSizeMismatch;
    2126             : 
    2127             :         opcode.addArithBySize(size);
    2128           0 :         goto EmitX86OpImplicitMem;
    2129             :       }
    2130             :       break;
    2131             : 
    2132           0 :     case InstDB::kEncodingX86StrMm:
    2133           0 :       if (isign3 == ENC_OPS2(Mem, Mem)) {
    2134           0 :         if (ASMJIT_UNLIKELY(o0.as<Mem>().baseAndIndexTypes() !=
    2135             :                             o1.as<Mem>().baseAndIndexTypes()))
    2136           0 :           goto InvalidInstruction;
    2137             : 
    2138             :         rmRel = &o1;
    2139           0 :         if (ASMJIT_UNLIKELY(o0.as<Mem>().hasOffset()))
    2140           0 :           goto InvalidInstruction;
    2141             : 
    2142             :         uint32_t size = o1.size();
    2143           0 :         if (ASMJIT_UNLIKELY(size == 0))
    2144           0 :           goto AmbiguousOperandSize;
    2145             : 
    2146           0 :         if (ASMJIT_UNLIKELY(o0.size() != size))
    2147           0 :           goto OperandSizeMismatch;
    2148             : 
    2149             :         opcode.addArithBySize(size);
    2150           0 :         goto EmitX86OpImplicitMem;
    2151             :       }
    2152             :       break;
    2153             : 
    2154           0 :     case InstDB::kEncodingX86Test:
    2155           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2156           0 :         if (o0.size() != o1.size())
    2157           0 :           goto OperandSizeMismatch;
    2158             : 
    2159             :         opcode.addArithBySize(o0.size());
    2160             :         rbReg = o0.id();
    2161             :         opReg = o1.id();
    2162             : 
    2163           0 :         if (o0.size() != 1)
    2164           0 :           goto EmitX86R;
    2165             : 
    2166           0 :         FIXUP_GPB(o0, rbReg);
    2167           0 :         FIXUP_GPB(o1, opReg);
    2168           0 :         goto EmitX86R;
    2169             :       }
    2170             : 
    2171           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2172             :         opcode.addArithBySize(o1.size());
    2173             :         opReg = o1.id();
    2174             :         rmRel = &o0;
    2175             : 
    2176           0 :         if (o1.size() != 1)
    2177           0 :           goto EmitX86M;
    2178             : 
    2179           0 :         FIXUP_GPB(o1, opReg);
    2180           0 :         goto EmitX86M;
    2181             :       }
    2182             : 
    2183             :       // The following instructions use the secondary opcode.
    2184             :       opcode = x86AltOpcodeOf(instInfo);
    2185             :       opReg = opcode.extractModO();
    2186             : 
    2187           0 :       if (isign3 == ENC_OPS2(Reg, Imm)) {
    2188             :         opcode.addArithBySize(o0.size());
    2189             :         rbReg = o0.id();
    2190             : 
    2191           0 :         if (o0.size() == 1) {
    2192           0 :           FIXUP_GPB(o0, rbReg);
    2193           0 :           immValue = o1.as<Imm>().valueAs<uint8_t>();
    2194             :           immSize = 1;
    2195             :         }
    2196             :         else {
    2197             :           immValue = o1.as<Imm>().value();
    2198           0 :           immSize = FastUInt8(Support::min<uint32_t>(o0.size(), 4));
    2199             :         }
    2200             : 
    2201             :         // Short form - AL, AX, EAX, RAX.
    2202           0 :         if (rbReg == 0 && !Support::test(options, InstOptions::kLongForm)) {
    2203             :           opcode &= Opcode::kPP_66 | Opcode::kW;
    2204           0 :           opcode |= 0xA8 + (o0.size() != 1);
    2205           0 :           goto EmitX86Op;
    2206             :         }
    2207             : 
    2208           0 :         goto EmitX86R;
    2209             :       }
    2210             : 
    2211           0 :       if (isign3 == ENC_OPS2(Mem, Imm)) {
    2212           0 :         if (ASMJIT_UNLIKELY(o0.size() == 0))
    2213           0 :           goto AmbiguousOperandSize;
    2214             : 
    2215             :         opcode.addArithBySize(o0.size());
    2216             :         rmRel = &o0;
    2217             : 
    2218             :         immValue = o1.as<Imm>().value();
    2219           0 :         immSize = FastUInt8(Support::min<uint32_t>(o0.size(), 4));
    2220           0 :         goto EmitX86M;
    2221             :       }
    2222             :       break;
    2223             : 
    2224           0 :     case InstDB::kEncodingX86Xchg:
    2225           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2226             :         opcode.addArithBySize(o0.size());
    2227             :         opReg = o0.id();
    2228             :         rmRel = &o1;
    2229             : 
    2230           0 :         if (o0.size() != 1)
    2231           0 :           goto EmitX86M;
    2232             : 
    2233           0 :         FIXUP_GPB(o0, opReg);
    2234           0 :         goto EmitX86M;
    2235             :       }
    2236             :       ASMJIT_FALLTHROUGH;
    2237             : 
    2238             :     case InstDB::kEncodingX86Xadd:
    2239           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2240             :         rbReg = o0.id();
    2241             :         opReg = o1.id();
    2242             : 
    2243             :         uint32_t opSize = o0.size();
    2244           0 :         if (opSize != o1.size())
    2245           0 :           goto OperandSizeMismatch;
    2246             : 
    2247           0 :         if (opSize == 1) {
    2248           0 :           FIXUP_GPB(o0, rbReg);
    2249           0 :           FIXUP_GPB(o1, opReg);
    2250           0 :           goto EmitX86R;
    2251             :         }
    2252             : 
    2253             :         // Special cases for 'xchg ?ax, reg'.
    2254           0 :         if (instId == Inst::kIdXchg && (opReg == 0 || rbReg == 0)) {
    2255           0 :           if (is64Bit() && opReg == rbReg && opSize >= 4) {
    2256           0 :             if (opSize == 8) {
    2257             :               // Encode 'xchg rax, rax' as '90' (REX and other prefixes are optional).
    2258             :               opcode &= Opcode::kW;
    2259             :               opcode |= 0x90;
    2260           0 :               goto EmitX86OpReg;
    2261             :             }
    2262             :             else {
    2263             :               // Encode 'xchg eax, eax' by by using a generic path.
    2264             :             }
    2265             :           }
    2266           0 :           else if (!Support::test(options, InstOptions::kLongForm)) {
    2267             :             // The special encoding encodes only one register, which is non-zero.
    2268           0 :             opReg += rbReg;
    2269             : 
    2270             :             opcode.addArithBySize(opSize);
    2271             :             opcode &= Opcode::kW | Opcode::kPP_66;
    2272             :             opcode |= 0x90;
    2273           0 :             goto EmitX86OpReg;
    2274             :           }
    2275             :         }
    2276             : 
    2277             :         opcode.addArithBySize(opSize);
    2278           0 :         goto EmitX86R;
    2279             :       }
    2280             : 
    2281           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2282             :         opcode.addArithBySize(o1.size());
    2283             :         opReg = o1.id();
    2284             :         rmRel = &o0;
    2285             : 
    2286           0 :         if (o1.size() == 1) {
    2287           0 :           FIXUP_GPB(o1, opReg);
    2288             :         }
    2289             : 
    2290           0 :         goto EmitX86M;
    2291             :       }
    2292             :       break;
    2293             : 
    2294           0 :     case InstDB::kEncodingX86Fence:
    2295             :       rbReg = 0;
    2296           0 :       goto EmitX86R;
    2297             : 
    2298           0 :     case InstDB::kEncodingX86Bndmov:
    2299           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2300             :         opReg = o0.id();
    2301             :         rbReg = o1.id();
    2302             : 
    2303             :         // ModRM encoding:
    2304           0 :         if (!Support::test(options, InstOptions::kX86_ModMR))
    2305           0 :           goto EmitX86R;
    2306             : 
    2307             :         // ModMR encoding:
    2308             :         opcode = x86AltOpcodeOf(instInfo);
    2309             :         std::swap(opReg, rbReg);
    2310           0 :         goto EmitX86R;
    2311             :       }
    2312             : 
    2313           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2314             :         opReg = o0.id();
    2315             :         rmRel = &o1;
    2316           0 :         goto EmitX86M;
    2317             :       }
    2318             : 
    2319           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2320             :         opcode = x86AltOpcodeOf(instInfo);
    2321             : 
    2322             :         rmRel = &o0;
    2323             :         opReg = o1.id();
    2324           0 :         goto EmitX86M;
    2325             :       }
    2326             :       break;
    2327             : 
    2328             :     // FPU Instructions
    2329             :     // ----------------
    2330             : 
    2331           0 :     case InstDB::kEncodingFpuOp:
    2332           0 :       goto EmitFpuOp;
    2333             : 
    2334           0 :     case InstDB::kEncodingFpuArith:
    2335           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2336             :         opReg = o0.id();
    2337             :         rbReg = o1.id();
    2338             : 
    2339             :         // We switch to the alternative opcode if the first operand is zero.
    2340           0 :         if (opReg == 0) {
    2341           0 : CaseFpuArith_Reg:
    2342             :           opcode = ((0xD8   << Opcode::kFPU_2B_Shift)       ) +
    2343           0 :                    ((opcode >> Opcode::kFPU_2B_Shift) & 0xFF) + rbReg;
    2344           0 :           goto EmitFpuOp;
    2345             :         }
    2346           0 :         else if (rbReg == 0) {
    2347             :           rbReg = opReg;
    2348             :           opcode = ((0xDC   << Opcode::kFPU_2B_Shift)       ) +
    2349           0 :                    ((opcode                         ) & 0xFF) + rbReg;
    2350           0 :           goto EmitFpuOp;
    2351             :         }
    2352             :         else {
    2353           0 :           goto InvalidInstruction;
    2354             :         }
    2355             :       }
    2356             : 
    2357           0 :       if (isign3 == ENC_OPS1(Mem)) {
    2358           0 : CaseFpuArith_Mem:
    2359             :         // 0xD8/0xDC, depends on the size of the memory operand; opReg is valid.
    2360           0 :         opcode = (o0.size() == 4) ? 0xD8 : 0xDC;
    2361             :         // Clear compressed displacement before going to EmitX86M.
    2362             :         opcode &= ~uint32_t(Opcode::kCDSHL_Mask);
    2363             : 
    2364             :         rmRel = &o0;
    2365           0 :         goto EmitX86M;
    2366             :       }
    2367             :       break;
    2368             : 
    2369           0 :     case InstDB::kEncodingFpuCom:
    2370           0 :       if (isign3 == 0) {
    2371             :         rbReg = 1;
    2372           0 :         goto CaseFpuArith_Reg;
    2373             :       }
    2374             : 
    2375           0 :       if (isign3 == ENC_OPS1(Reg)) {
    2376             :         rbReg = o0.id();
    2377           0 :         goto CaseFpuArith_Reg;
    2378             :       }
    2379             : 
    2380           0 :       if (isign3 == ENC_OPS1(Mem)) {
    2381           0 :         goto CaseFpuArith_Mem;
    2382             :       }
    2383             :       break;
    2384             : 
    2385           0 :     case InstDB::kEncodingFpuFldFst:
    2386           0 :       if (isign3 == ENC_OPS1(Mem)) {
    2387             :         rmRel = &o0;
    2388             : 
    2389           0 :         if (o0.size() == 4 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM32)) {
    2390           0 :           goto EmitX86M;
    2391             :         }
    2392             : 
    2393           0 :         if (o0.size() == 8 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM64)) {
    2394             :           opcode += 4;
    2395           0 :           goto EmitX86M;
    2396             :         }
    2397             : 
    2398           0 :         if (o0.size() == 10 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM80)) {
    2399             :           opcode = x86AltOpcodeOf(instInfo);
    2400             :           opReg  = opcode.extractModO();
    2401           0 :           goto EmitX86M;
    2402             :         }
    2403             :       }
    2404             : 
    2405           0 :       if (isign3 == ENC_OPS1(Reg)) {
    2406           0 :         if (instId == Inst::kIdFld ) { opcode = (0xD9 << Opcode::kFPU_2B_Shift) + 0xC0 + o0.id(); goto EmitFpuOp; }
    2407           0 :         if (instId == Inst::kIdFst ) { opcode = (0xDD << Opcode::kFPU_2B_Shift) + 0xD0 + o0.id(); goto EmitFpuOp; }
    2408           0 :         if (instId == Inst::kIdFstp) { opcode = (0xDD << Opcode::kFPU_2B_Shift) + 0xD8 + o0.id(); goto EmitFpuOp; }
    2409             :       }
    2410             :       break;
    2411             : 
    2412           0 :     case InstDB::kEncodingFpuM:
    2413           0 :       if (isign3 == ENC_OPS1(Mem)) {
    2414             :         // Clear compressed displacement before going to EmitX86M.
    2415             :         opcode &= ~uint32_t(Opcode::kCDSHL_Mask);
    2416             : 
    2417             :         rmRel = &o0;
    2418           0 :         if (o0.size() == 2 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM16)) {
    2419             :           opcode += 4;
    2420           0 :           goto EmitX86M;
    2421             :         }
    2422             : 
    2423           0 :         if (o0.size() == 4 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM32)) {
    2424           0 :           goto EmitX86M;
    2425             :         }
    2426             : 
    2427           0 :         if (o0.size() == 8 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM64)) {
    2428           0 :           opcode = x86AltOpcodeOf(instInfo) & ~uint32_t(Opcode::kCDSHL_Mask);
    2429             :           opReg  = opcode.extractModO();
    2430           0 :           goto EmitX86M;
    2431             :         }
    2432             :       }
    2433             :       break;
    2434             : 
    2435           0 :     case InstDB::kEncodingFpuRDef:
    2436           0 :       if (isign3 == 0) {
    2437             :         opcode += 1;
    2438           0 :         goto EmitFpuOp;
    2439             :       }
    2440             :       ASMJIT_FALLTHROUGH;
    2441             : 
    2442             :     case InstDB::kEncodingFpuR:
    2443           0 :       if (isign3 == ENC_OPS1(Reg)) {
    2444             :         opcode += o0.id();
    2445           0 :         goto EmitFpuOp;
    2446             :       }
    2447             :       break;
    2448             : 
    2449           0 :     case InstDB::kEncodingFpuStsw:
    2450           0 :       if (isign3 == ENC_OPS1(Reg)) {
    2451           0 :         if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdAx))
    2452           0 :           goto InvalidInstruction;
    2453             : 
    2454             :         opcode = x86AltOpcodeOf(instInfo);
    2455           0 :         goto EmitFpuOp;
    2456             :       }
    2457             : 
    2458           0 :       if (isign3 == ENC_OPS1(Mem)) {
    2459             :         // Clear compressed displacement before going to EmitX86M.
    2460             :         opcode &= ~uint32_t(Opcode::kCDSHL_Mask);
    2461             : 
    2462             :         rmRel = &o0;
    2463           0 :         goto EmitX86M;
    2464             :       }
    2465             :       break;
    2466             : 
    2467             :     // Ext Instructions (Legacy Extensions)
    2468             :     // ------------------------------------
    2469             : 
    2470           0 :     case InstDB::kEncodingExtPextrw:
    2471           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    2472             :         opcode.add66hIf(Reg::isXmm(o1));
    2473             : 
    2474             :         immValue = o2.as<Imm>().value();
    2475             :         immSize = 1;
    2476             : 
    2477             :         opReg = o0.id();
    2478             :         rbReg = o1.id();
    2479           0 :         goto EmitX86R;
    2480             :       }
    2481             : 
    2482           0 :       if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
    2483             :         // Secondary opcode of 'pextrw' instruction (SSE4.1).
    2484             :         opcode = x86AltOpcodeOf(instInfo);
    2485             :         opcode.add66hIf(Reg::isXmm(o1));
    2486             : 
    2487             :         immValue = o2.as<Imm>().value();
    2488             :         immSize = 1;
    2489             : 
    2490             :         opReg = o1.id();
    2491             :         rmRel = &o0;
    2492           0 :         goto EmitX86M;
    2493             :       }
    2494             :       break;
    2495             : 
    2496           0 :     case InstDB::kEncodingExtExtract:
    2497           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    2498             :         opcode.add66hIf(Reg::isXmm(o1));
    2499             : 
    2500             :         immValue = o2.as<Imm>().value();
    2501             :         immSize = 1;
    2502             : 
    2503             :         opReg = o1.id();
    2504             :         rbReg = o0.id();
    2505           0 :         goto EmitX86R;
    2506             :       }
    2507             : 
    2508           0 :       if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
    2509             :         opcode.add66hIf(Reg::isXmm(o1));
    2510             : 
    2511             :         immValue = o2.as<Imm>().value();
    2512             :         immSize = 1;
    2513             : 
    2514             :         opReg = o1.id();
    2515             :         rmRel = &o0;
    2516           0 :         goto EmitX86M;
    2517             :       }
    2518             :       break;
    2519             : 
    2520           0 :     case InstDB::kEncodingExtMov:
    2521             :       // GP|MM|XMM <- GP|MM|XMM
    2522           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2523             :         opReg = o0.id();
    2524             :         rbReg = o1.id();
    2525             : 
    2526           0 :         if (!Support::test(options, InstOptions::kX86_ModMR) || !instInfo->_altOpcodeIndex)
    2527           0 :           goto EmitX86R;
    2528             : 
    2529             :         opcode = x86AltOpcodeOf(instInfo);
    2530             :         std::swap(opReg, rbReg);
    2531           0 :         goto EmitX86R;
    2532             :       }
    2533             : 
    2534             :       // GP|MM|XMM <- Mem
    2535           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2536             :         opReg = o0.id();
    2537             :         rmRel = &o1;
    2538           0 :         goto EmitX86M;
    2539             :       }
    2540             : 
    2541             :       // The following instruction uses opcode[1].
    2542             :       opcode = x86AltOpcodeOf(instInfo);
    2543             : 
    2544             :       // Mem <- GP|MM|XMM
    2545           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2546             :         opReg = o1.id();
    2547             :         rmRel = &o0;
    2548           0 :         goto EmitX86M;
    2549             :       }
    2550             :       break;
    2551             : 
    2552           0 :     case InstDB::kEncodingExtMovbe:
    2553           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2554           0 :         if (o0.size() == 1)
    2555           0 :           goto InvalidInstruction;
    2556             : 
    2557             :         opcode.addPrefixBySize(o0.size());
    2558             :         opReg = o0.id();
    2559             :         rmRel = &o1;
    2560           0 :         goto EmitX86M;
    2561             :       }
    2562             : 
    2563             :       // The following instruction uses the secondary opcode.
    2564             :       opcode = x86AltOpcodeOf(instInfo);
    2565             : 
    2566           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2567           0 :         if (o1.size() == 1)
    2568           0 :           goto InvalidInstruction;
    2569             : 
    2570             :         opcode.addPrefixBySize(o1.size());
    2571             :         opReg = o1.id();
    2572             :         rmRel = &o0;
    2573           0 :         goto EmitX86M;
    2574             :       }
    2575             :       break;
    2576             : 
    2577             :     case InstDB::kEncodingExtMovd:
    2578           0 : CaseExtMovd:
    2579             :       opReg = o0.id();
    2580             :       opcode.add66hIf(Reg::isXmm(o0));
    2581             : 
    2582             :       // MM/XMM <- Gp
    2583           0 :       if (isign3 == ENC_OPS2(Reg, Reg) && Reg::isGp(o1)) {
    2584             :         rbReg = o1.id();
    2585           0 :         goto EmitX86R;
    2586             :       }
    2587             : 
    2588             :       // MM/XMM <- Mem
    2589           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2590             :         rmRel = &o1;
    2591           0 :         goto EmitX86M;
    2592             :       }
    2593             : 
    2594             :       // The following instructions use the secondary opcode.
    2595             :       opcode &= Opcode::kW;
    2596             :       opcode |= x86AltOpcodeOf(instInfo);
    2597             :       opReg = o1.id();
    2598             :       opcode.add66hIf(Reg::isXmm(o1));
    2599             : 
    2600             :       // GP <- MM/XMM
    2601           0 :       if (isign3 == ENC_OPS2(Reg, Reg) && Reg::isGp(o0)) {
    2602             :         rbReg = o0.id();
    2603           0 :         goto EmitX86R;
    2604             :       }
    2605             : 
    2606             :       // Mem <- MM/XMM
    2607           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2608             :         rmRel = &o0;
    2609           0 :         goto EmitX86M;
    2610             :       }
    2611             :       break;
    2612             : 
    2613           0 :     case InstDB::kEncodingExtMovq:
    2614           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2615             :         opReg = o0.id();
    2616             :         rbReg = o1.id();
    2617             : 
    2618             :         // MM <- MM
    2619           0 :         if (Reg::isMm(o0) && Reg::isMm(o1)) {
    2620             :           opcode = Opcode::k000F00 | 0x6F;
    2621             : 
    2622           0 :           if (!Support::test(options, InstOptions::kX86_ModMR))
    2623           0 :             goto EmitX86R;
    2624             : 
    2625             :           opcode += 0x10;
    2626             :           std::swap(opReg, rbReg);
    2627           0 :           goto EmitX86R;
    2628             :         }
    2629             : 
    2630             :         // XMM <- XMM
    2631           0 :         if (Reg::isXmm(o0) && Reg::isXmm(o1)) {
    2632             :           opcode = Opcode::kF30F00 | 0x7E;
    2633             : 
    2634           0 :           if (!Support::test(options, InstOptions::kX86_ModMR))
    2635           0 :             goto EmitX86R;
    2636             : 
    2637             :           opcode = Opcode::k660F00 | 0xD6;
    2638             :           std::swap(opReg, rbReg);
    2639           0 :           goto EmitX86R;
    2640             :         }
    2641             :       }
    2642             : 
    2643           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2644             :         opReg = o0.id();
    2645             :         rmRel = &o1;
    2646             : 
    2647             :         // MM <- Mem
    2648           0 :         if (Reg::isMm(o0)) {
    2649             :           opcode = Opcode::k000F00 | 0x6F;
    2650           0 :           goto EmitX86M;
    2651             :         }
    2652             : 
    2653             :         // XMM <- Mem
    2654           0 :         if (Reg::isXmm(o0)) {
    2655             :           opcode = Opcode::kF30F00 | 0x7E;
    2656           0 :           goto EmitX86M;
    2657             :         }
    2658             :       }
    2659             : 
    2660           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2661             :         opReg = o1.id();
    2662             :         rmRel = &o0;
    2663             : 
    2664             :         // Mem <- MM
    2665           0 :         if (Reg::isMm(o1)) {
    2666             :           opcode = Opcode::k000F00 | 0x7F;
    2667           0 :           goto EmitX86M;
    2668             :         }
    2669             : 
    2670             :         // Mem <- XMM
    2671           0 :         if (Reg::isXmm(o1)) {
    2672             :           opcode = Opcode::k660F00 | 0xD6;
    2673           0 :           goto EmitX86M;
    2674             :         }
    2675             :       }
    2676             : 
    2677             :       // MOVQ in other case is simply a MOVD instruction promoted to 64-bit.
    2678             :       opcode |= Opcode::kW;
    2679           0 :       goto CaseExtMovd;
    2680             : 
    2681             :     case InstDB::kEncodingExtRm_XMM0:
    2682           0 :       if (ASMJIT_UNLIKELY(!o2.isNone() && !Reg::isXmm(o2, 0)))
    2683           0 :         goto InvalidInstruction;
    2684             : 
    2685           0 :       isign3 &= 0x3F;
    2686           0 :       goto CaseExtRm;
    2687             : 
    2688             :     case InstDB::kEncodingExtRm_ZDI:
    2689           0 :       if (ASMJIT_UNLIKELY(!o2.isNone() && !x86IsImplicitMem(o2, Gp::kIdDi)))
    2690           0 :         goto InvalidInstruction;
    2691             : 
    2692           0 :       isign3 &= 0x3F;
    2693           0 :       goto CaseExtRm;
    2694             : 
    2695             :     case InstDB::kEncodingExtRm_Wx:
    2696           0 :       opcode.addWIf(o1.size() == 8);
    2697             :       ASMJIT_FALLTHROUGH;
    2698             : 
    2699           0 :     case InstDB::kEncodingExtRm_Wx_GpqOnly:
    2700             :       opcode.addWIf(Reg::isGpq(o0));
    2701             :       ASMJIT_FALLTHROUGH;
    2702             : 
    2703             :     case InstDB::kEncodingExtRm:
    2704           0 : CaseExtRm:
    2705           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2706             :         opReg = o0.id();
    2707             :         rbReg = o1.id();
    2708           0 :         goto EmitX86R;
    2709             :       }
    2710             : 
    2711           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2712             :         opReg = o0.id();
    2713             :         rmRel = &o1;
    2714           0 :         goto EmitX86M;
    2715             :       }
    2716             :       break;
    2717             : 
    2718           0 :     case InstDB::kEncodingExtRm_P:
    2719           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2720           0 :         opcode.add66hIf(Reg::isXmm(o0) | Reg::isXmm(o1));
    2721             : 
    2722             :         opReg = o0.id();
    2723             :         rbReg = o1.id();
    2724           0 :         goto EmitX86R;
    2725             :       }
    2726             : 
    2727           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2728             :         opcode.add66hIf(Reg::isXmm(o0));
    2729             : 
    2730             :         opReg = o0.id();
    2731             :         rmRel = &o1;
    2732           0 :         goto EmitX86M;
    2733             :       }
    2734             :       break;
    2735             : 
    2736           0 :     case InstDB::kEncodingExtRmRi:
    2737           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2738             :         opReg = o0.id();
    2739             :         rbReg = o1.id();
    2740           0 :         goto EmitX86R;
    2741             :       }
    2742             : 
    2743           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2744             :         opReg = o0.id();
    2745             :         rmRel = &o1;
    2746           0 :         goto EmitX86M;
    2747             :       }
    2748             : 
    2749             :       // The following instruction uses the secondary opcode.
    2750             :       opcode = x86AltOpcodeOf(instInfo);
    2751             :       opReg  = opcode.extractModO();
    2752             : 
    2753           0 :       if (isign3 == ENC_OPS2(Reg, Imm)) {
    2754             :         immValue = o1.as<Imm>().value();
    2755             :         immSize = 1;
    2756             : 
    2757             :         rbReg = o0.id();
    2758           0 :         goto EmitX86R;
    2759             :       }
    2760             :       break;
    2761             : 
    2762           0 :     case InstDB::kEncodingExtRmRi_P:
    2763           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2764           0 :         opcode.add66hIf(Reg::isXmm(o0) | Reg::isXmm(o1));
    2765             : 
    2766             :         opReg = o0.id();
    2767             :         rbReg = o1.id();
    2768           0 :         goto EmitX86R;
    2769             :       }
    2770             : 
    2771           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2772             :         opcode.add66hIf(Reg::isXmm(o0));
    2773             : 
    2774             :         opReg = o0.id();
    2775             :         rmRel = &o1;
    2776           0 :         goto EmitX86M;
    2777             :       }
    2778             : 
    2779             :       // The following instruction uses the secondary opcode.
    2780             :       opcode = x86AltOpcodeOf(instInfo);
    2781             :       opReg  = opcode.extractModO();
    2782             : 
    2783           0 :       if (isign3 == ENC_OPS2(Reg, Imm)) {
    2784             :         opcode.add66hIf(Reg::isXmm(o0));
    2785             : 
    2786             :         immValue = o1.as<Imm>().value();
    2787             :         immSize = 1;
    2788             : 
    2789             :         rbReg = o0.id();
    2790           0 :         goto EmitX86R;
    2791             :       }
    2792             :       break;
    2793             : 
    2794             :     case InstDB::kEncodingExtRmi:
    2795             :       immValue = o2.as<Imm>().value();
    2796             :       immSize = 1;
    2797             : 
    2798           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    2799             :         opReg = o0.id();
    2800             :         rbReg = o1.id();
    2801           0 :         goto EmitX86R;
    2802             :       }
    2803             : 
    2804           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
    2805             :         opReg = o0.id();
    2806             :         rmRel = &o1;
    2807           0 :         goto EmitX86M;
    2808             :       }
    2809             :       break;
    2810             : 
    2811             :     case InstDB::kEncodingExtRmi_P:
    2812             :       immValue = o2.as<Imm>().value();
    2813             :       immSize = 1;
    2814             : 
    2815           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    2816           0 :         opcode.add66hIf(Reg::isXmm(o0) | Reg::isXmm(o1));
    2817             : 
    2818             :         opReg = o0.id();
    2819             :         rbReg = o1.id();
    2820           0 :         goto EmitX86R;
    2821             :       }
    2822             : 
    2823           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
    2824             :         opcode.add66hIf(Reg::isXmm(o0));
    2825             : 
    2826             :         opReg = o0.id();
    2827             :         rmRel = &o1;
    2828           0 :         goto EmitX86M;
    2829             :       }
    2830             :       break;
    2831             : 
    2832             :     // Extrq & Insertq (SSE4A)
    2833             :     // -----------------------
    2834             : 
    2835             :     case InstDB::kEncodingExtExtrq:
    2836             :       opReg = o0.id();
    2837             :       rbReg = o1.id();
    2838             : 
    2839           0 :       if (isign3 == ENC_OPS2(Reg, Reg))
    2840           0 :         goto EmitX86R;
    2841             : 
    2842           0 :       if (isign3 == ENC_OPS3(Reg, Imm, Imm)) {
    2843             :         // This variant of the instruction uses the secondary opcode.
    2844             :         opcode = x86AltOpcodeOf(instInfo);
    2845             :         rbReg = opReg;
    2846             :         opReg = opcode.extractModO();
    2847             : 
    2848           0 :         immValue = (uint32_t(o1.as<Imm>().valueAs<uint8_t>())     ) +
    2849           0 :                    (uint32_t(o2.as<Imm>().valueAs<uint8_t>()) << 8) ;
    2850             :         immSize = 2;
    2851           0 :         goto EmitX86R;
    2852             :       }
    2853             :       break;
    2854             : 
    2855           0 :     case InstDB::kEncodingExtInsertq: {
    2856             :       const Operand_& o3 = opExt[EmitterUtils::kOp3];
    2857           0 :       const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
    2858             : 
    2859             :       opReg = o0.id();
    2860             :       rbReg = o1.id();
    2861             : 
    2862           0 :       if (isign4 == ENC_OPS2(Reg, Reg))
    2863           0 :         goto EmitX86R;
    2864             : 
    2865           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) {
    2866             :         // This variant of the instruction uses the secondary opcode.
    2867             :         opcode = x86AltOpcodeOf(instInfo);
    2868             : 
    2869           0 :         immValue = (uint32_t(o2.as<Imm>().valueAs<uint8_t>())     ) +
    2870           0 :                    (uint32_t(o3.as<Imm>().valueAs<uint8_t>()) << 8) ;
    2871             :         immSize = 2;
    2872           0 :         goto EmitX86R;
    2873             :       }
    2874             :       break;
    2875             :     }
    2876             : 
    2877             :     // 3DNOW Instructions
    2878             :     // ------------------
    2879             : 
    2880           0 :     case InstDB::kEncodingExt3dNow:
    2881             :       // Every 3dNow instruction starts with 0x0F0F and the actual opcode is
    2882             :       // stored as 8-bit immediate.
    2883           0 :       immValue = opcode.v & 0xFFu;
    2884             :       immSize = 1;
    2885             : 
    2886             :       opcode = Opcode::k000F00 | 0x0F;
    2887             :       opReg = o0.id();
    2888             : 
    2889           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2890             :         rbReg = o1.id();
    2891           0 :         goto EmitX86R;
    2892             :       }
    2893             : 
    2894           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2895             :         rmRel = &o1;
    2896           0 :         goto EmitX86M;
    2897             :       }
    2898             :       break;
    2899             : 
    2900             :     // VEX/EVEX Instructions
    2901             :     // ---------------------
    2902             : 
    2903           0 :     case InstDB::kEncodingVexOp:
    2904           0 :       goto EmitVexOp;
    2905             : 
    2906           0 :     case InstDB::kEncodingVexOpMod:
    2907             :       rbReg = 0;
    2908           0 :       goto EmitVexEvexR;
    2909             : 
    2910           0 :     case InstDB::kEncodingVexKmov:
    2911           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2912             :         opReg = o0.id();
    2913             :         rbReg = o1.id();
    2914             : 
    2915             :         // Form 'k, reg'.
    2916           0 :         if (Reg::isGp(o1)) {
    2917             :           opcode = x86AltOpcodeOf(instInfo);
    2918           0 :           goto EmitVexEvexR;
    2919             :         }
    2920             : 
    2921             :         // Form 'reg, k'.
    2922           0 :         if (Reg::isGp(o0)) {
    2923           0 :           opcode = x86AltOpcodeOf(instInfo) + 1;
    2924           0 :           goto EmitVexEvexR;
    2925             :         }
    2926             : 
    2927             :         // Form 'k, k'.
    2928           0 :         if (!Support::test(options, InstOptions::kX86_ModMR))
    2929           0 :           goto EmitVexEvexR;
    2930             : 
    2931             :         opcode.add(1);
    2932             :         std::swap(opReg, rbReg);
    2933           0 :         goto EmitVexEvexR;
    2934             :       }
    2935             : 
    2936           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    2937             :         opReg = o0.id();
    2938             :         rmRel = &o1;
    2939             : 
    2940           0 :         goto EmitVexEvexM;
    2941             :       }
    2942             : 
    2943           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2944             :         opcode.add(1);
    2945             :         opReg = o1.id();
    2946             :         rmRel = &o0;
    2947           0 :         goto EmitVexEvexM;
    2948             :       }
    2949             :       break;
    2950             : 
    2951           0 :     case InstDB::kEncodingVexR_Wx:
    2952           0 :       if (isign3 == ENC_OPS1(Reg)) {
    2953             :         rbReg = o0.id();
    2954             :         opcode.addWIf(o0.as<Reg>().isGpq());
    2955           0 :         goto EmitVexEvexR;
    2956             :       }
    2957             :       break;
    2958             : 
    2959           0 :     case InstDB::kEncodingVexM:
    2960           0 :       if (isign3 == ENC_OPS1(Mem)) {
    2961             :         rmRel = &o0;
    2962           0 :         goto EmitVexEvexM;
    2963             :       }
    2964             :       break;
    2965             : 
    2966           0 :     case InstDB::kEncodingVexM_VM:
    2967           0 :       if (isign3 == ENC_OPS1(Mem)) {
    2968             :         rmRel = &o0;
    2969           0 :         goto EmitVexEvexM;
    2970             :       }
    2971             :       break;
    2972             : 
    2973             :     case InstDB::kEncodingVexMr_Lx:
    2974             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    2975             : 
    2976           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    2977             :         opReg = o1.id();
    2978             :         rbReg = o0.id();
    2979           0 :         goto EmitVexEvexR;
    2980             :       }
    2981             : 
    2982           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2983             :         opReg = o1.id();
    2984             :         rmRel = &o0;
    2985           0 :         goto EmitVexEvexM;
    2986             :       }
    2987             :       break;
    2988             : 
    2989           0 :     case InstDB::kEncodingVexMr_VM:
    2990           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    2991             :         opcode |= Support::max(x86OpcodeLByVMem(o0), x86OpcodeLBySize(o1.size()));
    2992             : 
    2993             :         opReg = o1.id();
    2994             :         rmRel = &o0;
    2995           0 :         goto EmitVexEvexM;
    2996             :       }
    2997             :       break;
    2998             : 
    2999           0 :     case InstDB::kEncodingVexMri_Vpextrw:
    3000             :       // Use 'vpextrw reg, xmm1, i8' when possible.
    3001           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    3002             :         opcode = Opcode::k660F00 | 0xC5;
    3003             : 
    3004             :         opReg = o0.id();
    3005             :         rbReg = o1.id();
    3006             : 
    3007             :         immValue = o2.as<Imm>().value();
    3008             :         immSize = 1;
    3009           0 :         goto EmitVexEvexR;
    3010             :       }
    3011             : 
    3012           0 :       goto CaseVexMri;
    3013             : 
    3014             :     case InstDB::kEncodingVexMri_Lx:
    3015             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3016             :       ASMJIT_FALLTHROUGH;
    3017             : 
    3018             :     case InstDB::kEncodingVexMri:
    3019           0 : CaseVexMri:
    3020             :       immValue = o2.as<Imm>().value();
    3021             :       immSize = 1;
    3022             : 
    3023           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    3024             :         opReg = o1.id();
    3025             :         rbReg = o0.id();
    3026           0 :         goto EmitVexEvexR;
    3027             :       }
    3028             : 
    3029           0 :       if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
    3030             :         opReg = o1.id();
    3031             :         rmRel = &o0;
    3032           0 :         goto EmitVexEvexM;
    3033             :       }
    3034             :       break;
    3035             : 
    3036             :     case InstDB::kEncodingVexRm_ZDI:
    3037           0 :       if (ASMJIT_UNLIKELY(!o2.isNone() && !x86IsImplicitMem(o2, Gp::kIdDi)))
    3038           0 :         goto InvalidInstruction;
    3039             : 
    3040           0 :       isign3 &= 0x3F;
    3041           0 :       goto CaseVexRm;
    3042             : 
    3043             :     case InstDB::kEncodingVexRm_Wx:
    3044           0 :       opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o1));
    3045           0 :       goto CaseVexRm;
    3046             : 
    3047             :     case InstDB::kEncodingVexRm_Lx_Narrow:
    3048           0 :       if (o1.size())
    3049             :         opcode |= x86OpcodeLBySize(o1.size());
    3050           0 :       else if (o0.size() == 32)
    3051             :         opcode |= Opcode::kLL_2;
    3052           0 :       goto CaseVexRm;
    3053             : 
    3054           0 :     case InstDB::kEncodingVexRm_Lx_Bcst:
    3055           0 :       if (isign3 == ENC_OPS2(Reg, Reg) && Reg::isGp(o1.as<Reg>())) {
    3056           0 :         opcode = x86AltOpcodeOf(instInfo) | x86OpcodeLBySize(o0.size() | o1.size());
    3057             :         opReg = o0.id();
    3058             :         rbReg = o1.id();
    3059           0 :         goto EmitVexEvexR;
    3060             :       }
    3061             :       ASMJIT_FALLTHROUGH;
    3062             : 
    3063             :     case InstDB::kEncodingVexRm_Lx:
    3064             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3065             :       ASMJIT_FALLTHROUGH;
    3066             : 
    3067             :     case InstDB::kEncodingVexRm:
    3068           0 : CaseVexRm:
    3069           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    3070             :         opReg = o0.id();
    3071             :         rbReg = o1.id();
    3072           0 :         goto EmitVexEvexR;
    3073             :       }
    3074             : 
    3075           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    3076             :         opReg = o0.id();
    3077             :         rmRel = &o1;
    3078           0 :         goto EmitVexEvexM;
    3079             :       }
    3080             :       break;
    3081             : 
    3082           0 :     case InstDB::kEncodingVexRm_VM:
    3083           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    3084             :         opcode |= Support::max(x86OpcodeLByVMem(o1), x86OpcodeLBySize(o0.size()));
    3085             :         opReg = o0.id();
    3086             :         rmRel = &o1;
    3087           0 :         goto EmitVexEvexM;
    3088             :       }
    3089             :       break;
    3090             : 
    3091           0 :     case InstDB::kEncodingVexRm_T1_4X: {
    3092             :       const Operand_& o3 = opExt[EmitterUtils::kOp3];
    3093             :       const Operand_& o4 = opExt[EmitterUtils::kOp4];
    3094           0 :       const Operand_& o5 = opExt[EmitterUtils::kOp5];
    3095             : 
    3096           0 :       if (Reg::isVec(o0) && Reg::isVec(o1) && Reg::isVec(o2) && Reg::isVec(o3) && Reg::isVec(o4) && o5.isMem()) {
    3097             :         // Registers [o1, o2, o3, o4] must start aligned and must be consecutive.
    3098             :         uint32_t i1 = o1.id();
    3099             :         uint32_t i2 = o2.id();
    3100             :         uint32_t i3 = o3.id();
    3101             :         uint32_t i4 = o4.id();
    3102             : 
    3103           0 :         if (ASMJIT_UNLIKELY((i1 & 0x3) != 0 || i2 != i1 + 1 || i3 != i1 + 2 || i4 != i1 + 3))
    3104           0 :           goto NotConsecutiveRegs;
    3105             : 
    3106             :         opReg = x86PackRegAndVvvvv(o0.id(), i1);
    3107             :         rmRel = &o5;
    3108           0 :         goto EmitVexEvexM;
    3109             :       }
    3110             :       break;
    3111             :     }
    3112             : 
    3113             :     case InstDB::kEncodingVexRmi_Wx:
    3114           0 :       opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o1));
    3115           0 :       goto CaseVexRmi;
    3116             : 
    3117             :     case InstDB::kEncodingVexRmi_Lx:
    3118             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3119             :       ASMJIT_FALLTHROUGH;
    3120             : 
    3121             :     case InstDB::kEncodingVexRmi:
    3122           0 : CaseVexRmi:
    3123             :       immValue = o2.as<Imm>().value();
    3124             :       immSize = 1;
    3125             : 
    3126           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    3127             :         opReg = o0.id();
    3128             :         rbReg = o1.id();
    3129           0 :         goto EmitVexEvexR;
    3130             :       }
    3131             : 
    3132           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
    3133             :         opReg = o0.id();
    3134             :         rmRel = &o1;
    3135           0 :         goto EmitVexEvexM;
    3136             :       }
    3137             :       break;
    3138             : 
    3139             :     case InstDB::kEncodingVexRvm:
    3140      102527 : CaseVexRvm:
    3141      102527 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3142      111048 : CaseVexRvm_R:
    3143             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3144             :         rbReg = o2.id();
    3145      111048 :         goto EmitVexEvexR;
    3146             :       }
    3147             : 
    3148       22286 :       if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
    3149             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3150             :         rmRel = &o2;
    3151       22286 :         goto EmitVexEvexM;
    3152             :       }
    3153             :       break;
    3154             : 
    3155           0 :     case InstDB::kEncodingVexRvm_ZDX_Wx: {
    3156             :       const Operand_& o3 = opExt[EmitterUtils::kOp3];
    3157           0 :       if (ASMJIT_UNLIKELY(!o3.isNone() && !Reg::isGp(o3, Gp::kIdDx)))
    3158           0 :         goto InvalidInstruction;
    3159             :       ASMJIT_FALLTHROUGH;
    3160             :     }
    3161             : 
    3162             :     case InstDB::kEncodingVexRvm_Wx: {
    3163           0 :       opcode.addWIf(Reg::isGpq(o0) | (o2.size() == 8));
    3164           0 :       goto CaseVexRvm;
    3165             :     }
    3166             : 
    3167             :     case InstDB::kEncodingVexRvm_Lx_KEvex: {
    3168             :       opcode.forceEvexIf(Reg::isKReg(o0));
    3169             :       ASMJIT_FALLTHROUGH;
    3170             :     }
    3171             : 
    3172        6539 :     case InstDB::kEncodingVexRvm_Lx: {
    3173             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3174        6539 :       goto CaseVexRvm;
    3175             :     }
    3176             : 
    3177           0 :     case InstDB::kEncodingVexRvm_Lx_2xK: {
    3178           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3179             :         // Two registers are encoded as a single register.
    3180             :         //   - First K register must be even.
    3181             :         //   - Second K register must be first+1.
    3182           0 :         if ((o0.id() & 1) != 0 || o0.id() + 1 != o1.id())
    3183           0 :           goto InvalidPhysId;
    3184             : 
    3185             :         const Operand_& o3 = opExt[EmitterUtils::kOp3];
    3186             : 
    3187             :         opcode |= x86OpcodeLBySize(o2.size());
    3188             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3189             : 
    3190           0 :         if (o3.isReg()) {
    3191             :           rbReg = o3.id();
    3192           0 :           goto EmitVexEvexR;
    3193             :         }
    3194             : 
    3195           0 :         if (o3.isMem()) {
    3196             :           rmRel = &o3;
    3197           0 :           goto EmitVexEvexM;
    3198             :         }
    3199             :       }
    3200             :       break;
    3201             :     }
    3202             : 
    3203             :     case InstDB::kEncodingVexRvmr_Lx: {
    3204             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3205             :       ASMJIT_FALLTHROUGH;
    3206             :     }
    3207             : 
    3208         157 :     case InstDB::kEncodingVexRvmr: {
    3209             :       const Operand_& o3 = opExt[EmitterUtils::kOp3];
    3210         157 :       const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
    3211             : 
    3212         157 :       immValue = o3.id() << 4;
    3213             :       immSize = 1;
    3214             : 
    3215         157 :       if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
    3216             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3217             :         rbReg = o2.id();
    3218         157 :         goto EmitVexEvexR;
    3219             :       }
    3220             : 
    3221           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
    3222             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3223             :         rmRel = &o2;
    3224           0 :         goto EmitVexEvexM;
    3225             :       }
    3226             :       break;
    3227             :     }
    3228             : 
    3229             :     case InstDB::kEncodingVexRvmi_KEvex:
    3230             :       opcode.forceEvexIf(Reg::isKReg(o0));
    3231        1970 :       goto VexRvmi;
    3232             : 
    3233             :     case InstDB::kEncodingVexRvmi_Lx_KEvex:
    3234             :       opcode.forceEvexIf(Reg::isKReg(o0));
    3235             :       ASMJIT_FALLTHROUGH;
    3236             : 
    3237           0 :     case InstDB::kEncodingVexRvmi_Lx:
    3238             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3239             :       ASMJIT_FALLTHROUGH;
    3240             : 
    3241             :     case InstDB::kEncodingVexRvmi:
    3242        1976 : VexRvmi:
    3243             :     {
    3244             :       const Operand_& o3 = opExt[EmitterUtils::kOp3];
    3245        1976 :       const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
    3246             : 
    3247             :       immValue = o3.as<Imm>().value();
    3248             :       immSize = 1;
    3249             : 
    3250        1976 :       if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) {
    3251             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3252             :         rbReg = o2.id();
    3253        1567 :         goto EmitVexEvexR;
    3254             :       }
    3255             : 
    3256         409 :       if (isign4 == ENC_OPS4(Reg, Reg, Mem, Imm)) {
    3257             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3258             :         rmRel = &o2;
    3259         409 :         goto EmitVexEvexM;
    3260             :       }
    3261             :       break;
    3262             :     }
    3263             : 
    3264             :     case InstDB::kEncodingVexRmv_Wx:
    3265           0 :       opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o2));
    3266             :       ASMJIT_FALLTHROUGH;
    3267             : 
    3268           0 :     case InstDB::kEncodingVexRmv:
    3269           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3270             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3271             :         rbReg = o1.id();
    3272           0 :         goto EmitVexEvexR;
    3273             :       }
    3274             : 
    3275           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
    3276             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3277             :         rmRel = &o1;
    3278           0 :         goto EmitVexEvexM;
    3279             :       }
    3280             :       break;
    3281             : 
    3282           0 :     case InstDB::kEncodingVexRmvRm_VM:
    3283           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    3284             :         opcode  = x86AltOpcodeOf(instInfo);
    3285             :         opcode |= Support::max(x86OpcodeLByVMem(o1), x86OpcodeLBySize(o0.size()));
    3286             : 
    3287             :         opReg = o0.id();
    3288             :         rmRel = &o1;
    3289           0 :         goto EmitVexEvexM;
    3290             :       }
    3291             :       ASMJIT_FALLTHROUGH;
    3292             : 
    3293             :     case InstDB::kEncodingVexRmv_VM:
    3294           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
    3295             :         opcode |= Support::max(x86OpcodeLByVMem(o1), x86OpcodeLBySize(o0.size() | o2.size()));
    3296             : 
    3297             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3298             :         rmRel = &o1;
    3299           0 :         goto EmitVexEvexM;
    3300             :       }
    3301             :       break;
    3302             : 
    3303             : 
    3304           0 :     case InstDB::kEncodingVexRmvi: {
    3305             :       const Operand_& o3 = opExt[EmitterUtils::kOp3];
    3306           0 :       const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
    3307             : 
    3308             :       immValue = o3.as<Imm>().value();
    3309             :       immSize = 1;
    3310             : 
    3311           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) {
    3312             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3313             :         rbReg = o1.id();
    3314           0 :         goto EmitVexEvexR;
    3315             :       }
    3316             : 
    3317           0 :       if (isign4 == ENC_OPS4(Reg, Mem, Reg, Imm)) {
    3318             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3319             :         rmRel = &o1;
    3320           0 :         goto EmitVexEvexM;
    3321             :       }
    3322             :       break;
    3323             :     }
    3324             : 
    3325           0 :     case InstDB::kEncodingVexMovdMovq:
    3326           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    3327           0 :         if (Reg::isGp(o0)) {
    3328             :           opcode = x86AltOpcodeOf(instInfo);
    3329             :           opcode.addWBySize(o0.size());
    3330             :           opReg = o1.id();
    3331             :           rbReg = o0.id();
    3332           0 :           goto EmitVexEvexR;
    3333             :         }
    3334             : 
    3335           0 :         if (Reg::isGp(o1)) {
    3336             :           opcode.addWBySize(o1.size());
    3337             :           opReg = o0.id();
    3338             :           rbReg = o1.id();
    3339           0 :           goto EmitVexEvexR;
    3340             :         }
    3341             : 
    3342             :         // If this is a 'W' version (movq) then allow also vmovq 'xmm|xmm' form.
    3343           0 :         if (opcode & Opcode::kEvex_W_1) {
    3344             :           opcode &= ~(Opcode::kPP_VEXMask | Opcode::kMM_Mask | 0xFF);
    3345             :           opcode |=  (Opcode::kF30F00 | 0x7E);
    3346             : 
    3347             :           opReg = o0.id();
    3348             :           rbReg = o1.id();
    3349           0 :           goto EmitVexEvexR;
    3350             :         }
    3351             :       }
    3352             : 
    3353           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    3354           0 :         if (opcode & Opcode::kEvex_W_1) {
    3355             :           opcode &= ~(Opcode::kPP_VEXMask | Opcode::kMM_Mask | 0xFF);
    3356             :           opcode |=  (Opcode::kF30F00 | 0x7E);
    3357             :         }
    3358             : 
    3359             :         opReg = o0.id();
    3360             :         rmRel = &o1;
    3361           0 :         goto EmitVexEvexM;
    3362             :       }
    3363             : 
    3364             :       // The following instruction uses the secondary opcode.
    3365             :       opcode = x86AltOpcodeOf(instInfo);
    3366             : 
    3367           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    3368           0 :         if (opcode & Opcode::kEvex_W_1) {
    3369             :           opcode &= ~(Opcode::kPP_VEXMask | Opcode::kMM_Mask | 0xFF);
    3370             :           opcode |=  (Opcode::k660F00 | 0xD6);
    3371             :         }
    3372             : 
    3373             :         opReg = o1.id();
    3374             :         rmRel = &o0;
    3375           0 :         goto EmitVexEvexM;
    3376             :       }
    3377             :       break;
    3378             : 
    3379             :     case InstDB::kEncodingVexRmMr_Lx:
    3380             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3381             :       ASMJIT_FALLTHROUGH;
    3382             : 
    3383        1785 :     case InstDB::kEncodingVexRmMr:
    3384        1785 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    3385             :         opReg = o0.id();
    3386             :         rbReg = o1.id();
    3387        1785 :         goto EmitVexEvexR;
    3388             :       }
    3389             : 
    3390           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    3391             :         opReg = o0.id();
    3392             :         rmRel = &o1;
    3393           0 :         goto EmitVexEvexM;
    3394             :       }
    3395             : 
    3396             :       // The following instruction uses the secondary opcode.
    3397             :       opcode &= Opcode::kLL_Mask;
    3398             :       opcode |= x86AltOpcodeOf(instInfo);
    3399             : 
    3400           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    3401             :         opReg = o1.id();
    3402             :         rmRel = &o0;
    3403           0 :         goto EmitVexEvexM;
    3404             :       }
    3405             :       break;
    3406             : 
    3407           0 :     case InstDB::kEncodingVexRvmRmv:
    3408           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3409             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3410             :         rbReg = o1.id();
    3411             : 
    3412           0 :         if (!Support::test(options, InstOptions::kX86_ModMR))
    3413           0 :           goto EmitVexEvexR;
    3414             : 
    3415             :         opcode.addW();
    3416             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3417             :         rbReg = o2.id();
    3418           0 :         goto EmitVexEvexR;
    3419             :       }
    3420             : 
    3421           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
    3422             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3423             :         rmRel = &o1;
    3424           0 :         goto EmitVexEvexM;
    3425             :       }
    3426             : 
    3427           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
    3428             :         opcode.addW();
    3429             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3430             :         rmRel = &o2;
    3431           0 :         goto EmitVexEvexM;
    3432             :       }
    3433             :       break;
    3434             : 
    3435             :     case InstDB::kEncodingVexRvmRmi_Lx:
    3436             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3437             :       ASMJIT_FALLTHROUGH;
    3438             : 
    3439           0 :     case InstDB::kEncodingVexRvmRmi:
    3440           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3441             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3442             :         rbReg = o2.id();
    3443           0 :         goto EmitVexEvexR;
    3444             :       }
    3445             : 
    3446           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
    3447             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3448             :         rmRel = &o2;
    3449           0 :         goto EmitVexEvexM;
    3450             :       }
    3451             : 
    3452             :       // The following instructions use the secondary opcode.
    3453             :       opcode &= Opcode::kLL_Mask;
    3454             :       opcode |= x86AltOpcodeOf(instInfo);
    3455             : 
    3456             :       immValue = o2.as<Imm>().value();
    3457             :       immSize = 1;
    3458             : 
    3459           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    3460             :         opReg = o0.id();
    3461             :         rbReg = o1.id();
    3462           0 :         goto EmitVexEvexR;
    3463             :       }
    3464             : 
    3465           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
    3466             :         opReg = o0.id();
    3467             :         rmRel = &o1;
    3468           0 :         goto EmitVexEvexM;
    3469             :       }
    3470             :       break;
    3471             : 
    3472           0 :     case InstDB::kEncodingVexRvmRmvRmi:
    3473           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3474             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3475             :         rbReg = o1.id();
    3476             : 
    3477           0 :         if (!Support::test(options, InstOptions::kX86_ModMR))
    3478           0 :           goto EmitVexEvexR;
    3479             : 
    3480             :         opcode.addW();
    3481             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3482             :         rbReg = o2.id();
    3483           0 :         goto EmitVexEvexR;
    3484             :       }
    3485             : 
    3486           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
    3487             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3488             :         rmRel = &o1;
    3489           0 :         goto EmitVexEvexM;
    3490             :       }
    3491             : 
    3492           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
    3493             :         opcode.addW();
    3494             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3495             :         rmRel = &o2;
    3496           0 :         goto EmitVexEvexM;
    3497             :       }
    3498             : 
    3499             :       // The following instructions use the secondary opcode.
    3500             :       opcode = x86AltOpcodeOf(instInfo);
    3501             : 
    3502             :       immValue = o2.as<Imm>().value();
    3503             :       immSize = 1;
    3504             : 
    3505           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    3506             :         opReg = o0.id();
    3507             :         rbReg = o1.id();
    3508           0 :         goto EmitVexEvexR;
    3509             :       }
    3510             : 
    3511           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
    3512             :         opReg = o0.id();
    3513             :         rmRel = &o1;
    3514           0 :         goto EmitVexEvexM;
    3515             :       }
    3516             :       break;
    3517             : 
    3518           0 :     case InstDB::kEncodingVexRvmMr:
    3519           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3520             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3521             :         rbReg = o2.id();
    3522           0 :         goto EmitVexEvexR;
    3523             :       }
    3524             : 
    3525           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
    3526             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3527             :         rmRel = &o2;
    3528           0 :         goto EmitVexEvexM;
    3529             :       }
    3530             : 
    3531             :       // The following instructions use the secondary opcode.
    3532             :       opcode = x86AltOpcodeOf(instInfo);
    3533             : 
    3534           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    3535             :         opReg = o1.id();
    3536             :         rbReg = o0.id();
    3537           0 :         goto EmitVexEvexR;
    3538             :       }
    3539             : 
    3540           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    3541             :         opReg = o1.id();
    3542             :         rmRel = &o0;
    3543           0 :         goto EmitVexEvexM;
    3544             :       }
    3545             :       break;
    3546             : 
    3547             :     case InstDB::kEncodingVexRvmMvr_Lx:
    3548             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3549             :       ASMJIT_FALLTHROUGH;
    3550             : 
    3551           0 :     case InstDB::kEncodingVexRvmMvr:
    3552           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3553             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3554             :         rbReg = o2.id();
    3555           0 :         goto EmitVexEvexR;
    3556             :       }
    3557             : 
    3558           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
    3559             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3560             :         rmRel = &o2;
    3561           0 :         goto EmitVexEvexM;
    3562             :       }
    3563             : 
    3564             :       // The following instruction uses the secondary opcode.
    3565             :       opcode &= Opcode::kLL_Mask;
    3566             :       opcode |= x86AltOpcodeOf(instInfo);
    3567             : 
    3568           0 :       if (isign3 == ENC_OPS3(Mem, Reg, Reg)) {
    3569             :         opReg = x86PackRegAndVvvvv(o2.id(), o1.id());
    3570             :         rmRel = &o0;
    3571           0 :         goto EmitVexEvexM;
    3572             :       }
    3573             :       break;
    3574             : 
    3575             :     case InstDB::kEncodingVexRvmVmi_Lx_MEvex:
    3576             :       opcode.forceEvexIf(o1.isMem());
    3577             :       ASMJIT_FALLTHROUGH;
    3578             : 
    3579           0 :     case InstDB::kEncodingVexRvmVmi_Lx:
    3580             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3581             :       ASMJIT_FALLTHROUGH;
    3582             : 
    3583           0 :     case InstDB::kEncodingVexRvmVmi:
    3584           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3585             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3586             :         rbReg = o2.id();
    3587           0 :         goto EmitVexEvexR;
    3588             :       }
    3589             : 
    3590           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
    3591             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3592             :         rmRel = &o2;
    3593           0 :         goto EmitVexEvexM;
    3594             :       }
    3595             : 
    3596             :       // The following instruction uses the secondary opcode.
    3597             :       opcode &= Opcode::kLL_Mask | Opcode::kMM_ForceEvex;
    3598             :       opcode |= x86AltOpcodeOf(instInfo);
    3599             :       opReg = opcode.extractModO();
    3600             : 
    3601             :       immValue = o2.as<Imm>().value();
    3602             :       immSize = 1;
    3603             : 
    3604           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    3605             :         opReg = x86PackRegAndVvvvv(opReg, o0.id());
    3606             :         rbReg = o1.id();
    3607           0 :         goto EmitVexEvexR;
    3608             :       }
    3609             : 
    3610           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
    3611             :         opReg = x86PackRegAndVvvvv(opReg, o0.id());
    3612             :         rmRel = &o1;
    3613           0 :         goto EmitVexEvexM;
    3614             :       }
    3615             :       break;
    3616             : 
    3617             :     case InstDB::kEncodingVexVm_Wx:
    3618           0 :       opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o1));
    3619             :       ASMJIT_FALLTHROUGH;
    3620             : 
    3621           0 :     case InstDB::kEncodingVexVm:
    3622           0 :       if (isign3 == ENC_OPS2(Reg, Reg)) {
    3623             :         opReg = x86PackRegAndVvvvv(opReg, o0.id());
    3624             :         rbReg = o1.id();
    3625           0 :         goto EmitVexEvexR;
    3626             :       }
    3627             : 
    3628           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    3629             :         opReg = x86PackRegAndVvvvv(opReg, o0.id());
    3630             :         rmRel = &o1;
    3631           0 :         goto EmitVexEvexM;
    3632             :       }
    3633             :       break;
    3634             : 
    3635           0 :     case InstDB::kEncodingVexVmi_Lx_MEvex:
    3636           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Imm))
    3637             :         opcode.forceEvex();
    3638             :       ASMJIT_FALLTHROUGH;
    3639             : 
    3640             :     case InstDB::kEncodingVexVmi_Lx:
    3641             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3642             :       ASMJIT_FALLTHROUGH;
    3643             : 
    3644           0 :     case InstDB::kEncodingVexVmi:
    3645             :       immValue = o2.as<Imm>().value();
    3646             :       immSize = 1;
    3647             : 
    3648           0 : CaseVexVmi_AfterImm:
    3649           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
    3650             :         opReg = x86PackRegAndVvvvv(opReg, o0.id());
    3651             :         rbReg = o1.id();
    3652           0 :         goto EmitVexEvexR;
    3653             :       }
    3654             : 
    3655           0 :       if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
    3656             :         opReg = x86PackRegAndVvvvv(opReg, o0.id());
    3657             :         rmRel = &o1;
    3658           0 :         goto EmitVexEvexM;
    3659             :       }
    3660             :       break;
    3661             : 
    3662             :     case InstDB::kEncodingVexVmi4_Wx:
    3663           0 :       opcode.addWIf(Reg::isGpq(o0) || o1.size() == 8);
    3664             :       immValue = o2.as<Imm>().value();
    3665             :       immSize = 4;
    3666           0 :       goto CaseVexVmi_AfterImm;
    3667             : 
    3668             :     case InstDB::kEncodingVexRvrmRvmr_Lx:
    3669             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3670             :       ASMJIT_FALLTHROUGH;
    3671             : 
    3672           0 :     case InstDB::kEncodingVexRvrmRvmr: {
    3673             :       const Operand_& o3 = opExt[EmitterUtils::kOp3];
    3674           0 :       const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
    3675             : 
    3676           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
    3677             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3678             :         rbReg = o2.id();
    3679             : 
    3680           0 :         immValue = o3.id() << 4;
    3681             :         immSize = 1;
    3682           0 :         goto EmitVexEvexR;
    3683             :       }
    3684             : 
    3685           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) {
    3686             :         opcode.addW();
    3687             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3688             :         rmRel = &o3;
    3689             : 
    3690           0 :         immValue = o2.id() << 4;
    3691             :         immSize = 1;
    3692           0 :         goto EmitVexEvexM;
    3693             :       }
    3694             : 
    3695           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
    3696             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3697             :         rmRel = &o2;
    3698             : 
    3699           0 :         immValue = o3.id() << 4;
    3700             :         immSize = 1;
    3701           0 :         goto EmitVexEvexM;
    3702             :       }
    3703             :       break;
    3704             :     }
    3705             : 
    3706           0 :     case InstDB::kEncodingVexRvrmiRvmri_Lx: {
    3707             :       const Operand_& o3 = opExt[EmitterUtils::kOp3];
    3708             :       const Operand_& o4 = opExt[EmitterUtils::kOp4];
    3709             : 
    3710           0 :       if (ASMJIT_UNLIKELY(!o4.isImm()))
    3711           0 :         goto InvalidInstruction;
    3712             : 
    3713           0 :       const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
    3714             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size() | o2.size() | o3.size());
    3715             : 
    3716           0 :       immValue = o4.as<Imm>().valueAs<uint8_t>() & 0x0F;
    3717             :       immSize = 1;
    3718             : 
    3719           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
    3720             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3721             :         rbReg = o2.id();
    3722             : 
    3723           0 :         immValue |= o3.id() << 4;
    3724           0 :         goto EmitVexEvexR;
    3725             :       }
    3726             : 
    3727           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) {
    3728             :         opcode.addW();
    3729             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3730             :         rmRel = &o3;
    3731             : 
    3732           0 :         immValue |= o2.id() << 4;
    3733           0 :         goto EmitVexEvexM;
    3734             :       }
    3735             : 
    3736           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
    3737             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3738             :         rmRel = &o2;
    3739             : 
    3740           0 :         immValue |= o3.id() << 4;
    3741           0 :         goto EmitVexEvexM;
    3742             :       }
    3743             :       break;
    3744             :     }
    3745             : 
    3746      150197 :     case InstDB::kEncodingVexMovssMovsd:
    3747      150197 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3748       30807 :         goto CaseVexRvm_R;
    3749             :       }
    3750             : 
    3751      119390 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    3752             :         opReg = o0.id();
    3753             :         rmRel = &o1;
    3754       88508 :         goto EmitVexEvexM;
    3755             :       }
    3756             : 
    3757       30882 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    3758             :         opcode = x86AltOpcodeOf(instInfo);
    3759             :         opReg = o1.id();
    3760             :         rmRel = &o0;
    3761       30882 :         goto EmitVexEvexM;
    3762             :       }
    3763             :       break;
    3764             : 
    3765             :     // FMA4 Instructions
    3766             :     // -----------------
    3767             : 
    3768             :     case InstDB::kEncodingFma4_Lx:
    3769             :       // It's fine to just check the first operand, second is just for sanity.
    3770             :       opcode |= x86OpcodeLBySize(o0.size() | o1.size());
    3771             :       ASMJIT_FALLTHROUGH;
    3772             : 
    3773           0 :     case InstDB::kEncodingFma4: {
    3774             :       const Operand_& o3 = opExt[EmitterUtils::kOp3];
    3775           0 :       const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
    3776             : 
    3777           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
    3778             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3779             : 
    3780           0 :         if (!Support::test(options, InstOptions::kX86_ModMR)) {
    3781             :           // MOD/RM - Encoding preferred by LLVM.
    3782             :           opcode.addW();
    3783             :           rbReg = o3.id();
    3784             : 
    3785           0 :           immValue = o2.id() << 4;
    3786             :           immSize = 1;
    3787           0 :           goto EmitVexEvexR;
    3788             :         }
    3789             :         else {
    3790             :           // MOD/MR - Alternative encoding.
    3791             :           rbReg = o2.id();
    3792             : 
    3793           0 :           immValue = o3.id() << 4;
    3794             :           immSize = 1;
    3795           0 :           goto EmitVexEvexR;
    3796             :         }
    3797             :       }
    3798             : 
    3799           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) {
    3800             :         opcode.addW();
    3801             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3802             :         rmRel = &o3;
    3803             : 
    3804           0 :         immValue = o2.id() << 4;
    3805             :         immSize = 1;
    3806           0 :         goto EmitVexEvexM;
    3807             :       }
    3808             : 
    3809           0 :       if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
    3810             :         opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
    3811             :         rmRel = &o2;
    3812             : 
    3813           0 :         immValue = o3.id() << 4;
    3814             :         immSize = 1;
    3815           0 :         goto EmitVexEvexM;
    3816             :       }
    3817             :       break;
    3818             :     }
    3819             : 
    3820             :     // AMX Instructions
    3821             :     // ----------------
    3822             : 
    3823           0 :     case InstDB::kEncodingAmxCfg:
    3824           0 :       if (isign3 == ENC_OPS1(Mem)) {
    3825             :         rmRel = &o0;
    3826           0 :         goto EmitVexEvexM;
    3827             :       }
    3828             :       break;
    3829             : 
    3830           0 :     case InstDB::kEncodingAmxR:
    3831           0 :       if (isign3 == ENC_OPS1(Reg)) {
    3832             :         opReg = o0.id();
    3833             :         rbReg = 0;
    3834           0 :         goto EmitVexEvexR;
    3835             :       }
    3836             :       break;
    3837             : 
    3838           0 :     case InstDB::kEncodingAmxRm:
    3839           0 :       if (isign3 == ENC_OPS2(Reg, Mem)) {
    3840             :         opReg = o0.id();
    3841             :         rmRel = &o1;
    3842           0 :         goto EmitVexEvexM;
    3843             :       }
    3844             :       break;
    3845             : 
    3846           0 :     case InstDB::kEncodingAmxMr:
    3847           0 :       if (isign3 == ENC_OPS2(Mem, Reg)) {
    3848             :         opReg = o1.id();
    3849             :         rmRel = &o0;
    3850           0 :         goto EmitVexEvexM;
    3851             :       }
    3852             :       break;
    3853             : 
    3854           0 :     case InstDB::kEncodingAmxRmv:
    3855           0 :       if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
    3856             :         opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
    3857             :         rbReg = o1.id();
    3858           0 :         goto EmitVexEvexR;
    3859             :       }
    3860             :       break;
    3861             :   }
    3862             : 
    3863           0 :   goto InvalidInstruction;
    3864             : 
    3865             :   // Emit - X86 Opcode
    3866             :   // -----------------
    3867             : 
    3868           0 : EmitX86OpMovAbs:
    3869           0 :   immSize = FastUInt8(registerSize());
    3870             :   writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
    3871             : 
    3872       27492 : EmitX86Op:
    3873             :   // Emit mandatory instruction prefix.
    3874             :   writer.emitPP(opcode.v);
    3875             : 
    3876             :   // Emit REX prefix (64-bit only).
    3877             :   {
    3878             :     uint32_t rex = opcode.extractRex(options);
    3879       27492 :     if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
    3880           0 :       goto InvalidRexPrefix;
    3881       27492 :     rex &= ~kX86ByteInvalidRex & 0xFF;
    3882       27492 :     writer.emit8If(rex | kX86ByteRex, rex != 0);
    3883             :   }
    3884             : 
    3885             :   // Emit instruction opcodes.
    3886             :   writer.emitMMAndOpcode(opcode.v);
    3887       27492 :   writer.emitImmediate(uint64_t(immValue), immSize);
    3888       27492 :   goto EmitDone;
    3889             : 
    3890             :   // Emit - X86 - Opcode + Reg
    3891             :   // -------------------------
    3892             : 
    3893       88236 : EmitX86OpReg:
    3894             :   // Emit mandatory instruction prefix.
    3895             :   writer.emitPP(opcode.v);
    3896             : 
    3897             :   // Emit REX prefix (64-bit only).
    3898             :   {
    3899       88236 :     uint32_t rex = opcode.extractRex(options) | (opReg >> 3); // Rex.B (0x01).
    3900       88236 :     if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
    3901           0 :       goto InvalidRexPrefix;
    3902       88236 :     rex &= ~kX86ByteInvalidRex & 0xFF;
    3903       88236 :     writer.emit8If(rex | kX86ByteRex, rex != 0);
    3904             : 
    3905       88236 :     opReg &= 0x7;
    3906             :   }
    3907             : 
    3908             :   // Emit instruction opcodes.
    3909             :   opcode += opReg;
    3910             :   writer.emitMMAndOpcode(opcode.v);
    3911       88236 :   writer.emitImmediate(uint64_t(immValue), immSize);
    3912       88236 :   goto EmitDone;
    3913             : 
    3914             :   // Emit - X86 - Opcode with Implicit <mem> Operand
    3915             :   // -----------------------------------------------
    3916             : 
    3917           0 : EmitX86OpImplicitMem:
    3918           0 :   rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
    3919           0 :   if (ASMJIT_UNLIKELY(rmRel->as<Mem>().hasOffset() || (rmInfo & kX86MemInfo_Index)))
    3920           0 :     goto InvalidInstruction;
    3921             : 
    3922             :   // Emit mandatory instruction prefix.
    3923             :   writer.emitPP(opcode.v);
    3924             : 
    3925             :   // Emit REX prefix (64-bit only).
    3926             :   {
    3927             :     uint32_t rex = opcode.extractRex(options);
    3928           0 :     if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
    3929           0 :       goto InvalidRexPrefix;
    3930           0 :     rex &= ~kX86ByteInvalidRex & 0xFF;
    3931           0 :     writer.emit8If(rex | kX86ByteRex, rex != 0);
    3932             :   }
    3933             : 
    3934             :   // Emit override prefixes.
    3935             :   writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
    3936           0 :   writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
    3937             : 
    3938             :   // Emit instruction opcodes.
    3939             :   writer.emitMMAndOpcode(opcode.v);
    3940             : 
    3941             :   // Emit immediate value.
    3942             :   writer.emitImmediate(uint64_t(immValue), immSize);
    3943           0 :   goto EmitDone;
    3944             : 
    3945             :   // Emit - X86 - Opcode /r - Register
    3946             :   // ---------------------------------
    3947             : 
    3948       19619 : EmitX86R:
    3949             :   // Mandatory instruction prefix.
    3950             :   writer.emitPP(opcode.v);
    3951             : 
    3952             :   // Emit REX prefix (64-bit only).
    3953             :   {
    3954       19619 :     uint32_t rex = opcode.extractRex(options) |
    3955       19619 :                    ((opReg & 0x08) >> 1) | // REX.R (0x04).
    3956       19619 :                    ((rbReg & 0x08) >> 3) ; // REX.B (0x01).
    3957             : 
    3958       19619 :     if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
    3959           0 :       goto InvalidRexPrefix;
    3960       19619 :     rex &= ~kX86ByteInvalidRex & 0xFF;
    3961       19619 :     writer.emit8If(rex | kX86ByteRex, rex != 0);
    3962             : 
    3963             :     opReg &= 0x07;
    3964       19619 :     rbReg &= 0x07;
    3965             :   }
    3966             : 
    3967             :   // Emit instruction opcodes.
    3968             :   writer.emitMMAndOpcode(opcode.v);
    3969             : 
    3970             :   // Emit ModR.
    3971             :   writer.emit8(x86EncodeMod(3, opReg, rbReg));
    3972             : 
    3973             :   // Emit immediate value.
    3974       19619 :   writer.emitImmediate(uint64_t(immValue), immSize);
    3975       19619 :   goto EmitDone;
    3976             : 
    3977             :   // Emit - X86 - Opcode /r - Memory Base
    3978             :   // ------------------------------------
    3979             : 
    3980             : EmitX86RFromM:
    3981           0 :   rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
    3982           0 :   if (ASMJIT_UNLIKELY(rmRel->as<Mem>().hasOffset() || (rmInfo & kX86MemInfo_Index)))
    3983           0 :     goto InvalidInstruction;
    3984             : 
    3985             :   // Emit mandatory instruction prefix.
    3986             :   writer.emitPP(opcode.v);
    3987             : 
    3988             :   // Emit REX prefix (64-bit only).
    3989             :   {
    3990             :     uint32_t rex = opcode.extractRex(options) |
    3991             :                    ((opReg & 0x08) >> 1) | // REX.R (0x04).
    3992           0 :                    ((rbReg       ) >> 3) ; // REX.B (0x01).
    3993             : 
    3994           0 :     if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
    3995           0 :       goto InvalidRexPrefix;
    3996           0 :     rex &= ~kX86ByteInvalidRex & 0xFF;
    3997           0 :     writer.emit8If(rex | kX86ByteRex, rex != 0);
    3998             : 
    3999             :     opReg &= 0x07;
    4000           0 :     rbReg &= 0x07;
    4001             :   }
    4002             : 
    4003             :   // Emit override prefixes.
    4004             :   writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
    4005           0 :   writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
    4006             : 
    4007             :   // Emit instruction opcodes.
    4008             :   writer.emitMMAndOpcode(opcode.v);
    4009             : 
    4010             :   // Emit ModR/M.
    4011             :   writer.emit8(x86EncodeMod(3, opReg, rbReg));
    4012             : 
    4013             :   // Emit immediate value.
    4014             :   writer.emitImmediate(uint64_t(immValue), immSize);
    4015           0 :   goto EmitDone;
    4016             : 
    4017             :   // Emit - X86 - Opcode /r - memory Operand
    4018             :   // ---------------------------------------
    4019             : 
    4020          20 : EmitX86M:
    4021             :   // `rmRel` operand must be memory.
    4022             :   ASMJIT_ASSERT(rmRel != nullptr);
    4023             :   ASMJIT_ASSERT(rmRel->opType() == OperandType::kMem);
    4024             :   ASMJIT_ASSERT((opcode & Opcode::kCDSHL_Mask) == 0);
    4025             : 
    4026             :   // Emit override prefixes.
    4027          20 :   rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
    4028             :   writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
    4029             : 
    4030             :   memOpAOMark = writer.cursor();
    4031          20 :   writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
    4032             : 
    4033             :   // Emit mandatory instruction prefix.
    4034             :   writer.emitPP(opcode.v);
    4035             : 
    4036             :   // Emit REX prefix (64-bit only).
    4037             :   rbReg = rmRel->as<Mem>().baseId();
    4038             :   rxReg = rmRel->as<Mem>().indexId();
    4039             :   {
    4040             :     uint32_t rex;
    4041             : 
    4042          20 :     rex  = (rbReg >> 3) & 0x01; // REX.B (0x01).
    4043          20 :     rex |= (rxReg >> 2) & 0x02; // REX.X (0x02).
    4044          20 :     rex |= (opReg >> 1) & 0x04; // REX.R (0x04).
    4045             : 
    4046          20 :     rex &= rmInfo;
    4047          20 :     rex |= opcode.extractRex(options);
    4048             : 
    4049          20 :     if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
    4050           0 :       goto InvalidRexPrefix;
    4051          20 :     rex &= ~kX86ByteInvalidRex & 0xFF;
    4052          20 :     writer.emit8If(rex | kX86ByteRex, rex != 0);
    4053             : 
    4054          20 :     opReg &= 0x07;
    4055             :   }
    4056             : 
    4057             :   // Emit instruction opcodes.
    4058             :   writer.emitMMAndOpcode(opcode.v);
    4059             : 
    4060             :   // ... Fall through ...
    4061             : 
    4062             :   // Emit - MOD/SIB
    4063             :   // --------------
    4064             : 
    4065      142105 : EmitModSib:
    4066      142105 :   if (!(rmInfo & (kX86MemInfo_Index | kX86MemInfo_67H_X86))) {
    4067             :     // ==========|> [BASE + DISP8|DISP32].
    4068      142105 :     if (rmInfo & kX86MemInfo_BaseGp) {
    4069      142105 :       rbReg &= 0x7;
    4070             :       relOffset = rmRel->as<Mem>().offsetLo32();
    4071             : 
    4072             :       uint32_t mod = x86EncodeMod(0, opReg, rbReg);
    4073             :       bool forceSIB = commonInfo->isTsibOp();
    4074             : 
    4075      142105 :       if (rbReg == Gp::kIdSp || forceSIB) {
    4076             :         // TSIB or [XSP|R12].
    4077       71131 :         mod = (mod & 0xF8u) | 0x04u;
    4078       71131 :         if (rbReg != Gp::kIdBp && relOffset == 0) {
    4079             :           writer.emit8(mod);
    4080             :           writer.emit8(x86EncodeSib(0, 4, rbReg));
    4081             :         }
    4082             :         // TSIB or [XSP|R12 + DISP8|DISP32].
    4083             :         else {
    4084       63178 :           uint32_t cdShift = (opcode & Opcode::kCDSHL_Mask) >> Opcode::kCDSHL_Shift;
    4085       63178 :           int32_t cdOffset = relOffset >> cdShift;
    4086             : 
    4087       32614 :           if (Support::isInt8(cdOffset) && relOffset == int32_t(uint32_t(cdOffset) << cdShift)) {
    4088       32614 :             writer.emit8(mod + 0x40); // <- MOD(1, opReg, rbReg).
    4089             :             writer.emit8(x86EncodeSib(0, 4, rbReg));
    4090             :             writer.emit8(cdOffset & 0xFF);
    4091             :           }
    4092             :           else {
    4093       30564 :             writer.emit8(mod + 0x80); // <- MOD(2, opReg, rbReg).
    4094             :             writer.emit8(x86EncodeSib(0, 4, rbReg));
    4095             :             writer.emit32uLE(uint32_t(relOffset));
    4096             :           }
    4097             :         }
    4098             :       }
    4099       70974 :       else if (rbReg != Gp::kIdBp && relOffset == 0) {
    4100             :         // [BASE].
    4101             :         writer.emit8(mod);
    4102             :       }
    4103             :       else {
    4104             :         // [BASE + DISP8|DISP32].
    4105       19963 :         uint32_t cdShift = (opcode & Opcode::kCDSHL_Mask) >> Opcode::kCDSHL_Shift;
    4106       19963 :         int32_t cdOffset = relOffset >> cdShift;
    4107             : 
    4108       13828 :         if (Support::isInt8(cdOffset) && relOffset == int32_t(uint32_t(cdOffset) << cdShift)) {
    4109       13828 :           writer.emit8(mod + 0x40);
    4110             :           writer.emit8(cdOffset & 0xFF);
    4111             :         }
    4112             :         else {
    4113        6135 :           writer.emit8(mod + 0x80);
    4114             :           writer.emit32uLE(uint32_t(relOffset));
    4115             :         }
    4116             :       }
    4117             :     }
    4118             :     // ==========|> [ABSOLUTE | DISP32].
    4119           0 :     else if (!(rmInfo & (kX86MemInfo_BaseLabel | kX86MemInfo_BaseRip))) {
    4120             :       Mem::AddrType addrType = rmRel->as<Mem>().addrType();
    4121             :       relOffset = rmRel->as<Mem>().offsetLo32();
    4122             : 
    4123           0 :       if (is32Bit()) {
    4124             :         // Explicit relative addressing doesn't work in 32-bit mode.
    4125           0 :         if (ASMJIT_UNLIKELY(addrType == Mem::AddrType::kRel))
    4126           0 :           goto InvalidAddress;
    4127             : 
    4128             :         writer.emit8(x86EncodeMod(0, opReg, 5));
    4129             :         writer.emit32uLE(uint32_t(relOffset));
    4130             :       }
    4131             :       else {
    4132           0 :         bool isOffsetI32 = rmRel->as<Mem>().offsetHi32() == (relOffset >> 31);
    4133           0 :         bool isOffsetU32 = rmRel->as<Mem>().offsetHi32() == 0;
    4134             :         uint64_t baseAddress = code()->baseAddress();
    4135             : 
    4136             :         // If relative addressing was not explicitly set then we can try to guess. By guessing we check some
    4137             :         // properties of the memory operand and try to base the decision on the segment prefix and the address type.
    4138           0 :         if (addrType == Mem::AddrType::kDefault) {
    4139           0 :           if (baseAddress == Globals::kNoBaseAddress) {
    4140             :             // Prefer absolute addressing mode if the offset is 32-bit.
    4141           0 :             addrType = isOffsetI32 || isOffsetU32 ? Mem::AddrType::kAbs
    4142             :                                                   : Mem::AddrType::kRel;
    4143             :           }
    4144             :           else {
    4145             :             // Prefer absolute addressing mode if FS|GS segment override is present.
    4146           0 :             bool hasFsGs = rmRel->as<Mem>().segmentId() >= SReg::kIdFs;
    4147             :             // Prefer absolute addressing mode if this is LEA with 32-bit immediate.
    4148           0 :             bool isLea32 = (instId == Inst::kIdLea) && (isOffsetI32 || isOffsetU32);
    4149             : 
    4150           0 :             addrType = hasFsGs || isLea32 ? Mem::AddrType::kAbs
    4151             :                                           : Mem::AddrType::kRel;
    4152             :           }
    4153             :         }
    4154             : 
    4155           0 :         if (addrType == Mem::AddrType::kRel) {
    4156             :           uint32_t kModRel32Size = 5;
    4157           0 :           uint64_t virtualOffset = uint64_t(writer.offsetFrom(_bufferData)) + immSize + kModRel32Size;
    4158             : 
    4159           0 :           if (baseAddress == Globals::kNoBaseAddress || _section->id() != 0) {
    4160             :             // Create a new RelocEntry as we cannot calculate the offset right now.
    4161           0 :             err = _code->newRelocEntry(&re, RelocType::kAbsToRel);
    4162           0 :             if (ASMJIT_UNLIKELY(err))
    4163           0 :               goto Failed;
    4164             : 
    4165             :             writer.emit8(x86EncodeMod(0, opReg, 5));
    4166             : 
    4167           0 :             re->_sourceSectionId = _section->id();
    4168           0 :             re->_sourceOffset = offset();
    4169             :             re->_format.resetToSimpleValue(OffsetType::kSignedOffset, 4);
    4170           0 :             re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_bufferPtr), immSize);
    4171           0 :             re->_payload = uint64_t(rmRel->as<Mem>().offset());
    4172             : 
    4173             :             writer.emit32uLE(0);
    4174           0 :             writer.emitImmediate(uint64_t(immValue), immSize);
    4175           0 :             goto EmitDone;
    4176             :           }
    4177             :           else {
    4178           0 :             uint64_t rip64 = baseAddress + _section->offset() + virtualOffset;
    4179           0 :             uint64_t rel64 = uint64_t(rmRel->as<Mem>().offset()) - rip64;
    4180             : 
    4181           0 :             if (Support::isInt32(int64_t(rel64))) {
    4182             :               writer.emit8(x86EncodeMod(0, opReg, 5));
    4183           0 :               writer.emit32uLE(uint32_t(rel64 & 0xFFFFFFFFu));
    4184           0 :               writer.emitImmediate(uint64_t(immValue), immSize);
    4185           0 :               goto EmitDone;
    4186             :             }
    4187             :             else {
    4188             :               // We must check the original address type as we have modified
    4189             :               // `addrType`. We failed if the original address type is 'rel'.
    4190           0 :               if (ASMJIT_UNLIKELY(rmRel->as<Mem>().isRel()))
    4191           0 :                 goto InvalidAddress;
    4192             :             }
    4193             :           }
    4194             :         }
    4195             : 
    4196             :         // Handle unsigned 32-bit address that doesn't work with sign extension. Consider the following instructions:
    4197             :         //
    4198             :         //   1. lea rax, [-1]         - Sign extended to 0xFFFFFFFFFFFFFFFF
    4199             :         //   2. lea rax, [0xFFFFFFFF] - Zero extended to 0x00000000FFFFFFFF
    4200             :         //   3. add rax, [-1]         - Sign extended to 0xFFFFFFFFFFFFFFFF
    4201             :         //   4. add rax, [0xFFFFFFFF] - Zero extended to 0x00000000FFFFFFFF
    4202             :         //
    4203             :         // Sign extension is naturally performed by the CPU so we don't have to bother, however, zero extension
    4204             :         // requires address-size override prefix, which we probably don't have at this moment. So to make the address
    4205             :         // valid we need to insert it at `memOpAOMark` if it's not already there.
    4206             :         //
    4207             :         // If this is 'lea' instruction then it's possible to remove REX.W part from REX prefix (if it's there), which
    4208             :         // would be one-byte shorter than inserting address-size override.
    4209             :         //
    4210             :         // NOTE: If we don't do this then these instructions are unencodable.
    4211           0 :         if (!isOffsetI32) {
    4212             :           // 64-bit absolute address is unencodable.
    4213           0 :           if (ASMJIT_UNLIKELY(!isOffsetU32))
    4214           0 :             goto InvalidAddress64Bit;
    4215             : 
    4216             :           // We only patch the existing code if we don't have address-size override.
    4217           0 :           if (*memOpAOMark != 0x67) {
    4218           0 :             if (instId == Inst::kIdLea) {
    4219             :               // LEA: Remove REX.W, if present. This is easy as we know that 'lea' doesn't use any PP prefix so if REX
    4220             :               // prefix was emitted it would be at `memOpAOMark`.
    4221             :               uint32_t rex = *memOpAOMark;
    4222           0 :               if (rex & kX86ByteRex) {
    4223             :                 rex &= (~kX86ByteRexW) & 0xFF;
    4224           0 :                 *memOpAOMark = uint8_t(rex);
    4225             : 
    4226             :                 // We can remove the REX prefix completely if it was not forced.
    4227           0 :                 if (rex == kX86ByteRex && !Support::test(options, InstOptions::kX86_Rex))
    4228             :                   writer.remove8(memOpAOMark);
    4229             :               }
    4230             :             }
    4231             :             else {
    4232             :               // Any other instruction: Insert address-size override prefix.
    4233             :               writer.insert8(memOpAOMark, 0x67);
    4234             :             }
    4235             :           }
    4236             :         }
    4237             : 
    4238             :         // Emit 32-bit absolute address.
    4239             :         writer.emit8(x86EncodeMod(0, opReg, 4));
    4240             :         writer.emit8(x86EncodeSib(0, 4, 5));
    4241             :         writer.emit32uLE(uint32_t(relOffset));
    4242             :       }
    4243             :     }
    4244             :     // ==========|> [LABEL|RIP + DISP32]
    4245             :     else {
    4246             :       writer.emit8(x86EncodeMod(0, opReg, 5));
    4247             : 
    4248           0 :       if (is32Bit()) {
    4249           0 : EmitModSib_LabelRip_X86:
    4250           0 :         if (ASMJIT_UNLIKELY(_code->_relocations.willGrow(_code->allocator()) != kErrorOk))
    4251           0 :           goto OutOfMemory;
    4252             : 
    4253             :         relOffset = rmRel->as<Mem>().offsetLo32();
    4254           0 :         if (rmInfo & kX86MemInfo_BaseLabel) {
    4255             :           // [LABEL->ABS].
    4256           0 :           label = _code->labelEntry(rmRel->as<Mem>().baseId());
    4257           0 :           if (ASMJIT_UNLIKELY(!label))
    4258           0 :             goto InvalidLabel;
    4259             : 
    4260           0 :           err = _code->newRelocEntry(&re, RelocType::kRelToAbs);
    4261           0 :           if (ASMJIT_UNLIKELY(err))
    4262           0 :             goto Failed;
    4263             : 
    4264           0 :           re->_sourceSectionId = _section->id();
    4265           0 :           re->_sourceOffset = offset();
    4266             :           re->_format.resetToSimpleValue(OffsetType::kUnsignedOffset, 4);
    4267           0 :           re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_bufferPtr), immSize);
    4268           0 :           re->_payload = uint64_t(int64_t(relOffset));
    4269             : 
    4270           0 :           if (label->isBound()) {
    4271             :             // Label bound to the current section.
    4272           0 :             re->_payload += label->offset();
    4273           0 :             re->_targetSectionId = label->section()->id();
    4274             :             writer.emit32uLE(0);
    4275             :           }
    4276             :           else {
    4277             :             // Non-bound label or label bound to a different section.
    4278           0 :             relOffset = -4 - immSize;
    4279             :             relSize = 4;
    4280           0 :             goto EmitRel;
    4281             :           }
    4282             :         }
    4283             :         else {
    4284             :           // [RIP->ABS].
    4285           0 :           err = _code->newRelocEntry(&re, RelocType::kRelToAbs);
    4286           0 :           if (ASMJIT_UNLIKELY(err))
    4287           0 :             goto Failed;
    4288             : 
    4289           0 :           re->_sourceSectionId = _section->id();
    4290           0 :           re->_targetSectionId = _section->id();
    4291             :           re->_format.resetToSimpleValue(OffsetType::kUnsignedOffset, 4);
    4292           0 :           re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_bufferPtr), immSize);
    4293           0 :           re->_sourceOffset = offset();
    4294           0 :           re->_payload = re->_sourceOffset + re->_format.regionSize() + uint64_t(int64_t(relOffset));
    4295             : 
    4296             :           writer.emit32uLE(0);
    4297             :         }
    4298             :       }
    4299             :       else {
    4300             :         relOffset = rmRel->as<Mem>().offsetLo32();
    4301           0 :         if (rmInfo & kX86MemInfo_BaseLabel) {
    4302             :           // [RIP].
    4303           0 :           label = _code->labelEntry(rmRel->as<Mem>().baseId());
    4304           0 :           if (ASMJIT_UNLIKELY(!label))
    4305           0 :             goto InvalidLabel;
    4306             : 
    4307           0 :           relOffset -= (4 + immSize);
    4308           0 :           if (label->isBoundTo(_section)) {
    4309             :             // Label bound to the current section.
    4310           0 :             relOffset += int32_t(label->offset() - writer.offsetFrom(_bufferData));
    4311           0 :             writer.emit32uLE(uint32_t(relOffset));
    4312             :           }
    4313             :           else {
    4314             :             // Non-bound label or label bound to a different section.
    4315             :             relSize = 4;
    4316           0 :             goto EmitRel;
    4317             :           }
    4318             :         }
    4319             :         else {
    4320             :           // [RIP].
    4321             :           writer.emit32uLE(uint32_t(relOffset));
    4322             :         }
    4323             :       }
    4324             :     }
    4325             :   }
    4326           0 :   else if (!(rmInfo & kX86MemInfo_67H_X86)) {
    4327             :     // ESP|RSP can't be used as INDEX in pure SIB mode, however, VSIB mode allows XMM4|YMM4|ZMM4 (that's why the
    4328             :     // check is before the label).
    4329           0 :     if (ASMJIT_UNLIKELY(rxReg == Gp::kIdSp))
    4330           0 :       goto InvalidAddressIndex;
    4331             : 
    4332           0 : EmitModVSib:
    4333           0 :     rxReg &= 0x7;
    4334             : 
    4335             :     // ==========|> [BASE + INDEX + DISP8|DISP32].
    4336           0 :     if (rmInfo & kX86MemInfo_BaseGp) {
    4337           0 :       rbReg &= 0x7;
    4338             :       relOffset = rmRel->as<Mem>().offsetLo32();
    4339             : 
    4340             :       uint32_t mod = x86EncodeMod(0, opReg, 4);
    4341             :       uint32_t sib = x86EncodeSib(rmRel->as<Mem>().shift(), rxReg, rbReg);
    4342             : 
    4343           0 :       if (relOffset == 0 && rbReg != Gp::kIdBp) {
    4344             :         // [BASE + INDEX << SHIFT].
    4345             :         writer.emit8(mod);
    4346             :         writer.emit8(sib);
    4347             :       }
    4348             :       else {
    4349           0 :         uint32_t cdShift = (opcode & Opcode::kCDSHL_Mask) >> Opcode::kCDSHL_Shift;
    4350           0 :         int32_t cdOffset = relOffset >> cdShift;
    4351             : 
    4352           0 :         if (Support::isInt8(cdOffset) && relOffset == int32_t(uint32_t(cdOffset) << cdShift)) {
    4353             :           // [BASE + INDEX << SHIFT + DISP8].
    4354           0 :           writer.emit8(mod + 0x40); // <- MOD(1, opReg, 4).
    4355             :           writer.emit8(sib);
    4356             :           writer.emit8(uint32_t(cdOffset));
    4357             :         }
    4358             :         else {
    4359             :           // [BASE + INDEX << SHIFT + DISP32].
    4360           0 :           writer.emit8(mod + 0x80); // <- MOD(2, opReg, 4).
    4361             :           writer.emit8(sib);
    4362             :           writer.emit32uLE(uint32_t(relOffset));
    4363             :         }
    4364             :       }
    4365             :     }
    4366             :     // ==========|> [INDEX + DISP32].
    4367           0 :     else if (!(rmInfo & (kX86MemInfo_BaseLabel | kX86MemInfo_BaseRip))) {
    4368             :       // [INDEX << SHIFT + DISP32].
    4369             :       writer.emit8(x86EncodeMod(0, opReg, 4));
    4370             :       writer.emit8(x86EncodeSib(rmRel->as<Mem>().shift(), rxReg, 5));
    4371             : 
    4372             :       relOffset = rmRel->as<Mem>().offsetLo32();
    4373             :       writer.emit32uLE(uint32_t(relOffset));
    4374             :     }
    4375             :     // ==========|> [LABEL|RIP + INDEX + DISP32].
    4376             :     else {
    4377           0 :       if (is32Bit()) {
    4378             :         writer.emit8(x86EncodeMod(0, opReg, 4));
    4379             :         writer.emit8(x86EncodeSib(rmRel->as<Mem>().shift(), rxReg, 5));
    4380           0 :         goto EmitModSib_LabelRip_X86;
    4381             :       }
    4382             :       else {
    4383             :         // NOTE: This also handles VSIB+RIP, which is not allowed in 64-bit mode.
    4384           0 :         goto InvalidAddress;
    4385             :       }
    4386             :     }
    4387             :   }
    4388             :   else {
    4389             :     // 16-bit address mode (32-bit mode with 67 override prefix).
    4390           0 :     relOffset = (int32_t(rmRel->as<Mem>().offsetLo32()) << 16) >> 16;
    4391             : 
    4392             :     // NOTE: 16-bit addresses don't use SIB byte and their encoding differs. We use a table-based approach to
    4393             :     // calculate the proper MOD byte as it's easier. Also, not all BASE [+ INDEX] combinations are supported
    4394             :     // in 16-bit mode, so this may fail.
    4395             :     const uint32_t kBaseGpIdx = (kX86MemInfo_BaseGp | kX86MemInfo_Index);
    4396             : 
    4397           0 :     if (rmInfo & kBaseGpIdx) {
    4398             :       // ==========|> [BASE + INDEX + DISP16].
    4399             :       uint32_t mod;
    4400             : 
    4401           0 :       rbReg &= 0x7;
    4402           0 :       rxReg &= 0x7;
    4403             : 
    4404           0 :       if ((rmInfo & kBaseGpIdx) == kBaseGpIdx) {
    4405             :         uint32_t shf = rmRel->as<Mem>().shift();
    4406           0 :         if (ASMJIT_UNLIKELY(shf != 0))
    4407           0 :           goto InvalidAddress;
    4408           0 :         mod = x86Mod16BaseIndexTable[(rbReg << 3) + rxReg];
    4409             :       }
    4410             :       else {
    4411           0 :         if (rmInfo & kX86MemInfo_Index)
    4412             :           rbReg = rxReg;
    4413           0 :         mod = x86Mod16BaseTable[rbReg];
    4414             :       }
    4415             : 
    4416           0 :       if (ASMJIT_UNLIKELY(mod == 0xFF))
    4417           0 :         goto InvalidAddress;
    4418             : 
    4419           0 :       mod += opReg << 3;
    4420           0 :       if (relOffset == 0 && mod != 0x06) {
    4421             :         writer.emit8(mod);
    4422             :       }
    4423             :       else if (Support::isInt8(relOffset)) {
    4424           0 :         writer.emit8(mod + 0x40);
    4425             :         writer.emit8(uint32_t(relOffset));
    4426             :       }
    4427             :       else {
    4428           0 :         writer.emit8(mod + 0x80);
    4429             :         writer.emit16uLE(uint32_t(relOffset));
    4430             :       }
    4431             :     }
    4432             :     else {
    4433             :       // Not supported in 16-bit addresses.
    4434           0 :       if (rmInfo & (kX86MemInfo_BaseRip | kX86MemInfo_BaseLabel))
    4435           0 :         goto InvalidAddress;
    4436             : 
    4437             :       // ==========|> [DISP16].
    4438           0 :       writer.emit8(opReg | 0x06);
    4439             :       writer.emit16uLE(uint32_t(relOffset));
    4440             :     }
    4441             :   }
    4442             : 
    4443      142105 :   writer.emitImmediate(uint64_t(immValue), immSize);
    4444      142105 :   goto EmitDone;
    4445             : 
    4446             :   // Emit - FPU
    4447             :   // ----------
    4448             : 
    4449           0 : EmitFpuOp:
    4450             :   // Mandatory instruction prefix.
    4451             :   writer.emitPP(opcode.v);
    4452             : 
    4453             :   // FPU instructions consist of two opcodes.
    4454           0 :   writer.emit8(opcode.v >> Opcode::kFPU_2B_Shift);
    4455             :   writer.emit8(opcode.v);
    4456           0 :   goto EmitDone;
    4457             : 
    4458             :   // Emit - VEX Opcode
    4459             :   // -----------------
    4460             : 
    4461             : EmitVexOp:
    4462             :   {
    4463             :     // These don't use immediate.
    4464             :     ASMJIT_ASSERT(immSize == 0);
    4465             : 
    4466             :     // Only 'vzeroall' and 'vzeroupper' instructions use this encoding, they don't define 'W' to be '1' so we can
    4467             :     // just check the 'mmmmm' field. Both functions can encode by using VEX2 prefix so VEX3 is basically only used
    4468             :     // when specified as instruction option.
    4469             :     ASMJIT_ASSERT((opcode & Opcode::kW) == 0);
    4470             : 
    4471           0 :     uint32_t x = (uint32_t(opcode  & Opcode::kMM_Mask      ) >> (Opcode::kMM_Shift     )) |
    4472           0 :                  (uint32_t(opcode  & Opcode::kLL_Mask      ) >> (Opcode::kLL_Shift - 10)) |
    4473           0 :                  (uint32_t(opcode  & Opcode::kPP_VEXMask   ) >> (Opcode::kPP_Shift -  8)) ;
    4474             : 
    4475           0 :     if (Support::test(options, InstOptions::kX86_Vex3)) {
    4476           0 :       x  = (x & 0xFFFF) << 8;                               // [00000000|00000Lpp|000mmmmm|00000000].
    4477           0 :       x ^= (kX86ByteVex3) |                                 // [........|00000Lpp|000mmmmm|__VEX3__].
    4478             :            (0x07u  << 13) |                                 // [........|00000Lpp|111mmmmm|__VEX3__].
    4479           0 :            (0x0Fu  << 19) |                                 // [........|01111Lpp|111mmmmm|__VEX3__].
    4480             :            (opcode << 24) ;                                 // [_OPCODE_|01111Lpp|111mmmmm|__VEX3__].
    4481             : 
    4482             :       writer.emit32uLE(x);
    4483           0 :       goto EmitDone;
    4484             :     }
    4485             :     else {
    4486           0 :       x = ((x >> 8) ^ x) ^ 0xF9;
    4487             :       writer.emit8(kX86ByteVex2);
    4488             :       writer.emit8(x);
    4489             :       writer.emit8(opcode.v);
    4490           0 :       goto EmitDone;
    4491             :     }
    4492             :   }
    4493             : 
    4494             :   // Emit - VEX|EVEX - /r - Register
    4495             :   // -------------------------------
    4496             : 
    4497      114557 : EmitVexEvexR:
    4498             :   {
    4499             :     // Construct `x` - a complete EVEX|VEX prefix.
    4500      114557 :     uint32_t x = ((opReg << 4) & 0xF980u) |                 // [........|........|Vvvvv..R|R.......].
    4501      114557 :                  ((rbReg << 2) & 0x0060u) |                 // [........|........|........|.BB.....].
    4502             :                  (opcode.extractLLMMMMM(options)) |         // [........|.LL.....|Vvvvv..R|RBBmmmmm].
    4503      114557 :                  (_extraReg.id() << 16);                    // [........|.LL..aaa|Vvvvv..R|RBBmmmmm].
    4504      114557 :     opReg &= 0x7;
    4505             : 
    4506             :     // Handle AVX512 options by a single branch.
    4507             :     const InstOptions kAvx512Options = InstOptions::kX86_ZMask | InstOptions::kX86_ER | InstOptions::kX86_SAE;
    4508      114557 :     if (Support::test(options, kAvx512Options)) {
    4509             :       static constexpr uint32_t kBcstMask = 0x1 << 20;
    4510             :       static constexpr uint32_t kLLMask10 = 0x2 << 21;
    4511             :       static constexpr uint32_t kLLMask11 = 0x3 << 21;
    4512             : 
    4513             :       // Designed to be easily encodable so the position must be exact. The {rz-sae} is encoded as {11},
    4514             :       // so it should match the mask.
    4515             :       static_assert(uint32_t(InstOptions::kX86_RZ_SAE) == kLLMask11,
    4516             :                     "This code requires InstOptions::X86_RZ_SAE to match kLLMask11 to work properly");
    4517             : 
    4518           0 :       x |= uint32_t(options & InstOptions::kX86_ZMask);     // [........|zLLb.aaa|Vvvvv..R|RBBmmmmm].
    4519             : 
    4520             :       // Support embedded-rounding {er} and suppress-all-exceptions {sae}.
    4521           0 :       if (Support::test(options, InstOptions::kX86_ER | InstOptions::kX86_SAE)) {
    4522             :         // Embedded rounding is only encodable if the instruction is either scalar or it's a 512-bit
    4523             :         // operation as the {er} rounding predicate collides with LL part of the instruction.
    4524           0 :         if ((x & kLLMask11) != kLLMask10) {
    4525             :           // Ok, so LL is not 10, thus the instruction must be scalar. Scalar instructions don't
    4526             :           // support broadcast so if this instruction supports it {er} nor {sae} would be encodable.
    4527           0 :           if (ASMJIT_UNLIKELY(commonInfo->hasAvx512B()))
    4528           0 :             goto InvalidEROrSAE;
    4529             :         }
    4530             : 
    4531           0 :         if (Support::test(options, InstOptions::kX86_ER)) {
    4532           0 :           if (ASMJIT_UNLIKELY(!commonInfo->hasAvx512ER()))
    4533           0 :             goto InvalidEROrSAE;
    4534             : 
    4535           0 :           x &=~kLLMask11;                                   // [........|.00..aaa|Vvvvv..R|RBBmmmmm].
    4536           0 :           x |= kBcstMask | (uint32_t(options) & kLLMask11); // [........|.LLb.aaa|Vvvvv..R|RBBmmmmm].
    4537             :         }
    4538             :         else {
    4539           0 :           if (ASMJIT_UNLIKELY(!commonInfo->hasAvx512SAE()))
    4540           0 :             goto InvalidEROrSAE;
    4541             : 
    4542           0 :           x &=~kLLMask11;                                   // [........|.00..aaa|Vvvvv..R|RBBmmmmm].
    4543           0 :           x |= kBcstMask;                                   // [........|.00b.aaa|Vvvvv..R|RBBmmmmm].
    4544             :         }
    4545             :       }
    4546             :     }
    4547             : 
    4548             :     // These bits would force EVEX prefix.
    4549             :     constexpr uint32_t kEvexForce = 0x00000010u;            // [........|........|........|...x....].
    4550             :     constexpr uint32_t kEvexBits = 0x00D78150u;             // [........|xx.x.xxx|x......x|.x.x....].
    4551             : 
    4552             :     // Force EVEX prefix even in case the instruction has VEX encoding, because EVEX encoding is preferred. At the
    4553             :     // moment this is only required by AVX_VNNI instructions, which were added after AVX512_VNNI instructions. If
    4554             :     // such instruction doesn't specify prefix, EVEX (AVX512_VNNI) is selected by default.
    4555      114557 :     if (commonInfo->preferEvex()) {
    4556           0 :       if ((x & kEvexBits) == 0 && !Support::test(options, InstOptions::kX86_Vex | InstOptions::kX86_Vex3)) {
    4557           0 :         x |= kEvexForce;
    4558             :       }
    4559             :     }
    4560             : 
    4561             :     // Check if EVEX is required by checking bits in `x` :     [........|xx.x.xxx|x......x|.x.x....].
    4562      114557 :     if (x & kEvexBits) {
    4563           0 :       uint32_t y = ((x << 4) & 0x00080000u) |               // [........|...bV...|........|........].
    4564           0 :                    ((x >> 4) & 0x00000010u) ;               // [........|...bV...|........|...R....].
    4565           0 :       x  = (x & 0x00FF78EFu) | y;                           // [........|zLLbVaaa|0vvvv000|RBBRmmmm].
    4566           0 :       x  = x << 8;                                          // [zLLbVaaa|0vvvv000|RBBRmmmm|00000000].
    4567           0 :       x |= (opcode >> kVSHR_W    ) & 0x00800000u;           // [zLLbVaaa|Wvvvv000|RBBRmmmm|00000000].
    4568           0 :       x |= (opcode >> kVSHR_PP_EW) & 0x00830000u;           // [zLLbVaaa|Wvvvv0pp|RBBRmmmm|00000000] (added PP and EVEX.W).
    4569             :                                                             //      _     ____    ____
    4570           0 :       x ^= 0x087CF000u | kX86ByteEvex;                      // [zLLbVaaa|Wvvvv1pp|RBBRmmmm|01100010].
    4571             : 
    4572             :       writer.emit32uLE(x);
    4573             :       writer.emit8(opcode.v);
    4574             : 
    4575           0 :       rbReg &= 0x7;
    4576             :       writer.emit8(x86EncodeMod(3, opReg, rbReg));
    4577           0 :       writer.emitImmByteOrDWord(uint64_t(immValue), immSize);
    4578           0 :       goto EmitDone;
    4579             :     }
    4580             : 
    4581             :     // Not EVEX, prepare `x` for VEX2 or VEX3:             x = [........|00L00000|0vvvv000|R0Bmmmmm].
    4582      114557 :     x |= ((opcode >> (kVSHR_W  + 8)) & 0x8000u) |           // [00000000|00L00000|Wvvvv000|R0Bmmmmm].
    4583      114557 :          ((opcode >> (kVSHR_PP + 8)) & 0x0300u) |           // [00000000|00L00000|0vvvv0pp|R0Bmmmmm].
    4584      114557 :          ((x      >> 11            ) & 0x0400u) ;           // [00000000|00L00000|WvvvvLpp|R0Bmmmmm].
    4585      114557 :     x |= x86GetForceEvex3MaskInLastBit(options);            // [x0000000|00L00000|WvvvvLpp|R0Bmmmmm].
    4586             : 
    4587             :     // Check if VEX3 is required / forced:                     [x.......|........|x.......|..xxxxx.].
    4588      114557 :     if (x & 0x8000803Eu) {
    4589        2610 :       uint32_t xorMsk = x86VEXPrefix[x & 0xF] | (opcode << 24);
    4590             : 
    4591             :       // Clear all high bits.
    4592        2610 :       x  = (x & 0xFFFF) << 8;                               // [00000000|WvvvvLpp|R0Bmmmmm|00000000].
    4593             :                                                             //            ____    _ _
    4594        2610 :       x ^= xorMsk;                                          // [_OPCODE_|WvvvvLpp|R1Bmmmmm|VEX3|XOP].
    4595             :       writer.emit32uLE(x);
    4596             : 
    4597        2610 :       rbReg &= 0x7;
    4598             :       writer.emit8(x86EncodeMod(3, opReg, rbReg));
    4599        2610 :       writer.emitImmByteOrDWord(uint64_t(immValue), immSize);
    4600        2610 :       goto EmitDone;
    4601             :     }
    4602             :     else {
    4603             :       // 'mmmmm' must be '00001'.
    4604             :       ASMJIT_ASSERT((x & 0x1F) == 0x01);
    4605             : 
    4606      111947 :       x = ((x >> 8) ^ x) ^ 0xF9;
    4607             :       writer.emit8(kX86ByteVex2);
    4608             :       writer.emit8(x);
    4609             :       writer.emit8(opcode.v);
    4610             : 
    4611      111947 :       rbReg &= 0x7;
    4612             :       writer.emit8(x86EncodeMod(3, opReg, rbReg));
    4613      111947 :       writer.emitImmByteOrDWord(uint64_t(immValue), immSize);
    4614      111947 :       goto EmitDone;
    4615             :     }
    4616             :   }
    4617             : 
    4618             :   // Emit - VEX|EVEX - /r - Memory
    4619             :   // -----------------------------
    4620             : 
    4621      142085 : EmitVexEvexM:
    4622             :   ASMJIT_ASSERT(rmRel != nullptr);
    4623             :   ASMJIT_ASSERT(rmRel->opType() == OperandType::kMem);
    4624             : 
    4625      142085 :   rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
    4626             :   writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
    4627             : 
    4628             :   memOpAOMark = writer.cursor();
    4629      142085 :   writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
    4630             : 
    4631      142085 :   rbReg = rmRel->as<Mem>().hasBaseReg()  ? rmRel->as<Mem>().baseId()  : uint32_t(0);
    4632      142085 :   rxReg = rmRel->as<Mem>().hasIndexReg() ? rmRel->as<Mem>().indexId() : uint32_t(0);
    4633             : 
    4634             :   {
    4635      142085 :     uint32_t broadcastBit = uint32_t(rmRel->as<Mem>().hasBroadcast());
    4636             : 
    4637             :     // Construct `x` - a complete EVEX|VEX prefix.
    4638      142085 :     uint32_t x = ((opReg <<  4) & 0x0000F980u)  |           // [........|........|Vvvvv..R|R.......].
    4639      142085 :                  ((rxReg <<  3) & 0x00000040u)  |           // [........|........|........|.X......].
    4640      142085 :                  ((rxReg << 15) & 0x00080000u)  |           // [........|....X...|........|........].
    4641      142085 :                  ((rbReg <<  2) & 0x00000020u)  |           // [........|........|........|..B.....].
    4642      142085 :                  opcode.extractLLMMMMM(options) |           // [........|.LL.X...|Vvvvv..R|RXBmmmmm].
    4643      142085 :                  (_extraReg.id()    << 16)      |           // [........|.LL.Xaaa|Vvvvv..R|RXBmmmmm].
    4644      142085 :                  (broadcastBit      << 20)      ;           // [........|.LLbXaaa|Vvvvv..R|RXBmmmmm].
    4645      142085 :     opReg &= 0x07u;
    4646             : 
    4647             :     // Mark invalid VEX (force EVEX) case:                  // [@.......|.LLbXaaa|Vvvvv..R|RXBmmmmm].
    4648      142085 :     x |= uint32_t(~commonInfo->flags() & InstDB::InstFlags::kVex) << (31 - Support::ConstCTZ<uint32_t(InstDB::InstFlags::kVex)>::value);
    4649             : 
    4650             :     // Handle AVX512 options by a single branch.
    4651             :     const InstOptions kAvx512Options = InstOptions::kX86_ZMask   |
    4652             :                                        InstOptions::kX86_ER      |
    4653             :                                        InstOptions::kX86_SAE     ;
    4654      142085 :     if (Support::test(options, kAvx512Options)) {
    4655             :       // {er} and {sae} are both invalid if memory operand is used.
    4656           0 :       if (ASMJIT_UNLIKELY(Support::test(options, InstOptions::kX86_ER | InstOptions::kX86_SAE)))
    4657           0 :         goto InvalidEROrSAE;
    4658             : 
    4659           0 :       x |= uint32_t(options & InstOptions::kX86_ZMask);     // [@.......|zLLbXaaa|Vvvvv..R|RXBmmmmm].
    4660             :     }
    4661             : 
    4662             :     // If these bits are used then EVEX prefix is required.
    4663             :     constexpr uint32_t kEvexForce = 0x00000010u;            // [........|........|........|...x....].
    4664             :     constexpr uint32_t kEvexBits = 0x80DF8110u;             // [@.......|xx.xxxxx|x......x|...x....].
    4665             : 
    4666             :     // Force EVEX prefix even in case the instruction has VEX encoding, because EVEX encoding is preferred. At the
    4667             :     // moment this is only required for AVX_VNNI instructions, which were added after AVX512_VNNI instructions. If
    4668             :     // such instruction doesn't specify prefix, EVEX (AVX512_VNNI) would be used by default,
    4669      142085 :     if (commonInfo->preferEvex()) {
    4670           0 :       if ((x & kEvexBits) == 0 && !Support::test(options, InstOptions::kX86_Vex | InstOptions::kX86_Vex3)) {
    4671           0 :         x |= kEvexForce;
    4672             :       }
    4673             :     }
    4674             : 
    4675             :     // Check if EVEX is required by checking bits in `x` :     [@.......|xx.xxxxx|x......x|...x....].
    4676      142085 :     if (x & kEvexBits) {
    4677           0 :       uint32_t y = ((x << 4) & 0x00080000u) |               // [@.......|....V...|........|........].
    4678           0 :                    ((x >> 4) & 0x00000010u) ;               // [@.......|....V...|........|...R....].
    4679           0 :       x  = (x & 0x00FF78EFu) | y;                           // [........|zLLbVaaa|0vvvv000|RXBRmmmm].
    4680           0 :       x  = x << 8;                                          // [zLLbVaaa|0vvvv000|RBBRmmmm|00000000].
    4681           0 :       x |= (opcode >> kVSHR_W    ) & 0x00800000u;           // [zLLbVaaa|Wvvvv000|RBBRmmmm|00000000].
    4682           0 :       x |= (opcode >> kVSHR_PP_EW) & 0x00830000u;           // [zLLbVaaa|Wvvvv0pp|RBBRmmmm|00000000] (added PP and EVEX.W).
    4683             :                                                             //      _     ____    ____
    4684           0 :       x ^= 0x087CF000u | kX86ByteEvex;                      // [zLLbVaaa|Wvvvv1pp|RBBRmmmm|01100010].
    4685             : 
    4686           0 :       if (x & 0x10000000u) {
    4687             :         // Broadcast support.
    4688             :         //
    4689             :         // 1. Verify our LL field is correct as broadcast changes the "size" of the source operand. For example if
    4690             :         //    a broadcasted operand is qword_ptr[X] {1to8} the source size becomes 64 and not 8 as the memory operand
    4691             :         //    would report.
    4692             :         //
    4693             :         // 2. Change the compressed displacement scale to either x2 (SHL1), x4 (SHL 2), or x8 (SHL 3) depending on
    4694             :         //    the broadcast unit/element size.
    4695             :         uint32_t broadcastUnitSize = commonInfo->broadcastSize();
    4696           0 :         uint32_t broadcastVectorSize = broadcastUnitSize << uint32_t(rmRel->as<Mem>().getBroadcast());
    4697             : 
    4698           0 :         if (ASMJIT_UNLIKELY(broadcastUnitSize == 0))
    4699           0 :           goto InvalidBroadcast;
    4700             : 
    4701             :         // LL was already shifted 8 bits right.
    4702             :         constexpr uint32_t kLLShift = 21 + 8;
    4703             : 
    4704           0 :         uint32_t currentLL = x & (0x3u << kLLShift);
    4705           0 :         uint32_t broadcastLL = (Support::max<uint32_t>(Support::ctz(broadcastVectorSize), 4) - 4) << kLLShift;
    4706             : 
    4707           0 :         if (broadcastLL > (2u << kLLShift))
    4708           0 :           goto InvalidBroadcast;
    4709             : 
    4710             :         uint32_t newLL = Support::max(currentLL, broadcastLL);
    4711           0 :         x = (x & ~(uint32_t(0x3) << kLLShift)) | newLL;
    4712             : 
    4713             :         opcode &=~uint32_t(Opcode::kCDSHL_Mask);
    4714           0 :         opcode |= Support::ctz(broadcastUnitSize) << Opcode::kCDSHL_Shift;
    4715             :       }
    4716             :       else {
    4717             :         // Add the compressed displacement 'SHF' to the opcode based on 'TTWLL'.
    4718             :         // The index to `x86CDisp8SHL` is composed as `CDTT[4:3] | W[2] | LL[1:0]`.
    4719           0 :         uint32_t TTWLL = ((opcode >> (Opcode::kCDTT_Shift - 3)) & 0x18) +
    4720           0 :                          ((opcode >> (Opcode::kW_Shift    - 2)) & 0x04) +
    4721           0 :                          ((x >> 29) & 0x3);
    4722           0 :         opcode += x86CDisp8SHL[TTWLL];
    4723             :       }
    4724             : 
    4725             :       writer.emit32uLE(x);
    4726             :       writer.emit8(opcode.v);
    4727             :     }
    4728             :     else {
    4729             :       // Not EVEX, prepare `x` for VEX2 or VEX3:           x = [........|00L00000|0vvvv000|RXBmmmmm].
    4730      142085 :       x |= ((opcode >> (kVSHR_W  + 8)) & 0x8000u) |         // [00000000|00L00000|Wvvvv000|RXBmmmmm].
    4731      142085 :            ((opcode >> (kVSHR_PP + 8)) & 0x0300u) |         // [00000000|00L00000|Wvvvv0pp|RXBmmmmm].
    4732      142085 :            ((x      >> 11            ) & 0x0400u) ;         // [00000000|00L00000|WvvvvLpp|RXBmmmmm].
    4733      142085 :       x |= x86GetForceEvex3MaskInLastBit(options);          // [x0000000|00L00000|WvvvvLpp|RXBmmmmm].
    4734             : 
    4735             :       // Clear a possible CDisp specified by EVEX.
    4736             :       opcode &= ~Opcode::kCDSHL_Mask;
    4737             : 
    4738             :       // Check if VEX3 is required / forced:                   [x.......|........|x.......|.xxxxxx.].
    4739      142085 :       if (x & 0x8000807Eu) {
    4740           0 :         uint32_t xorMsk = x86VEXPrefix[x & 0xF] | (opcode << 24);
    4741             : 
    4742             :         // Clear all high bits.
    4743           0 :         x  = (x & 0xFFFF) << 8;                             // [00000000|WvvvvLpp|RXBmmmmm|00000000].
    4744             :                                                             //            ____    ___
    4745           0 :         x ^= xorMsk;                                        // [_OPCODE_|WvvvvLpp|RXBmmmmm|VEX3_XOP].
    4746             :         writer.emit32uLE(x);
    4747             :       }
    4748             :       else {
    4749             :         // 'mmmmm' must be '00001'.
    4750             :         ASMJIT_ASSERT((x & 0x1F) == 0x01);
    4751             : 
    4752      142085 :         x = ((x >> 8) ^ x) ^ 0xF9;
    4753             :         writer.emit8(kX86ByteVex2);
    4754             :         writer.emit8(x);
    4755             :         writer.emit8(opcode.v);
    4756             :       }
    4757             :     }
    4758             :   }
    4759             : 
    4760             :   // MOD|SIB address.
    4761      142085 :   if (!commonInfo->hasFlag(InstDB::InstFlags::kVsib))
    4762      142085 :     goto EmitModSib;
    4763             : 
    4764             :   // MOD|VSIB address without INDEX is invalid.
    4765           0 :   if (rmInfo & kX86MemInfo_Index)
    4766           0 :     goto EmitModVSib;
    4767           0 :   goto InvalidInstruction;
    4768             : 
    4769             :   // Emit - Jmp/Jcc/Call
    4770             :   // -------------------
    4771             : 
    4772           0 : EmitJmpCall:
    4773             :   {
    4774             :     // Emit REX prefix if asked for (64-bit only).
    4775             :     uint32_t rex = opcode.extractRex(options);
    4776           0 :     if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
    4777           0 :       goto InvalidRexPrefix;
    4778           0 :     rex &= ~kX86ByteInvalidRex & 0xFF;
    4779           0 :     writer.emit8If(rex | kX86ByteRex, rex != 0);
    4780             : 
    4781           0 :     uint64_t ip = uint64_t(writer.offsetFrom(_bufferData));
    4782             :     uint32_t rel32 = 0;
    4783             :     uint32_t opCode8 = x86AltOpcodeOf(instInfo);
    4784             : 
    4785             :     uint32_t inst8Size  = 1 + 1; //          OPCODE + REL8 .
    4786             :     uint32_t inst32Size = 1 + 4; // [PREFIX] OPCODE + REL32.
    4787             : 
    4788             :     // Jcc instructions with 32-bit displacement use 0x0F prefix,
    4789             :     // other instructions don't. No other prefixes are used by X86.
    4790             :     ASMJIT_ASSERT((opCode8 & Opcode::kMM_Mask) == 0);
    4791             :     ASMJIT_ASSERT((opcode  & Opcode::kMM_Mask) == 0 ||
    4792             :                   (opcode  & Opcode::kMM_Mask) == Opcode::kMM_0F);
    4793             : 
    4794             :     // Only one of these should be used at the same time.
    4795           0 :     inst32Size += uint32_t(opReg != 0);
    4796           0 :     inst32Size += uint32_t((opcode & Opcode::kMM_Mask) == Opcode::kMM_0F);
    4797             : 
    4798           0 :     if (rmRel->isLabel()) {
    4799           0 :       label = _code->labelEntry(rmRel->as<Label>());
    4800           0 :       if (ASMJIT_UNLIKELY(!label))
    4801           0 :         goto InvalidLabel;
    4802             : 
    4803           0 :       if (label->isBoundTo(_section)) {
    4804             :         // Label bound to the current section.
    4805           0 :         rel32 = uint32_t((label->offset() - ip - inst32Size) & 0xFFFFFFFFu);
    4806           0 :         goto EmitJmpCallRel;
    4807             :       }
    4808             :       else {
    4809             :         // Non-bound label or label bound to a different section.
    4810           0 :         if (opCode8 && (!opcode.v || Support::test(options, InstOptions::kShortForm))) {
    4811             :           writer.emit8(opCode8);
    4812             : 
    4813             :           // Record DISP8 (non-bound label).
    4814             :           relOffset = -1;
    4815             :           relSize = 1;
    4816           0 :           goto EmitRel;
    4817             :         }
    4818             :         else {
    4819             :           // Refuse also 'short' prefix, if specified.
    4820           0 :           if (ASMJIT_UNLIKELY(!opcode.v || Support::test(options, InstOptions::kShortForm)))
    4821           0 :             goto InvalidDisplacement;
    4822             : 
    4823           0 :           writer.emit8If(0x0F, (opcode & Opcode::kMM_Mask) != 0);// Emit 0F prefix.
    4824             :           writer.emit8(opcode.v);                                // Emit opcode.
    4825             :           writer.emit8If(x86EncodeMod(3, opReg, 0), opReg != 0); // Emit MOD.
    4826             : 
    4827             :           // Record DISP32 (non-bound label).
    4828             :           relOffset = -4;
    4829             :           relSize = 4;
    4830           0 :           goto EmitRel;
    4831             :         }
    4832             :       }
    4833             :     }
    4834             : 
    4835           0 :     if (rmRel->isImm()) {
    4836             :       uint64_t baseAddress = code()->baseAddress();
    4837             :       uint64_t jumpAddress = rmRel->as<Imm>().valueAs<uint64_t>();
    4838             : 
    4839             :       // If the base-address is known calculate a relative displacement and check if it fits in 32 bits (which is
    4840             :       // always true in 32-bit mode). Emit relative displacement as it was a bound label if all checks are ok.
    4841           0 :       if (baseAddress != Globals::kNoBaseAddress) {
    4842           0 :         uint64_t rel64 = jumpAddress - (ip + baseAddress) - inst32Size;
    4843           0 :         if (Environment::is32Bit(arch()) || Support::isInt32(int64_t(rel64))) {
    4844           0 :           rel32 = uint32_t(rel64 & 0xFFFFFFFFu);
    4845           0 :           goto EmitJmpCallRel;
    4846             :         }
    4847             :         else {
    4848             :           // Relative displacement exceeds 32-bits - relocator can only insert trampoline for jmp/call, but not
    4849             :           // for jcc/jecxz.
    4850           0 :           if (ASMJIT_UNLIKELY(!x86IsJmpOrCall(instId)))
    4851           0 :             goto InvalidDisplacement;
    4852             :         }
    4853             :       }
    4854             : 
    4855           0 :       err = _code->newRelocEntry(&re, RelocType::kAbsToRel);
    4856           0 :       if (ASMJIT_UNLIKELY(err))
    4857           0 :         goto Failed;
    4858             : 
    4859           0 :       re->_sourceOffset = offset();
    4860           0 :       re->_sourceSectionId = _section->id();
    4861           0 :       re->_payload = jumpAddress;
    4862             : 
    4863           0 :       if (ASMJIT_LIKELY(opcode.v)) {
    4864             :         // 64-bit: Emit REX prefix so the instruction can be patched later. REX prefix does nothing if not patched,
    4865             :         // but allows to patch the instruction to use MOD/M and to point to a memory where the final 64-bit address
    4866             :         // is stored.
    4867           0 :         if (Environment::is64Bit(arch()) && x86IsJmpOrCall(instId)) {
    4868           0 :           if (!rex)
    4869             :             writer.emit8(kX86ByteRex);
    4870             : 
    4871           0 :           err = _code->addAddressToAddressTable(jumpAddress);
    4872           0 :           if (ASMJIT_UNLIKELY(err))
    4873           0 :             goto Failed;
    4874             : 
    4875           0 :           re->_relocType = RelocType::kX64AddressEntry;
    4876             :         }
    4877             : 
    4878           0 :         writer.emit8If(0x0F, (opcode & Opcode::kMM_Mask) != 0);  // Emit 0F prefix.
    4879             :         writer.emit8(opcode.v);                                  // Emit opcode.
    4880             :         writer.emit8If(x86EncodeMod(3, opReg, 0), opReg != 0);   // Emit MOD.
    4881           0 :         re->_format.resetToSimpleValue(OffsetType::kSignedOffset, 4);
    4882           0 :         re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_bufferPtr), immSize);
    4883             :         writer.emit32uLE(0);                                     // Emit DISP32.
    4884             :       }
    4885             :       else {
    4886             :         writer.emit8(opCode8);                                   // Emit opcode.
    4887           0 :         re->_format.resetToSimpleValue(OffsetType::kSignedOffset, 1);
    4888           0 :         re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_bufferPtr), immSize);
    4889             :         writer.emit8(0);                                         // Emit DISP8 (zero).
    4890             :       }
    4891           0 :       goto EmitDone;
    4892             :     }
    4893             : 
    4894             :     // Not Label|Imm -> Invalid.
    4895           0 :     goto InvalidInstruction;
    4896             : 
    4897             :     // Emit jmp/call with relative displacement known at assembly-time. Decide between 8-bit and 32-bit displacement
    4898             :     // encoding. Some instructions only allow either 8-bit or 32-bit encoding, others allow both encodings.
    4899           0 : EmitJmpCallRel:
    4900           0 :     if (Support::isInt8(int32_t(rel32 + inst32Size - inst8Size)) && opCode8 && !Support::test(options, InstOptions::kLongForm)) {
    4901             :       options |= InstOptions::kShortForm;
    4902             :       writer.emit8(opCode8);                                     // Emit opcode
    4903             :       writer.emit8(rel32 + inst32Size - inst8Size);              // Emit DISP8.
    4904           0 :       goto EmitDone;
    4905             :     }
    4906             :     else {
    4907           0 :       if (ASMJIT_UNLIKELY(!opcode.v || Support::test(options, InstOptions::kShortForm)))
    4908           0 :         goto InvalidDisplacement;
    4909             : 
    4910             :       options &= ~InstOptions::kShortForm;
    4911           0 :       writer.emit8If(0x0F, (opcode & Opcode::kMM_Mask) != 0);    // Emit 0x0F prefix.
    4912             :       writer.emit8(opcode.v);                                    // Emit Opcode.
    4913             :       writer.emit8If(x86EncodeMod(3, opReg, 0), opReg != 0);     // Emit MOD.
    4914             :       writer.emit32uLE(rel32);                                   // Emit DISP32.
    4915           0 :       goto EmitDone;
    4916             :     }
    4917             :   }
    4918             : 
    4919             :   // Emit - Relative
    4920             :   // ---------------
    4921             : 
    4922           0 : EmitRel:
    4923             :   {
    4924             :     ASMJIT_ASSERT(relSize == 1 || relSize == 4);
    4925             : 
    4926             :     // Chain with label.
    4927           0 :     size_t offset = size_t(writer.offsetFrom(_bufferData));
    4928             :     OffsetFormat of;
    4929             :     of.resetToSimpleValue(OffsetType::kSignedOffset, relSize);
    4930             : 
    4931           0 :     LabelLink* link = _code->newLabelLink(label, _section->id(), offset, relOffset, of);
    4932           0 :     if (ASMJIT_UNLIKELY(!link))
    4933           0 :       goto OutOfMemory;
    4934             : 
    4935           0 :     if (re)
    4936           0 :       link->relocId = re->id();
    4937             : 
    4938             :     // Emit dummy zeros, must be patched later when the reference becomes known.
    4939           0 :     writer.emitZeros(relSize);
    4940             :   }
    4941           0 :   writer.emitImmediate(uint64_t(immValue), immSize);
    4942             : 
    4943             :   // Emit - Done
    4944             :   // -----------
    4945             : 
    4946      392009 : EmitDone:
    4947      392009 :   if (Support::test(options, InstOptions::kReserved)) {
    4948             : #ifndef ASMJIT_NO_LOGGING
    4949       27492 :     if (_logger)
    4950           0 :       EmitterUtils::logInstructionEmitted(this, instId, options, o0, o1, o2, opExt, relSize, immSize, writer.cursor());
    4951             : #endif
    4952             :   }
    4953             : 
    4954             :   resetExtraReg();
    4955             :   resetInstOptions();
    4956             :   resetInlineComment();
    4957             : 
    4958             :   writer.done(this);
    4959      392009 :   return kErrorOk;
    4960             : 
    4961             :   // Error Handler
    4962             :   // -------------
    4963             : 
    4964             : #define ERROR_HANDLER(ERR) ERR: err = DebugUtils::errored(kError##ERR); goto Failed;
    4965           0 :   ERROR_HANDLER(OutOfMemory)
    4966           0 :   ERROR_HANDLER(InvalidLabel)
    4967           0 :   ERROR_HANDLER(InvalidInstruction)
    4968           0 :   ERROR_HANDLER(InvalidLockPrefix)
    4969           0 :   ERROR_HANDLER(InvalidXAcquirePrefix)
    4970           0 :   ERROR_HANDLER(InvalidXReleasePrefix)
    4971           0 :   ERROR_HANDLER(InvalidRepPrefix)
    4972           0 :   ERROR_HANDLER(InvalidRexPrefix)
    4973           0 :   ERROR_HANDLER(InvalidEROrSAE)
    4974           0 :   ERROR_HANDLER(InvalidAddress)
    4975           0 :   ERROR_HANDLER(InvalidAddressIndex)
    4976           0 :   ERROR_HANDLER(InvalidAddress64Bit)
    4977           0 :   ERROR_HANDLER(InvalidDisplacement)
    4978           0 :   ERROR_HANDLER(InvalidPhysId)
    4979           0 :   ERROR_HANDLER(InvalidSegment)
    4980           0 :   ERROR_HANDLER(InvalidImmediate)
    4981           0 :   ERROR_HANDLER(InvalidBroadcast)
    4982           0 :   ERROR_HANDLER(OperandSizeMismatch)
    4983           0 :   ERROR_HANDLER(AmbiguousOperandSize)
    4984           0 :   ERROR_HANDLER(NotConsecutiveRegs)
    4985             : #undef ERROR_HANDLER
    4986             : 
    4987           0 : Failed:
    4988             : #ifndef ASMJIT_NO_LOGGING
    4989           0 :   return EmitterUtils::logInstructionFailed(this, err, instId, options, o0, o1, o2, opExt);
    4990             : #else
    4991             :   resetExtraReg();
    4992             :   resetInstOptions();
    4993             :   resetInlineComment();
    4994             :   return reportError(err);
    4995             : #endif
    4996             : }
    4997             : 
    4998             : //x86::Assembler - Align
    4999             : // =====================
    5000             : 
    5001           0 : Error Assembler::align(AlignMode alignMode, uint32_t alignment) {
    5002           0 :   if (ASMJIT_UNLIKELY(!_code))
    5003           0 :     return reportError(DebugUtils::errored(kErrorNotInitialized));
    5004             : 
    5005           0 :   if (ASMJIT_UNLIKELY(uint32_t(alignMode) > uint32_t(AlignMode::kMaxValue)))
    5006           0 :     return reportError(DebugUtils::errored(kErrorInvalidArgument));
    5007             : 
    5008           0 :   if (alignment <= 1)
    5009             :     return kErrorOk;
    5010             : 
    5011           0 :   if (ASMJIT_UNLIKELY(!Support::isPowerOf2(alignment) || alignment > Globals::kMaxAlignment))
    5012           0 :     return reportError(DebugUtils::errored(kErrorInvalidArgument));
    5013             : 
    5014           0 :   uint32_t i = uint32_t(Support::alignUpDiff<size_t>(offset(), alignment));
    5015           0 :   if (i > 0) {
    5016             :     CodeWriter writer(this);
    5017           0 :     ASMJIT_PROPAGATE(writer.ensureSpace(this, i));
    5018             : 
    5019             :     uint8_t pattern = 0x00;
    5020           0 :     switch (alignMode) {
    5021           0 :       case AlignMode::kCode: {
    5022           0 :         if (hasEncodingOption(EncodingOptions::kOptimizedAlign)) {
    5023             :           // Intel 64 and IA-32 Architectures Software Developer's Manual - Volume 2B (NOP).
    5024             :           enum { kMaxNopSize = 9 };
    5025             : 
    5026             :           static const uint8_t nopData[kMaxNopSize][kMaxNopSize] = {
    5027             :             { 0x90 },
    5028             :             { 0x66, 0x90 },
    5029             :             { 0x0F, 0x1F, 0x00 },
    5030             :             { 0x0F, 0x1F, 0x40, 0x00 },
    5031             :             { 0x0F, 0x1F, 0x44, 0x00, 0x00 },
    5032             :             { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 },
    5033             :             { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 },
    5034             :             { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 },
    5035             :             { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }
    5036             :           };
    5037             : 
    5038             :           do {
    5039             :             uint32_t n = Support::min<uint32_t>(i, kMaxNopSize);
    5040           0 :             const uint8_t* src = nopData[n - 1];
    5041             : 
    5042           0 :             i -= n;
    5043             :             do {
    5044           0 :               writer.emit8(*src++);
    5045           0 :             } while (--n);
    5046           0 :           } while (i);
    5047             :         }
    5048             : 
    5049             :         pattern = 0x90;
    5050             :         break;
    5051             :       }
    5052             : 
    5053           0 :       case AlignMode::kData:
    5054             :         pattern = 0xCC;
    5055           0 :         break;
    5056             : 
    5057             :       case AlignMode::kZero:
    5058             :         // Pattern already set to zero.
    5059             :         break;
    5060             :     }
    5061             : 
    5062           0 :     while (i) {
    5063             :       writer.emit8(pattern);
    5064           0 :       i--;
    5065             :     }
    5066             : 
    5067             :     writer.done(this);
    5068             :   }
    5069             : 
    5070             : #ifndef ASMJIT_NO_LOGGING
    5071           0 :   if (_logger) {
    5072             :     StringTmp<128> sb;
    5073           0 :     sb.appendChars(' ', _logger->indentation(FormatIndentationGroup::kCode));
    5074             :     sb.appendFormat("align %u\n", alignment);
    5075           0 :     _logger->log(sb);
    5076             :   }
    5077             : #endif
    5078             : 
    5079             :   return kErrorOk;
    5080             : }
    5081             : 
    5082             : // x86::Assembler - Events
    5083             : // =======================
    5084             : 
    5085       27492 : Error Assembler::onAttach(CodeHolder* code) noexcept {
    5086             :   Arch arch = code->arch();
    5087       27492 :   ASMJIT_PROPAGATE(Base::onAttach(code));
    5088             : 
    5089       27492 :   if (Environment::is32Bit(arch)) {
    5090             :     // 32 bit architecture - X86.
    5091             :     _forcedInstOptions |= InstOptions::kX86_InvalidRex;
    5092             :     _setAddressOverrideMask(kX86MemInfo_67H_X86);
    5093             :   }
    5094             :   else {
    5095             :     // 64 bit architecture - X64.
    5096             :     _forcedInstOptions &= ~InstOptions::kX86_InvalidRex;
    5097             :     _setAddressOverrideMask(kX86MemInfo_67H_X64);
    5098             :   }
    5099             : 
    5100             :   return kErrorOk;
    5101             : }
    5102             : 
    5103           0 : Error Assembler::onDetach(CodeHolder* code) noexcept {
    5104             :   _forcedInstOptions &= ~InstOptions::kX86_InvalidRex;
    5105             :   _setAddressOverrideMask(0);
    5106           0 :   return Base::onDetach(code);
    5107             : }
    5108             : 
    5109             : ASMJIT_END_SUB_NAMESPACE
    5110             : 
    5111             : #endif // !ASMJIT_NO_X86
    5112             : 
    5113             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16