# this file is included both by the bootstrapping compiler and by the later optimization library # registers < [ /rax /rcx /rdx /rbx /rsp /rbp /rsi /rdi /r8 /r9 /r10 /r11 /r12 /r13 /r14 /r15 ] { 1 -01 defv }' each > ==:bit64table { bit64table -01 . -- } /bit64assert deff < [ /eax /ecx /edx /ebx /esp /ebp /esi /edi /r8d /r9d /r10d /r11d /r12d /r13d /r14d /r15d ] { 1 -01 defv }' each > ==:bit32table { bit32table -01 . -- } /bit32assert deff < [ /ax /cx /dx /bx /sp /bp /si /di /r8w /r9w /r10w /r11w /r12w /r13w /r14w /r15w ] { 1 -01 defv }' each > ==:bit16table { bit16table -01 . -- } /bit16assert deff < [ /al /cl /dl /bl /spl /ah /bpl /ch /sil /dh /dil /bh /r8b /r9b /r10b /r11b /r12b /r13b /r14b /r15b ] { 1 -01 defv }' each > ==:bit8table { bit8table -01 . -- } /bit8assert deff < [ /xmm0 /xmm1 /xmm2 /xmm3 /xmm4 /xmm5 /xmm6 /xmm7 /xmm8 /xmm9 /xmm10 /xmm11 /xmm12 /xmm13 /xmm14 /xmm15 ] { 1 -01 defv }' each > ==:xmmTable { xmmTable -01 . -- } /xmmAssert deff < [ /zero /al /ax /eax /rax /none /xmm0 ] { 0 -01 defv }' each [ /one /cl /cx /ecx /rcx /xmm1 ] { 1 -01 defv }' each [ /two /dl /dx /edx /rdx /xmm2 ] { 2 -01 defv }' each [ /three /bl /bx /ebx /rbx /xmm3 ] { 3 -01 defv }' each [ /four /sib /spl /ah /sp /esp /rsp /xmm4 ] { 4 -01 defv }' each [ /five /rip /bpl /bp /ebp /rbp /xmm5 ] { 5 -01 defv }' each [ /six /sil /si /esi /rsi /xmm6 ] { 6 -01 defv }' each [ /seven /dil /di /edi /rdi /xmm7 ] { 7 -01 defv }' each [ /r8b /r8w /r8d /r8 /xmm8 ] { 8 -01 defv }' each [ /r9b /r9w /r9d /r9 /xmm9 ] { 9 -01 defv }' each [ /r10b /r10w /r10d /r10 /xmm10 ] { 10 -01 defv }' each [ /r11b /r11w /r11d /r11 /xmm11 ] { 11 -01 defv }' each [ /r12b /r12w /r12d /r12 /xmm12 ] { 12 -01 defv }' each [ /r13b /r13w /r13d /r13 /xmm13 ] { 13 -01 defv }' each [ /r14b /r14w /r14d /r14 /xmm14 ] { 14 -01 defv }' each [ /r15b /r15w /r15d /r15 /xmm15 ] { 15 -01 defv }' each > ==:regnoTable { regnoTable -01 . } /regno deff < [ /al /cl /dl /bl ] { 0 -01 defv }' each [ /spl /bpl /sil /dil ] { 1 -01 defv }' each [ /r8b /r9b /r10b /r11b /r12b /r13b /r14b /r15b ] { 1 -01 defv }' each > ==:rexreqbyteTable { rexreqbyteTable -01 . } /rexreqbyte deff # encoding a REX prefix { # ==b ==x ==r ==w %40 -01 regno %08 band 0 gt %01 mul add -01 regno %08 band 0 gt %02 mul add -01 regno %08 band 0 gt %04 mul add -01 0 gt %08 mul add } /rex deff { ==mem ==reg mem [ /spl /sp /esp /rsp /bpl /bp /ebp /rbp /r12b /r12w /r12d /r12 /r13b /r13w /r13d /r13 ] eq any { "modrm00 not possible on rsp / rbp / r12 / r13 and their partial registers" die } rep %00 mem regno %07 band add reg regno 8 mul %38 band add } /modrm00 deff { ==mem ==reg mem [ /spl /sp /esp /rsp /r12b /r12w /r12d /r12 ] eq any { # actually encode sib with rsp index register (to get it ignored) %40 /sib regno %07 band add reg regno 8 mul %38 band add # sib-byte %00 # index = 1 (ignored anyway) %38 /rsp regno 8 mul band add # (ignored) %07 mem regno band add } { %40 mem regno %07 band add reg regno 8 mul %38 band add } ? * } /modrm01 deff { ==mem ==reg mem [ /spl /sp /esp /rsp ] eq any { # actually encode sib with rsp index register (to get it ignored) %80 /sib regno %07 band add reg regno 8 mul %38 band add # sib-byte %00 # index = 1 (ignored anyway) %38 /rsp regno 8 mul band add # (ignored) %07 mem regno band add } { %80 mem regno %07 band add reg regno 8 mul %38 band add } ? * } /modrm10 deff { ==mem ==reg %C0 mem regno %07 band add reg regno 8 mul %38 band add } /modrm11 deff { ==base ==idx ==scale idx [ /spl /sp /esp /rsp ] eq any { "sib cannot encode rsp as index" die } rep base [ /bpl /bp /ebp /rbp ] eq any { "sib cannot encode rbp as base" die } rep scale _ 0 gt not { "invalid scale chosen for sib" die } rep 8 le not { "invalid scale chosen for sib" die } rep scale [ 1 %00 %40 1 %80 1 1 1 %C0 ] * _ 1 eq { "invalid scale chosen for sib" die } rep %C0 band %38 idx regno 8 mul band add %07 base regno band add } /sib deff { 8 { _ 256 umod -01 256 udiv } rep -- } /imm64 deff # div / mod unsigned { _ 0 lt { 4294967296 add } rep 4294967295 band 4 { _ 256 umod -01 256 udiv } rep -- } /imm32 deff { _ 0 lt { 65536 add } rep 65535 band 2 { _ 256 umod -01 256 udiv } rep -- } /imm16 deff { _ 0 lt { 256 add } rep 255 band } /imm8 deff { %66 } /width16 deff # label handling < < { defv }' /put deff > ==labels [ ] ==labelHoles { =labelHoles }' =*setLabelHoles < > ==outer > ==labelStack { ==l ] _ len l labelStack .labels .put [ -011 len dearray } /label deff { ==l ] _ len ==offset labelStack .labelHoles [ { labelStack .labels l . offset 1 add sub _ 128 lt not { "8 bit relative label out of range: " l cat die } rep _ 128 neg ge not { "8 bit relative label out of range: " l cat die } rep imm8 offset -102 =[] } ] cat labelStack .setLabelHoles [ -011 len dearray %00 } /labelRel8 deff { ==l ] _ len ==offset labelStack .labelHoles [ { labelStack .labels l . offset 2 add sub _ 32768 lt not { "16 bit relative label out of range: " l cat die } rep _ 32768 neg ge not { "16 bit relative label out of range: " l cat die } rep imm16 offset [ 0 1 ] add 2 dearray -204314 =[] =[] } ] cat labelStack .setLabelHoles [ -011 len dearray %00 %00 } /labelRel16 deff { ==l ] _ len ==offset labelStack .labelHoles [ { labelStack .labels l . offset 4 add sub _ 2147483648 lt not { "32 bit relative label out of range: " l cat die } rep _ 2147483648 neg ge not { "32 bit relative label out of range" l cat die } rep imm32 offset [ 0 1 2 3 ] add 4 dearray -408518628738 =[] =[] =[] =[] } ] cat labelStack .setLabelHoles [ -011 len dearray %00 %00 %00 %00 } /labelRel32 deff { < < { defv }' /put deff > ==labels [ ] ==labelHoles { =labelHoles }' =*setLabelHoles labelStack ==outer > =labelStack } /labelRecord deff { ==opcodes labelStack .labelHoles { opcodes -01 * } each labelStack .outer =labelStack opcodes } /labelResolve deff { < ==opcode ==name { ==offset offset 128 neg ge not { "Rel8 offset below -128" die } rep offset 128 lt not { "Rel8 offset above 127" die } rep opcode offset imm8 } name "Rel8" cat { ==lbl opcode lbl labelRel8 } name "Lbl8" cat > -- 2 |deff rep }' /defJmpRel8 deff { "opcode only exists on AMD cpus (and has 'interesting' semantics even there)" die } /defJmpRel16 deff { < ==opcode ==name { ==offset offset 2147483648 neg ge not { "Rel32 offset below -2147483648" die } rep offset 2147483648 lt not { "Rel32 offset above 2147483647" die } rep %0F opcode offset imm32 } name "Rel32" cat { ==lbl %0F opcode lbl labelRel32 } name "Lbl32" cat > -- 2 |deff rep }' /defJmpRel32 deff # generalized arithmethic 8086 instructions # { cat _ { "executing " -01 cat dump }_ -102 ; -01 deff }' /defOp deff # debugging version { cat deff }' /defOp deff < # base register only { < _ bit64assert ==base /none ==idx { ==r r base modrm00 } /encode deff > } ==Mem # base register plus 8 bit displacement { < _ bit64assert ==base /none ==idx _ 128 lt not { "Disp8 too large" die } rep ==disp { ==r r base modrm01 disp imm8 } /encode deff > } ==MemDisp8 # base register plus 32 bit displacement { < _ bit64assert ==base /none ==idx ==disp { ==r r base modrm10 disp imm32 } /encode deff > } ==MemDisp32 # base and index register { < _ bit64assert ==base _ bit64assert ==idx { ==r r /sib modrm00 1 idx base sib } /encode deff > } ==MemIndex # base and scaled index register { < _ bit64assert ==base _ bit64assert ==idx ==scale { ==r r /sib modrm00 scale idx base sib } /encode deff > } ==MemIndexScale # base and scaled index register plus 8 bit displacement { < _ bit64assert ==base _ bit64assert ==idx ==scale _ 128 lt not { "Disp8 too large" die } rep ==disp { ==r r /sib modrm01 scale idx base sib disp imm8 } /encode deff > } ==MemIndexScaleDisp8 # base and scaled index register plus 8 bit displacement { < _ bit64assert ==base _ bit64assert ==idx ==scale ==disp { ==r r /sib modrm10 scale idx base sib disp imm32 } /encode deff > } ==MemIndexScaleDisp32 # rip relative adressing pointing at label { < /rip ==base /none ==idx ==lbl { ==r r /rip modrm00 lbl labelRel32 } /encode deff > } ==RipLbl32 > ==memoryAddressingVariants { ==opcode ==mnemonic { ==dst ==src src bit8assert dst bit8assert src regno %07 gt dst regno %07 gt src rexreqbyte dst rexreqbyte or or or { 0 src /none dst rex } rep opcode src dst modrm11 } mnemonic /bRegReg defOp memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem ==reg reg bit8assert reg regno %07 gt reg rexreqbyte mem .base regno %07 gt mem .idx regno %07 gt or or or { 0 reg mem .idx mem .base rex } rep opcode reg mem .encode } mnemonic /bReg variant cat defOp { ==reg parse ==mem reg bit8assert reg regno %07 gt reg rexreqbyte mem .base regno %07 gt mem .idx regno %07 gt or or or { 0 reg mem .idx mem .base rex } rep opcode %02 add reg mem .encode } mnemonic /b variant cat /Reg cat defOp } each } /defAsmAddb deff { ==opcode ==mnemonic { ==dst ==src dst bit32assert src bit32assert dst regno %07 gt src regno %07 gt or { 0 src /none dst rex } rep opcode src dst modrm11 } mnemonic /lRegReg defOp memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem ==reg reg bit32assert reg regno %07 gt mem .base regno %07 gt mem .idx regno %07 gt or or { 0 reg mem .idx mem .base rex } rep opcode reg mem .encode } mnemonic /lReg variant cat defOp { ==reg parse ==mem reg bit32assert reg regno %07 gt mem .base regno %07 gt mem .idx regno %07 gt or or { 0 reg mem .idx mem .base rex } rep opcode %02 add reg mem .encode } mnemonic /l variant cat /Reg cat defOp } each } /defAsmAddl deff { ==opcode ==mnemonic { ==dst ==src dst bit64assert src bit64assert 1 src /none dst rex opcode src dst modrm11 } mnemonic /qRegReg defOp memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem ==reg reg bit64assert 1 reg mem .idx mem .base rex opcode reg mem .encode } mnemonic /qReg variant cat defOp { ==reg parse ==mem reg bit64assert 1 reg mem .idx mem .base rex opcode %02 add reg mem .encode } mnemonic /q variant cat /Reg cat defOp } each } /defAsmAddq deff { ==modrmOpcode ==mnemonic { ==reg ==i reg bit8assert i 256 lt not { "Imm8 too large" die } rep reg regno %07 gt reg rexreqbyte or { 0 /none /none reg rex } rep %80 modrmOpcode reg modrm11 i imm8 } mnemonic /bImmReg defOp { ==reg ==i reg bit64assert i 256 lt not { "Imm8 too large" die } rep 1 /none /none reg rex %83 modrmOpcode reg modrm11 i imm8 } mnemonic /qImm8Reg defOp { ==reg ==i reg bit64assert i 65536 65536 mul lt not { "Imm32 too large" die } rep 1 /none /none reg rex %81 modrmOpcode reg modrm11 i imm32 } mnemonic /qImm32Reg defOp memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem ==i i 256 lt not { "Imm8 too large" die } rep mem .base regno %07 gt mem .idx regno %07 gt or { 0 /none mem .idx mem .base rex } rep %80 modrmOpcode mem .encode i imm8 } mnemonic /bImm variant cat defOp { parse ==mem ==i i 65536 lt not { "Imm16 too large" die } rep width16 mem .base regno %07 gt mem .idx regno %07 gt or { 0 /none mem .idx mem .base rex } rep %81 modrmOpcode mem .encode i imm16 } mnemonic /wImm variant cat defOp { parse ==mem ==i i 256 lt not { "Imm8 too large" die } rep 1 /none mem .idx mem .base rex %83 modrmOpcode mem .encode i imm8 } mnemonic /qImm8 variant cat defOp { parse ==mem ==i i 65536 65536 mul lt not { "Imm32 too large" die } rep 1 /none mem .idx mem .base rex %81 modrmOpcode mem .encode i imm32 } mnemonic /qImm32 variant cat defOp } each } /defAsmAddImm deff # instructions { ==reg ==mem reg bit32assert mem bit64assert reg regno %07 gt mem regno %07 gt or { 0 reg /none mem rex } rep %03 reg mem modrm00 } /addlMemReg deff { ==opcode2 ==opcode1 ==mnemonic { ==reg2 ==reg1 reg2 bit64assert reg1 bit64assert 1 reg1 /none reg2 rex opcode1 opcode2 reg1 reg2 modrm11 } mnemonic /qRegReg defOp memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem ==reg reg bit64assert 1 reg mem .idx mem .base rex opcode1 opcode2 reg mem .encode } mnemonic /qReg variant cat defOp } each } /defAsmBtq deff { ==opcode2 ==opcode1 ==mnemonic { ==reg1 ==reg2 reg2 bit64assert reg1 bit64assert 1 reg1 /none reg2 rex opcode1 opcode2 reg1 reg2 modrm11 } mnemonic /qRegReg defOp memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { ==reg parse ==mem reg bit64assert 1 reg mem .idx mem .base rex opcode1 opcode2 reg mem .encode } mnemonic /qReg variant cat defOp } each } /defAsmBsfq deff { ==modrmOpcode ==opcode2 ==opcode1 ==mnemonic { ==reg ==i reg bit64assert 1 /none /none reg rex opcode1 opcode2 modrmOpcode reg modrm11 i imm8 } mnemonic /qImm8Reg defOp memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem ==imm 1 /none mem .idx mem .base rex opcode1 opcode2 modrmOpcode mem .encode imm imm8 } mnemonic /qImm8 variant cat defOp } each } /defAsmBtqImm deff /adc %11 defAsmAddq /adc /two defAsmAddImm /add %01 defAsmAddq /add /zero defAsmAddImm /and %20 defAsmAddb /and %21 defAsmAddq /and /four defAsmAddImm /bt %0F %A3 defAsmBtq /bt %0F %BA /four defAsmBtqImm /btr %0F %B3 defAsmBtq /btr %0F %BA /six defAsmBtqImm /bts %0F %AB defAsmBtq /bts %0F %BA /five defAsmBtqImm /bsf %0F %BC defAsmBsfq /bsr %0F %BD defAsmBsfq { ==reg reg bit64assert 1 /none /none reg rex %0F %C8 reg regno %07 band add } /bswapqReg deff { ==off %E8 off imm32 } /callqRel32 deff { ==lbl %E8 lbl labelRel32 } /callqLbl32 deff { ==reg reg bit64assert reg regno %07 gt { 1 /none /none reg rex } rep %FF /two reg modrm11 } /callqReg deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem mem .base regno %07 gt mem .idx regno %07 gt or { 0 /none mem .idx mem .base rex } rep %FF /two mem .encode } /callq variant defOp } each { 1 /none /none /none rex %99 } /cqo deff { %FC } /cld deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %47 dst src modrm11 } /cmovaqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %46 dst src modrm11 } /cmovnaqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %43 dst src modrm11 } /cmovaeqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %42 dst src modrm11 } /cmovnaeqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %42 dst src modrm11 } /cmovbqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %46 dst src modrm11 } /cmovbeqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %42 dst src modrm11 } /cmovcqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %4F dst src modrm11 } /cmovgqRegReg deff { ==reg ==mem mem bit64assert reg bit64assert 1 reg /none mem rex %0F %43 reg mem modrm00 } /cmovncqMemReg deff { ==reg ==mem ==disp disp 128 lt not { "Disp8 out of range" die } rep mem bit64assert reg bit64assert 1 reg /none mem rex %0F %43 reg mem modrm01 disp imm8 } /cmovncqMemDisp8Reg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %4E dst src modrm11 } /cmovngqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %4D dst src modrm11 } /cmovgeqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %4C dst src modrm11 } /cmovngeqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %45 dst src modrm11 } /cmovnzqRegReg deff { ==dst ==src src bit64assert dst bit64assert 1 dst /none src rex %0F %44 dst src modrm11 } /cmovzqRegReg deff { %A6 } /cmpsb deff { 1 /none /none /none rex %A7 } /cmpsq deff { ==mem ==reg reg bit32assert mem bit64assert reg regno %07 gt mem regno %07 gt or { 0 reg /none mem rex } rep %39 reg mem modrm00 } /cmplRegMem deff /cmp %38 defAsmAddb /cmp %39 defAsmAddq /cmp /seven defAsmAddImm { ==dst ==src src bit64assert dst xmmAssert %F2 1 dst /none src rex %0F %2A dst src modrm11 } /cvtsi2sdqRegXmm deff { ==dst ==src src xmmAssert dst xmmAssert %F2 1 dst /none src rex %0F %5A dst src modrm11 } /cvtsd2ssXmmXmm deff { ==dst ==src src xmmAssert dst xmmAssert %F3 1 dst /none src rex %0F %5A dst src modrm11 } /cvtss2sdXmmXmm deff { ==mem mem bit64assert 1 /none /none mem rex %FF /one mem modrm00 } /decqMem deff { ==reg reg bit64assert 1 /none /none reg rex %FF /one reg modrm11 } /decqReg deff { ==reg reg bit64assert 1 /none /none reg rex %F7 /six reg modrm11 } /divqReg deff { %DE %C1 } /faddp deff { %DF %F1 } /fcomip deff { %DE %F9 } /fdivp deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem mem .base regno %07 gt mem .idx regno %07 gt or { 0 /none mem .idx mem .base rex } rep %DF /five mem .encode } /fildq variant defOp } each memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem mem .base regno %07 gt mem .idx regno %07 gt or { 0 /none mem .idx mem .base rex } rep %DF /seven mem .encode } /fistp64 variant defOp } each memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem mem .base regno %07 gt mem .idx regno %07 gt or { 0 /none mem .idx mem .base rex } rep %DD /zero mem .encode } /fld64 variant defOp } each { %DE %C9 } /fmulp deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem mem .base regno %07 gt mem .idx regno %07 gt or { 0 /none mem .idx mem .base rex } rep %DD /three mem .encode } /fstp64 variant defOp } each { %DD %D8 } /fstp deff { %DE %E9 } /fsubp deff { ==reg reg bit64assert 1 /none /none reg rex %F7 /seven reg modrm11 } /idivqReg deff { ==reg reg bit8assert 1 /none /none reg rex %FE /zero reg modrm11 } /incbReg deff { ==mem mem bit64assert 1 /none /none mem rex %FF /zero mem modrm00 } /incqMem deff { ==reg reg bit64assert 1 /none /none reg rex %FF /zero reg modrm11 } /incqReg deff /loop %E2 defJmpRel8 /jmp %EB defJmpRel8 { ==lbl "opcode only exists on AMD cpus (and has 'interesting' semantics even there)" die width16 %E9 lbl labelRel16 } /jmpLbl16 deff { ==lbl %E9 lbl labelRel32 } /jmpLbl32 deff /ja _ %77 defJmpRel8 %87 defJmpRel32 /jae _ %73 defJmpRel8 %83 defJmpRel32 /jb _ %72 defJmpRel8 %82 defJmpRel32 /jc _ %72 defJmpRel8 %82 defJmpRel32 /jbe _ %76 defJmpRel8 %86 defJmpRel32 /je _ %74 defJmpRel8 %84 defJmpRel32 /jg _ %7F defJmpRel8 %8F defJmpRel32 /jge _ %7D defJmpRel8 %8D defJmpRel32 /jl _ %7C defJmpRel8 %8C defJmpRel32 /jle _ %7E defJmpRel8 %8E defJmpRel32 /jnb _ %73 defJmpRel8 %83 defJmpRel32 /jnc _ %73 defJmpRel8 %83 defJmpRel32 /jne _ %75 defJmpRel8 %85 defJmpRel32 /jng _ %7E defJmpRel8 %8E defJmpRel32 /jnl _ %7D defJmpRel8 %8D defJmpRel32 /jnge _ %7C defJmpRel8 %8C defJmpRel32 /jnle _ %7F defJmpRel8 %8F defJmpRel32 /jns _ %79 defJmpRel8 %89 defJmpRel32 /jno _ %71 defJmpRel8 %81 defJmpRel32 /jnz _ %75 defJmpRel8 %85 defJmpRel32 /js _ %78 defJmpRel8 %88 defJmpRel32 /jo _ %70 defJmpRel8 %80 defJmpRel32 /jz _ %74 defJmpRel8 %84 defJmpRel32 { ==reg reg bit64assert reg regno %07 gt { 1 /none /none reg rex } rep %FF /four reg modrm11 } /jmpqReg deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem mem .base regno %07 gt mem .idx regno %07 gt or { 0 /none mem .idx mem .base rex } rep %FF /four mem .encode } /jmpq variant defOp } each { ==reg ==mem ==idx ==scale ==disp reg bit32assert mem bit64assert idx bit64assert disp 128 lt not { "Disp8 out of range" die } rep reg regno %07 gt mem regno %07 gt idx regno %07 gt or or { 0 reg idx mem rex } rep %8D reg /sib modrm01 scale idx mem sib disp imm8 } /lealMemIndexScaleDisp8Reg deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { ==reg parse ==mem reg bit64assert 1 reg mem .idx mem .base rex %8D reg mem .encode } /leaq variant /Reg cat defOp } each { %AC } /lodsb deff { 1 /none /none /none rex %AD } /lodsq deff { ==reg ==i reg bit8assert i 256 lt not { "Imm8 too large" die } rep reg regno %07 gt reg rexreqbyte or { 0 /none /none reg rex } rep %C6 /zero reg modrm11 i imm8 } /movbImmReg deff { ==mem ==i mem bit64assert i 256 lt not { "Imm8 too large" die } rep mem regno %07 gt { 0 /none /none mem rex } rep %C6 /zero mem modrm00 i imm8 } /movbImmMem deff { ==mem ==disp ==i mem bit64assert disp 128 lt not { "Disp8 out of range" die } rep i 256 lt not { "Imm8 too large" die } rep mem regno %07 gt { 0 /none /none mem rex } rep %C6 /zero mem modrm01 disp imm8 i imm8 } /movbImmMemDisp8 deff { ==mem ==i mem bit64assert i 65536 lt not { "Imm16 too large" die } rep width16 mem regno %07 gt { 0 /none /none mem rex } rep %C7 /zero mem modrm00 i imm16 } /movwImmMem deff { ==mem ==disp ==i mem bit64assert disp 128 lt not { "Disp8 out of range" die } rep i 65536 lt not { "Imm16 too large" die } rep width16 mem regno %07 gt { 0 /none /none mem rex } rep %C7 /zero mem modrm01 disp imm8 i imm16 } /movwImmMemDisp8 deff { ==mem ==i mem bit64assert i 65536 65536 mul lt not { "Imm32 too large" die } rep mem regno %07 gt { 0 /none /none mem rex } rep %C7 /zero mem modrm00 i imm32 } /movlImmMem deff { ==mem ==disp ==i mem bit64assert disp 128 lt not { "Disp8 out of range" die } rep i 65536 65536 mul lt not { "Imm32 too large" die } rep mem regno %07 gt { 0 /none /none mem rex } rep %C7 /zero mem modrm01 disp imm8 i imm32 } /movlImmMemDisp8 deff { ==reg ==i reg bit64assert 1 /none /none reg rex %B8 reg regno %07 band add i imm64 } /movqImmReg deff { ==mem ==disp ==i mem bit64assert i 2147483648 lt not { "Imm32 too small" die } rep i 2147483648 neg ge not { "Imm32 too large" die } rep 1 /none /none mem rex %C7 /zero mem modrm01 disp imm8 i imm32 } /movqImm32MemDisp8 deff { ==reg reg bit64assert 1 /none /none reg rex %B8 reg regno %07 band add } /movqImmOOBReg deff /mov %88 defAsmAddb /mov %89 defAsmAddl /mov %89 defAsmAddq { ==dst ==src src bit64assert dst xmmAssert %66 1 dst /none src rex %0F %6E dst src modrm11 } /movqRegXmm deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { ==dst parse ==mem dst xmmAssert %66 1 dst mem .idx mem .base rex %0F %6E dst mem .encode } /movq variant "Xmm" cat defOp } each { ==dst ==src src xmmAssert dst bit64assert %66 1 src /none dst rex %0F %7E src dst modrm11 } /movqXmmReg deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem ==src src xmmAssert %66 1 src mem .idx mem .base rex %0F %7E src mem .encode } /movqXmm variant defOp } each { %A4 } /movsb deff { width16 %A5 } /movsw deff { %A5 } /movsl deff { 1 /none /none /none rex %A5 } /movsq deff { ==dst ==src dst bit64assert src bit8assert 1 dst /none src rex %0F %BE dst src modrm11 } /movsxbqRegReg deff { ==dst ==src dst bit64assert src bit16assert 1 dst /none src rex %0F %BF dst src modrm11 } /movsxwqRegReg deff { ==dst ==src dst bit64assert src bit32assert 1 dst /none src rex %63 dst src modrm11 } /movsxlqRegReg deff { ==dst ==src dst bit64assert src bit8assert 1 dst /none src rex %0F %B6 dst src modrm11 } /movzxbqRegReg deff { ==dst ==src dst bit64assert src bit16assert 1 dst /none src rex %0F %B7 dst src modrm11 } /movzxwqRegReg deff { ==reg ==mem reg bit64assert mem bit64assert 1 reg /none mem rex %0F %B6 reg mem modrm00 } /movzxMem8Reg64 deff # TODO: this is a weird name, should be movzxbqMemReg { ==reg ==mem ==disp reg bit64assert mem bit64assert disp 128 lt not { "Disp8 out of range" die } rep 1 reg /none mem rex %0F %B6 reg mem modrm01 disp imm8 } /movzxMem8Disp8Reg64 deff # TODO: this is a weird name, should be movzxbqMemDisp8Reg { ==reg ==mem ==idx ==scale ==disp reg bit64assert mem bit64assert idx bit64assert disp 128 lt not { "Disp8 out of range" die } rep 1 reg idx mem rex %0F %B6 reg /sib modrm01 scale idx mem sib disp imm8 } /movzxMem8IndexScaleDisp8Reg64 deff # TODO: this is a weird name, should be movzxbqMemIndexScaleDisp8Reg { ==reg reg bit64assert 1 /none /none reg rex %F7 /four reg modrm11 } /mulqReg deff { ==reg reg bit64assert 1 /none /none reg rex %F7 /three reg modrm11 } /negqReg deff { %90 } /nop deff { ==reg reg bit8assert reg regno %07 gt reg rexreqbyte or { 0 /none /none reg rex } rep %F6 /two reg modrm11 } /notbReg deff { ==reg reg bit64assert 1 /none /none reg rex %F7 /two reg modrm11 } /notqReg deff /or %08 defAsmAddb /or %09 defAsmAddq /or /one defAsmAddImm { ==reg reg regno %07 gt { 1 /none /none reg rex } rep %58 reg regno %07 band add } /popqReg deff { ==reg reg regno %07 gt { 1 /none /none reg rex } rep %50 reg regno %07 band add } /pushqReg deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem mem .base regno %07 gt mem .idx regno %07 gt or { 1 /none mem .idx mem .base rex } rep %8F /zero mem .encode } /popq variant defOp { parse ==mem mem .base regno %07 gt mem .idx regno %07 gt or { 1 /none mem .idx mem .base rex } rep %FF /six mem .encode } /pushq variant defOp } each { ==imm %68 imm imm32 } /pushqImm32 deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem mem .base regno %07 gt mem .idx regno %07 gt or { 1 /none mem .idx mem .base rex } rep %0F %0D /zero mem .encode } /prefetch variant defOp } each { %F3 } /reprcx deff { %F2 } /repnz deff { %F3 } /repz deff { %C3 } /retn deff { ==reg reg bit8assert reg regno %07 gt reg rexreqbyte or { 0 reg /none /none rex } rep %D2 /zero reg modrm11 } /rolbClReg deff { ==reg reg bit64assert 1 /none /none reg rex %D3 /zero reg modrm11 } /rolqClReg deff { ==reg ==i reg bit64assert i 64 lt not { "Shift immediate too large" die } rep 1 /none /none reg rex %C1 /zero reg modrm11 i imm8 } /rolqImm8Reg deff { ==reg reg bit8assert reg regno %07 gt reg rexreqbyte or { 0 reg /none /none rex } rep %D2 /one reg modrm11 } /rorbClReg deff { ==reg reg bit64assert 1 /none /none reg rex %D3 /one reg modrm11 } /rorqClReg deff { ==reg ==i reg bit64assert i 64 lt not { "Shift immediate too large" die } rep 1 /none /none reg rex %C1 /one reg modrm11 i imm8 } /rorqImm8Reg deff { %AE } /scasb deff { 1 /none /none /none rex %AF } /scasq deff { ==reg reg regno %07 gt reg rexreqbyte or { 0 reg /none /none rex } rep %0F %92 /zero reg modrm11 } /setcbReg deff { ==reg reg regno %07 gt reg rexreqbyte or { 0 reg /none /none rex } rep %0F %94 /zero reg modrm11 } /seteReg deff { ==reg reg regno %07 gt reg rexreqbyte or { 0 reg /none /none rex } rep %0F %95 /zero reg modrm11 } /setneReg deff { ==reg reg regno %07 gt reg rexreqbyte or { 0 reg /none /none rex } rep %0F %9C /zero reg modrm11 } _ /setlReg deff /setngeReg deff { ==reg reg regno %07 gt reg rexreqbyte or { 0 reg /none /none rex } rep %0F %9D /zero reg modrm11 } _ /setnlReg deff /setgeReg deff { ==reg reg regno %07 gt reg rexreqbyte or { 0 reg /none /none rex } rep %0F %9E /zero reg modrm11 } _ /setleReg deff /setngReg deff { ==reg reg regno %07 gt reg rexreqbyte or { 0 reg /none /none rex } rep %0F %9F /zero reg modrm11 } _ /setnleReg deff /setgReg deff { ==reg reg bit64assert 1 /none /none reg rex %D1 /four reg modrm11 } /shlq1Reg deff { ==reg reg bit64assert 1 /none /none reg rex %D3 /four reg modrm11 } /shlqClReg deff { ==reg ==i reg bit64assert i 64 lt not { "Shift immediate too large" die } rep 1 /none /none reg rex %C1 /four reg modrm11 i imm8 } /shlqImm8Reg deff { ==reg reg bit64assert 1 /none /none reg rex %D1 /five reg modrm11 } /shrq1Reg deff { ==reg reg bit64assert 1 /none /none reg rex %D3 /five reg modrm11 } /shrqClReg deff { ==reg ==i reg bit64assert i 64 lt not { "Shift immediate too large" die } rep 1 /none /none reg rex %C1 /five reg modrm11 i imm8 } /shrqImm8Reg deff { %FD } /std deff { %AA } /stosb deff { 1 /none /none /none rex %AB } /stosq deff /sbb %19 defAsmAddq /sbb /three defAsmAddImm { ==reg ==mem reg bit32assert mem bit64assert reg regno %07 gt mem regno %07 gt or { 0 reg /none mem rex } rep %2B reg mem modrm00 } /sublMemReg deff /sub %29 defAsmAddq /sub /five defAsmAddImm { %0F %05 } /syscall deff { ==mem ==idx ==scale ==reg reg bit8assert mem bit64assert idx bit64assert reg regno %07 gt reg rexreqbyte mem regno %07 gt idx regno %07 gt or or or { 0 reg idx mem rex } rep %84 reg /sib modrm00 scale idx mem sib } /testbRegMemIndexScale deff { ==reg ==i reg bit8assert i 256 lt not { "Imm8 too large" die } rep reg regno %07 gt reg rexreqbyte or { 0 /none /none reg rex } rep %F6 /zero reg modrm11 i imm8 } /testbImmReg deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem ==i i 256 lt not { "Imm8 too large" die } rep mem .base regno %07 gt mem .idx regno %07 gt or { 0 /none mem .idx mem .base rex } rep %F6 /zero mem .encode i imm8 } /testbImm variant defOp } each { ==dst ==src dst bit64assert src bit64assert 1 src /none dst rex %85 src dst modrm11 } /testqRegReg deff { ==mem ==idx ==scale ==reg reg bit64assert mem bit64assert idx bit64assert 1 reg idx mem rex %85 reg /sib modrm00 scale idx mem sib } /testqRegMemIndexScale deff { %0F %0B } /ud2 deff { ==dst ==src dst bit64assert src bit64assert 1 src /none dst rex %87 src dst modrm11 } /xchgqRegReg deff memoryAddressingVariants keys { ==variant memoryAddressingVariants variant . =*parse { parse ==mem ==reg reg bit64assert 1 reg mem .idx mem .base rex %87 reg mem .encode } /xchgqReg variant defOp } each /xor %30 defAsmAddb /xor %31 defAsmAddq /xor /six defAsmAddImm # vim: syn=elymas