aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chambers <[email protected]>2021-10-09 23:45:16 +1300
committerAndrew Chambers <[email protected]>2021-10-09 23:45:16 +1300
commit5ccab989e58d0bb2d643dfaec51dbea0734ce05f (patch)
tree3420b6192145b819c9832c50787b94eab856368b
parenta3edd52b53b236a2b88049e634981e8dc7b0bc4d (diff)
Add div/idiv.
-rw-r--r--asm.peg22
-rw-r--r--main.c32
-rw-r--r--minias.h2
-rw-r--r--test/test.sh7
4 files changed, 62 insertions, 1 deletions
diff --git a/asm.peg b/asm.peg
index 568510e..2396ae8 100644
--- a/asm.peg
+++ b/asm.peg
@@ -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); }
diff --git a/main.c b/main.c
index 8e3da68..a7d0f4c 100644
--- a/main.c
+++ b/main.c
@@ -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,
diff --git a/minias.h b/minias.h
index b9fa886..b9bce6b 100644
--- a/minias.h
+++ b/minias.h
@@ -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"