aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asm.peg890
-rw-r--r--main.c765
-rw-r--r--minias.h93
-rw-r--r--parse.c133
-rw-r--r--test/test.sh4
5 files changed, 912 insertions, 973 deletions
diff --git a/asm.peg b/asm.peg
index 88f5324..a284c1b 100644
--- a/asm.peg
+++ b/asm.peg
@@ -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
diff --git a/main.c b/main.c
index c444cc8..3c8f6ee 100644
--- a/main.c
+++ b/main.c
@@ -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);
}
diff --git a/minias.h b/minias.h
index 5914c1b..2d6fd83 100644
--- a/minias.h
+++ b/minias.h
@@ -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;
diff --git a/parse.c b/parse.c
index 1634bb6..8699384 100644
--- a/parse.c
+++ b/parse.c
@@ -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