nooc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/nooc
Log | Files | Refs | LICENSE

commit 738b2e07d43b8d4674d9381dfe6e7ec8aaea6ec3
parent ba722cd97189940089a85da342bf952cd56abcec
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Tue, 23 Nov 2021 16:46:16 -0600

functional binary expression evaluation

We now have primitive, unoptimized register allocation. This lets
us correctly evaluate binary expressions, at least if there aren't
too many terms. If there are too many terms we will run out of
registers, and the compiler will error out.

Diffstat:
Mmain.c | 14+++++++++-----
Mprog.nc | 2+-
Mx64.c | 43+++++++++++++++++++++++++++++++++++++++++++
Mx64.h | 6++++++
4 files changed, 59 insertions(+), 6 deletions(-)

diff --git a/main.c b/main.c @@ -303,7 +303,6 @@ parse(struct token *tok) size_t genexpr(char *buf, size_t idx, enum reg reg) { - // FIXME: this doesn't work for binary expressions size_t len = 0; char *ptr = buf; struct expr *expr = &exprs.data[idx]; @@ -323,10 +322,12 @@ genexpr(char *buf, size_t idx, enum reg reg) } else if (expr->kind == EXPR_BINARY) { switch (expr->d.op) { case OP_PLUS: { - struct expr *left = &exprs.data[expr->left]; - struct expr *right = &exprs.data[expr->right]; - len = mov_r_imm(ptr ? ptr + len : ptr, reg, left->d.v.v.val); - len += add_r_imm(ptr ? ptr + len : ptr, reg, right->d.v.v.val); + len += genexpr(ptr ? ptr + len : ptr, expr->left, reg); + enum reg rreg = getreg(); + len += genexpr(ptr ? ptr + len : ptr, expr->right, rreg); + + len += add_r64_r64(ptr ? ptr + len : ptr, reg, rreg); + freereg(rreg); break; } default: @@ -355,9 +356,12 @@ gensyscall(char *buf, struct fparams *params) // encoding for argument registers in ABI order for (int i = 0; i < params->len; i++) { + used_reg |= (1 << abi_arg[i]); len += genexpr(ptr ? ptr + len : ptr, params->data[i], abi_arg[i]); } + clearreg(); + if (buf) { char syscall[] = {0x0f, 0x05}; memcpy(ptr + len, syscall, 2); diff --git a/prog.nc b/prog.nc @@ -3,6 +3,6 @@ stdout = 0 exit = 60 len1 = 11 len2 = 6 -syscall(write, stdout, "hello world", len1) +syscall(write, + + 0 1 + 0 1, "hello world", + 1 + 2 + 3 + 4 1) syscall(write, stdout, " world", len2) syscall(exit, 0) diff --git a/x64.c b/x64.c @@ -1,9 +1,38 @@ +#include <assert.h> #include <stddef.h> #include <stdint.h> #include <string.h> + #include "x64.h" +#include "util.h" char abi_arg[] = {RAX, RDI, RSI, RDX, R10, R8, R9}; +unsigned short used_reg; + +void +clearreg() +{ + used_reg = 0; +} + +enum reg +getreg() +{ + for (int i = 0; i < 16; i++) { + if (!(used_reg & (1 << i))) { + used_reg |= (1 << i); + return i; + } + } + + error("out of registers!"); +} + +void +freereg(enum reg reg) +{ + used_reg &= ~(1 << reg); +} size_t add_r_imm(char *buf, enum reg reg, uint64_t imm) @@ -60,3 +89,17 @@ mov_r64_m64(char *buf, enum reg reg, uint64_t addr) return 8; } + +size_t +add_r64_r64(char *buf, enum reg reg1, enum reg reg2) +{ + uint8_t mov[] = {0x48, 0x03}; + uint8_t op = (MOD_DIRECT << 6) | (reg1 << 3) | reg2; + if (buf) { + memcpy(buf, mov, 2); + buf += 2; + *(buf++) = op; + } + + return 3; +} diff --git a/x64.h b/x64.h @@ -25,7 +25,13 @@ enum mod { }; extern char abi_arg[]; +extern unsigned short used_reg; + +void clearreg(); +enum reg getreg(); +void freereg(enum reg reg); size_t add_r_imm(char *buf, enum reg reg, uint64_t imm); size_t mov_r_imm(char *buf, enum reg reg, uint64_t imm); size_t mov_r64_m64(char *buf, enum reg reg, uint64_t addr); +size_t add_r64_r64(char *buf, enum reg reg1, enum reg reg2);