diff options
| -rw-r--r-- | asm.peg | 890 | ||||
| -rw-r--r-- | main.c | 765 | ||||
| -rw-r--r-- | minias.h | 93 | ||||
| -rw-r--r-- | parse.c | 133 | ||||
| -rw-r--r-- | test/test.sh | 4 |
5 files changed, 912 insertions, 973 deletions
@@ -83,10 +83,10 @@ instr = i:add { $$ = i; } | i:and { $$ = i; } | i:addss { $$ = i; } - | i:addsd { $$ = i; } )) + | i:addsd { $$ = i; })) | (& 'c' ( - i:cmp { $$ = i; } + i:cmp { $$ = i; } | i:call { $$ = i; } | i:cvtsi2sd { $$ = i; } | i:cvtsi2ss { $$ = i; } @@ -97,54 +97,38 @@ instr = | 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; })) - | 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; } - | i:xchg { $$ = i; } - | i:xor { $$ = i; } - # Floating point is less common, so check last. - | i:divss { $$ = i; } - | i:divsd { $$ = i; } - | i:pxor { $$ = i; } - | i:xorpd { $$ = i; } - | i:xorps { $$ = i; } - | i:ucomisd { $$ = i; } - | i:ucomiss { $$ = i; } - | i:nop { $$ = i; } - -cltd = "cltd" { $$ = (Parsev){ .kind=ASM_CLTD }; } -cqto = "cqto" { $$ = (Parsev){ .kind=ASM_CQTO }; } -leave = "leave" { $$ = (Parsev){ .kind=ASM_LEAVE }; } -nop = "nop" { $$ = (Parsev){ .kind=ASM_NOP }; } -ret = "ret" { $$ = (Parsev){ .kind=ASM_RET }; } - -push = "push" ( - 'q'? ws s:r64 { $$ = INSTR1(0, s); } - | 'q' ws s:mem { $$ = INSTR1(1, s); } -) { $$.instr.kind = ASM_PUSH; } - -pop = "pop" ( - 'q'? ws d:r64 { $$ = INSTR1(0, d); } - | 'q' ws d:mem { $$ = INSTR1(1, d); } -) { $$.instr.kind = ASM_POP; } + ( + i:set { $$ = i; } + | i:sub { $$ = i; } + | i:sal { $$ = i; } + | i:sar { $$ = i; } + | i:shl { $$ = i; } + | i:shr { $$ = i; } + | i:subsd { $$ = i; } + | i:subss { $$ = 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; } + | i:xchg { $$ = i; } + | i:xor { $$ = i; } + # Floating point is less common, so check last. + | i:divss { $$ = i; } + | i:divsd { $$ = i; } + | i:pxor { $$ = i; } + | i:xorpd { $$ = i; } + | i:xorps { $$ = i; } + | i:ucomisd { $$ = i; } + | i:ucomiss { $$ = i; } + | i:nop { $$ = i; } call = "call" 'q'? ws ( '*' t:mem @@ -196,360 +180,598 @@ condition-code = | "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(-1, (Rex){0}, 0x50, s); } + | 'q' ws s:mem { $$ = OPMEM(-1, (Rex){0}, 0xff, 0x06, s); } +) + +pop = "pop" ( + 'q'? ws d:r64 { $$ = R(-1, (Rex){0}, 0x58, d); } + | 'q' ws d:mem { $$ = OPMEM(-1, (Rex){0}, 0x8f, 0x00, d); } +) + div = "div" ( - 'b' ws a:mem { $$ = INSTR1(0, a); } - | 'w' ws a:mem { $$ = INSTR1(1, a); } - | 'l' ws a:mem { $$ = INSTR1(2, a); } - | 'q' ws a:mem { $$ = INSTR1(3, a); } - | 'b'? ws a:r8 { $$ = INSTR1(4, a); } - | 'w'? ws a:r16 { $$ = INSTR1(5, a); } - | 'l'? ws a:r32 { $$ = INSTR1(6, a); } - | 'q'? ws a:r64 { $$ = INSTR1(7, a); } -) { $$.instr.kind = ASM_DIV; } + 'b' ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0xf6, 0x06, a); } + | 'w' ws a:mem { $$ = OPMEM(0x66, (Rex){0}, 0xf7, 0x06, a); } + | 'l' ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0xf7, 0x06, a); } + | 'q' ws a:mem { $$ = OPMEM(-1, (Rex){.w=1}, 0xf7, 0x06, a); } + | 'b'? ws a:r8 { $$ = OPREG(-1, (Rex){0}, 0xf6, 0x06, a); } + | 'w'? ws a:r16 { $$ = OPREG(0x66, (Rex){0}, 0xf7, 0x06, a); } + | 'l'? ws a:r32 { $$ = OPREG(-1, (Rex){0}, 0xf7, 0x06, a); } + | 'q'? ws a:r64 { $$ = OPREG(-1, (Rex){.w=1}, 0xf7, 0x06, a); } +) idiv = "idiv" ( - 'b' ws a:mem { $$ = INSTR1(0, a); } - | 'w' ws a:mem { $$ = INSTR1(1, a); } - | 'l' ws a:mem { $$ = INSTR1(2, a); } - | 'q' ws a:mem { $$ = INSTR1(3, a); } - | 'b'? ws a:r8 { $$ = INSTR1(4, a); } - | 'w'? ws a:r16 { $$ = INSTR1(5, a); } - | 'l'? ws a:r32 { $$ = INSTR1(6, a); } - | 'q'? ws a:r64 { $$ = INSTR1(7, a); } -) { $$.instr.kind = ASM_IDIV; } + 'b' ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0xf6, 0x07, a); } + | 'w' ws a:mem { $$ = OPMEM(0x66, (Rex){0}, 0xf7, 0x07, a); } + | 'l' ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0xf7, 0x07, a); } + | 'q' ws a:mem { $$ = OPMEM(-1, (Rex){.w=1}, 0xf7, 0x07, a); } + | 'b'? ws a:r8 { $$ = OPREG(-1, (Rex){0}, 0xf6, 0x07, a); } + | 'w'? ws a:r16 { $$ = OPREG(0x66, (Rex){0}, 0xf7, 0x07, a); } + | 'l'? ws a:r32 { $$ = OPREG(-1, (Rex){0}, 0xf7, 0x07, a); } + | 'q'? ws a:r64 { $$ = OPREG(-1, (Rex){.w=1}, 0xf7, 0x07, a); } +) mul = "mul" ( - 'b' ws a:mem { $$ = INSTR1(0, a); } - | 'w' ws a:mem { $$ = INSTR1(1, a); } - | 'l' ws a:mem { $$ = INSTR1(2, a); } - | 'q' ws a:mem { $$ = INSTR1(3, a); } - | 'b'? ws a:r8 { $$ = INSTR1(4, a); } - | 'w'? ws a:r16 { $$ = INSTR1(5, a); } - | 'l'? ws a:r32 { $$ = INSTR1(6, a); } - | 'q'? ws a:r64 { $$ = INSTR1(7, a); } -) { $$.instr.kind = ASM_MUL; } + 'b' ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0xf6, 0x04, a); } + | 'w' ws a:mem { $$ = OPMEM(0x66, (Rex){0}, 0xf7, 0x04, a); } + | 'l' ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0xf7, 0x04, a); } + | 'q' ws a:mem { $$ = OPMEM(-1, (Rex){.w=1}, 0xf7, 0x04, a); } + | 'b'? ws a:r8 { $$ = OPREG(-1, (Rex){0}, 0xf6, 0x04, a); } + | 'w'? ws a:r16 { $$ = OPREG(0x66, (Rex){0}, 0xf7, 0x04, a); } + | 'l'? ws a:r32 { $$ = OPREG(-1, (Rex){0}, 0xf7, 0x04, a); } + | 'q'? ws a:r64 { $$ = OPREG(-1, (Rex){.w=1}, 0xf7, 0x04, a); } +) neg = "neg" ( - 'b' ws a:mem { $$ = INSTR1(0, a); } - | 'w' ws a:mem { $$ = INSTR1(1, a); } - | 'l' ws a:mem { $$ = INSTR1(2, a); } - | 'q' ws a:mem { $$ = INSTR1(3, a); } - | 'b'? ws a:r8 { $$ = INSTR1(4, a); } - | 'w'? ws a:r16 { $$ = INSTR1(5, a); } - | 'l'? ws a:r32 { $$ = INSTR1(6, a); } - | 'q'? ws a:r64 { $$ = INSTR1(7, a); } -) { $$.instr.kind = ASM_NEG; } + 'b' ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0xf6, 0x03, a); } + | 'w' ws a:mem { $$ = OPMEM(0x66, (Rex){0}, 0xf7, 0x03, a); } + | 'l' ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0xf7, 0x03, a); } + | 'q' ws a:mem { $$ = OPMEM(-1, (Rex){.w=1}, 0xf7, 0x03, a); } + | 'b'? ws a:r8 { $$ = OPREG(-1, (Rex){0}, 0xf6, 0x03, a); } + | 'w'? ws a:r16 { $$ = OPREG(0x66, (Rex){0}, 0xf7, 0x03, a); } + | 'l'? ws a:r32 { $$ = OPREG(-1, (Rex){0}, 0xf7, 0x03, a); } + | 'q'? ws a:r64 { $$ = OPREG(-1, (Rex){.w=1}, 0xf7, 0x03, a); } +) imul = "imul" ( - 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = INSTR2(8, s, d); } - | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(9, s, d); } - | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(10, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR2(11, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR2(12, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR2(13, s, d); } - | 'w'? ws i:imm16 ws? ',' ws? s:mem ws? ',' ws? d:r16 { $$ = INSTR3(14, s, d, i); } - | 'l'? ws i:imm32 ws? ',' ws? s:mem ws? ',' ws? d:r32 { $$ = INSTR3(15, s, d, i); } - | 'q'? ws i:imm32 ws? ',' ws? s:mem ws? ',' ws? d:r64 { $$ = INSTR3(16, s, d, i); } - | 'w'? ws i:imm16 ws? ',' ws? s:r16 ws? ',' ws? d:r16 { $$ = INSTR3(17, s, d, i); } - | 'l'? ws i:imm32 ws? ',' ws? s:r32 ws? ',' ws? d:r32 { $$ = INSTR3(18, s, d, i); } - | 'q'? ws i:imm32 ws? ',' ws? s:r64 ws? ',' ws? d:r64 { $$ = INSTR3(19, s, d, i); } + 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG2(0x66, (Rex){0}, 0x01000faf, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG2(-1, (Rex){0}, 0x01000faf, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG2(-1, (Rex){.w=1}, 0x01000faf, s, d); } + | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x01000faf, s, d); } + | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x01000faf, s, d); } + | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x01000faf, s, d); } + | 'w'? ws i:imm16 ws? ',' ws? s:r16 ws? ',' ws? d:r16 { $$ = IMMREGREG2(0x66, (Rex){0}, 0x69, i, s, d); } + | 'l'? ws i:imm32 ws? ',' ws? s:r32 ws? ',' ws? d:r32 { $$ = IMMREGREG2(-1, (Rex){0}, 0x69, i, s, d); } + | 'q'? ws i:imm32 ws? ',' ws? s:r64 ws? ',' ws? d:r64 { $$ = IMMREGREG2(-1, (Rex){.w=1}, 0x69, i, s, d); } + | 'w'? ws i:imm16 ws? ',' ws? s:mem ws? ',' ws? d:r16 { $$ = IMMMEMREG(0x66, (Rex){0}, 0x69, i, s, d); } + | 'l'? ws i:imm32 ws? ',' ws? s:mem ws? ',' ws? d:r32 { $$ = IMMMEMREG(-1, (Rex){0}, 0x69, i, s, d); } + | 'q'? ws i:imm32 ws? ',' ws? s:mem ws? ',' ws? d:r64 { $$ = IMMMEMREG(-1, (Rex){.w=1}, 0x69, i, s, d); } # Must come last due to peg ordering. - | 'b' ws a:mem { $$ = INSTR1(0, a); } - | 'w' ws a:mem { $$ = INSTR1(1, a); } - | 'l' ws a:mem { $$ = INSTR1(2, a); } - | 'q' ws a:mem { $$ = INSTR1(3, a); } - | 'b'? ws a:r8 { $$ = INSTR1(4, a); } - | 'w'? ws a:r16 { $$ = INSTR1(5, a); } - | 'l'? ws a:r32 { $$ = INSTR1(6, a); } - | 'q'? ws a:r64 { $$ = INSTR1(7, a); } -) { $$.instr.kind = ASM_IMUL; } + | 'b' ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0xf6, 0x05, a); } + | 'w' ws a:mem { $$ = OPMEM(0x66, (Rex){0}, 0xf7, 0x05, a); } + | 'l' ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0xf7, 0x05, a); } + | 'q' ws a:mem { $$ = OPMEM(-1, (Rex){.w=1}, 0xf7, 0x05, a); } + | 'b'? ws a:r8 { $$ = OPREG(-1, (Rex){0}, 0xf6, 0x05, a); } + | 'w'? ws a:r16 { $$ = OPREG(0x66, (Rex){0}, 0xf7, 0x05, a); } + | 'l'? ws a:r32 { $$ = OPREG(-1, (Rex){0}, 0xf7, 0x05, a); } + | 'q'? ws a:r64 { $$ = OPREG(-1, (Rex){.w=1}, 0xf7, 0x05, a); } +) lea = "lea" ( - 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = INSTR2(0, s, d); } - | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(1, s, d); } - | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(2, s, d); } -) { $$.instr.kind = ASM_LEA; } + 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x8d, s, d); } + | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x8d, s, d); } + | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x8d, s, d); } +) mov = "mov" ( - 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = INSTR2(0, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR2(1, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR2(2, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR2(3, s, d); } - | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = INSTR2(4, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = INSTR2(5, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = INSTR2(6, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = INSTR2(7, s, d); } - | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = INSTR2(8, s, d); } - | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = INSTR2(9, s, d); } - | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(10, s, d); } - | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(11, s, d); } - | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = INSTR2(12, s, d); } - | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = INSTR2(13, s, d); } - | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = INSTR2(14, s, d); } - | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = INSTR2(15, s, d); } - | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = INSTR2(16, s, d); } - | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = INSTR2(17, s, d); } - | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = INSTR2(18, s, d); } - | 'q'? ws s:imm ws? ',' ws? d:r64 { $$ = INSTR2(19, s, d); } -) { $$.instr.kind = ASM_MOV; } + 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG(-1, (Rex){0}, 0x88, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG(0x66, (Rex){0}, 0x89, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG(-1, (Rex){0}, 0x89, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG(-1, (Rex){.w=1}, 0x89, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x088, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM(0x66, (Rex){0}, 0x89, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x89, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){.w=1}, 0x89, s, d); } + + | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG(-1, (Rex){0}, 0x8a, s, d); } + | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x8b, s, d); } + | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x8b, s, d); } + | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x8b, s, d); } + + | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = RIMM(-1, (Rex){0}, 0xb0, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = RIMM(0x66, (Rex){0}, 0xb8, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = RIMM(-1, (Rex){0}, 0xb8, s, d); } + | 'q'? ws s:imm ws? ',' ws? d:r64 { + if (needsmovabs(&s.imm)){ + s.imm.nbytes = 8; + $$ = RIMM(-1, (Rex){.w=1}, 0xb8, s, d); + } else { + s.imm.nbytes = 4; + s.imm.v.c = ((uint64_t)s.imm.v.c) & 0xffffffff; + $$ = IMMREG(-1, (Rex){.w=1}, 0xc7, 0x00, s, d); + } + } + | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0xc6, 0x00, s, d); } + | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0xc7, 0x00, s, d); } + | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0xc7, 0x00, s, d); } + | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0xc7, 0x00, s, d); } +) movsx = "movs" ( - 'bw' ws s:mem ws? ',' ws? d:r16 { $$ = INSTR2(0, s, d); } - | 'bl' ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(1, s, d); } - | 'bq' ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(2, s, d); } - | 'wl' ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(3, s, d); } - | 'wq' ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(4, s, d); } - | 'bw' ws s:r8 ws? ',' ws? d:r16 { $$ = INSTR2(5, s, d); } - | 'bl' ws s:r8 ws? ',' ws? d:r32 { $$ = INSTR2(6, s, d); } - | 'bq' ws s:r8 ws? ',' ws? d:r64 { $$ = INSTR2(7, s, d); } - | 'wl' ws s:r16 ws? ',' ws? d:r32 { $$ = INSTR2(8, s, d); } - | 'wq' ws s:r16 ws? ',' ws? d:r64 { $$ = INSTR2(9, s, d); } - | 'lq' ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(10, s, d); } - | 'lq' ws s:r32 ws? ',' ws? d:r64 { $$ = INSTR2(11, s, d); } -) { $$.instr.kind = ASM_MOVSX; } + 'bw' ws s:r8 ws? ',' ws? d:r16 { $$ = REGREG2(0x66, (Rex){0}, 0x01000fbe, s, d); } + | 'bl' ws s:r8 ws? ',' ws? d:r32 { $$ = REGREG2(-1, (Rex){0}, 0x01000fbe, s, d); } + | 'bq' ws s:r8 ws? ',' ws? d:r64 { $$ = REGREG2(-1, (Rex){.w=1}, 0x01000fbe, s, d); } + | 'wl' ws s:r16 ws? ',' ws? d:r32 { $$ = REGREG2(-1, (Rex){0}, 0x01000fbf, s, d); } + | 'wq' ws s:r16 ws? ',' ws? d:r64 { $$ = REGREG2(-1, (Rex){.w=1}, 0x01000fbf, s, d); } + | 'lq' ws s:r32 ws? ',' ws? d:r64 { $$ = REGREG2(-1, (Rex){.w=1}, 0x63, s, d); } + | 'bw' ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x01000fbe, s, d); } + | 'bl' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x01000fbe, s, d); } + | 'bq' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x01000fbe, s, d); } + | 'wl' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x01000fbf, s, d); } + | 'wq' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x01000fbf, s, d); } + | 'lq' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x63, s, d); } +) movzx = "movz" ( - 'bw' ws s:mem ws? ',' ws? d:r16 { $$ = INSTR2(0, s, d); } - | 'bl' ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(1, s, d); } - | 'bq' ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(2, s, d); } - | 'wl' ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(3, s, d); } - | 'wq' ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(4, s, d); } - | 'bw' ws s:r8 ws? ',' ws? d:r16 { $$ = INSTR2(5, s, d); } - | 'bl' ws s:r8 ws? ',' ws? d:r32 { $$ = INSTR2(6, s, d); } - | 'bq' ws s:r8 ws? ',' ws? d:r64 { $$ = INSTR2(7, s, d); } - | 'wl' ws s:r16 ws? ',' ws? d:r32 { $$ = INSTR2(8, s, d); } - | 'wq' ws s:r16 ws? ',' ws? d:r64 { $$ = INSTR2(9, s, d); } -) { $$.instr.kind = ASM_MOVZX; } - -xchg = 'xchg' ( - 'w'? ws s:ax ws? ',' ws? d:r16 { $$ = INSTR2(0, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:ax { $$ = INSTR2(1, s, d); } - | 'l'? ws s:eax ws? ',' ws? d:r32 { $$ = INSTR2(2, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:eax { $$ = INSTR2(3, s, d); } - | 'q'? ws s:rax ws? ',' ws? d:r64 { $$ = INSTR2(4, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:rax { $$ = INSTR2(5, s, d); } - | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = INSTR2(6, s, d); } - | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = INSTR2(7, s, d); } - | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(8, s, d); } - | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(9, s, d); } - | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = INSTR2(10, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = INSTR2(11, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = INSTR2(12, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = INSTR2(13, s, d); } - | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = INSTR2(14, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR2(15, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR2(16, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR2(17, s, d); } -) { $$.instr.kind = ASM_XCHG; } - -add = "add" a:basic-op-args { a.instr.kind = ASM_ADD; $$ = a; } -cmp = "cmp" a:basic-op-args { a.instr.kind = ASM_CMP; $$ = a; } -and = "and" a:basic-op-args { a.instr.kind = ASM_AND; $$ = a; } -or = "or" a:basic-op-args { a.instr.kind = ASM_OR; $$ = a; } -sub = "sub" a:basic-op-args { a.instr.kind = ASM_SUB; $$ = a; } -xor = "xor" a:basic-op-args { a.instr.kind = ASM_XOR; $$ = a; } -basic-op-args = - 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = INSTR2(0, s, d); } - | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = INSTR2(1, s, d); } - | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = INSTR2(2, s, d); } - | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = INSTR2(3, s, d); } - | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = INSTR2(4, s, d); } - | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = INSTR2(5, s, d); } - | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = INSTR2(6, s, d); } - | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = INSTR2(7, s, d); } - | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = INSTR2(8, s, d); } - | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = INSTR2(9, s, d); } - | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = INSTR2(10, s, d); } - | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = INSTR2(11, s, d); } - | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = INSTR2(12, s, d); } - | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = INSTR2(13, s, d); } - | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(14, s, d); } - | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(15, s, d); } - | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = INSTR2(16, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = INSTR2(17, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = INSTR2(18, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = INSTR2(19, s, d); } - | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = INSTR2(20, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR2(21, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR2(22, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR2(23, s, d); } + 'bw' ws s:r8 ws? ',' ws? d:r16 { $$ = REGREG2(0x66, (Rex){0}, 0x01000fb6, s, d); } + | 'bl' ws s:r8 ws? ',' ws? d:r32 { $$ = REGREG2(-1, (Rex){0}, 0x01000fb6, s, d); } + | 'bq' ws s:r8 ws? ',' ws? d:r64 { $$ = REGREG2(-1, (Rex){.w=1}, 0x01000fb6, s, d); } + | 'wl' ws s:r16 ws? ',' ws? d:r32 { $$ = REGREG2(-1, (Rex){0}, 0x01000fb7, s, d); } + | 'wq' ws s:r16 ws? ',' ws? d:r64 { $$ = REGREG2(-1, (Rex){.w=1}, 0x01000fb7, s, d); } + | 'bw' ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x01000fb6, s, d); } + | 'bl' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x01000fb6, s, d); } + | 'bq' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x01000fb6, s, d); } + | 'wl' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x01000fb7, s, d); } + | 'wq' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x01000fb7, s, d); } +) + +add = "add" ( + 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = IMM(-1, (Rex){0}, 0x04, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = IMM(0x66, (Rex){0}, 0x05, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = IMM(-1, (Rex){0}, 0x05, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = IMM(-1, (Rex){.w=1}, 0x05, s, d); } + + | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = IMMREG(-1, (Rex){0}, 0x80, 0x00, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0x81, 0x00, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0x81, 0x00, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0x81, 0x00, s, d); } + + | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x80, 0x00, s, d); } + | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0x81, 0x00, s, d); } + | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x81, 0x00, s, d); } + | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0x81, 0x00, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG(-1, (Rex){0}, 0x00, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG(0x66, (Rex){0}, 0x01, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG(-1, (Rex){0}, 0x01, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG(-1, (Rex){.w=1}, 0x01, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x00, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM(0x66, (Rex){0}, 0x01, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x01, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){.w=1}, 0x01, s, d); } + + | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG(-1, (Rex){0}, 0x02, s, d); } + | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x03, s, d); } + | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x03, s, d); } + | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x03, s, d); } +) + + +and = "and" ( + 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = IMM(-1, (Rex){0}, 0x24, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = IMM(0x66, (Rex){0}, 0x25, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = IMM(-1, (Rex){0}, 0x25, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = IMM(-1, (Rex){.w=1}, 0x25, s, d); } + + | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = IMMREG(-1, (Rex){0}, 0x80, 0x04, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0x81, 0x04, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0x81, 0x04, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0x81, 0x04, s, d); } + + | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x80, 0x04, s, d); } + | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0x81, 0x04, s, d); } + | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x81, 0x04, s, d); } + | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0x81, 0x04, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG(-1, (Rex){0}, 0x20, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG(0x66, (Rex){0}, 0x21, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG(-1, (Rex){0}, 0x21, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG(-1, (Rex){.w=1}, 0x21, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x20, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM(0x66, (Rex){0}, 0x21, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x21, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){.w=1}, 0x21, s, d); } + + | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG(-1, (Rex){0}, 0x22, s, d); } + | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x23, s, d); } + | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x23, s, d); } + | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x23, s, d); } +) + +cmp = "cmp" ( + 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = IMM(-1, (Rex){0}, 0x3c, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = IMM(0x66, (Rex){0}, 0x3d, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = IMM(-1, (Rex){0}, 0x3d, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = IMM(-1, (Rex){.w=1}, 0x3d, s, d); } + + | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = IMMREG(-1, (Rex){0}, 0x80, 0x07, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0x81, 0x07, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0x81, 0x07, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0x81, 0x07, s, d); } + + | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x80, 0x07, s, d); } + | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0x81, 0x07, s, d); } + | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x81, 0x07, s, d); } + | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0x81, 0x07, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG(-1, (Rex){0}, 0x38, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG(0x66, (Rex){0}, 0x39, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG(-1, (Rex){0}, 0x39, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG(-1, (Rex){.w=1}, 0x39, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x38, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM(0x66, (Rex){0}, 0x39, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x39, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){.w=1}, 0x39, s, d); } + + | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG(-1, (Rex){0}, 0x3a, s, d); } + | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x3b, s, d); } + | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x3b, s, d); } + | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x3b, s, d); } +) + +or = "or" ( + 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = IMM(-1, (Rex){0}, 0x0c, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = IMM(0x66, (Rex){0}, 0x0d, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = IMM(-1, (Rex){0}, 0x0d, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = IMM(-1, (Rex){.w=1}, 0x0d, s, d); } + + | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = IMMREG(-1, (Rex){0}, 0x80, 0x01, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0x81, 0x01, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0x81, 0x01, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0x81, 0x01, s, d); } + + | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x80, 0x01, s, d); } + | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0x81, 0x01, s, d); } + | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x81, 0x01, s, d); } + | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0x81, 0x01, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG(-1, (Rex){0}, 0x08, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG(0x66, (Rex){0}, 0x09, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG(-1, (Rex){0}, 0x09, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG(-1, (Rex){.w=1}, 0x09, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x08, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM(0x66, (Rex){0}, 0x09, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x09, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){.w=1}, 0x09, s, d); } + + | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG(-1, (Rex){0}, 0x0a, s, d); } + | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x0b, s, d); } + | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x0b, s, d); } + | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x0b, s, d); } +) + +sub = "sub" ( + 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = IMM(-1, (Rex){0}, 0x2c, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = IMM(0x66, (Rex){0}, 0x2d, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = IMM(-1, (Rex){0}, 0x2d, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = IMM(-1, (Rex){.w=1}, 0x2d, s, d); } + + | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = IMMREG(-1, (Rex){0}, 0x80, 0x05, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0x81, 0x05, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0x81, 0x05, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0x81, 0x05, s, d); } + + | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x80, 0x05, s, d); } + | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0x81, 0x05, s, d); } + | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x81, 0x05, s, d); } + | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0x81, 0x05, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG(-1, (Rex){0}, 0x28, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG(0x66, (Rex){0}, 0x29, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG(-1, (Rex){0}, 0x29, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG(-1, (Rex){.w=1}, 0x29, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x28, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM(0x66, (Rex){0}, 0x29, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x29, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){.w=1}, 0x29, s, d); } + + | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG(-1, (Rex){0}, 0x2a, s, d); } + | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x2b, s, d); } + | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x2b, s, d); } + | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x2b, s, d); } +) + +xor = "xor" ( + 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = IMM(-1, (Rex){0}, 0x34, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = IMM(0x66, (Rex){0}, 0x35, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = IMM(-1, (Rex){0}, 0x35, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = IMM(-1, (Rex){.w=1}, 0x35, s, d); } + + | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = IMMREG(-1, (Rex){0}, 0x80, 0x06, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0x81, 0x06, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0x81, 0x06, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0x81, 0x06, s, d); } + + | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x80, 0x06, s, d); } + | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0x81, 0x06, s, d); } + | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0x81, 0x06, s, d); } + | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0x81, 0x06, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG(-1, (Rex){0}, 0x30, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG(0x66, (Rex){0}, 0x31, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG(-1, (Rex){0}, 0x31, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG(-1, (Rex){.w=1}, 0x31, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x30, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM(0x66, (Rex){0}, 0x31, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x31, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){.w=1}, 0x31, s, d); } + + | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG(-1, (Rex){0}, 0x32, s, d); } + | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x33, s, d); } + | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x33, s, d); } + | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x33, s, d); } +) +xchg = "xchg" ( + 'w'? ws s:ax ws? ',' ws? d:r16 { $$ = R(0x66, (Rex){0}, 0x90, d) } + | 'w'? ws s:r16 ws? ',' ws? d:ax { $$ = R(0x66, (Rex){0}, 0x90, s) } + | 'l'? ws s:eax ws? ',' ws? d:r32 { $$ = R(-1, (Rex){0}, 0x90, d) } + | 'l'? ws s:r32 ws? ',' ws? d:eax { $$ = R(-1, (Rex){0}, 0x90, s) } + | 'q'? ws s:rax ws? ',' ws? d:r64 { $$ = R(-1, (Rex){.w=1}, 0x90, d) } + | 'q'? ws s:r64 ws? ',' ws? d:rax { $$ = R(-1, (Rex){.w=1}, 0x90, s) } + + | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG(-1, (Rex){0}, 0x86, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG(0x66, (Rex){0}, 0x87, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG(-1, (Rex){0}, 0x87, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG(-1, (Rex){.w=1}, 0x87, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x86, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM(0x66, (Rex){0}, 0x87, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x87, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){.w=1}, 0x87, s, d); } + + | 'b'? ws s:mem ws? ',' ws? d:r8 { $$ = MEMREG(-1, (Rex){0}, 0x86, s, d); } + | 'w'? ws s:mem ws? ',' ws? d:r16 { $$ = MEMREG(0x66, (Rex){0}, 0x87, s, d); } + | 'l'? ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(-1, (Rex){0}, 0x87, s, d); } + | 'q'? ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(-1, (Rex){.w=1}, 0x87, s, d); } +) + set = "set" cc:condition-code ( - 'b'? ws a:mem{ $$ = INSTR1(0, a); $$.instr.variant = cc.i64; } - | 'b'? ws a:r8 { $$ = INSTR1(0, a); $$.instr.variant = 31 + cc.i64; } -) { $$.instr.kind = ASM_SET } - -sal = "sal" args:shift-args {$$ = args; $$.instr.kind = ASM_SAL} -sar = "sar" args:shift-args {$$ = args; $$.instr.kind = ASM_SAR} -shl = "shl" args:shift-args {$$ = args; $$.instr.kind = ASM_SHL} -shr = "shr" args:shift-args {$$ = args; $$.instr.kind = ASM_SHR} -shift-args = - 'w' ws c:cl ws? ',' ws? d:mem { $$ = INSTR2(0, c, d); } - | 'l' ws c:cl ws? ',' ws? d:mem { $$ = INSTR2(1, c, d); } - | 'q' ws c:cl ws? ',' ws? d:mem { $$ = INSTR2(2, c, d); } - | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = INSTR2(3, c, d); } - | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = INSTR2(4, c, d); } - | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = INSTR2(5, c, d); } - | 'w' ws i:imm8 ws? ',' ws? d:mem { $$ = INSTR2(6, i, d); } - | 'l' ws i:imm8 ws? ',' ws? d:mem { $$ = INSTR2(7, i, d); } - | 'q' ws i:imm8 ws? ',' ws? d:mem { $$ = INSTR2(8, i, d); } - | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = INSTR2(9, i, d); } - | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = INSTR2(10, i, d); } - | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = INSTR2(11, i, d); } + 'b'? ws a:r8 { $$ = OPREG(-1, (Rex){0}, 0x01000f00 | cc2setop[cc.i64], 0x00, a) } + | 'b'? ws a:mem { $$ = OPMEM(-1, (Rex){0}, 0x01000f00 | cc2setop[cc.i64], 0x00, a) } +) + +sal = "sal" ( + 'w' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(0x66, (Rex){0},0xd3, 0x04, d); } + | 'l' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(-1, (Rex){0}, 0xd3, 0x04, d); } + | 'q' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(-1, (Rex){.w=1}, 0xd3, 0x04, d); } + | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = OPREG(0x66, (Rex){0}, 0xd3, 0x04, d); } + | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = OPREG(-1, (Rex){0}, 0xd3, 0x04, d); } + | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = OPREG(-1, (Rex){.w=1}, 0xd3, 0x04, d); } + | 'w' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0xc1, 0x04, i, d); } + | 'l' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0xc1, 0x04, i, d); } + | 'q' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0xc1, 0x04, i, d); } + | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0xc1, 0x04, i, d); } + | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0xc1, 0x04, i, d); } + | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0xc1, 0x04, i, d); } +) + +sar = "sar" ( + 'w' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(0x66, (Rex){0},0xd3, 0x07, d); } + | 'l' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(-1, (Rex){0}, 0xd3, 0x07, d); } + | 'q' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(-1, (Rex){.w=1}, 0xd3, 0x07, d); } + | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = OPREG(0x66, (Rex){0}, 0xd3, 0x07, d); } + | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = OPREG(-1, (Rex){0}, 0xd3, 0x07, d); } + | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = OPREG(-1, (Rex){.w=1}, 0xd3, 0x07, d); } + | 'w' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0xc1, 0x07, i, d); } + | 'l' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0xc1, 0x07, i, d); } + | 'q' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0xc1, 0x07, i, d); } + | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0xc1, 0x07, i, d); } + | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0xc1, 0x07, i, d); } + | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0xc1, 0x07, i, d); } +) + +shl = "shl" ( + 'w' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(0x66, (Rex){0},0xd3, 0x04, d); } + | 'l' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(-1, (Rex){0}, 0xd3, 0x04, d); } + | 'q' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(-1, (Rex){.w=1}, 0xd3, 0x04, d); } + | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = OPREG(0x66, (Rex){0}, 0xd3, 0x04, d); } + | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = OPREG(-1, (Rex){0}, 0xd3, 0x04, d); } + | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = OPREG(-1, (Rex){.w=1}, 0xd3, 0x04, d); } + | 'w' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0xc1, 0x04, i, d); } + | 'l' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0xc1, 0x04, i, d); } + | 'q' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0xc1, 0x04, i, d); } + | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0xc1, 0x04, i, d); } + | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0xc1, 0x04, i, d); } + | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0xc1, 0x04, i, d); } +) + +shr = "shr" ( + 'w' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(0x66, (Rex){0},0xd3, 0x05, d); } + | 'l' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(-1, (Rex){0}, 0xd3, 0x05, d); } + | 'q' ws c:cl ws? ',' ws? d:mem { $$ = OPMEM(-1, (Rex){.w=1}, 0xd3, 0x05, d); } + | 'w'? ws c:cl ws? ',' ws? d:r16 { $$ = OPREG(0x66, (Rex){0}, 0xd3, 0x05, d); } + | 'l'? ws c:cl ws? ',' ws? d:r32 { $$ = OPREG(-1, (Rex){0}, 0xd3, 0x05, d); } + | 'q'? ws c:cl ws? ',' ws? d:r64 { $$ = OPREG(-1, (Rex){.w=1}, 0xd3, 0x05, d); } + | 'w' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0xc1, 0x05, i, d); } + | 'l' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0xc1, 0x05, i, d); } + | 'q' ws i:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0xc1, 0x05, i, d); } + | 'w'? ws i:imm8 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0xc1, 0x05, i, d); } + | 'l'? ws i:imm8 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0xc1, 0x05, i, d); } + | 'q'? ws i:imm8 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0xc1, 0x05, i, d); } +) test = "test" ( - 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = INSTR2(0, s, d); } - | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = INSTR2(1, s, d); } - | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = INSTR2(2, s, d); } - | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = INSTR2(3, s, d); } - | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = INSTR2(4, s, d); } - | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = INSTR2(5, s, d); } - | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = INSTR2(6, s, d); } - | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = INSTR2(7, s, d); } - | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = INSTR2(8, s, d); } - | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = INSTR2(9, s, d); } - | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = INSTR2(10, s, d); } - | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = INSTR2(11, s, d); } - | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = INSTR2(12, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = INSTR2(13, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = INSTR2(14, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = INSTR2(15, s, d); } - | 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = INSTR2(16, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = INSTR2(17, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = INSTR2(18, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR2(19, s, d); } - -) { $$.instr.kind = ASM_TEST; } + 'b'? ws s:r8 ws? ',' ws? d:r8 { $$ = REGREG(-1, (Rex){0}, 0x84, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:r16 { $$ = REGREG(0x66, (Rex){0}, 0x85, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:r32 { $$ = REGREG(-1, (Rex){0}, 0x85, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = REGREG(-1, (Rex){.w=1}, 0x85, s, d); } + + | 'b'? ws s:r8 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x84, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:mem { $$ = REGMEM(0x66, (Rex){0}, 0x85, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x85, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){.w=1}, 0x85, s, d); } + + | 'b'? ws s:imm8 ws? ',' ws? d:al { $$ = IMM(-1, (Rex){0}, 0xa8, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = IMM(0x66, (Rex){0}, 0xa9, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = IMM(-1, (Rex){0}, 0xa9, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = IMM(-1, (Rex){.w=1}, 0xa9, s, d); } + + | 'b'? ws s:imm8 ws? ',' ws? d:r8 { $$ = IMMREG(-1, (Rex){0}, 0xf6, 0x00, s, d); } + | 'w'? ws s:imm16 ws? ',' ws? d:r16 { $$ = IMMREG(0x66, (Rex){0}, 0xf7, 0x00, s, d); } + | 'l'? ws s:imm32 ws? ',' ws? d:r32 { $$ = IMMREG(-1, (Rex){0}, 0xf7, 0x00, s, d); } + | 'q'? ws s:imm32 ws? ',' ws? d:r64 { $$ = IMMREG(-1, (Rex){.w=1}, 0xf7, 0x00, s, d); } + + | 'b' ws s:imm8 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0xf6, 0x00, s, d); } + | 'w' ws s:imm16 ws? ',' ws? d:mem { $$ = IMMMEM(0x66, (Rex){0}, 0xf7, 0x00, s, d); } + | 'l' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){0}, 0xf7, 0x00, s, d); } + | 'q' ws s:imm32 ws? ',' ws? d:mem { $$ = IMMMEM(-1, (Rex){.w=1}, 0xf7, 0x00, s, d); } +) # Floating point instructions. addsd = "addsd" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_ADDSD; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf2, (Rex){0}, 0x01000f58, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf2, (Rex){0}, 0x01000f58, s, d); } +) addss = "addss" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_ADDSS; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf3, (Rex){0}, 0x01000f58, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf3, (Rex){0}, 0x01000f58, s, d); } +) subsd = "subsd" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_SUBSD; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf2, (Rex){0}, 0x01000f5c, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf2, (Rex){0}, 0x01000f5c, s, d); } +) subss = "subss" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_SUBSS; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf3, (Rex){0}, 0x01000f5c, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf3, (Rex){0}, 0x01000f5c, s, d); } +) cvtsi2sd = "cvtsi2sd" ( - ws s:r32 ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } - | ws s:r64 ws? ',' ws? d:xmm { $$ = INSTR2(2, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(3, s, d); } -) { $$.instr.kind = ASM_CVTSI2SD; } + ws s:r32 ws? ',' ws? d:xmm { $$ = REGREG2(0xf2, (Rex){0}, 0x01000f2a, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf2, (Rex){0}, 0x01000f2a, s, d); } + | ws s:r64 ws? ',' ws? d:xmm { $$ = REGREG2(0xf2, (Rex){.w=1}, 0x01000f2a, s, d); } + # XXX | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf2, (Rex){.w=1}, 0x01000f2a, s, d); } +) cvtsi2ss = "cvtsi2ss" ( - ws s:r32 ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } - | ws s:r64 ws? ',' ws? d:xmm { $$ = INSTR2(2, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(3, s, d); } -) { $$.instr.kind = ASM_CVTSI2SS; } + ws s:r32 ws? ',' ws? d:xmm { $$ = REGREG2(0xf3, (Rex){0}, 0x01000f2a, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf3, (Rex){0}, 0x01000f2a, s, d); } + | ws s:r64 ws? ',' ws? d:xmm { $$ = REGREG2(0xf3, (Rex){.w=1}, 0x01000f2a, s, d); } + # XXX | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf3, (Rex){.w=1}, 0x01000f2a, s, d); } +) cvtss2sd = "cvtss2sd" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_CVTSS2SD; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf3, (Rex){0}, 0x01000f5a, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf3, (Rex){0}, 0x01000f5a, s, d); } +) cvtsd2ss = "cvtsd2ss" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_CVTSD2SS; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0x010066f3, (Rex){0}, 0x5a, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0x010066f3, (Rex){0}, 0x5a, s, d); } +) cvttss2si = "cvttss2si" ( - 'l'? ws s:xmm ws? ',' ws? d:r32 { $$ = INSTR2(0, s, d); } - | 'q'? ws s:xmm ws? ',' ws? d:r64 { $$ = INSTR2(1, s, d); } - | 'l' ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(2, s, d); } - | 'q' ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(3, s, d); } -) { $$.instr.kind = ASM_CVTTSS2SI; } + 'l'? ws s:xmm ws? ',' ws? d:r32 { $$ = REGREG2(0xf3, (Rex){0}, 0x01000f2c, s, d); } + | 'q'? ws s:xmm ws? ',' ws? d:r64 { $$ = REGREG2(0xf3, (Rex){.w=1}, 0x01000f2c, s, d); } + | 'l' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(0xf3, (Rex){0}, 0x01000f7e, s, d); } + | 'q' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(0xf3, (Rex){.w=1}, 0x01000f2c, s, d); } +) cvttsd2si = "cvttsd2si" ( - 'l'? ws s:xmm ws? ',' ws? d:r32 { $$ = INSTR2(0, s, d); } - | 'q'? ws s:xmm ws? ',' ws? d:r64 { $$ = INSTR2(1, s, d); } - | 'l' ws s:mem ws? ',' ws? d:r32 { $$ = INSTR2(2, s, d); } - | 'q' ws s:mem ws? ',' ws? d:r64 { $$ = INSTR2(3, s, d); } -) { $$.instr.kind = ASM_CVTTSD2SI; } + 'l'? ws s:xmm ws? ',' ws? d:r32 { $$ = REGREG2(0xf2, (Rex){0}, 0x01000f2c, s, d); } + | 'q'? ws s:xmm ws? ',' ws? d:r64 { $$ = REGREG2(0xf2, (Rex){.w=1}, 0x01000f2c, s, d); } + | 'l' ws s:mem ws? ',' ws? d:r32 { $$ = MEMREG(0xf2, (Rex){0}, 0x01000f7e, s, d); } + | 'q' ws s:mem ws? ',' ws? d:r64 { $$ = MEMREG(0xf2, (Rex){.w=1}, 0x01000f2c, s, d); } +) divsd = "divsd" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_DIVSD; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf2, (Rex){0}, 0x01000f5e, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf2, (Rex){0}, 0x01000f5e, s, d); } +) divss = "divss" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_DIVSS; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf3, (Rex){0}, 0x01000f5e, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf3, (Rex){0}, 0x01000f5e, s, d); } +) movaps = "movaps" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } - | ws s:xmm ws? ',' ws? d:mem { $$ = INSTR2(2, s, d); } -) { $$.instr.kind = ASM_MOVAPS; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(-1, (Rex){0}, 0x01000f28, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(-1, (Rex){0}, 0x01000f28, s, d); } + | ws s:xmm ws? ',' ws? d:mem { $$ = REGMEM(-1, (Rex){0}, 0x01000f29, s, d); } +) mulsd = "mulsd" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_MULSD; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf2, (Rex){0}, 0x01000f59, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf2, (Rex){0}, 0x01000f59, s, d); } +) mulss = "mulss" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_MULSS; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf3, (Rex){0}, 0x01000f59, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf3, (Rex){0}, 0x01000f59, s, d); } +) movss = "movss" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } - | ws s:xmm ws? ',' ws? d:mem { $$ = INSTR2(2, s, d); } -) { $$.instr.kind = ASM_MOVSS; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf3, (Rex){0}, 0x01000f10, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf3, (Rex){0}, 0x01000f10, s, d); } + | ws s:xmm ws? ',' ws? d:mem { $$ = REGMEM(0xf3, (Rex){0}, 0x01000f11, s, d); } +) movsd = "movsd" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } - | ws s:xmm ws? ',' ws? d:mem { $$ = INSTR2(2, s, d); } -) { $$.instr.kind = ASM_MOVSD; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0xf2, (Rex){0}, 0x01000f10, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf2, (Rex){0}, 0x01000f10, s, d); } + | ws s:xmm ws? ',' ws? d:mem { $$ = REGMEM(0xf2, (Rex){0}, 0x01000f11, s, d); } +) movq = "mov" ( - 'q'? ws s:xmm ws? ',' ws? d:r64 { $$ = INSTR2(0, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } - | 'q' ws s:xmm ws? ',' ws? d:mem { $$ = INSTR2(2, s, d); } - | 'q' ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(3, s, d); } -) { $$.instr.kind = ASM_MOVQ; } + 'q'? ws s:xmm ws? ',' ws? d:r64 { $$ = REGREG(0x66, (Rex){.w=1}, 0x01000f7e, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:xmm { $$ = REGREG2(0x66, (Rex){.w=1}, 0x01000f6e, s, d); } + | 'q' ws s:xmm ws? ',' ws? d:mem { $$ = REGMEM(0x66, (Rex){0}, 0x01000fd6, s, d); } + | 'q' ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0xf3, (Rex){0}, 0x01000f7e, s, d); } +) ucomiss = "ucomiss" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_UCOMISS; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(-1, (Rex){0}, 0x01000f2e, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(-1, (Rex){0}, 0x01000f2e, s, d); } +) ucomisd = "ucomisd" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_UCOMISD; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0x66, (Rex){0}, 0x01000f2e, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0x66, (Rex){0}, 0x01000f2e, s, d); } +) pxor = "pxor" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_PXOR; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0x66, (Rex){0}, 0x01000fef, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0x66, (Rex){0}, 0x01000fef, s, d); } +) xorpd = "xorpd" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_XORPD; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(0x66, (Rex){0}, 0x01000f57, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(0x66, (Rex){0}, 0x01000f57, s, d); } +) xorps = "xorps" ( - ws s:xmm ws? ',' ws? d:xmm { $$ = INSTR2(0, s, d); } - | ws s:mem ws? ',' ws? d:xmm { $$ = INSTR2(1, s, d); } -) { $$.instr.kind = ASM_XORPS; } + ws s:xmm ws? ',' ws? d:xmm { $$ = REGREG2(-1, (Rex){0}, 0x01000f57, s, d); } + | ws s:mem ws? ',' ws? d:xmm { $$ = MEMREG(-1, (Rex){0}, 0x01000f57, s, d); } +) r64-or-rip = ( r:r64 @@ -3,10 +3,10 @@ /* Parsed assembly */ static AsmLine *allasm = NULL; -/* Number of assembly the relaxation passes. */ +/* Number of assembly relaxation passes. */ static int nrelax = 1; -/* Symbol table. */ +/* Symbols before writing to symtab section. */ static struct hashtable *symbols = NULL; /* Array of all relocations before adding to the rel section. */ @@ -213,15 +213,6 @@ static uint8_t regbits(AsmKind k) { return (k - (ASM_REG_BEGIN + 1)) % 16; } static uint8_t isreg64(AsmKind k) { return k >= ASM_RAX && k <= ASM_R15; } -/* Rex opcode prefix. */ -typedef struct Rex { - uint8_t required : 1; - uint8_t w : 1; - uint8_t r : 1; - uint8_t x : 1; - uint8_t b : 1; -} Rex; - /* Register that requires the use of a rex prefix. */ static uint8_t isrexreg(AsmKind k) { return k > ASM_REG_BEGIN && k < ASM_REG_END && @@ -289,14 +280,6 @@ static void assemblerex(Rex rex) { sb(rexbyte(rex)); } -/* Assemble op +rw | op + rd. */ -static void assembleplusr(Rex rex, VarBytes prefix, VarBytes opcode, - uint8_t reg) { - assemblevbytes(prefix); - assemblerex(rex); - assemblevbytes(opcode | (reg & 7)); -} - static void assemblemodregrm(Rex rex, VarBytes prefix, VarBytes opcode, uint8_t mod, uint8_t reg, uint8_t rm) { assemblevbytes(prefix); @@ -449,301 +432,6 @@ static void assemblemem(const Memarg *memarg, Rex rex, VarBytes prefix, } } -/* Assemble op + imm -> r/m. */ -static void assembleimmrm(const Instr *instr, Rex rex, VarBytes prefix, - VarBytes opcode, uint8_t immreg) { - uint8_t rm; - const Memarg *memarg; - const Imm *imm; - - imm = &instr->arg1->imm; - - if (instr->arg2->kind == ASM_MEMARG) { - memarg = &instr->arg2->memarg; - - if (memarg->base == ASM_RIP) { - assembleriprel(memarg, rex, prefix, opcode, immreg, -imm->nbytes); - } else { - assemblemem(memarg, rex, prefix, opcode, immreg); - } - - } else { - rm = regbits(instr->arg2->kind); - rex.required = isrexreg(instr->arg2->kind); - rex.b = !!(rm & (1 << 3)); - assemblemodregrm(rex, prefix, opcode, 0x03, immreg, rm); - } - assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); -} - -/* Assemble op + r <-> r/m. */ -static void assemblerrm(const Instr *instr, VarBytes prefix, VarBytes opcode, - int invert) { - Rex rex; - AsmKind regarg; - uint8_t reg1bits, reg2bits; - const Memarg *memarg; - const Parsev *arg1, *arg2; - - if (invert) { - arg1 = instr->arg2; - arg2 = instr->arg1; - } else { - arg1 = instr->arg1; - arg2 = instr->arg2; - } - - if (arg1->kind == ASM_MEMARG) { - memarg = &arg1->memarg; - regarg = arg2->kind; - reg1bits = regbits(regarg); - rex = (Rex){.required = isrexreg(regarg), - .w = isreg64(regarg), - .r = !!(reg1bits & (1 << 3))}; - assemblemem(memarg, rex, prefix, opcode, reg1bits); - } else if (arg2->kind == ASM_MEMARG) { - memarg = &arg2->memarg; - regarg = arg1->kind; - reg1bits = regbits(regarg); - rex = (Rex){.required = isrexreg(regarg), - .w = isreg64(regarg), - .r = !!(reg1bits & (1 << 3))}; - assemblemem(memarg, rex, prefix, opcode, reg1bits); - } else { - reg1bits = regbits(arg1->kind); - reg2bits = regbits(arg2->kind); - rex = (Rex){.required = isrexreg(arg1->kind) || isrexreg(arg2->kind), - .w = isreg64(arg1->kind) || isreg64(arg2->kind), - .r = !!(reg1bits & (1 << 3)), - .b = !!(reg2bits & (1 << 3))}; - assemblemodregrm(rex, prefix, opcode, 0x03, reg1bits, reg2bits); - } -} - -/* Assemble a 'basic op' which is just a repeated op pattern we have named. */ -static void assemblebasicop(const Instr *instr, VarBytes opcode, - uint8_t immreg) { - VarBytes prefix; - const Imm *imm; - Rex rex; - - prefix = ((instr->variant % 4) == 1) ? 0x66 : -1; - - if (instr->variant < 4) { - imm = &instr->arg1->imm; - rex = (Rex){ - .w = instr->variant == 3, - }; - assemblevbytes(prefix); - assemblerex(rex); - assemblevbytes(opcode); - assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); - } else if (instr->variant < 12) { - rex = (Rex){ - .w = (instr->variant % 4) == 3, - }; - assembleimmrm(instr, rex, prefix, opcode, immreg); - } else { - assemblerrm(instr, prefix, opcode, 0); - } -} - -static void assemblexchg(const Instr *xchg) { - Rex rex; - AsmKind reg; - VarBytes prefix, opcode; - static uint8_t variant2op[18] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x86, 0x87, 0x87, 0x87, 0x86, 0x87, - 0x87, 0x87, 0x86, 0x87, 0x87, 0x87}; - - opcode = variant2op[xchg->variant]; - if (xchg->variant < 6) { - reg = (xchg->variant % 2) ? xchg->arg1->kind : xchg->arg2->kind; - prefix = (xchg->variant < 2) ? 0x66 : -1; - rex = (Rex){ - .required = isrexreg(xchg->arg1->kind) || isrexreg(xchg->arg2->kind), - .w = isreg64(xchg->arg1->kind) || isreg64(xchg->arg2->kind), - .b = !!(regbits(reg) & (1 << 3)), - }; - assembleplusr(rex, prefix, opcode, regbits(reg)); - } else { - prefix = (((xchg->variant - 6) % 4) == 1) ? 0x66 : -1; - assemblerrm(xchg, prefix, opcode, 0); - } -} - -static void assemblemov(const Instr *mov) { - Rex rex; - int8_t reg; - const Imm *imm; - VarBytes prefix, opcode; - - static uint8_t variant2op[20] = {0x88, 0x89, 0x89, 0x89, 0x88, 0x89, 0x89, - 0x89, 0x8a, 0x8b, 0x8b, 0x8b, 0xc6, 0xc7, - 0xc7, 0xc7, 0xb0, 0xb8, 0xb8, 0xc7}; - - prefix = ((mov->variant % 4) == 1) ? 0x66 : -1; - opcode = variant2op[mov->variant]; - - if (mov->variant < 12) { - assemblerrm(mov, prefix, opcode, 0); - } else if (mov->variant < 16) { - rex = (Rex){.w = (mov->variant % 4) == 3}; - assembleimmrm(mov, rex, prefix, opcode, 0x00); - } else if (mov->variant == 19) { - uint64_t mask, maskedc; - - imm = &mov->arg1->imm; - mask = 0xffffffff80000000; - maskedc = ((uint64_t)imm->v.c) & mask; - - if ((maskedc == mask || maskedc == 0) && imm->v.l == NULL) { - /* Sign extension works for this value, regular mov */ - reg = regbits(mov->arg2->kind); - rex = (Rex){ - .required = isrexreg(mov->arg2->kind), - .w = 1, - .b = !!(reg & (1 << 3)), - }; - assemblemodregrm(rex, prefix, opcode, 0x03, 0x00, reg); - assemblereloc(imm->v.l, imm->v.c, 4, R_X86_64_32); - } else { - /* 64 bit immediate required. */ - reg = regbits(mov->arg2->kind); - rex = (Rex){ - .required = isrexreg(mov->arg2->kind), - .w = 1, - .b = !!(reg & (1 << 3)), - }; - assemblerex(rex); - sb(0xb8 | (reg & 7)); - assemblereloc(imm->v.l, imm->v.c, 8, R_X86_64_64); - } - } else { - imm = &mov->arg1->imm; - reg = regbits(mov->arg2->kind); - rex = (Rex){ - .required = isrexreg(mov->arg2->kind), - .w = isreg64(mov->arg2->kind), - .b = !!(reg & (1 << 3)), - }; - assembleplusr(rex, prefix, opcode, reg); - assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); - } -} - -static void assemblemovextend(const Instr *mov, VarBytes opcode) { - VarBytes prefix; - if (mov->variant == 0 || mov->variant == 5) - prefix = 0x66; - else - prefix = -1; - assemblerrm(mov, prefix, opcode, 1); -} - -static void assembledivmulneg(const Instr *instr, uint8_t reg) { - Rex rex; - VarBytes prefix, opcode; - uint8_t rm; - - rex = (Rex){ - .w = (instr->variant % 4) == 3, - }; - prefix = (instr->variant % 4) == 1 ? 0x66 : -1; - opcode = (instr->variant % 4) == 1 ? 0xf6 : 0xf7; - - if (instr->arg1->kind == ASM_MEMARG) { - assemblemem(&instr->arg1->memarg, rex, prefix, opcode, reg); - } else { - rm = regbits(instr->arg1->kind); - rex.w = isreg64(instr->arg1->kind); - rex.r = !!(reg & (1 << 3)); - rex.b = !!(rm & (1 << 3)); - assemblemodregrm(rex, prefix, opcode, 0x03, reg, rm); - } -} - -static void assembleshift(const Instr *instr, uint8_t immreg) { - Rex rex; - VarBytes prefix, opcode; - uint8_t rm; - - opcode = (instr->variant < 6) ? 0xd3 : 0xc1; - rex = (Rex){.w = (instr->variant % 3) == 2}; - prefix = ((instr->variant % 3) == 0) ? 0x66 : -1; - - if (instr->arg1->kind == ASM_IMM) { - assembleimmrm(instr, rex, prefix, opcode, immreg); - } else if (instr->arg2->kind == ASM_MEMARG) { - assemblemem(&instr->arg2->memarg, rex, prefix, opcode, immreg); - } else { - rm = regbits(instr->arg2->kind); - rex.r = !!(immreg & (1 << 3)); - rex.b = !!(rm & (1 << 3)); - assemblemodregrm(rex, prefix, opcode, 0x03, immreg, rm); - } -} - -static void assemblemovsmmx(const Instr *instr, VarBytes prefix) { - VarBytes opcode; - if (instr->variant == 2) { - opcode = 0x01000f11; - assemblerrm(instr, prefix, opcode, 0); - } else { - opcode = 0x01000f10; - assemblerrm(instr, prefix, opcode, 1); - } -} - -static void assembletest(const Instr *instr) { - const Imm *imm; - Rex rex; - VarBytes prefix; - uint8_t byteop; - - byteop = ((instr->variant % 4) == 0); - prefix = ((instr->variant % 4) == 1) ? 0x66 : -1; - - if (instr->variant < 4) { - rex = (Rex){.w = instr->variant == 3}; - assemblevbytes(prefix); - assemblerex(rex); - assemblevbytes(byteop ? 0xa8 : 0xa9); - imm = &instr->arg1->imm; - assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); - } else if (instr->variant < 12) { - rex = (Rex){.w = (instr->variant % 4) == 3}; - assembleimmrm(instr, rex, prefix, byteop ? 0xf6 : 0xf7, 0); - } else { - assemblerrm(instr, prefix, byteop ? 0x84 : 0x85, 0); - } -} - -static void assembleset(const Instr *instr) { - Rex rex; - VarBytes prefix, opcode; - uint8_t reg, rm; - static uint8_t variant2op[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, - }; - opcode = 0x01000f00 | variant2op[instr->variant % 31]; - prefix = -1; - if (instr->arg1->kind == ASM_MEMARG) { - rex = (Rex){0}; - assemblemem(&instr->arg1->memarg, rex, prefix, opcode, 0); - } else { - rm = regbits(instr->arg1->kind); - rex = (Rex){ - .required = isrexreg(instr->arg1->kind), - .w = isreg64(instr->arg1->kind), - .b = !!(rm & (1 << 3)), - }; - assemblemodregrm(rex, prefix, opcode, 0x03, 0, rm); - } -} - static void assemblecall(const Call *call) { Rex rex; uint8_t rm; @@ -751,7 +439,8 @@ static void assemblecall(const Call *call) { if (call->indirect) { if (call->target.indirect->kind == ASM_MEMARG) { rex = (Rex){0}; - assemblemem(&call->target.indirect->memarg, rex, -1, 0xff, 0x02); + abort(); // assemblemem(&call->target.indirect->memarg, rex, -1, 0xff, + // 0x02); } else { rm = regbits(call->target.indirect->kind); rex = (Rex){.b = !!(rm & (1 << 3))}; @@ -764,25 +453,6 @@ static void assemblecall(const Call *call) { } } -static void assembleimul(const Instr *instr) { - VarBytes prefix, opcode; - - if (instr->variant < 8) { - assembledivmulneg(instr, 0x05); - } else if (instr->variant < 14) { - opcode = 0x01000faf; - prefix = ((instr->variant - 8) % 3) == 0 ? 0x66 : -1; - assemblerrm(instr, prefix, opcode, 1); - } else { - const Imm *imm; - imm = &instr->arg3->imm; - opcode = 0x69; - prefix = ((instr->variant - 14) % 3) == 0 ? 0x66 : -1; - assemblerrm(instr, prefix, opcode, 1); - assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); - } -} - static void assemblejmp(const Jmp *j) { int jmpsize; int64_t distance; @@ -927,262 +597,205 @@ static void assemble(void) { lfatal("%s already defined", sym->name); sym->defined = 1; break; - case ASM_CALL: - assemblecall(&v->call); - break; - case ASM_JMP: - assemblejmp(&v->jmp); - break; - case ASM_PUSH: { + case ASM_INSTR: { Rex rex; - uint8_t reg; + const Instr *instr; + const Memarg *memarg; + const Imm *imm; + uint8_t mod, reg, rm; - if (v->instr.arg1->kind == ASM_MEMARG) { - rex = (Rex){0}; - assemblemem(&v->instr.arg1->memarg, rex, -1, 0xff, 0x06); - } else { - reg = regbits(v->instr.arg1->kind); - rex = (Rex){.b = !!(reg & (1 << 3))}; - assembleplusr(rex, -1, 0x50, reg); - } - break; - } - case ASM_POP: { - Rex rex; - uint8_t reg; + instr = &v->instr; - if (v->instr.arg1->kind == ASM_MEMARG) { - rex = (Rex){0}; - assemblemem(&v->instr.arg1->memarg, rex, -1, 0x8f, 0x00); - } else { - reg = regbits(v->instr.arg1->kind); - rex = (Rex){.b = !!(reg & (1 << 3))}; - assembleplusr(rex, -1, 0x58, reg); - } - break; - } - case ASM_NOP: - sb(0x90); - break; - case ASM_LEAVE: - sb(0xc9); - break; - case ASM_CLTD: - sb(0x99); - break; - case ASM_CQTO: - sb2(0x48, 0x99); - break; - case ASM_CVTSI2SD: - assemblerrm(&v->instr, 0xf2, 0x01000f2a, 1); - break; - case ASM_CVTSI2SS: - assemblerrm(&v->instr, 0xf3, 0x01000f2a, 1); - break; - case ASM_CVTSS2SD: - assemblerrm(&v->instr, 0xf3, 0x01000f5a, 1); - break; - case ASM_CVTSD2SS: - assemblerrm(&v->instr, 0xf2, 0x01000f5a, 1); - break; - case ASM_CVTTSD2SI: - assemblerrm(&v->instr, 0xf2, 0x01000f2c, 1); - break; - case ASM_CVTTSS2SI: - assemblerrm(&v->instr, 0xf3, 0x01000f2c, 1); - break; - case ASM_RET: - sb(0xc3); - break; - case ASM_LEA: { - VarBytes prefix; - prefix = v->instr.variant == 0 ? 0x66 : -1; - assemblerrm(&v->instr, prefix, 0x8d, 0); - break; - } - case ASM_MOVAPS: { - VarBytes prefix, opcode; - prefix = -1; - opcode = v->instr.variant == 2 ? 0x01000f29 : 0x01000f28; - assemblerrm(&v->instr, prefix, opcode, 1); - break; - } - case ASM_MOV: - assemblemov(&v->instr); - break; - case ASM_MOVQ: - switch (v->instr.variant) { - case 0: - assemblerrm(&v->instr, 0x66, 0x01000f7e, 0); + switch (instr->encoder) { + case ENCODER_OP: + assemblevbytes(instr->opcode); + break; + case ENCODER_OPREG: + rm = regbits(instr->arg1->kind); + rex = instr->rex; + rex.required = isrexreg(instr->arg1->kind); + rex.b = !!(rm & (1 << 3)); + assemblevbytes(instr->prefix); + assemblerex(rex); + assemblevbytes(instr->opcode); + sb(modregrmbyte(0x03, instr->fixedreg, rm)); + break; + case ENCODER_OPMEM: + memarg = &instr->arg1->memarg; + rex = instr->rex; + assemblemem(memarg, rex, instr->prefix, instr->opcode, instr->fixedreg); break; - case 1: - assemblerrm(&v->instr, 0x66, 0x01000f6e, 1); + case ENCODER_R: + reg = regbits(instr->arg1->kind); + rex = instr->rex; + rex.required = isrexreg(instr->arg1->kind); + rex.b = !!(reg & (1 << 3)); + assemblevbytes(instr->prefix); + assemblerex(rex); + assemblevbytes(instr->opcode | (reg & 7)); break; - case 2: - assemblerrm(&v->instr, 0x66, 0x01000fd6, 0); + case ENCODER_RIMM: + imm = &instr->arg1->imm; + reg = regbits(instr->arg2->kind); + rex = instr->rex; + rex.required = isrexreg(instr->arg2->kind); + rex.b = !!(reg & (1 << 3)); + assemblevbytes(instr->prefix); + assemblerex(rex); + assemblevbytes(instr->opcode | (reg & 7)); + if (imm->nbytes == 1) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8); + else if (imm->nbytes == 2) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16); + else if (imm->nbytes == 4) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); + else if (imm->nbytes == 8) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_64); + else + unreachable(); + break; + case ENCODER_IMM: + imm = &instr->arg1->imm; + rex = instr->rex; + assemblevbytes(instr->prefix); + assemblerex(rex); + assemblevbytes(instr->opcode); + if (imm->nbytes == 1) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8); + else if (imm->nbytes == 2) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16); + else if (imm->nbytes == 4) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); + else + unreachable(); break; - case 3: - assemblerrm(&v->instr, 0xf3, 0x01000f7e, 1); + case ENCODER_IMMREG: + imm = &instr->arg1->imm; + reg = instr->fixedreg; + rm = regbits(instr->arg2->kind); + rex = instr->rex; + rex.required = isrexreg(instr->arg2->kind); + rex.b = !!(rm & (1 << 3)); + assemblevbytes(instr->prefix); + assemblerex(rex); + assemblevbytes(instr->opcode); + sb(modregrmbyte(0x03, reg, rm)); + if (imm->nbytes == 1) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8); + else if (imm->nbytes == 2) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16); + else if (imm->nbytes == 4) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); + else + unreachable(); + break; + case ENCODER_IMMMEM: + imm = &instr->arg1->imm; + memarg = &instr->arg2->memarg; + reg = instr->fixedreg; + rex = instr->rex; + if (memarg->base == ASM_RIP) { + assembleriprel(memarg, rex, instr->prefix, instr->opcode, + instr->fixedreg, -imm->nbytes); + } else { + assemblemem(memarg, rex, instr->prefix, instr->opcode, + instr->fixedreg); + } + if (imm->nbytes == 1) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8); + else if (imm->nbytes == 2) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16); + else if (imm->nbytes == 4) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); + else + unreachable(); + break; + case ENCODER_REGMEM: + case ENCODER_MEMREG: + if (instr->encoder == ENCODER_MEMREG) { + memarg = &instr->arg1->memarg; + reg = regbits(instr->arg2->kind); + } else { + memarg = &instr->arg2->memarg; + reg = regbits(instr->arg1->kind); + } + rex = instr->rex; + rex.required = + isrexreg(instr->arg1->kind) || isrexreg(instr->arg2->kind); + rex.r = !!(reg & (1 << 3)); + assemblemem(memarg, rex, instr->prefix, instr->opcode, reg); + break; + case ENCODER_REGREG: + case ENCODER_REGREG2: + if (instr->encoder == ENCODER_REGREG) { + reg = regbits(instr->arg1->kind); + rm = regbits(instr->arg2->kind); + } else { + reg = regbits(instr->arg2->kind); + rm = regbits(instr->arg1->kind); + } + rex = instr->rex; + rex.required = + isrexreg(instr->arg1->kind) || isrexreg(instr->arg2->kind); + rex.r = !!(reg & (1 << 3)); + rex.b = !!(rm & (1 << 3)); + assemblevbytes(instr->prefix); + assemblerex(rex); + assemblevbytes(instr->opcode); + sb(modregrmbyte(0x03, reg, rm)); + break; + case ENCODER_IMMREGREG2: + imm = &instr->arg1->imm; + reg = regbits(instr->arg3->kind); + rm = regbits(instr->arg2->kind); + rex = instr->rex; + rex.required = + isrexreg(instr->arg1->kind) || isrexreg(instr->arg2->kind); + rex.r = !!(reg & (1 << 3)); + rex.b = !!(rm & (1 << 3)); + assemblevbytes(instr->prefix); + assemblerex(rex); + assemblevbytes(instr->opcode); + sb(modregrmbyte(0x03, reg, rm)); + if (imm->nbytes == 1) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8); + else if (imm->nbytes == 2) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16); + else if (imm->nbytes == 4) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); + else + unreachable(); + break; + case ENCODER_IMMMEMREG: + imm = &instr->arg1->imm; + memarg = &instr->arg2->memarg; + reg = regbits(instr->arg3->kind); + rex = instr->rex; + rex.required = + isrexreg(instr->arg1->kind) || isrexreg(instr->arg2->kind); + rex.r = !!(reg & (1 << 3)); + assemblemem(memarg, rex, instr->prefix, instr->opcode, reg); + if (imm->nbytes == 1) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_8); + else if (imm->nbytes == 2) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_16); + else if (imm->nbytes == 4) + assemblereloc(imm->v.l, imm->v.c, imm->nbytes, R_X86_64_32); + else + unreachable(); break; default: unreachable(); } - break; - case ASM_MOVSD: - assemblemovsmmx(&v->instr, 0xf2); - break; - case ASM_MOVSS: - assemblemovsmmx(&v->instr, 0xf3); - break; - case ASM_MOVSX: { - VarBytes opcode; - if (v->instr.variant >= 10) { - opcode = 0x63; // movsxd - } else { - static uint8_t variant2op[10] = {0xbe, 0xbe, 0xbe, 0xbf, 0xbf, - 0xbe, 0xbe, 0xbe, 0xbf, 0xbf}; - opcode = 0x01000f00 | variant2op[v->instr.variant]; - } - assemblemovextend(&v->instr, opcode); - break; - } - case ASM_MOVZX: { - VarBytes opcode; - static uint8_t variant2op[10] = {0xb6, 0xb6, 0xb6, 0xb7, 0xb7, - 0xb6, 0xb6, 0xb6, 0xb7, 0xb7}; - opcode = 0x01000f00 | variant2op[v->instr.variant]; - assemblemovextend(&v->instr, opcode); - break; - } - case ASM_ADD: { - static uint8_t variant2op[24] = { - 0x04, 0x05, 0x05, 0x05, 0x80, 0x81, 0x81, 0x81, - 0x80, 0x81, 0x81, 0x81, 0x02, 0x03, 0x03, 0x03, - 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, - }; - assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x00); - break; - } - case ASM_AND: { - static uint8_t variant2op[24] = { - 0x24, 0x25, 0x25, 0x25, 0x80, 0x81, 0x81, 0x81, - 0x80, 0x81, 0x81, 0x81, 0x22, 0x23, 0x23, 0x23, - 0x20, 0x21, 0x21, 0x21, 0x20, 0x21, 0x21, 0x21, - }; - assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x04); - break; - } - case ASM_CMP: { - static uint8_t variant2op[24] = { - 0x3c, 0x3d, 0x3d, 0x3d, 0x80, 0x81, 0x81, 0x81, - 0x80, 0x81, 0x81, 0x81, 0x3a, 0x3b, 0x3b, 0x3b, - 0x38, 0x39, 0x39, 0x39, 0x38, 0x39, 0x39, 0x39, - }; - assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x07); - break; - } - case ASM_ADDSS: - assemblerrm(&v->instr, 0xf3, 0x01000f58, 1); - break; - case ASM_ADDSD: - assemblerrm(&v->instr, 0xf2, 0x01000f58, 1); - break; - case ASM_DIV: - assembledivmulneg(&v->instr, 0x06); - break; - case ASM_IDIV: - assembledivmulneg(&v->instr, 0x07); - break; - case ASM_DIVSD: - assemblerrm(&v->instr, 0xf2, 0x01000f5e, 1); - break; - case ASM_DIVSS: - assemblerrm(&v->instr, 0xf3, 0x01000f5e, 1); - break; - case ASM_MUL: - assembledivmulneg(&v->instr, 0x04); - break; - case ASM_MULSD: - assemblerrm(&v->instr, 0xf2, 0x01000f59, 1); - break; - case ASM_MULSS: - assemblerrm(&v->instr, 0xf3, 0x01000f59, 1); - break; - case ASM_IMUL: - assembleimul(&v->instr); - break; - case ASM_NEG: - assembledivmulneg(&v->instr, 0x03); - break; - case ASM_OR: { - static uint8_t variant2op[24] = { - 0x0c, 0x0d, 0x0d, 0x0d, 0x80, 0x81, 0x81, 0x81, - 0x80, 0x81, 0x81, 0x81, 0x0a, 0x0b, 0x0b, 0x0b, - 0x08, 0x09, 0x09, 0x09, 0x08, 0x09, 0x09, 0x09, - }; - assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x01); - break; - } - case ASM_PXOR: - assemblerrm(&v->instr, 0x66, 0x01000fef, 1); - break; - case ASM_SET: - assembleset(&v->instr); - break; - case ASM_SAL: - /* fallthrough */ - case ASM_SHL: - assembleshift(&v->instr, 0x04); - break; - case ASM_SAR: - assembleshift(&v->instr, 0x07); - break; - case ASM_SHR: - assembleshift(&v->instr, 0x05); - break; - case ASM_SUB: { - static uint8_t variant2op[24] = { - 0x2c, 0x2d, 0x2d, 0x2d, 0x80, 0x81, 0x81, 0x81, - 0x80, 0x81, 0x81, 0x81, 0x2a, 0x2b, 0x2b, 0x2b, - 0x28, 0x29, 0x29, 0x29, 0x28, 0x29, 0x29, 0x29, - }; - assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x05); + break; } - case ASM_SUBSS: - assemblerrm(&v->instr, 0xf3, 0x01000f5c, 1); - break; - case ASM_SUBSD: - assemblerrm(&v->instr, 0xf2, 0x01000f5c, 1); - break; - case ASM_TEST: - assembletest(&v->instr); - break; - case ASM_UCOMISD: - assemblerrm(&v->instr, 0x66, 0x01000f2e, 1); - break; - case ASM_UCOMISS: - assemblerrm(&v->instr, -1, 0x01000f2e, 1); - break; - case ASM_XORPD: - assemblerrm(&v->instr, 0x66, 0x01000f57, 1); - break; - case ASM_XORPS: - assemblerrm(&v->instr, -1, 0x01000f57, 1); - break; - case ASM_XOR: { - static uint8_t variant2op[24] = { - 0x34, 0x35, 0x35, 0x35, 0x80, 0x81, 0x81, 0x81, - 0x80, 0x81, 0x81, 0x81, 0x32, 0x33, 0x33, 0x33, - 0x30, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x31, - }; - assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x06); + case ASM_CALL: + assemblecall(&v->call); break; - } - case ASM_XCHG: { - assemblexchg(&v->instr); + case ASM_JMP: + assemblejmp(&v->jmp); break; - } default: lfatal("assemble: unexpected kind: %d", v->kind); } @@ -47,7 +47,7 @@ typedef enum { ASM_IMM, ASM_STRING, ASM_MEMARG, - // Directives + // Directives. ASM_DIR_GLOBL, ASM_DIR_SECTION, ASM_DIR_ASCII, @@ -60,61 +60,10 @@ typedef enum { ASM_DIR_INT, ASM_DIR_QUAD, ASM_DIR_BALIGN, - // Instructions - ASM_NOP, - ASM_RET, - ASM_PUSH, - ASM_POP, + // Instructions. ASM_CALL, - ASM_CLTD, - ASM_CQTO, ASM_JMP, - ASM_LEAVE, - ASM_ADD, - ASM_ADDSS, - ASM_ADDSD, - ASM_AND, - ASM_CMP, - ASM_CVTSS2SD, - ASM_CVTSD2SS, - ASM_CVTSI2SD, - ASM_CVTSI2SS, - ASM_CVTTSD2SI, - ASM_CVTTSS2SI, - ASM_DIV, - ASM_DIVSS, - ASM_DIVSD, - ASM_IDIV, - ASM_LEA, - ASM_MUL, - ASM_MULSD, - ASM_MULSS, - ASM_IMUL, - ASM_MOV, - ASM_MOVAPS, - ASM_MOVQ, - ASM_MOVSD, - ASM_MOVSS, - ASM_MOVSX, - ASM_MOVZX, - ASM_NEG, - ASM_OR, - ASM_PXOR, - ASM_SAL, - ASM_SAR, - ASM_SET, - ASM_SHL, - ASM_SHR, - ASM_SUB, - ASM_SUBSS, - ASM_SUBSD, - ASM_TEST, - ASM_UCOMISD, - ASM_UCOMISS, - ASM_XCHG, - ASM_XOR, - ASM_XORPD, - ASM_XORPS, + ASM_INSTR, // Registers, order matters. ASM_REG_BEGIN, @@ -303,9 +252,43 @@ typedef struct Jmp { const char *target; } Jmp; +/* Rex opcode prefix. */ +typedef struct Rex { + uint8_t required : 1; + uint8_t w : 1; + uint8_t r : 1; + uint8_t x : 1; + uint8_t b : 1; +} Rex; + +/* Various classes of instruction encoding. + The *2 variants just have operands swapped. */ +typedef enum Encoder { + ENCODER_OP, + ENCODER_OPREG, + ENCODER_OPMEM, + ENCODER_R, + ENCODER_RIMM, + ENCODER_IMM, + ENCODER_IMMMEM, + ENCODER_IMMREG, + ENCODER_MEMREG, + ENCODER_MEMREG2, + ENCODER_REGMEM, + ENCODER_REGMEM2, + ENCODER_REGREG, + ENCODER_REGREG2, + ENCODER_IMMREGREG2, + ENCODER_IMMMEMREG, +} Encoder; + typedef struct Instr { AsmKind kind; - uint32_t variant; + Encoder encoder; + Rex rex; + uint32_t fixedreg; + int32_t opcode; + int32_t prefix; const Parsev *arg1; const Parsev *arg2; const Parsev *arg3; @@ -86,24 +86,135 @@ static String decodestring(char *s) { return (String){.kind = ASM_STRING, .len = len, .data = data}; } -#define INSTR1(V, A1) \ +static int needsmovabs(Imm *imm) { + int64_t mask, maskedc; + + if (imm->v.l) + return 1; + + mask = 0xffffffff80000000; + maskedc = (uint64_t)imm->v.c & mask; + return (maskedc != mask && maskedc != 0); +} + +#define OP(OPCODE) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_OP, .prefix = -1, \ + .opcode = OPCODE, \ + } \ + } + +#define OPREG(PREFIX, REX, OPCODE, REG, A1) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_OPREG, .prefix = PREFIX, \ + .rex = REX, .fixedreg = REG, .opcode = OPCODE, .arg1 = internparsev(&A1) \ + } \ + } + +#define OPMEM(PREFIX, REX, OPCODE, REG, A1) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_OPMEM, .prefix = PREFIX, \ + .rex = REX, .fixedreg = REG, .opcode = OPCODE, .arg1 = internparsev(&A1) \ + } \ + } + +#define R(PREFIX, REX, OPCODE, A1) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_R, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .arg1 = internparsev(&A1), \ + } \ + } + +#define IMM(PREFIX, REX, OPCODE, A1, A2) \ (Parsev) { \ .instr = (Instr) { \ - .kind = 0, .variant = V, .arg1 = internparsev(&A1), .arg2 = NULL, \ - .arg3 = NULL \ + .kind = ASM_INSTR, .encoder = ENCODER_IMM, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .arg1 = internparsev(&A1), \ + .arg2 = internparsev(&A2) \ } \ } -#define INSTR2(V, A1, A2) \ + +#define RIMM(PREFIX, REX, OPCODE, A1, A2) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_RIMM, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .arg1 = internparsev(&A1), \ + .arg2 = internparsev(&A2) \ + } \ + } + +#define IMMREG(PREFIX, REX, OPCODE, IMMREG, A1, A2) \ (Parsev) { \ .instr = (Instr) { \ - .kind = 0, .variant = V, .arg1 = internparsev(&A1), \ - .arg2 = internparsev(&A2), .arg3 = NULL \ + .kind = ASM_INSTR, .encoder = ENCODER_IMMREG, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .fixedreg = IMMREG, \ + .arg1 = internparsev(&A1), .arg2 = internparsev(&A2) \ } \ } -#define INSTR3(V, A1, A2, A3) \ + +#define IMMMEM(PREFIX, REX, OPCODE, IMMREG, A1, A2) \ (Parsev) { \ .instr = (Instr) { \ - .kind = 0, .variant = V, .arg1 = internparsev(&A1), \ + .kind = ASM_INSTR, .encoder = ENCODER_IMMMEM, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .fixedreg = IMMREG, \ + .arg1 = internparsev(&A1), .arg2 = internparsev(&A2) \ + } \ + } + +#define REGMEM(PREFIX, REX, OPCODE, A1, A2) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_REGMEM, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .arg1 = internparsev(&A1), \ + .arg2 = internparsev(&A2) \ + } \ + } + +#define MEMREG(PREFIX, REX, OPCODE, A1, A2) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_MEMREG, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .arg1 = internparsev(&A1), \ + .arg2 = internparsev(&A2) \ + } \ + } + +#define REGREG(PREFIX, REX, OPCODE, A1, A2) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_REGREG, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .arg1 = internparsev(&A1), \ + .arg2 = internparsev(&A2) \ + } \ + } + +#define REGREG2(PREFIX, REX, OPCODE, A1, A2) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_REGREG2, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .arg1 = internparsev(&A1), \ + .arg2 = internparsev(&A2) \ + } \ + } + +#define IMMREGREG2(PREFIX, REX, OPCODE, A1, A2, A3) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_IMMREGREG2, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .arg1 = internparsev(&A1), \ + .arg2 = internparsev(&A2), .arg3 = internparsev(&A3) \ + } \ + } + +#define IMMMEMREG(PREFIX, REX, OPCODE, A1, A2, A3) \ + (Parsev) { \ + .instr = (Instr) { \ + .kind = ASM_INSTR, .encoder = ENCODER_IMMMEMREG, .prefix = PREFIX, \ + .opcode = OPCODE, .rex = REX, .arg1 = internparsev(&A1), \ .arg2 = internparsev(&A2), .arg3 = internparsev(&A3) \ } \ } @@ -111,6 +222,12 @@ static String decodestring(char *s) { #define REG(K) \ (Parsev) { .kind = ASM_##K } +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, +}; + #define YYSTYPE Parsev #define YY_CTX_LOCAL #define YY_CTX_MEMBERS Parsev v; diff --git a/test/test.sh b/test/test.sh index 7b0e41c..abe404a 100644 --- a/test/test.sh +++ b/test/test.sh @@ -31,6 +31,9 @@ t () { } # Various regression tests first. +t "movss %xmm15,-0x128(%rbp)" +t "movaps -0x38(%rbp),%xmm15" +t "movsd -0x38(%rbp),%xmm15" t "xchgq %r13, %rax" t "movl \$1000, %r8d" t "movb %sil, (%rdi)" @@ -42,6 +45,7 @@ t "callq *%r10" t "movb %r11b, (%rsi, %r12, 1)" + for r in rax r10 do for x in xmm0 xmm13 |
