| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# ii.htm
Class
II
Enumerations
%IiCategoryList
%IiCpuList
%IiSimdList
Encodings
CPU requirements
CPU features
Intel
Miscellaneous
Modifiers (general)
Modifiers (AVX)
Prefix (legacy)
Properties (general)
Properties (AVX)
Reloc
Register
Macros
IiAbort
IiAbortIfNot
IiAbortIfNotCounter
IiAbortIfNotST0
IiAbortIf64
IiAbortIfNot64
IiAllowBroadcasting
IiAllowLocking
IiAllowRounding
IiAllowSuppressing
IiAllowMaskMerging
IiAllowModifier
IiAllowNoSwizzle
IiAllowPrefix
IiAssumeEmpty
IiDataSize
IiDisp8EVEX
IiDisp8MVEX
IiDispatchCPU
IiDispatchCode
IiDispatchData
IiDispatchDisp
IiDispatchDist
IiDispatchFormat
IiDispatchImm
IiDispatchImmSize
IiDispatchLocation
IiDispatchNotAccum
IiDispatchDataSize
IiDispatchPrefix
IiDispatchSingleShift
IiDispatchSuffix
IiDispatchWidth
IiDispSize
IiEmitImm
IiEmitImm2
IiEmitOpcode
IiEmitPrefix
IiEncoding
IiImmSize
IiImmCreate
IiIs4
IiModRM
IiOpEn
IiReloc
IiRemoveOTOGGLE
IiRemoveREXR
IiRemoveREXW
IiRequire
IiStringDestination
IiStringSource
IiSuffixed
IiSwap
IiVSIB
Procedures
IiAssemble
IiAssembleAVX
IiAssembleMultiop
IiCompressDisp8
IiCpuToKeys
IiCreateModRM
IiFlush
IiGetRegFamily
IiGetRegOrdinal
IiHandlers
IiModifiersToKeys
IiRelocSizeRIP

Class II (shortcut of Intel Instruction ) describes CPU features defined in x86-64 architecture and its object represents a parsed machine instruction with evaluated operands ready to assemble.

Object of II class was allocated by IiAssemble and it was prepared there to be processed by the instruction handler.

Machine instruction modules
Instruction category | Uses registers | Module file
--- | --- | ---
all | Machine instruction handlers support | `-` | `ii.htm`
A | Vendor specific (AMD) | `RAX..YMM15` | `iia.htm`
B | Intel Fused Multiply-Add (FMA) | `XMM0..ZMM31` | `iib.htm`
C | Vendor-specific (CYRIX) | `MM0..MM7` | `iic.htm`
D | 3DNow! specific (AMD, D3NOW) | `XMM0..XMM15` | `iid.htm`
F | Floating-point (FPU) | `ST0..ST7` | `iif.htm`
G | General instructions | `RAX..R15` | `iig.htm`
K | Mask-registers manipulation (AVX512) | `K0..K7` | `iik.htm`
M | Multimedia (MMX) | `MM0..MM7` | `iim.htm`
P | Packed (SSE) | `XMM0..XMM15` | `iip.htm`
S | System special (SPEC, UNDOC, PROT, PRIV, MPX, SGX, CET) | `special` | `iis.htm`
T | Transactional & other extensions (TSX, RTM, VMX, SVM) | `-` | `iit.htm`
V | Advanced Vector extension (AVX) | `XMM0..YMM15` | `iiv.htm`
X | XOP-encodable AMD | `XMM0..YMM15` | `iix.htm`
Y | Advanced Vector extension (AVX2) | `XMM0..YMM15` | `iiy.htm`
Z | Advanced Vector extension (AVX512) | `XMM0..ZMM31` | `iiz.htm`

Machine instruction assembly object model
  EaMain EaCreate EaAssemble Src SrcCreate SrcAssemble Stm StmClean StmParse StmExecute IiAssemble Ii Iihandler IiFlush StmListing StmFlush SrcDestroy EaDestroy

↑ IiHandlers

  IiHandlers are represented by procedures called with register convention from IiAssemble. They are responsible for the assembly of actual machine instructions. Each of 2254 instruction mnemonics (suffixed or nonsuffixed) has got its own handler.

  Instruction handlers are divided into categories in order to keep the number of handlers per module low.

  Header of each module has alphabetical list of its instructions. If you are not sure to which category an instruction belongs, search for it in the global Index.

  Description of each machine instruction is available in the header of its handler in the form of link to [FCx86] whenever available. Some info was also automatically supplemented from [Refx86asm].
  AVX instructions are supplemented with encoding reference from [IntelAVX512] . Encoding was retrieved from CPU-vendor PDF files semiautomatically, so possible errors and typos may have propagated from documentation to the final code.

  > In order to introduce a new machine instruction to EuroAssembler

  > 1. Select apropriate instruction category ?=A..Z and its source file ii?.htm,
  > 2. declare the mnemonic in `%Ii?List` in the source file,
  > 3. create public procedure of the instruction handler,
  > 4. create a link to this handler in alphabetical list `%Ii?List` in the source header,
  > 5. create test file for the instruction,
  > 6. rebuild EuroAssembler.

Input
  EBX= is a pointer to the parsed statement STM with specified section and aligned offset.
  EDI= is a pointer to II object with evaluated operands and modifiers.
  EDX= contains instruction format constructed from operand types in Intel encoding , e.g. `r32.imm` for instruction `ADD EBX,123`. The highest ordinal operand type is in DL. EDX=0 for operandless instructions.
  Actual size of memory operand (`mem`) in EDX may be Intel-encoded to `m8/m16/m32/m64` before dispatching. This is achieved by using macro IiDataSize.
Output
  Handlers may destroy any GPR including EBP. Handlers end with simple `RET`.
  After II has been modified and the handler returns to IiAssemble , object II is submitted to IiFlush which will emit the machine code from `II` to `Stm.EmitBuffer` and relocations to `Stm.RelocBuffer`.
  Finally, StmFlush stores alignment, code|data and relocations from statement to the section buffers.
Error
  Errors are reported with macro Msg.
Called from
  IiAssemble.
Remarks

  Handlers from all modules use procedures and macros defined here in this common file ii.htm.
  All those macros preserve contents of all register unchanged. Many macros expect EDX=format, EBX=^STM, EDI=^II.

  Abortable macros IiDispatchFormat and IiAbortIf* will break further execution of Ii?Handler and return to it's parent, i.e. to IiAssemble. They may only be used on the same stack level as at Ii?Handler entry.

  Job of most Ii* macros is to specify request for emission of instruction component (prefix, opcode, ModR/M, SIB, displacement and immediates) in object II . The actual emission is performed in procedure IiFlush.

Format of byte REX
REX | W | R | X | B
--- | --- | --- | --- | ---
`0` | `1` | `0` | `0` | `operand width 64` | `Reg/Opcode extension r3` | `SIB.I extension x3` | `SIB.B or R/M extension b3`

Format of prefix XOP
Byte 0 | Byte 1 | Byte 2
--- | --- | ---
1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | ~r3 | ~x3 | ~x3 | m4 | m3 | m2 | m1 | m0 | W | ~v3 | ~v2 | ~v1 | ~v0 | L | p1 | p0

Format of prefix VEX2
Byte 0 | Byte 1
--- | ---
1 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | ~r3 | ~v3 | ~v2 | ~v1 | ~v0 | L | p1 | p0

Format of prefix VEX3
Byte 0 | Byte 1 | Byte 2
--- | --- | ---
1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | ~r3 | ~x3 | ~b3 | m4 | m3 | m2 | m1 | m0 | W | ~v3 | ~v2 | ~v1 | ~v0 | L | p1 | p0

Format of prefix MVEX
Byte 0 | Byte 1 | Byte 2 | Byte 3
--- | --- | --- | ---
0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | ~r3 | ~x3 | ~b3 | ~r4 | m3 | m2 | m1 | m0 | W | ~v3 | ~v2 | ~v1 | ~v0 | 0 | p1 | p0 | E | S2 | S1 | S0 | ~v4 | k2 | k1 | k0

Format of prefix EVEX
Byte 0 | Byte 1 | Byte 2 | Byte 3
--- | --- | --- | ---
0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | ~r3 | ~x3 | ~b3 | ~r4 | m3 | m2 | m1 | m0 | W | ~v3 | ~v2 | ~v1 | ~v0 | 1 | p1 | p0 | z | L' | L | b | ~v4 | k2 | k1 | k0

Format of byte ModR/M
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
--- | --- | --- | --- | --- | --- | --- | ---
`Mod` | `Reg/Opcode` | `R/M`
`mod1` | `mod0` | `r2` | `r1` | `r0` | `b2` | `b1` | `b0`

Format of byte SIB
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
--- | --- | --- | --- | --- | --- | --- | ---
SS: `Scale` | I: `Index` | B: `Base`
`S1` | `S0` | `x2` | `x1` | `x0` | `b2` | `b1` | `b0`

Operands encoding in MVEX|EVEX prefix
AVX-512 operands | EVEX / MVEX | ModRM byte | (V)SIB byte
--- | --- | --- | ---
R | X | B | R' | V' | mod | reg | R/M | scale | index | base
Mod=0|1|2; mem type: Rr, [S * Rx + Rb] | r3 | x3 | b3 | r4 | x4 | m | m | r2 | r1 | r0 | 1 | 0 | 0 | S1 | S0 | x2 | x1 | x0 | b2 | b1 | b0
Mod=3; reg type: Rr, Rb | r3 | b4 | b3 | r4 |  | 1 | 1 | r2 | r1 | r0 | b2 | b1 | b0 | not used

    ii PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32
       INCLUDEHEAD euroasm.htm, \  Interface (structures, symbols and macros) of other modules used in this source.
                   ea.htm,dict.htm,eaopt.htm,exp.htm,lst.htm,msg.htm,pgm.htm,pgmopt.htm,reloc.htm,src.htm, \
                   sss.htm,stm.htm,sym.htm

    ii HEAD ; Start of module interface.

↑ II
  Class II (Intel Instruction) describes CPU features defined in x86-64 architecture and its object represents a parsed machine instruction with evaluated operands ready to assemble.

    II STRUC ; Parsed machine instruction with evaluated operands.
      ; EDI+00h.
      ; Operands of machine instruction evaluated by ExpEval to EXP objects.
    .Operand1:    DS EXP ; Ordinal operand %1.
    .Operand2:    DS EXP ; Ordinal operand %2.
    .Operand3:    DS EXP ; Ordinal operand %3.
    .Operand4:    DS EXP ; Ordinal operand %4.
      ; EDI+50h.
    .Align        DD D ; 0=unspec, 1=B, 2=W, 4=D, 8=Q, 16=O, 32=Y, 64=Z.
     ; Explicit and implicit machine-instruction prefixes (other than *VEX) in Prefix encoding.
    .PfxAllowed   DD D ; Prefixes allowed for this instruction, set by macro IiAllowPrefix in handler.
    .PfxExplicit  DD D ; Bitwise OR of all prefixes explicitly specified by programmer inside the statement.
    .PfxEmitted   DD D ; Implicit prefixes required by IiHandlers - SEGxS, REP, OTOGGLE, ATOGGLE, REX.
      ; EDI+60h.
    ; General instruction modifiers in general modifier encoding:
    .MfgAllowed   DD D ; Modifiers specified as acceptable for this instruction by instruction handler.
    .MfgSuffix    DD D ; Explicitly specified as suffix of instruction mnemonic, e.g. ADCD [Symbol],1
    .MfgExplicit  DD D ; Explicitly requested as keywords in machine instruction, e.g. ADC [Symbol],1,DATA=DWORD
    .MfgImplicit  DD D ; Implicitly defined data width by memory-operand type,     e.g. ADC [DwordSymbol],1
      ; EDI+70h.
    .MfgEmitted   DD D ; Modifiers specifying what is finally emitted.
    ; AVX instruction modifiers in AVX modifier encoding concerning Advanced Vector Extension prefix.
    .MfxAllowed   DD D ; Modifiers specified as acceptable for this instruction by instruction handler.
    .MfxExplicit  DD D ; Explicitly requested as keywords in machine instruction, e.g. VADDPD ZMM0,ZMM2,[RSI],MASK=K2,ZEROING=No
    .MfxEmitted   DD D ; AVX modifiers actually encoded in emitted *VEX prefix.
      ; EDI+80h.
    ; Instruction properties and features.
    .Ppg          DD D ; Properties (general) specifying what is finally emitted. Set by IiHandlers.
    .Ppx          DD D ; Properties (AVX) specifying contents of AVX prefix. Set by IiHandlers.
    .Cpu          DD D ; CPU= and SIMD= values required by the instruction and its registers and prefixes.
    .Features     DD D ; Processor features required by the instruction and its registers and prefixes.
      ; EDI+90h.
    ; Assembled instruction code fields ready to flush to Stm.EmitBuffer, described by flags in II.MfgEmitted.
    .DispLow      DD D ; 0..8 bytes of displacement, valid if II.MfgEmitted:iiMfgDISP_Mask is set.
    .DispHigh     DD D
    .DispRelocSeg DD D ; ^SSS Segment of symbol used in displacement.
    .DispRelocSym DD D ; ^SYM if symbol was used in displacement.
      ; EDI+0A0h
    .ImmLow       DD D ; 0..8 bytes of immediate operand. valid if II.MfgEmitted:iiMfgIMM_Mask is set.
    .ImmHigh      DD D
    .ImmRelocSeg  DD D ; ^SSS Segment of symbol used in immediate operand.
    .ImmRelocSym  DD D ; ^SYM if symbol was used in immediate.
      ; EDI+0B0h. Finally assembled code which is emitted to section.
    .Opcode       DB 16*B ; Operation code of instruction (size is specified by II.Ppg:iiPpgOpcodeSizeMask).
    ; EDI+0C0h.
    .ModRM        DD D ; ModR/M byte in LSB, sometimes followed with SIB byte.
     .SIB    EQU .ModRM+1 ; Only valid if II.Ppg:iiPpgModRM+iiPpgSIB is set.
     .Imm2   EQU .ModRM+2 ; Only valid if II.Ppg:iiPpgImm2 is set.
     .Para   EQU .ModRM+2 ; Imm.segment value in direct far JMP/CALL. Only valid if II.Ppg:iiPpgPara is set.
    .Reloc        DD D ; Relocation flags iiReloc* in IiReloc encoding.
    .SssStatus    DD D ; Cache copy of current section status, see sssWidthMask.
    .PgmoptStatus DD D ; Cache copy of current program options status, see PGMOPT.
      ; EDI+0D0h.
     ; Pointers to literal prefix definitions, e.g. =B"VEX.NDS.256.66.0F.WIG".
     ; String begins with XOP/VEX/MVEX/EVEX and it is NULL-terminated.
     ; Point-separated definitions will be parsed in IiAssembleAVX.
    .AvxSrcXOP    DD D ; Pointer to XOP  definition string.
    .AvxSrcVEX    DD D ; Pointer to VEX  definition string.
    .AvxSrcMVEX   DD D ; Pointer to MVEX definition string.
    .AvxSrcEVEX   DD D ; Pointer to EVEX definition string.
      ;EDI+0E0h.
    .Disp8EVEX    DD D ; Compression bits of disp8*N for OPER=0..7 when prefix EVEX is used. See IiDisp8EVEX.
    .Disp8MVEX    DD D ; Compression bits of disp8*N for OPER=0..7 when prefix MVEX is used. See IiDisp8MVEX.
    .PfxCode      DD 4*B ; Opcodes of 0..4 used explicit prefixes, in Stm order, the first in LSB, NULL padded.
    .AvxCode      DD 4*B ; Assembled AVX prefix in format XOP or *VEX (size 2..4 is specified by II.Ppx:iiPpxAvxSize).
              ENDSTRUC II

↑ %IiCategoryList
  Instruction category suffixes, see the table above . Each instruction category represents source modul and file iig.htm, iif.htm etc.

    %IiCategoryList %SET g,s,t,f,m,p,c,d,v,a,b,x,y,z,k

↑ %IiCpuList
  `EUROASM CPU=` values, ordered from the highest.

    %IiCpuList %SET X64,686,586,486,386,286,186,086

↑ %IiSimdList
  `EUROASM SIMD=` values, ordered from the highest.

    %IiSimdList %SET AVX512,AVX2,AVX,SSE4.2,SSE4.1,SSE4,SSSE3,SSE3,SSE2,SSE1,SSE

↑ Properties encoding (general)
  Flags `iiPpg*` describe the emitted code. They are kept in II.Ppg by instruction handlers and together with II.MfgEmitted they instruct IiFlush how to encode the instruction.

    iiPpgOpcodeSizeMask = 0x0000_000F ; Number of opcode bytes in II.Opcode.
    iiPpgDispSegDiff    = 0x0000_0010 ; Group/segment of displacement differs from current group/segment.
    iiPpgImmSegDiff     = 0x0000_0020 ; Group/segment of immediate operand differs from current group/segment.
    iiPpgOperSizeBySss  = 0x0000_0040 ; If not specified explicitly, use operand-size by segment width.
    iiPpgOperSizeByReg  = 0x0000_0080 ; IiDataSize was determined from operand register width.
    iiPpgAddrSize       = 0x0000_0300 ; Effective address-size 0,1,2,3 = unspecified,16,32,64. Set in IiModRM.
    iiPpgModRMd         = 0x0000_0400 ; ModRM /digit requested. Digit value 0..7 is in iiPpgModDigit. Set by IiModRM.
    iiPpgModRMr         = 0x0000_0800 ; ModRM /r requested. Set by IiModRM.
    ;                   = 0x0000_1000 ; Not used.
    iiPpgSIB            = 0x0000_2000 ; II.ModRM+1 byte is valid SIB.
    iiPpgImm2           = 0x0000_4000 ; II.ModRM+2 byte is valid secondary immediate byte.
    iiPpgPara           = 0x0000_8000 ; II.ModRM+2 word is valid immediate segment-register value (paragraph address).
    iiPpgNoREX          = 0x0001_0000 ; Instruction requires no REX be present (it uses AH,BH,CH,DH).
    iiPpgMod01          = 0x0002_0000 ; Reset ModRM bit 7 (change mod 11b to 01b)
    iiPpgMod10          = 0x0004_0000 ; Reset ModRM bit 6 (change mod 11b to 10b)
    ;                   = 0x0008_0000 ; Not used.
    iiPpgVSIB1          = 0x0010_0000 ; Used vector indexregister is XMM or ZMM.
    iiPpgVSIB2          = 0x0020_0000 ; Used vector indexregister is YMM or ZMM.
    iiPpgVSIBind        = 0x0030_0000 ; VSIB indices (none,XMM,YMM,ZMM) required by handler. Synced with iiPpxVSIBfam.
    iiPpgVEXvOp         = 0x00C0_0000 ; Which operand (none,1,2,3) is encoded in *VEX.vvvv field.
    iiPpgModRegOp       = 0x0300_0000 ; Which operand (none,1,2,3) is encoded in ModRM.RegOpcode field.
    iiPpgModRMOp        = 0x0C00_0000 ; Which operand (none,1,2,3) is encoded in ModRM.R/M field.
    iiPpgModDigit       = 0x7000_0000 ; Auxiliary opcode encoded as ModRM /digit. Valid only if iiPpgModRMd is set.
    ;                   = 0x8000_0000 ; Not used.

↑ Properties encoding (AVX)
  Flags `iiPpx*` describe AVX prefix (XOP/*VEX). They are kept in II.Ppx by instruction handlers and together with II.MfxEmitted they instruct IiFlush how to encode the instruction.

    iiPpxPpMask      = 0x0000_0003 ; Compacted instruction prefix 0,1,2,3=none,66,F3,F2.
    iiPpxL           = 0x0000_0004 ; Vector width XOP.L alias VEX.L.  0,1=128,256.
    iiPpxW           = 0x0000_0008 ; Operation width promotion bit W.
    iiPpxAvxSize     = 0x0000_0070 ; Number of AVX prefix bytes in II.AvxCode (2..4).
    ;                = 0x0000_0080 ; Not used.
    ;                = 0x0000_0100 ; Not used.
    iiPpxMm3         = 0x0000_0200 ; 3byte opcode prefix 0x0F38 or 0x0F3A.
     ; iiPpxMmMask   = 0x0000_0300 ; Opcode map. 0,1,2,3=map8,map9,map10,res. if XOP, otherwise none,0F,0F38,0F3A. Previous version 20250912.
    iiPpxMmMask      = 0x0000_0700 ; Opcode map VEX,MVEX,EVEX: none,0F,0F38,0F3A,res,MAP5,MAP6,MAP7. Opcode map XOP:MAP8,MAP9,MAP10,5*res.
    ;                = 0x0000_0800 ; Not used.
    iiPpxAssignMask  = 0x0000_7000 ; Operand assignments in VEX prefix. See IiModRM.
    iiPpxNDS         = 0x0000_1000 ; VEX.vvvv encodes the first (preserved) source operand.
    iiPpxNDD         = 0x0000_2000 ; VEX.vvvv encodes destination (overwritten) operand.
    iiPpxDDS         = 0x0000_4000 ; VEX.vvvv encodes the second source operand.
    iiPpxRemoveREX   = 0x0000_8000 ; Handler requested not emit empty REX (0x40).
    iiPpxRemoveREX.W = 0x0001_0000 ; Handler requested not emit REX.W.
    iiPpxRemoveREX.R = 0x0002_0000 ; Handler requested not emit REX.R.
    iiPpxR`          = 0x0004_0000 ; ModR/M.reg  extension 4.bit, M/EVEX.R' for ZMM16..ZMM31.
    iiPpxV`          = 0x0008_0000 ; M/EVEX.vvvv extension 4.bit, M/EVEX.V' for ZMM16..ZMM31.
    iiPpxVSIB1       = 0x0010_0000 ; Used vector indexregister is XMM or ZMM.
    iiPpxVSIB2       = 0x0020_0000 ; Used vector indexregister is YMM or ZMM.
    iiPpxVSIBfam     = 0x0030_0000 ; Used vector indexregister adopted by ExpEval. Synced with iiPpgVSIBind. 00b=none, 01b=XMM, 10b=YMM, 11b=ZMM.
    iiPpxNoZEROING   = 0x0040_0000 ; Do not allow ZEROING together with MASK.
    iiPpxNoSwizzle   = 0x0080_0000 ; Do not allow swizzle (only MVEX OPER=0 is acceptable when EH=0).
    iiPpxMEVEXonly   = 0x0100_0000 ; Not encodable as XOP/VEX (uses ZMM or YMM16..ZMM31).
    iiPpxDisp8Allow  = 0x0200_0000 ; Disp8*N compression is possible in M/EVEX encoded instruction.
    iiPpxEH0         = 0x0400_0000 ; MVEX.EH explicitly reset to 0.
    iiPpxEH1         = 0x0800_0000 ; MVEX.EH explicitly set to 1.
    iiPpxL0          = 0x1000_0000 ; Vector length XOP.L alias VEX.L explicitly reset to 0.
    iiPpxL1          = 0x2000_0000 ; Vector length XOP.L alias VEX.L explicitly set to 1.
    iiPpxLZ          = iiPpxL0     ; Vector length XOP.L alias VEX.L explicitly reset to 0.
    iiPpxW0          = 0x4000_0000 ; Operation width promotion bit W explicitly reset to 0.
    iiPpxW1          = 0x8000_0000 ; Operation width promotion bit W explicitly set to 1.

↑ Modifiers encoding (general)
  Keyword instruction modifiers used in most of €ASM machine instructions: `ADDR=, CODE=, DATA=, DISP=, DIST=, IMM=, SCALE=`.
  They are parsed by StmGetIiModifiers and stored to II.MfgExplicit.
  Same flags are also used in II.MfgAllowed, II.MfgSuffix, II.MfgExplicit, II.MfgImplicit, II.MfgEmitted.

    iiMfgIMM_None       = 0 ; IMM=
    iiMfgIMM_BYTE       = 0x0000_0001 ; Encode immediate operand in 1 byte.
    iiMfgIMM_WORD       = 0x0000_0002 ; Encode immediate operand in 2 bytes.
    iiMfgIMM_DWORD      = 0x0000_0004 ; Encode immediate operand in 4 bytes.
    iiMfgIMM_QWORD      = 0x0000_0008 ; Encode immediate operand in 8 bytes.
    iiMfgIMM_Mask       = iiMfgIMM_BYTE|iiMfgIMM_WORD|iiMfgIMM_DWORD|iiMfgIMM_QWORD
    iiMfgDISP_None      = 0 ; DISP=
    iiMfgDISP_BYTE      = 0x0000_0010 ; Encode displacement in 1 byte.
    iiMfgDISP_WORD      = 0x0000_0020 ; Encode displacement in 2 bytes.
    iiMfgDISP_DWORD     = 0x0000_0040 ; Encode displacement in 4 bytes.
    iiMfgDISP_QWORD     = 0x0000_0080 ; Encode displacement in 8 bytes as ADDR=ABS.
    iiMfgDISP_Mask      = iiMfgDISP_BYTE|iiMfgDISP_WORD|iiMfgDISP_DWORD|iiMfgDISP_QWORD
    iiMfgDATA_None      = 0 ; DATA=
    iiMfgDATA_BYTE      = 0x0000_0100 ; Operand size is  1 byte.  See also suffix B.
    iiMfgDATA_WORD      = 0x0000_0200 ; Operand size is  2 bytes. See also suffix W.
    iiMfgDATA_DWORD     = 0x0000_0400 ; Operand size is  4 bytes. See also suffix D.
    iiMfgDATA_QWORD     = 0x0000_0800 ; Operand size is  8 bytes. See also suffix Q.
    iiMfgDATA_TBYTE     = 0x0000_1000 ; Operand size is 10 bytes.
    iiMfgDATA_OWORD     = 0x0000_2000 ; Operand size is 16 bytes.
    iiMfgDATA_YWORD     = 0x0000_4000 ; Operand size is 32 bytes.
    iiMfgDATA_ZWORD     = 0x0000_8000 ; Operand size is 64 bytes.
    iiMfgDATA_Mask      = iiMfgDATA_BYTE|iiMfgDATA_WORD|iiMfgDATA_DWORD|iiMfgDATA_QWORD|iiMfgDATA_TBYTE|iiMfgDATA_OWORD|iiMfgDATA_YWORD|iiMfgDATA_ZWORD
    iiMfgCODE_None      = 0 ; CODE=
    iiMfgCODE_SHORT     = 0x0001_0000 ; Use encoding with shorter or lower opcode (default).
    iiMfgCODE_LONG      = 0x0002_0000 ; Use longer or numericaly higher opcode.
    iiMfgCODE_Mask      = iiMfgCODE_SHORT|iiMfgCODE_LONG
    iiMfgSCALE_None     = 0 ; SCALE=
    iiMfgSCALE_SMART    = 0x0004_0000 ; Optimise encoding for shortest possible code.
    iiMfgSCALE_VERBATIM = 0x0008_0000 ; Encode scaling exactly as specified in address expression.
    iiMfgSCALE_Mask     = iiMfgSCALE_SMART|iiMfgSCALE_VERBATIM
    iiMfgADDR_None      = 0 ; ADDR=
    iiMfgADDR_ABS       = 0x0010_0000 ; Encode displacement as absolute distance with relocation.
    iiMfgADDR_REL       = 0x0020_0000 ; Encode immediate in 64bit mode as RIP relative distance (default).
    iiMfgADDR_PLT       = 0x0040_0000 ; Encode immediate as PLT item relative distance.
    iiMfgADDR_GOT       = 0x0080_0000 ; Encode immediate as GOT item relative distance.
    ;                   = 0x0100_0000 ; Unused.
    ;                   = 0x0200_0000 ; Unused.
    ;                   = 0x0400_0000 ; Unused.
    ;                   = 0x0800_0000 ; Unused.
    iiMfgADDR_Mask      = iiMfgADDR_ABS|iiMfgADDR_REL|iiMfgADDR_PLT|iiMfgADDR_GOT
    iiMfgDIST_None      = 0 ; DIST=
    iiMfgDIST_SHORT     = 0x1000_0000 ; Encode JMP distance as RIP relative in 1 byte.            See also suffix S.
    iiMfgDIST_NEAR      = 0x2000_0000 ; Encode JMP/CALL distance as RIP relative in 2 or 4 bytes. See also suffix N.
    iiMfgDIST_FAR       = 0x4000_0000 ; Encode JMP/CALL distance as an absolute segment:offset.   See also suffix F.
    iiMfgDIST_Mask      = iiMfgDIST_SHORT|iiMfgDIST_NEAR|iiMfgDIST_FAR
    iiMfgNESTING_OFF    = 0x8000_0000 ; NESTINGCHECK=OFF was specified in the block pseudoinstruction.

↑ Modifiers encoding (AVX)
  Keyword instruction modifiers used in AVX machine instructions: `BCST=, EH=, MASK=, OPER=, PREFIX=, ROUND=, SAE=, ZEROING=`.
  They are parsed by StmGetIiModifiers and stored to II.MfxExplicit.
  Same flags are also used in II.MfxAllowed, II.MfxExplicit, II.MfxEmitted.

    iiMfxMASK_None      = 0 ; MASK=
    iiMfxMASK_K0        = 0x0000_0001
    iiMfxMASK_K1        = 0x0000_0002
    iiMfxMASK_K2        = 0x0000_0004
    iiMfxMASK_K3        = 0x0000_0008
    iiMfxMASK_K4        = 0x0000_0010
    iiMfxMASK_K5        = 0x0000_0020
    iiMfxMASK_K6        = 0x0000_0040
    iiMfxMASK_K7        = 0x0000_0080
    iiMfxMASK_Mask      = 0x0000_00FF
    iiMfxPREFIX_None    = 0 ; PREFIX=
    iiMfxPREFIX_REX     = 0x0000_0100
    iiMfxPREFIX_XOP     = 0x0000_0200
    iiMfxPREFIX_VEX2    = 0x0000_0400
    iiMfxPREFIX_VEX3    = 0x0000_0800
    iiMfxPREFIX_VEX     = iiMfxPREFIX_VEX2 | iiMfxPREFIX_VEX3
    iiMfxPREFIX_MVEX    = 0x0000_1000
    iiMfxPREFIX_EVEX    = 0x0000_2000
    iiMfxPREFIX_Mask    = iiMfxPREFIX_REX|iiMfxPREFIX_XOP|iiMfxPREFIX_VEX|iiMfxPREFIX_MVEX|iiMfxPREFIX_EVEX
    iiMfxROUND_None     = 0 ; ROUND=
    iiMfxROUND_NEAR     = 0x0001_0000
    iiMfxROUND_DOWN     = 0x0002_0000
    iiMfxROUND_UP       = 0x0004_0000
    iiMfxROUND_ZERO     = 0x0008_0000
    iiMfxROUND_Mask     = iiMfxROUND_NEAR|iiMfxROUND_DOWN|iiMfxROUND_UP|iiMfxROUND_ZERO
    iiMfxEH_None        = 0 ; EH= boolean value.
    iiMfxEH_0           = 0x0010_0000
    iiMfxEH_1           = 0x0020_0000
    iiMfxEH_Mask        = iiMfxEH_0|iiMfxEH_1
    iiMfxZEROING_None   = 0 ; ZEROING=
    iiMfxZEROING_0      = 0x0040_0000 ; Merging.
    iiMfxZEROING_1      = 0x0080_0000
    iiMfxZEROING_Mask   = iiMfxZEROING_0|iiMfxZEROING_1
    iiMfxSAE_None       = 0 ; SAE=
    iiMfxSAE_0          = 0x0100_0000
    iiMfxSAE_1          = 0x0200_0000
    iiMfxSAE_Mask       = iiMfxSAE_0|iiMfxSAE_1
    iiMfxBCST_None      = 0 ; BCST=
    iiMfxBCST_0         = 0x0400_0000
    iiMfxBCST_1         = 0x0800_0000
    iiMfxBCST_Mask      = iiMfxBCST_0|iiMfxBCST_1
    iiMfxOPER_None      = 0 ; OPER=
    iiMfxOPER_Mask      = 0x7000_0000 ; Synchronized with DWORD EVEX.L'.L.b and MVEX.S2.S1.S0.
    iiMfxOPER_Used      = 0x8000_0000 ; Value 0..7 in iiMfxOPER_Mask is valid.

↑ IiReloc encoding
  Flags `iiReloc*` describe requests for relocations in the emitted code. They are kept in II.Reloc. Together with II.MfgEmitted and II.Ppg they instruct IiFlush how to encode the instruction. They should be set by the macro IiReloc.
  For description of relocation in emitted code, see RELOC.
  The low byte of `II.Reloc` (00h, 14h, 28h, 3Ch) is valid only with `iiRelocExtAttrReq` and it identifies the operand (.Operand1, .Operand2, .Operand3, .Operand4) with possible postponed attribute evaluation.

    iiRelocOffsExtAttr = 0x0000_00FF ; Offset of .OperandX in II (00h, 14h, 28h, 3Ch) with postponed attribute of external symbol.
    iiRelocDispAbs     = 0x0001_0000 ; Displacement is segment-relocable, create relocAbsVA.
    iiRelocDispRel     = 0x0002_0000 ; Displacement is self-relocable, create relocRel.
    iiRelocDispRIP     = 0x0008_0000 ; Displacement needs 64bit-mode RIP-relocation before emit. No RELOC record.
    iiRelocImmAbs      = 0x0010_0000 ; Immediate is segment-relocable, create RelocAbs.
    iiRelocImmRel      = 0x0020_0000 ; Immediate is self-relocable, create relocRel.
    iiRelocImmRIP      = 0x0080_0000 ; Immediate needs rIP relocation before emit. No RELOC record.
    iiRelocFar         = 0x0100_0000 ; Immediate II.ImmRelocSeg needs relocFar.
    iiRelocPara        = 0x0200_0000 ; Immediate segment-register value (paragraph address) needs relocPara.
    iiRelocExtAttrReq  = 0x8000_0000 ; Indication that iiRelocExtAttr is valid.

↑ CPU requirements
  `iiCPU_*` flags describe CPU and SIMD level requested by instruction and/or by registers used in its operands.
  Theese flags are used in II.Cpu, EAOPT.Machine and DictRegisters.Data.
  Only one `iiCPU_CpuMask` option is required in IiHandlers, but setting it with `EUROASM CPU=?86` will also set all lower options in `EAOPT.Machine:iiEaoptCPU` as well.
  Only one `iiCPU_SimdMask` option is required in IiHandlers, but setting it with `EUROASM CPU=SSE?` will also set all lower options in `EAOPT.Machine:iiEaoptCPU` as well.

    iiCPU_CpuMask = 0x0000_1FC0 ; Required CPU generation controlled by EUROASM CPU= option.
    iiCPU_086     = 0x0000_0000 ; CPU=086 for instructions which work on any Intel compatible machine.
    iiCPU_186     = 0x0000_0040 ; This instruction requires CPU level 186.
    iiCPU_286     = 0x0000_0080 ; This instruction requires CPU level 286.
    iiCPU_386     = 0x0000_0100 ; This instruction requires CPU level 386 (32bit processor).
    iiCPU_486     = 0x0000_0200 ; This instruction requires CPU level 486.
    iiCPU_586     = 0x0000_0400 ; Alias PENTIUM.
    iiCPU_686     = 0x0000_0800 ; Alias P6 and later.
    iiCPU_X64     = 0x0000_1000 ; This instruction requires 64bit processor.

    iiCPU_SimdMask = 0x007F_E000 ; Required SIMD generation controlled by EUROASM SIMD= option.
    iiCPU_SSE      = 0x0000_2000 ; This instruction requires SIMD level SSE1.
    iiCPU_SSE1     = 0x0000_2000 ; This instruction requires SIMD level SSE1.
    iiCPU_SSE2     = 0x0000_4000 ; This instruction requires SIMD level SSE2.
    iiCPU_SSE3     = 0x0000_8000 ; This instruction requires SIMD level SSE3.
    iiCPU_SSSE3    = 0x0001_0000 ; This instruction requires SIMD level SSSE3.
    iiCPU_SSE4     = 0x0002_0000 ; This instruction requires SIMD level SSE4.
    iiCPU_SSE4.1   = 0x0004_0000 ; This instruction requires SIMD level SSE4.1.
    iiCPU_SSE4.2   = 0x0008_0000 ; This instruction requires SIMD level SSE4.2.
    iiCPU_AVX      = 0x0010_0000 ; This instruction requires SIMD level AVX.
    iiCPU_AVX2     = 0x0020_0000 ; This instruction requires SIMD level AVX2.
    iiCPU_AVX512   = 0x0040_0000 ; This instruction requires SIMD level AVX512.
    ; Flags used in DictRegisters to require CPU generation by using a register in instruction:
    iiCpuDictRegMask = iiCPU_386|iiCPU_X64|iiCPU_SSE1|iiCPU_AVX|iiCPU_AVX512
    ; Flags used in DictPrefixes to require CPU generation by using a prefix in instruction:
    iiCpuDictPfxMask = iiCPU_386|iiCPU_686

↑ CPU features encoding
  `iiFea_*` flags specify which special CPU feature is requested by instruction and/or by registers used in its operands.
  Theese flags are used in II.Features, EAOPT.Features and under `iiFeaDictRegMask` in DictRegisters.Data.

    iiFea_PROT   = 0x0000_0001 ; Protected mode.
    iiFea_VMX    = 0x0000_0002 ; Virtual Machine Extensions, VMX, SVM.
    ;            = 0x0000_0004 ;
    iiFea_AES    = 0x0000_0008 ; Intel AES instructions.
    iiFea_SHA    = 0x0000_0010 ; Intel SHA instructions.
    iiFea_LWP    = 0x0000_0020 ; LightWeight Profiling extensions (AMD).
    iiFea_XOP    = 0x0000_0040 ; Encoding prefix XOP (AMD).
    iiFea_MVEX   = 0x0000_0080 ; Encoding prefix MVEX (AVX512).
    iiFea_EVEX   = 0x0000_0100 ; Encoding prefix EVEX (AVX512).
    iiFea_FPU    = 0x0000_0200 ; Floating-point unit (math coprocessor).
    iiFea_TSX    = 0x0000_0400 ; Transactional Synchronization Extensions, TSX, RTM.
    iiFea_MMX    = 0x0000_0800 ; MultiMedia extensions.
    ;            = 0x0000_1000 ;
    iiFea_SGX    = 0x0000_2000 ; Software Guard Extensions.
    ;            = 0x0000_4000 ;
    ;            = 0x0000_8000 ;
    iiFea_ABM    = 0x0001_0000 ; Advanced Bit Manipulation, ABM, BMI1, BMI2, TBM.
    ;            = 0x0002_0000 ;
    iiFea_SVM    = 0x0004_0000 ; Shared Virtual Memory
    iiFea_MPX    = 0x0008_0000 ; Memory Protection Extensions.
    iiFea_CET    = 0x0010_0000 ; Control-flow Enforcement Technology.
    iiFea_PRIV   = 0x0020_0000 ; This instruction/register requires privileged mode CPL=0.
    ;            = 0x0040_0000 ;
    iiFea_UNDOC  = 0x0080_0000 ; Undocumented instruction/register.
    iiFea_AMD    = 0x0100_0000 ; Processor made by AMD.
    iiFea_CYRIX  = 0x0200_0000 ; Processor made by CYRIX.
    iiFea_VIA    = 0x0400_0000 ; Processor made by VIA.
    ;            = 0x0800_0000 ;
    iiFea_D3NOW  = 0x1000_0000 ; 3DNow! extensions (AMD).
    iiFea_FMA    = 0x2000_0000 ; Fused Multiply-Add extensions.
    ;            = 0x4000_0000 ;
    iiFea_SPEC   = 0x8000_0000 ; Special feature not mentioned above.
                      ; Flags used in DictRegisters to require CPU feature by using a register in instruction:
    iiFeaDictRegMask = iiFea_FPU|iiFea_MMX|iiFea_MPX|iiFea_PRIV|iiFea_UNDOC
                      ; Flags used in DictPrefixes to require CPU feature by using a prefix in instruction:
    iiFeaDictPfxMask = iiFea_TSX

↑ Prefix encoding
  Flags `iiPfx_*` describe instruction prefixes other than *VEX. They are used in DictPrefixes.Data, II.PfxAllowed, II.PfxExplicit, II.PfxEmitted.

    iiPfxCode      = 0x0000_00FF ; 8bit operation code of the prefix.
    iiPfxREX       = 0x0000_0040 ; 0x40
    iiPfxREX.B     = 0x0000_0041 ; 0x41
    iiPfxREX.X     = 0x0000_0042 ; 0x42
    iiPfxREX.R     = 0x0000_0044 ; 0x44
    iiPfxREX.W     = 0x0000_0048 ; 0x48
    iiPfxGrpAny    = 0x0000_F000 ; Prefix group presence mask.
    iiPfxGrp1      = 0x0000_1000
    iiPfxGrp2      = 0x0000_2000
    iiPfxGrp3      = 0x0000_4000
    iiPfxGrp4      = 0x0000_8000
    iiPfxMask      = 0xFFFF_0000 ; Prefix identification. Bit-Nr in iiPfxMask correspondes with warnings number W2356..W2371.
    iiPfxLOCK      = 0x0001_0000 ; 0xF0
    iiPfxRepAny    = 0x000C_0000
    iiPfxREP       = 0x0004_0000 ; 0xF3
    iiPfxREPE      = 0x0004_0000 ; 0xF3
    iiPfxREPNE     = 0x0008_0000 ; 0xF2
    iiPfxSegAny    = 0x03F0_0000
    iiPfxSegAny086 = 0x00F0_0000
    iiPfxSEGES     = 0x0010_0000 ; 0x26
    iiPfxSEGCS     = 0x0020_0000 ; 0x2E
    iiPfxSEGSS     = 0x0040_0000 ; 0x36
    iiPfxSEGDS     = 0x0080_0000 ; 0x3E
    iiPfxSEGFS     = 0x0100_0000 ; 0x64
    iiPfxSEGGS     = 0x0200_0000 ; 0x65
    iiPfxTsxAny    = 0x0C00_0000
    iiPfxXACQUIRE  = 0x0400_0000 ; 0xF2
    iiPfxXRELEASE  = 0x0800_0000 ; 0xF3
    iiPfxHintAny   = 0x3000_0000
    iiPfxSELDOM    = 0x1000_0000 ; 0x2E
    iiPfxOFTEN     = 0x2000_0000 ; 0x3E
    iiPfxOTOGGLE   = 0x4000_0000 ; 0x66
    iiPfxATOGGLE   = 0x8000_0000 ; 0x67

↑ Register encoding
  Flags `iiReg_*` describe each CPU register in 8 bits.
  When the two most significant bits [7,6] are both reset, the register belongs to 8member family.
  When the most significant bit [7] is set, the register belongs to 32member family (XMM,YMM or ZMM).
  Otherwise the register belongs to 16member family (general-purpose registers).
  Least significant 3, 4 or 5 bits identify each member of the register family.
  Register family and ordinal can be extracted from this encodig with IiGetRegFamily and IiGetRegOrdinal.
  This encoding is used in register definition DictRegisters.Data.
Examples
  Register CX is encoded as `iiReg_R16 + 1 = 0101_0001b`,
  register R10B is encoded as `iiRegR08 + 10 = 0100_1010b`,
  register ZMM25 is encoded as `iiRegZMM + 25 = 110_11001b`,
  register K5 is encoded as `iiRegKRG + 5 = 11100_101b`.

    iiRegIdMask    = 1111_1111b ; Register identification in 8 bits.
    iiReg_Fam8     = 11111_000b ; Families with max. 8 members:
    iiReg_Ord8     = 00000_111b ; Register ordinal mask 0..7.
    iiReg_SEG      = 00001_000b ; Segment registers ES,CS,SS,DS,ES,FS,GS,SEGR6,SEGR7.
    iiReg_FPR      = 00010_000b ; Floating-point registers ST0..ST7.
    iiReg_MMX      = 00011_000b ; 64 bit MMX registers MM0..MM7.
    iiReg_DGR      = 00100_000b ; Debug registers DR0..DR7.
    iiReg_TSR      = 00101_000b ; Test registers TR3..TR7.
    iiReg_CTR      = 00110_000b ; Control registers CR0..CR7.
    iiReg_CT8      = 00111_000b ; Control register CR8.
    iiReg_Fam16    = 11000_000b ; Families with 16 members:
    iiReg_Ord16    = 0000_1111b ; Register ordinal mask 0..15.
    iiReg_R08      = 0100_0000b ; GPR  8 bits  AL..R15B.
    iiReg_R16      = 0101_0000b ; GPR 16 bits  AX..R15W.
    iiReg_R32      = 0110_0000b ; GPR 32 bits EAX..R15D.
    iiReg_R64      = 0111_0000b ; GPR 64 bits RAX..R15.
    iiReg_Fam32    = 1000_0000b ; Families with 32 members:
    iiReg_Ord32    = 000_11111b ; Register ordinal mask 0..31.
    iiReg_XMM      = 100_00000b ; 128 bit SSE registers XMM0..XMM31.
    iiReg_YMM      = 101_00000b ; 256 bit SSE registers YMM0..YMM31.
    iiReg_ZMM      = 110_00000b ; 512 bit SSE registers ZMM0..ZMM31.
    iiReg_Spec     = 111_00000b ; Special families:
    iiReg_KRG      = 11100_000b ; AVX512 mask registers K0..K7.
    iiReg_BND      = 111100_00b ; MPX registers BND0..BND3.
    ; Register addressing properties.
    iiRegBase      = 0x0000_4000 ; May be base-register.
    iiRegIndex     = 0x0000_8000 ; May be index-register.
    iiRegSeg       = 0x0001_0000 ; Segment register. This will set iiReg_SEG, too.
    iiRegREX       = 0x0002_0000 ; Encoding requires REX/VEX prefix.
    iiRegNoREX     = 0x0004_0000 ; Encoding requires no REX prefix. Flag used in DictRegisters.Data.
    iiRegPpMask    = iiRegBase|iiRegIndex|iiRegSeg|iiRegREX|iiRegNoREX

↑ Miscellaneous encoding
  Used for passing values from macro invocation to its runtime proc etc.

    iiMfsALIGN_Mask  = 0x0000_00FF ; 00=unspec, 01=B 02=W 04=D 08=Q 40=Z etc.
     ; Flags used in macro IiDataSize and IiImmSize.
    iiOsUseOperand1   = 0x0000_0001
    iiOsUseOperand2   = 0x0000_0002
    iiOsUseOperand3   = 0x0000_0004
    iiOsAllowQword    = 0x0000_0008
    iiOsDistFar       = 0x0000_0008
    iiOsSpecifyMemOff = 0x0000_0010
    iiOsUseSegment    = 0x0000_0020
    iiOsAddrRel       = 0x0000_0020
    iiOsFloatingPoint = 0x0000_0040
    iiOsSigned        = 0x0000_0040
    iiOsStreamingSIMD = 0x0000_0080
    iiOsUnsigned      = 0x0000_0080
    ; Flag used in macro IiStringDestination.
    iiSdAllowSeg      = 0x1000_0000 ; Allow other segment prefix beside ES.
    ; Flag used in handler IitGroupXstate.
    iiXs64            = 0x0080_0000 ; Use 64bit version of extended CPU state area.

↑ Intel encoding
  Following 8bit constants are instruction operand categories similar to the specifications used in [IntelMan].
  Each IiHandler is submitted with EDX containing one operand per byte in this encoding.

    none    = 0000_0000b ; No operand.
    imm8    = 0000_0001b ; 8bit immediate operand.
    imm16   = 0000_0010b ; 16bit immediate operand.
    far     = 0000_0011b ; Far pointer in memory.
    imm32   = 0000_0100b ; 32bit immediate operand.
     ;      = 0000_0101b ; Unused.
    imm64   = 0000_0110b ; 64bit immediate operand.
    imm     = 0000_0111b ; Immediate operand, unspecified size.
    Sreg    = 0000_1000b ; iiReg_SEG  Segment register.
    STi:    = 0001_0000b ; iiReg_FPR  Floating-point register. Label needs a colon to avoid collision with instruction STI.
    mmx     = 0001_1000b ; iiReg_MMX  MMX register.
    dgr     = 0010_0000b ; iiReg_DGR  Debug register.
    tsr     = 0010_1000b ; iiReg_TSR  Test register.
    ctr     = 0011_0000b ; iiReg_CTR  Control register.
    ct8     = 0011_1000b ; iiReg_CT8  Control register CR8.
    r8:     = 0100_0000b ; iiReg_R08   8bit general-purpose register. Label needs a colon to avoid collision with register R8.
    r16     = 0101_0000b ; iiReg_R16  16bit general-purpose register.
    r32     = 0110_0000b ; iiReg_R32  32bit general-purpose register.
    r64     = 0111_0000b ; iiReg_R64  64bit general-purpose register.
    xmm     = 1000_0000b ; iiReg_XMM  XMM register.
    ymm     = 1010_0000b ; iiReg_YMM  YMM register.
    zmm     = 1100_0000b ; iiReg_ZMM  ZMM register.
    krg     = 1110_0000b ; iiReg_KRG  K0..K7 mask register.
    bnd     = 1111_0000b ; iiReg_BND  BND0..BND3 bound register.
    m8      = 1111_0001b ;   8bit memory variable, DB.
    m16     = 1111_0010b ;  16bit memory variable, DW.
     ;      = 1111_0011b ;  Unused.
    m32     = 1111_0100b ;  32bit memory variable, DD.
     ;      = 1111_0101b ;  Unused.
    m64     = 1111_0110b ;  64bit memory variable, DQ.
    m80     = 1111_1000b ;  80bit memory variable, DT.
    m128    = 1111_1001b ; 128bit memory variable, DO.
    m256    = 1111_1010b ; 256bit memory variable, DY.
    m512    = 1111_1011b ; 512bit memory variable, DZ.
    mem     = 1111_1111b ; Memory operand, unspecified size.

    ; Combinations of operand types which occur in instructions provided to handlers in EDX.
    ; The last operand is in DL, the last but one in DH etc.
    ; E.g. the handler for SAL BX,8 is called with EDX = r16.imm = 0x00005007.

    imm.m16      = imm <<8 + m16                                                                               ;>>
    imm.m32      = imm <<8 + m32                                                                               ;>>
    imm.m64      = imm <<8 + m64                                                                               ;>>
    mem.mem      = mem <<8 + mem                                                                               ;>>
    mem.Sreg     = mem <<8 + Sreg                                                                              ;>>
    mem.r8       = mem <<8 + r8:                                                                               ;>>
    mem.r16      = mem <<8 + r16                                                                               ;>>
    mem.r32      = mem <<8 + r32                                                                               ;>>
    mem.r64      = mem <<8 + r64                                                                               ;>>
    mem.STi      = mem <<8 + STi:                                                                              ;>>
    mem.imm      = mem <<8 + imm                                                                               ;>>
    mem.imm8     = mem <<8 + imm8                                                                              ;>>
    mem.imm16    = mem <<8 + imm16                                                                             ;>>
    mem.imm32    = mem <<8 + imm32                                                                             ;>>
    mem.imm64    = mem <<8 + imm64                                                                             ;>>
    mem.xmm      = mem <<8 + xmm                                                                               ;>>
    mem.ymm      = mem <<8 + ymm                                                                               ;>>
    mem.zmm      = mem <<8 + zmm                                                                               ;>>
    mem.xmm.imm  = mem <<16 + xmm<<8 + imm                                                                     ;>>>>
    mem.mmx.mmx  = mem <<16 + mmx<<8 + mmx                                                                     ;>>>>
    mem.xmm.xmm  = mem <<16 + xmm<<8 + xmm                                                                     ;>>>>
    mem.ymm.imm  = mem <<16 + ymm<<8 + imm                                                                     ;>>>>
    mem.ymm.ymm  = mem <<16 + ymm<<8 + ymm                                                                     ;>>>>
    mem.zmm.imm  = mem <<16 + zmm<<8 + imm                                                                     ;>>>>

    r8.r8        = r8: <<8 + r8:                                                                               ;>>
    r8.r16       = r8: <<8 + r16                                                                               ;>>
    r8.imm       = r8: <<8 + imm                                                                               ;>>
    r8.imm8      = r8: <<8 + imm8                                                                              ;>>
    r8.imm16     = r8: <<8 + imm16                                                                             ;>>
    r8.imm32     = r8: <<8 + imm32                                                                             ;>>
    r8.imm64     = r8: <<8 + imm64                                                                             ;>>
    r8.mem       = r8: <<8 + mem                                                                               ;>>
    r8.m8        = r8: <<8 + m8                                                                                ;>>
    r8.xmm.imm  =  r8:<<16 + xmm<<8 + imm                                                                      ;>>
    m8.r8        = m8 <<8 + r8:                                                                                ;>>
    m8.r16       = m8 <<8 + r16                                                                                ;>>
    m8.r16.r8    = m8 <<16 + r16<<8 + r8:                                                                      ;>>
    m8.r16.imm   = m8 <<16 + r16<<8 + imm                                                                      ;>>
    m8.r32       = m8 <<8 + r32                                                                                ;>>
    m8.r32.r8    = m8 <<16 + r32<<8 + r8:                                                                      ;>>
    m8.r32.imm   = m8 <<16 + r32<<8 + imm                                                                      ;>>
    m8.r64       = m8 <<8 + r64                                                                                ;>>
    m8.r64.r8    = m8 <<16 + r64<<8 + r8:                                                                      ;>>
    m8.r64.imm   = m8 <<16 + r64<<8 + imm                                                                      ;>>
    m8.imm       = m8 <<8 + imm                                                                                ;>>
    m8.imm8      = m8 <<8 + imm8                                                                               ;>>
    m8.imm16     = m8 <<8 + imm16                                                                              ;>>
    m8.imm32     = m8 <<8 + imm32                                                                              ;>>
    m8.imm64     = m8 <<8 + imm64                                                                              ;>>

    r16.r8       = r16<<8 + r8:                                                                                ;>>
    r16.r16      = r16<<8 + r16                                                                                ;>>
    r16.r32      = r16<<8 + r32                                                                                ;>>
    r16.r16.imm  = r16<<16 + r16<<8 + imm                                                                      ;>>
    r16.r16.r8   = r16<<16 + r16<<8 + r8:                                                                      ;>>
    r16.r64      = r16<<8 + r64                                                                                ;>>
    r16.imm      = r16<<8 + imm                                                                                ;>>
    r16.imm8     = r16<<8 + imm8                                                                               ;>>
    r16.imm16    = r16<<8 + imm16                                                                              ;>>
    r16.imm32    = r16<<8 + imm32                                                                              ;>>
    r16.imm64    = r16<<8 + imm64                                                                              ;>>
    r16.mem      = r16<<8 + mem                                                                                ;>>
    r16.m8       = r16<<8 + m8                                                                                 ;>>
    r16.m16      = r16<<8 + m16                                                                                ;>>
    r16.m32      = r16<<8 + m32                                                                                ;>>
    r16.m64      = r16<<8 + m64                                                                                ;>>
    r16.m512     = r16<<8 + m512                                                                               ;>>
    r16.Sreg     = r16<<8 + Sreg                                                                               ;>>
    r16.m16.imm  = r16<<16 + m16<<8 + imm                                                                      ;>>
    r16.mmx.imm  = r16<<16 + mmx<<8 + imm                                                                      ;>>
    r16.xmm.imm  = r16<<16 + xmm<<8 + imm                                                                      ;>>
    r16.r16.r8.r16  = r16<<24 + r16<<16 + r8:<<8 + r16                                                         ;>>>>>>
    mem.r16.r8.r16  = mem<<24 + r16<<16 + r8:<<8 + r16                                                         ;>>>>>>
    r16.r16.r16.r8  = r16<<24 + r16<<16 + r16<<8 + r8:                                                         ;>>>>>>
    r16.mem.r16.r8  = r16<<24 + mem<<16 + r16<<8 + r8:                                                         ;>>>>>>

    m16.r8       = m16<<8 + r8:                                                                                ;>>
    m16.r16      = m16<<8 + r16                                                                                ;>>
    m16.Sreg     = m16<<8 + Sreg                                                                               ;>>
    m16.r16.r8   = m16<<16 + r16<<8 + r8:                                                                      ;>>
    m16.r16.imm  = m16<<16 + r16<<8 + imm                                                                      ;>>
    m16.r32      = m16<<8 + r32                                                                                ;>>
    m16.r32.imm  = m16<<16 + r32<<8 + imm                                                                      ;>>
    m16.r32.r8   = m16<<16 + r32<<8 + r8:                                                                      ;>>
    m16.r64      = m16<<8 + r64                                                                                ;>>
    m16.r64.r8   = m16<<16 + r64<<8 + r8:                                                                      ;>>
    m16.r64.imm  = m16<<16 + r64<<8 + imm                                                                      ;>>
    m16.STi      = m16<<8 + STi                                                                                ;>>
    m16.imm      = m16<<8 + imm                                                                                ;>>
    m16.imm8     = m16<<8 + imm8                                                                               ;>>
    m16.imm16    = m16<<8 + imm16                                                                              ;>>
    m16.imm32    = m16<<8 + imm32                                                                              ;>>
    m16.imm64    = m16<<8 + imm64                                                                              ;>>

    r32.r8       = r32<<8 + r8:                                                                                ;>>
    r32.r16      = r32<<8 + r16                                                                                ;>>
    r32.r32      = r32<<8 + r32                                                                                ;>>
    r32.r64      = r32<<8 + r64                                                                                ;>>
    r32.Sreg     = r32<<8 + Sreg                                                                               ;>>
    r32.r32.imm  = r32<<16 + r32<<8 + imm                                                                      ;>>
    r32.r32.mem  = r32<<16 + r32<<8 + mem                                                                      ;>>
    r32.mem.imm  = r32<<16 + mem<<8 + imm                                                                      ;>>
    r32.r32.r32  = r32<<16 + r32<<8 + r32                                                                      ;>>
    r32.mem.r32  = r32<<16 + mem<<8 + r32                                                                      ;>>
    r32.r32.r8   = r32<<16 + r32<<8 + r8:                                                                      ;>>
    r32.imm      = r32<<8 + imm                                                                                ;>>
    r32.imm8     = r32<<8 + imm8                                                                               ;>>
    r32.imm16    = r32<<8 + imm16                                                                              ;>>
    r32.imm32    = r32<<8 + imm32                                                                              ;>>
    r32.imm64    = r32<<8 + imm64                                                                              ;>>
    r32.mem      = r32<<8 + mem                                                                                ;>>
    r32.m8       = r32<<8 + m8                                                                                 ;>>
    r32.m16      = r32<<8 + m16                                                                                ;>>
    r32.m32      = r32<<8 + m32                                                                                ;>>
    r32.m64      = r32<<8 + m64                                                                                ;>>
    r32.m512     = r32<<8 + m512                                                                               ;>>
    r32.m32.imm  = r32<<16 + m32<<8 + imm                                                                      ;>>
    r32.mmx.imm  = r32<<16 + mmx<<8 + imm                                                                      ;>>
    r32.xmm.imm  = r32<<16 + xmm<<8 + imm                                                                      ;>>
    r32.r32.r32.r32  = r32<<24 + r32<<16 + r32<<8 + r32                                                        ;>>>>>>
    r32.r32.mem.r32  = r32<<24 + r32<<16 + mem<<8 + r32                                                        ;>>>>>>
    r32.ymm          = r32<<8 + ymm                                                                                ;>>
    r32.r32.r8.r32   = r32<<24 + r32<<16 + r8:<<8 + r32                                                         ;>>>>>>
    mem.r32.r8.r32   = mem<<24 + r32<<16 + r8:<<8 + r32                                                         ;>>>>>>
    r32.r32.r32.r8   = r32<<24 + r32<<16 + r32<<8 + r8:                                                         ;>>>>>>
    r32.mem.r32.r8   = r32<<24 + mem<<16 + r32<<8 + r8:                                                         ;>>>>>>

    m32.r8       = m32<<8 + r8:                                                                                ;>>
    m32.r16      = m32<<8 + r16                                                                                ;>>
    m32.Sreg     = m32<<8 + Sreg                                                                               ;>>
    m32.r16.r8   = m32<<16 + r16<<8 + r8:                                                                      ;>>
    m32.r16.imm  = m32<<16 + r16<<8 + imm                                                                      ;>>
    m32.r32      = m32<<8 + r32                                                                                ;>>
    m32.r32.r8   = m32<<16 + r32<<8 + r8:                                                                      ;>>
    m32.r32.imm  = m32<<16 + r32<<8 + imm                                                                      ;>>
    m32.r64      = m32<<8 + r64                                                                                ;>>
    m32.r64.r8   = m32<<16 + r64<<8 + r8:                                                                      ;>>
    m32.r64.imm  = m32<<16 + r64<<8 + imm                                                                      ;>>
    m32.STi      = m32<<8 + STi                                                                                ;>>
    m32.imm      = m32<<8 + imm                                                                                ;>>
    m32.imm8     = m32<<8 + imm8                                                                               ;>>
    m32.imm16    = m32<<8 + imm16                                                                              ;>>
    m32.imm32    = m32<<8 + imm32                                                                              ;>>
    m32.imm64    = m32<<8 + imm64                                                                              ;>>

    r64.r8       = r64<<8 + r8:                                                                                ;>>
    r64.r16      = r64<<8 + r16                                                                                ;>>
    r64.r32      = r64<<8 + r32                                                                                ;>>
    r64.r64      = r64<<8 + r64                                                                                ;>>
    r64.Sreg     = r64<<8 + Sreg                                                                               ;>>
    r64.r32.imm  = r64<<16 + r32<<8 + imm                                                                      ;>>
    r64.r64.imm  = r64<<16 + r64<<8 + imm                                                                      ;>>
    r64.r64.mem  = r64<<16 + r64<<8 + mem                                                                      ;>>
    r64.mem.imm  = r64<<16 + mem<<8 + imm                                                                      ;>>
    r64.r64.r64  = r64<<16 + r64<<8 + r64                                                                      ;>>
    r64.mem.r64  = r64<<16 + mem<<8 + r64                                                                      ;>>
    r64.r64.r8   = r64<<16 + r64<<8 + r8:                                                                      ;>>
    r64.imm      = r64<<8 + imm                                                                                ;>>
    r64.imm8     = r64<<8 + imm8                                                                               ;>>
    r64.imm16    = r64<<8 + imm16                                                                              ;>>
    r64.imm32    = r64<<8 + imm32                                                                              ;>>
    r64.imm64    = r64<<8 + imm64                                                                              ;>>
    r64.mem      = r64<<8 + mem                                                                                ;>>
    r64.m8       = r64<<8 + m8                                                                                 ;>>
    r64.m16      = r64<<8 + m16                                                                                ;>>
    r64.m32      = r64<<8 + m32                                                                                ;>>
    r64.m64      = r64<<8 + m64                                                                                ;>>
    r64.m512     = r64<<8 + m512                                                                               ;>>
    r64.m64.imm  = r64<<16 + m64<<8 + imm                                                                      ;>>
    r64.mmx.imm  = r64<<16 + mmx<<8 + imm                                                                      ;>>
    r64.xmm.imm  = r64<<16 + xmm<<8 + imm                                                                      ;>>
    r64.krg.krg  = r64<<16 + krg<<8 + krg                                                                      ;>>
    r64.ymm      = r64<<8 + ymm                                                                                ;>>
    r64.r64.r64.r64  = r64<<24 + r64<<16 + r64<<8 + r64                                                        ;>>>>>>
    r64.r64.mem.r64  = r64<<24 + r64<<16 + mem<<8 + r64                                                        ;>>>>>>

    m64.r8       = m64<<8 + r8:                                                                                ;>>
    m64.r16      = m64<<8 + r16                                                                                ;>>
    m64.Sreg     = m64<<8 + Sreg                                                                               ;>>
    m64.r32      = m64<<8 + r32                                                                                ;>>
    m64.r16.r8   = m64<<16 + r16<<8 + r8:                                                                      ;>>
    m64.r16.imm  = m64<<16 + r16<<8 + imm                                                                      ;>>
    m64.r32.r8   = m64<<16 + r32<<8 + r8:                                                                      ;>>
    m64.r32.imm  = m64<<16 + r32<<8 + imm                                                                      ;>>
    m64.r64.r8   = m64<<16 + r64<<8 + r8:                                                                      ;>>
    m64.r64.imm  = m64<<16 + r64<<8 + imm                                                                      ;>>

    m64.r64      = m64<<8 + r64                                                                                ;>>
    m64.STi      = m64<<8 + STi                                                                                ;>>
    m64.imm      = m64<<8 + imm                                                                                ;>>
    m64.imm8     = m64<<8 + imm8                                                                               ;>>
    m64.imm16    = m64<<8 + imm16                                                                              ;>>
    m64.imm32    = m64<<8 + imm32                                                                              ;>>
    m64.imm64    = m64<<8 + imm64                                                                              ;>>
    m80.STi      = m80<<8 + STi                                                                                ;>>

    imm.r8       = imm<<8 + r8:                                                                                ;>>
    imm.r16      = imm<<8 + r16                                                                                ;>>
    imm.r32      = imm<<8 + r32                                                                                ;>>
    imm.r64      = imm<<8 + r64                                                                                ;>>
    imm.imm      = imm<<8 + imm                                                                                ;>>

    Sreg.r16     = Sreg<<8 + r16                                                                               ;>>
    Sreg.r32     = Sreg<<8 + r32                                                                               ;>>
    Sreg.r64     = Sreg<<8 + r64                                                                               ;>>
    Sreg.m16     = Sreg<<8 + m16                                                                               ;>>
    Sreg.m32     = Sreg<<8 + m32                                                                               ;>>
    Sreg.m64     = Sreg<<8 + m64                                                                               ;>>
    Sreg.mem     = Sreg<<8 + mem                                                                               ;>>

    mmx.mmx      = mmx<<8 + mmx                                                                                ;>>
    mmx.r8.imm   = mmx<<16 + r8:<<8 + imm                                                                      ;>>>>
    mmx.r16.imm  = mmx<<16 + r16<<8 + imm                                                                      ;>>>>
    mmx.r32.imm  = mmx<<16 + r32<<8 + imm                                                                      ;>>>>
    mmx.r64.imm  = mmx<<16 + r64<<8 + imm                                                                      ;>>>>
    mmx.mem.imm  = mmx<<16 + mem<<8 + imm                                                                      ;>>>>
    mmx.mmx.imm  = mmx<<16 + mmx<<8 + imm                                                                      ;>>>>
    mmx.r32      = mmx<<8 + r32                                                                                ;>>
    mmx.r64      = mmx<<8 + r64                                                                                ;>>
    r32.mmx      = r32<<8 + mmx                                                                                ;>>
    r64.mmx      = r64<<8 + mmx                                                                                ;>>
    mmx.mem      = mmx<<8 + mem                                                                                ;>>
    mmx.imm      = mmx<<8 + imm                                                                                ;>>
    mem.mmx      = mem<<8 + mmx                                                                                ;>>
    mmx.xmm      = mmx<<8 + xmm                                                                                ;>>

    xmm.xmm      = xmm<<8 + xmm                                                                                ;>>
    xmm.mmx      = xmm<<8 + mmx                                                                                ;>>
    xmm.r8:      = xmm<<8 + r8:                                                                                ;>>
    xmm.r16      = xmm<<8 + r16                                                                                ;>>
    xmm.r32      = xmm<<8 + r32                                                                                ;>>
    xmm.r64      = xmm<<8 + r64                                                                                ;>>
    r32.xmm      = r32<<8 + xmm                                                                                ;>>
    r64.xmm      = r64<<8 + xmm                                                                                ;>>
    xmm.ymm      = xmm<<8 + ymm                                                                                ;>>
    xmm.zmm      = xmm<<8 + zmm                                                                                ;>>
    xmm.mem      = xmm<<8 + mem                                                                                ;>>
    xmm.m32      = xmm<<8 + m32                                                                                ;>>
    xmm.m64      = xmm<<8 + m64                                                                                ;>>
    xmm.krg      = xmm<<8 + krg                                                                                ;>>
    xmm.xmm.r32  = xmm<<16 + xmm<<8 + r32                                                                      ;>>>>
    xmm.xmm.r64  = xmm<<16 + xmm<<8 + r64                                                                      ;>>>>
    xmm.xmm.imm  = xmm<<16 + xmm<<8 + imm                                                                      ;>>>>
    xmm.xmm.mem  = xmm<<16 + xmm<<8 + mem                                                                      ;>>>>
    xmm.mem.imm  = xmm<<16 + mem<<8 + imm                                                                      ;>>>>
    xmm.r8.imm   = xmm<<16 + r8:<<8 + imm                                                                      ;>>>>
    xmm.r16.imm  = xmm<<16 + r16<<8 + imm                                                                      ;>>>>
    xmm.r32.imm  = xmm<<16 + r32<<8 + imm                                                                      ;>>>>
    xmm.r64.imm  = xmm<<16 + r64<<8 + imm                                                                      ;>>>>
    xmm.imm      = xmm<<8 + imm                                                                                ;>>
    xmm.xmm.xmm  = xmm<<16 + xmm<<8 + xmm                                                                      ;>>>>
    xmm.mem.xmm  = xmm<<16 + mem<<8 + xmm                                                                      ;>>>>
    xmm.imm.imm  = xmm<<16 + imm<<8 + imm                                                                      ;>>>>
    xmm.ymm.imm  = xmm<<16 + ymm<<8 + imm                                                                      ;>>>>
    xmm.zmm.imm  = xmm<<16 + zmm<<8 + imm                                                                      ;>>>>
    xmm.xmm.imm.imm  = xmm<<24 + xmm<<16 + imm<<8 + imm                                                        ;>>>>>>
    xmm.xmm.xmm.imm  = xmm<<24 + xmm<<16 + xmm<<8 + imm                                                        ;>>>>>>
    xmm.xmm.xmm.xmm  = xmm<<24 + xmm<<16 + xmm<<8 + xmm                                                        ;>>>>>>
    xmm.xmm.mem.xmm  = xmm<<24 + xmm<<16 + mem<<8 + xmm                                                        ;>>>>>>
    xmm.xmm.mem.imm  = xmm<<24 + xmm<<16 + mem<<8 + imm                                                        ;>>>>>>
    xmm.xmm.xmm.mem  = xmm<<24 + xmm<<16 + xmm<<8 + mem                                                        ;>>>>>>
    xmm.xmm.r32.imm  = xmm<<24 + xmm<<16 + r32<<8 + imm                                                        ;>>>>>>
    xmm.xmm.r64.imm  = xmm<<24 + xmm<<16 + r64<<8 + imm                                                        ;>>>>>>
    ymm.r8:      = ymm<<8  + r8:                                                                               ;>>
    ymm.r16      = ymm<<8  + r16                                                                               ;>>
    ymm.r32      = ymm<<8  + r32                                                                               ;>>
    ymm.r64      = ymm<<8  + r64                                                                               ;>>
    ymm.mem      = ymm<<8  + mem                                                                               ;>>
    ymm.xmm      = ymm<<8  + xmm                                                                               ;>>
    ymm.ymm      = ymm<<8  + ymm                                                                               ;>>
    ymm.zmm      = ymm<<8  + zmm                                                                               ;>>
    ymm.krg      = ymm<<8  + krg                                                                               ;>>
    ymm.ymm.ymm  = ymm<<16 + ymm<<8 + ymm                                                                      ;>>>>
    ymm.ymm.xmm  = ymm<<16 + ymm<<8 + xmm                                                                      ;>>>>
    ymm.ymm.mem  = ymm<<16 + ymm<<8 + mem                                                                      ;>>>>
    ymm.ymm.imm  = ymm<<16 + ymm<<8 + imm                                                                      ;>>>>
    ymm.ymm.ymm.imm  = ymm<<24 + ymm<<16 + ymm<<8 + imm                                                        ;>>>>>>
    ymm.ymm.mem.imm  = ymm<<24 + ymm<<16 + mem<<8 + imm                                                        ;>>>>>>
    ymm.ymm.xmm.imm  = ymm<<24 + ymm<<16 + xmm<<8 + imm                                                        ;>>>>>>
    ymm.ymm.ymm.ymm  = ymm<<24 + ymm<<16 + ymm<<8 + ymm                                                        ;>>>>>>
    ymm.ymm.mem.ymm  = ymm<<24 + ymm<<16 + mem<<8 + ymm                                                        ;>>>>>>
    ymm.ymm.ymm.mem  = ymm<<24 + ymm<<16 + ymm<<8 + mem                                                        ;>>>>>>
    ymm.mem.ymm  = ymm<<16 + mem<<8 + ymm                                                                      ;>>>>
    ymm.mem.imm  = ymm<<16 + mem<<8 + imm                                                                      ;>>>>
    ymm.zmm.imm  = ymm<<16 + zmm<<8 + imm                                                                      ;>>>>
    zmm.r8:      = zmm<<8  + r8:                                                                               ;>>
    zmm.r16      = zmm<<8  + r16                                                                               ;>>
    zmm.r32      = zmm<<8  + r32                                                                               ;>>
    zmm.r64      = zmm<<8  + r64                                                                               ;>>
    zmm.xmm      = zmm<<8  + xmm                                                                               ;>>
    zmm.ymm      = zmm<<8  + ymm                                                                               ;>>
    zmm.zmm      = zmm<<8  + zmm                                                                               ;>>
    zmm.mem      = zmm<<8  + mem                                                                               ;>>
    zmm.krg      = zmm<<8  + krg                                                                               ;>>
    zmm.zmm.zmm  = zmm<<16 + zmm<<8 + zmm                                                                      ;>>>>
    zmm.zmm.xmm  = zmm<<16 + zmm<<8 + xmm                                                                      ;>>>>
    zmm.zmm.mem  = zmm<<16 + zmm<<8 + mem                                                                      ;>>>>
    zmm.mem.imm  = zmm<<16 + mem<<8 + imm                                                                      ;>>>>
    zmm.zmm.imm  = zmm<<16 + zmm<<8 + imm                                                                      ;>>>>
    zmm.krg.zmm  = zmm<<16 + krg<<8 + zmm                                                                      ;>>>>
    zmm.krg.mem  = zmm<<16 + krg<<8 + mem                                                                      ;>>>>
    zmm.zmm.zmm.imm  = zmm<<24 + zmm<<16 + zmm<<8 + imm                                                        ;>>>>>>
    zmm.zmm.xmm.imm  = zmm<<24 + zmm<<16 + xmm<<8 + imm                                                        ;>>>>>>
    zmm.zmm.ymm.imm  = zmm<<24 + zmm<<16 + ymm<<8 + imm                                                        ;>>>>>>
    zmm.zmm.mem.imm  = zmm<<24 + zmm<<16 + mem<<8 + imm                                                        ;>>>>>>

    krg.krg      = krg<<8  + krg                                                                               ;>>
    krg.mem      = krg<<8  + mem                                                                               ;>>
    krg.imm      = krg<<8  + imm                                                                               ;>>
    mem.krg      = mem<<8  + krg                                                                               ;>>
    krg.r32      = krg<<8  + r32                                                                               ;>>
    r32.krg      = r32<<8  + krg                                                                               ;>>
    krg.r64      = krg<<8  + r64                                                                               ;>>
    r64.krg      = r64<<8  + krg                                                                               ;>>
    krg.xmm      = krg<<8  + xmm                                                                               ;>>
    krg.ymm      = krg<<8  + ymm                                                                               ;>>
    krg.zmm      = krg<<8  + zmm                                                                               ;>>
    krg.krg.krg  = krg<<16 + krg<<8 + krg                                                                      ;>>>>
    krg.r64.imm  = krg<<16 + r64<<8 + imm                                                                      ;>>>>
    krg.krg.imm  = krg<<16 + krg<<8 + imm                                                                      ;>>>>
    krg.xmm.imm  = krg<<16 + xmm<<8 + imm                                                                      ;>>>>
    krg.ymm.imm  = krg<<16 + ymm<<8 + imm                                                                      ;>>>>
    krg.zmm.imm  = krg<<16 + zmm<<8 + imm                                                                      ;>>>>
    krg.mem.imm  = krg<<16 + mem<<8 + imm                                                                      ;>>>>
    krg.m128.imm = krg<<16 + m128<<8 + imm                                                                     ;>>>>
    krg.m256.imm = krg<<16 + m256<<8 + imm                                                                     ;>>>>
    krg.m512.imm = krg<<16 + m512<<8 + imm                                                                     ;>>>>
    krg.xmm.xmm  = krg<<16 + xmm<<8 + xmm                                                                      ;>>>>
    krg.xmm.mem  = krg<<16 + xmm<<8 + mem                                                                      ;>>>>
    krg.ymm.ymm  = krg<<16 + ymm<<8 + ymm                                                                      ;>>>>
    krg.ymm.mem  = krg<<16 + ymm<<8 + mem                                                                      ;>>>>
    krg.zmm.zmm  = krg<<16 + zmm<<8 + zmm                                                                      ;>>>>
    krg.zmm.mem  = krg<<16 + zmm<<8 + mem                                                                      ;>>>>
    krg.xmm.mem.imm  = krg<<24 + xmm<<16 + mem<<8 + imm                                                        ;>>>>>>
    krg.xmm.xmm.imm  = krg<<24 + xmm<<16 + xmm<<8 + imm                                                        ;>>>>>>
    krg.ymm.mem.imm  = krg<<24 + ymm<<16 + mem<<8 + imm                                                        ;>>>>>>
    krg.ymm.ymm.imm  = krg<<24 + ymm<<16 + ymm<<8 + imm                                                        ;>>>>>>
    krg.zmm.mem.imm  = krg<<24 + zmm<<16 + mem<<8 + imm                                                        ;>>>>>>
    krg.zmm.zmm.imm  = krg<<24 + zmm<<16 + zmm<<8 + imm                                                        ;>>>>>>

    bnd.bnd      = bnd<<8  + bnd                                                                               ;>>
    bnd.mem      = bnd<<8  + mem                                                                               ;>>
    bnd.r32      = bnd<<8  + r32                                                                               ;>>
    bnd.r64      = bnd<<8  + r64                                                                               ;>>
    mem.bnd      = mem<<8  + bnd                                                                               ;>>
    bnd.mem.r32  = bnd<<16 + mem<<8 + r32                                                                      ;>>>>
    bnd.mem.r64  = bnd<<16 + mem<<8 + r64                                                                      ;>>>>
    mem.r32.bnd  = mem<<16 + r32<<8 + bnd                                                                      ;>>>>
    mem.r64.bnd  = mem<<16 + r64<<8 + bnd                                                                      ;>>>>
    mem.bnd.r32  = mem<<16 + bnd<<8 + r32                                                                      ;>>>>
    mem.bnd.r64  = mem<<16 + bnd<<8 + r64                                                                      ;>>>>

    r32.ctr      = r32<<8 + ctr                                                                                ;>>
    r64.ctr      = r64<<8 + ctr                                                                                ;>>
    ctr.r32      = ctr<<8 + r32                                                                                ;>>
    ctr.r64      = ctr<<8 + r64                                                                                ;>>
    r32.ct8      = r32<<8 + ct8                                                                                ;>>
    r64.ct8      = r64<<8 + ct8                                                                                ;>>
    ct8.r32      = ct8<<8 + r32                                                                                ;>>
    ct8.r64      = ct8<<8 + r64                                                                                ;>>

    r32.dgr      = r32<<8 + dgr                                                                                ;>>
    r64.dgr      = r64<<8 + dgr                                                                                ;>>
    dgr.r32      = dgr<<8 + r32                                                                                ;>>
    dgr.r64      = dgr<<8 + r64                                                                                ;>>

    r32.tsr      = r32<<8 + tsr                                                                                ;>>
    tsr.r32      = tsr<<8 + r32                                                                                ;>>

    STi.STi      = STi:<<8 + STi:                                                                              ;>>
    STi.mem      = STi:<<8 + mem                                                                               ;>>
    STi.m16      = STi:<<8 + m16                                                                               ;>>
    STi.m32      = STi:<<8 + m32                                                                               ;>>
    STi.m64      = STi:<<8 + m64                                                                               ;>>
    STi.m80      = STi:<<8 + m80                                                                               ;>>

↑ IiAbort MsgNr, cc=
  Macro IiAbort will cancel further instruction emitting by handler and returns to parent IiAssemble.
Input
  MsgNr is number of error message.
  cc= is optional condition code for conditional abort.
  EBX is pointer to STM.
Output
  -
Example
  IiAbort '6732' IiAbort cc=NZ,'7210'
Expanded in
  IiHandlers.
See also

    IiAbort %MACRO MsgNr, cc=
          %IF "%cc"<>""
    :      J%!cc .IiAbort%.:
          %ENDIF
          MOV EAX,%MsgNr
          JMP IiAbort@RT:
     .IiAbort%.:
    IiAbort@RT: PROC1
         Msg EAX
         RstSt [EBX+STM.Status],stmOperationPresent ; Invalidate the instruction, do not emit anything.
         RET ; Abandon the handler, return to IiAssemble.
        ENDPROC1 IiAbort@RT:
      %ENDMACRO IiAbort

↑ IiAbortIf64
  Macro IiAbortIf64 will abort the instruction handler if current segment width is 64 bits.
Input
  EDI= pointer to II (evaluated machine instruction).
Output
  -
On error
  Reports E6739 This instruction is not supported in 64bit mode.
Expanded in
  IiHandlers.
See also

    IiAbortIf64 %MACRO
           TESTD [EDI+II.SssStatus],sssWidth64
           IiAbort cc=NZ,'6739'
       %ENDMACRO IiAbortIf64

↑ IiAbortIfNot64
  Macro IiAbortIfNot64 will abort the instruction handler if current segment width is not 64 bits.
Input
  EDI= pointer to II (evaluated machine instruction).
Output
  -
On error
  Reports E6749 This instruction is supported in 64bit mode only.
Expanded in
  IiHandlers.
See also

    IiAbortIfNot64 %MACRO
           TESTD [EDI+II.SssStatus],sssWidth64
           IiAbort cc=Z,'6749'
       %ENDMACRO IiAbortIfNot64

↑ IiAbortIfNotST0
  Macro IiAbortIfNotST0 will abort the instruction handler if none of Operand1 and Operand2 is FP register ST0.
Input
  EDI= pointer to II (evaluated machine instruction).
Output
  CF=1, ZF=0 Operand1 is not ST0, Operand2 is ST0.
  CF=0, ZF=0 Operand1 is ST0, Operand2 is not ST0.
  CF=0, ZF=1 Both Operand1 and Operand2 are ST0.
On error
  E7602 At least one operand must be FP register ST0.
Expanded in
  IiHandlers.
See also

    IiAbortIfNotST0 %MACRO
           CALL IiAbortIfNotST0@RT:
    IiAbortIfNotST0@RT: PROC1
          PUSH EAX
           MOV AL,[EDI+II.Operand1+EXP.Low]
           MOV AH,[EDI+II.Operand2+EXP.Low]
           CMP AL,iiReg_FPR+0
           JE .10:
           CMP AH,iiReg_FPR+0
           JE .10:
           Msg '7602' ; At least one operand must be FP register ST0.
           ADD ESP,8 ; Discard pushed EAX and RET, return to abort parent Iif handler.
           RET
       .10:CMP AH,AL
          POP EAX
          RET
        ENDP1 IiAbortIfNotST0@RT:
     %ENDMACRO IiAbortIfNotST0

↑ IiAbortIfNot OperandNr, Register
  Macro IiAbortIfNot checks if OperandNr is provided with the particular Register.
Input
  OperandNr is one of enumerated identifiers `Operand1, Operand2, Operand3, Operand4`.
  Register is one of `CL, AX, CX, DX, EAX, ECX, EDX, RAX, RDX, ST0, ST1, XMM0`.
  EDI= pointer to II (evaluated operands).
Output
  -
On error
  E7610 Only register !2$ is expected as operand !1D.
Examples
  IiAbortIfNot Operand2, CL IiAbortIfNot Operand4, XMM0
Expanded in
  IiHandlers.
See also

    IiAbortIfNot %MACRO OperandNr, Register
           %IF "%OperandNr[1..7]" !== "Operand"
              %ERROR Id=5851,'Wrong argument %%1 provided for macro IiAbortIfNot in %^PROC'
              %EXITMACRO IiAbortIfNot
           %ENDIF
           %reg %SETA 0
           %IF "%Register" == "CL"
             %reg %SETA iiReg_R08+1
           %ENDIF
           %IF "%Register" == "AX"
             %reg %SETA iiReg_R16+0
           %ENDIF
           %IF "%Register" == "CX"
             %reg %SETA iiReg_R16+1
           %ENDIF
           %IF "%Register" == "DX"
             %reg %SETA iiReg_R16+2
           %ENDIF
           %IF "%Register" == "EAX"
             %reg %SETA iiReg_R32+0
           %ENDIF
           %IF "%Register" == "ECX"
             %reg %SETA iiReg_R32+1
           %ENDIF
           %IF "%Register" == "EDX"
             %reg %SETA iiReg_R32+2
           %ENDIF
           %IF "%Register" == "RAX"
             %reg %SETA iiReg_R64+0
           %ENDIF
           %IF "%Register" == "RDX"
             %reg %SETA iiReg_R64+2
           %ENDIF
           %IF "%Register" == "ST0"
             %reg %SETA iiReg_FPR+0
           %ENDIF
           %IF "%Register" == "ST1"
             %reg %SETA iiReg_FPR+1
           %ENDIF
           %IF "%Register" == "XMM0"
             %reg %SETA iiReg_XMM+0
           %ENDIF
           %IF %reg=0
             %ERROR Id=5852,'Unknown register %Register provided for macro IiAbortIfNot in %^PROC.'
             %EXITMACRO IiAbortIfNot
           %ENDIF
           CMPB [EDI+II.%OperandNr+EXP.Low+0],%reg
           Msg cc=NE,'7610',%OperandNr[8],=B'%Register' ; Only register !2$ is expected as operand !1D.
       %ENDMACRO IiAbortIfNot

↑ IiAbortIfNotCounter OperandNr
  Macro IiAbortIfNotCounter aborts the handler when the specified Operand is not counter register CX,ECX,RCX.
  Otherwise the handler continues below the macro.
Input
  OperandNr is one of enumerated values `Operand1,Operand2,Operand3,Operand4` with GPR register operand.
  EDI= pointer to II.
Output
  Assembly continues at specified label or below.
On error
  Handler aborted with E6756 Only register CX, ECX or RCX can be used as a counter.
Example
  IiAbortIfNotCounter Operand2
Expanded in
  IiHandlers.
See also

    IiAbortIfNotCounter %MACRO OperandNr
        PUSH EAX
          MOV EAX,[EDI+II.%OperandNr+EXP.Low]
          AND AL,iiReg_Ord16
          CMP AL,1 ; CL/CX/ECX/RCX.
        POP EAX
        IiAbort cc=NE,'6756'
      %ENDMACRO IiAbortIfNotCounter

↑ IiAllowModifier AllowedModifiers
  Macro IiAllowModifier specifies which modifiers are meaningfuly allowed in this instruction and sets their mask in [EDI+II.MfgAllowed] and/or [EDI+II.MfxAllowed].
  Not all instruction modifiers need to be explicitly allowed by this macro.
  Modifiers `ALIGN` and `NESTINGCHECK` need not be explicitly allowed.
  Modifiers `DISP` and `SCALE` are implicitly allowed if the handler expands macro IiModRM.
  Modifier `DATA` is implicitly allowed if the handler expands macro IiDataSize.
Input
  AllowedModifiers Each operand contains modifier name, which is one of enumerated values `ADDR`, `BCST`, `CODE`, `DATA`, `DISP`, `DIST`, `EH`, `IMM`, `MASK`, `OPER`, `PREFIX`, `ROUND`, `SAE`, `SCALE`, `ZEROING` (in upper case).
  EDI= pointer to II
Output
  -
Example
  IiAllowModifier DATA, DISP
Expanded in
  IiHandlers.

    IiAllowModifier  %MACRO
      %Mfg %SETA 0
      %Mfx %SETA 0
      Key  %FOR %*
            %IF TYPE#iiMfg%Key[]_Mask = 'N' ; Decide if %Key is defined as iiMfg or iiMfx.
             %Mfg %SETA %Mfg | iiMfg%Key[]_Mask
            %ELSE
             %Mfx %SETA %Mfx | iiMfx%Key[]_Mask
            %ENDIF
           %ENDFOR Key
           %IF %Mfg
             SetSt [EDI+II.MfgAllowed],%Mfg
           %ENDIF
           %IF %Mfx
             SetSt [EDI+II.MfxAllowed],%Mfx
           %ENDIF
       %ENDMACRO IiAllowModifier

↑ IiAllowLocking Operand1, Operand2,,,
  Macro IiAllowLocking specifies that instruction prefix `LOCK` is allowed if at least one of specified operands is [memory].
  In register-register operations the prefix will not be allowed.
Input
  Operand? is one or more enumerated identifiers `Operand1, Operand2, Operand3, Operand4`.
  EDI= pointer to II
Output
  `iiPfxLOCK` is set in [EDI+II.PfxAllowed].
Example
  IiAllowLocking Operand1, Operand2
Expanded in
  IiHandlers.
See also
  IiAllowPrefix.

    IiAllowLocking  %MACRO
        %IF %#
    OperandNr %FOR %*
          PUSHD [EDI+II.%OperandNr+EXP.Status]
          CALL IiAllowLocking@RT:
        %ENDFOR OperandNr
        %ELSE
          %ERROR Id=5853,"IiAllowLocking OpenrandNr missing in %^PROC."
        %ENDIF
    IiAllowLocking@RT: PROC1
       PUSH EAX
         MOV EAX,[ESP+8]
         Dispatch AL,'M','B','W','D','Q','U','T','O','Y','Z','I'
         JMP .90:
    .M:
    .B:
    .W:
    .D:
    .Q:
    .U:
    .T:
    .I:
    .O:
    .Y:
    .Z:
       SetSt [EDI+II.PfxAllowed],iiPfxLOCK
    .90:POP EAX
        RET 4
      ENDP1 IiAllowLocking@RT:
     %ENDMACRO IiAllowLocking

↑ IiAllowMaskMerging
  Macro IiAllowMaskMerging specifies that modifier `MASK=` is allowed in this instruction but modifier `ZEROING=` is not.
Input
  EDI= pointer to II
Output
  `iiMfxMASK_Mask` is set in [EDI+II.MfxAllowed].
  `iiPpxNoZEROING` is set in [EDI+II.Ppx].
Example
  IiAllowMaskMerging
Expanded in
  IiHandlers.
See also
  IiAllowModifier.

    IiAllowMaskMerging  %MACRO
       SetSt [EDI+II.MfxAllowed],iiMfxMASK_Mask
       RstSt [EDI+II.Ppx],iiPpxNoZEROING
     %ENDMACRO IiAllowMaskMerging

↑ IiAllowBroadcasting Datatype, Operand=DL
  Macro IiAllowBroadcasting specifies that modifier `BCST=` is allowed in this instruction when the last operand is in memory.
Input
  Datatype is one of enumerated values `DWORD QWORD` under `iiMfgDATA_Mask` which will be specified as emitted operand size in [EDI+II.MfgEmitted] when BCST=ON. Nothing is specified if omitted.
  Operand= is DL (the last operand) or DH (last but one) which is compared to mem.
  EDX has operand types as set by IiAssemble.
  EDI= pointer to II
Output
  `iiMfxBCST_Mask` set in [EDI+II.MfxAllowed].
Example
  IiAllowBroadcasting DWORD, Operand=DH
Expanded in
  IiHandlers.
See also

    IiAllowBroadcasting  %MACRO Datatype, Operand=DL
      CMP %Operand,mem ; Broadcasting is possible only if the operand is in memory.
      JNE iabc%.:
      ORD [EDI+II.MfxAllowed],iiMfxBCST_Mask
      %IF "%Datatype" !=== ""
        JNSt [EDI+II.MfxExplicit],iiMfxBCST_1,iabc%.:
        ORD [EDI+II.MfgEmitted],iiMfgDATA_%Datatype
      %ENDIF
    iabc%.:
     %ENDMACRO IiAllowBroadcasting

↑ IiAllowRounding Operand=DL, Register=zmm
  Macro IiAllowRounding specifies that modifier `ROUND=` is allowed in this instruction when the specified operand is SSE register.
  `iiMfxSAE_Mask` is allowed concurrently with `iiMfxROUND_Mask` because the use of static rounding implies SAE=ON, i.e. suppressing all exceptions (but not vice versa).
Input
  EDX has operand types as set by IiAssemble.
  Operand= is DL (the last operand) or DH (last but one) which is compared to Register.
  Register= is zmm, ymm or xmm.
  EDI= pointer to II
Output
  `iiMfxROUND_Mask` set in [EDI+II.MfxAllowed].
Example
  IiAllowRounding Operand=DH
Expanded in
  IiHandlers.
See also

    IiAllowRounding  %MACRO Operand=DL, Register=zmm
      CMP %Operand,%Register ; Static rounding is possible only in EVEX when the last operand is ZMM register.
      JNE iar%.:
      ORD [EDI+II.MfxAllowed],iiMfxROUND_Mask+iiMfxSAE_Mask
    iar%.:
     %ENDMACRO IiAllowRounding

↑ IiAllowNoSwizzle
  Macro IiAllowNoSwizzle applies on MVEX-encoded instructions and specifies that modifier `OPER=` can only have value 0 when EH=0 in register-register operation.
Input
  EDI= pointer to II
Output
  `iiPpxNoSwizzle` set in [EDI+II.Ppx].
Example
  IiAllowNoSwizzle
Expanded in
  IiHandlers.
See also

    IiAllowNoSwizzle  %MACRO
       SetSt [EDI+II.Ppx],iiPpxNoSwizzle
     %ENDMACRO IiAllowNoSwizzle

↑ IiAllowSuppressing Operand=DL, Register=zmm, Swizzle=Yes
  Macro IiAllowSuppressing specifies that modifier `SAE=` (suppress all exeptions) is allowed in this instruction when the specified operand is SSE register and sets iiMfxSAE_Mask in [EDI+II.MfxAllowed].
Input
  Operand= is DL (the last operand) or DH (last but one) which is compared to Register.
  Register= is zmm, ymm or xmm.
  Swizzle= is Yes or No (whether MVEX register swizzle is supported when EH=0).
  EDX has operand types as set by IiAssemble.
  EDI= pointer to II
Output
  `iiMfxSAE_Mask` set in [EDI+II.MfxAllowed].
Example
  IiAllowSuppressing Operand=DH, Register=xmm
Expanded in
  IiHandlers.
See also

    IiAllowSuppressing  %MACRO Operand=DL, Register=zmm, Swizzle=Yes
      CMP %Operand,%Register ; Exceptions suppressing is possible only in EVEX when the operand is SSE register.
      JNE ias%.:
      SetSt [EDI+II.MfxAllowed],iiMfxSAE_Mask
      %IF "%Swizzle[1]" !=== "Y"
        SetSt [EDI+II.Ppx],iiPpxNoSwizzle
      %ENDIF
    ias%.:
     %ENDMACRO IiAllowSuppressing

↑ IiAllowPrefix AllowedPrefixes
  Macro IiAllowPrefix specifies which explicit or implicit prefixes are allowed/expected in the instruction and sets them in `[EDI+II.PfxAllowed]` and/or `[EDI+II.MfxAllowed]`.
  Prefixes OTOGGLE, ATOGGLE, REX are automatically allowed in all instructions.
  Segment-override prefixes are automatically allowed in instructions with memory operand.
  Explicit prefix LOCK should be allowed in instructions `ADC*, ADD*, ADDPD, AND*, BTC, BTR, BTS, CMPXCHG, CMPXCHG8B, CMPXCHG16B, DEC*, INC*, NEG*, NOT*, OR*, SBB*, SUB*, XADD*, XCHG*, XOR*.` The LOCK prefix is only allowed if the FIRST operand is a MEMORY LOCATION. On registers this prefix is NOT allowed, see [LockBug], [PentiumBug].
  Explicit prefixes REP, REPE, REPZ, REPNE, REPNZ should be allowed in instructions `CMPS*, INS*, LODS*, MOVS*, OUTS*, SCAS*, STOS*`
  Prefixes SELDOM, OFTEN should be allowed in instructions `Jcc, LOOPcc`.
  Implicit AVX prefixes XOP, VEX, MVEX, EVEX must be allowed in handlers of AVX instructions before using IiAssembleAVX.
Input
  AllowedPrefixes as defined in prefix encoding under `iiPfxMask` (without `iiPfx`) or in AVX modifiers encoding (without `iiMfxPREFIX_`).
  EDI= pointer to II (evaluated operands).
Output
  Corresponding flags in `II.PfxAllowed` and/or `II.MfxAllowed` are set.
Examples
  IiAllowPrefix HintAny IiAllowPrefix AVX, EVEX
Expanded in
  IiHandlers.
See also

    IiAllowPrefix  %MACRO AllowedPrefixes
     %Pfx %SETA 0
     %Mfx %SETA 0
     %AVXprefixes %SET XOP,VEX,EVEX,MVEX
     prefix %FOR %*
       %pftype %SET iiPfx
       AVXprefix %FOR %AVXprefixes
         %IF "%prefix" == "%AVXprefix"
           %pftype %SET iiMfx
         %ENDIF
        %ENDFOR AVXprefix
        %IF "%pftype" == "iiMfx"
           %Mfx %SETA %Mfx | iiMfxPREFIX_%prefix
        %ELSE
           %Pfx %SETA %Pfx | iiPfx%prefix
        %ENDIF
       %ENDFOR prefix
       %IF %Pfx
         SetSt [EDI+II.PfxAllowed],%Pfx
       %ENDIF
       %IF %Mfx
         SetSt [EDI+II.MfxAllowed],%Mfx
       %ENDIF
     %ENDMACRO IiAllowPrefix

↑ IiAssumeEmpty OperandNr, DefaultValue
  Macro IiAssumeEmpty fills the operand in `[EDI+II]` identified as OperandNr with its assumed default value, if it was empty.
Input
  OperandNr is one of enumerated values `Operand1, Operand2, Operand3, Operand4`.
  DefaultValue specifies what will overwrite the empty operand. It may be one of enumerated tokens `1, 10, ST0, ST1, Operand1, Operand2, Operand3, Operand4`.
  EDI= pointer to II.
Output
  [EDI+II.OperandNr] is changed from empty to default. EDX is not changed.
Examples
  IiAssumeEmpty Operand2, 1 ; Change SHL EAX to SHL EAX,1. IiAssumeEmpty Operand2, Operand1 ; Change TEST EBX to TEST EBX,EBX.
Expanded in
  IiHandlers.
See also

    IiAssumeEmpty %MACRO OperandNr, DefaultValue
           %IF "%DefaultValue[1..7]" === "Operand"
              CMPB [EDI+II.%OperandNr+EXP.Status],0
              JNZ .%.: ; Skip if operand is not empty.
              PUSHD [EDI+II.%DefaultValue+EXP.Status]
              PUSHD [EDI+II.%DefaultValue+EXP.Seg]
              PUSHD [EDI+II.%DefaultValue+EXP.Low]
              PUSHD [EDI+II.%DefaultValue+EXP.High]
              PUSHD [EDI+II.%DefaultValue+EXP.Sym]
              POPD [EDI+II.%OperandNr+EXP.Sym]
              POPD [EDI+II.%OperandNr+EXP.High]
              POPD [EDI+II.%OperandNr+EXP.Low]
              POPD [EDI+II.%OperandNr+EXP.Seg]
              POPD [EDI+II.%OperandNr+EXP.Status]
            .%.:
              %EXITMACRO IiAssumeEmpty
            %ENDIF
            %IF "%DefaultValue"==="1" || "%DefaultValue"==="10"
              CMPB [EDI+II.%OperandNr+EXP.Status],0
              JNZ .%.: ; Skip if operand is not empty.
              MOVB [EDI+II.%OperandNr+EXP.Low],%DefaultValue
              MOVB [EDI+II.%OperandNr+EXP.Status],'N'
            .%.:
              %EXITMACRO IiAssumeEmpty
            %ENDIF
            %IF "%DefaultValue[1..2]"==="ST"
              CMPB [EDI+II.%OperandNr+EXP.Status],0
              JNZ .%.: ; Skip if operand is not empty.
              MOVB [EDI+II.%OperandNr+EXP.Low],iiReg_FPR+%DefaultValue[3]
              MOVB [EDI+II.%OperandNr+EXP.Status],'R'
            .%.:
              %EXITMACRO IiAssumeEmpty
            %ENDIF
            %ERROR Id=5854,'Unexpected argument "%DefaultValue" provided for macro IiAssumeEmpty in %^PROC.'
         %ENDMACRO IiAssumeEmpty

↑ IiSwap OperandANr, OperandBNr
  Macro IiSwap will exchange contents of two operands in `[EDI+II]`. It does not swap their types in EDX.
Input
  OperandANr, OperandBNr are enumerated values `Operand1, Operand2, Operand3, Operand4`.
  EDI= pointer to II.
Output
  Operands are swapped.
Examples
  IiSwap Operand1, Operand2
Expanded in
  IiHandlers.
See also

    IiSwap %MACRO OperandANr, OperandBNr
      Nr  %FOR 1,2,3,4
           %IF "%OperandANr"=="Operand%Nr"
             PUSHD [EDI+II.Operand%Nr+EXP.Sym]
             PUSHD [EDI+II.Operand%Nr+EXP.High]
             PUSHD [EDI+II.Operand%Nr+EXP.Low]
             PUSHD [EDI+II.Operand%Nr+EXP.Seg]
             PUSHD [EDI+II.Operand%Nr+EXP.Status]
           %ENDIF
          %ENDFOR Nr
      Nr  %FOR 1,2,3,4
           %IF "%OperandBNr"=="Operand%Nr"
             PUSHD [EDI+II.Operand%Nr+EXP.Sym]
             PUSHD [EDI+II.Operand%Nr+EXP.High]
             PUSHD [EDI+II.Operand%Nr+EXP.Low]
             PUSHD [EDI+II.Operand%Nr+EXP.Seg]
             PUSHD [EDI+II.Operand%Nr+EXP.Status]
           %ENDIF
          %ENDFOR Nr
      Nr  %FOR 1,2,3,4
           %IF "%OperandANr"=="Operand%Nr"
             POPD [EDI+II.Operand%Nr+EXP.Status]
             POPD [EDI+II.Operand%Nr+EXP.Seg]
             POPD [EDI+II.Operand%Nr+EXP.Low]
             POPD [EDI+II.Operand%Nr+EXP.High]
             POPD [EDI+II.Operand%Nr+EXP.Sym]
           %ENDIF
          %ENDFOR Nr
      Nr  %FOR 1,2,3,4
           %IF "%OperandBNr"=="Operand%Nr"
             POPD [EDI+II.Operand%Nr+EXP.Status]
             POPD [EDI+II.Operand%Nr+EXP.Seg]
             POPD [EDI+II.Operand%Nr+EXP.Low]
             POPD [EDI+II.Operand%Nr+EXP.High]
             POPD [EDI+II.Operand%Nr+EXP.Sym]
           %ENDIF
          %ENDFOR Nr
      %ENDMACRO IiSwap

↑ IiVSIB Indices
  Macro IiVSIB specifies that memory operand is addressed by SSE vector register XMM, YMM or ZMM used as indexregister.
Input
  Indices is empty or one of enumerated values vm32x, vm64x, vm32y, vm64y, vm32z, vm64z.
  EDI= pointer to II.
Output
  Required indexregister is marked in `[EDI+II.Ppg]:iiPpgVSIBind`.
Examples
  IiVSIB vm64z
Expanded in
  IiHandlers of gather/scatter instructions.

    IiVSIB %MACRO Indices
         RstSt [EDI+II.Ppg],iiPpgVSIBind
         %IF "%Indices" !=== ""
           %VSIBind %SETA 0
           %IF "%Indices" == "vm32x" || "%Indices" == "vm64x"
              %VSIBind %SETA iiPpgVSIB1
           %ENDIF
           %IF "%Indices" == "vm32y" || "%Indices" == "vm64y"
              %VSIBind %SETA iiPpgVSIB2
           %ENDIF
           %IF "%Indices" == "vm32z" || "%Indices" == "vm64z"
              %VSIBind %SETA iiPpgVSIB1 | iiPpgVSIB2
           %ENDIF
           %IF %VSIBind
             SetSt [EDI+II.Ppg],%VSIBind
           %ELSE
             %ERROR Id=5855,"Invalid IiVSIB indice '%Indices' in %^PROC."
           %ENDIF
         %ENDIF
      %ENDMACRO IiVSIB

↑ IiDispatchFormat Format1, Format2,,,
  Macro IiDispatchFormat checks EDX and forks the assembly to the corresponding format labels.
  If EDX does not equal to any of instruction formats specified as macro operands, error E7511 is reported, the current handler is aborted and macro returns to handler's caller. This may happen when the programmer has provided the instruction with operand combination unsupported by CPU.
Input
  EDX=operand format in Intel encoding.
  EBX=pointer to the statement.
Output
  Assembly continues at the local label created from operand name prefixed with `.` (fullstop). Each macro operand requires that the corresponding local label be defined in handler procedure.
On error
  E7511 Wrong operand combination !1S. is reported if EDX could not be dispatched. Handler is aborted and it returns to the caller (IiAssemble).
Example
  IiDispatchFormat r08.imm, r16.imm, r32.imm .r08.imm: Emit ... RET .r16.imm: Emit ... RET .r32.imm: Emit ... RET
Expanded in
  IiHandlers.
See also
  IiDispatchWidth.

    IiDispatchFormat %MACRO
    format  %FOR %*
          CMP EDX,%format
          JE .%format:
         %ENDFOR format
         JMP IiDispatchFormatFail@RT:       ; JMP instead of CALL will abort the parent PROC when no format matched EDX.
    IiDispatchFormatFail@RT:  PROC1         ; Prepare and report E7511 Wrong operand combination !1S.
     ; Input: EDX=format in Intel encoding.  If ZF=1, display D1911 instead of E7511.
     ;        EBX=^STM.
        PUSHFD                             ; Save ZF.
         RstSt [EBX+STM.Status],stmOperationPresent            ; Invalidate the instruction.
         Invoke EaBufferReserve::,IiDispatchFormatFail@RT      ; Buffer for message parameter !1S.
         MOV EBX,EAX
         MOV EDI,4
         SUB ECX,ECX
    %IiEnc2 %SET m8,r8                               ; Operand names which have 2 characters.
    %IiEnc3 %SET m16,m32,m64,m80,mem,r16,r32,r64,ctr,ct8,krg,bnd,dgr,tsr,STi,mmx,xmm,ymm,zmm,far,imm
    %IiEnc4 %SET m128,m256,m512,Sreg,imm8,none
    %IiEnc5 %SET imm16,imm32,imm64                   ; Operand names which have 5 characters.
          BSWAP EDX
          SUB EBP,EBP                                ; Marker if other than "none" was already stored.
     .10: CMP EDI,1                                  ; The last time report "none" anyway.
          JNE .15:
          INC EBP
     .15: CMP DL,none
          JNE .20:
          TEST EBP
          JZ .85:                                    ; Silently ignore leading empty operands.
     .20: INC EBP
          MOV CL,2+1
          CMP DL,r8:
          JE .r8:
          CMP DL,m8
          JE .m8:
          JMP .30:
    .r8:  MOV ESI,=B"r8,"
          JMP .80:
    .m8:  MOV ESI,=B"m8,"
          JMP .80:
     .30: MOV CL,3+1
          Dispatch DL,%IiEnc3
          JMP .40:
    enc  %FOR %IiEnc3
    .%enc:  MOV ESI,=B"%enc[],"
            JMP .80:
          %ENDFOR enc
     .40: MOV CL,4+1
          Dispatch DL,%IiEnc4
          JMP .50:
    enc  %FOR %IiEnc4
    .%enc:  MOV ESI,=B"%enc[],"
            JMP .80:
          %ENDFOR enc
     .50: MOV CL,5+1
          Dispatch DL,%IiEnc5
          MOV ESI,=B"unknown,"
          MOV CL,8
          JMP .80:
    enc  %FOR %IiEnc5
    .%enc:  MOV ESI,=B"%enc[],"
            JMP .80:
          %ENDFOR enc
     .80:BufferStore EBX,ESI,ECX
     .85:ROR EDX,8                                   ; Switch to the next operand, if any,
         DEC EDI                                     ;  but not more than four times.
         JNZ .10:
         BufferRetrieve EBX
         Invoke EaBufferRelease::,EBX
         JECXZ .n9:
         DEC ECX                                     ; Omit the last comma.
     .n9:POPFD                                       ; Restore input ZF.
         PUSH ECX,ESI
           MOV EBX,ESP                               ; Prepare Msg parameter !1S.
           Msg cc=NZ,PgmStatus=pgmLastPass,'7511',EBX;  Wrong operand combination !1S.
           Msg cc=Z,'1911',EBX                       ; Dispatching operand combination !1S.
         POP ESI,ECX
         RET
       ENDPROC1 IiDispatchFormatFail@RT:
     %ENDMACRO IiDispatchFormat

↑ IiDispatchSingleShift Target
  Macro IiDispatchSingleShiftDQ will distinguish between single logical shift and double logical shift instructions by their operands, and jump to %Target if single.
Input
  Target label where single shift is handled.
  EDI= pointer to II.
Output
  Assembly continues at one specified label or below.
On error
  -
Example
  IiDispatchSingleShift .Single:
Expanded in
  IigSHLD, IigSHRD.
See also

    IiDispatchSingleShift %MACRO Target
       CMPB [EDI+II.Operand2+EXP.Status],'R' ; Is Operand2 a register?
       JNE %Target
       CMPB [EDI+II.Operand2+EXP.Low],iiReg_R08+1 ; Is Operand2 register CL?
       JE %Target
      %ENDMACRO IiDispatchSingleShift

↑ IiDispatchSuffix D=, Q=
  Macro IiDispatchSuffix tests if mnemonic suffix is used and forks to the corresponding target label, if nonempty.
Input
  D=,Q= target label when the suffix is used in mnemonic.
  EDI= pointer to II.
Output
  Assembly continues at one specified label or below.
On error
  -
Example
  IiDispatchSuffix Q=.mmx.mmx.Q:
Expanded in
  IiHandlers.
See also
  IiDispatchFormat.

    IiDispatchSuffix %MACRO D=, Q=
    suffix %FOR D,Q
         %label %SET2 %%%suffix
         %IF "%label" !=== ""
           JSt [EDI+II.MfgSuffix],iiMfgDATA_%suffix[]WORD, %label
         %ENDIF
        %ENDFOR suffix
      %ENDMACRO IiDispatchSuffix

↑ IiDispatchNotAccum OperandNr, Target
  Macro IiDispatchNotAccum jumps to Target when the specified Operand is not accumulator register AL,AX,EAX,RAX.
  Otherwise the handler continues below the macro.
Input
  OperandNr is one of enumerated values `Operand1,Operand2,Operand3,Operand4`.
  Target is a label in handler where to jump when OperandNr is not an accumulator register.
  EDI= pointer to II.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchNotAccum Operand1, .r16.imm16:
Expanded in
  IiHandlers.
See also

    IiDispatchNotAccum %MACRO OperandNr, Target
        TESTB [EDI+II.%OperandNr+EXP.Low],iiReg_Ord16
        JNZ %Target
      %ENDMACRO IiDispatchNotAccum

↑ IiDispatchCPU CPU_386=, CPU_686=, CPU_X64=
  Macro IiDispatchCPU tests current EUROASM option CPU= and jumps to the corresponding target, if specified as macro keyword operand.
  Otherwise the handler continues below the macro.
Input
  CPU_386= is target when CPU level is at least CPU=386.
  CPU_686= is target when CPU level is at least CPU=686.
  CPU_X64= is target when CPU level is at least CPU=X64.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchCPU CPU_386=.32:, CPU_X64= .64:
Expanded in
  IiHandlers.
See also

    IiDispatchCPU %MACRO CPU_386=, CPU_686=, CPU_X64=
       %IF "%CPU_386" !=== ""
         JSt [Ea.Eaopt.Machine::],iiCPU_386, %CPU_386
       %ENDIF
       %IF "%CPU_686" !=== ""
         JSt [Ea.Eaopt.Machine::],iiCPU_686, %CPU_686
       %ENDIF
       %IF "%CPU_X64" !=== ""
         JSt [Ea.Eaopt.Machine::],iiCPU_X64, %CPU_X64
       %ENDIF
       %IF %# >0
         %ERROR Id=5856,"Unexpected IiDispatchCPU argument %1 in %^PROC."
       %ENDIF
      %ENDMACRO IiDispatchCPU

↑ IiDispatchLocation TargetSection, RIP=, NEAR=, FAR=
  Macro IiDispatchLocation decides which distance should be the transfer instruction encoded for, and jumps to the coresponding label if it is specified. Otherwise the handler continues below the macro.
  It is expanded in control-transfer instructions when the distance is not explicitly specified.
Input
  TargetSection is pointer to SSS section of the target of assembled control-transfer instruction. When it is identical with the current section of the instruction (intrasection JMP|CALL), the distance will be RIP, i.e. resolvable at assembly time.
  TargetSection may be 0, for instance in instruction `JMP 0x400` , or it may be sssExtern when the target is EXTERN, for instance in instruction `JMP ExternTarget:` . In this case the returned distance depends on program model:
  In multicode models (MEDIUM|LARGE|HUGE) it is assumed that the target is in a different segment and the distance will be FAR, assembled as `JMPF ExternTarget:` with relocFar relocation.
  In monocode models (FLAT|TINY|SMALL|COMPACT) it is assumed that the ExternTarget is available with current CS value and thus it will be assembled as `JMPN ExternTarget:` with relocRel relocation.
  RIP= label where to continue when the JMP|CALL target is in the same section. Target is near or short, relocatable at assembly time, no RELOC record will be used.
  NEAR= label where to continue when the JMP|CALL target is in the same group|segment. Target is near, relocatable at link time, relocRel will be used.
  FAR= label where to continue when the target is in different segment|group and CS needs to be changed, too. Target is far, either scalar (no RELOC record will be used) or it is an address symbol and relocFar will be used then.
  EDI= pointer to II.
  EBX= pointer to STM with assembled instruction.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchLocation [EDI+II.Operand1.Seg], FAR= .far:
Expanded in
  IiHandlers of control-transfer instructions.
See also
  IiDispatchDist

    IiDispatchLocation %MACRO TargetSection, RIP=, NEAR=, FAR=
       PUSH %TargetSection
       CALL IiDispatchLocation@RT: ; Returns CF=1 if FAR, CF=0,ZF=1 if RIP, CF=0,ZF=0 if NEAR.
       %IF "%FAR" !=== ""
         JC %FAR
       %ENDIF
       %IF "%RIP" !=== ""
         JE %RIP
       %ENDIF
       %IF "%NEAR" !=== ""
         JA %NEAR
       %ENDIF
    IiDispatchLocation@RT: PROC1
        PUSHAD
          MOV ECX,[ESP+9*4]                   ; ECX=section of the target.
          MOV EDX,[EBX+STM.Section]           ; EDX=section of the current instruction. It never should be 0.
          TEST EDX
          JZ .RIP:                            ; Something wrong happened.
          CMP ECX,EDX
          JE .RIP:                            ; Return with CF=0, ZF=1. RIP intrasection near or short transfer, resolvable at assembly time.
          MOV EAX,EDX                         ; Set EAX>0.
          ; Distance will be NEAR if both sections belong to the same segment|group. Otherwise it depends on the memory model.
          JECXZ .Model:
          MOV ECX,[ECX+SSS.SegmPtr]
          TEST EDX
          JZ .RIP:
          MOV EDX,[EDX+SSS.SegmPtr]
          CMP ECX,EDX
          JE .NEAR:                           ; Return with CF=0, ZF=0. NEAR intrasegment near transfer, resolvable at link time.
          MOV ECX,[ECX+SSS.GroupPtr]
          JECXZ .Model:
          TEST EDX
          JZ .Model:
          MOV EDX,[EDX+SSS.GroupPtr]
          CMP ECX,EDX
          JE .NEAR:
    .Model: ; Returned distance depends on program memory model.
          JSt [EDI+II.PgmoptStatus],pgmoptMEDIUM|pgmoptLARGE|pgmoptHUGE, .FAR: ; If the memory model has many code segments.
    .NEAR:CMP EAX,0                           ; Set CF=0, ZF=0, NEAR intrasegment transfer resolvable at link time, relocRel will be required.
          JMP .RIP:
    .FAR: CMP EDX,-1                          ; Set CF=1, ZF=0, FAR transfer, relocFar will be required.
    .RIP:POPAD
        RET 4
       ENDP1 IiDispatchLocation@RT:
      %ENDMACRO IiDispatchLocation

↑ IiDispatchCode SHORT=, LONG=
  Macro IiDispatchCode tests explicit instruction modifier CODE= and jumps to the coresponding label if it is specified.
  Otherwise the handler continues below the macro.
Input
  SHORT= is target when CODE=SHORT was specified in instruction.
  LONG= is target when CODE=LONG was specified in instruction.
  EDI= pointer to II.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchCode LONG= .L:
Expanded in
  IiHandlers.
See also

    IiDispatchCode %MACRO SHORT=, LONG=
       %IF "%SHORT" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgCODE_SHORT, %SHORT
       %ENDIF
       %IF "%LONG" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgCODE_LONG, %LONG
       %ENDIF
       %IF %# >0
         %ERROR Id=5857,"Unexpected IiDispatchCode argument %1 in %^PROC."
       %ENDIF
       %IF %# >0
         %ERROR Id=5858,"Unexpected IiDispatchCode argument %1 in %^PROC."
       %ENDIF
      %ENDMACRO IiDispatchCode

↑ IiDispatchData BYTE=, WORD=, DWORD=, QWORD=
  Macro IiDispatchData tests operand-size specifiers
  1. [EDI+II.MfgEmitted]
  2. [EDI+II.MfgSuffix]
  3. [EDI+II.MfgExplicit]
  and jumps to the coresponding label if it is specified.
  Otherwise the handler continues below the macro.
Input
  BYTE=,WORD=,DWORD=,QWORD= is target when mnemonic suffix or explicit DATA= modifier is used.
  EDI= pointer to II.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchData WORD=.immW:
Expanded in
  IiHandlers.
See also

    IiDispatchData %MACRO BYTE=,WORD=,DWORD=,QWORD=
       %IF "%BYTE" !=== ""
         JSt  [EDI+II.MfgEmitted],iiMfgDATA_BYTE, %BYTE
         JSt   [EDI+II.MfgSuffix],iiMfgDATA_BYTE, %BYTE
       %ENDIF
       %IF "%WORD" !=== ""
         JSt  [EDI+II.MfgEmitted],iiMfgDATA_WORD, %WORD
         JSt   [EDI+II.MfgSuffix],iiMfgDATA_WORD, %WORD
       %ENDIF
       %IF "%DWORD" !=== ""
         JSt  [EDI+II.MfgEmitted],iiMfgDATA_DWORD, %DWORD
         JSt   [EDI+II.MfgSuffix],iiMfgDATA_DWORD, %DWORD
       %ENDIF
       %IF "%QWORD" !=== ""
         JSt  [EDI+II.MfgEmitted],iiMfgDATA_QWORD, %QWORD
         JSt   [EDI+II.MfgSuffix],iiMfgDATA_QWORD, %QWORD
       %ENDIF
       %IF "%BYTE" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDATA_BYTE, %BYTE
       %ENDIF
       %IF "%WORD" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDATA_WORD, %WORD
       %ENDIF
       %IF "%DWORD" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDATA_DWORD, %DWORD
       %ENDIF
       %IF "%QWORD" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDATA_QWORD, %QWORD
       %ENDIF
       %IF %# >0
         %ERROR Id=5859,"Unexpected IiDispatchData argument %1 in %^PROC."
       %ENDIF
      %ENDMACRO IiDispatchData

↑ IiDispatchDisp BYTE=, WORD=, DWORD=, QWORD=
  Macro IiDispatchDisp tests explicit instruction modifier DISP= and jumps to the coresponding label if it is specified.
  Otherwise the handler continues below the macro.
Input
  BYTE= is target when DISP=BYTE was specified in instruction.
  WORD= is target when DISP=WORD was specified in instruction.
  DWORD= is target when DISP=DWORD was specified in instruction.
  QWORD= is target when DISP=QWORD was specified in instruction.
  EDI= pointer to II.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchDisp DWORD= .L:
Expanded in
  IiHandlers.
See also
  IiDispatchImm.

    IiDispatchDisp %MACRO BYTE=,WORD=,DWORD=,QWORD=
       %IF "%BYTE" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDISP_BYTE, %BYTE
       %ENDIF
       %IF "%WORD" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDISP_WORD, %WORD
       %ENDIF
       %IF "%DWORD" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDISP_DWORD, %DWORD
       %ENDIF
       %IF "%QWORD" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDISP_QWORD, %QWORD
       %ENDIF
       %IF %# >0
         %ERROR Id=5860,"Unexpected IiDispatchDisp argument %1 in %^PROC."
       %ENDIF
      %ENDMACRO IiDispatchDisp

↑ IiDispatchDist SHORT=, NEAR=, FAR=
  Macro IiDispatchDist tests mnemonic suffix ~S, ~N, ~F and explicit instruction modifier DIST= and jumps to the coresponding label if it is specified.
  Otherwise the handler continues below the macro.
Input
  SHORT= NEAR= FAR= is target when suffix or DIST= modifier was specified in instruction.
  EDI= pointer to II.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchDist FAR= .far:
Expanded in
  IiHandlers.
See also

    IiDispatchDist %MACRO SHORT=,NEAR=,FAR=
       %IF "%SHORT" !=== ""
         JSt [EDI+II.MfgSuffix],iiMfgDIST_SHORT, %SHORT
       %ENDIF
       %IF "%NEAR" !=== ""
         JSt [EDI+II.MfgSuffix],iiMfgDIST_NEAR, %NEAR
       %ENDIF
       %IF "%FAR" !=== ""
         JSt [EDI+II.MfgSuffix],iiMfgDIST_FAR, %FAR
       %ENDIF
       %IF "%SHORT" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDIST_SHORT, %SHORT
       %ENDIF
       %IF "%NEAR" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDIST_NEAR, %NEAR
       %ENDIF
       %IF "%FAR" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDIST_FAR, %FAR
       %ENDIF
       %IF %# >0
         %ERROR Id=5861,"Unexpected IiDispatchDist argument %1 in %^PROC."
       %ENDIF
      %ENDMACRO IiDispatchDist

↑ IiDispatchImm BYTE=, WORD=, DWORD=, QWORD=
  Macro IiDispatchImm tests explicit instruction modifier IMM= and jumps to the coresponding label if it is specified.
  Otherwise the handler continues below the macro.
Input
  BYTE= is target when IMM=BYTE was specified in instruction.
  WORD= is target when IMM=WORD was specified in instruction.
  DWORD= is target when IMM=DWORD was specified in instruction.
  QWORD= is target when IMM=QWORD was specified in instruction.
  EDI= pointer to II.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchImm DWORD= .L:
Expanded in
  IiHandlers.
See also
  IiDispatchCode.

    IiDispatchImm %MACRO BYTE=,WORD=,DWORD=,QWORD=
       %IF "%BYTE" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgIMM_BYTE, %BYTE
       %ENDIF
       %IF "%WORD" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgIMM_WORD, %WORD
       %ENDIF
       %IF "%DWORD" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgIMM_DWORD, %DWORD
       %ENDIF
       %IF "%QWORD" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgIMM_QWORD, %QWORD
       %ENDIF
       %IF %# >0
         %ERROR Id=5862,"Unexpected IiDispatchImm argument %1 in %^PROC."
       %ENDIF
      %ENDMACRO IiDispatchImm

↑ IiDispatchImmSize BYTE=, WORD=, DWORD=, QWORD=
  Macro IiDispatchImmSize tests immediate operand property (number magnitude) which was specified in `[EDI+II.MfgImplicit]` by previous invocation of macro IiImmSize and jumps to the coresponding label if it is specified.
  Otherwise the handler continues below the macro.
Input
  BYTE= is target when immediate operand fits to a byte.
  WORD= is target when immediate operand fits to a word
  DWORD= is target when immediate operand fits to a dword
  QWORD= is target when immediate operand fits to a qword
  EDI= pointer to II.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchImmSize BYTE=.reg.imm8
Expanded in
  IiHandlers.
See also
  IiDispatchCode.

    IiDispatchImmSize %MACRO BYTE=,WORD=,DWORD=,QWORD=
       %IF "%BYTE" !=== ""
         JSt [EDI+II.MfgImplicit],iiMfgIMM_BYTE, %BYTE
       %ENDIF
       %IF "%WORD" !=== ""
         JSt [EDI+II.MfgImplicit],iiMfgIMM_WORD, %WORD
       %ENDIF
       %IF "%DWORD" !=== ""
         JSt [EDI+II.MfgImplicit],iiMfgIMM_DWORD, %DWORD
       %ENDIF
       %IF "%QWORD" !=== ""
         JSt [EDI+II.MfgImplicit],iiMfgIMM_QWORD, %QWORD
       %ENDIF
       %IF %# >0
         %ERROR Id=5863,"Unexpected IiDispatchImmSize argument %1 in %^PROC."
       %ENDIF
      %ENDMACRO IiDispatchImmSize

↑ IiDispatchDataSize DWORD=, QWORD=, OWORD=, YWORD=
  Macro IiDispatchDataSize tests if explicit or implicit modifier is set in `[EDI+II.MfgExplicit]` or `[EDI+II.MfgImplicit]` and jumps to the corresponding label if it is specified. Otherwise the handler continues below the macro.
Input
  DWORD=, QWORD=, OWORD, YWORD= are labels where to jump to.
  EDI= pointer to II.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchDataSize OWORD=.xmm.mem, YWORD=.ymm.mem:
Expanded in
  IiHandlers.
See also

    IiDispatchDataSize %MACRO DWORD=, QWORD=, OWORD=, YWORD=
     size %FOR DWORD,QWORD,OWORD,YWORD
       %label %SET2 %%%size
       %IF "%label" !=== ""
         JSt [EDI+II.MfgExplicit],iiMfgDATA_%size, %label
       %ENDIF
      %ENDFOR size
     size %FOR DWORD,QWORD,OWORD,YWORD
       %label %SET2 %%%size
       %IF "%label" !=== ""
         JSt [EDI+II.MfgImplicit],iiMfgDATA_%size, %label
       %ENDIF
      %ENDFOR size
     %ENDMACRO IiDispatchDataSize

↑ IiDispatchPrefix VEX=, VEX2=, VEX3=, XOP=, MVEX=, EVEX=
  Macro IiDispatchPrefix tests if an AVX-prefix modifier is set in `[EDI+II.MfxExplicit]`, i.e. if the instruction has explicitly set keyword `PREFIX=` , and jumps to the corresponding label if it is specified. Otherwise the handler continues below the macro.
Input
  VEX=, VEX2=, VEX3=, XOP=, MVEX=, EVEX= are labels where to jump to.
  EDI= pointer to II.
Output
  Assembly continues at specified label or below.
On error
  -
Example
  IiDispatchPrefix VEX=.vex:
Expanded in
  IiHandlers.
See also

    IiDispatchPrefix %MACRO VEX=, VEX2=, VEX3=, XOP=, MVEX=, EVEX=
       %IF "%VEX" !=== ""
         JSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX, %VEX
       %ENDIF
       %IF "%VEX2" !=== ""
         JSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX2, %VEX2
       %ENDIF
       %IF "%VEX3" !=== ""
         JSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX3, %VEX3
       %ENDIF
       %IF "%XOP" !=== ""
         JSt [EDI+II.MfxExplicit],iiMfxPREFIX_XOP, %XOP
       %ENDIF
       %IF "%MVEX" !=== ""
         JSt [EDI+II.MfxExplicit],iiMfxPREFIX_MVEX, %MVEX
       %ENDIF
       %IF "%EVEX" !=== ""
         JSt [EDI+II.MfxExplicit],iiMfxPREFIX_EVEX, %EVEX
       %ENDIF
     %ENDMACRO IiDispatchPrefix

↑ IiDispatchWidth BITS16=, BITS32=, BITS64=
  Macro IiDispatchWidth inspects the width of current segment, as specified in `[EDI+II.SssStatus]` and jumps to the label set in the corresponding keyword, if it is set.
Input
  BITS16=, BITS32=, BITS64= are labels where to jump to.
  EDI= pointer to II.
Output
  Assembly continues at one of the labels or below the macro.
On error
  -
Example
  IiDispatchWidth BITS32=.r32
Expanded in
  IiHandlers.
See also
  IiDispatchFormat.

    IiDispatchWidth %MACRO BITS16=, BITS32=, BITS64=
      width %FOR BITS32,BITS64,BITS16
        %label %SET2 %%%width
        %IF "%label" !=== ""
          JSt [EDI+II.SssStatus],sssWidth%width[5..6], %label
        %ENDIF
       %ENDFOR width
       %IF %# >0
         %ERROR Id=5864,"Unexpected IiDispatchWidth argument %1 in %^PROC."
       %ENDIF
      %ENDMACRO IiDispatchWidth

↑ IiDispSize OperandNr
  Macro IiDispSize is expanded instead of IiModRM in IigMOV when operand could be `moffs`, i.e. one operands is accumulator register and the other is in memory addressed by offset only (no base, no index).
  It copies displacement value of specified memory operand to `II.Displacement`. and relocation segment to `II.DispRelocSeg`. Explicit instruction modifier DISP= is taken into account here, if possible.
  If the macro decides that longcode encoding with ModR/M should be used, it sets carry flag and does not modify II.MfgEmitted. Handler should invoke IiModRM then.
  Otherwise one of `II.MfgEmitted:iiMfgDISP_Mask` flags is set and request for absolute relocation `II.Reloc:iiRelocDispAbs` is set.
Input
  OperandNr is one of enumerated values `Operand1, Operand2, which contains [mem].`.
  EDI= pointer to II.
Output
  CF=0 One flag in `[EDI+II.MfgEmitted]:iiMfgDISP_Mask]` is set. Use short opcode.
  CF=1 II.MfgEmitted is not modified, use IiModRM to specify encoding.
Error
  -
Example
  IiDispSize Operand2
Expanded in
  IigMOV.
See also
  IiImmSize, IiModRM.

    IiDispSize %MACRO OperandNr
           %IF "%OperandNr[1..7]" !== "Operand"
              %ERROR Id=5865,'Wrong argument provided for macro IiDispSize.'
              %EXITMACRO IiDispSize
           %ENDIF
           PUSHD %OperandNr[8] * SIZE#EXP
           CALL IiDispSize@RT:
    IiDispSize@RT: PROC1
         PUSH EAX,ECX,EDX,ESI
            MOV EDX,[ESP+20]                         ; OperandNr offset in II: 20,40,60,80.
            LEA ESI,[EDI+II.Operand1-SIZE#EXP+EDX]   ; ^EXP with evalueted [mem] expression.
            MOV EAX,[ESI+EXP.Low]
            MOV EDX,[ESI+EXP.High]
            MOV ECX,[ESI+EXP.Seg]
            MOV [EDI+II.DispLow],EAX
            MOV [EDI+II.DispHigh],EDX
            MOV [EDI+II.DispRelocSeg],ECX
            MOV EAX,[ESI+EXP.Status]
            JSt EAX,expBasePres|expIndexPres, .CodeLong:
            AND EAX,expDwidth                        ; AH=0,3,4,5,6,7 = none,0,8,16,32,64 bits.
            IiDispatchWidth BITS32=.W.32:, BITS64=.W.64:
            JSt [EDI+II.MfgExplicit],iiMfgCODE_LONG|iiMfgSCALE_VERBATIM, .CodeLong:
            TEST ECX
            JNZ .Reloc16:                            ; Jump if [mem] is not scalar.
            JSt [EDI+II.MfgExplicit],iiMfgDISP_DWORD,.NorelA32:
            CMP AH,5
            JA .NorelA32:                            ; If disp32 in 16bit segment and scalar exceeds 16 bits.
            JMP .Norel16:
    .W.32:  JSt [EDI+II.MfgExplicit],iiMfgCODE_LONG|iiMfgSCALE_VERBATIM, .CodeLong:
            TEST ECX
            JNZ .Reloc32:
            JNSt [EDI+II.MfgExplicit],iiMfgDISP_WORD,.Norel32:
            ; No reason was found to use short encoding A0..A3 which is longer than ModR/M with DISP=(D)WORD.
            CMP AH,5
            JA .Norel32:
            JMP .NorelA16:
    .W.64:  TEST EDX                                 ; Check high DWORD of displacement. Disp32 is zero-extended by 32bit addressing mode in 64bit mode.
            JNZ .Disp64:                             ; MOV EAX,[-1]  in 64bit mode requires DISP=QWORD, A1FFFFFFFFFFFFFFFF.
            JSt [EDI+II.MfgExplicit],iiMfgDISP_QWORD, .Disp64: ; If explicitly requested 64bit displacement.
            JSt [EDI+II.MfgExplicit],iiMfgCODE_LONG|iiMfgSCALE_VERBATIM, .CodeLong:
            TEST ECX
            JNZ .RelocA32:
    .NorelA32:SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE
    .Norel32:SetSt [EDI+II.MfgEmitted],iiMfgDISP_DWORD
             JMP .Norel:
    .Reloc16:SetSt [EDI+II.MfgEmitted],iiMfgDISP_WORD
             JMP .Reloc
    .RelocA32:SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE
    .Reloc32:SetSt [EDI+II.MfgEmitted],iiMfgDISP_DWORD
    .Reloc:  SetSt [EDI+II.Reloc],iiRelocDispAbs
             MOV ECX,[EDI+II.DispRelocSeg]
             JECXZ .Norel:
             MOV EAX,[ECX+SSS.SymPtr]
             MOV [EDI+II.DispRelocSym],EAX
             JMP .Norel:
    .NorelA16:SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE
    .Norel16:SetSt [EDI+II.MfgEmitted],iiMfgDISP_WORD
             JMP .Norel:
    .CodeLong:STC ; Abort short encoding, use ModR/M.
             JMP .End:
    .Disp64:SetSt [EDI+II.MfgEmitted],iiMfgDISP_QWORD
            TEST ECX
            JNZ .Reloc:
    .Norel: SetSt [EDI+II.MfgEmitted],iiMfgADDR_ABS
    .End:  POP ESI,EDX,ECX,EAX
           RET 4
        ENDPROC1 IiDispSize@RT:
     %ENDMACRO IiDispSize

↑ IiDisp8EVEX Tuple
  Macro IiDisp8EVEX defines scaling factor N for EVEX-encoded instructions when compressed displacement coding disp8*N is used.
  The factor (unspecified, 1, 2, 4, 8, 16, 32, 64) is defined for each of eight combinations of bits `EVEX.L'.L.b`. The actual combination is usually chosen by registers width (XMM/YMM/ZMM) and by modifiers `BCST=, ROUND=, SAE=, OPER=` . Code value x of each 4bit nibble (0..6) represents scaling factor N=2x and x specifies how many bits (0..6) will CPU shift-left the encoded disp8 to obtain the effective displacement value. Special nibble value F signalizes that this combination (OPER= value) is not permitted and will cause W2450.

  > If the macro does not appear in instruction handler and if EVEX encoding is used, €ASM will issue warning W2450 The value OPER=!1D is not supported in this MVEX/EVEX instruction , regardless of OPER= value.

Input
  Tuple is enumerated token, see [IntelAVX512]:

  Disp8*N scaling used with prefix EVEX
  Tuple as used by | EVEX.L'.L.b alias OPER= | Code value
  --- | --- | ---
  €ASM | Intel doc | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
  FV32 |  | 16 | 4 | 32 | 4 | 64 | 4 | - | - | 0x425262FF
  FV64 | Full | 16 | 8 | 32 | 8 | 64 | 8 | - | - | 0x435363FF
  HV32 |  | 8 | 4 | 16 | 4 | 32 | 4 | - | - | 0x324252FF
  FVM | Full Mem | 16 | - | 32 | - | 64 | - | - | - | 0x4F5F6FFF
  T1S8 |  | 1 | - | 1 | - | 1 | - | - | - | 0x0F0F0FFF
  T1S16 |  | 2 | - | 2 | - | 2 | - | - | - | 0x1F1F1FFF
  T1S32 |  | 4 | - | 4 | - | 4 | - | - | - | 0x2F2F2FFF
  T1S64 |  | 8 | - | 8 | - | 8 | - | - | - | 0x3F3F3FFF
  T1F32 |  | 4 | - | 4 | - | 4 | - | - | - | 0x2F2F2FFF
  T1F64 |  | 8 | - | 8 | - | 8 | - | - | - | 0x3F3F3FFF
  T2F32 |  | 8 | - | 8 | - | 8 | - | - | - | 0x3F3F3FFF
  T2F64 |  | - | - | 16 | - | 16 | - | - | - | 0xFF4F4FFF
  T4F32 |  | - | - | 16 | - | 16 | - | - | - | 0xFF4F4FFF
  T4F64 |  | - | - | - | - | 32 | - | - | - | 0xFFFF5FFF
  T8F32 |  | - | - | - | - | 32 | - | - | - | 0xFFFF5FFF
  HVM |  | 8 | - | 16 | - | 32 | - | - | - | 0x3F4F5FFF
  QVM |  | 4 | - | 8 | - | 16 | - | - | - | 0x2F3F4FFF
  OVM |  | 2 | - | 4 | - | 8 | - | - | - | 0x1F2F3FFF
  M128 |  | 16 | - | 16 | - | 16 | - | - | - | 0x4F4F4FFF
  DUP |  | 8 | - | 32 | - | 64 | - | - | - | 0x3F5F6FFF

  EDI= pointer to II.
Output
  Set of exponents is stored to [EDI+II.Disp8EVEX].
Example
  IiDisp8EVEX HVM
Expanded in
  IiHandlers.
See also
  IiDisp8MVEX IiCompressDisp8

    IiDisp8EVEX %MACRO Tuple
       %CodeValue %SETA 0
       %IF "%Tuple" == "FV32"
         %CodeValue %SETA 0x425262FF
       %ENDIF
       %IF "%Tuple" == "FV64"
         %CodeValue %SETA 0x435363FF
       %ENDIF
       %IF "%Tuple" == "HV32"
         %CodeValue %SETA 0x324252FF
       %ENDIF
       %IF "%Tuple" == "FVM"
         %CodeValue %SETA 0x4F5F6FFF
       %ENDIF
       %IF "%Tuple" == "T1S8"
         %CodeValue %SETA 0x0F0F0FFF
       %ENDIF
       %IF "%Tuple" == "T1S16"
         %CodeValue %SETA 0x1F1F1FFF
       %ENDIF
       %IF "%Tuple" == "T1S32"
         %CodeValue %SETA 0x2F2F2FFF
       %ENDIF
       %IF "%Tuple" == "T1S64"
         %CodeValue %SETA 0x3F3F3FFF
       %ENDIF
       %IF "%Tuple" == "T1F32"
         %CodeValue %SETA 0x2F2F2FFF
       %ENDIF
       %IF "%Tuple" == "T1F64"
         %CodeValue %SETA 0x3F3F3FFF
       %ENDIF
       %IF "%Tuple" == "T2F32"
         %CodeValue %SETA 0x3F3F3FFF
       %ENDIF
       %IF "%Tuple" == "T2F64"
         %CodeValue %SETA 0xFF4F4FFF
       %ENDIF
       %IF "%Tuple" == "T4F32"
         %CodeValue %SETA 0xFF4F4FFF
       %ENDIF
       %IF "%Tuple" == "T4F64"
         %CodeValue %SETA 0xFFFF5FFF
       %ENDIF
       %IF "%Tuple" == "T8F32"
         %CodeValue %SETA 0xFFFF5FFF
       %ENDIF
       %IF "%Tuple" == "HVM"
         %CodeValue %SETA 0x3F4F5FFF
       %ENDIF
       %IF "%Tuple" == "QVM"
         %CodeValue %SETA 0x2F3F4FFF
       %ENDIF
       %IF "%Tuple" == "OVM"
         %CodeValue %SETA 0x1F2F3FFF
       %ENDIF
       %IF "%Tuple" == "M128"
         %CodeValue %SETA 0x4F4F4FFF
       %ENDIF
       %IF "%Tuple" == "DUP"
         %CodeValue %SETA 0x3F5F6FFF
       %ENDIF
       %IF %CodeValue
         MOV [EDI+II.Disp8EVEX],%CodeValue, DATA=DWORD
       %ELSE
         %ERROR Id=5866,"Undefined Disp8EVEX value '%Tuple' in %^PROC."
       %ENDIF
     %ENDMACRO IiDisp8EVEX

↑ IiDisp8MVEX Conversion
  Macro IiDisp8MVEX defines scaling factor N for MVEX-encoded instructions when compressed displacement coding disp8*N is used.
  The factor (unspecified, 1, 2, 4, 8, 16, 32, 64) is defined for each of eight combinations of bits `MVEX.S2.S1.S0` provided as instruction modifier `OPER=`. Code value x of each 4bit nibble (0..6) represents scaling factor N=2x and x specifies how many bits (0..6) will CPU shift-left the encoded disp8 to obtain the effective displacement value. Special nibble value F signalizes that this OPER= value is not permitted and will cause W2450.

  > If the macro does not appear in instruction handler and if MVEX encoding is used, €ASM will issue warning W2450 The value OPER=!1D is not supported in this MVEX/EVEX instruction , regardless of OPER= value.

Input
  Conversion is one of enumerated tokens from the table below:

  Disp8*N exponents used with prefix MVEX
  Conversion | MVEX.S2.S1.S0 alias OPER= | Code value
  --- | --- | ---
  0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
  Di32 | 4 | - | - | - | 1 | 1 | 2 | 2 | 0x2FFF0011
  Df32 | 4 | - | - | 2 | 1 | 1 | 2 | 2 | 0x2FF10011
  Sn64 | 8 | - | - | - | - | - | - | - | 0x3FFFFFFF
  Ui32 | 16 | - | - | - | 4 | 4 | 8 | 8 | 0x4FFF2233
  Sn32 | 16 | - | - | 8 | 4 | 4 | 8 | 8 | 0x4FF32233
  Si64 | 32 | - | - | - | - | - | - | - | 0x5FFFFFFF
  Sb32 | 32 | 4 | 16 | - | - | - | - | - | 0x524FFFFF
  Di64 | 64 | - | - | - | - | - | - | - | 0x6FFFFFFF
  Un32 | 64 | - | - | - | 16 | 16 | 32 | 32 | 0x6FFF4455
  Dn32 | 64 | - | - | 32 | 16 | 16 | 32 | 32 | 0x6FF54455
  Sf32 | 64 | - | 16 | - | - | - | - | - | 0x6F4FFFFF
  Si32 | 64 | 4 | 16 | - | 16 | 16 | 32 | 32 | 0x624F4455
  Uf32 | 64 | 4 | 16 | 32 | 16 | 16 | 32 | 32 | 0x62454455
  Us32 | 64 | 4 | 16 | 32 | 16 | - | 32 | 32 | 0x62454F55
  Ub64 | 64 | 8 | 32 | - | - | - | - | - | 0x635FFFFF

  EDI= pointer to II.
Output
  Set of exponents is stored to [EDI+II.Disp8MVEX].
Example
  IiDisp8MVEX Sf32
Expanded in
  IiHandlers.
See also
  IiDisp8EVEX IiCompressDisp8

    IiDisp8MVEX %MACRO Conversion
      %CodeValue %SETA 0
      %IF "%Conversion" == "Di32"
        %CodeValue %SETA 0x2FFF0011
      %ENDIF
      %IF "%Conversion" == "Df32"
        %CodeValue %SETA 0x2FF10011
      %ENDIF
      %IF "%Conversion" == "Sn64"
        %CodeValue %SETA 0x3FFFFFFF
      %ENDIF
      %IF "%Conversion" == "Ui32"
        %CodeValue %SETA 0x4FFF2233
      %ENDIF
      %IF "%Conversion" == "Sn32"
        %CodeValue %SETA 0x4FF32233
      %ENDIF
      %IF "%Conversion" == "Si64"
        %CodeValue %SETA 0x5FFFFFFF
      %ENDIF
      %IF "%Conversion" == "Sb32"
        %CodeValue %SETA 0x524FFFFF
      %ENDIF
      %IF "%Conversion" == "Di64"
        %CodeValue %SETA 0x6FFFFFFF
      %ENDIF
      %IF "%Conversion" == "Un32"
        %CodeValue %SETA 0x6FFF4455
      %ENDIF
      %IF "%Conversion" == "Dn32"
        %CodeValue %SETA 0x6FF54455
      %ENDIF
      %IF "%Conversion" == "Sf32"
        %CodeValue %SETA 0x6F4FFFFF
      %ENDIF
      %IF "%Conversion" == "Si32"
        %CodeValue %SETA 0x624F4455
      %ENDIF
      %IF "%Conversion" == "Uf32"
        %CodeValue %SETA 0x62454455
      %ENDIF
      %IF "%Conversion" == "Us32"
        %CodeValue %SETA 0x62454F55
      %ENDIF
      %IF "%Conversion" == "Ub64"
        %CodeValue %SETA 0x635FFFFF
      %ENDIF
      %IF %CodeValue
        MOV [EDI+II.Disp8MVEX],%CodeValue, DATA=DWORD
      %ELSE
        %ERROR Id=5867,"Undefined Disp8MVEX value '%Conversion' in %^PROC."
      %ENDIF
     %ENDMACRO IiDisp8MVEX

↑ IiModRM RegOpcode

  Macro IiModRM specifies that the ModRM byte should be emitted, optionally followed by SIB and displacement.

  The actual ModR/M+SIB byte(s) will be generated later by IiCreateModRM.

  Format of ModR/M byte
  7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
  --- | --- | --- | --- | --- | --- | --- | ---
  `Mod` | `Reg/Opcode` | `R/M`

  Format of SIB byte
  7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
  --- | --- | --- | --- | --- | --- | --- | ---
  `Scale` | `Index` | `Base`

  This macro should always be accompanied by IiOpEn, which declares which operand is encoded in ModR/M fields `Reg/Opcode` and `R/M`.

Input
  RegOpcode is one of enumerated options `/r /0 /1 /2 /3 /4 /5 /6 /7` or register EAX,EBX,ECX which contains either iiPpgModRMr or /digit value 0..7 in position iiPpgModDigit combined with iiPpgModRMd.
  EDI= pointer to II.
Output
  `[EDI+II.Ppg]` is modified with `iiPpgModRMr, iiPpgModRMd, iiPpgModDigit`.
Example
  IiModRM /6
Expanded in
  IiHandlers.
See also
  IiVSIB.

    IiModRM %MACRO RegOpcode
      %IF "%RegOpcode"=="EAX" | "%RegOpcode"=="EBX" | "%RegOpcode"=="ECX"
        OR [EDI+II.Ppg],%RegOpcode
      %ELSE
       %Ppg %SETA 0
       %IF "%RegOpcode[2]" == "r"
         %Ppg %SETA iiPpgModRMr
       %ELSE ; /digit.
         %Ppg %SETA %RegOpcode[2] << 28 | iiPpgModRMd  ; >>
       %ENDIF
       %IF %Ppg && "%RegOpcode[1]" === "/"
          SetSt [EDI+II.Ppg],%Ppg
       %ELSE
          %ERROR Id=5868,"Invalid RegOpcode specificator '%RegOpcode' in %^PROC."
       %ENDIF
      %ENDIF
     %ENDMACRO IiModRM

↑ IiEmitImm OperandNr, Datatype, Max=0
  Macro IiEmitImm will copy the value of immediate operand to `[EDI+II.Immediate]` and set its size using a flag from `[EDI+II.MfgEmitted]:iiMfgIMM_Mask`. This tells IiFlush to emit immediate value later.
  IiEmitImm does not ask for relocations.
  Instead of IiEmitImm the handler can use IiImmSize and set `[EDI+II.MfgEmitted]:iiMfgIMM_Mask` to achieve similar functionality.
Input
  OperandNr is one of enumerated options `Operand1`, `Operand2`,`Operand3`,`Operand4`. Specified operand in II object must be a plain number type ('N') or address ('A'). Segment of address is ignored.
  Datatype in one of enumerated values `BYTE, WORD, DWORD, QWORD`.
  Max=0 is maximal immediate value (1..255), W2461 is issued on exceeding. Special value 0 (default) means that the immediate value is not checked.
  EDI= pointer to II.
Output
  II object is modified.
Example
  IiEmitImm Operand3, BYTE, Max=31
On error
  W2461 Immediate value "!1D" should not exceed !2D.
Expanded in
  IiHandlers.
See also
  IiImmSize.

    IiEmitImm %MACRO OperandNr, Datatype, Max=0
        %ExpNr %SETA %OperandNr[8] ; 1..4.
        %IF %ExpNr+0 <1 || %ExpNr+0 >4
          %ERROR Id=5869,'Macro IiEmitImm in %^PROC expects 1st argument Operand1,Operand2,Operand3 or Operand4.'
          %EXITMACRO IiEmitImm
        %ENDIF
        %IF "%Datatype"==""
         %ERROR  Id=5870,'Macro IiEmitImm in %^PROC expects 2nd argument BYTE, WORD, DWORD or QWORD.'
         %EXITMACRO IiEmitImm
        %ENDIF
        PUSHD (%ExpNr-1) * SIZE#EXP | iiMfgIMM_%Datatype<<16 | %Max<<24                                ;>>>>
        CALL IiEmitImm@RT:
    IiEmitImm@RT: PROC1                   ; One combined operand is on stack.
        PUSH EAX,EDX
         MOV EDX,[ESP+12]                  ; The operand.
         AND EDX,0x000000FF                ; 00h|14h|28h|3Ch operand index in II.
         ADD EDX,EDI                       ; EDX=^EXP.
         MOV EAX,[EDX+EXP.Low]
         MOV EDX,[EDX+EXP.High]
         MOV [EDI+II.ImmLow],EAX
         MOV [EDI+II.ImmHigh],EDX
         MOV EAX,[ESP+12]
         SHR EAX,16
         MOV EDX,EAX
         AND EAX,iiMfgIMM_Mask             ; EAX is now one flag of iiMfgIMM_Mask: 1,2,4,8.
         SHR EDX,8 ; Max value.
         SetSt [EDI+II.MfgEmitted],EAX
         TEST EDX
         JZ .90:
         CMP EDX,[EDI+II.ImmLow]
         JAE .90:
         Msg '2461',[EDI+II.ImmLow],EDX    ; W2461 Immediate value !1D should not exceed !2D.
    .90:POP EDX,EAX
        RET 4
        ENDPROC1 IiEmitImm@RT:
      %ENDMACRO IiEmitImm

↑ IiEmitImm2 OperandNr, Max=255
  Macro IiEmitImm2 will copy the value of secondary immediate operand to `[EDI+II.Imm2]` and set the flag `[EDI+II.Ppg]:iiPpgImm2`. This tells IiFlush to emit secondary immediate value later.
Input
  OperandNr is one of enumerated options `Operand1`, `Operand2`,`Operand3`,`Operand4`. Specified operand in II object must be a plain number type ('N') and it must be encodable in 8 bits.
  Max=255 Maximal allowed possible value.
  EDI= pointer to II.
Output
  II object is modified.
On Error
  E6746 Secondary immediate operand should be a plain number.
  E6747 Secondary immediate operand is too big for 1 byte.
  W2461 Immediate value (!1D) should not exceed !2D.
Example
  IiEmitImm2 Operand3, Max=31
Expanded in
  IiHandlers.
See also
  IiImmSize.

    IiEmitImm2 %MACRO OperandNr, Max=255
        %ExpNr %SETA %OperandNr[8]         ; 1..4.
        %IF %ExpNr+0 <1 || %ExpNr+0 >4
          %ERROR Id=5871,'Macro IiEmitImm2 expects 1st argument Operand1,Operand2,Operand3 or Operand4.'
          %EXITMACRO IiEmitImm2
        %ENDIF
        PUSHD (%ExpNr-1) * SIZE#EXP | %Max<<24                                              ; >>
        CALL IiEmitImm2@RT:
    IiEmitImm2@RT: PROC1                  ; One combined operand is on stack.
        PUSH EAX,ECX,EDX
         MOV EDX,[ESP+16]                  ; The operand.
         AND EDX,0x000000FF                ; 00h|14h|28h|3Ch operand index in II.
         ADD EDX,EDI                       ; EDX=^EXP.
         CMPB [EDX+EXP.Status],'N'
         Msg cc=NE,'6746'                  ; E6746 Secondary immediate operand should be a plain number.
         MOV EAX,[EDX+EXP.Low]
         MOV EDX,[EDX+EXP.High]
         MOV [EDI+II.Imm2],AL
         SetSt [EDI+II.Ppg],iiPpgImm2
         Invoke ExpWidth::
         CMP CL,expWidth1B
         MOV ECX,[ESP+16]                  ; %1 procedure argument.
         Msg cc=A,'6747'                   ; E6747 Secondary immediate operand is too big for 1 byte.
         SHR ECX,24                        ; CL=%Max.
         CMP AL,CL
         Msg cc=A,'2461',EAX,ECX           ; W2461 Immediate value (!1D) should not exceed !2D.
    .90:POP EDX,ECX,EAX
        RET 4
        ENDPROC1 IiEmitImm2@RT:
      %ENDMACRO IiEmitImm2

↑ IiReloc IiRelocType, OperandNr
  Macro IiReloc asks IiFlush to create relocation of displacement or immediate operand.
  It will set a flag in `II.Reloc` which is the request for relocation and optionally for attribute evaluation of external symbol postponed to link time.
Input
  IiRelocType is one of the `iiRelocDisp*` or `iiRelocImm*` flags in IiRelocEnc encoding.
  OperandNr is one of enumerated identifiers `Operand1, Operand2, Operand3, Operand4` or omitted.
  EDI= pointer to II.
Output
  Specified IiRelocType is set in `II.Reloc`.
Examples
  IiReloc iiRelocDispAbs IiReloc iiRelocPara, Operand1
Expanded in
  IiHandlers.

    IiReloc %MACRO IiRelocType, OperandNr
       %IF %# = 1
         SetSt [EDI+II.Reloc],%IiRelocType
       %ELSE
         SetSt [EDI+II.Reloc],iiRelocExtAttrReq + %IiRelocType + II.%OperandNr
       %ENDIF
      %ENDMACRO IiReloc

↑ IiEmitOpcode Byte1, Byte2, Byte3,,,
  Macro IiEmitOpcode stores specified byte(s) to `[EDI+II.Opcode]` and modifies `[EDI+II.MfgEmitted:iiPpgOpcodeSizeMask]` accordingly.
Input
  ByteX 1..15 bytes can be specified as direct value, e.g. `0xF5`, or as 32bit register, e.g. `EAX` from which only LSB is used.
  EDI= pointer to II.
Output
  II object is modified.
Example
  IiEmitOpcode 0x37,ECX,EAX
Expanded in
  IiHandlers.
See also

    IiEmitOpcode %MACRO
    Operand %FOR %*
          PUSHD %Operand
          CALL IiEmitOpcode@RT:
        %ENDFOR Operand
    IiEmitOpcode@RT: PROC1 ; Input: EDI=^II, Stack=Byte to emit.
              PUSH EAX,EDX
                MOV EAX,[ESP+12]           ; Operand is now in AL.
                MOV EDX,[EDI+II.Ppg]       ; iiPpgOpcodeSizeMask is in lowest 4 bits.
                INC EDX
                MOV [EDI+II.Ppg],EDX
                AND EDX,iiPpgOpcodeSizeMask
                JZ .90:                    ; Out of II.Opcode, this should never happen
                                           ;  unless IiEmitOpcode is called more than 15 times by mistake.
                MOV [EDI+II.Opcode+EDX-1],AL
         .90: POP EDX,EAX
              RET 4
         ENDPROC1 IiEmitOpcode@RT:
       %ENDMACRO IiEmitOpcode

↑ IiEmitPrefix PrefixSpecifikator(s)
  Macro IiEmitPrefix will mark a request for emitting of specified prefix(es) in `[EDI+II.PfxEmitted]`. Specficators applicable on AVX prefix are separated with dot `.`, they are stored as a pointer to source-specification string into `[EDI+II.AvxSrc*]`. The actual AVX prefix will be parsed from them later by IiAssembleAVX.

  Prefix specificator | Encoding flag | II.member | Applicable on AVX prefix
  --- | --- | --- | ---
  LOCK | iiPfxLOCK | II.PfxEmitted | -
  REP | iiPfxREP | II.PfxEmitted | -
  REPE | iiPfxREPE | II.PfxEmitted | -
  REPNE | iiPfxREPNE | II.PfxEmitted | -
  ATOGGLE | iiPfxATOGGLE | II.PfxEmitted | -
  OTOGGLE | iiPfxOTOGGLE | II.PfxEmitted | -
  REX | iiPfxREX | II.PfxEmitted | -
  REX.W | iiPfxREX.W | II.PfxEmitted | -
  REX.R | iiPfxREX.R | II.PfxEmitted | -
  REX.X | iiPfxREX.X | II.PfxEmitted | -
  REX.B | iiPfxREX.B | II.PfxEmitted | -
  128 | iiMfgDATA_OWORD | II.MfgImplicit | XOP,VEX,MVEX,EVEX
  256 | iiMfgDATA_YWORD | II.MfgImplicit | XOP,VEX,MVEX,EVEX
  512 | iiMfgDATA_ZWORD | II.MfgImplicit | MVEX,EVEX
  XOP | iiMfxPREFIX_XOP | II.MfxEmitted | XOP
  VEX | iiMfxPREFIX_VEX | II.MfxEmitted | VEX2,VEX3
  VEX2 | iiMfxPREFIX_VEX2 | II.MfxEmitted | VEX2
  VEX3 | iiMfxPREFIX_VEX3 | II.MfxEmitted | VEX3
  MVEX | iiMfxPREFIX_MVEX | II.MfxEmitted | MVEX
  EVEX | iiMfxPREFIX_EVEX | II.MfxEmitted | EVEX
  NDD | iiPpxNDD | II.Ppx | XOP,VEX,MVEX,EVEX
  NDS | iiPpxNDS | II.Ppx | XOP,VEX,MVEX,EVEX
  DDS | iiPpxDDS | II.Ppx | XOP,VEX,MVEX,EVEX
  W0 | iiPpxW0 | II.Ppx | XOP,VEX,MVEX,EVEX
  W1 | iiPpxW1 | II.Ppx | XOP,VEX3,MVEX,EVEX
  WIG | - | II.Ppx | XOP,VEX,MVEX,EVEX
  LZ | iiPpxL0 | II.Ppx | XOP,VEX,MVEX,EVEX
  L0 | iiPpxL0 | II.Ppx | XOP,VEX,MVEX,EVEX
  L1 | iiPpxL1 | II.Ppx | XOP,VEX,MVEX,EVEX
  LIG | - | II.Ppx | XOP,VEX,MVEX,EVEX
  66 | iiPpxPpMask 01 | II.Ppx | XOP,VEX,MVEX,EVEX
  F2 | iiPpxPpMask 11 | II.Ppx | XOP,VEX,MVEX,EVEX
  F3 | iiPpxPpMask 10 | II.Ppx | XOP,VEX,MVEX,EVEX
  0F | iiPpxMmMask 01 | II.Ppx | VEX,MVEX,EVEX
  0F38 | iiPpxMmMask 010 | II.Ppx | VEX3,MVEX,EVEX
  0F3A | iiPpxMmMask 011 | II.Ppx | VEX3,MVEX,EVEX
  MAP5 | iiPpxMmMask 101 | II.Ppx | EVEX
  MAP6 | iiPpxMmMask 110 | II.Ppx | EVEX
  MAP7 | iiPpxMmMask 111 | II.Ppx | EVEX
  MAP8 | iiPpxMmMask 000 | II.Ppx | XOP
  MAP9 | iiPpxMmMask 001 | II.Ppx | XOP
  MAP10 | iiPpxMmMask 010 | II.Ppx | XOP
  EH0 | iiPpxEH0 | II.Ppx | MVEX
  EH1 | iiPpxEH1 | II.Ppx | MVEX

Input
  PrefixSpecificator is a list of enumerated options from the table above.
  EDI= pointer to II.
Output
  II object is modified.
Examples
  IiEmitPrefix OTOGGLE, REPE IiEmitPrefix XOP.MAP9.128.L0.W0 IiEmitPrefix VEX.DDS.256.66.0F38.W1, EVEX.DDS.LIG.66.0F38.W1
Expanded in
  IiHandlers.
See also

    IiEmitPrefix %MACRO
     %AVXprefixes %SET XOP.,VEX.,EVEX,MVEX
     spec %FOR %*
         %unknown %SETB TRUE
         %AVXtype %SETB FALSE
         AVXprefix %FOR %AVXprefixes
           %IF "%spec[1..4]" == "%AVXprefix"
             %AVXtype %SETB TRUE
           %ENDIF
         %ENDFOR
          %IF !%AVXtype
           SetSt [EDI+II.PfxEmitted],iiPfx%spec
           %IF "%spec[1..3]" === "REX"
             RstSt [EDI+II.Ppx],iiPpxRemoveREX+iiPpxRemoveREX.W+iiPpxRemoveREX.R
           %ENDIF
           %unknown %SETB FALSE
         %ELSE ; Otherwise it must be AVX string, e.g. VEX.NDS.256.66.0F.WIG.
      %avx %SET %spec[1..4]
          %IF "%avx" === "XOP."
            MOVD [EDI+II.AvxSrcXOP],=B"%spec"
            %unknown %SETB FALSE
          %ENDIF
          %IF "%avx" === "VEX."
            MOVD [EDI+II.AvxSrcVEX],=B"%spec"
            %unknown %SETB FALSE
          %ENDIF
          %IF "%avx" === "EVEX"
            MOVD [EDI+II.AvxSrcEVEX],=B"%spec"
            SetSt [EDI+II.MfxAllowed],iiMfxZEROING_Mask+iiMfxOPER_Mask
            %unknown %SETB FALSE
          %ENDIF
          %IF "%avx" === "MVEX"
            MOVD [EDI+II.AvxSrcMVEX],=B"%spec"
            SetSt [EDI+II.MfxAllowed],iiMfxEH_Mask+iiMfxOPER_Mask
            %unknown %SETB FALSE
          %ENDIF
         %ENDIF
         %IF %unknown
           %ERROR Id=5872,"Unknown IiEmitPrefix operand '%spec' in '%^PROC'."
         %ENDIF
        %ENDFOR spec
     %ENDMACRO IiEmitPrefix

↑ IiEncoding Modifiers
  Macro IiEncoding specifies finally emitted instruction modifiers. They will be used by IiFlush to choose *VEX, displacement and immediate field size.
  Encoded modifiers will be displayed by diagnostic message D1080 when `EUROASM DISPLAYENC=ENABLED`.
Input
  Modifiers specified in format KEY=VALUE (enumerated) or KEY=Used (numeric) or KEY=Mask (Boolean), see Modifiers encoding.
  EDI= pointer to II.
Output
  II flags in members `MfgEmitted` and `MfxEmitted` are set.
Examples
  IiEncoding DISP=BYTE, CODE=SHORT IiEncoding PREFIX=EVEX, MASK=Used, ZEROING=Mask
Expanded in
  IiHandlers.
See also

    IiEncoding %MACRO R32, IMM=None,DISP=None,DATA=None,SCALE=None,DIST=None,ADDR=None,CODE=None, \
                      BCST=None,MASK=None,OPER=None,ROUND=None,SAE=None,BCST=None,EH=None,ZEROING=None,PREFIX=None
    %Mfg %SETA iiMfgIMM_%IMM|iiMfgDISP_%DISP|iiMfgDATA_%DATA|iiMfgSCALE_%SCALE|iiMfgDIST_%DIST|iiMfgADDR_%ADDR|iiMfgCODE_%CODE
    %Mfx %SETA iiMfxMASK_%MASK|iiMfxOPER_%OPER|iiMfxROUND_%ROUND|iiMfxSAE_%SAE|iiMfxBCST_%BCST|iiMfxEH_%EH|iiMfxZEROING_%ZEROING|iiMfxPREFIX_%PREFIX
        %IF %Mfg
          SetSt [EDI+II.MfgEmitted],%Mfg
        %ENDIF
        %IF %Mfx
          SetSt [EDI+II.MfxEmitted],%Mfx
        %ENDIF
        %IF "%R32"!===""
          OR [EDI+II.MfgEmitted],%R32
        %ENDIF
       %ENDMACRO IiEncoding

↑ IiOpEn OpEnCode
  Macro IiOpEn defines where are operands encoded in the instruction.
Input
  OpEnCode is a combination of 1..3 letters R,M,V. The 1st letter specifies Operand1, 2nd letter Operand2, 3rd letter Operand3.
  Letter R specifies encoding in ModRM field Reg/Opcode,
  Letter M specifies encoding in ModRM field R/M,
  Letter V specifies encoding in *VEX field V'vvvv.
  EDI= pointer to II.
Output
  Information is marked to `[EDI+II.Ppg]` as general properties `iiPpgModRegOp, iiPpgModRMOp, iiPpgVEXvOp`.
Examples
  IiOpEn RMV ; Operand1 will be in Reg/Opcode, Operand2 in R/M, Operand3 in VVVV.
Expanded in
  IiHandlers.
See also

    IiOpEn %MACRO OpEnCode
       %Ppg %SETA 0
       %IF "%OpEnCode" == "RM"
         %Ppg %SETA 0x0900_0000
       %ENDIF
       %IF "%OpEnCode" == "MR"
         %Ppg %SETA 0x0600_0000
       %ENDIF
       %IF "%OpEnCode" == "VM"
         %Ppg %SETA 0x0840_0000
       %ENDIF
       %IF "%OpEnCode" == "RVM"
         %Ppg %SETA 0x0D80_0000
       %ENDIF
       %IF "%OpEnCode" == "RMV"
         %Ppg %SETA 0x09C0_0000
       %ENDIF
       %IF "%OpEnCode" == "MVR"
         %Ppg %SETA 0x0780_0000
       %ENDIF
       %IF "%OpEnCode" == "M"
         %Ppg %SETA 0x0400_0000
       %ENDIF
       %IF "%OpEnCode" == "V"
         %Ppg %SETA 0x0040_0000
       %ENDIF
       RstSt [EDI+II.Ppg],iiPpgVEXvOp|iiPpgModRegOp|iiPpgModRMOp
       %IF %Ppg
         SetSt [EDI+II.Ppg],%Ppg
       %ELSE
         %ERROR Id=5873,"Unknown OpEnCode '%OpEnCode' in %^PROC."
       %ENDIF
      %ENDMACRO IiOpEn

↑ IiIs4 OperandNr
  Macro IiIs4 encodes SSE register specified as OperandNr (XMM0..XMM15) into immediate operand referenced as /is4 in CPU specification.
Input
  OperandNr is one of enumerated values `Operand1, Operand2, Operand3, Operand4`.
  EDI= pointer to II.
Output
  `iiPpgImm2` is set and ordinal number of SSE register is encoded in bits 4..7 of `[EDI+II.Imm2]`.
Error
  E6767 or E6768 Only SSE register 0..7 may be used as 4th operand.
Example
  IiIs4 Operand4
Expanded in
  IiHandlers.
See also

    IiIs4 %MACRO OperandNr
       PUSH EAX
        Invoke IiGetRegOrdinal::, [EDI+II.%OperandNr+EXP.Low]
        CMP AL,15
        Msg cc=A,'6768' ; Only SSE register 0..15 may be used as 4th operand.
        JSt [EDI+II.SssStatus],sssWidth64,.is4.%.:
        CMP AL,7
        Msg cc=A,'6767' ; Only SSE register 0..7 may be used as 4th operand.
    .is4.%.:
        SAL AL,4
        OR [EDI+II.Imm2],AL
        SetSt [EDI+II.Ppg],iiPpgImm2
       POP EAX
      %ENDMACRO IiIs4

↑ IiImmSize OperandNr
  Macro IiImmSize is expanded in IiHandlers of instruction with immediate operand.
  It copies immediate value of specified operand to `II.Imm` and its section, if any, to `II.ImmRelocSeg`.
  Macro does not request for relocation in `II.Reloc` , this is the job of IiReloc.
  Proposed immediate size (Byte/Word/Dword/Qword) is stored to II.MfgImplicit:iiMfgIMM_Mask and it is calculated from the signed number magnitude, which should be later increased to word or doubleword when the immediate is a relocatable address.
  Explicit instruction modifier IMM= is not taken into account here.
Input
  OperandNr is one of `Operand1, Operand2, Operand3, Operand4`.
  EDI= pointer to II.
Output
  Explicit modifier IMM= is allowed.
  `II.ImmLow, II.ImmHigh, II.ImmRelocSeg, II.ImmRelocSym, II.Para` are updated.
  One flag in `[EDI+II.MfgImplicit]:iiMfgIMM_Mask]` is set.
Error
  E6771 if immediate segment value !1Hh is too big for 16 bits in far CALL/JMP.
Example
  IiImmSize Operand1
Expanded in
  IiHandlers.
See also
  IiRelocSizeRIP, IiEmitImm.

    IiImmSize %MACRO OperandNr
     %ExpNr %SETA %OperandNr[8] ; 1..4.
         %IF %ExpNr+0 <1 || %ExpNr+0 >4
           %ERROR Id=5874,'Macro IiEmitImm in %^PROC expects 1st argument Operand1,Operand2,Operand3 or Operand4.'
           %EXITMACRO IiImmSize
        %ENDIF
         PUSHD (%ExpNr-1) * SIZE#EXP
         CALL IiImmSize@RT:
    IiImmSize@RT:: PROC1
         PUSHAD
           MOV ESI,[ESP+36]                ; Load macroparameter with operand offset in II.
           ADD ESI,EDI                     ; ESI=^EXP (expression with immediate operand).
           SetSt [EDI+II.MfgAllowed],iiMfgIMM_Mask
           MOV EAX,[ESI+EXP.Low]
           MOV EDX,[ESI+EXP.High]
           MOV [EDI+II.ImmLow],EAX
           MOV [EDI+II.ImmHigh],EDX
           Invoke ExpWidthSigned::         ; Calculate the width of number EDX:EAX.
           Dispatch CL,expWidth2B,expWidth4B,expWidth8B ; CL=3,4,5,6,7 for immediate operand width 8,8,16,32,64.
    .expWidth1B: MOV EBX,iiMfgIMM_BYTE
           JMP .50:
    .expWidth2B: MOV EBX,iiMfgIMM_WORD
           JMP .50:
    .expWidth8B: MOV EBX,iiMfgIMM_QWORD
           JMP .50:
    .expWidth4B: MOV EBX,iiMfgIMM_DWORD
     .50:  MOV EAX,[ESI+EXP.Status]
           MOV ECX,[ESI+EXP.Seg]
           MOV EDX,[ESI+EXP.Sym]
           AND AL,expDataType
           Dispatch AL,'N','A','F','P'
           JMP .90:                        ; Do nothing when the operand is not immediate.
     .F:   ; Operand is direct far immediate, e.g. 0040h:0
           MOV [EDI+II.Para],CX            ; EXP.Seg contains Para value instead of ^SSS.
           CMP ECX,0x0000FFFF
           Msg cc=A,'6771',ECX             ; Immediate segment value !1Hh is too big for 16 bits.
           SetSt [EDI+II.Ppg],iiPpgPara    ; Request to emit imm Para value after imm offset.
           JMP .80:
      .P:  ; Operand is a paragraph address, e.g. PARA# Main.
      .N:  ; Operand is immediate address or number.
      .A:  MOV [EDI+II.ImmRelocSeg],ECX    ; Prepare for the case of future relocation.
           MOV [EDI+II.ImmRelocSym],EDX    ; Prepare for the case of future relocation.
     .80:  SetSt [EDI+II.MfgImplicit],EBX
     .90:POPAD
         RET 4
       ENDPROC1 IiImmSize@RT:
     %ENDMACRO IiImmSize

↑ IiImmCreate ImmValue, OpPosition=Operand4
  Macro IiImmCreate will create a fake immediate operand with specified value as operand OpPosition.
  It is used in handlers of conditional instructions where the condition is specified in mnemonic and encoded as ib, e.g. VCMPccPD.
Input
  ImmValue is register with the immediate value.
  OpPosition=Operand4 is one of enumerated values `Operand1, Operand2, Operand3, Operand4`.
  EDX= contains operand types in Intel encoding.
  EDI= pointer to II.
Output
  EDX is shifted one byte left and DL (now the last operand) is set to imm.
  [EDI+II.OpPosition] is set to numeric type with ImmValue.
Error
  none.
Example
  IiImmCreate CL
Expanded in
  IiHandlers.

    IiImmCreate %MACRO ImmValue, OpPosition=Operand4
        SHL EDX,8
        MOV DL,imm
        MOV  [EDI+II.%OpPosition+EXP.Low],%ImmValue
        MOVB [EDI+II.%OpPosition+EXP.Status],'N'
     %ENDMACRO IiImmCreate

↑ IiDataSize Hint, AllowQword=OFF, SpecifyMem=ON, UseSegment=OFF, FloatingPoint=OFF, StreamingSIMD=OFF
  Macro IiDataSize is expanded in IiHandlers usually just before macro IiDispatchFormat, when the instruction is already identified but operand types in EDX are not finally determined.
  It calculates effective operand size and modifies instruction format in Intel encoding which was provided by IiAssemble as a preliminary draft in EDX. It also requests implicit prefix OTOGGLE and REX.W, if necessary.
  Final effective value of operand size (Byte/Word/Dword/Qword) is stored to II.MfgEmitted:iiMfgDATA_Mask and it is calculated here in accordance with hint provided as IiDataSize argument.
  Rules for operand width selection in €ASM:
  1. If a general-purpose register is chosen as destination or source, operands size equals to its width. This cannot be overriden with mnemonic suffix nor with DATA= modifier. For instance `INC EAX` always operates with 32 bits.
  2. When operand size cannot be determined from register width, then mnemonic suffix from `II.MfgSuffix:iiMfgDATA_Mask` will be taken into account, if used. For instance, in instruction `INCB [ESI+6]` a BYTE memory variable is incremented.
  3. If operand size is still not recognized, modifier DATA= is consulted, as stored in `II.MfgExplicit:iiMfgDATA_Mask`, for instance `INC [Symbol],DATA=WORD`.
  4. When instruction uses no general-purpose register, no suffix and no DATA= modifier, operand size will be determined from symbol type in EXP.Sym, if a symbol occurs in memory operand. E.g. in `INC [DwordSymbol]` 32 bit DWORD is incremented, on assumption that DwordSymbol was defined as `DwordSymbol DD value`.
     If FloatingPoint=ON and one of operands is memory variable, like `FADD ST0,[DwordSymbol]` , size is determined from that type and not from FP register.
     If StreamingSIMD=ON, operation-size prefix OTOGGLE is not requested, even when 32bit register is used in 16bit mode or vice versa.
  5. If operand size is still not recognized, as in `JMPN [ESI]`, and UseSegment=ON, operand size is adopted from the current segment width.
  6. If operand size could not be determined by any method previously mentioned, error E6730 is reported, e.g. in `INC [EBX]`.
  Operand size is by default determined from the first two operands. Expanding IiDataSize with hint `Operand1` asks the macro to determine operand size from operand 1 only. This happens in instructions like `SHL [WordVar],CL` which have operand size Word, although operand 2 is 8bit register.
Input
  Hint is enumerated argument which may have one of theese options:
  - BYTE: Operand size will be forced to 8 bits.
  - WORD: Operand size will be forced to 16 bits.
  - DWORD: Operand size will be forced to 32 bits.
  - QWORD: Operand size will be forced to 64 bits.
  - TBYTE: Operand size will be forced to 80 bits.
  - OWORD: Operand size will be forced to 128 bits.
  - YWORD: Operand size will be forced to 256 bits.
  - ZWORD: Operand size will be forced to 512 bits.
  - Operand1: Operand size will be determined from the first operand only.
  - Operand2: Operand size will be determined from the second operand only.
  - Operand3: Operand size will be determined from the third operand only.
  - If omitted (default): Operand size will be determined from register/memory in Operand1 and Operand2.
  SpecifyMem=ON If set to OFF, mem in EDX will not be replaced with more specific Intel encoding m8, m16 etc.
  UseSegment=OFF. If set to ON and operand size not specified otherwise, segment width will be used.
  AllowQword=OFF. If set to ON, E6732 is not reported when Qword operand size is detected in non 64bit mode.
  FloatingPoint=OFF. If set to ON, mem in EDX can be rewritten to m80 when the operand type is TBYTE. Prefixes OTOGGLE and REX.W are not requested.
  StreamingSIMD=OFF. If set to ON, it will suppress request for OTOGGLE prefix.
  EDI= pointer to II.
  EBX= pointer to STM.
  EDX= contains operand types in Intel encoding.
Output
  One flag in `[EDI+II.MfgEmitted]:iiMfgDATA_Mask]` is set. `[EDI+II.MfgAllowed:iiMfgDATA_Mask` is set.
  Implicit prefixes REX.W and OTOGGLE will be requested in `[EDI+II.PfxEmitted]` if necessary.
  Byte(s) in EDX which specified general operand type mem will be rewritten to more specific m8, m16, m32, m64. Other registers are unchanged.
  `II.MfgImplicit` may be updated, `II.PfxEmitted` requested.
Error
  Errors E6730, E6732 are reported with macro Msg. `[EBX+STM.Status]:stmOperationPresent` is reset on error.
Example
  IiDataSize Operand1, UseSegment=ON, SpecifyMem=OFF
Expanded in
  IiHandlers.
See also

    IiDataSize %MACRO Hint, AllowQword=OFF, SpecifyMem=ON, UseSegment=OFF, FloatingPoint=OFF, StreamingSIMD=OFF,
           %HintValue %SETA 0 ; Combined operand which will be passed to runtime proc.
     %if "%Hint"=="BYTE"||"%Hint"=="WORD"||"%Hint"=="DWORD"||"%Hint"=="QWORD"||"%Hint"=="OWORD"||"%Hint"=="YWORD"||"%Hint"=="ZWORD"
             %HintValue %SETA iiMfgDATA_%Hint
           %ENDIF
           %IF "%Hint"=="Operand1"
             %HintValue %SETA %HintValue | iiOsUseOperand1
           %ENDIF
           %IF "%Hint"=="Operand2"
             %HintValue %SETA %HintValue | iiOsUseOperand2
           %ENDIF
           %IF "%Hint"=="Operand3"
             %HintValue %SETA %HintValue | iiOsUseOperand3
           %ENDIF
           %IF %HintValue=0 ; If none of the options above applied.
             %HintValue %SETA iiOsUseOperand1 + iiOsUseOperand2 ; Default.
           %ENDIF
           %IF %HintValue=0 && "%Hint" !=== ""
             %ERROR Id=5875,'Invalid IiDataSize operand "%Hint" in %^PROC.'
           %ENDIF
           %IF "%AllowQword" !== "OFF"
             %HintValue %SETA %HintValue | iiOsAllowQword
           %ENDIF
           %IF "%SpecifyMem" !== "ON"
             %HintValue %SETA %HintValue | iiOsSpecifyMemOff
           %ENDIF
           %IF "%UseSegment" !== "OFF"
             %HintValue %SETA %HintValue | iiOsUseSegment
           %ENDIF
           %IF "%FloatingPoint" !== "OFF"
             %HintValue %SETA %HintValue | iiOsFloatingPoint
           %ENDIF
           %IF "%StreamingSIMD" !== "OFF"
             %HintValue %SETA %HintValue | iiOsStreamingSIMD
           %ENDIF
           PUSHD %HintValue
           CALL IiDataSize@RT:
           JSt [EBX+STM.Status],stmOperationPresent,.cont%.:
           RET                                       ; Abort instruction handler when E6730 or E6732 was reported in IiDataSize@RT.
     .cont%.:

    IiDataSize@RT:  PROC1
          PUSH EAX,ECX,ESI,EBP
           MOV EBP,[ESP+20]                          ; Load parameter Hint.
           IiAllowModifier DATA
           MOV EAX,EBP
           JSt EAX,iiMfgDATA_Mask,.30:               ; If iiMfgDATA_Mask flag determined explicitly by Hint, we're done.
           JNSt EBP,iiOsUseOperand3,.10:             ; Skip getting the size from operand 3.
          ; Determine operand size from II.Operand3.
           LEA ESI,[EDI+II.Operand3]
           CALL .SizeFromOperandESI:
           JMP .30:                                  ; Operand1 and Operand2 are not consulted when Hint is Operand3.

    .SizeFromOperandESI PROC1                        ; Input: ESI=^EXP with operand, EBP=Hint.
            MOV ECX,[ESI+EXP.Status]                 ; Output: EAX=iiMfgDATA_Mask+iiPpgOperSizeByReg+iiPpgOperSizeBySss,  ECX=destroyed.
            XOR EAX,EAX
            Dispatch CL,'R','M'
     .Ret:  RET                                      ; Operand size cannot be determined by this operand.
    .M:     MOV ECX,[ESI+EXP.Sym]
            JECXZ .Ret:
            MOV ECX,[ECX+SYM.Status]
            Dispatch CL,'B','U','W','D','Q','T','O','Y','Z'
            RET
    .R:     Invoke IiGetRegFamily::, [ESI+EXP.Low]   ; Returns registers family in EAX.
            MOV ECX,EAX
            MOV EAX,iiPpgOperSizeBySss
            CMP CL,iiReg_SEG
            JE .Ret:                                 ; Segment register does not specify the operand size.
            JSt EBP,iiOsFloatingPoint,.Ret:          ; FPR does not specify the operand size.
            MOV EAX,iiPpgOperSizeByReg
            Dispatch CL,iiReg_R08,iiReg_R16,iiReg_R32,iiReg_R64, \
             iiReg_FPR, iiReg_XMM, iiReg_YMM, iiReg_ZMM
            XOR EAX,EAX
            RET                                      ; Operand size cannot be determined by this register.
    .iiReg_R08:
    .B:     SetSt EAX,iiMfgDATA_BYTE
            RET
    .iiReg_R16:
    .U:
    .W:     SetSt EAX,iiMfgDATA_WORD
            RET
    .iiReg_R32:
    .D:     SetSt EAX,iiMfgDATA_DWORD
            RET
    .iiReg_FPR:
    .T:     SetSt EAX,iiMfgDATA_TBYTE
            RET
    .iiReg_R64:
    .Q:     SetSt EAX,iiMfgDATA_QWORD
            RET
    .iiReg_XMM:
    .O:    SetSt EAX,iiMfgDATA_OWORD
           RET
    .iiReg_YMM:
    .Y:    SetSt EAX,iiMfgDATA_YWORD
           RET
    .iiReg_ZMM:
    .Z:    SetSt EAX,iiMfgDATA_ZWORD
           RET
        ENDP1 .SizeFromOperandESI

     .10:  JNSt EBP,iiOsUseOperand2,.20:            ; Skip getting the size from operand 2.
           ; Determine operand size from II.Operand2.
           LEA ESI,[EDI+II.Operand2]
           CALL .SizeFromOperandESI:
           PUSH EAX
             RstSt EAX,iiMfgDATA_Mask               ; Those bits do not go to II.Ppg.
             SetSt [EDI+II.Ppg],EAX
           POP EAX
           JSt EAX,iiPpgOperSizeByReg,.30:          ; If determined by register, we're done.
           MOV ECX,EAX                              ; Temporary store operand size by 2. operand.
     .20:  MOV ESI,EBP                              ; Retrieve Hint again.
           JNSt ESI,iiOsUseOperand1, .25:           ; Skip getting the size from operand 1.
          ; Determine operand size from II.Operand1.
           LEA ESI,[EDI+II.Operand1]
           PUSH ECX                                 ; Keep datasize from Operand2, if any.
             CALL .SizeFromOperandESI:
           POP ECX
           PUSH EAX
             RstSt EAX,iiMfgDATA_Mask               ; Those bits do not go to II.Ppg.
             SetSt [EDI+II.Ppg],EAX
           POP EAX
           JSt EAX,iiPpgOperSizeByReg,.30:          ; If size is determined by register, we're done.
           OR ECX,EAX                               ; Accumulate flags size hints of first two operands to ECX.
     .25:  MOV EAX,[EDI+II.MfgSuffix]               ; If not determined by register, try suffix.
           JSt EAX,iiMfgDATA_Mask,.30:              ; If determined by suffix, we're done.
           MOV EAX,[EDI+II.MfgExplicit]             ; If not determined by register and suffix, try DATA= modifier.
           JSt EAX,iiMfgDATA_Mask,.30:              ; If determined by modifier, we're done.
           MOV EAX,ECX                              ; If not determined by the register, suffix, modifier, use memory datatype in ECX.
     .30:  AND EAX,iiMfgDATA_Mask
           JNZ .35:                                 ; If determined by memory type, we're done.
           JNSt EBP,iiOsFloatingPoint,.31:
           ; If FloatingPoint=ON and no operand is [memory], use register width.
           CMPB [ESI+II.Operand1],'M'
           JE .31:
           CMPB [ESI+II.Operand2],'M'
           JE .31:
           CMPB [ESI+II.Operand3],'M'
           JE .31:
           MOV EAX,iiMfgDATA_TBYTE                   ; If FloatingPoint=ON, use register width in reg-reg operations.
           JMP .35:
     .31:  JSt EBP,iiOsUseSegment,.33:               ; If not operand size not specified yet, use segment width.
    .E6730:Msg PgmStatus=pgmLastPass,'6730'          ; Operand size could not be determined, please use DATA= modifier.
           JMPN .Err:
     .33:  MOV ECX,[EDI+II.SssStatus]
           AND ECX,sssWidthMask
           SHR ECX,15                                ; Convert sssWidthMask to iiMfgDATA_Mask.
     .34:  OR EAX,ECX                                ; Use segment width as operand size.
          ; JMP .35:
     .35:  OR [EDI+II.MfgEmitted],EAX                ; Effective operand size finally set.
           MOV ESI,EBP                               ; Hint.
           JSt EBP,iiOsFloatingPoint,.60:            ; In FP instruction the operand size does not use OTOGGLE and REX.W.
           JSt [EDI+II.MfgEmitted],iiMfgDATA_TBYTE,.E6730: ; TBYTE is allowed in FP instructions only.
           ; Require implicit prefixes REX.W and OTOGGLE, if necessary.
           MOV ECX,[EDI+II.SssStatus]                ; Segment width.
           JNSt ECX,sssWidth64,.40:
           JSt EAX,iiMfgDATA_QWORD,.REX.W            ; 64bit operand in 64bit segment.
           JSt EAX,iiMfgDATA_WORD,.OTOGGLE           ; 16bit operand in 64bit segment.
     .40:  JNSt ECX,sssWidth32,.50:
           JSt EAX,iiMfgDATA_WORD,.OTOGGLE           ; 16bit operand in 32bit segment.
           JSt ESI,iiOsAllowQword,.60:
           JSt EAX,iiMfgDATA_QWORD,.E6732:           ; 64bit operand in 32bit segment.
     .50:  JNSt ECX,sssWidth16,.60:
           JSt EAX,iiMfgDATA_DWORD,.OTOGGLE:         ; 32bit operand in 16bit segment.
           JSt ESI,iiOsAllowQword,.60:
           JSt EAX,iiMfgDATA_QWORD,.E6732:           ; 64bit operand in 16bit segment.
           JMP .60:
    .E6732:Msg '6732' ; Required operand-size 64 can be used in 64bit segment only.
    .Err:  RstSt [EBX+STM.Status],stmOperationPresent ; Cancel the instruction.
           JMP .90:
    .REX.W:SetSt [EDI+II.PfxEmitted],iiPfxREX.W
           JMP .60:
    .OTOGGLE:JSt ESI,iiOsStreamingSIMD,.60:
           SetSt [EDI+II.PfxEmitted],iiPfxOTOGGLE
     .60:  ; EAX is now the effective operand width encoded as iiMfgDATA_Mask.
           ; EDX may have Intel-encoded memory operand with unspecified width (mem) in some of its bytes.
           ; mem will be replaced with m8, m16, m32, m64, m80, m128, m256, m512.
           JSt EBP,iiOsSpecifyMemOff,.90:             ; Do not replace mem if SpecifyMem=OFF.
           MOV ECX,4                                  ; Number of bytes representing operands in EDX.
           MOV AL,m32
           JSt EAX,iiMfgDATA_DWORD,.70:
           MOV AL,m16
           JSt EAX,iiMfgDATA_WORD,.70:
           MOV AL,m64
           JSt EAX,iiMfgDATA_QWORD,.70:
           MOV AL,m80
           JSt EAX,iiMfgDATA_TBYTE,.70:
           MOV AL,m8
           JSt EAX,iiMfgDATA_BYTE,.70:
           MOV AL,m128
           JSt EAX,iiMfgDATA_OWORD,.70:
           MOV AL,m256
           JSt EAX,iiMfgDATA_YWORD,.70:
           MOV AL,m512
           JSt EAX,iiMfgDATA_ZWORD,.70:
           MOV AL,mem
     .70:  CMP DL,mem
           JNE .80:
           MOV DL,AL
     .80:  ROR EDX,8
           DEC ECX
           JNZ .70:                                   ; Repeat four times.
     .90: POP EBP,ESI,ECX,EAX
          RET 4
        ENDPROC1 IiDataSize@RT:
      %ENDMACRO IiDataSize

↑ IiRemoveOTOGGLE
  Macro IiRemoveOTOGGLE removes unnecessary prefix OTOGGLE which might have been requested by IiAssemble.
Input
  EDI= pointer to II.
Output
  Request for OTOGGLE is reset in `[EDI+II.PfxEmitted]`.

    IiRemoveOTOGGLE %MACRO
         RstSt [EDI+II.PfxEmitted],iiPfxOTOGGLE
       %ENDMACRO IiRemoveOTOGGLE

↑ IiRemoveREXR
  Macro IiRemoveREXR removes unnecessary prefix REX.R which might have been requested by macro IiDataSize. Other REX flags than .R are not removed.
  It is invoked in handlers of instructions promoted to 64bit, such as PUSH, POP.
Input
  EDI= pointer to II.
Output
  Prefix REX.R=0x44 replaced with zero in `[EDI+II.PfxEmitted]`.

    IiRemoveREXR %MACRO
        ORD [EDI+II.Ppx],iiPpxRemoveREX.R + iiPpxRemoveREX
       %ENDMACRO IiRemoveREXR

↑ IiRemoveREXW
  Macro IiRemoveREXW removes unnecessary prefix REX.W which might have been requested by macro IiDataSize. Other REX flags than .W are not removed.
  It is invoked in handlers of instructions promoted to 64bit, such as PUSH, POP or whenever is REX.W handled in a special way.
  If used together with IiEmitPrefix REX.W in the same handler, the latter macro will prevail.
Input
  EDI= pointer to II.
Output
  Prefix REX.W=0x48 replaced with zero in `[EDI+II.PfxEmitted]`.

    IiRemoveREXW %MACRO
        ORD [EDI+II.Ppx],iiPpxRemoveREX.W + iiPpxRemoveREX
       %ENDMACRO IiRemoveREXW

↑ IiRequire Requirements
  Macro IiRequire specifies SIMD= and CPU= generation and features required by the instruction.
Input
  Requirements is a list of enumerated tokens:
  - CPU= values from %IiCpuList, e.g. `386,586,X64,`
  - SIMD= values from %IiSimdList, e.g. `SSE,SSE4.2,AVX512,`
  - CPU feature from %EaoptFeaList, e.g. `AMD,PROT,UNDOC`
  . Tokens must be in upper case, aliases are not supported.
  EDI= pointer to II.
Output
  Corresponding flags are set in `II.Cpu` and `II.Features`.
Example
  IiRequire 686,AMD,D3NOW
Comment
  Not all options need to be explicitly specified by this macro in instruction handlers, as they are implicitly requested by using certain registers and/or prefixes:
  - 386 if 32bit register or segment is used.
  - 386 if prefix FS, GS, ATOGGLE, OTOGGLE is used.
  - 686 if prefix OFTEN, SELDOM is used.
  - 686,TSX if prefix XACQUIRE, XRELEASE is used.
  - X64 if 64bit register or segment is used.
  - X64 if prefix REX is used.
  - X64 if SSE register above 15 is used.
  - FPU if FPU register ST0..ST7 is used.
  - MMX if MMX register MM0..MM7 is used.
  - SSE1 if SSE register XMM0..XMM7 is used.
  - AVX if SSE register YMM0..YMM7 is used.
  - AVX if encoded with VEX prefix.
  - AVX,XOP,AMD if encoded with XOP prefix.
  - AVX512,MVEX if encoded with MVEX prefix.
  - AVX512,EVEX if encoded with EVEX prefix.
  - AVX512 if mask register K0..K7 is used.
  - MPX if bound register BND0..BND3 is used.
  - PRIV if control, debug, test register is used.
Expanded in
  IiHandlers.
See also

    IiRequire %MACRO
        %IiCpu %SETA 0
        %IiFea %SETA 0
        %REPEAT
        %Illegal %SETB 1
      cpu %FOR %IiCpuList, %IiSimdList
            %IF "%1"==="%cpu"
              %Illegal %SETB 0
              %IiCpu %SETA %IiCpu | iiCPU_%cpu
              %EXITFOR ; Break the further list investigations when item found.
            %ENDIF
          %ENDFOR cpu
      fea %FOR %EaoptFeaList
            %IF "%1"==="%fea"
              %Illegal %SETB 0
              %IiFea %SETA %IiFea | iiFea_%fea
              %EXITFOR  ; Break the further list investigations when item found.
            %ENDIF
          %ENDFOR fea
          %IF %Illegal
            %ERROR Id=5876,'Illegal IiRequire option "%1".'
          %ENDIF
          %SHIFT ; Take the next macroargument.
        %UNTIL "%1"===""
        %IF %IiCpu
          OR [EDI+II.Cpu],%IiCpu,DATA=DWORD,IMM=DWORD
        %ENDIF
        %IF %IiFea
         OR [EDI+II.Features],%IiFea,DATA=DWORD,IMM=DWORD
        %ENDIF
      %ENDMACRO IiRequire

↑ IiStringDestination OperandNr, AllowSeg=OFF
  Macro IiStringDestination will check if the specified memory operand is string instruction destination and prematurely aborts instruction handler if not.
  Valid string destination is rDI, for instance `[ES:DI]`. Only ES can be used as segment override when AllowSeg=OFF. This macro will request for ATOGGLE if necessary, and for SEGxS when AllowSeg=ON.
Input
  OperandNr is one of enumerated values `Operand1, Operand2`.
  AllowSeg=OFF If left OFF, only ES prefix is allowed.
  EDI= pointer to II (evaluated operands).
Output
  -
On error
  -
Example
  IiStringDestination Operand2
Expanded in
  IiHandlers.
See also
  IiStringSource.

    IiStringDestination %MACRO OperandNr, AllowSeg=OFF
           %IF "%OperandNr[1..7]" !== "Operand"
              %ERROR Id=5877,'Wrong argument provided for macro IiStringDestination.'
              %EXITMACRO IiStringDestination
           %ENDIF
           %IF "%AllowSeg"=="OFF"
              PUSHD %OperandNr[8] * SIZE#EXP
           %ELSE
              PUSHD %OperandNr[8] * SIZE#EXP + iiSdAllowSeg
           %ENDIF
           CALL IiStringDestination@RT:
    IiStringDestination@RT: PROC1
    %IiSdParam %SET ESP+12
         PUSH EAX,EDX
          MOV EAX,[%IiSdParam] ; 20,40,60,80.
          AND EAX,0x000000FF ; Mask off iiSdAllowSeg flag, if present.
          LEA EDX,[EDI+II.Operand1-SIZE#EXP+EAX] ; ^EXP with %OperandNr. Its must be 'M' type.
          MOV EAX,expAwidth
          AND EAX,[EDX+EXP.Status]
          JZ .50: ; If address-size is not specified by base register width, keep default segment width. No ATOGGLE required.
          SHL EAX
          JC .20: ; If r64 or r32 used in [mem].
          JSt [EDI+II.SssStatus],sssWidth16,.50:
          JSt [EDI+II.SssStatus],sssWidth32,.ATOGGLE:
          Msg '6733' ; Required address width 16 cannot be used in 64bit segment.
          JMP .Abort:
     .20: SHL EAX
          JC .30: ; If r64 used in [mem].
          JSt [EDI+II.SssStatus],sssWidth16|sssWidth64, .ATOGGLE:
          JMP .50:
     .30: JSt [EDI+II.SssStatus],sssWidth64,.50:
          Msg '6731' ; Required address width 64 can be used in 64bit segment only.
    .Abort:ADD ESP,16
          RET ; Abort the parent handler.
    .ATOGGLE: SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE
     .50: MOV EAX,[EDX+EXP.Status]
          JNSt EAX,expSegmPres,.70:
          ; Segment register present in operand.
          JSt [%IiSdParam],iiSdAllowSeg, .55:
          ; Only ES is allowed.
          JNSt EAX,expSegm, .70: ; If ordinal=0 (ES), continue.
    .E6758:Msg '6758' ; Wrong string destination specified. Only [ES:rDI] is acceptable.
          JMP .Abort:
     .55: AND EAX,expSegm ; Any segment register is allowed, default is DS.
          SHR EAX,24 ; EAX is now Sreg ordinal 0..5.
          CMP AL,3
          JE .70: ; Ignore implicit segment-register DS.
          JNA .60:
          IiRequire 386 ; FS or GS requires 386.
     .60: ADD AL,20 ; EAX is now 20..25, i.e. iiPfxSEGES..iiPfxSEGGS.
          BTS [EDI+II.PfxEmitted],EAX ; Request for segment override.
     .70: MOV EAX,[EDX+EXP.Status]
          JSt EAX,expScalePres,.E6758:
          JNSt EAX,expBasePres, .80:
          JSt EAX,expIndexPres,.E6758:
          SHL EAX,4 ; Move base to index position in EXP.Status.
          JMP .85:
     .80: JNSt EAX,expIndexPres,.90:
     .85: AND EAX,expIndex
          CMP EAX,0x00700000
          JNE .E6758: ; If not rDI.
     .90:POP EDX,EAX
         RET 4
        ENDPROC1 IiStringDestination@RT:
       %ENDMACRO IiStringDestination

↑ IiStringSource OperandNr
  Macro IiStringSource will check if the specified memory operand is string instruction source and prematurely aborts instruction handler if not.
  Valid string source is rSI with optional segment override, for instance `[ES:SI]`. This macro will request for segment override and request for ATOGGLE and segment prefix if necessary.
Input
  OperandNr is one of enumerated values `Operand1, Operand2`.
  EDI= pointer to II (evaluated operands).
Output
  -
On error
  -
Example
  IiStringSource Operand2
Expanded in
  IiHandlers.
See also
  IiStringDestination.

    IiStringSource %MACRO OperandNr
           %IF "%OperandNr[1..7]" !== "Operand"
              %ERROR Id=5878,'Wrong argument provided for macro IiStringSource.'
              %EXITMACRO IiStringSource
           %ENDIF
           PUSHD %OperandNr[8] * SIZE#EXP
           CALL IiStringSource@RT:
    IiStringSource@RT: PROC1
         PUSH EAX,EDX
          MOV EAX,[ESP+12] ; 20,40,60,80.
          LEA EDX,[EDI+II.Operand1-SIZE#EXP+EAX] ; ^EXP with %OperandNr. Its must be 'M' type.
          MOV EAX,expAwidth
          AND EAX,[EDX+EXP.Status]
          JZ .50: ; If address-size is not specified by base register width, keep default segment width. No ATOGGLE required.
          SHL EAX
          JC .20: ; If r64 or r32 used in [mem].
          JSt [EDI+II.SssStatus],sssWidth16,.50:
          JSt [EDI+II.SssStatus],sssWidth32,.ATOGGLE:
          Msg '6733' ; Required address width 16 cannot be used in 64bit segment.
          JMP .Abort:
     .20: SHL EAX
          JC .30: ; If r64 used in [mem].
          JSt [EDI+II.SssStatus],sssWidth16|sssWidth64, .ATOGGLE:
          JMP .50:
     .30: JSt [EDI+II.SssStatus],sssWidth64,.50:
          Msg '6731' ; Required address width 64 can be used in 64bit segment only.
    .Abort:ADD ESP,16
          RET ; Abort the parent handler.
    .E6757:Msg '6757' ; Wrong string source specified. Only [rS:rSI] is acceptable.
          JMP .Abort
    .ATOGGLE: SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE
     .50: MOV EAX,[EDX+EXP.Status]
          JNSt EAX,expSegmPres,.70:
          AND EAX,expSegm
          SHR EAX,24 ; EAX is now Sreg ordinal 0..5.
          CMP AL,3
          JE .70: ; Ignore implicit segment-register DS.
          JNA .60:
          IiRequire 386
     .60: ADD AL,20 ; EAX is now 20..25, i.e. iiPfxSEGES..iiPfxSEGGS.
          BTS [EDI+II.PfxEmitted],EAX ; Request for segment override.
     .70: MOV EAX,[EDX+EXP.Status]
          JSt EAX,expScalePres,.E6757:
          JNSt EAX,expBasePres,.80:
          JSt EAX,expIndexPres,.E6757:
          SHL EAX,4 ; Move base to index position in EXP.Status.
          JMP .85:
     .80: JNSt EAX,expIndexPres,.90:
     .85: AND EAX,expIndex
          CMP EAX,0x00600000
          JNE .E6757: ; If not rSI.
     .90:POP EDX,EAX
         RET 4
        ENDPROC1 IiStringSource@RT:
       %ENDMACRO IiStringSource

↑ IiSuffixed Mnemo, Suffix, Category=g
  Macro IiSuffixed is expanded in handlers of machine instructions which have a suffix appended to its mnemonic to specify operand size or distance of jump/call.
  Macro will set corresponging flag in [EDI+II.MfgSuffix] and jump to the parent's unsuffixed handler.
Input
  Mnemo is instruction mnemonic without suffix.
  Suffix in one of enumerated letters `B W D Q` or `S N F`.
  Category in one of enumerated letters `%IiCategoryList`.
  EDI= pointer to II.
Output
  II.MfgSuffix is modified.
Examples
  IiSuffixed ADC,D
  IiSuffixed CRC32,Q,Category=p
Expanded in
  IigHandlers.
See also

    IiSuffixed %MACRO Mnemo, Suffix, Category=g
     %Flag %SET
         %IF "%Suffix"==="B"
           %Flag %SET iiMfgDATA_BYTE
         %ENDIF
         %IF "%Suffix"==="W"
           %Flag %SET iiMfgDATA_WORD
         %ENDIF
         %IF "%Suffix"==="D"
           %Flag %SET iiMfgDATA_DWORD
         %ENDIF
         %IF "%Suffix"==="Q"
           %Flag %SET iiMfgDATA_QWORD
         %ENDIF
         %IF "%Suffix"==="S"
           %Flag %SET iiMfgDIST_SHORT
         %ENDIF
         %IF "%Suffix"==="N"
           %Flag %SET iiMfgDIST_NEAR
         %ENDIF
         %IF "%Suffix"==="F"
           %Flag %SET iiMfgDIST_FAR
         %ENDIF
         %IF "%Flag"===""
           %ERROR Id=5879,'Invalid %Mnemo suffix "%Suffix".'
         %ELSE
            SetSt [EDI+II.MfgSuffix],%Flag
            JMP Ii%Category%Mnemo:
         %ENDIF
        %ENDMACRO IiSuffixed

      ENDHEAD ii ; End of module interface.

↑ IiAssemble Stm
  Procedure IiAssemble will assemble and emit one machine instruction.
  It is responsible for processing of explicit prefixes and instruction modifiers, then it evaluates instruction operands, calls the corresponding instruction handler with data prepared in II structure. Finally it invokes IiFlush to emit assembled data from II to statement buffers.
Input
  Stm is a pointer to parsed statement with machine instruction.
Output
  Symbol created if requested, statement is ready for list and flush.
Error
  Errors are reported with macro Msg. `Stm.Status:stmOperationPresent` is reset on error.
See also
  IiHandlers.
Invokes
  ExpAlign ExpConvertToNumber ExpEval ExpReportError IiFlush IiGetRegFamily SssCheckPurpose SssGetSegm StmGetIiModifiers SymCreate
Invoked by
  ExpStoreInstr IiAssembleMultiop StmExecute

    IiAssemble Procedure Stm
    IiExp    LocalVar Size=SIZE#II                   ; Allocation of II object which will be submitted to instruction handler.
    IiFormat LocalVar                                ; Operands specification: 0..4 bytes in Intel encoding submitted to handler in EDX.
    IiCpuRegProp  LocalVar                           ; CPU requirements requested by registers used in instruction.
          ; Initialize II object.
          ClearLocalVar
          MOV EBX,[%Stm]
          LEA EDI,[%IiExp]
          MOVB [EBX+STM.Status],'I'                  ; TYPE#Symbol, if a label is present in this statement.
          XOR EAX,EAX
          NOT EAX
          MOV [EDI+II.Disp8EVEX],EAX
          MOV [EDI+II.Disp8MVEX],EAX
          SetSt [EDI+II.PfxAllowed],iiPfxOTOGGLE+iiPfxATOGGLE
         ; Get the code section.
          MOV ESI,[EBX+STM.Section]
          TEST ESI
          JZ .05:
          JNSt [Ea.Eaopt.Status::],eaoptAUTOSEGMENT,.15:
          JSt [ESI+SSS.Purpose],sssPurposeCODE,.20:  ; OK if current section is CODE.
     .05: Invoke SssGetSegm::,[EBX+STM.Program],sssPurposeCODE
          JNC .10:
          Msg '3201',Dict_PurposeCODE::             ; No segment with PURPOSE=!1S found.
          MOV EAX,[EBX+STM.Section]
     .10: MOV ESI,EAX                                ; The new section.
          SetSt [EBX+STM.Flags],stmtNotBSS
     .15: Invoke SssCheckPurpose::,ESI,sssPurposeCODE; Warn if not code section.
     .20: MOV [EBX+STM.Section],ESI
          TEST ESI
          JZ .23:
          MOV EAX,[ESI+SSS.Status]
          MOV EDX,[EBX+STM.Program]
          MOV [EDI+II.SssStatus],EAX
          MOV EAX,[EDX+PGM.Pgmopt.Status]
          MOV [EDI+II.PgmoptStatus],EAX
     ; Evaluate modifiers, alignment and aligned offset to the statement EBX.
          XOR EAX,EAX
          NOT EAX
          MOV [EDI+II.MfgAllowed],EAX                ; Temporarily allow all instruction modifiers,
          MOV [EDI+II.MfxAllowed],EAX                ;  as we don't want any warnings yet.
          Invoke StmGetIiModifiers::,EBX,EDI
          XOR EAX,EAX
          MOV [EDI+II.MfgAllowed],EAX                ; Disallow back all modifiers, let the handler allow only relevant ones.
          MOV [EDI+II.MfxAllowed],EAX
          MOV EAX,[EDI+II.Align]                     ; Explicitly specified in an instruction, e.g.  XOR EAX,EAX,ALIGN=16
          MOV EDX,[ESI+SSS.OrgHigh]
          MOV ESI,[ESI+SSS.OrgLow]
          Invoke ExpAlign::,ESI,EAX,0
          MOV [EBX+STM.AlignBytes],ECX
          ADD ESI,ECX
          ADC EDX,0
          MOV [EBX+STM.OffsetLow],ESI                ; Aligned statement origin.
          MOV [EBX+STM.OffsetHigh],EDX
     .23: ; Evaluate legacy prefixes.
          MOV ECX,[EBX+STM.NrOfPrefixes]
          LEA ESI,[EBX+STM.Prefix1Data]
          LEA EDX,[EDI+II.PfxCode+0]
          JECXZ .30:
     .25: MOV EAX,[ESI]
          MOV [EDX],AL                               ; Prefix operation code.
          XOR AL,AL
          OR [EDI+II.PfxExplicit],EAX
          AND EAX,iiCpuDictPfxMask
          SetSt [EDI+II.Cpu],EAX                     ; CPU generation required by using a prefix.
          MOV EAX,iiFeaDictPfxMask
          AND EAX,[ESI]
          SetSt [EDI+II.Features],EAX                ; CPU features required by using a prefix.
          ADD ESI,12                                 ; Skip to the next prefix in a statement.
          INC EDX                                    ; Skip to the next II prefix code.
          LOOP .25:
     .30: ; Evaluate ordinal operands.
          BufferRetrieve [EBX+STM.OrdBuffer]
          TEST ECX
          JZ .50:                                    ; ESI,ECX is Ptr+Size of source ordinal operand in statement, e.g. AL or [EBX+8].
          LEA EDX,[EDI+II.Operand1]                  ; Expression of the ordinal operand. Start with the first one.
     .35: PUSHAD                                     ; The loop between .35: and .50: evaluates all nonempty ordinal operands.
            MOV ECX,[ESI+4]                          ; Size of source operand.
            MOV ESI,[ESI+0]
            Invoke ExpEval::,EDX,ESI,ECX,EBX
            Msg cc=PE,'2210'                         ; Precision lost in calculation with FP number rounded to integer.
            Invoke ExpReportError::,EDX              ; If error occured in operand.
            Invoke ExpConvertToNumber::,EDX          ; In case of 'G' (character constant) convert it to number.
            MOV EAX,[EDX+EXP.Status]                 ; In case of VSIB addressed memory is the LSB modified by 0x80 (=bit V').
            SUB ECX,ECX
            BTR EAX,7                                ; expVbit4 - is vector indexregister above 15 used?
            JNC .38:
            SetSt [EDI+II.Ppx],iiPpxV` + iiPpxMEVEXonly
            MOV [EDX+EXP.Status],EAX                 ; Remove 7.bit from expression type (for dispatching purpose).
     .38:   Dispatch AL,'R','N','A','M','F','P',0x23
            Msg '7510',EAX                           ; Invalid operand type "!1Z".
    .0x23:  RstSt [EBX+STM.Status],stmOperationPresent ; Invalidate the instruction on error (AL='#').
            JMP .45:                                 ; Go to the next operand.
    .R:     ; Operand is a register.
            MOV ECX,[EDX+EXP.Low]                    ; DictRegisters.Data
            MOV EAX,iiCpuDictRegMask
            AND EAX,ECX
            SetSt [EDI+II.Cpu],EAX                   ; Add CPU and SIMD generation required by using the register.
            JNSt EAX,iiCPU_AVX512,.R3:
            MOV EAX,iiReg_KRG
            AND EAX,ECX
            CMP EAX,iiReg_KRG
            JE .R3:                                  ; Mask register does not necessarily evocate EVEX/MVEXonly.
            SetSt [EDI+II.Ppx],iiPpxMEVEXonly
       .R3: MOV EAX,iiFeaDictRegMask
            AND EAX,ECX
            SetSt [EDI+II.Features],EAX              ; Add CPU features required by using the register.
            JNSt ECX,iiRegREX,.R5:
            SetSt [EDI+II.PfxEmitted],iiPfxREX       ; Handle REX registers SPL,BPL, SIL, DIL.
       .R5: JNSt ECX,iiRegNoREX,.R7:
            SetSt [EDI+II.Ppg],iiPpgNoREX            ; Signalize that REX is not allowed to encode this register.
       .R7: Invoke IiGetRegFamily::, ECX
            JMP .40:
    .M:     ; Operand is memory variable, e.g. [EBX+4*ESI+Displ].
            MOV EAX,expVSIBfam
            AND EAX,[EDX+EXP.Status]
            IiAllowModifier DISP,SCALE
            SHL EAX,9                                ; Convert expVSIBfam to iiPpxVSIBfam.
            OR [EDI+II.Ppx],EAX
            MOV AL,mem
            JMP .40:
    .F:     ; Operand is far immediate, e.g. 0040h:0010h.
            MOV AL,far
            JMP .40:
    .P:     ; Operand is paragraph address, e.g. PARA# Main.
    .A:
    .N:     ; Operand is immediate (external, far, address or scalar number).
            MOV AL,imm
            ;JMP .40:
     .40:   ; Operand is evaluated, its type is in AL.
            SHL [%IiFormat],8,DATA=DWORD
            MOV [%IiFormat],AL
     .45: POPAD
          ADD EDX,SIZE#EXP                           ; Shift to EXP of the next operand in II.
          LEA EAX,[EDI+II.Operand4]
          CMP EDX,EAX
          JA .50:                                    ; More than four operands are not expected.
          ADD ESI,8
          SUB ECX,8
          JA .35:                                    ; Go to evaluate the next operand.
     .50: ; Let handler assemble the instruction to II structure.
          JNSt [EBX+STM.Status],stmOperationPresent,.70: ; Abort assembly when the instruction was invalidated due to error in operands.
          MOV EDX,[%IiFormat]
          PUSH EBX,EBP,EDI
             CALL [EBX+STM.OperationData]            ; Call the instruction handler, e.g. IigMOV:.
          POP EDI,EBP,EBX
          JNSt [EBX+STM.Status],stmOperationPresent,.70: ; Abort assembly when the instruction was invalidated in handler.
          ; Flush the emitted code and relocations from statement to section.
          Invoke IiFlush,EDI,EBX
          JSt [EBX+STM.Status],stmOperationPresent,.85: ; If not invalidated in IiFlush.
     .70: ; Abort assembly when the instruction was invalidated.
          BufferClear [EBX+STM.EmitBuffer]
          BufferClear [EBX+STM.RelocBuffer]
     .85: BufferRetrieve [EBX+STM.EmitBuffer]
          MOV [EBX+STM.Size],ECX
          JNSt [EBX+STM.Status],stmLabelPresent,.90:
          ; Create a symbol if the statement was labeled.
          MOV EAX,stmLabelIsPublic
          AND EAX,[EBX+STM.Status]
          OR  EAX,symDefined
          Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
     .90:EndProcedure IiAssemble

↑ IiAssembleMultiop Stm
  IiAssembleMultiop submits multiple operands of instructions `INC*, DEC*, PUSH*, POP*` to IiAssemble one by one and then links emitted code and relocations to original statement %Stm.
  The list of multiop instructions is specified by StmMultiop?.
Input
  Stm Parsed statement with multiop instruction.
Output
  Stm is executed and ready for listing and flushing to section.
Error
  Errors are reported with macro Msg.
See also
  IiAssemble, StmMultiop?.
Invokes
  EaBufferRelease EaBufferReserve IiAssemble SymCreate
Invoked by
  ExpStoreInstr StmExecute
Tested by
  t3192 t3196 t3284 t3285

    IiAssembleMultiop Procedure Stm
    Stm1          LocalVar Size=SIZE#STM             ; Temporary statement with only one operand.
    moEmitBuffer  LocalVar                           ; Temporary Stm buffers.
    moRelocBuffer LocalVar
    moMsgBuffer   LocalVar
         Invoke EaBufferReserve::,IiAssembleMultiop
         MOV [%moEmitBuffer],EAX
         Invoke EaBufferReserve::,IiAssembleMultiop
         MOV [%moRelocBuffer],EAX
         Invoke EaBufferReserve::,IiAssembleMultiop
         MOV [%moMsgBuffer],EAX
         MOV EBX,[%Stm]
         LEA EDI,[%Stm1]
         MOVB [EBX+STM.Status],'I'
         CopyTo EDI,EBX,Size=SIZE#STM
         MOVD [EDI+STM.NrOfOrdinals],1
         RstSt [EDI+STM.Status],stmLabelPresent
         BufferRetrieve [EBX+STM.OrdBuffer]
         BufferClear [EDI+STM.OrdBuffer]
         BufferStore [EDI+STM.OrdBuffer],ESI,8
         Invoke IiAssemble,EDI                       ; The %1st operand is assembled twice, 1st pass only sets STM.AlignBytes and .Offset.
         MOV EAX,[EDI+STM.OffsetLow]
         MOV EDX,[EDI+STM.OffsetHigh]
         MOV [EBX+STM.OffsetLow],EAX
         MOV [EBX+STM.OffsetHigh],EDX
         MOV EAX,[EDI+STM.AlignBytes]
         MOV [EBX+STM.AlignBytes],EAX
     .10:PUSH ECX,ESI                                ; Loop which handles operands one by one and performs IiAssemble with them.
           BufferClear [EDI+STM.EmitBuffer]
           BufferClear [EDI+STM.RelocBuffer]
           BufferClear [EDI+STM.MsgBuffer]
           BufferClear [EDI+STM.OrdBuffer]
           BufferStore [EDI+STM.OrdBuffer],ESI,8
           SetSt [EDI+STM.Status],stmOperationPresent; Repair status which might have been invalidated by previous operations.
           MOV EAX,[EBX+STM.Size]                    ; Specify size emitted by previous instructions in statement, in case of Multiop.
           MOV [EDI+STM.Size],EAX
           Invoke IiAssemble,EDI
           BufferRetrieve [EDI+STM.RelocBuffer]
           CMP CL,SIZE#RELOC
           JL .40:                                   ; Skip when there are no absolute relocations in this instruction.
           XCHG EAX,ESI                              ; Temporary save pointer and size of (one or two) RELOC records to EAX,EDX.
           MOV EDX,ECX
           BufferRetrieve [%moEmitBuffer]
           ADD [EAX+RELOC.OrgLow],ECX                ; Patch relocation position with datasize of previous multiop instructions.
           CMP DL,SIZE#RELOC
           JNA .30:                                  ; Skip if not more than one RELOC record.
           ADD [EAX+SIZE#RELOC+RELOC.OrgLow],ECX     ; Patch 2nd relocation, e.g. in MOVD [$],$.
     .30:  BufferStore [%moRelocBuffer],EAX,EDX
     .40:  BufferRetrieve [EDI+STM.EmitBuffer]
           BufferStore [%moEmitBuffer],ESI,ECX
           BufferRetrieve [EDI+STM.MsgBuffer]
           BufferStore [%moMsgBuffer],ESI,ECX
           MOV EAX,[EDI+STM.Size]                    ; Size of this instruction.
           ADD [EBX+STM.Size],EAX
         POP ESI,ECX
         ADD ESI,8
         SUB ECX,8
         JNZ .10:                                    ; The next operand.
         BufferClear [EBX+STM.EmitBuffer]
         BufferRetrieve [%moEmitBuffer]
         BufferStore [EBX+STM.EmitBuffer],ESI,ECX
         BufferClear [EBX+STM.RelocBuffer]
         BufferRetrieve [%moRelocBuffer]
         BufferStore [EBX+STM.RelocBuffer],ESI,ECX
         BufferClear [EBX+STM.MsgBuffer]
         BufferRetrieve [%moMsgBuffer]
         BufferStore [EBX+STM.MsgBuffer],ESI,ECX
         Invoke EaBufferRelease::,[%moMsgBuffer]
         Invoke EaBufferRelease::,[%moRelocBuffer]
         Invoke EaBufferRelease::,[%moEmitBuffer]
         JNSt [EBX+STM.Status],stmLabelPresent,.90:
         MOV EAX,stmLabelIsPublic
         AND EAX,[EBX+STM.Status]
         OR  EAX,symDefined
         Invoke SymCreate::,EAX,[EBX+STM.LabelPtr],[EBX+STM.LabelSize],EBX
     .90:EndProcedure IiAssembleMultiop

↑ IiCpuToKeys Cpu, Fea, Buffer
  IiCpuToKeys converts CPU/SIMD generation and features from CPU requirements and CPU features encoding to plain text.
Input
  Cpu Combination of flags in CPU encoding.
  Fea Combination of features in CPU features encoding.
  Buffer Pointer to BUFFER for the output text, reserved by caller.
Output
  Buffer is filled with options in the form of keywords.
Error
  -
Example
  Invoke IiCpuToKeys, iiCPU_686+iiCPU_SSE4.1, iiFea_XOP, EBX ; Buffer EBX now contains text `CPU=686,SIMD=SSE4.1,XOP=ENABLED`.
See also
  StmGetIiModifiers, IiModifiersToKeys.
Invoked by
  IiFlush PseudoSEGMENT

    IiCpuToKeys Procedure Cpu, Fea, Buffer
         MOV EBX,[%Buffer]
         MOV EAX,[%Cpu]
     cpu %FOR X64,686,586,486,386,286,186
            JNSt EAX,iiCPU_%cpu, .EndCpu%cpu:
            BufferStore EBX,=B"CPU=%cpu,",8
            JMP .EndCPU:
           .EndCpu%cpu:
         %ENDFOR cpu
    .EndCPU:
    simd %FOR AVX512,AVX2,AVX,SSE4.2,SSE4.1,SSE4,SSSE3,SSE3,SSE2,SSE1
            JNSt EAX,iiCPU_%simd, .EndCpu%simd:
            %ValSize %SETS %simd
            BufferStore EBX,=B"SIMD=%simd,",%ValSize+6
            JMP .EndSIMD:
           .EndCpu%simd:
         %ENDFOR simd
    .EndSIMD:
         MOV EAX,[%Fea]
    fea  %FOR %EaoptFeaList
           JNSt EAX,iiFea_%fea, .EndFea%fea:
           %ValSize %SETS %fea
           BufferStore EBX,=B"%fea=ENABLED,",%ValSize+9
          .EndFea%fea:
         %ENDFOR fea
         BufferDecrement EBX ; Omit the last comma.
     EndProcedure IiCpuToKeys

↑ IiModifiersToKeys IiMfg, IiMfx, Buffer
  IiModifiersToKeys converts instruction modifiers from general and AVX encoding to plain text.
Input
  iiMfg Combination of flags in modifier encoding (general).
  iiMfx Combination of flags in modifier encoding (AVX).
  Buffer Pointer to BUFFER for the output text, reserved by caller.
Output
  Buffer is filled with modifiers in the form of keywords.
Error
  -
Example
  Invoke IiModifiersToKeys, iiMfgIMM_BYTE+iiMfgDATA_WORD, 0, EBX ; Buffer EBX now contains text `IMM=BYTE,DATA=WORD`.
See also
  StmGetIiModifiers, IiCpuToKeys.
Invoked by
  IiFlush
Tested by
  t5135

    IiModifiersToKeys Procedure IiMfg, IiMfx, Buffer
    Mval  LocalVar
          MOV EBX,[%Buffer]
          MOV ECX,[%IiMfx]
          MOV EDX,[%IiMfg]
          LEA EDI,[%Mval]
    IiMf2Keyword %MACRO Prefix,Key,Value ; Internal macro to store text "KEY=VALUE," to buffer EBX if it is set in ECX or EDX.
          %Val %SET %Value
          %IF "%Value"=="0"
            %Val %SET OFF
          %ENDIF
          %IF "%Value"=="1"
            %Val %SET ON
          %ENDIF
          %KeySize  %SETS %Key
          %ValSize  %SETS %Val
          %reg %SET ECX
          %IF "%Prefix" == "iiMfg"
            %reg %SET EDX
          %ENDIF
          JNSt %reg,%Prefix%Key[]_%Value, .Not%Key%Value:
          BufferStore EBX,=B"%Key=",%KeySize+1
          BufferStore EBX,=B"%Val,",%ValSize+1
         .Not%Key%Value:
     %ENDMACRO IiMf2Keyword ; End of internal macro definition.
      IiMf2Keyword iiMfg,CODE,SHORT
      IiMf2Keyword iiMfg,CODE,LONG
      IiMf2Keyword iiMfx,PREFIX,REX
      IiMf2Keyword iiMfx,PREFIX,XOP
      IiMf2Keyword iiMfx,PREFIX,VEX2
      IiMf2Keyword iiMfx,PREFIX,VEX3
      IiMf2Keyword iiMfx,PREFIX,MVEX
      IiMf2Keyword iiMfx,PREFIX,EVEX
      IiMf2Keyword iiMfx,EH,0
      IiMf2Keyword iiMfx,EH,1
      IiMf2Keyword iiMfx,MASK,K0
      IiMf2Keyword iiMfx,MASK,K1
      IiMf2Keyword iiMfx,MASK,K2
      IiMf2Keyword iiMfx,MASK,K3
      IiMf2Keyword iiMfx,MASK,K4
      IiMf2Keyword iiMfx,MASK,K5
      IiMf2Keyword iiMfx,MASK,K6
      IiMf2Keyword iiMfx,MASK,K7
      IiMf2Keyword iiMfx,ZEROING,0
      IiMf2Keyword iiMfx,ZEROING,1
      IiMf2Keyword iiMfx,ROUND,NEAR
      IiMf2Keyword iiMfx,ROUND,DOWN
      IiMf2Keyword iiMfx,ROUND,UP
      IiMf2Keyword iiMfx,ROUND,ZERO
      IiMf2Keyword iiMfx,SAE,0
      IiMf2Keyword iiMfx,SAE,1
      IiMf2Keyword iiMfg,DATA,BYTE
      IiMf2Keyword iiMfg,DATA,WORD
      IiMf2Keyword iiMfg,DATA,DWORD
      IiMf2Keyword iiMfg,DATA,QWORD
      IiMf2Keyword iiMfg,DATA,TBYTE
      IiMf2Keyword iiMfg,DATA,OWORD
      IiMf2Keyword iiMfg,DATA,YWORD
      IiMf2Keyword iiMfg,DATA,ZWORD
      IiMf2Keyword iiMfx,BCST,0
      IiMf2Keyword iiMfx,BCST,1
      BTR ECX,31 ; (iiMfxOPER_Used)  Other ECX contents is no longer necessary.
      JNC .OPERnotUsed:
      SHR ECX,28 ; Convert iiMfxOPER_Mask to a number 0..7.
      BufferStore EBX,=B"OPER=",5
      OR  CL,'0'
      MOV CH,','
      MOV [EDI],ECX
      BufferStore EBX,EDI,2
    .OPERnotUsed:
      JNSt EDX,iiMfgNESTING_OFF,.StandardNestingCheck:
      BufferStore EBX,=B"NESTINGCHECK=,",14
    .StandardNestingCheck:
      IiMf2Keyword iiMfg,DISP,BYTE
      IiMf2Keyword iiMfg,DISP,WORD
      IiMf2Keyword iiMfg,DISP,DWORD
      IiMf2Keyword iiMfg,DISP,QWORD
      IiMf2Keyword iiMfg,SCALE,SMART
      IiMf2Keyword iiMfg,SCALE,VERBATIM
      IiMf2Keyword iiMfg,DIST,SHORT
      IiMf2Keyword iiMfg,DIST,NEAR
      IiMf2Keyword iiMfg,DIST,FAR
      IiMf2Keyword iiMfg,ADDR,ABS
      IiMf2Keyword iiMfg,ADDR,REL
      IiMf2Keyword iiMfg,IMM,BYTE
      IiMf2Keyword iiMfg,IMM,WORD
      IiMf2Keyword iiMfg,IMM,DWORD
      IiMf2Keyword iiMfg,IMM,QWORD
      BufferDecrement EBX ; Omit the last comma.
     EndProcedure IiModifiersToKeys

↑ IiRelocSizeRIP Ii, Stm
  IiRelocSizeRIP examines necessary width of RIP-relative Immediate encoding in intrasegment (near or short) transfer instructions JMP, CALL, JMPE, JKZD, JNKZD. Procedure returns combination of modifier flags.
Input
  Ii is pointer to partially assembled II. II.Immediate must be filled with absolute target offset.
  Stm is pointer to STM.
Output
  EAX= `iiMfgDATA_Mask + iiMfgIMM_Mask` (Mask is Byte/Word/Dword).
Error
  -
See also
  IiFlush, IiImmSize.
Invokes
  ExpWidthSigned
Invoked by
  IigCALL IigJMP IigJcc IigLOOP IikJKZD IisJMPE

    IiRelocSizeRIP Procedure Ii, Stm
        MOV EDI,[%Ii]
        MOV EBX,[%Stm]
        ; Calculate instruction size to ESI.
        MOV ESI,3 ; Opcode of JKnZD is 3 or 4 bytes long.
        CMPD [EBX+STM.OperationData],IikJKZD::
        JE .10:
        CMPD [EBX+STM.OperationData],IikJKNZD::
        JNE .20:
    .10:JNSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX3, .40:
        INC ESI
        JMP .40:
    .20:MOV ESI,2 ; Opcode of JMPE is 2 bytes long (0x0FB8).
        CMPD [EBX+STM.OperationData],IisJMPE::
        JE .40:
        MOV ESI,1 ; Opcode of CALLN, JMPS, JMPN is 1 byte long.
    .40 ADD ESI,[EBX+STM.NrOfPrefixes] ; No explicit prefixes but OFTEN,SELDOM should be used with JMP, CALL, LOOP, JMPE, JKZD.
        INC ESI  ; First assume Imm encoding as ImmByte (short jump).
        MOVD [%ReturnEAX],iiMfgIMM_BYTE+iiMfgDATA_BYTE
        MOV EAX,[EBX+STM.OffsetLow]
        MOV EDX,[EBX+STM.OffsetHigh]
        ADD EAX,ESI
        ADC EDX,0 ; EDX:EAX is now rIP - offset of the following instruction, assuming short jump.
        NOT EAX
        NOT EDX
        ADD EAX,1
        ADC EDX,0 ; EDX:EAX is now negated rIP.
        ADD EAX,[EDI+II.ImmLow] ; Add target to get displacement rel8.
        ADC EDX,[EDI+II.ImmHigh]
        Invoke ExpWidthSigned::
        CMP CL,expWidth1B ; Does signed displacement fit to 1 byte?
        JNA .90:
        INC ESI ; Assume encoding as ImmWord.
        JNSt [EDI+II.SssStatus],sssWidth32,.60:
        INC ESI ; Encoding size covers OTOGGLE prefix in 32bit segment.
    .60:MOVD [%ReturnEAX],iiMfgIMM_WORD+iiMfgDATA_WORD
        MOV EAX,[EBX+STM.OffsetLow]
        MOV EDX,[EBX+STM.OffsetHigh]
        ADD EAX,ESI
        ADC EDX,0 ; EDX:EAX is now rIP - offset of the following instruction, assuming near word jump/call.
        NOT EAX
        NOT EDX
        ADD EAX,1
        ADC EDX,0 ; EDX:EAX is now negated rIP.
        ADD EAX,[EDI+II.ImmLow] ; Add target to get displacement rel16.
        ADC EDX,[EDI+II.ImmHigh]
        Invoke ExpWidthSigned::
        CMP CL,expWidth2B ; Does signed displacement fit to 2 bytes?
        JNA .90:
        ; Otherwise it requires 32bit relative offset, encoded as ImmDword.
        MOVD [%ReturnEAX],iiMfgIMM_DWORD+iiMfgDATA_DWORD
    .90:EndProcedure IiRelocSizeRIP

↑ IiGetRegOrdinal RegisterCode
  IiGetRegOrdinal returns register ordinal number from register code.
Input
  RegisterCode in Register encoding . Only LSB of this parameter is used.
Output
  EAX= register ordinal number 0..31.
Error
  F9985 IiGetRegFamily/Ordinal provided with invalid register encoding.
Example
  Invoke IiGetRegFamily, [EDI+II.Operand2+EXP.Low]
See also
  IiGetRegFamily.
Invoked by
  IiAssembleAVX IiCreateModRM IiFlush

    IiGetRegOrdinal:: Procedure RegisterCode
        MOV EAX,[%RegisterCode]
        MOV ECX,iiReg_Ord32
        TEST AL,iiReg_Fam32
        JNZ .60:
        MOV CL,iiReg_Ord16
        TEST AL,iiReg_Fam16
        JNZ .80:
        MOV CL,iiReg_Ord8
        TEST AL,iiReg_Fam8
        JNZ .70:
    .E9985:Msg '9985' ; IiGetRegOrdinal provided with invalid register encoding.
     .60:CMP AL,iiReg_Spec
         JB .80:
         MOV CL,iiReg_Ord8
     .70:CMP AL,iiReg_CT8
         JB .80:
         MOV CL,iiReg_Ord16
     .80:AND EAX,ECX
         MOV [%ReturnEAX],EAX
        EndProcedure IiGetRegOrdinal

↑ IiGetRegFamily RegisterCode
  Procedure IiGetRegFamily returns register family from register code.
Input
  RegisterCode in Register encoding . Only LSB of this parameter is used.
Output
  EAX= register family (register code with removed ordinal number).
Error
  F9985 IiGetRegFamily/Ordinal provided with invalid register encoding.
Example
  Invoke IiGetRegFamily, [EDI+II.Operand2+EXP.Low]
See also
  IiGetRegOrdinal.
Invoked by
  IiAssemble

    IiGetRegFamily:: Procedure RegisterCode
        MOV EAX,[%RegisterCode]
        MOV ECX,~iiReg_Ord32
        TEST AL,iiReg_Fam32
        JNZ .60:
        MOV CL,~iiReg_Ord16
        TEST AL,iiReg_Fam16
        JNZ .80:
        MOV CL,~iiReg_Ord8
        TEST AL,iiReg_Fam8
        JNZ .70:
        Msg '9985' ; IiGetRegFamily/Ordinal provided with invalid register encoding.
    .60:CMP AL,iiReg_Spec
        JB .80:
        MOV CL,~iiReg_Ord8
    .70:CMP AL,iiReg_CT8
        JE .90:
        JB .80:
        MOV CL,~iiReg_Ord16
    .80:AND ECX,0xFF
    .90:AND EAX,ECX
        MOV [%ReturnEAX],EAX
       EndProcedure IiGetRegFamily

↑ IiAssembleAVX Ii
  Procedure IiAssembleAVX will select and encode final version of prefix XOP, VEX2, VEX3, MVEX, EVEX into II structure.
  `II.MfxAllowed` has already specified which types of AVX prefix are acceptable with current operand combination. Prefix-type selection follows these priorities:
  1. `II.Ppx:iiPpxMEVEXonly` constrains the type according to current operands. If any XMM,YMM above 15, or any ZMM register is used, the instruction is only encodable with EVEX or MVEX.
  2. VEX2 is preferred to VEX3 unless opcode map is `0F38` or `0F3A`, or width promotion bit `W` is set, or `REX.B` or `REX.X` is set (addressing by R8..R15), or if explicitly requested by `PREFIX=VEX3`.
  3. Prefix preferred by user in `II.MfxExplicit` is taken into account then.
  4. If EVEX/MVEX modifier `EH=,SAE=,ROUND=,MASK=,ZEROING=,OPER=` is used, EVEX/MVEX prefix will be selected, unless explicitly requested PREFIX=VEX.
  5. Deprecated prefixes XOP, MVEX should be explicitly requested when VEX, EVEX are applicable as well, otherwise they won't be selected.
     Instructions encodable only with XOP or MVEX form do not have to explicitly specify `PREFIX=` modifier.

  IiAssembleAVX uses the source prefix notation from `II.AvxSrc*` and information from `II.MfxAllowed, II.MfgExplicit, II.MfxExplicit` as explicitly requested by instruction modifiers. It will choose the shortest version and assemble the prefix in `II.AvxCode`. Its size is written to `II.Ppg:iiPpxAvxSize` and returned in ECX. The finally selected version of AVX prefix will be set as the one and only flag in `II.MfxEmitted:iiMfxPREFIX_Mask`.

  Operands encoding in M/EVEX prefix
  AVX-512 operands | EVEX / MVEX | ModRM byte | (V)SIB byte
  --- | --- | --- | ---
  R | X | B | R' | V' | mod | reg | R/M | scale | index | base
  mem type: Rr, [S * Rx + Rb] | r3 | x3 | b3 | r4 | x4 | 0 | 0 | r2 | r1 | r0 | 1 | 0 | 0 | S1 | S0 | x2 | x1 | x0 | b2 | b1 | b0
  reg type: Rr, Rb | r3 | b4 | b3 | r4 |  | 1 | 1 | r2 | r1 | r0 | b2 | b1 | b0 | not used

Input
  Ii is pointer to II structure.
Output
  ECX= size of assembled prefix (2..4).
Error
  CF=1 Errors are reported with macro Msg.
Invokes
  IiGetRegOrdinal
Invoked by
  IiFlush
Tested by
  t5110 t5120 t5135

    IiAssembleAVX Procedure Ii
         MOV EDI,[%Ii]
         IiRequire AVX
         IiAllowModifier PREFIX
         SUB EAX,EAX
         JNSt [EDI+II.Ppx],iiPpxMEVEXonly, .05: ; If ZMM used (requires AVX512 prefix).
         RstSt [EDI+II.MfxAllowed],iiMfxPREFIX_XOP+iiMfxPREFIX_VEX
         MOV [EDI+II.AvxSrcXOP],EAX
         MOV [EDI+II.AvxSrcVEX],EAX
     .05:; Disallow types not defined in Intel doc (no II.AvxSrc* record).
         CMP EAX,[EDI+II.AvxSrcXOP]
         JNZ .10:
         RstSt [EDI+II.MfxAllowed],iiMfxPREFIX_XOP
     .10:CMP EAX,[EDI+II.AvxSrcVEX]
         JNZ .12:
         RstSt [EDI+II.MfxAllowed],iiMfxPREFIX_VEX
     .12:CMP EAX,[EDI+II.AvxSrcEVEX]
         JNZ .14:
         RstSt [EDI+II.MfxAllowed],iiMfxPREFIX_EVEX
     .14:CMP EAX,[EDI+II.AvxSrcMVEX]
         JNZ .16:
         RstSt [EDI+II.MfxAllowed],iiMfxPREFIX_MVEX
     .16: ; Select prefix by explicit PREFIX modifier.
         MOV EAX,iiMfxPREFIX_Mask
         AND EAX,[EDI+II.MfxExplicit]
         AND EAX,[EDI+II.MfxAllowed] ; Leave only requested encodable types in EAX.
         JSt EAX,iiMfxPREFIX_VEX, .VEX:
         JSt EAX,iiMfxPREFIX_EVEX,.EVEX:
         JSt EAX,iiMfxPREFIX_MVEX,.MVEX:
         JSt EAX,iiMfxPREFIX_XOP, .XOP:
     ; If no obeyable explicit PREFIX= request, select prefix by decorators used.
     ; If instruction uses modifier ROUND=, SAE=, BCST=, OPER=, MASK=, ZEROING=, EH=, then only MVEX or EVEX is possible.
         JSt [EDI+II.MfxExplicit],  \
     iiMfxOPER_Used|iiMfxMASK_Mask|iiMfxROUND_Mask|iiMfxSAE_Mask|iiMfxBCST_Mask|iiMfxEH_Mask|iiMfxZEROING_Mask, .20:
     ; Otherwise try VEX/XOP, if defined.
         MOV ESI,[EDI+II.AvxSrcVEX]
         TEST ESI
         JNZ .VEX:
         MOV ESI,[EDI+II.AvxSrcXOP]
         TEST ESI
         JNZ .XOP:
     .20:; If EVEX-specific modifier ZEROING= is explicitly requested, use EVEX, if possible.
         JNSt [EDI+II.MfxExplicit],iiMfxZEROING_Mask,.30:
         MOV ESI,[EDI+II.AvxSrcEVEX]
         TEST ESI
         JNZ .EVEX:
     .30: ; If MVEX-specific modifier EH= is explicitly requested, use MVEX, if possible.
         JNSt [EDI+II.MfxExplicit],iiMfxEH_Mask,.40:
         MOV ESI,[EDI+II.AvxSrcMVEX]
         TEST ESI
         JNZ .MVEX:
     .40:; Otherwise use EVEX or MVEX, in this order.
         MOV ESI,[EDI+II.AvxSrcEVEX]
         TEST ESI
         JNZ .EVEX:
         MOV ESI,[EDI+II.AvxSrcMVEX]
         TEST ESI
         JNZ .MVEX:
     ; If EVEX/MVEX not defined for this instruction, try VEX/XOP once again (AVX2 modifiers will not be obeyed this time).
         MOV ESI,[EDI+II.AvxSrcVEX]
         TEST ESI
         JNZ .VEX:
         MOV ESI,[EDI+II.AvxSrcXOP]
         TEST ESI
         JNZ .XOP:
        ; Instruction handler error or SSE instruction called with XMM16..31 etc.
         LEA EAX,[EBX+STM.OperationPtr]
         Msg '7517',EAX ; Instruction !1S is not encodable with this operand combination.
         RstSt [EBX+STM.Status],stmOperationPresent ; Invalidate the instruction, do not emit anything.
         JMP .90:

    .MVEX:MOV ESI,[EDI+II.AvxSrcMVEX]
         CALL .AvxSrcParse:
         IiEncoding PREFIX=MVEX,DATA=ZWORD ; Emit prefix MVEX.
         IiRequire AVX512,MVEX
         IiAllowModifier OPER,EH
         MOV ESI,0x0000_0062 ; MVEX prefix to LSB.
         JNSt [EDI+II.MfxAllowed], iiMfxEH_Mask, .M1:
         JNSt [EDI+II.MfxExplicit],iiMfxEH_1, .M1: ; MVEX.E is eviction hint EH=ON.
        ; IiEncoding EH=Mask
         SetSt ESI,0x8000_0000 ; Set MVEX.E if explicitly requested EH=ON.
     .M1:JNSt [EDI+II.MfxAllowed], iiMfxSAE_Mask, .M2:
         JNSt [EDI+II.MfxExplicit],iiMfxSAE_1, .M2:
         SetSt ESI,0x4000_0000 ; MVEX.S2.
     .M2:JNSt [EDI+II.MfxAllowed], iiMfxROUND_Mask, .M3:
         MOV EAX,iiMfxROUND_Mask
         AND EAX,[EDI+II.MfxExplicit]
         JZ .M3: ; If no rounding explicitly requested.
         BSF ECX,EAX ; ECX is now 16,17,18,19 for ROUND=NEAR,DOWN,UP,ZERO.
         SHL ECX,28 ; Convert rounding mode from 10h,11h,12h,13h to MVEX.S1S0.
         RstSt ESI,0x3000_0000
         SetSt ESI,ECX
         SetSt ESI,0x8000_0000 ; MVEX.E must be set to enable rounding.
     .M3: ; If OPER= is specified, it overrides previously set bitfields for MVEX.S2.S1.S0.
        ; JNSt [EDI+II.MfxAllowed],ECX, .E6:  ; OPER is always allowed when M/EVEX.
         JNSt [EDI+II.MfxExplicit],iiMfxOPER_Used, .M6:
         MOV EAX,iiMfxOPER_Mask
         AND EAX,[EDI+II.MfxExplicit]
         RstSt ESI,0x7000_0000
         SetSt ESI,EAX ; Overwrite MVEX.S2.S1.S0.
     .M6:; Set finally used encodings of EH,SAE,ROUND,OPER from ESI to II.MfxEmitted.
         JNSt [EDI+II.Ppx],iiPpxEH0,.M7:
         RstSt ESI,0x8000_0000
     .M7:JNSt [EDI+II.Ppx],iiPpxEH1,.M8:
         SetSt ESI,0x8000_0000
     .M8:JNSt [EDI+II.MfxAllowed],iiMfxEH_Mask,.ME1:
         RstSt [EDI+II.MfxEmitted],iiMfxEH_Mask
         JNSt ESI,0x8000_0000, .ME0:
         IiEncoding EH=1
         JMPS .ME1:
    .ME0:IiEncoding EH=0
    .ME1:RstSt [EDI+II.MfxEmitted],iiMfxSAE_Mask
         JNSt [EDI+II.MfxAllowed],iiMfxSAE_Mask,.MS1:
         JNSt ESI,0x4000_0000, .MS0:
         IiEncoding SAE=1
         JMPS .MS1:
    .MS0:IiEncoding SAE=0
    .MS1:RstSt [EDI+II.MfxEmitted],iiMfxROUND_Mask
         JNSt [EDI+II.MfxAllowed],iiMfxROUND_Mask,.MR1:
         JNSt ESI,0x8000_0000, .MR1: ; No rounding if MVEX.E is not set.
         MOV EAX,0x3000_0000
         AND EAX,ESI
         SHR EAX,28 ; EAX is now 0,1,2,3 for ROUND=NEAR,DOWN,UP,ZERO.
         ADD AL,16
         BTS [EDI+II.MfxEmitted],EAX
    .MR1:MOV EAX,0x7000_0000
         AND EAX,ESI
         SetSt EAX,iiMfxOPER_Used
         SetSt [EDI+II.MfxEmitted],EAX

    .EM1: ; Common EVEX and MVEX fields.
         MOV ECX,[EDI+II.PfxEmitted] ; Copy REX to CL.
         AND ECX,0000_0111b ; Leave only R,X,B.
         SHL ECX,13 ; Convert REX.RXB to E/MVEX.RXB.
         OR  ESI,ECX ; E/MVEX.RXB.
         MOV EAX,iiPpxR`
         AND EAX,[EDI+II.Ppx]
         SHR EAX,6 ; Convert iiPpxR` to E/MVEX.R'.
         OR ESI,EAX ; E/MVEX.R'.
         MOV EAX,iiPpxMmMask
         AND EAX,[EDI+II.Ppx]
         OR ESI,EAX ; E/MVEX.mm.
         MOV ECX,iiPpxW
         AND ECX,[EDI+II.Ppx]
         JNSt [EDI+II.Ppx],iiPpxW1,.EM3:
         SetSt ECX,iiPpxW
    .EM3:JNSt [EDI+II.Ppx],iiPpxW0,.EM4:
         RstSt ECX,iiPpxW
    .EM4:SHL ECX,20 ; Convert iiPpxW to M/EVEX.W.
         OR  ESI,ECX ; E/MVEX.W.
         MOV EAX,iiPpxPpMask
         AND EAX,[EDI+II.Ppx]
         SHL EAX,16 ; Convert iiPpxPpMask to M.EVEX.pp.
         OR  ESI,EAX ; E/MVEX.pp.
         CALL .vvvv:
         OR ESI,EAX ; E/MVEX.V'vvvv.
         MOV EAX,iiMfxMASK_Mask
         JNSt [EDI+II.MfxAllowed],EAX, .EM5:
         AND EAX,[EDI+II.MfxExplicit]
         JZ .EM5: ; If MASK=K0.
         SetSt [EDI+II.MfxEmitted],EAX
         BSF ECX,EAX ; ECX is now 0..7.
         SHL ECX,24 ; Convert explicit MASK=1..7 to prefix field EVEX.aaa/MVEX.kkk.
         SetSt ESI,ECX ; Set EVEX.aaa alias MVEX.kkk.
    .EM5:XOR ESI,0x0878F000 ; Invert encoding of fields V',vvvv,R,X,B,R'.
         MOV CL,4
         JMP .90:

    .EVEX:MOV ESI,[EDI+II.AvxSrcEVEX]
         CALL .AvxSrcParse:
         IiEncoding PREFIX=EVEX ;  Emit prefix EVEX.
         IiRequire AVX512,EVEX
         IiAllowModifier OPER
         JNSt [EDI+II.MfxAllowed],iiMfxMASK_Mask,.N1:
         JSt [EDI+II.Ppx],iiPpxNoZEROING,.N1:
         IiAllowModifier ZEROING ; If MASK is allowed, allow ZEROING, too.
    .N1: IiRequire AVX512
         MOV ESI,0x0004_0062 ; E/MVEX prefix to LSB + fixed type bit 1=EVEX, 0=MVEX.
        ; Bitfields EVEX.L'L 00,01,10 specify operand size 128,256,512 by default.
        ; This can be overriden later when ROUND= or OPER= specifies rounding, broadcast, SAE.
         MOV EAX,iiMfgDATA_ZWORD+iiMfgDATA_YWORD+iiMfgDATA_OWORD
         AND EAX,[EDI+II.MfgImplicit] ; EAX is now 0x0000_8000 or 0x0000_4000.
         SetSt [EDI+II.MfgEmitted],EAX
         RstSt EAX,iiMfgDATA_OWORD
         JNSt [EDI+II.Ppx],iiPpxL0,.L0:
         RstSt EAX,iiMfgDATA_YWORD      ; EVEX.L0
     .L0:JNSt [EDI+II.Ppx],iiPpxL1,.L1:
         SetSt EAX,iiMfgDATA_YWORD      ; EVEX.L1
     .L1:SHL EAX,15 ; EAX is now 0x4000_0000 or 0x2000_0000, i.e. EVEX.512 or EVEX.256.
         OR ESI,EAX ; EVEX.L'L.   Otherwise leave 0, i.e. EVEX.128.
         JNSt [EDI+II.MfxAllowed],iiMfxZEROING_Mask, .E3:
         JSt [EDI+II.MfxExplicit],iiMfxZEROING_1, .E2:
         JSt [EDI+II.MfxExplicit],iiMfxZEROING_0, .E1:
         JNSt [EDI+II.MfxExplicit],iiMfxMASK_Mask, .E3:
     .E1:IiEncoding ZEROING=0 ; If MASK= is used, display ZEROING too.
         JMPS .E3:
        ; JSt [EDI+II.MfxExplicit],iiMfxZEROING_1, .E3:
     .E2:IiEncoding ZEROING=1
         SetSt ESI,0x8000_0000 ; Set EVEX.z if explicitly requested ZEROING=ON.
     .E3:JNSt [EDI+II.MfxAllowed],iiMfxBCST_Mask,.E4:
         JSt [EDI+II.MfxExplicit],iiMfxBCST_1,.E5:
        ; IiEncoding BCST=1
     .E4:JNSt [EDI+II.MfxAllowed],iiMfxSAE_Mask, .E6:
         JNSt [EDI+II.MfxExplicit],iiMfxSAE_1,.E6:
        ; IiEncoding SAE=Mask
     .E5:SetSt ESI,0x1000_0000 ; EVEX.b
     .E6:JNSt [EDI+II.MfxAllowed],iiMfxROUND_Mask, .E7:
         MOV EAX,iiMfxROUND_Mask
         AND EAX,[EDI+II.MfxExplicit]
         JZ .E7: ; If no rounding explicitly requested.
         BSF ECX,EAX ; ECX is now 16,17,18,19 for ROUND=NEAR,DOWN,UP,ZERO.
         SHL ECX,29 ; Convert rounding mode from 0,1,2,3 to EVEX.L'.L.
         RstSt ESI,0x6000_0000
         SetSt ESI,ECX
         SetSt ESI,0x1000_0000 ; Always set EVEX.b when rounding mode is used.
     .E7: ; If OPER= is specified, it overrides previously set bitfields for L'L, BCST=, SAE= and ROUND=.
         MOV ECX,iiMfxOPER_Mask
       ; JNSt [EDI+II.MfxAllowed],ECX, .E8:  ; OPER is always allowed when M/EVEX.
         JNSt [EDI+II.MfxExplicit],iiMfxOPER_Used, .E8:
         MOV EAX,iiMfxOPER_Mask
         AND EAX,[EDI+II.MfxExplicit]
         RstSt ESI,iiMfxOPER_Mask
         SetSt ESI,EAX ; Overwrite EVEX.L'.L'b with OPER value.
     .E8:; Set finally used encodings of BCST,SAE,ROUND,OPER from ESI to II.MfxEmitted.
         RstSt [EDI+II.MfxEmitted],iiMfxSAE_Mask
         JNSt [EDI+II.MfxAllowed],iiMfxSAE_Mask,.ES1:
         JNSt ESI,0x1000_0000, .ES0: ; If actually used EVEX.b=0.
         IiEncoding SAE=1
         JMPS .ES1:
    .ES0:IiEncoding SAE=0
    .ES1:RstSt [EDI+II.MfxEmitted],iiMfxBCST_Mask
         JNSt [EDI+II.MfxAllowed],iiMfxBCST_Mask,.EB1:
         JNSt ESI,0x1000_0000, .EB0: ; If actually used EVEX.b=0.
         IiEncoding BCST=1
         JMPS .EB1:
    .EB0:IiEncoding BCST=0
    .EB1:RstSt [EDI+II.MfxEmitted],iiMfxROUND_Mask
         JNSt [EDI+II.MfxAllowed],iiMfxROUND_Mask,.ER1:
         JNSt ESI,0x1000_0000, .ER1: ; No rounding if EVEX.b is not set.
         MOV EAX,0x6000_0000 ; EVEX.L'.L.
         AND EAX,ESI
         SHR EAX,29 ; EAX is now 0,1,2,3 for ROUND=NEAR,DOWN,UP,ZERO.
         ADD AL,16
         BTS [EDI+II.MfxEmitted],EAX
         IiEncoding SAE=1
    .ER1:MOV EAX,0x7000_0000
         AND EAX,ESI
         SetSt EAX,iiMfxOPER_Used
         SetSt [EDI+II.MfxEmitted],EAX
     .E9:JMP .EM1: ; Continue with common fields for EVEX/MVEX.

    .XOP: ; Emit prefix XOP.
         MOV ESI,[EDI+II.AvxSrcXOP]
         CALL .AvxSrcParse:
         IiEncoding PREFIX=XOP
         IiRequire XOP, AMD
         MOV ESI,0x8F ; XOP prefix to LSB.
         MOV ECX,iiPpxMmMask  ; 0x0000_0300.
         AND ECX,[EDI+II.Ppx] ; CH is now 0,1,2,3.
         ADD CH,8 ; Convert MAP8,MAP9,MAP10,reserved to XOP opcode map 8,9,10,11.
         OR ESI,ECX
    .XOPVEX3: ; Common continuation for XOP and VEX3. Escape prefix and map_select are already set in ESI.
         MOV ECX,[EDI+II.PfxEmitted] ; Copy REX to CL.
         AND ECX,0000_0111b ; XOP/VEX3 bits RXB.
         SHL ECX,13 ; Position in XOP/VEX3 RXB.
         OR ESI,ECX
         MOV EAX,iiPpxW ; XOP/VEX bit W.
         AND EAX,[EDI+II.Ppx]
         JNSt [EDI+II.Ppx],iiPpxW0,.XV1:
         RstSt EAX,iiPpxW
    .XV1:JNSt [EDI+II.Ppx],iiPpxW1,.XV2:
         SetSt EAX,iiPpxW
    .XV2:SHL EAX,20 ; Convert iiPpxW to XOP/VEX.W.
         SetSt ESI,EAX
         MOV EAX,iiMfgDATA_YWORD+iiMfgDATA_OWORD
         AND EAX,[EDI+II.MfgImplicit]
         SetSt [EDI+II.MfgEmitted],EAX
         JNSt EAX,iiMfgDATA_YWORD, .XV5: ; XOP/VEX3 bit L.
         SetSt ESI,0x0004_0000
    .XV5:JNSt [EDI+II.Ppx],iiPpxL1,.XV6:
         SetSt ESI,0x0004_0000
    .XV6:JNSt [EDI+II.Ppx],iiPpxL0,.XV7:
         RstSt ESI,0x0004_0000
    .XV7:MOV EAX,iiPpxPpMask ; XOP/VEX3 bits pp.
         AND EAX,[EDI+II.Ppx]
         SHL EAX,16 ; Convert iiPpxPpMask to XOP.pp.
         OR ESI,EAX
         CALL .vvvv: ; XOP/VEX3 bits vvvv.
         OR ESI,EAX
         XOR ESI,0x0078E000 ; XOP/VEX3 inverted bits vvvv,R,X,B.
         MOV CL,3
         JMP .90:

    .VEX:MOV ESI,[EDI+II.AvxSrcVEX]
         CALL .AvxSrcParse:
         ; Choose between VEX2 or VEX3.
         JSt [EDI+II.Ppx],iiPpxW1|iiPpxW|iiPpxMm3, .VEX3: ; W=1 or if 3byte opcode 0x0F38, 0x0F3A required.
         JSt [EDI+II.PfxEmitted], (iiPfxREX.B|iiPfxREX.X)^iiPfxREX, .VEX3: ; If REX.B or REX.X is set (addressing by R8..R15).
         JSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX2, .VEX2: ; If explicitly requested VEX or VEX2.
         JSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX3, .VEX3: ; If explicitly requested longer version VEX3.
    .VEX2:IiEncoding PREFIX=VEX2 ; Emit prefix VEX2.
         RstSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX3 ; In case PREFIX=VEX requested, don't warn that VEX3 disobeyed.
         MOV ESI,0xC5 ; VEX2 prefix to LSB.
         MOV ECX,[EDI+II.PfxEmitted] ; Copy REX to CL.
         AND ECX,0000_0100b ; Leave only R.
         SHL ECX,13 ; Position in VEX.R.
         OR ESI,ECX
         MOV EAX,iiMfgDATA_YWORD+iiMfgDATA_OWORD
         AND EAX,[EDI+II.MfgImplicit]
         SetSt [EDI+II.MfgEmitted],EAX
         JNSt EAX,iiMfgDATA_YWORD, .V1:
         SetSt ESI,0x0000_0400 ; VEX2.L.
    .V1: JNSt [EDI+II.Ppx],iiPpxL1,.V2:
         SetSt ESI,0x0000_0400
    .V2: JNSt [EDI+II.Ppx],iiPpxL0,.V3:
         RstSt ESI,0x0000_0400
    .V3: MOV EAX,iiPpxPpMask
         AND EAX,[EDI+II.Ppx]
         SHL EAX,8
         OR ESI,EAX
         CALL .vvvv:
         SHR EAX,8
         OR ESI,EAX
         XOR ESI,0x0000_F800 ; Invert encoding of fields R,vvvv.
         MOV CL,2
         JMP .90:

    .VEX3:IiEncoding PREFIX=VEX3 ; Emit prefix VEX3.
         JNSt  [EDI+II.MfxExplicit],iiMfxPREFIX_VEX3,.v3:
         RstSt [EDI+II.MfxExplicit],iiMfxPREFIX_VEX2 ; Don't warn that VEX2 was disobeyed when PREFIX=VEX was requested.
     .v3:MOV ESI,0xC4 ; VEX3 prefix to LSB.
         MOV ECX,iiPpxMmMask ; 0x0000_0300.
         AND ECX,[EDI+II.Ppx] ; CH is now 0,1,2,3 for VEX3 opcode map 0,1,2,3 (reserved,0F,0F38,0F3A).
         OR ESI,ECX
         JMP .XOPVEX3: ; Continue as in prefix .XOP:

    .AvxSrcParse: PROC ; Parse source prefix definition to II.
       ; Input: EDI=^II, ESI=^ASCIIZ source_string, e.g. "VEX.NDS.128.66.0F.WIG".
       ; Output: EDI,EBX preserved.
         MOV AL,'.'
    .WIG:
    .LIG:
    .MAP8: ; Ignored specifiers.
     .10:CMP AL,0 ; End of prefix source string?
         JE .90:
         XOR EDX,EDX
         MOV ECX,ESI
     .20:LODSB
         CMP AL,'.'
         JE .30:
         CMP AL,0
         JE .30:
         SHRD EDX,EAX,8
         JMP .20:
     .30:CMP DX,0
         JNZ .40:
         SHR EDX,16
     .40:CMP DL,0
         JNZ .50:
         SHR EDX,8 ; EDX now holds the last 4 characters of prefix component, NULL padded.
     .50:Dispatch EDX,'128','256','512','XOP','VEX','MVEX','EVEX', \
                'NDD','NDS','DDS','W0','W1','WIG','L0','L1','LIG','LZ','66','F2','F3',\
                '0F','0F38','0F3A','MAP8','MAP9','AP10','EH0','EH1'
         LEA EAX,[EBX+STM.OperationPtr] ; Internal handler error.
         Msg '9982',ECX,EAX ; Invalid token "!1$" in AVX prefix for instruction !2S.
         JMP .90:
    .XOP:JSt [EDI+II.Ppx],iiPpxMEVEXonly,.10:
         SetSt [EDI+II.MfxAllowed],iiMfxPREFIX_XOP
         JMP .10:
    .VEX:JSt [EDI+II.Ppx],iiPpxMEVEXonly,.10:
         SetSt [EDI+II.MfxAllowed],iiMfxPREFIX_VEX
         JMP .10:
    .EVEX:SetSt [EDI+II.MfxAllowed],iiMfxPREFIX_EVEX
         JMP .10:
    .MVEX:SetSt [EDI+II.MfxAllowed],iiMfxPREFIX_MVEX
         JMP .10:
    .128:SetSt [EDI+II.MfgImplicit],iiMfgDATA_OWORD
         JMP .10:
    .256:SetSt [EDI+II.MfgImplicit],iiMfgDATA_YWORD
         JMP .10:
    .512:SetSt [EDI+II.MfgImplicit],iiMfgDATA_ZWORD
         JMP .10:
     ; Specifiers NDS/NDD/DDS are ignored, we use IiEmitModRM key ModRM=OperandX instead.
    .NDD:SetSt [EDI+II.Ppx],iiPpxNDD
         JMP .10:
    .NDS:SetSt [EDI+II.Ppx],iiPpxNDS
         JMP .10:
    .DDS:SetSt [EDI+II.Ppx],iiPpxDDS
         JMP .10:
    .W0: SetSt [EDI+II.Ppx],iiPpxW0
         JMP .10:
    .W1: SetSt [EDI+II.Ppx],iiPpxW1
         JMP .10:
    .LZ:
    .L0: SetSt [EDI+II.Ppx],iiPpxL0
         JMP .10:
    .L1: SetSt [EDI+II.Ppx],iiPpxL1
         JMP .10:
    .EH0:SetSt [EDI+II.Ppx],iiPpxEH0
         JMP .10:
    .EH1:SetSt [EDI+II.Ppx],iiPpxEH1
         JMP .10:
    .66: SetSt [EDI+II.Ppx],01b ; Convert to iiPpxPpMask.
         JMP .10:
    .F3: SetSt [EDI+II.Ppx],10b
         JMP .10:
    .F2: SetSt [EDI+II.Ppx],11b
         JMP .10:
    .MAP9:
    .0F:  SetSt [EDI+II.Ppx],01_00000000b ; Convert to iiPpxMmMask.
          JMP .10:
    .AP10:
    .0F38:SetSt [EDI+II.Ppx],10_00000000b
          JMP .10:
    .0F3A:SetSt [EDI+II.Ppx],11_00000000b
          JMP .10:
     .90: RET
         ENDP .AvxSrcParse:

    .vvvv: PROC ; Returns the ordinal number of register which should be encoded in *VEX.vvvv field
    ;              from the operand specified by iiPpxVvMask.
    ; Input:  EDI=^II
    ; Output: Ordinal bits 0..3 of vvvv are returned in bits 19..22 of EAX.
    ;         Ordinal bit 4 of V'vvvv is returned in bit 27 of EAX (when SSE register 15..31 is used).
    ;         0000V000_0vvvv000_00000000_00000000b
    ;         Returned bits vvvv are zero if II.AvxImplicit:iiPpxVvMask is 0 (no operand in vvvv)
    ;         but bit 27 may be returned in EAX when II.PpxV was set (VSIB index is SSE register 15..31).
         MOV EAX,iiPpgVEXvOp
         AND EAX,[EDI+II.Ppg]
         JNZ .v3: ; If vvvv operand is used.
         MOV EAX,iiPpxV` ; Mask for bit V`.
         AND EAX,[EDI+II.Ppx]
         SHL EAX,8 ; Convert iiPpxV` to EVEX.27.
         JMP .v9:
     .v3:; EAX is now 0x0040_0000, 0x0080_0000, 0x00C0_0000 for operand 1,2,3.
         SAR EAX,22 ; EAX is now 1,2,3 for operand 1,2,3.
         PUSH ECX
           MOV ECX,EAX
           LEA EAX,[EDI+II.Operand1-SIZE#EXP]
      .v5: ADD EAX,SIZE#EXP
           LOOP .v5:
         POP ECX ; EAX now points to EDI+II.Operand1,2,3.
         Invoke IiGetRegOrdinal::, [EAX+EXP.Low] ; Return ordinal in EAX bits 0..4.
         BTR EAX,4
         JNC .v6:
         BTS EAX,8
     .v6:SHL EAX,19 ; Move reg.ordinal to its position in EVEX.
     .v9:RET
        ENDP .vvvv:

     .90:MOV [EDI+II.AvxCode],ESI ; Prefix from ESI is stored.
         IiAllowModifier PREFIX ; Allow all prefixes again to get rid of W2400.
         MOVZX ECX,CL  ; Prefix size (2,3,4) in CL is saved and returned in ECX.
         MOV [%ReturnECX],ECX
         SAL ECX,4 ; Convert to iiPpxAvxSize mask.
         OR [EDI+II.Ppx],ECX
       EndProcedure IiAssembleAVX

↑ IiCompressDisp8 Ii, Stm
  IiCompressDisp8 is invoked right after IiAssembleAVX when prefix EVEX or MVEX was emitted and `II.Ppx:iiPpxDisp8Allow` flag is set (by IiModRM). It provides disp8*N compression scaling of displacement, if possible, and redefines the result either as DISP=BYTE compressed, or DISP=DWORD uncompressed.
Input
  Ii is pointer to II object.
  Stm is pointer to the statement STM.
Output
  Modified `II.Disp, II.ModRM:Mod, II.MfxEmitted:DISP_Mask`.
Error
  CF=1 Errors are reported with macro Msg.
See also
  IiDisp8EVEX IiDisp8MVEX
Invokes
  ExpWidthSigned
Invoked by
  IiFlush
Tested by
  t5150 t5154 t5156

    IiCompressDisp8 Procedure Ii, Stm
    Disp8Reloc LocalVar Size=SIZE#RELOC
        ClearLocalVar
        MOV EDI,[%Ii]
        JNSt [EDI+II.MfgEmitted],iiMfgDISP_Mask,.90: ; If no displacement, leave it as is.
        MOV EAX,[EDI+II.Disp8EVEX]
        JSt [EDI+II.MfxEmitted],iiMfxPREFIX_EVEX, .10:
        MOV EAX,[EDI+II.Disp8MVEX]
    .10:MOV ECX,iiMfxOPER_Mask
        AND ECX,[EDI+II.AvxCode]
        SHR ECX,26                                   ; ECX is now 0,4,8,12,16,20,24,28 when OPER=0,1,2,3,4,5,6,7.
        SAL EAX,CL                                   ; Select the corresponding nibble of Disp8*VEX to most-significant nibble.
        SAR EAX,28                                   ; Shift it to the least-significant nibble.
        SHR ECX,2                                    ; ECX is now OPER= value 0..7.
        TEST EAX                                     ; EAX is now 0,1,2,3,4,5,6, or -1.
        JZ .90:
        Msg cc=S,'2450',ECX                          ; The value OPER=!1D is not supported in this instruction.
        JS .50:                                      ; Use disp32/16 when Disp8*N is wrong.
        XCHG EAX,ECX                                 ; ECX has now the number of compression bits 0..6.
        MOV EBX,ECX                                  ; Save compression bits 0..6 to BL.
        MOV EDX,[EDI+II.DispHigh]
        MOV EAX,[EDI+II.DispLow]
        JECXZ .35:
    .30:SAR EDX,1                                    ; Disp8*N compression.
        RCR EAX,1
        JC .50:                                      ; Unaligned displacement cannot be compressed, use disp32/16.
        LOOP .30:
    .35:Invoke ExpWidthSigned::                      ; Get width of compressed Qword EDX:EAX to ECX.
        CMP CL,expWidth1B
        JA .50:                                      ; Compressed displacement doesn't fit to a byte, use disp32/16 uncompressed.
        ; Success, disp8*N will be used.
        MOV [EDI+II.DispLow],EAX                     ; Rewrite final displacement value with the compressed one.
        MOV [EDI+II.DispHigh],EDX
        RstSt [EDI+II.MfgEmitted],iiMfgDISP_Mask
        SetSt [EDI+II.MfgEmitted],iiMfgDISP_BYTE
        ANDB [EDI+II.ModRM],0011_1111b
        ORB  [EDI+II.ModRM],0100_0000b               ; Change ModRM.Mod to 01 (base+disp8)
        SAL EBX,28                                   ; This will be relocDisp8N in  RELOC.Status.
        XCHG EAX,EBX
        LEA EBX,[%Disp8Reloc]                        ; Relocation record will be emitted to decorate compressed displacement in dump column of the listing.
        Clear EBX,Size=SIZE#RELOC
        MOV [EBX+RELOC.Status],EAX
        MOV EAX,[%Stm]
        BufferRetrieve [EAX+STM.EmitBuffer]          ; Get number of emitted bytes so far.
        ; IiCompressDisp8 is invoked from IiFlush when only legacy prefixes were emitted and nothing else.
        ADD ECX,4+1+1+1                              ; Add size of M/EVEX prefix + opcode + ModR/M + disp8.
        JNSt [EDI+II.Ppg],iiPpgSIB, .40:
        INC ECX                                      ; Add size of SIB, if present.
    .40:MOV [EBX+RELOC.OrgLow],ECX                   ; Disp8 offset relative to the start of statement.
        BufferStore [EAX+STM.RelocBuffer],EBX,SIZE#RELOC ; Store Disp8 presudorelocation used to decorate disp8 byte.
        JMPS .90:
    .50:; Leave uncompressed displacement as disp32/16.
        MOV EDX,iiMfgDISP_DWORD
        MOV EAX,[EDI+II.Operand3+EXP.Status]         ; Examine effective address-size in [memory] operand.
        CMP AL,'M'
        JE .70:
        MOV EAX,[EDI+II.Operand2+EXP.Status]
        CMP AL,'M'
        JE .70:
        MOV EAX,[EDI+II.Operand1+EXP.Status]
        CMP AL,'M'
        JNE .80:
    .70:SHR EAX,30                                   ; Isolate EXP.Status:expAwidth (address-size).
        CMP AL,1                                     ; 0,1,2,3 = unspecified,16,32,64 bits.
        JNE .80:
        MOV EDX,iiMfgDISP_WORD                       ; Displacement size in 16bit addressing mode.
    .80:RstSt [EDI+II.MfgEmitted],iiMfgDISP_Mask
        SetSt [EDI+II.MfgEmitted],EDX
        ANDB [EDI+II.ModRM],0011_1111b
        ORB  [EDI+II.ModRM],1000_0000b               ; Change ModRM.Mod to 10 (base+disp32/16).
    .90:EndProcedure IiCompressDisp8

↑ IiCreateModRM
  Procedure IiCreateModRM reads properties of machine instruction stored in object Ii and generates .ModRM and .SIB in II object addressed by EDI.
  It is invoked from IiFlush before IiAssembleAVX when `iiPpgModRMd | iiPpgModRMr` are set to construct ModRM byte + SIB.
Input
  EDI is pointer to II object updated by the instruction handler.
  EBX= is pointer to STM.
Output
  II object modified.
Error
  Errors are reported with macro Msg.
Example
  Invoke IiCreateModRM
See also
  macro IiModRM.
Invokes
  IiGetRegOrdinal
Invoked by
  IiFlush
Tested by
  t3016

    IiCreateModRM: Procedure
        IiAllowPrefix SegAny                      ; Memory operand is accessed.
        IiAllowModifier DISP, DIST, SCALE, ADDR
        ; Construct II.ModRM field RegOpcode.
        MOV EAX,[EDI+II.Ppg]
        MOV ECX,EAX
        SHR EAX,28 ; Convert iiPpgModDigit to 0..7 (if IiModRM /digit was used).
        JSt ECX,iiPpgModRMd, .20:
        ; IiModRM /r was used. Find the operand of RegOpcode field.
        MOV EAX,iiPpgModRegOp ; Mask for operand number.
        AND EAX,ECX
        SHR EAX,24 ; EAX is now 0,1,2,3 for Unspec,Operand1,2,3.
        TEST EAX
        JZ .F9987: ; Internal error: ModRM fields are not specified in handler (missing IiOpEn).
        LEA EDX,[EDI+II.Operand1-SIZE#EXP]
    .05:ADD EDX,SIZE#EXP
        DEC EAX
        JNZ .05:
        Invoke IiGetRegOrdinal, [EDX+EXP.Low] ; EDX points now to the operand going to RegOpcode field.
        BTR EAX,4
        JNC .10: ; If it's not a SSE register above 15.
        SetSt [EDI+II.Ppx],iiPpxR`
    .10:BTR EAX,3
        JNC .20: ; If it's not a GP or SSE register above 7.
        SetSt [EDI+II.PfxEmitted],iiPfxREX.R
    .20:; EAX is RegOpcode field 0..7, higher ordinals bits 3 and 4 were marked in REX.R and VEX.R' and reset.
        SHL AL,3
        OR [EDI+II.ModRM],AL ; ModR/M bitfield Reg/Opcode is finally set.
        ; Construct II.ModRM fields Mod and R/M.  ECX=II.Ppg.
        MOV EAX,iiPpgModRMOp ; Mask for operand number.
        AND EAX,ECX
        SHR EAX,26 ; EAX=0,1,2,3 for Unspec,Operand1,2,3.
        TEST EAX
        JNZ .23:
    .F9987:Msg '9987' ; Internal error: ModRM fields are not specified in handler (missing IiOpEn).
        JMP .90:
    .23:LEA EDX,[EDI+II.Operand1-SIZE#EXP]
    .25:ADD EDX,SIZE#EXP
        DEC EAX
        JNZ .25:
     ; If the operand EDX is register (mod=11b) or based with no SIB present,
     ;   write operand ordinal bits 0..2 to ModRM:R/M, bit 3 to REX.B and bit 4 to REX.X.
     ; If the operand EDX is [memory] and requires SIB,
     ;   write  baseregister ordinal bits 0..2 to SIB.base,  bit 3 to REX.B,
     ;   write indexregister ordinal bits 0..2 to SIB.index, bit 3 to REX.X, bit 4 to EVEX.V'.
        MOV EAX,[EDX+EXP.Status] ; Examine operand type in AL.
        Dispatch AL,'R','M','B','U','W','D','Q','T','O','Y','Z','I'
        JMP .90: ; Expected register or memory operand missing, fatal error was reported by failing IiDispatchFormat.
    .R: ; EDX specifies register operand, Mod will be 11b, no SIB.
        Invoke IiGetRegOrdinal, [EDX+EXP.Low] ; Return register ordinal in EAX.
        BTR EAX,4
        JNC .R4: ; If not SSE register XMM16..ZMM31.
        IiEmitPrefix REX.X ; This flag is misused by EVEX prefix instead of nonexisting B'.
    .R4:BTR EAX,3
        JNC .R5: ; If not X64 register R8..R15, XMM8..XMM15 etc.
        SetSt [EDI+II.PfxEmitted],iiPfxREX.B
    .R5:OR AL,11000000b ; Set Mod=11b.
        JNSt [EDI+II.Ppg],iiPpgMod01,.R6:
        AND AL,0111_1111b ; Short encoding of INC,DEC use ModRM byte as opcode. Mod 11b changed to 01b.
    .R6:JNSt [EDI+II.Ppg],iiPpgMod10,.R7:
        AND AL,1011_1111b ; Short encoding of MOV reg,imm use ModRM byte as opcode. Mod 11b changed to 10b.
    .R7:OR [EDI+II.ModRM],AL
        JMP .90:
    .M:
    .B:
    .U:
    .W:
    .D:
    .Q:
    .T:
    .O:
    .Y:
    .Z:
    .I:
        ; EDX specifies ^EXP memory operand. Mod will be 00b, 01b or 10b. R/M depends on Index/Base/Displacement.
        ; Prepare displacement for emit (though it might be not used finally).
        MOV EAX,[EDX+EXP.Low]
        MOV ECX,[EDX+EXP.High]
        MOV [EDI+II.DispLow],EAX
        MOV [EDI+II.DispHigh],ECX
        MOV EAX,[EDX+EXP.Sym]
        MOV ESI,[EDX+EXP.Seg]
        MOV [EDI+II.DispRelocSym],EAX
        MOV [EDI+II.DispRelocSeg],ESI
        ; If segment was used, e.g. [ES:EDI+Displ], ask for segment override prefix.
        MOV EAX,[EDX+EXP.Status]
        JNSt EAX,expSegmPres,.40: ; Skip when no segment-override was present.
        MOV ECX,EAX
        AND EAX,expSegm
        SHR EAX,24 ; EAX is now Sreg ordinal 0..5.
        ADD AL,20  ; EAX is now 20..25, i.e. iiPfxSEGES..iiPfxSEGGS.
        JNSt ECX,expBasePres, .30:
        AND ECX,expBase
        SHR ECX,16 ; ECX is now 0..15, i.e. ordinal number of base register rAX..R15.
        CMP CL,5   ; rBP?
        JA .30:
        CMP CL,4   ; rSP?
        JB .30:
        ; Base register is rBP or rSP, default segment is SS.
        CMP AL,22  ; iiPfxSEGSS?
        JE .40:    ; Do not emit superfluous segment override by SS.
        JMP .35:
    .30:; None or other base registers than rBP,rSP default to DS.
        CMP AL,23  ; iiPfxSEGDS?
        JE .40:    ; Do not emit superfluous segment override by DS.
    .35:JNSt [EDI+II.SssStatus],sssWidth64,.38: ; Warn that segment override is ignored in 64bit mode.
        CMP AL,24  ; FS or GS?
        JAE .38:
        Msg  '2377' ; Segment override is ignored in 64bit mode.
    .38:BTS [EDI+II.PfxEmitted],EAX ; Request for segment override.
    .40:; Calculate effective address size.
        MOV EAX,[EDX+EXP.Status] ; expAwidth is in bits 30..31.
        MOV ECX,EAX
        SHR EAX,30 ; Address-size detected by ExpEval: 0,1,2,3 for unspecified,16,32,64.
        TEST EAX
        JNZ .55:
        ; Address-size is not determined by base/index register, e.g. [ES:Displ], so it has to be calculated now.
        AND ECX,expDwidth ; CH is 0..7 (actual displacement width).
        INC EAX ; First assume address-size 16bit: EAX=1.
        JSt [EDI+II.SssStatus],sssWidth64,.45: ; 16bit address mode is not available in 64bit segment.
        JSt [EDI+II.MfgExplicit],iiMfgDISP_DWORD,.45: ; If explicitly requested, use 32bit addressing.
        JSt [EDI+II.Ppg],iiPpgVSIBind,.45: ; If instruction requires VSIB, use 32bit addressing.
        CMP CH,expWidth2B
        JA .45: ; If displacement magnitude exceeds 16 bits, use 32bit addressing.
        JSt [EDI+II.MfgExplicit],iiMfgDISP_WORD,.55: ; If explicitly requested, use 16bit addressing.
        JSt [EDI+II.SssStatus],sssWidth16,.55: ; If DISP= not specified, use segment width.
    .45:INC EAX ; 16bit is not enough, try 32: EAX=2.
        JSt [EDI+II.SssStatus],sssWidth64,.50: ; If in 64bit segment, use 64bit addressing mode.
        ; Warn if explicit ATOGGLE tries to switch 32bit mode to 16bit.
        JNSt [EDI+II.SssStatus],sssWidth32,.48:
        TESTD [EDI+II.PfxExplicit],iiPfxATOGGLE
        Msg cc=NZ,'2371' ; Prefix ATOGGLE: is not expected in this instruction.
    .48:CMP CH,110b ; expWidth4B.
        JNA .55: ; If displacement fits to 32 bits.
    .50:INC EAX ; 32bits is not enough, effective address-size is 64: EAX=3.
    .55:SHL EAX,8  ; Convert to II.Ppg:iiPpgAddrSize 100h, 200h, 300h for 16,32,64 bits.
        OR [EDI+II.Ppg],EAX
        ; Effective address-size is finally determined, AH=1,2,3 for 16,32,64 bits.
        DEC AH ; EAX=000h,100h,200h.
        MOV ECX,[EDX+EXP.Status] ; Preload memory variable properties.
        SHR EAX,6 ; EAX=0,4,8, which is index into the .AddressingTable below.
        CMP AL,4
        JB .80: ; If 16bit mode, require nothing.
        JE .70: ; If 32bit mode, require 386.
        IiRequire X64
    .70:IiRequire 386
        ; Select and perform addressing mode procedure .Addr16:, .Addr32: or .Addr64:.
    .80:CALL [EAX+.AddressingTable]
    .90:JMP .99:
    [.data]
         ALIGN DWORD
    .AddressingTable  DD  IiCreateModRM.Addr16:, IiCreateModRM.Addr32:, IiCreateModRM.Addr64: ; Dispatch addressing mode.

    .FindRM16Table: ; Used in  .Addr16.FindRM16 procedure.
              DD expIndexPres + 6<<20 + expBasePres + 3<<16 ; >> R/M=000b SI+BX
              DD expIndexPres + 7<<20 + expBasePres + 3<<16 ; >> R/M=001b DI+BX
              DD expIndexPres + 6<<20 + expBasePres + 5<<16 ; >> R/M=010b SI+BP
              DD expIndexPres + 7<<20 + expBasePres + 5<<16 ; >> R/M=011b DI+BP
              DD expIndexPres + 6<<20                       ; >> R/M=100b SI
              DD expIndexPres + 7<<20                       ; >> R/M=101b DI
              DD                        expBasePres + 5<<16 ; >> R/M=110b   (BP)
              DD                        expBasePres + 3<<16 ; >> R/M=111b    BX
    [.text]
    .Addr16: PROC ; 16bit addressing mode: base BX/BP/-, index SI/DI/-, no scaling, DispB or DispW.
        ; Input: EDI=^II, EDX=^EXP type mem, ECX=[EDX+EXP.Status].
        ; Output: ModR/M, optional SIB and Displacement will be set in II object pointed to by EDI.
        ; II.ModRM has field Reg/Opcode already set. Field Mod will be 00b, 01b or 10b.
        TESTD [EDI+II.Ppg],iiPpgVSIBind
        Msg cc=NZ,'6744' ; This VSIB instruction cannot be used in 16bit addressing mode.
        JSt [EDI+II.SssStatus],sssWidth16,.10:
        JNSt [EDI+II.SssStatus],sssWidth64,.05:
        Msg '6733' ; Required address-size 16 cannot be used in 64bit segment.
    .05:SetSt [EDI+II.PfxEmitted],iiPfxATOGGLE ; Require address-size prefix to get 16bit addressing mode in 32bit segment.
    .10:; Prepare displacement and its width.
        JSt [EDI+II.MfgExplicit],iiMfgDISP_WORD, .12:
        SetSt [EDI+II.Ppx],iiPpxDisp8Allow ; Using of Disp8*N compression is possible,
        ; if not explicitly requested DISP=WORD,
        ; if a displacement BYTE or WORD is used,
        ; if no displacement relocation is necessary,
        ; and if base and/or index register is used.
    .12:MOV EAX,expDwidth   ; Memory operand displacement width mask.
        AND EAX,ECX         ; AH is now 0,3,4,5,6,7 = none,zero,8,16,32,64 bits.
        CMP AH,5
        MOV ESI,[EDX+EXP.Low] ; Copy displacement value from operand to II.
        MOV [EDI+II.DispLow],ESI
        Msg cc=A,'6741',ESI ; Displacement !1K is too big for 16bit addressing mode.
        MOV ECX,[EDX+EXP.Seg]
        JECXZ .15:          ; Skip when the operand has scalar displacement, e.g. [BP+8].
        SetSt [EDI+II.Reloc],iiRelocDispAbs ; Request for relocation and use disp16.
        RstSt [EDI+II.Ppx],iiPpxDisp8Allow ; Disp8*N is not possible due to relocation.
    .15:MOV ECX,[EDX+EXP.Status]
        JSt ECX,expIndexPres|expBasePres,.20:
        RstSt [EDI+II.Ppx],iiPpxDisp8Allow ; Disp8*N is not possible due to omitted register.
        MOV CL,00000110b ; Special case: no base, no index. Mod=00, R/M=6, disp16.
        SetSt [EDI+II.MfgEmitted],iiMfgDISP_WORD
        JMP .80:
    .20:JSt [EDI+II.Reloc],iiRelocDispAbs,.50:
        JSt ECX,expIndexPres,.40:
        MOV ESI,expBase
        AND ESI,ECX
        CMP ESI,0x00050000
        JNE .40: ; If base register is not BP.
        CMP AH,4
        JA .30:  ; If displacement does not fit to byte.
        JSt [EDI+II.MfgExplicit],iiMfgDISP_WORD,.30: ; If explicitly requested DISP=WORD.
        MOV ECX,[EDX+EXP.Seg]
        TEST ECX
        JNZ .28: ; If displacement contains relocation.
        MOV CL,01000110b ; Special case detected: no index, base=BP, disp8.
        SetSt [EDI+II.MfgEmitted],iiMfgDISP_BYTE
        JMP .80:
    .28:SetSt [EDI+II.Reloc],iiRelocDispAbs
        MOV [EDI+II.ImmRelocSeg],ECX
    .30:MOV CL,10000110b ; Special case detected: no index, base=BP, disp16.
        SetSt [EDI+II.MfgEmitted],iiMfgDISP_WORD
        JMP .80:
    .40: ; Index present and/or base<>BP present.
        JSt [EDI+II.MfgExplicit],iiMfgDISP_WORD,.50: ; If explicitly requested DISP=WORD.
        CMP AH,4
        JA .50: ; ; If displacement does not fit to byte.
        MOV ECX,[EDX+EXP.Seg]
        JECXZ .60: ; Skip if displacement does not contain relocation.
        SetSt [EDI+II.Reloc],iiRelocDispAbs
    .50:; Mod=10, disp=16. Find R/M by registers combination.
        CALL IiCreateModRM.FindRM16
        OR CL,10000000b ; Mod=10b.
        IiEncoding DISP=WORD
        JMP .80:
    .60: ; Displacement will be byte or none.
        JSt [EDI+II.MfgExplicit],iiMfgDISP_BYTE,.65: ; If explicitly requested DISP=BYTE.
        CMP AH,3
        JBE .70: ; If displacement zero or missing.
    .65:; Mod=01b, disp8.
        CALL IiCreateModRM.FindRM16
        OR CL,01000000b ; Mod=01b.
        IiEncoding DISP=BYTE
        JMP .80:
    .70:; Mod=00b, no displacement.
        CALL IiCreateModRM.FindRM16
    .80:OR [EDI+II.ModRM],CL
        IiEncoding ADDR=ABS ; In 16bit mode is all addressing absolute.
    .90:RET
      ENDP .Addr16:

    .FindRM16 PROC ; Find R/M encoding of ModR/M byte from register combination in 16bit addressing mode.
                    ; Input:EDX=^EXP operand type mem. Output: CL=R/M field in bits 0..2.
         MOV EAX,expBase+expIndex+expScalePres+expBasePres+expIndexPres
         AND EAX,[EDX+EXP.Status]
         MOV ESI,IiCreateModRM.FindRM16Table
         MOV ECX,8 ; Number of items in the table.
         XCHG ESI,EDI
         REPNE SCASD
         XCHG EDI,ESI ; ECX is now 7..0 for R/M 0..7.
         NOT ECX
         AND CL,7
         RET
        ENDP .FindRM16

    .Addr32: ; 32bit addressing mode.
         JSt [EDI+II.SssStatus],sssWidth32,  IiCreateModRM.Addr3264:
         IiEmitPrefix ATOGGLE ; Require addr-size prefix 0x67 in 16bit and 64bit segment.
         JMP IiCreateModRM.Addr3264:

    .Addr64: ; 64bit addressing mode.
         TESTD [EDI+II.SssStatus],sssWidth64
         Msg cc=Z,'6731'      ; Required address-size 64 can be used in 64bit segment only.
         ;JMP IiCreateModRM.Addr3264:

    .Addr3264: PROC ; Common continuation for 32bit and 64bit addressing mode.
        ; Base r32/r64, index r32/r64 (not ESP/RSP) or xmm/ymm/zmm, scale, Disp8, Disp32.
        ; Input: EDI=^II, EDX=^EXP of type [mem], ECX=[EDX+EXP.Status]. Field Reg/Opcode is already set.
        ; Output: Mod, R/M, optional SIB and Displacement are modified in EDI=^II.
        IiAllowModifier SCALE,ADDR
    .Step1: ; Optimise scaling, if not disabled by SCALE=VERBATIM.
        MOV ECX,[EDX+EXP.Status]
        JSt [EDI+II.MfgExplicit],iiMfgSCALE_VERBATIM, .Step2:
        JSt [EDI+II.Ppg],iiPpgVSIBind, .Step2: ; If VSIB is required, use SIB.
    .Rule1:                                    ; If scaling=1*Index, remove scaling.
        JNSt ECX,expScalePres, .Rule2:
        JSt ECX,expScale,.Rule3:               ; Skip if scale>1.
        AND ECX,~(expScale+expScalePres)       ; Scale=1, remove scaling.
        MOV [EDX+EXP.Status],ECX
    .Rule2: ; If no scaling, index present and base not present, swap base with index (shorter encoding).
        AND ECX,expIndexPres+expBasePres
        CMP ECX,expIndexPres
        JNE .19:
        MOV ECX,expIndex
        AND ECX,[EDX+EXP.Status]
        SHR ECX,4 ; Copy expIndex to expBase.
        OR ECX,expBasePres
        OR [EDX+EXP.Status],ECX
        ANDD [EDX+EXP.Status],~(expIndex+expIndexPres)
        JMPS .19:
    .Rule3:; If scaling=2*Index and Base not present, use Index+Base instead and remove scaling (shorter encoding).
        JNSt ECX,expScalePres,.19:
        JNSt ECX,0x10000000,.19:
        JSt ECX,expBasePres | 0x20000000, .19:
        AND ECX,expIndex
        RstSt [EDX+EXP.Status],expBase+expScale+expScalePres
        SHR ECX,4 ; Shift expIndex to expBase.
        OR ECX,expBasePres
        OR [EDX+EXP.Status],ECX
    .19:MOV ECX,[EDX+EXP.Status]
    .Step2: ; Specify displacement encode size 0,1 or 4 bytes and set it to II.MfgEmitted.
        MOV ESI,iiMfgDISP_DWORD       ; First assume disp32.
        JSt [EDI+II.MfgExplicit],iiMfgDISP_DWORD,.29: ; If explicitly requested, use disp32.
        CMPD [EDX+EXP.Seg],0
        JNZ .29:                      ; If displacement is not a scalar number, use disp32.
        JNSt ECX,expBasePres, .29:    ; If no base register is present, use disp32.
        ; Otherwise using of Disp8 compression is theoretically possible.
        SetSt [EDI+II.Ppx],iiPpxDisp8Allow
        MOV EAX,expDwidth             ; Check displacement numeric magnitude.
        AND EAX,ECX ; AH is now 0,3,4,5,6,7 = none,zero,8,16,32,64 significant bits actually used in displacement.
        CMP AH,6
        Msg cc=A,'6742',[EDX+EXP.Low] ; Displacement !1K is too big for 32/64bit addressing mode.
        JAE .29:                      ; Use disp32, higher bytes truncated.
        CMP AH,4                      ; Not more than eight significant bits are used in displacement.
        JA .29:                       ; If displacement does not fit to a byte, use ESI=disp32.
        ; Displacement fits to 8 bits. Check if 8bit overflow occured (MSbit of 0th and 7th byte are different).
        MOV AL,[EDX+EXP.High+3]       ; Most significant bit of 64bit signed displacement.
        XOR AL,[EDX+EXP.Low+0]
        JS .29: ; If LSB overflowed, this would incorrectly sign-extend, therefore use disp32.
        MOV ESI,iiMfgDISP_BYTE        ; Use disp8, which will be sign-extended to 32|64 bits on runtime.
        CMP AH,3                      ; Displacement zero?
        JA .29:                       ; If displacement nonzero, use disp8.
        JSt [EDI+II.MfgExplicit],ESI,.29: ; If requested DISP=BYTE, use disp8 even when no displacement exists.
        ; Base register EBP, RBP or R13 requires at least disp8 or disp32, too.
        MOV EAX,0x0007_0000           ; Mask for lower 3 bits of expBase register's ordinal.
        AND EAX,ECX
        CMP EAX,0x0005_0000
        JE .29:                       ; If base is EBP, RBP or R13, use disp8.
        XOR ESI,ESI                   ; Otherwise no displacement will be emitted.
    .29:SetSt [EDI+II.MfgEmitted],ESI ; Displacement width is finally set.
    .Step3: ; Specify if SIB will be used and set II.Ppg:iiPpgSIB if yes.
        JSt ECX,expScalePres|expIndexPres, .SIB: ; If scaling or index is present, use SIB.
        MOV EAX,0x0007_0000           ; Mask for lower 3 bits of expBase register's ordinal.
        AND EAX,ECX
        CMP EAX,0x0004_0000
        JE .SIB:                      ; If base is ESP, RSP or R12, use SIB.
        JSt [EDI+II.Ppg],iiPpgVSIBind,.SIB: ; If VSIB is required, use SIB.
        JSt [EDI+II.MfgExplicit],iiMfgSCALE_VERBATIM,.SIB: ; If SIB was explicitly required.
        JSt ECX,expBasePres,.NoSIB:   ; Other base and no index are encodable without SIB.
        ; If no index and no base is present, still we may need to emit SIB when ADDR=ABS was requested in 64bit mode
        ;   or when SCALE=VERBATIM was requested in any mode.
        JSt [EDI+II.MfgExplicit],iiMfgSCALE_VERBATIM,.SIB:
        JNSt [EDI+II.SssStatus],sssWidth64,.NoSIB:
        CMPD [EDI+II.DispRelocSeg],0
        JZ .SIB:                       ; Absolute addressing with SIB is necessary for scalar displacement.
        JSt [EDI+II.MfgExplicit],iiMfgADDR_ABS,.SIB:   ; If explicitly requested ADDR=ABS in 64bit mode, use SIB.
        JSt [EDI+II.MfgExplicit],iiMfgADDR_REL,.NoSIB: ; If explicitly requested ADDR=REL in 64bit mode, do not use SIB.
        JSt [EDI+II.PfxEmitted],iiPfxSEGFS|iiPfxSEGGS,.SIB: ; If FS or GS used and ADDR not explicitly specified, use SIB (ABS).
    .NoSIB:IiEncoding SCALE=SMART                      ; By default prefer ADDR=REL, no SIB in 64bit mode.
        JMPS .Step4:
    .SIB:IiEncoding SCALE=VERBATIM
        SetSt [EDI+II.Ppg],iiPpgSIB
    .Step4: ; Specify addressing frame as absolute or RIP-relative.
        JSt ECX,expBasePres|expIndexPres,.ABS:   ; When a register is present, frame is absolute.
        JSt [EDI+II.Ppg],iiPpgSIB,.ABS:          ; When SIB is emitted, addressing frame is always absolute.
        JNSt [EDI+II.SssStatus],sssWidth64,.ABS: ; Frame is always absolute in legacy mode.
    .REL:IiEncoding ADDR=REL                     ; Use by default in 64bit mode.
        JMPS .Step5:
    .ABS:IiEncoding ADDR=ABS
    .Step5: ; Specify displacement relocation.
        MOV EAX,[EDI+II.DispRelocSeg]
        TEST EAX
        JZ .Step6:                               ; Displacement is a scalar value, no relocation.
        MOV ESI,iiRelocDispAbs
        JSt [EDI+II.MfgEmitted],iiMfgADDR_ABS,.Reloc:
        MOV ESI,iiRelocDispRIP
        CMP EAX,[EBX+STM.Section]                ; If Displacement is an address targeting the same section,
        JE .Reloc:                               ;   it can be resolved in IiFlush.
        MOV ESI,iiRelocDispRel                   ; Otherwise use relative relocation.
    .Reloc:SetSt [EDI+II.Reloc],ESI
    .Step6:; Construction of (V)SIB byte. (Scaled) index register is present or ADDR=ABS or base is ESP,RSP,R12.
        JNSt [EDI+II.Ppg],iiPpgSIB,.Step7:       ; Skip this step when SIB is not requested.
        MOV EAX,expScale
        AND EAX,ECX
        SHR EAX,22
        OR [EDI+II.SIB],AL                       ; Set SIB scaling bits.
        MOV EAX,expBase
        AND EAX,ECX
        SHR EAX,16
        JSt ECX,expBasePres,.62:
        MOV AL,0101b                             ; If no base present, set SIB base bits as if it is rBP.
    .62:BTR EAX,3
        JNC .64:
        IiEmitPrefix REX.B
    .64:OR [EDI+II.SIB],AL                       ; Set SIB base bits.
        MOV EAX,expIndex
        AND EAX,ECX
        SHR EAX,17                               ; Convert expIndex to ModRM.
        JSt ECX,expIndexPres,.66:
        MOV AL,00100000b                         ; If no index present, set SIB index to ESP or RSP.
    .66:BTR EAX,6
        JNC .68:
        IiEmitPrefix REX.X
    .68:OR [EDI+II.SIB],AL                       ; Set SIB index bits. SIB is completed now.
    .Step7:; Construction of ModR/M field R/M.
        MOV AL,00000100b
        JSt [EDI+II.Ppg],iiPpgSIB,.79:           ; If SIB is present, R/M must be 100b.
        MOV AL,00000101b
        JNSt ECX,expBasePres,.79:                ; If no base is present, R/M must be 101b.
        MOV EAX,expBase
        AND EAX,ECX
        SHR EAX,16
        BTR EAX,3
        JNC .79:
        IiEmitPrefix REX.B
    .79:OR [EDI+II.ModRM],AL                     ; Set R/M field.
    .Step8:; Construction of ModR/M field Mod.
        JNSt ECX,expBasePres,.88:                ; If no base is present, Mod must be left on 00b.
        MOV AL,01000000b                         ; Mod 01b (disp8).
        JSt [EDI+II.MfgEmitted],iiMfgDISP_BYTE,.89:
        MOV AL,10000000b                         ; Mod 10b (disp32).
        JSt [EDI+II.MfgEmitted],iiMfgDISP_DWORD,.89:
    .88:MOV AL,00000000b                         ; Mod 00b (no displacement).
    .89:OR [EDI+II.ModRM],AL                     ; ModRM is completed now.
        RET
      ENDP .Addr3264:
    .99:EndProcedure IiCreateModRM

↑ IiFlush Ii, Stm
  IiFlush takes properties of machine instruction stored in object Ii, generates instruction components, links them together and stores them to Stm.EmitBuffer and StmRelocBuffer. It also reports errors on discovered conflicts and warns when requested modifiers were not obeyed.
  `RELOC.Section` is 0, it will be set in SssEmit.
  `RELOC.Org` is related to $ (the first byte of this instruction), it will be elevated in SssEmit
Input
  Ii is pointer to II object updated by IiAssemble.
  Stm is pointer to parsed STM.
Output
  Stm.EmitBuffer is filled with assembled instruction code (without alignment stuff).
  Stm.RelocBuffer is filled with zero, one or two RELOC records.
Error
  Errors are reported with macro Msg.
Depends on
  IiRequire
Invokes
  EaBufferRelease EaBufferReserve ExpWidthBitwise IiAssembleAVX IiCompressDisp8 IiCpuToKeys IiCreateModRM IiGetRegOrdinal IiModifiersToKeys
Invoked by
  IiAssemble
Tested by
  t3018 t3019 t5170

    IiFlush Procedure Ii, Stm
    Reloc LocalVar Size=SIZE#RELOC
         MOV EBX,[%Stm]
         MOV EDI,[%Ii]
         JNSt [EDI+II.Ppg],iiPpgModRMr|iiPpgModRMd, .10:
         ; Construct ModRM+(V)SIB bytes.
         Invoke IiCreateModRM
    .10: ; Flush explicit prefixes, e.g. in SEGES MOV AX,[SI].
         MOV ECX,[EBX+STM.NrOfPrefixes]
         JECXZ .12:
         LEA ESI,[EDI+II.PfxCode]
         BufferStore [EBX+STM.EmitBuffer],ESI,ECX    ; Store unconditionally all ECX prefixes.
    .12: ; Flush implicit segment prefixes, if they were not specified explicitly.
         MOV EAX,iiPfxSegAny
         AND EAX,[EDI+II.PfxEmitted]                 ; E.g. in MOV AX,[ES:SI].
         JZ .18: ; If no implicit segment override.
         JNSt EAX,iiPfxSEGFS|iiPfxSEGGS,.14:
         IiRequire 386
    .14: TEST [EDI+II.PfxExplicit],EAX
         JNZ .18:                                    ; If implicit segment override was already requested as explicit, ignore.
         JNSt [EDI+II.PfxExplicit],iiPfxGrp2,.16: ; Different segment override explicitly requested?
         Msg '2820'                                  ; Illegal combination of prefixes from the same group.
    .16: BSF EAX,EAX                                 ; EAX=20..25 for ES..GS.
         SUB EAX,20                                  ; EAX= 0..5  for ES..GS.
         SHL EAX,2                                   ; EAX= 0..20 for ES..GS.
         LEA ESI,[DictPrefixesGrp2::+DICT.Data+EAX+2*EAX] ; SIZE#DICT=3*4. Let ESI point to prefix code.
         BufferStore [EBX+STM.EmitBuffer],ESI,1
    .18: ; Flush implicit prefixes LOCK, OTOGGLE, ATOGGLE, REPE, REPNE, VEX, REX.
         JNSt [EDI+II.PfxEmitted],iiPfxLOCK,.20:
         JSt [EDI+II.PfxExplicit],iiPfxLOCK,.20:     ; If LOCK was already requested as explicit prefix.
         LEA ESI,[DictPrefixLock::+DICT.Data]
         BufferStore [EBX+STM.EmitBuffer],ESI,1
    .20: JNSt [EDI+II.PfxEmitted],iiPfxOTOGGLE,.22:
         JSt [EDI+II.PfxExplicit],iiPfxOTOGGLE,.22:  ; If OTOGGLE was already requested as explicit prefix.
         LEA ESI,[DictPrefixesGrp3::+DICT.Data]
         BufferStore [EBX+STM.EmitBuffer],ESI,1
    .22: JNSt [EDI+II.PfxEmitted],iiPfxATOGGLE,.24:
         JSt [EDI+II.PfxExplicit],iiPfxATOGGLE,.24:  ; If ATOGGLE was already requested as explicit prefix.
         LEA ESI,[DictPrefixesGrp4::+DICT.Data]
         BufferStore [EBX+STM.EmitBuffer],ESI,1
    .24: JNSt [EDI+II.PfxEmitted],iiPfxREPE,.26:
         JSt [EDI+II.PfxExplicit],iiPfxREPE,.26:     ; If REPE was already requested as explicit prefix.
         LEA ESI,[DictPrefixRepe::+DICT.Data]
         BufferStore [EBX+STM.EmitBuffer],ESI,1
    .26: JNSt [EDI+II.PfxEmitted],iiPfxREPNE,.28:
         JSt [EDI+II.PfxExplicit],iiPfxREPNE,.28:    ; If REPNE already requested as explicit prefix.
         LEA ESI,[DictPrefixRepne::+DICT.Data]
         BufferStore [EBX+STM.EmitBuffer],ESI,1
    .28: ; Flush REX/VEX prefix.
         MOV EAX,[EDI+II.AvxSrcXOP]
         OR  EAX,[EDI+II.AvxSrcVEX]
         OR  EAX,[EDI+II.AvxSrcEVEX]
         OR  EAX,[EDI+II.AvxSrcMVEX]
         JZ .32:                                     ; If no AVX prefix is specified, emit REX when it is nonzero.
         Invoke IiAssembleAVX,EDI                    ; Returns prefix size (2..4) in ECX.
         JNSt [EDI+II.MfxEmitted],iiMfxPREFIX_EVEX|iiMfxPREFIX_MVEX,.30:
         JNSt [EDI+II.MfxEmitted],iiMfxPREFIX_MVEX,.29:
         JNSt [EDI+II.Ppx],iiPpxNoSwizzle,.29:
         MOV EAX,[EDI+II.AvxCode]
         SHR EAX,28                                  ; AL is now MVEX bits EH.S2.S1.S0.
         BTR EAX,3
         JC .29:                                     ; Skip swizzle check when EH=1.
         CMPB [EDI+II.Operand3+EXP.Status],'M'
         JE .29:                                     ; Skip swizzle check if memory-operand3 is present.
         CMPB [EDI+II.Operand2+EXP.Status],'M'
         JE .29:                                     ; Skip swizzle check if memory-operand2 is present.
         TEST AL
         Msg cc=NZ,'2452',EAX                        ; Register swizzle (EH=0,OPER=!1D) is not supported in this MVEX instruction.
    .29: JNSt [EDI+II.Ppx],iiPpxDisp8Allow, .30:
         Invoke IiCompressDisp8,EDI,EBX
    .30: LEA ESI,[EDI+II.AvxCode]
         BufferStore [EBX+STM.EmitBuffer],ESI,ECX
         JMP .38:                                    ; Skip REX when AVX prefix is used.
    .32: LEA ESI,[EDI+II.PfxEmitted]                 ; REX prefix is in LSB.
         JNSt [EDI+II.Ppx],iiPpxRemoveREX.R, .33:
         ANDB [ESI],0xFB
    .33: JNSt [EDI+II.Ppx],iiPpxRemoveREX.W, .34:
         ANDB [ESI],0xF7
    .34: JNSt [EDI+II.Ppx],iiPpxRemoveREX, .36:
         CMPB [ESI],iiPfxREX
         JNE .36:
         MOVB [ESI],0
         JMP .38:
    .36: CMPB [ESI],0
         JZ .38:                                     ; Skip when no REX prefix was required.
         MOV ECX,1                                   ; Prepare the size of REX prefix.
         BufferStore [EBX+STM.EmitBuffer],ESI,ECX
         IiRequire X64                               ; REX requires CPU=X64.
    .38: ; Flush operation code.
         MOV ECX,[EDI+II.Ppg]
         AND ECX,iiPpgOpcodeSizeMask                 ; ECX=size of opcode (1..15).
         JZ .40:
         LEA ESI,[EDI+II.Opcode]
         BufferStore [EBX+STM.EmitBuffer],ESI,ECX
    .40: ; Flush ModR/M, SIB.
         MOV CL,1
         JNSt [EDI+II.Ppg],iiPpgModRMr|iiPpgModRMd,.42: ; SIB is never emitted without ModR/M.
         BT [EDI+II.Ppg],13                          ; iiPpgSIB=0x0000_2000 = bit 13.
         ADC ECX,0                                   ; ECX=2 when SIB is present, otherwise ECX=1.
         LEA ESI,[EDI+II.ModRM]
         BufferStore [EBX+STM.EmitBuffer],ESI,ECX    ; Emit ModR/M or ModR/M+SIB.
    .42: ; Create displacement relocations.
         MOV EAX,[EDI+II.Reloc]
         JNSt EAX,iiRelocDispAbs|iiRelocDispRel|iiRelocDispRIP,.50: ; Skip when no displacement relocation was requested.
         BufferRetrieve [EBX+STM.EmitBuffer]         ; ECX is now the size of prefixes+opcode+ModRM+SIB emitted so far in this instruction.
         LEA ESI,[%Reloc]                            ; Prepare RELOC record.
         Clear ESI,Size=SIZE#RELOC
         MOV [ESI+RELOC.OrgLow],ECX                  ; Temporary RELOC.Org will be elevated later in StmFlush.
         MOV ECX,[EDI+II.DispRelocSym]
         MOV [ESI+RELOC.Symbol],ECX
         JNSt EAX,iiRelocExtAttrReq,.44:
         JECXZ .44:
         MOVZX EDX,AL                                ; II.OperandX offset iiRelocOffsExtAttr. EDX=00h|14h|28h|3Ch.
         MOV EDX,[EDX+EDI+II.Operand1.Status]
         AND EDX,expExtAttr                          ; Isolate the attribute identification (dictAttrNONE, dictAttrSEGMENT etc).
         SetSt [ESI+RELOC.Status],EDX                ; Request possible postponed attribute evaluation.
    .44: MOV EDX,iiMfgDISP_WORD|iiMfgDISP_DWORD|iiMfgDISP_QWORD ; Mask of the width of relocated object.
         AND EDX,[EDI+II.MfgEmitted]
         SHL EDX,15                                  ; Convert iiMfgDISP_Mask to relocWidthMask.
         SetSt [ESI+RELOC.Status],EDX                ; Specify the size of relocated object (2,4,8 bytes).
         JSt EAX,iiRelocDispRIP, .iiRelocDispRIP
         JECXZ .46:
         MOV EDX,[ECX+SYM.Section]
         TEST EDX
         JZ .46:
         MOV ECX,[EDX+SSS.SymPtr]                    ; Target is relocated by the section's bottom symSe. Symbol's offset is in II.Disp.
         MOV [ESI+RELOC.Symbol],ECX
    .46: JSt EAX,iiRelocDispAbs, .iiRelocDispAbs     ; Dispatch by the requested relocation type.
         JSt EAX,iiRelocDispRel, .iiRelocDispRel
         JMP .50:

    .iiRelocDispRIP: ; Intrasection rIP-relative displacement adressing (ADDR=REL) is solved here at asm-time. No RELOC needed.
         MOV ECX,[EDI+II.MfgEmitted]                 ; Encoded size of displacement and immediate field (iiMfgDISP_WORD|DWORD|QWORD+iiMfgIMM_WORD|DWORD|QWORD).
         MOV EAX,iiMfgDISP_Mask
         XOR EDX,EDX
         AND EAX,ECX
         SHR EAX,4                                   ; Convert iiMfgDISP_Mask to the number of bytes in displacement field (0,1,2,4,8).
         AND ECX,iiMfgIMM_Mask
         ;SHR ECX,0                                  ; Convert iiMfgIMM_Mask to the number of bytes in imm field (0,1,2,4,8).
         BT [EDI+II.Ppg],14                          ; iiPpgImm2 = 0x0000_4000, bit 14. Test the size of Imm2 (0,1).
         ADC EAX,ECX                                 ; EDX:EAX is now the total size of current instruction.
         ADD EAX,[ESI+RELOC.OrgLow]                  ; Add the size of prefixes+opcode+ModRM+SIB emitted so far in this instruction.
         ADD EAX,[EBX+STM.Size]                      ; In case of Multiop (PUSH|POP|INC|DEC) add the size of previous STM data. Otherwise Stm.Size=0.
         ADD EAX,[EBX+STM.OffsetLow]                 ; Add the offset of $ (origin of this statement).
         ADC EDX,[EBX+STM.OffsetHigh]                ; EDX:EAX is now rIP, i.e. offset of the next instruction.
         SUB [EDI+II.DispLow],EAX                    ; Perform the actual relocation in emitted code.
         SBB [EDI+II.DispHigh],EDX
         JMP .50:                                    ; Do not create RELOC record.

    .iiRelocDispRel: ; Store RIP-relative displacement relocation to the symbol ECX which belongs to other section (perhaps external).
         SetSt [ESI+RELOC.Status],relocRel
         MOV EAX,[EDI+II.MfgEmitted]                 ; Encoded size of displacement and immediate field (iiMfgDISP_WORD|DWORD|QWORD+iiMfgIMM_WORD|DWORD|QWORD).
         MOV EDX,EAX
         AND EAX,iiMfgDISP_Mask
         AND EDX,iiMfgIMM_Mask
         SHR EAX,4                                   ; Convert iiMfgDISP_Mask to the number of bytes in disp field (0,1,2,4,8).
         ;SHR EDX,0                                  ; Convert iiMfgIMM_Mask to the number bytes in imm filed (0,1,2,4,8).
         BT [EDI+II.Ppg],14                          ; iiPpgImm2 = 0x0000_4000, bit 14. Test the size of Imm2 (0,1).
         ADC EAX,EDX
         CDQ                                         ; EDX:EAX is now the size of disp+imm+imm2, i.e. rIP (end of instruction) related to RELOC.Org.
         SUB [ESI+RELOC.AddendLow],EAX
         SBB [ESI+RELOC.AddendHigh],EDX
         JMP .48:                                    ; Go to store RELOC ESI.

    .iiRelocDispAbs:                                 ; Store absolute displacement relocation record.
         JECXZ .50:                                  ; If there's no symbol in displacement, the target is constant, e.g. MOV EAX,[EBP+40]. No reloc.
         SetSt [ESI+RELOC.Status],relocAbsVA
     .48:BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC ; Statement EBX requires relocation at combine or link time.
     .50: ; Flush the displacement.
         MOV ECX,[EDI+II.MfgEmitted]
         AND ECX,iiMfgDISP_Mask
         JZ .55:
         SHR ECX,4                                   ; Convert flags in iiMfgDISP_Mask to number of disp bytes 0,1,2,4,8.
         LEA ESI,[EDI+II.DispLow]
         BufferStore [EBX+STM.EmitBuffer],ESI,ECX
         CMP CL,8
         JE .55:
         JNSt [EDI+II.SssStatus],sssWidth64,.55:     ; Skip the check if index or base register is used.
         MOV EAX,[EDI+II.Operand1+EXP.Status]
         CMP AL,'M'
         JNE .51:
         JSt EAX,expBasePres|expIndexPres,.55:
     .51:MOV EAX,[EDI+II.Operand2+EXP.Status]
         CMP AL,'M'
         JNE .53:
         JSt EAX,expBasePres|expIndexPres,.55:
     .53:; Check if the displacement is encodable in 32 bits.
         JSt [EDI+II.MfgEmitted],iiMfgADDR_REL,.55:
         CMPD [ESI+4],0                              ; Test if displacement exceeds 4GB in ADDR=ABS.
         JZ .55:
         Msg  PgmStatus=pgmLastPass,'3432'           ; Displacement above 4 GB is not directly encodable. Use indirect addressing.
     .55: ; Create relocations of immediate operand.
         MOV EAX,[EDI+II.Reloc]
         JNSt EAX,iiRelocImmAbs|iiRelocImmRel|iiRelocImmRIP|iiRelocPara|iiRelocFar,.62: ; Skip when no relocation of imm was requested.
         BufferRetrieve [EBX+STM.EmitBuffer]         ; ECX is now the size of prefixes+opcode+ModRM+SIB+disp emitted so far in this instruction.
         LEA ESI,[%Reloc]                            ; Prepare RELOC record.
         Clear ESI,Size=SIZE#RELOC
         MOV [ESI+RELOC.OrgLow],ECX                  ; Temporary RELOC.Org will be elevated later in StmFlush.
         MOV ECX,[EDI+II.ImmRelocSym]
         MOV [ESI+RELOC.Symbol],ECX
         JNSt EAX,iiRelocExtAttrReq,.5C:
         JECXZ .5C:
         MOVZX EDX,AL                                ; II.OperandX offset iiRelocOffsExtAttr. EDX=00h|14h|28h|3Ch.
         MOV EDX,[EDX+EDI+II.Operand1.Status]        ; EXP.Status of the relocated operand.
         AND EDX,expExtAttr                          ; Isolate the attribute identification (dictAttrNONE, dictAttrSEGMENT etc).
         SetSt [ESI+RELOC.Status],EDX                ; Request possible postponed attribute evaluation.
    .5C: MOV EDX,iiMfgIMM_WORD|iiMfgIMM_DWORD|iiMfgIMM_QWORD ; Mask of the width of relocated object.
         AND EDX,[EDI+II.MfgEmitted]
         SHL EDX,19                                  ; Convert iiMfgIMM_Mask to relocWidthMask.
         SetSt [ESI+RELOC.Status],EDX                ; Specify the flag relocWidth16,32,64.
         JSt EAX,iiRelocImmRIP, .iiRelocImmRIP:
         JSt EAX,iiRelocImmRel, .iiRelocImmRel:
         JECXZ .5E:
         MOV EDX,[ECX+SYM.Section]
         TEST EDX
         JZ .5E:
         MOV ECX,[EDX+SSS.SymPtr]                    ; Target is relocated by the section's bottom symSe. Symbol's offset is in II.Imm.
         MOV [ESI+RELOC.Symbol],ECX
    .5E: JSt EAX,iiRelocImmAbs, .iiRelocImmAbs:      ; Dispatch by the requested relocation type.
         JSt EAX,iiRelocFar,    .iiRelocFar:
         JSt EAX,iiRelocPara,   .iiRelocPara:
         JMP .62:
        ; Dispatched handlers input: ESI=^RELOC, ECX=^SYM of target (may be 0).
    .iiRelocImmRIP:                                  ; Intrasection rIP-relative imm addressing (CALL, JMP) is solved here at asm-time. No RELOC needed.
         MOV EAX,iiMfgIMM_Mask
         AND EAX,[EDI+II.MfgEmitted]                 ; Encoded size of immediate field (iiMfgDISP_BYTE|WORD|DWORD|QWORD).
         XOR EDX,EDX
         ;SHR EAX,0                                  ; Convert iiMfgIMM_Mask to the number of bytes in imm field (0,1,2,4,8).
         BT [EDI+II.Ppg],14                          ; iiPpgImm2 = 0x0000_4000, bit 14. Test the size of Imm2 (0 or 1).
         ADC EAX,[ESI+RELOC.OrgLow]                  ; Add the size of prefixes+opcode+ModRM+SIB+disp emitted so far in this instruction.
         ADD EAX,[EBX+STM.Size]                      ; In case of Multiop (PUSH|POP|INC|DEC) add the size of previous STM data. Otherwise Stm.Size=0.
         ADD EAX,[EBX+STM.OffsetLow]                 ; Add the offset of $ (origin of this statement).
         ADC EDX,[EBX+STM.OffsetHigh]                ; EDX:EAX is now rIP, i.e. offset of the next instruction.
         SUB [EDI+II.ImmLow],EAX                     ; Perform the actual relocation in emitted code.
         SBB [EDI+II.ImmHigh],EDX
         JMP .62:                                    ; Do not create RELOC record.

    .iiRelocImmRel:                                  ; Relative relocation to the target symbol ECX which is in other section or external.
         SetSt [ESI+RELOC.Status],relocRel
         MOV EAX,iiMfgIMM_Mask
         AND EAX,[EDI+II.MfgEmitted]                 ; Encoded size of immediate field (iiMfgDISP_BYTE|WORD|DWORD|QWORD).
         ;SHR EAX,0                                  ; Convert iiMfgIMM_Mask to the number of imm bytes (0,1,2,4,8).
         BT [EDI+II.Ppg],14                          ; iiPpgImm2 = 0x0000_4000, bit 14. Test the size of Imm2 (0 or 1).
         ADC EAX,0                                   ; Add the size of prefixes+opcode+ModRM+SIB+disp emitted so far in this instruction.
         CDQ                                         ; Sign-extend EAX to EDX:EAX.
         SUB [ESI+RELOC.AddendLow],EAX
         SBB [ESI+RELOC.AddendHigh],EDX
         JECXZ .57:                                  ; ECX is the target symbol, or 0 when the target is scalar.
         MOV EDX,[ECX+SYM.Section]
         TEST EDX
         JZ .57:
    .56: MOV ECX,[EDX+SSS.SymPtr]
         MOV [ESI+RELOC.Symbol],ECX                  ; symSe which represents the relocatable bottom of target section|segment.
    .57: BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC
         JMP .62:                                    ; Go to store RELOC.

    .iiRelocImmAbs:                                  ; Absolute immediate relocation record.
         TEST ECX                                    ; If there's no symbol in immediate operand, the target is constant,
         JZ .62:                                     ;   e.g. MOV EAX,0x40_0000. No reloc.
         MOV EAX,[ESI+RELOC.Status]
         AND EAX,relocExtAttr
         CMP EAX,dictAttrPARA<<16                    ; >>
         JE .58:
         SetSt [ESI+RELOC.Status],relocAbsVA
         JMP .59:
    .58: SetSt [ESI+RELOC.Status],relocPara
    .59: BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC ; Statement EBX requires relocation at combine or link time.
         JNSt [EDI+II.Reloc],iiRelocPara, .62:
         ; Both iiRelocAbsVA and iiRelocPara were set when the target is a relocatable FAR address. Second RELOC record will be created.
         MOV EAX,[ESI+RELOC.Status]
         AND EAX,relocWidthMask
         SHR EAX,19                                   ; EAX is 2 or 4.
         MOV EDX,relocWidth16+relocPara
         ADD [ESI+RELOC.OrgLow],EAX
         MOV [ESI+RELOC.Status],EDX
         BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC ; Statement EBX requires relocation at combine or link time.
         JMP .62:

    .iiRelocPara:                                    ; Immediate PARA# value relocation (OMF FIXUPP Location=2), e.g. MOV AX,PARA# [DATA].
         SetSt [ESI+RELOC.Status],relocPara+relocWidth16
         JECXZ .6R:
         JMP .6R:

    .iiRelocFar:                                     ; Immediate far ptr 16:16 or 16:32, e.g. JMPF FarProc.
        MOV EAX,relocFar+relocWidth32                ; The first one is an absolute word/dword relocation of offset.
        JSt [EDI+II.MfgEmitted],iiMfgIMM_DWORD,.60:
        MOV EAX,relocFar+relocWidth16
    .60:MOV [ESI+RELOC.Status],EAX
    .6R:BufferStore [EBX+STM.RelocBuffer],ESI,SIZE#RELOC
    .62:; Flush the immediate operand.
        LEA ESI,[EDI+II.ImmLow]
        MOV EAX,[ESI+0]
        MOV EDX,[ESI+4]
        Invoke ExpWidthBitwise::
        SUB CL,4                                     ; CL is now -1,0,1,2,3 for immediate size 0,byte,word,dword,qword.
        MOV EAX,1
        MOV EDX,[EDI+II.MfgEmitted]
        JNG .64:
        SHL EAX,CL                                   ; AL is now  0,1,2,4,8 for immediate value 0,byte,word,dword,qword.
    .64:AND EDX,iiMfgIMM_Mask
        JZ .70:                                      ; Skip when no immediate was requested.
        ;SHR EDX,0                                   ; Convert iiMfgIMM_Mask flags to the number of imm bytes 0,1,2,4,8.
        JSt [EDI+II.Reloc],iiRelocImmRIP,.66:        ; Do not check overflow when RIP addressing frame is used.
        CMP EAX,EDX
        LEA EAX,[EDI+II.ImmLow]
        Msg cc=A,PgmStatus=pgmLastPass,'6728',EAX,EDX; Immediate value 0x!1Q is too big for !2D bytes.
    .66:BufferStore [EBX+STM.EmitBuffer],ESI,EDX     ; Emit 1..4 bytes of immediate value.
    .70:JNSt [EDI+II.Ppg],iiPpgPara,.72:             ; Flush the 16bit paragraph address (immediate segment value in JMPF/CALLF).
        LEA ESI,[EDI+II.Para]
        BufferStore [EBX+STM.EmitBuffer],ESI,2
    .72:JNSt [EDI+II.Ppg],iiPpgImm2,.73:             ; Flush auxiliary immediate byte.
        LEA ESI,[EDI+II.Imm2]
        BufferStore [EBX+STM.EmitBuffer],ESI,1       ; The instruction is now emitted.
    .73:MOV EAX,iiPpgVSIBind                         ; VSIB check if vector indexregister is required and used.
         MOV EDX,[EDI+II.Ppx]
         MOV ECX,[EDI+II.Ppg]
         AND EDX,EAX
         AND ECX,EAX
         JNZ .74:                                    ; If VSIB is required.
         TEST EDX
         Msg cc=NZ,'6284'                            ; This instruction does not accept vector indexregister.
         JMP .80:                                    ; If no SSE register was used as index.

    .GetOrdinal: PROC ; Return ordinal number from 'R' register or 'M' VSIB indexregister in operand EDX.
            ; Input:  EDI=^II, EDX=^EXP.
            ; Output: EAX=register ordinal 0..31 or -1 when operand is not 'R' or 'M'.
            MOV EAX,[EDX+EXP.Status]
            Dispatch AL,'R','M'
            MOV EAX,-1
            RET
         .R:Invoke IiGetRegOrdinal,[EDX+EXP.Low]
            RET
         .M:SHR EAX,20                               ; Convert EXP.Status:expIndex to ordinal in AL.
            AND EAX,iiReg_Ord16                       ; Get rid of other status bits.
            JNSt [EDI+II.Ppx],iiPpxV`, .V:
            OR AL,0x10                               ; Ordinal bit 4.
         .V:RET
         ENDP .GetOrdinal:

    .74: MOV EAX,ECX
         SHR EAX,20                                  ; EAX is now 0,1,2,3 for none,vm32x,vm32y,vm32z
         ADD AL,'X'-1
         CMP ECX,EDX
         JE .75:
         Msg '6285',EAX                              ; This instruction requires vector indexregister !1ZMM.
         RstSt [EBX+STM.Status],stmOperationPresent  ; Invalidate the instruction.
    .75: JNSt [EDI+II.MfxEmitted],iiMfxPREFIX_MVEX|iiMfxPREFIX_EVEX, .76:
         ; VSIB check if maskregister is used and nonzero..
         TESTB [EDI+II.AvxCode+3],0x07               ; Position of mask-register in MVEX/EVEX prefix.
         Msg cc=Z,'3312'                             ; No mask was specified, this instruction requires MASK=K1..K7.
         JNSt [EDI+II.MfxEmitted],iiMfxPREFIX_EVEX, .76:
         TESTB [EDI+II.AvxCode+3],0x80               ; Position of EVEX.z.
         Msg cc=NZ,'3313'                            ; Zeroing is not allowed in this instruction.
    .76: ; VSIB check if all involved SSE registers are distinct..
         LEA EDX,[EDI+II.Operand1]
         CALL .GetOrdinal:
         MOV ESI,EAX
         LEA EDX,[EDI+II.Operand2]
         CALL .GetOrdinal:
         MOV ECX,EAX
         LEA EDX,[EDI+II.Operand3]
         CALL .GetOrdinal:
         CMP AL,-1
         JE .78:                                     ; Skip when Operand3 was not used.
         CMP EAX,ESI
         JE .W3315:
         CMP EAX,ECX
         JE .W3315:
    .78: CMP ECX,ESI
         JNE .80:
    .W3315:Msg '3315'                                ; Destination, vector index register and mask register should be distinct.
    .80: JNSt [EDI+II.PfxEmitted],iiPfxREX,.82:      ; Check if all CPU requirements are granted by EAOPT.Machine.
         JSt [EDI+II.SssStatus],sssWidth64,.82:
         Msg '6784'                                  ; Operand requires prefix REX which is supported in 64bit segment only.
    .82: JNSt [EDI+II.Ppg],iiPpgNoREX,.84:
         JNSt [EDI+II.PfxEmitted],iiPfxREX,.84:
         Msg '6785'                                  ; Registers AH,BH,CH,DH cannot be used when instruction requires prefix REX/VEX.
    .84: MOV ECX,[EDI+II.Cpu]                        ; CPU generation required by handler/prefix/register.
         MOV EDX,[Ea.Eaopt.Machine::]                ; Granted by CPU=, SIMD= option.
         AND EDX,ECX                                 ; Not-required flags are irrelevant.
         XOR EDX,ECX                                 ; Each bit set in ECX should be set in EAOPT.Machine, too.
         MOV ECX,[EDI+II.Features]                   ; CPU features required by handler/register.
         MOV ESI,[Ea.Eaopt.Features::]               ; Granted by feature options MMX=, UNDOC= etc.
         AND ESI,ECX                                 ; Not required flags are irrelevant.
         XOR ESI,ECX                                 ; Each bit set in ECX should be set in EAOPT.Features, too.
         MOV EAX,EDX                                 ; EDX has set CPU flag(s) not granted by EUROASM options.
         OR EAX,ESI                                  ; ESI has set CPU features not granted by EUROASM options.
         JZ .86:                                     ; If both EDX,ESI are clear, all requested properties were anticipated.
         Invoke EaBufferReserve::, IiFlush           ; Otherwise report W2340.
         Invoke IiCpuToKeys,EDX,ESI,EAX
         BufferRetrieve EAX
         Invoke EaBufferRelease::,EAX
         PUSH ECX,ESI
           MOV EAX,ESP
           Msg '2340',EAX                            ; This instruction requires option "EUROASM %1S".
         POP ESI,ECX
    .86: ; Check if all used prefixes are allowed in this instruction by IiAllowPrefix
         MOV EAX,[EDI+II.PfxExplicit]                ; Prefixes explicitly used in this instruction.
         MOV EDX,[EDI+II.PfxAllowed]                 ; Expected prefixes.
         AND EAX,iiPfxMask
         AND EDX,EAX                                 ; Prefixes not explicitly used in this instruction are irrelevant.
         XOR EDX,EAX                                 ; Each bit set in EAX should be set in EDX, too.
         JZ .88:                                     ; If all prefixes are anticipated.
         BSF EAX,EDX                                 ; EAX is now 16..29, will be converted to W2356..W2369.
         MOV CL,10
         DIV CL                                      ; AL=1..2, AH=0..9.
         XCHG AL,AH
         BSWAP EAX                                   ; Construct the warning identifier.
         OR EAX,'2340'                               ; W2356..W2369 Prefix xxx is not expected in this instruction.
         Msg EAX
    .88: ; Check if explicit modifiers are allowed.
         MOV EAX,[EDI+II.MfgExplicit]                ; General modifiers explicitly requested for this instruction.
         MOV EDX,[EDI+II.MfgAllowed]
         AND EDX,EAX                                 ; Modifiers not explicitly requested in this instruction are irrelevant.
         XOR EDX,EAX                                 ; Each bit set in EAX should be set in EDX, too.
         MOV EAX,[EDI+II.MfxExplicit]                ; AVX modifiers explicitly requested for this instruction.
         MOV ECX,[EDI+II.MfxAllowed]
         RstSt EAX,iiMfxOPER_Used+iiMfxOPER_Mask
         AND ECX,EAX                                 ; Modifiers not explicitly requested in this instruction are irrelevant.
         XOR ECX,EAX                                 ; Each bit set in EAX should be set in ECX, too.
         MOV EAX,EDX                                 ; EDX:ECX should be zero.
         OR  EAX,ECX
         JZ .90:                                     ; Skip when all modifiers were allowed.
         Invoke EaBufferReserve::,IiFlush
         Invoke IiModifiersToKeys,EDX,ECX,EAX
         BufferRetrieve EAX
         Invoke EaBufferRelease::,EAX
         PUSH ECX,ESI
           MOV EAX,ESP
           Msg '2400',EAX                            ; Modifier "!1S" is not applicable in this instruction.
         POP ESI,ECX
    .90: ; Display actually used modifiers when EUROASM DISPLAYENC=YES.
         JNSt [Ea.Eaopt.Status::],eaoptDISPLAYENC,.92:
         JNSt [EBX+STM.Status],stmOperationPresent,.92: ; Skip display when the instruction was invalidated.
         BufferRetrieve [EBX+STM.EmitBuffer]
         MOV EDX,ECX                                 ; Instruction size.
         Invoke EaBufferReserve::,%^PROC
         Invoke IiModifiersToKeys,[EDI+II.MfgEmitted],[EDI+II.MfxEmitted],EAX
         BufferRetrieve EAX
         Invoke EaBufferRelease::,EAX
         PUSH ECX,ESI
           MOV EAX,ESP
           Msg '1080',EDX,EAX                        ; Emitted size=!1D!2S.
         POP ESI,ECX
    .92: ; Check if explicit modifiers were satisfied.
         MOV ECX,[EDI+II.MfxExplicit]                ; AVX modifiers explicitly requested for this instruction.
         MOV EAX,[EDI+II.MfxEmitted]                 ; Modifiers actually used in instruction assembly.
         RstSt ECX,iiMfxOPER_Mask+iiMfxOPER_Used     ; OPER= is always obeyed.
         AND EAX,ECX                                 ; Modifiers not used in this instruction are irrelevant.
         XOR ECX,EAX                                 ; Each bit set in ECX should be set in EAX, too.
    .94: MOV EDX,[EDI+II.MfgExplicit]                ; General modifiers explicitly requested for this instruction.
         MOV EAX,[EDI+II.MfgEmitted]                 ; Modifiers actually used in instruction assembly.
         AND EAX,EDX                                 ; Modifiers not used in this instruction are irrelevant.
         XOR EDX,EAX                                 ; Each bit set in EDX should be set in EAX, too.
         MOV EAX,EDX                                 ; Test if EDX:ECX=0.
         OR  EAX,ECX
         JZ .96:                                     ; Skip when all modifiers were obeyed, otherwise W2401.
         Invoke EaBufferReserve::,IiFlush
         Invoke IiModifiersToKeys,EDX,ECX,EAX
         BufferRetrieve EAX
         Invoke EaBufferRelease::,EAX
         JECXZ .96:
         PUSH ECX,ESI
           MOV EAX,ESP
           Msg '2401',EAX,PgmStatus=pgmLastPass      ; Modifiers "!1S" could not be obeyed in this instruction.
         POP ESI,ECX
    .96: ; Check if instruction suffix is not in conflict with effective operand size.
         MOV EAX,[EDI+II.MfgEmitted]
         MOV EDX,[EDI+II.MfgSuffix]                  ; Data width commanded with mnemonic suffix.
         JNSt [EDI+II.MfgEmitted],iiMfgDATA_WORD,.98:
         JSt [EDI+II.MfgEmitted],iiMfgIMM_BYTE,.99:  ; A special case for PUSHB imm8 where IMM=B,DATA=W. Version 20251110.
    .98: AND EAX,EDX
         CMP EAX,EDX
         JE .99:
         TEST EDX,iiMfgDATA_Mask
         Msg cc=NZ,'6740',PgmStatus=pgmLastPass      ; Impracticable operand-size requested with mnemonic suffix.
         Msg cc=Z, '6760',PgmStatus=pgmLastPass      ; Impracticable distance requested with mnemonic suffix.
    .99:
      EndProcedure IiFlush

DebugOutput proc StdOutput esi,Size=ecx RET ENDP

     ENDPROGRAM ii

▲Back to the top▲