line = ws? s:stmt { yy->v = s; } | eol { yy->v.kind = ASM_BLANK; } | . { yy->v.kind = ASM_SYNTAX_ERROR; } ws = ([ \t]+ | comment)+ comment = "/*" ( ! "\n" ! "*/" . )* "*/" # No support for multiline comments for now as they break our line numbers. eolcomment = '#' (! "\n" .)+ eol = ws? eolcomment? "\n" stmt = '.' d:directive eol {$$ = d;} | i:instr eol { $$ = i; } | l:label eol { $$ = l; } directive = "glob" 'o'? 'l' ws i:ident { $$.globl = (Globl){.kind = ASM_DIR_GLOBL, .name = i.charptr }; } | "ascii" <'z'?> ws s:string { s.kind = *yytext ? ASM_DIR_ASCII : ASM_DIR_ASCIIZ ; $$ = s; } | "data" { $$.kind = ASM_DIR_DATA; } | "text" { $$.kind = ASM_DIR_TEXT; } | "balign" ws n:number { $$.balign = (Balign){.kind = ASM_DIR_BALIGN, .align = n.i64 }; } | "byte" ws v:value { $$.dirbyte = (Byte){.kind = ASM_DIR_BYTE, .value = v.value }; } | "short" ws v:value { $$.dirshort = (Short){.kind = ASM_DIR_SHORT, .value = v.value }; } | "int" ws v:value { $$.dirint = (Int){.kind = ASM_DIR_INT, .value = v.value }; } | "quad" ws v:value { $$.dirquad = (Quad){.kind = ASM_DIR_QUAD, .value = v.value }; } | "set" ws s:ident ws? ',' ws? v:value { $$.set = (Set){.kind = ASM_DIR_SET, .sym = s.charptr, .value = v.value }; } | "weak" ws s:ident { $$.weak = (Weak){.kind = ASM_DIR_WEAK, .sym = s.charptr}; } | fd:fill-directive { $$ = fd; } | sd:section-directive { $$ = sd; } fill-directive = "fill" ws r:number ws? "," ws? s:number ws? "," ws? v:number { $$.fill = (Fill){ .kind=ASM_DIR_FILL, .repeat = r.i64, .size = s.i64, .value = v.i64 }; } section-directive = "section" ws? n:section-name ( ws? ',' ws? f:section-flags ws? ',' ws? t:section-type {$$.section = (DirSection){.kind=ASM_DIR_SECTION, .name=n.charptr, .flags=f.charptr, .type=t.i64}; } | ws? ',' ws? f:section-flags {$$.section = (DirSection){.kind=ASM_DIR_SECTION, .name=n.charptr, .flags=f.charptr, .type=SHT_PROGBITS}; } | {$$.section = (DirSection){.kind=ASM_DIR_SECTION, .name=n.charptr, .flags="", .type=SHT_PROGBITS}; } ) section-name = <[.a-zA-Z0-9\-]+> { $$.charptr = internstring(yytext); } section-flags = '"' <[awx]*> '"' { $$.charptr = internstring(yytext); } section-type = "@nobits" { $$.i64 = SHT_NOBITS; } | "@progbits" { $$.i64 = SHT_PROGBITS; } label = i:ident ':' { $$.label = (Label){.kind = ASM_LABEL, .name = i.charptr}; } instr = # Ordered by instruction frequency for performance. # e.g. movs are very common, so they come first. # The & operator means check without consuming input. (& 'm' ( i:mov { $$ = i; } | i:movsx { $$ = i; } | i:movzx { $$ = i; } | i:mul { $$ = i; } | i:movaps { $$ = i; } | i:movq { $$ = i; } | i:movsd { $$ = i; } | i:movss { $$ = i; } | i:mulsd { $$ = i; } | i:mulss { $$ = i; })) | (& 'a' ( i:add { $$ = i; } | i:and { $$ = i; } | i:addss { $$ = i; } | i:addsd { $$ = i; })) | (& 'c' ( i:cmp { $$ = i; } | i:call { $$ = i; } | i:cvtsi2sd { $$ = i; } | i:cvtsi2ss { $$ = i; } | i:cvtss2sd { $$ = i; } | i:cvtsd2ss { $$ = i; } | i:cvttsd2si { $$ = i; } | i:cvttss2si { $$ = i; } | i:cltd { $$ = i; } | i:cqto { $$ = i; })) | (& 's' ( i:set { $$ = i; } | i:sub { $$ = i; } | i:sal { $$ = i; } | i:sar { $$ = i; } | i:shl { $$ = i; } | i:shr { $$ = i; } | i:subsd { $$ = i; } | i:subss { $$ = i; })) | (& 'x' ( i:xchg { $$ = i; } | i:xor { $$ = i; } | i:xorpd { $$ = i; } | i:xorps { $$ = i; } )) | i:or { $$ = i; } | i:leave { $$ = i; } | i:ret { $$ = i; } | i:push { $$ = i; } | i:pop { $$ = i; } | i:jmp { $$ = i; } | i:div { $$ = i; } | i:idiv { $$ = i; } | i:lea { $$ = i; } | i:imul { $$ = i; } | i:neg { $$ = i; } | i:test { $$ = i; } # Floating point is less common, so check last. | i:divss { $$ = i; } | i:divsd { $$ = i; } | i:pxor { $$ = i; } | i:ucomisd { $$ = i; } | i:ucomiss { $$ = i; } | i:nop { $$ = i; } call = "call" 'q'? ws ( '*' t:mem { $$ = OPMEM({.w=0}, -1, 0xff, 0x02, t); } | '*' t:r64 { $$ = OPREG({.w=0}, -1, 0xff, 0x02, t); } | t:value { Parsev ma = (Parsev){.memarg = (Memarg) {.kind=ASM_MEMARG, .disp = t.value }}; $$ = RELCALL({.w=0}, -1, 0xe8, ma); } ) jmp = 'j' v:jmp-variant ws t:ident { $$.jmp = (Jmp) {.kind = ASM_JMP, .cc=v.i64, .target=t.charptr}; } jmp-variant = "mp" { $$.i64 = 0; } | cc:condition-code { $$.i64 = cc.i64 + 1;} condition-code = "z" { $$.i64 = 0; } | "s" { $$.i64 = 1; } | "po" { $$.i64 = 2; } | "pe" { $$.i64 = 3; } | "p" { $$.i64 = 4; } | "o" { $$.i64 = 5; } | ("n" ( "z" { $$.i64 = 6; } | "s" { $$.i64 = 7; } | "p" { $$.i64 = 8; } | "o" { $$.i64 = 9; } | "le" { $$.i64 = 10; } | "l" { $$.i64 = 11; } | "ge" { $$.i64 = 12; } | "g" { $$.i64 = 13; } | "e" { $$.i64 = 14; } | "c" { $$.i64 = 15; } | "be" { $$.i64 = 16; } | "b" { $$.i64 = 17; } | "ae" { $$.i64 = 18; } | "a" { $$.i64 = 19; })) | "le" { $$.i64 = 20; } | "l" { $$.i64 = 21; } | "ge" { $$.i64 = 22; } | "g" { $$.i64 = 23; } | "e" { $$.i64 = 24; } | "c" { $$.i64 = 25; } | "be" { $$.i64 = 26; } | "b" { $$.i64 = 27; } | "ae" { $$.i64 = 28; } | "a" { $$.i64 = 29; } cltd = "cltd" { $$ = OP(0x99); } cqto = "cqto" { $$ = OP(0x01004899); } leave = "leave" { $$ = OP(0xc9); } nop = "nop" { $$ = OP(0x90); } ret = "ret" { $$ = OP(0xc3); } push = "push" ( 'q'? ws s:r64 { $$ = R({.w=0}, -1, 0x50, s); } | 'q' ws s:mem { $$ = OPMEM({.w=0}, -1, 0xff, 0x06, s); } ) pop = "pop" ( 'q'? ws d:r64 { $$ = R({.w=0}, -1, 0x58, d); } | 'q' ws d:mem { $$ = OPMEM({.w=0}, -1, 0x8f, 0x00, d); } ) div = "div" ( 'b'? ws a:r8 { $$ = OPREG({.w=0}, -1, 0xf6, 0x06, a); } | 'w'? ws a:r16 { $$ = OPREG({.w=0}, 0x66, 0xf7, 0x06, a); } | 'l'? ws a:r32 { $$ = OPREG({.w=0}, -1, 0xf7, 0x06, a); } | 'q'? ws a:r64 { $$ = OPREG({.w=1}, -1, 0xf7, 0x06, a); } | 'b' ws a:mem { $$ = OPMEM({.w=0}, -1, 0xf6, 0x06, a); } | 'w' ws a:mem { $$ = OPMEM({.w=0}, 0x66, 0xf7, 0x06, a); } | 'l' ws a:mem { $$ = OPMEM({.w=0}, -1, 0xf7, 0x06, a); } | 'q' ws a:mem { $$ = OPMEM({.w=1}, -1, 0xf7, 0x06, a); } ) idiv = "idiv" ( 'b'? ws a:r8 { $$ = OPREG({.w=0}, -1, 0xf6, 0x07, a); } | 'w'? ws a:r16 { $$ = OPREG({.w=0}, 0x66, 0xf7, 0x07, a); } | 'l'? ws a:r32 { $$ = OPREG({.w=0}, -1, 0xf7, 0x07, a); } | 'q'? ws a:r64 { $$ = OPREG({.w=1}, -1, 0xf7, 0x07, a); } | 'b' ws a:mem { $$ = OPMEM({.w=0}, -1, 0xf6, 0x07, a); } | 'w' ws a:mem { $$ = OPMEM({.w=0}, 0x66, 0xf7, 0x07, a); } | 'l' ws a:mem { $$ = OPMEM({.w=0}, -1, 0xf7, 0x07, a); } | 'q' ws a:mem { $$ = OPMEM({.w=1}, -1, 0xf7, 0x07, a); } ) mul = "mul" ( 'b'? ws a:r8 { $$ = OPREG({.w=0}, -1, 0xf6, 0x04, a); } | 'w'? ws a:r16 { $$ = OPREG({.w=0}, 0x66, 0xf7, 0x04, a); } | 'l'? ws a:r32 { $$ = OPREG({.w=0}, -1, 0xf7, 0x04, a); } | 'q'? ws a:r64 { $$ = OPREG({.w=1}, -1, 0xf7, 0x04, a); } | 'b' ws a:mem { $$ = OPMEM({.w=0}, -1, 0xf6, 0x04, a); } | 'w' ws a:mem { $$ = OPMEM({.w=0}, 0x66, 0xf7, 0x04, a); } | 'l' ws a:mem { $$ = OPMEM({.w=0}, -1, 0xf7, 0x04, a); } | 'q' ws a:mem { $$ = OPMEM({.w=1}, -1, 0xf7, 0x04, a); } ) neg = "neg" ( 'b'? ws a:r8 { $$ = OPREG({.w=0}, -1, 0xf6, 0x03, a); } | 'w'? ws a:r16 { $$ = OPREG({.w=0}, 0x66, 0xf7, 0x03, a); } | 'l'? ws a:r32 { $$ = OPREG({.w=0}, -1, 0xf7, 0x03, a); } | 'q'? ws a:r64 { $$ = OPREG({.w=1}, -1, 0xf7, 0x03, a); } | 'b' ws a:mem { $$ = OPMEM({.w=0}, -1, 0xf6, 0x03, a); } | 'w' ws a:mem { $$ = OPMEM({.w=0}, 0x66, 0xf7, 0x03, a); } | 'l' ws a:mem { $$ = OPMEM({.w=0}, -1, 0xf7, 0x03, a); } | 'q' ws a:mem { $$ = OPMEM({.w=1}, -1, 0xf7, 0x03, a); } ) imul = "imul" ( 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG2({.w=0}, 0x66, 0x01000faf, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG2({.w=0}, -1, 0x01000faf, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG2({.w=1}, -1, 0x01000faf, s, d); } | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x01000faf, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x01000faf, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x01000faf, s, d); } | 'w'? ws i:imm16-8 ws? ',' ws? s:r16 ws? ',' ws? d:r16 { $$ = IMMREGREG2({.w=0}, 0x66, i.imm.nbytes == 1 ? 0x6b : 0x69, i, s, d); } | 'l'? ws i:imm32-8 ws? ',' ws? s:r32 ws? ',' ws? d:r32 { $$ = IMMREGREG2({.w=0}, -1, i.imm.nbytes == 1 ? 0x6b : 0x69, i, s, d); } | 'q'? ws i:imm32-8 ws? ',' ws? s:r64 ws? ',' ws? d:r64 { $$ = IMMREGREG2({.w=1}, -1, i.imm.nbytes == 1 ? 0x6b : 0x69, i, s, d); } | 'w'? ws i:imm16-8 ws? ',' ws? s:mem ws? ',' ws? d:r16 { $$ = IMMMEMREG({.w=0}, 0x66, i.imm.nbytes == 1 ? 0x6b : 0x69, i, s, d); } | 'l'? ws i:imm32-8 ws? ',' ws? s:mem ws? ',' ws? d:r32 { $$ = IMMMEMREG({.w=0}, -1, i.imm.nbytes == 1 ? 0x6b : 0x69, i, s, d); } | 'q'? ws i:imm32-8 ws? ',' ws? s:mem ws? ',' ws? d:r64 { $$ = IMMMEMREG({.w=1}, -1, i.imm.nbytes == 1 ? 0x6b : 0x69, i, s, d); } # Must come last due to peg ordering. | 'b' ws a:mem { $$ = OPMEM({.w=0}, -1, 0xf6, 0x05, a); } | 'w' ws a:mem { $$ = OPMEM({.w=0}, 0x66, 0xf7, 0x05, a); } | 'l' ws a:mem { $$ = OPMEM({.w=0}, -1, 0xf7, 0x05, a); } | 'q' ws a:mem { $$ = OPMEM({.w=1}, -1, 0xf7, 0x05, a); } | 'b'? ws a:r8 { $$ = OPREG({.w=0}, -1, 0xf6, 0x05, a); } | 'w'? ws a:r16 { $$ = OPREG({.w=0}, 0x66, 0xf7, 0x05, a); } | 'l'? ws a:r32 { $$ = OPREG({.w=0}, -1, 0xf7, 0x05, a); } | 'q'? ws a:r64 { $$ = OPREG({.w=1}, -1, 0xf7, 0x05, a); } ) lea = "lea" ( 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x8d, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x8d, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x8d, s, d); } ) mov = "mov" ( 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG({.w=0}, -1, 0x88, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG({.w=0}, 0x66, 0x89, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG({.w=0}, -1, 0x89, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG({.w=1}, -1, 0x89, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x88, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, 0x66, 0x89, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x89, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM({.w=1}, -1, 0x89, s, d); } | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG({.w=0}, -1, 0x8a, s, d); } | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x8b, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x8b, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x8b, s, d); } | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = RIMM({.w=0}, -1, 0xb0, s, d); } | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = RIMM({.w=0}, 0x66, 0xb8, s, d); } | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = RIMM({.w=0}, -1, 0xb8, s, d); } | 'q'? ws s:imm ws? ',' ws? d:r64 { if (needsmovabs(&s.imm)){ s.imm.nbytes = 8; $$ = RIMM({.w=1}, -1, 0xb8, s, d); } else { s.imm.nbytes = 4; s.imm.v.c = ((uint64_t)s.imm.v.c) & 0xffffffff; $$ = IMMREG({.w=1}, -1, 0xc7, 0x00, s, d); } } | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0xc6, 0x00, s, d); } | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, 0xc7, 0x00, s, d); } | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0xc7, 0x00, s, d); } | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, 0xc7, 0x00, s, d); } ) movsx = "movs" ( 'bw' ws s:r8 ws? ',' ws? d:r16 { $$ = REGREG2({.w=0}, 0x66, 0x01000fbe, s, d); } | 'bl' ws s:r8 ws? ',' ws? d:r32 { $$ = REGREG2({.w=0}, -1, 0x01000fbe, s, d); } | 'bq' ws s:r8 ws? ',' ws? d:r64 { $$ = REGREG2({.w=1}, -1, 0x01000fbe, s, d); } | 'wl' ws s:r16 ws? ',' ws? d:r32 { $$ = REGREG2({.w=0}, -1, 0x01000fbf, s, d); } | 'wq' ws s:r16 ws? ',' ws? d:r64 { $$ = REGREG2({.w=1}, -1, 0x01000fbf, s, d); } | 'lq' ws s:r32 ws? ',' ws? d:r64 { $$ = REGREG2({.w=1}, -1, 0x63, s, d); } | 'bw' ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x01000fbe, s, d); } | 'bl' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x01000fbe, s, d); } | 'bq' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x01000fbe, s, d); } | 'wl' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x01000fbf, s, d); } | 'wq' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x01000fbf, s, d); } | 'lq' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x63, s, d); } ) movzx = "movz" ( 'bw' ws s:r8 ws? ',' ws? d:r16 { $$ = REGREG2({.w=0}, 0x66, 0x01000fb6, s, d); } | 'bl' ws s:r8 ws? ',' ws? d:r32 { $$ = REGREG2({.w=0}, -1, 0x01000fb6, s, d); } | 'bq' ws s:r8 ws? ',' ws? d:r64 { $$ = REGREG2({.w=1}, -1, 0x01000fb6, s, d); } | 'wl' ws s:r16 ws? ',' ws? d:r32 { $$ = REGREG2({.w=0}, -1, 0x01000fb7, s, d); } | 'wq' ws s:r16 ws? ',' ws? d:r64 { $$ = REGREG2({.w=1}, -1, 0x01000fb7, s, d); } | 'bw' ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x01000fb6, s, d); } | 'bl' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x01000fb6, s, d); } | 'bq' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x01000fb6, s, d); } | 'wl' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x01000fb7, s, d); } | 'wq' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x01000fb7, s, d); } ) add = "add" ( 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = (d.kind == ASM_AL) ? IMM ({.w=0}, -1, 0x04, s, d) : IMMREG({.w=0}, -1, 0x80, 0x00, s, d); } | 'w'? ws s:imm16-8 ws? ',' ws? d:r16 { $$ = (d.kind == ASM_AX && s.imm.nbytes == 2) ? IMM ({.w=0}, 0x66, 0x05, s, d) : IMMREG({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x00, s, d); } | 'l'? ws s:imm32-8 ws? ',' ws? d:r32 { $$ = (d.kind == ASM_EAX && s.imm.nbytes == 4) ? IMM ({.w=0}, -1, 0x05, s, d) : IMMREG({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x00, s, d); } | 'q'? ws s:imm32-8 ws? ',' ws? d:r64 { $$ = (d.kind == ASM_RAX && s.imm.nbytes == 4) ? IMM ({.w=1}, -1, 0x05, s, d) : IMMREG({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x00, s, d); } | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0x80, 0x00, s, d); } | 'w' ws s:imm16-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x00, s, d); } | 'l' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x00, s, d); } | 'q' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x00, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG({.w=0}, -1, 0x00, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG({.w=0}, 0x66, 0x01, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG({.w=0}, -1, 0x01, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG({.w=1}, -1, 0x01, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x00, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, 0x66, 0x01, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x01, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM({.w=1}, -1, 0x01, s, d); } | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG({.w=0}, -1, 0x02, s, d); } | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x03, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x03, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x03, s, d); } ) and = "and" ( 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = (d.kind == ASM_AL) ? IMM ({.w=0}, -1, 0x24, s, d) : IMMREG({.w=0}, -1, 0x80, 0x04, s, d); } | 'w'? ws s:imm16-8 ws? ',' ws? d:r16 { $$ = (d.kind == ASM_AX && s.imm.nbytes == 2) ? IMM ({.w=0}, 0x66, 0x25, s, d) : IMMREG({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x04, s, d); } | 'l'? ws s:imm32-8 ws? ',' ws? d:r32 { $$ = (d.kind == ASM_EAX && s.imm.nbytes == 4) ? IMM ({.w=0}, -1, 0x25, s, d) : IMMREG({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x04, s, d); } | 'q'? ws s:imm32-8 ws? ',' ws? d:r64 { $$ = (d.kind == ASM_RAX && s.imm.nbytes == 4) ? IMM ({.w=1}, -1, 0x25, s, d) : IMMREG({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x04, s, d); } | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0x80, 0x04, s, d); } | 'w' ws s:imm16-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x04, s, d); } | 'l' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x04, s, d); } | 'q' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x04, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG({.w=0}, -1, 0x20, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG({.w=0}, 0x66, 0x21, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG({.w=0}, -1, 0x21, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG({.w=1}, -1, 0x21, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x20, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, 0x66, 0x21, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x21, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM({.w=1}, -1, 0x21, s, d); } | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG({.w=0}, -1, 0x22, s, d); } | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x23, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x23, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x23, s, d); } ) cmp = "cmp" ( 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = (d.kind == ASM_AL) ? IMM ({.w=0}, -1, 0x3c, s, d) : IMMREG({.w=0}, -1, 0x80, 0x07, s, d); } | 'w'? ws s:imm16-8 ws? ',' ws? d:r16 { $$ = (d.kind == ASM_AX && s.imm.nbytes == 2) ? IMM ({.w=0}, 0x66, 0x3d, s, d) : IMMREG({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x07, s, d); } | 'l'? ws s:imm32-8 ws? ',' ws? d:r32 { $$ = (d.kind == ASM_EAX && s.imm.nbytes == 4) ? IMM ({.w=0}, -1, 0x3d, s, d) : IMMREG({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x07, s, d); } | 'q'? ws s:imm32-8 ws? ',' ws? d:r64 { $$ = (d.kind == ASM_RAX && s.imm.nbytes == 4) ? IMM ({.w=1}, -1, 0x3d, s, d) : IMMREG({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x07, s, d); } | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0x80, 0x07, s, d); } | 'w' ws s:imm16-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x07, s, d); } | 'l' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x07, s, d); } | 'q' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x07, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG({.w=0}, -1, 0x38, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG({.w=0}, 0x66, 0x39, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG({.w=0}, -1, 0x39, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG({.w=1}, -1, 0x39, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x38, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, 0x66, 0x39, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x39, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM({.w=1}, -1, 0x39, s, d); } | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG({.w=0}, -1, 0x3a, s, d); } | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x3b, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x3b, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x3b, s, d); } ) or = "or" ( 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = (d.kind == ASM_AL) ? IMM ({.w=0}, -1, 0x0c, s, d) : IMMREG({.w=0}, -1, 0x80, 0x01, s, d); } | 'w'? ws s:imm16-8 ws? ',' ws? d:r16 { $$ = (d.kind == ASM_AX && s.imm.nbytes == 2) ? IMM ({.w=0}, 0x66, 0x0d, s, d) : IMMREG({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x01, s, d); } | 'l'? ws s:imm32-8 ws? ',' ws? d:r32 { $$ = (d.kind == ASM_EAX && s.imm.nbytes == 4) ? IMM ({.w=0}, -1, 0x0d, s, d) : IMMREG({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x01, s, d); } | 'q'? ws s:imm32-8 ws? ',' ws? d:r64 { $$ = (d.kind == ASM_RAX && s.imm.nbytes == 4) ? IMM ({.w=1}, -1, 0x0d, s, d) : IMMREG({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x01, s, d); } | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0x80, 0x01, s, d); } | 'w' ws s:imm16-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x01, s, d); } | 'l' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x01, s, d); } | 'q' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x01, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG({.w=0}, -1, 0x08, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG({.w=0}, 0x66, 0x09, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG({.w=0}, -1, 0x09, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG({.w=1}, -1, 0x09, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x08, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, 0x66, 0x09, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x09, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM({.w=1}, -1, 0x09, s, d); } | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG({.w=0}, -1, 0x0a, s, d); } | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x0b, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x0b, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x0b, s, d); } ) sub = "sub" ( 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = (d.kind == ASM_AL) ? IMM ({.w=0}, -1, 0x2c, s, d) : IMMREG({.w=0}, -1, 0x80, 0x05, s, d); } | 'w'? ws s:imm16-8 ws? ',' ws? d:r16 { $$ = (d.kind == ASM_AX && s.imm.nbytes == 2) ? IMM ({.w=0}, 0x66, 0x2d, s, d) : IMMREG({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x05, s, d); } | 'l'? ws s:imm32-8 ws? ',' ws? d:r32 { $$ = (d.kind == ASM_EAX && s.imm.nbytes == 4) ? IMM ({.w=0}, -1, 0x2d, s, d) : IMMREG({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x05, s, d); } | 'q'? ws s:imm32-8 ws? ',' ws? d:r64 { $$ = (d.kind == ASM_RAX && s.imm.nbytes == 4) ? IMM ({.w=1}, -1, 0x2d, s, d) : IMMREG({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x05, s, d); } | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0x80, 0x05, s, d); } | 'w' ws s:imm16-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x05, s, d); } | 'l' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x05, s, d); } | 'q' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x05, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG({.w=0}, -1, 0x28, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG({.w=0}, 0x66, 0x29, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG({.w=0}, -1, 0x29, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG({.w=1}, -1, 0x29, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x28, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, 0x66, 0x29, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x29, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM({.w=1}, -1, 0x29, s, d); } | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG({.w=0}, -1, 0x2a, s, d); } | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x2b, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x2b, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x2b, s, d); } ) xor = "xor" ( 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = (d.kind == ASM_AL) ? IMM ({.w=0}, -1, 0x34, s, d) : IMMREG({.w=0}, -1, 0x80, 0x06, s, d); } | 'w'? ws s:imm16-8 ws? ',' ws? d:r16 { $$ = (d.kind == ASM_AX && s.imm.nbytes == 2) ? IMM ({.w=0}, 0x66, 0x35, s, d) : IMMREG({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x06, s, d); } | 'l'? ws s:imm32-8 ws? ',' ws? d:r32 { $$ = (d.kind == ASM_EAX && s.imm.nbytes == 4) ? IMM ({.w=0}, -1, 0x35, s, d) : IMMREG({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x06, s, d); } | 'q'? ws s:imm32-8 ws? ',' ws? d:r64 { $$ = (d.kind == ASM_RAX && s.imm.nbytes == 4) ? IMM ({.w=1}, -1, 0x35, s, d) : IMMREG({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x06, s, d); } | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0x80, 0x06, s, d); } | 'w' ws s:imm16-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x06, s, d); } | 'l' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x06, s, d); } | 'q' ws s:imm32-8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, s.imm.nbytes == 1 ? 0x83 : 0x81, 0x06, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG({.w=0}, -1, 0x30, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG({.w=0}, 0x66, 0x31, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG({.w=0}, -1, 0x31, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG({.w=1}, -1, 0x31, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x30, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, 0x66, 0x31, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x31, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM({.w=1}, -1, 0x31, s, d); } | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG({.w=0}, -1, 0x32, s, d); } | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x33, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x33, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x33, s, d); } ) xchg = "xchg" ( 'w'? ws s:ax ws? ',' ws? d:r16 { $$ = R({.w=0}, 0x66, 0x90, d) } | 'w'? ws s:r16 ws? ',' ws? d:ax { $$ = R({.w=0}, 0x66, 0x90, s) } | 'l'? ws s:eax ws? ',' ws? d:r32 { $$ = R({.w=0}, -1, 0x90, d) } | 'l'? ws s:r32 ws? ',' ws? d:eax { $$ = R({.w=0}, -1, 0x90, s) } | 'q'? ws s:rax ws? ',' ws? d:r64 { $$ = R({.w=1}, -1, 0x90, d) } | 'q'? ws s:r64 ws? ',' ws? d:rax { $$ = R({.w=1}, -1, 0x90, s) } | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG({.w=0}, -1, 0x86, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG({.w=0}, 0x66, 0x87, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG({.w=0}, -1, 0x87, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG({.w=1}, -1, 0x87, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x86, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, 0x66, 0x87, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x87, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM({.w=1}, -1, 0x87, s, d); } | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG({.w=0}, -1, 0x86, s, d); } | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x87, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x87, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x87, s, d); } ) %{ static uint8_t cc2setop[30] = { 0x94, 0x98, 0x9b, 0x9a, 0x9a, 0x90, 0x95, 0x99, 0x9b, 0x91, 0x9f, 0x9d, 0x9c, 0x9e, 0x95, 0x93, 0x97, 0x93, 0x92, 0x96, 0x9e, 0x9c, 0x9d, 0x9f, 0x94, 0x92, 0x96, 0x92, 0x93, 0x97, }; %} set = "set" cc:condition-code ( 'b'? ws a:r8 { $$ = OPREG({.w=0}, -1, 0x01000f00 | cc2setop[cc.i64], 0x00, a) } | 'b'? ws a:mem { $$ = OPMEM({.w=0}, -1, 0x01000f00 | cc2setop[cc.i64], 0x00, a) } ) sal = "sal" ( 'w' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM ({.w=0}, 0x66, 0xd3, 0x04, d); } | 'l' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM ({.w=0}, -1, 0xd3, 0x04, d); } | 'q' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM ({.w=1}, -1, 0xd3, 0x04, d); } | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = OPREG ({.w=0}, 0x66, 0xd3, 0x04, d); } | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = OPREG ({.w=0}, -1, 0xd3, 0x04, d); } | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = OPREG ({.w=1}, -1, 0xd3, 0x04, d); } | 'w' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, 0xc1, 0x04, i, d); } | 'l' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0xc1, 0x04, i, d); } | 'q' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, 0xc1, 0x04, i, d); } | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = IMMREG({.w=0}, 0x66, 0xc1, 0x04, i, d); } | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = IMMREG({.w=0}, -1, 0xc1, 0x04, i, d); } | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = IMMREG({.w=1}, -1, 0xc1, 0x04, i, d); } ) sar = "sar" ( 'w' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM ({.w=0}, 0x66, 0xd3, 0x07, d); } | 'l' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM ({.w=0}, -1, 0xd3, 0x07, d); } | 'q' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM ({.w=1}, -1, 0xd3, 0x07, d); } | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = OPREG ({.w=0}, 0x66, 0xd3, 0x07, d); } | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = OPREG ({.w=0}, -1, 0xd3, 0x07, d); } | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = OPREG ({.w=1}, -1, 0xd3, 0x07, d); } | 'w' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, 0xc1, 0x07, i, d); } | 'l' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0xc1, 0x07, i, d); } | 'q' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, 0xc1, 0x07, i, d); } | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = IMMREG({.w=0}, 0x66, 0xc1, 0x07, i, d); } | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = IMMREG({.w=0}, -1, 0xc1, 0x07, i, d); } | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = IMMREG({.w=1}, -1, 0xc1, 0x07, i, d); } ) shl = "shl" ( 'w' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM ({.w=0}, 0x66, 0xd3, 0x04, d); } | 'l' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM ({.w=0}, -1, 0xd3, 0x04, d); } | 'q' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM ({.w=1}, -1, 0xd3, 0x04, d); } | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = OPREG ({.w=0}, 0x66, 0xd3, 0x04, d); } | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = OPREG ({.w=0}, -1, 0xd3, 0x04, d); } | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = OPREG ({.w=1}, -1, 0xd3, 0x04, d); } | 'w' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, 0xc1, 0x04, i, d); } | 'l' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0xc1, 0x04, i, d); } | 'q' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, 0xc1, 0x04, i, d); } | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = IMMREG({.w=0}, 0x66, 0xc1, 0x04, i, d); } | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = IMMREG({.w=0}, -1, 0xc1, 0x04, i, d); } | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = IMMREG({.w=1}, -1, 0xc1, 0x04, i, d); } ) shr = "shr" ( 'w' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM({.w=0}, 0x66, 0xd3, 0x05, d); } | 'l' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM({.w=0}, -1, 0xd3, 0x05, d); } | 'q' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM({.w=1}, -1, 0xd3, 0x05, d); } | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = OPREG({.w=0}, 0x66, 0xd3, 0x05, d); } | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = OPREG({.w=0}, -1, 0xd3, 0x05, d); } | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = OPREG({.w=1}, -1, 0xd3, 0x05, d); } | 'w' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, 0xc1, 0x05, i, d); } | 'l' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0xc1, 0x05, i, d); } | 'q' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, 0xc1, 0x05, i, d); } | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = IMMREG({.w=0}, 0x66, 0xc1, 0x05, i, d); } | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = IMMREG({.w=0}, -1, 0xc1, 0x05, i, d); } | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = IMMREG({.w=1}, -1, 0xc1, 0x05, i, d); } ) test = "test" ( 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG({.w=0}, -1, 0x84, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG({.w=0}, 0x66, 0x85, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG({.w=0}, -1, 0x85, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG({.w=1}, -1, 0x85, s, d); } | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x84, s, d); } | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, 0x66, 0x85, s, d); } | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM({.w=0}, -1, 0x85, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM({.w=1}, -1, 0x85, s, d); } | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG({.w=0}, -1, 0x84, s, d); } | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG({.w=0}, 0x66, 0x85, s, d); } | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG({.w=0}, -1, 0x85, s, d); } | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG({.w=1}, -1, 0x85, s, d); } | 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = IMM({.w=0}, -1, 0xa8, s, d); } | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = IMM({.w=0}, 0x66, 0xa9, s, d); } | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = IMM({.w=0}, -1, 0xa9, s, d); } | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = IMM({.w=1}, -1, 0xa9, s, d); } | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = IMMREG({.w=0}, -1, 0xf6, 0x00, s, d); } | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = IMMREG({.w=0}, 0x66, 0xf7, 0x00, s, d); } | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = IMMREG({.w=0}, -1, 0xf7, 0x00, s, d); } | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = IMMREG({.w=1}, -1, 0xf7, 0x00, s, d); } | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0xf6, 0x00, s, d); } | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, 0x66, 0xf7, 0x00, s, d); } | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM({.w=0}, -1, 0xf7, 0x00, s, d); } | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM({.w=1}, -1, 0xf7, 0x00, s, d); } ) # Floating point instructions. addsd = "addsd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf2, 0x01000f58, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf2, 0x01000f58, s, d); } ) addss = "addss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf3, 0x01000f58, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf3, 0x01000f58, s, d); } ) subsd = "subsd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf2, 0x01000f5c, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf2, 0x01000f5c, s, d); } ) subss = "subss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf3, 0x01000f5c, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf3, 0x01000f5c, s, d); } ) cvtsi2sd = "cvtsi2sd" ( ws s:r32 ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf2, 0x01000f2a, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf2, 0x01000f2a, s, d); } | ws s:r64 ws? ',' ws? d:xmm { $$ = REGREG2({.w=1}, 0xf2, 0x01000f2a, s, d); } ) cvtsi2ss = "cvtsi2ss" ( ws s:r32 ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf3, 0x01000f2a, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf3, 0x01000f2a, s, d); } | ws s:r64 ws? ',' ws? d:xmm { $$ = REGREG2({.w=1}, 0xf3, 0x01000f2a, s, d); } ) cvtss2sd = "cvtss2sd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf3, 0x01000f5a, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf3, 0x01000f5a, s, d); } ) cvtsd2ss = "cvtsd2ss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf2, 0x01000f5a, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf2, 0x01000f5a, s, d); } ) cvttss2si = "cvttss2si" ( 'l'? ws s:xmm ws? ',' ws? d:r32 { $$ = REGREG2({.w=0}, 0xf3, 0x01000f2c, s, d); } | 'q'? ws s:xmm ws? ',' ws? d:r64 { $$ = REGREG2({.w=1}, 0xf3, 0x01000f2c, s, d); } | 'l' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG ({.w=0}, 0xf3, 0x01000f7e, s, d); } | 'q' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG ({.w=1}, 0xf3, 0x01000f2c, s, d); } ) cvttsd2si = "cvttsd2si" ( 'l'? ws s:xmm ws? ',' ws? d:r32 { $$ = REGREG2({.w=0}, 0xf2, 0x01000f2c, s, d); } | 'q'? ws s:xmm ws? ',' ws? d:r64 { $$ = REGREG2({.w=1}, 0xf2, 0x01000f2c, s, d); } | 'l' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG ({.w=0}, 0xf2, 0x01000f7e, s, d); } | 'q' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG ({.w=1} ,0xf2, 0x01000f2c, s, d); } ) divsd = "divsd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf2, 0x01000f5e, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf2, 0x01000f5e, s, d); } ) divss = "divss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf3, 0x01000f5e, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf3, 0x01000f5e, s, d); } ) movaps = "movaps" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, -1, 0x01000f28, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, -1, 0x01000f28, s, d); } | ws s:xmm ws? ',' ws? d:mem { $$ = REGMEM ({.w=0}, -1, 0x01000f29, s, d); } ) mulsd = "mulsd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf2, 0x01000f59, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf2, 0x01000f59, s, d); } ) mulss = "mulss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf3, 0x01000f59, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf3, 0x01000f59, s, d); } ) movss = "movss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf3, 0x01000f10, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf3, 0x01000f10, s, d); } | ws s:xmm ws? ',' ws? d:mem { $$ = REGMEM ({.w=0}, 0xf3, 0x01000f11, s, d); } ) movsd = "movsd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0xf2, 0x01000f10, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf2, 0x01000f10, s, d); } | ws s:xmm ws? ',' ws? d:mem { $$ = REGMEM ({.w=0}, 0xf2, 0x01000f11, s, d); } ) movq = "mov" ( 'q'? ws s:xmm ws? ',' ws? d:r64 { $$ = REGREG ({.w=1}, 0x66, 0x01000f7e, s, d); } | 'q'? ws s:r64 ws? ',' ws? d:xmm { $$ = REGREG2({.w=1}, 0x66, 0x01000f6e, s, d); } | 'q' ws s:xmm ws? ',' ws? d:mem { $$ = REGMEM ({.w=0}, 0x66, 0x01000fd6, s, d); } | 'q' ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0xf3, 0x01000f7e, s, d); } ) ucomiss = "ucomiss" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, -1, 0x01000f2e, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, -1, 0x01000f2e, s, d); } ) ucomisd = "ucomisd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0x66, 0x01000f2e, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0x66, 0x01000f2e, s, d); } ) pxor = "pxor" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0x66, 0x01000fef, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0x66, 0x01000fef, s, d); } ) xorpd = "xorpd" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, 0x66, 0x01000f57, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, 0x66, 0x01000f57, s, d); } ) xorps = "xorps" ( ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2({.w=0}, -1, 0x01000f57, s, d); } | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG ({.w=0}, -1, 0x01000f57, s, d); } ) r64-or-rip = ( r:r64 | r:rip ) { $$ = r; } mem = d:value ws? sib:opt-scale-index-base { $$ = (Parsev){ .memarg=sib.memarg }; $$.memarg.disp = d.value; } | sib:scale-index-base { $$ = (Parsev){ .memarg=sib.memarg }; } opt-scale-index-base = sib:scale-index-base { $$ = sib; } | { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = 0, .index=ASM_NO_REG, .base = ASM_NO_REG, .disp = {0} }; } scale-index-base = '(' ws? b:r64-or-rip ws? ')' { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = 0, .index=ASM_NO_REG, .base = b.kind, .disp = {0} }; } | '(' ws? b:r64 ws? ',' ws? i:r64 ws? ',' ws? s:number ws? ')' { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = s.i64, .index=i.kind, .base = b.kind, .disp = {0} }; } | '(' ws? b:r64 ws? ',' ws? i:r64 ')' { $$.memarg = (Memarg){.kind=ASM_MEMARG, .scale = 1, .index=i.kind, .base = b.kind, .disp = {0} }; } imm = '$' ws? val:value { $$ = (Parsev) { .imm = (Imm){ .kind = ASM_IMM, .v = val.value, .nbytes = 0} }; } imm8 = i:imm { i.imm.nbytes = 1; $$ = i; } imm16 = i:imm { i.imm.nbytes = 2; $$ = i; } imm32 = i:imm { i.imm.nbytes = 4; $$ = i; } imm16-8 = i:imm { i.imm.nbytes = 2; if (i.imm.v.l == NULL) { if ((int64_t)(int8_t)i.imm.v.c == i.imm.v.c) { i.imm.nbytes = 1; } } $$ = i; } imm32-8 = i:imm { i.imm.nbytes = 4; if (i.imm.v.l == NULL) { if ((int64_t)(int8_t)i.imm.v.c == i.imm.v.c) { i.imm.nbytes = 1; } } $$ = i; } al = "%al" { $$ = REG(AL); } cl = "%cl" { $$ = REG(CL); } ax = "%ax" { $$ = REG(AX); } eax = "%eax" { $$ = REG(EAX); } rax = "%rax" { $$ = REG(RAX); } rip = "%rip" { $$ = REG(RIP); } r8 = '%' ( "al" { $$ = REG(AL); } | "cl" { $$ = REG(CL); } | "dl" { $$ = REG(DL); } | "bl" { $$ = REG(BL); } | "spl" { $$ = REG(SPL); } | "bpl" { $$ = REG(BPL); } | "sil" { $$ = REG(SIL); } | "dil" { $$ = REG(DIL); } | "r8b" { $$ = REG(R8B); } | "r9b" { $$ = REG(R9B); } | "r10b" { $$ = REG(R10B); } | "r11b" { $$ = REG(R11B); } | "r12b" { $$ = REG(R12B); } | "r13b" { $$ = REG(R13B); } | "r14b" { $$ = REG(R14B); } | "r15b" { $$ = REG(R15B); } ) r16 = '%' ( "ax" { $$ = REG(AX); } | "cx" { $$ = REG(CX); } | "dx" { $$ = REG(DX); } | "bx" { $$ = REG(BX); } | "sp" { $$ = REG(SP); } | "bp" { $$ = REG(BP); } | "si" { $$ = REG(SI); } | "di" { $$ = REG(DI); } | "r8w" { $$ = REG(R8W); } | "r9w" { $$ = REG(R9W); } | "r10w" { $$ = REG(R10W); } | "r11w" { $$ = REG(R11W); } | "r12w" { $$ = REG(R12W); } | "r13w" { $$ = REG(R13W); } | "r14w" { $$ = REG(R14W); } | "r15w" { $$ = REG(R15W); } ) r32 = '%' ( "eax" { $$ = REG(EAX); } | "ecx" { $$ = REG(ECX); } | "edx" { $$ = REG(EDX); } | "ebx" { $$ = REG(EBX); } | "esp" { $$ = REG(ESP); } | "ebp" { $$ = REG(EBP); } | "esi" { $$ = REG(ESI); } | "edi" { $$ = REG(EDI); } | "r8d" { $$ = REG(R8D); } | "r9d" { $$ = REG(R9D); } | "r10d" { $$ = REG(R10D); } | "r11d" { $$ = REG(R11D); } | "r12d" { $$ = REG(R12D); } | "r13d" { $$ = REG(R13D); } | "r14d" { $$ = REG(R14D); } | "r15d" { $$ = REG(R15D); } ) r64 = "%r" ( "ax" { $$ = REG(RAX); } | "cx" { $$ = REG(RCX); } | "dx" { $$ = REG(RDX); } | "bx" { $$ = REG(RBX); } | "sp" { $$ = REG(RSP); } | "bp" { $$ = REG(RBP); } | "si" { $$ = REG(RSI); } | "di" { $$ = REG(RDI); } | "8" ![lwb] { $$ = REG(R8); } | "9" ![lwb] { $$ = REG(R9); } | "10" ![lwb] { $$ = REG(R10); } | "11" ![lwb] { $$ = REG(R11); } | "12" ![lwb] { $$ = REG(R12); } | "13" ![lwb] { $$ = REG(R13); } | "14" ![lwb] { $$ = REG(R14); } | "15" ![lwb] { $$ = REG(R15); } ) xmm = "%xmm" ( # Reverse order due to peg ordering. "15" { $$ = REG(XMM15); } | "14" { $$ = REG(XMM14); } | "13" { $$ = REG(XMM13); } | "12" { $$ = REG(XMM12); } | "11" { $$ = REG(XMM11); } | "10" { $$ = REG(XMM10); } | "9" { $$ = REG(XMM7); } | "8" { $$ = REG(XMM7); } | "7" { $$ = REG(XMM7); } | "6" { $$ = REG(XMM6); } | "5" { $$ = REG(XMM5); } | "4" { $$ = REG(XMM4); } | "3" { $$ = REG(XMM3); } | "2" { $$ = REG(XMM2); } | "1" { $$ = REG(XMM1); } | "0" { $$ = REG(XMM0); } ) # We disallow newlines in our strings, it is simpler for lineno tracking. string = '"' <(string-escape | ( ! '\n' ! '\\' !'"' .))*> '"' { $$.string = decodestring(yytext); } string-escape = '\\' ( '\\' | '"' | [nrt] | 'x' [0-9A-Fa-f]+ | [0-7][0-7][0-7] ) value = n:number { $$.value = (Value){ .l = NULL, .c = n.i64 }; } | i:ident ws? ( '+' ws? n:number { $$.value = (Value){ .c = n.i64 }; } | &'-' n:number { $$.value = (Value){ .c = n.i64 }; } | { $$.value = (Value){ .c = 0 }; } ) { $$.value.l = i.charptr; } ident = <[._a-zA-Z][._a-zA-Z0-9]*> { $$.charptr = internstring(yytext); } number = '-' ws? n:unsigned-number { $$.i64 = -n.i64; } | n:unsigned-number { $$.i64 = n.i64; } unsigned-number = '0' [xX] <[0-9a-fA-F]+> { $$.i64 = (int64_t)strtoull(yytext, NULL, 16); } | <[0-9]+> { $$.i64 = (int64_t)strtoull(yytext, NULL, 10); }