EuroAssembler Index Manual Download Source Macros


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 categoryUses registersModule file
allMachine instruction handlers support -ii.htm
AVendor specific (AMD) RAX..YMM15iia.htm
BIntel Fused Multiply-Add (FMA) XMM0..ZMM31iib.htm
CVendor-specific (CYRIX) MM0..MM7iic.htm
D3DNow! specific (AMD, D3NOW) XMM0..XMM15iid.htm
FFloating-point (FPU) ST0..ST7iif.htm
GGeneral instructions RAX..R15iig.htm
KMask-registers manipulation (AVX512) K0..K7iik.htm
MMultimedia (MMX) MM0..MM7iim.htm
PPacked (SSE) XMM0..XMM15iip.htm
SSystem special (SPEC, UNDOC, PROT, PRIV, MPX, SGX) specialiis.htm
TTransactional & other extensions (TSX, RTM, VMX, SVM) -iit.htm
VAdvanced Vector extension (AVX) XMM0..YMM15iiv.htm
XXOP-encodable AMD XMM0..YMM15iix.htm
YAdvanced Vector extension (AVX2) XMM0..YMM15iiy.htm
ZAdvanced Vector extension (AVX512) XMM0..ZMM31iiz.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 2250 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 instruction handler,
  4. create a link to this handler in alphabetical list %Ii?AList 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.


   EUROASM  NOWARN=2101
ii PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32
INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules.
INCLUDEHEAD  \  ; Include headers of another modules used in this module.
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,     \
syswin.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 to EXP objects by ExpEval.
.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.
;                = 0x0000_0C00 ; 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.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.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.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 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 returns to 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
      Dispatch DL,%IiEnc2
      JMP .30:
enc  %FOR %IiEnc2
.%enc:  MOV ESI,=B"%enc[],"
        JMP .80:
      %ENDFOR enc
 .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
TupleEVEX.L'.L.b alias OPER= Code value
01234567
FV32 164324644-- 0x425262FF
FV64 168328648-- 0x435363FF
HV32 84164324-- 0x324252FF
FVM 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 OPER= MVEX.S2.S1.S0 Code value
01234567
Di32 4---1122 0x2FFF0011
Df32 4--21122 0x2FF10011
Sn64 8------- 0x3FFFFFFF
Ui32 16---4488 0x4FFF2233
Sn32 16--84488 0x4FF32233
Si64 32------- 0x5FFFFFFF
Sb32 32416----- 0x524FFFFF
Di64 64------- 0x6FFFFFFF
Un32 64---16163232 0x6FFF4455
Dn32 64--3216163232 0x6FF54455
Sf32 64-16----- 0x6F4FFFFF
Si32 64416-16163232 0x624F4455
Uf32 644163216163232 0x62454455
Us32 644163216-3232 0x62454F55
Ub64 64832----- 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
76543210
ModReg/Opcode R/M
Format of SIB byte
76543210
ScaleIndex 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 flagII.memberApplicable on AVX prefix
LOCKiiPfxLOCKII.PfxEmitted-
REP iiPfxREP II.PfxEmitted-
REPEiiPfxREPEII.PfxEmitted-
REPNEiiPfxREPNEII.PfxEmitted-
ATOGGLEiiPfxATOGGLEII.PfxEmitted-
OTOGGLEiiPfxOTOGGLEII.PfxEmitted-
REXiiPfxREXII.PfxEmitted-
REX.WiiPfxREX.WII.PfxEmitted-
REX.RiiPfxREX.RII.PfxEmitted-
REX.XiiPfxREX.XII.PfxEmitted-
REX.BiiPfxREX.BII.PfxEmitted-
128iiMfgDATA_OWORDII.MfgImplicitXOP,VEX,MVEX,EVEX
256iiMfgDATA_YWORDII.MfgImplicitXOP,VEX,MVEX,EVEX
512iiMfgDATA_ZWORDII.MfgImplicitMVEX,EVEX
XOPiiMfxPREFIX_XOPII.MfxEmittedXOP
VEXiiMfxPREFIX_VEXII.MfxEmittedVEX2,VEX3
VEX2iiMfxPREFIX_VEX2II.MfxEmittedVEX2
VEX3iiMfxPREFIX_VEX3II.MfxEmittedVEX3
MVEXiiMfxPREFIX_MVEXII.MfxEmittedMVEX
EVEXiiMfxPREFIX_EVEXII.MfxEmittedEVEX
NDDiiPpxNDDII.PpxXOP,VEX,MVEX,EVEX
NDSiiPpxNDSII.PpxXOP,VEX,MVEX,EVEX
DDSiiPpxDDSII.PpxXOP,VEX,MVEX,EVEX
W0iiPpxW0II.PpxXOP,VEX,MVEX,EVEX
W1iiPpxW1II.PpxXOP,VEX3,MVEX,EVEX
WIG-II.PpxXOP,VEX,MVEX,EVEX
LZiiPpxL0II.PpxXOP,VEX,MVEX,EVEX
L0iiPpxL0II.PpxXOP,VEX,MVEX,EVEX
L1iiPpxL1II.PpxXOP,VEX,MVEX,EVEX
LIG-II.PpxXOP,VEX,MVEX,EVEX
66iiPpxPpMask 01II.PpxXOP,VEX,MVEX,EVEX
F2iiPpxPpMask 11II.PpxXOP,VEX,MVEX,EVEX
F3iiPpxPpMask 10II.PpxXOP,VEX,MVEX,EVEX
0FiiPpxMmMask 01II.PpxVEX,MVEX,EVEX
0F38iiPpxMmMask 10II.PpxVEX3,MVEX,EVEX
0F3AiiPpxMmMask 11II.PpxVEX3,MVEX,EVEX
MAP8iiPpxMmMask 00II.PpxXOP
MAP9iiPpxMmMask 01II.PpxXOP
MAP10iiPpxMmMask 10II.PpxXOP
EH0iiPpxEH0II.PpxMVEX
EH1iiPpxEH1II.PpxMVEX
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"
        %unknown %SETB FALSE
      %ENDIF
      %IF "%avx" === "MVEX"
        MOVD [EDI+II.AvxSrcMVEX],=B"%spec"
        %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 can 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: 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:. 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:
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
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 operandsEVEX / MVEX ModRM byte(V)SIB byte
RXBR'V' modregR/M scaleindexbase
mem type: Rr, [S * Rx + Rb] r3x3b3r4x4 00r2r1r0100 S1S0x2x1x0b2b1b0
reg type: Rr, Rb r3b4b3r4 11r2r1r0b2b1b0 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.
     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
 ENDPROGRAM ii

▲Back to the top▲