aboutsummaryrefslogtreecommitdiff
path: root/src/as_codegen.c
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-03-26 19:10:25 +0800
committerMistivia <i@mistivia.com>2025-03-26 19:10:25 +0800
commit312716a295626f2b60b41777728c7f220fee843d (patch)
tree5747882b5a662c29a734dc66486035f93fe42990 /src/as_codegen.c
parentb2be728e0cf6f024ecc524b28806012c53ca5206 (diff)
finish fvm-as
Diffstat (limited to 'src/as_codegen.c')
-rw-r--r--src/as_codegen.c112
1 files changed, 94 insertions, 18 deletions
diff --git a/src/as_codegen.c b/src/as_codegen.c
index 5c1d60e..678733f 100644
--- a/src/as_codegen.c
+++ b/src/as_codegen.c
@@ -1,12 +1,38 @@
#include "as_codegen.h"
+
+#include <string.h>
+
#include "as_analyzer.h"
#include "as_op.h"
#include "fvm.h"
#include "utils.h"
-bytearray *new_bytearray(allocator *alct);
-void bytearray_emit8(bytearray *self, int8_t data);
-void bytearray_emit64(bytearray *self, int64_t data);
+bytearray *new_bytearray(allocator *alct) {
+ bytearray* arr = allocate(alct, sizeof(bytearray));
+ arr->len = 0;
+ arr->cap = 16;
+ arr->buf = allocate(alct, 16);
+ arr->alct = alct;
+ return arr;
+}
+
+void bytearray_emit8(bytearray *arr, int8_t data) {
+ if (arr->len == arr->cap) {
+ void* oldbuf = arr->buf;
+ arr->buf = allocate(arr->alct, 2 * arr->cap);
+ memcpy(arr->buf, oldbuf, arr->cap);
+ arr->cap = arr->cap * 2;
+ }
+ arr->buf[arr->len] = data;
+ arr->len++;
+}
+
+void bytearray_emit64(bytearray *self, int64_t data) {
+ int8_t* ptr = (int8_t*)&data;
+ for (int i = 0; i < 8; i++) {
+ bytearray_emit8(self, ptr[i]);
+ }
+}
int8_t op_bytecode(op op) {
@@ -43,6 +69,12 @@ int8_t op_bytecode(op op) {
if (op == OP_XOR) return (int8_t)FVM_OP_XOR;
if (op == OP_INVERT) return (int8_t)FVM_OP_INVERT;
+ if (op == OP_JNZ) return (int8_t)FVM_OP_JNZ;
+ if (op == OP_JZ) return (int8_t)FVM_OP_JZ;
+ if (op == OP_JMP) return (int8_t)FVM_OP_JMP;
+ if (op == OP_CALL) return (int8_t)FVM_OP_CALL;
+ if (op == OP_SYSCALL) return (int8_t)FVM_OP_SYSCALL;
+
if (op == OP_GT) return (int8_t)FVM_OP_GT;
if (op == OP_LT) return (int8_t)FVM_OP_LT;
if (op == OP_GE) return (int8_t)FVM_OP_GE;
@@ -86,22 +118,66 @@ result codegen(allocator* alct, prog* prog, sym_table tbl) {
int8_t code = op_bytecode(op);
bytearray_emit8(output, code);
offset += 1;
- } else if (op_size(op) == 9) {
- if (op == OP_IMM) {
- if (instr->tag_name != NULL || instr->arg == NULL) {
- return err(safe_sprintf(alct, "line %d: invalid instruction format. (imm)\n", instr->lineno));
- }
- bytearray_emit8(output, FVM_OP_IMM);
- bytearray_emit64(output, instr->arg->ival);
- offset += 9;
- } else if (op == OP_REL) {
- if (instr->tag_name == NULL || instr->arg != NULL) {
- return err(safe_sprintf(alct, "line %d: invalid instruction format. (rel)\n", instr->lineno));
- }
- bytearray_emit8(output, FVM_OP_IMM);
+ } else if (op == OP_IMM) {
+ if (instr->tag_name != NULL || instr->arg == NULL) {
+ return err(safe_sprintf(alct, "line %d: invalid instruction format. (imm)\n", instr->lineno));
}
- } else if (op_size(op) == 10) {
-
+ bytearray_emit8(output, FVM_OP_IMM);
+ bytearray_emit64(output, instr->arg->ival);
+ offset += 9;
+ } else if (op == OP_REL) {
+ if (instr->tag_name == NULL || instr->arg != NULL) {
+ return err(safe_sprintf(alct, "line %d: invalid instruction format. (rel)\n", instr->lineno));
+ }
+ bytearray_emit8(output, FVM_OP_IMM);
+ int target_offset = sym_table_lookup(&tbl, instr->tag_name);
+ if (target_offset == -1) {
+ return err(safe_sprintf(alct, "line %d: unknown tag: %s", instr->lineno, instr->tag_name));
+ }
+ bytearray_emit64(output, target_offset - (offset + 9));
+ bytearray_emit8(output, FVM_OP_PC);
+ bytearray_emit8(output, FVM_OP_ADD);
+ offset += 11;
+ } else if (op == OP_LDARG) {
+ if (instr->tag_name != NULL || instr->arg == NULL) {
+ return err(safe_sprintf(alct, "line %d: invalid instruction format. (ldarg)\n", instr->lineno));
+ }
+ bytearray_emit8(output, FVM_OP_IMM);
+ bytearray_emit64(output, 8 * (instr->arg->ival + 2));
+ bytearray_emit8(output, FVM_OP_BP);
+ bytearray_emit8(output, FVM_OP_ADD);
+ bytearray_emit8(output, FVM_OP_LD);
+ offset += 12;
+ } else if (op == OP_STARG) {
+ if (instr->tag_name != NULL || instr->arg == NULL) {
+ return err(safe_sprintf(alct, "line %d: invalid instruction format. (starg)\n", instr->lineno));
+ }
+ bytearray_emit8(output, FVM_OP_IMM);
+ bytearray_emit64(output, 8 * (instr->arg->ival + 2));
+ bytearray_emit8(output, FVM_OP_BP);
+ bytearray_emit8(output, FVM_OP_ADD);
+ bytearray_emit8(output, FVM_OP_ST);
+ offset += 12;
+ } else if (op == OP_LDVAR) {
+ if (instr->tag_name != NULL || instr->arg == NULL) {
+ return err(safe_sprintf(alct, "line %d: invalid instruction format. (ldvar)\n", instr->lineno));
+ }
+ bytearray_emit8(output, FVM_OP_IMM);
+ bytearray_emit64(output, 8 * (-instr->arg->ival - 1));
+ bytearray_emit8(output, FVM_OP_BP);
+ bytearray_emit8(output, FVM_OP_ADD);
+ bytearray_emit8(output, FVM_OP_LD);
+ offset += 12;
+ } else if (op == OP_STVAR) {
+ if (instr->tag_name != NULL || instr->arg == NULL) {
+ return err(safe_sprintf(alct, "line %d: invalid instruction format. (stvar)\n", instr->lineno));
+ }
+ bytearray_emit8(output, FVM_OP_IMM);
+ bytearray_emit64(output, 8 * (-instr->arg->ival - 2));
+ bytearray_emit8(output, FVM_OP_BP);
+ bytearray_emit8(output, FVM_OP_ADD);
+ bytearray_emit8(output, FVM_OP_ST);
+ offset += 12;
}
}
return ok(output);