diff options
| author | Andrew Chambers <[email protected]> | 2021-10-09 23:45:16 +1300 |
|---|---|---|
| committer | Andrew Chambers <[email protected]> | 2021-10-09 23:45:16 +1300 |
| commit | 5ccab989e58d0bb2d643dfaec51dbea0734ce05f (patch) | |
| tree | 3420b6192145b819c9832c50787b94eab856368b | |
| parent | a3edd52b53b236a2b88049e634981e8dc7b0bc4d (diff) | |
Add div/idiv.
| -rw-r--r-- | asm.peg | 22 | ||||
| -rw-r--r-- | main.c | 32 | ||||
| -rw-r--r-- | minias.h | 2 | ||||
| -rw-r--r-- | test/test.sh | 7 |
4 files changed, 62 insertions, 1 deletions
@@ -58,6 +58,8 @@ instr = | i:jmp { $$ = i; } | i:add { $$ = i; } | i:and { $$ = i; } + | i:div { $$ = i; } + | i:idiv { $$ = i; } | i:lea { $$ = i; } | i:mov { $$ = i; } | i:or { $$ = i; } @@ -92,6 +94,24 @@ lea = | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR2(2, s, d); } ) { $$.instr2.kind = ASM_LEA; } +div = "div" ( + args:div-opargs { $$ = args; } +) { $$.instr2.kind = ASM_DIV; } + +idiv = "idiv" ( + args:div-opargs { $$ = args; } +) { $$.instr2.kind = ASM_IDIV; } + +div-opargs = + 'b' ws a:m { $$ = INSTR1(0, a); } + | 'w' ws a:m { $$ = INSTR1(1, a); } + | 'l' ws a:m { $$ = INSTR1(2, a); } + | 'q' ws a:m { $$ = 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); } + imm-rm-opargs = 'b' ws s:imm8 ws? ',' ws? d:m { $$ = INSTR2(0, s, d); } | 'w' ws s:imm16 ws? ',' ws? d:m { $$ = INSTR2(1, s, d); } @@ -245,7 +265,7 @@ r64 = | "%r14" ![lwb] { $$ = REG(ASM_R14); } | "%r15" ![lwb] { $$ = REG(ASM_R15); } -# We disallow newlines in our strings, it is simpler for error messages. +# We disallow newlines in our strings, it is simpler for lineno tracking. string = '"' <(string-escape | ( ! '\n' ! '\\' !'"' .))*> '"' { $$.string = decodestring(yytext); } @@ -528,6 +528,30 @@ static void assemblemov(Instr2 *mov) { } } +static void assemblediv(Instr1 *div, uint8_t reg) { + uint8_t opcode, opsz, rex, mod, rm; + + opsz = 1 << (div->variant % 4); + opcode = opsz == 1 ? 0xf6 : 0xf7; + + if (div->variant < 4) { + if (div->arg->memarg.reg == ASM_RIP) { + assembleriprel(&div->arg->memarg, opsz == 8, opcode, reg, opsz); + } else { + assemblemem(&div->arg->memarg, opsz == 8, opcode, reg, opsz); + } + } else { + mod = 0x03; + rm = regbits(div->arg->kind); + if (opsz == 2) + sb(0x66); + rex = rexbyte(isreg64(div->arg->kind), reg & (1 << 3), 0, rm & (1 << 3)); + if (rex != rexbyte(0, 0, 0, 0)) + sb(rex); + sb2(opcode, modregrm(0x03, reg, rm)); + } +} + static void assemble(void) { Symbol *sym; Parsev *v; @@ -669,6 +693,14 @@ static void assemble(void) { assemblebasicop(&v->instr2, variant2op[v->instr2.variant], 0x04); break; } + case ASM_DIV: { + assemblediv(&v->instr1, 0x06); + break; + } + case ASM_IDIV: { + assemblediv(&v->instr1, 0x07); + break; + } case ASM_OR: { static uint8_t variant2op[24] = { 0x0c, 0x0d, 0x0d, 0x0d, 0x80, 0x81, 0x81, 0x81, @@ -64,6 +64,8 @@ typedef enum { ASM_LEAVE, ASM_ADD, ASM_AND, + ASM_DIV, + ASM_IDIV, ASM_LEA, ASM_MOV, ASM_MOVSX, diff --git a/test/test.sh b/test/test.sh index cf5660b..05d40bf 100644 --- a/test/test.sh +++ b/test/test.sh @@ -30,6 +30,13 @@ t () { echo -n "." } +t "div %rax" +t "divq (%rax)" +t "divq (%rip)" +t "idiv %rax" +t "idivq (%rax)" +t "idivq (%rip)" + t "pushq (%r9)" t "pushq %r9" t "pushq %rax" |
