diff --git a/backend/src/vm.c b/backend/src/vm.c deleted file mode 100644 index 8cdb31a..0000000 --- a/backend/src/vm.c +++ /dev/null @@ -1,899 +0,0 @@ -#include "vm.h" -#include "util.h" -#include -#include -#include - -void vm_construct(VM* vm) -{ - size_t files_capacity = 64; - FsFile* files = malloc(sizeof(FsFile) * files_capacity); - - *vm = (VM) { - .files = files, - .files_size = 0, - .files_capacity = files_capacity, - .next_file_id = 0, - }; - - vm->files[vm->files_size++] = (FsFile) { .id = 0, .fp = stdin }; - vm->files[vm->files_size++] = (FsFile) { .id = 1, .fp = stdout }; - vm->files[vm->files_size++] = (FsFile) { .id = 2, .fp = stderr }; - vm->next_file_id += 3; -} - -void vm_destroy(VM* vm) -{ - (void)vm; -} - -ALWAYS_INLINE static inline Op line_op(uint32_t line) -{ - return line & 0xff; -} - -ALWAYS_INLINE static inline Reg line_dst(uint32_t line) -{ - return line >> 8 & 0xff; -} - -ALWAYS_INLINE static inline Reg line_src_right(uint32_t line) -{ - return line >> 16 & 0xff; -} - -ALWAYS_INLINE static inline Reg line_src_left(uint32_t line) -{ - return line >> 24 & 0xff; -} - -ALWAYS_INLINE static inline uint32_t eat_i32(const uint32_t** pc) -{ - uint32_t imm = **pc; - ++*pc; - return imm; -} - -ALWAYS_INLINE static inline uint64_t eat_i64(const uint32_t** pc) -{ - uint64_t imm = **pc; - ++*pc; - imm &= (uint64_t)**pc << 32; - ++*pc; - return imm; -} - -ALWAYS_INLINE static inline double eat_f64(const uint32_t** pc) -{ - return (double)eat_i64(pc); -} - -int vm_run(VM* vm, const uint32_t* program) -{ - (void)vm; - - Regs regs = { - .iregs = { 0 }, - .fregs = { 0.0 }, - }; - - uint64_t* const stack = malloc(STACK_SIZE * sizeof(uint64_t)); - Call* const call_stack_base = malloc(CALL_STACK_SIZE * sizeof(Call)); - - Call* call_stack = call_stack_base; - - const uint32_t* program_base = program; - const uint32_t* pc = program_base; - - uint64_t* sb = stack; - uint64_t* sp = sb; - - for (;;) { - uint32_t line = *pc; - Op op = line_op(line); - ++pc; - switch (op) { - case Op_Nop: { - break; - } - case Op_Halt: { - goto halt_program; - } - case Op_Builtin: { - break; - } - - // --- - - case Op_Call: { - Reg reg = line_src_left(line); - *call_stack = (Call) { .caller_sb = sb, .return_ptr = pc + 1 }; - ++call_stack; - pc = program_base + regs.iregs[reg]; - break; - } - case Op_CallI: { - uint32_t ptr = eat_i32(&pc); - *call_stack = (Call) { .caller_sb = sb, .return_ptr = pc + 1 }; - ++call_stack; - pc = program_base + ptr; - break; - } - case Op_Ret: { - --call_stack; - sb = call_stack->caller_sb; - pc = call_stack->return_ptr; - break; - } - case Op_Alloca: { - uint32_t size = eat_i32(&pc); - sp += size; - break; - } - - // --- - - case Op_Jmp: { - uint32_t ptr = eat_i32(&pc); - pc = program_base + ptr; - break; - } - case Op_Jnz: { - uint32_t ptr = eat_i32(&pc); - if (regs.iregs[line_src_right(line)] != 0) { - pc = program_base + ptr; - } else { - ++pc; - } - break; - } - case Op_Jz: { - Reg reg = line_src_left(line); - uint32_t ptr = eat_i32(&pc); - if (regs.iregs[reg] == 0) { - pc = program_base + ptr; - } else { - ++pc; - } - break; - } - - // --- - - case Op_Load8: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - regs.iregs[dst] = *(uint8_t*)regs.iregs[src]; - break; - } - case Op_LoadI8: { - Reg dst = line_dst(line); - uint64_t addr = eat_i64(&pc); - regs.iregs[dst] = *(uint8_t*)addr; - break; - } - case Op_LoadA8: { - Reg dst = line_dst(line); - Reg base = line_src_left(line); - Reg offset = line_src_right(line); - uint32_t incr = eat_i32(&pc); - uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr; - regs.iregs[dst] = *(uint8_t*)(addr); - break; - } - case Op_Load16: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - regs.iregs[dst] = *(uint16_t*)regs.iregs[src]; - break; - } - case Op_LoadI16: { - Reg dst = line_dst(line); - uint64_t addr = eat_i64(&pc); - regs.iregs[dst] = *(uint16_t*)addr; - break; - } - case Op_LoadA16: { - Reg dst = line_dst(line); - Reg base = line_src_left(line); - Reg offset = line_src_right(line); - uint32_t incr = eat_i32(&pc); - uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr; - regs.iregs[dst] = *(uint16_t*)(addr); - break; - } - case Op_Load32: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - regs.iregs[dst] = *(uint32_t*)regs.iregs[src]; - break; - } - case Op_LoadI32: { - Reg dst = line_dst(line); - uint64_t addr = eat_i64(&pc); - regs.iregs[dst] = *(uint32_t*)addr; - break; - } - case Op_LoadA32: { - Reg dst = line_dst(line); - Reg base = line_src_left(line); - Reg offset = line_src_right(line); - uint32_t incr = eat_i32(&pc); - uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr; - regs.iregs[dst] = *(uint32_t*)(addr); - break; - } - case Op_Load64: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - regs.iregs[dst] = *(uint64_t*)regs.iregs[src]; - break; - } - case Op_LoadI64: { - Reg dst = line_dst(line); - uint64_t addr = eat_i64(&pc); - regs.iregs[dst] = *(uint64_t*)addr; - break; - } - case Op_LoadA64: { - Reg dst = line_dst(line); - Reg base = line_src_left(line); - Reg offset = line_src_right(line); - uint32_t incr = eat_i32(&pc); - uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr; - regs.iregs[dst] = *(uint64_t*)(addr); - break; - } - case Op_LoadF: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - regs.fregs[dst] = *(double*)regs.iregs[src]; - break; - } - case Op_LoadIF: { - Reg dst = line_dst(line); - uint64_t addr = eat_i64(&pc); - regs.fregs[dst] = *(double*)addr; - break; - } - case Op_LoadAF: { - Reg dst = line_dst(line); - Reg base = line_src_left(line); - Reg offset = line_src_right(line); - uint32_t incr = eat_i32(&pc); - regs.fregs[dst] - = *(double*)(regs.iregs[base] + regs.iregs[offset] * incr); - break; - } - - // --- - - case Op_Store8: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - *(uint8_t*)regs.iregs[dst] = (uint8_t)regs.iregs[src]; - break; - } - case Op_StoreA8: { - Reg src = line_src_left(line); - Reg base = line_dst(line); - Reg offset = line_src_right(line); - uint32_t incr = eat_i32(&pc); - uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr; - *(uint8_t*)addr = (uint8_t)regs.iregs[src]; - break; - } - case Op_Store16: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - *(uint16_t*)regs.iregs[dst] = (uint16_t)regs.iregs[src]; - break; - } - case Op_StoreA16: { - Reg src = line_src_left(line); - Reg base = line_dst(line); - Reg offset = line_src_right(line); - uint32_t incr = eat_i32(&pc); - uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr; - *(uint16_t*)addr = (uint16_t)regs.iregs[src]; - break; - } - case Op_Store32: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - *(uint32_t*)regs.iregs[dst] = (uint32_t)regs.iregs[src]; - break; - } - case Op_StoreA32: { - Reg src = line_src_left(line); - Reg base = line_dst(line); - Reg offset = line_src_right(line); - uint32_t incr = eat_i32(&pc); - uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr; - *(uint32_t*)addr = (uint32_t)regs.iregs[src]; - break; - } - case Op_Store64: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - *(uint64_t*)regs.iregs[dst] = regs.iregs[src]; - break; - } - case Op_StoreA64: { - Reg src = line_src_left(line); - Reg base = line_dst(line); - Reg offset = line_src_right(line); - uint32_t incr = eat_i32(&pc); - uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr; - *(uint64_t*)addr = regs.iregs[src]; - break; - } - case Op_StoreF: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - *(double*)regs.iregs[dst] = regs.fregs[src]; - break; - } - case Op_StoreAF: { - Reg src = line_src_left(line); - Reg base = line_dst(line); - Reg offset = line_src_right(line); - uint32_t incr = eat_i32(&pc); - uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr; - *(double*)addr = regs.fregs[src]; - break; - } - - // --- - - case Op_LoadImm32: { - Reg dst = line_dst(line); - regs.iregs[dst] = eat_i32(&pc); - break; - } - case Op_LoadImm64: { - Reg dst = line_dst(line); - regs.iregs[dst] = eat_i64(&pc); - break; - } - case Op_LoadImmF: { - Reg dst = line_dst(line); - regs.fregs[dst] = eat_f64(&pc); - break; - } - case Op_LoadSb: { - Reg dst = line_dst(line); - regs.iregs[dst] = (uint64_t)sb; - break; - } - case Op_LoadSp: { - Reg dst = line_dst(line); - regs.iregs[dst] = (uint64_t)sp; - break; - } - - // --- - - case Op_MovII: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - regs.iregs[dst] = regs.iregs[src]; - break; - } - case Op_MovIF: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - regs.fregs[dst] = (double)regs.iregs[src]; - break; - } - case Op_MovFI: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - regs.iregs[dst] = (uint64_t)regs.fregs[src]; - break; - } - case Op_MovFF: { - Reg dst = line_dst(line); - Reg src = line_src_left(line); - regs.fregs[dst] = regs.fregs[src]; - break; - } - - case Op_Push: { - Reg src = line_src_left(line); - *sp = regs.iregs[src]; - ++sp; - break; - } - case Op_Pop: { - Reg dst = line_dst(line); - --sp; - regs.iregs[dst] = *sp; - break; - } - - case Op_PushF: { - Reg src = line_src_left(line); - *sp = (uint64_t)regs.fregs[src]; - ++sp; - break; - } - case Op_PopF: { - Reg dst = line_dst(line); - --sp; - regs.fregs[dst] = (double)*sp; - break; - } - - // --- - - case Op_Eq: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] == regs.iregs[right] ? 1 : 0; - break; - } - case Op_Ne: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] != regs.iregs[right] ? 1 : 0; - break; - } - case Op_Lt: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] < regs.iregs[right] ? 1 : 0; - break; - } - case Op_Gt: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] > regs.iregs[right] ? 1 : 0; - break; - } - case Op_Lte: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] <= regs.iregs[right] ? 1 : 0; - break; - } - case Op_Gte: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] >= regs.iregs[right] ? 1 : 0; - break; - } - case Op_And: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] & regs.iregs[right]; - break; - } - case Op_Or: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] | regs.iregs[right]; - break; - } - case Op_Xor: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] ^ regs.iregs[right]; - break; - } - case Op_Add: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] + regs.iregs[right]; - break; - } - case Op_Sub: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] - regs.iregs[right]; - break; - } - case Op_Mul: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] * regs.iregs[right]; - break; - } - case Op_Div: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] / regs.iregs[right]; - break; - } - case Op_Rem: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.iregs[left] / regs.iregs[right]; - break; - } - case Op_IMul: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - int64_t val - = (int64_t)regs.iregs[left] * (int64_t)regs.iregs[right]; - regs.iregs[dst] = (uint64_t)val; - break; - } - case Op_IDiv: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - int64_t val - = (int64_t)regs.iregs[left] / (int64_t)regs.iregs[right]; - regs.iregs[dst] = (uint64_t)val; - break; - } - - // --- - - case Op_EqI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] == right ? 1 : 0; - break; - } - case Op_NeI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] != right ? 1 : 0; - break; - } - case Op_LtI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] < right ? 1 : 0; - break; - } - case Op_GtI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] > right ? 1 : 0; - break; - } - case Op_LteI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] <= right ? 1 : 0; - break; - } - case Op_GteI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] >= right ? 1 : 0; - break; - } - case Op_AndI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] & right; - break; - } - case Op_OrI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] | right; - break; - } - case Op_XorI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] ^ right; - break; - } - case Op_AddI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] + right; - break; - } - case Op_SubI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] - right; - break; - } - case Op_RSubI: { - Reg dst = line_dst(line); - uint64_t left = eat_i32(&pc); - Reg right = line_src_right(line); - regs.iregs[dst] = left - regs.iregs[right]; - break; - } - case Op_MulI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] * right; - break; - } - case Op_DivI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] / right; - break; - } - case Op_RemI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - regs.iregs[dst] = regs.iregs[left] % right; - break; - } - case Op_IMulI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - int64_t val = (int64_t)regs.iregs[left] * (int64_t)right; - regs.iregs[dst] = (uint64_t)val; - break; - } - case Op_IDivI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - uint64_t right = eat_i32(&pc); - int64_t val = (int64_t)regs.iregs[left] / (int64_t)right; - regs.iregs[dst] = (uint64_t)val; - break; - } - - // --- - - case Op_EqF: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.fregs[left] == regs.fregs[right] ? 1 : 0; - break; - } - case Op_NeF: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.fregs[left] != regs.fregs[right] ? 1 : 0; - break; - } - case Op_LtF: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.fregs[left] < regs.fregs[right] ? 1 : 0; - break; - } - case Op_GtF: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.fregs[left] > regs.fregs[right] ? 1 : 0; - break; - } - case Op_LteF: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.fregs[left] <= regs.fregs[right] ? 1 : 0; - break; - } - case Op_GteF: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.iregs[dst] = regs.fregs[left] >= regs.fregs[right] ? 1 : 0; - break; - } - case Op_AddF: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.fregs[dst] = regs.fregs[left] + regs.fregs[right]; - break; - } - case Op_SubF: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.fregs[dst] = regs.fregs[left] - regs.fregs[right]; - break; - } - case Op_MulF: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.fregs[dst] = regs.fregs[left] * regs.fregs[right]; - break; - } - case Op_DivF: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - Reg right = line_src_right(line); - regs.fregs[dst] = regs.fregs[left] / regs.fregs[right]; - break; - } - - // --- - - case Op_EqFI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - double right = eat_f64(&pc); - regs.iregs[dst] = regs.fregs[left] == right ? 1 : 0; - break; - } - case Op_NeFI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - double right = eat_f64(&pc); - regs.iregs[dst] = regs.fregs[left] != right ? 1 : 0; - break; - } - case Op_LtFI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - double right = eat_f64(&pc); - regs.iregs[dst] = regs.fregs[left] < right ? 1 : 0; - break; - } - case Op_GtFI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - double right = eat_f64(&pc); - regs.iregs[dst] = regs.fregs[left] > right ? 1 : 0; - break; - } - case Op_LteFI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - double right = eat_f64(&pc); - regs.iregs[dst] = regs.fregs[left] <= right ? 1 : 0; - break; - } - case Op_GteFI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - double right = eat_f64(&pc); - regs.iregs[dst] = regs.fregs[left] >= right ? 1 : 0; - break; - } - case Op_AddFI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - double right = eat_f64(&pc); - regs.fregs[dst] = regs.fregs[left] + right; - break; - } - case Op_SubFI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - double right = eat_f64(&pc); - regs.fregs[dst] = regs.fregs[left] - right; - break; - } - case Op_RSubFI: { - Reg dst = line_dst(line); - double left = eat_f64(&pc); - Reg right = line_src_right(line); - regs.fregs[dst] = left - regs.fregs[right]; - break; - } - case Op_MulFI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - double right = eat_f64(&pc); - regs.fregs[dst] = regs.fregs[left] * right; - break; - } - case Op_DivFI: { - Reg dst = line_dst(line); - Reg left = line_src_left(line); - double right = eat_f64(&pc); - regs.fregs[dst] = regs.fregs[left] / right; - break; - } - } - } - -halt_program: - free(stack); - free(call_stack_base); - return 0; -} - -int vm_exec_builtin(VM* vm, Builtin builtin, Regs* regs) -{ - MAYBE_UNUSED uint64_t* res = ®s->iregs[0]; - MAYBE_UNUSED uint64_t arg1 = regs->iregs[1]; - MAYBE_UNUSED uint64_t arg2 = regs->iregs[2]; - MAYBE_UNUSED uint64_t arg3 = regs->iregs[3]; - MAYBE_UNUSED uint64_t arg4 = regs->iregs[4]; - - switch (builtin) { - case Builtin_Alloc: { - break; - } - case Builtin_FsOpen: { - uint64_t id = 0; - int r = vm_open_file(vm, &id, (char*)arg1, (char*)arg2); - *res = r == 0 ? 0 : 1; - break; - } - case Builtin_FsClose: { - vm_close_file(vm, arg1); - break; - } - case Builtin_FsWrite: - fwrite((void*)arg2, arg3, 1, vm_file_fp(vm, arg1)); - break; - case Builtin_FsRead: - fread((void*)arg2, arg3, 1, vm_file_fp(vm, arg1)); - break; - case Builtin_FsFlush: - fflush(vm_file_fp(vm, arg1)); - break; - case Builtin_FsEof: - *res = feof(vm_file_fp(vm, arg1)) == EOF ? 1 : 0; - break; - } - return 0; -} - -int vm_open_file(VM* vm, uint64_t* id, const char* path, const char* mode) -{ - FILE* fp = fopen(path, mode); - if (fp == NULL) - return -1; - *id = vm->next_file_id; - ++vm->next_file_id; - vm->files[vm->files_size++] = (FsFile) { *id, fp }; - return 0; -} - -void vm_close_file(VM* vm, uint64_t id) -{ - size_t i = 0; - for (; i < vm->files_size; ++i) - if (vm->files[i].id == id) - break; - if (i == vm->files_size) - return; - for (size_t j = i; j < vm->files_size - 1; ++j) - vm->files[j] = vm->files[j + 1]; -} - -FILE* vm_file_fp(VM* vm, uint64_t id) -{ - for (size_t i = 0; i < vm->files_size; ++i) - if (vm->files[i].id == id) - return vm->files[i].fp; - return NULL; -} diff --git a/backend/src/vm.h b/backend/src/vm.h deleted file mode 100644 index 155a891..0000000 --- a/backend/src/vm.h +++ /dev/null @@ -1,221 +0,0 @@ -#ifndef VM_H -#define VM_H - -#include -#include - -/// Instruction operations. -/// -/// These definitions dictate how instructions should be decoded. -/// -/// `%ireg` is an int or pointer register. -/// `%i32` is a 32-bit immediate int value. -/// `%i64` is a 64-bit immediate int value. -/// -/// `%freg` is a float register. -/// `%f64` is a 64-bit immediate float value. -/// -/// The instruction header is 4 bytes. Usually instruction headers are encoding -/// like this: -/// ``` -/// XX = 1 byte -/// -/// XX XX XX XX -/// ^^ ^^ ^^ ^^ - Op -/// | | | -/// | | ++-- destination register -/// | | -/// | ++-- right/second operand register -/// | -/// ++--- left/first operand register -/// ``` -/// -/// Then immediate values are appended after the header. -/// -/// Immediates are little endian. This means that the smallest byte has the -/// smallest address. Example: take a value like `4660`, convert it to hex -/// `0x1234`, split up in bytes `12 34`, put it into an array `[12, 34]`. This -/// is big endian ie. WRONG. Put the bytes `12 34` into the array in reverse -/// order `[34, 12]`. This is little endiang ie. CORRECT. -/// -typedef enum { - Op_Nop, - Op_Halt, - Op_Builtin, - - Op_Call, - Op_CallI, - Op_Ret, - Op_Alloca, - - Op_Jmp, - Op_Jnz, - Op_Jz, - - Op_Load8, - Op_LoadI8, - Op_LoadA8, - Op_Load16, - Op_LoadI16, - Op_LoadA16, - Op_Load32, - Op_LoadI32, - Op_LoadA32, - Op_Load64, - Op_LoadI64, - Op_LoadA64, - Op_LoadF, - Op_LoadIF, - Op_LoadAF, - - Op_Store8, - Op_StoreA8, - Op_Store16, - Op_StoreA16, - Op_Store32, - Op_StoreA32, - Op_Store64, - Op_StoreA64, - Op_StoreF, - Op_StoreAF, - - Op_LoadImm32, - Op_LoadImm64, - Op_LoadImmF, - Op_LoadSb, - Op_LoadSp, - - Op_MovII, - Op_MovIF, - Op_MovFI, - Op_MovFF, - - Op_Push, - Op_Pop, - - Op_PushF, - Op_PopF, - - Op_Eq, - Op_Ne, - Op_Lt, - Op_Gt, - Op_Lte, - Op_Gte, - Op_And, - Op_Or, - Op_Xor, - Op_Add, - Op_Sub, - Op_Mul, - Op_Div, - Op_Rem, - Op_IMul, - Op_IDiv, - - Op_EqI, - Op_NeI, - Op_LtI, - Op_GtI, - Op_LteI, - Op_GteI, - Op_AndI, - Op_OrI, - Op_XorI, - Op_AddI, - Op_SubI, - Op_RSubI, - Op_MulI, - Op_DivI, - Op_RemI, - Op_IMulI, - Op_IDivI, - - Op_EqF, - Op_NeF, - Op_LtF, - Op_GtF, - Op_LteF, - Op_GteF, - Op_AddF, - Op_SubF, - Op_MulF, - Op_DivF, - - Op_EqFI, - Op_NeFI, - Op_LtFI, - Op_GtFI, - Op_LteFI, - Op_GteFI, - Op_AddFI, - Op_SubFI, - Op_RSubFI, - Op_MulFI, - Op_DivFI, -} Op; - -typedef enum { - Builtin_Alloc, - Builtin_FsOpen, - Builtin_FsClose, - Builtin_FsWrite, - Builtin_FsRead, - Builtin_FsFlush, - Builtin_FsEof, -} Builtin; - -#define IREGS 32 -#define FREGS 16 - -#define STACK_SIZE 65536 -#define CALL_STACK_SIZE 65536 - -typedef struct { - uint64_t id; - FILE* fp; -} FsFile; - -/// -/// Main data structure for the runtime virtual machine. -/// -/// NOTICE: This structure is not necessarily used actively when running the -/// program. This is because the runner caches some values instead of storing -/// them in the struct. The point of this struct is mostly to provide some form -/// of cohesion of the virtual machine. This means that for debugging, this -/// internals of this struct CANNOT be relied on for live data. -/// -typedef struct { - FsFile* files; - size_t files_size; - size_t files_capacity; - uint64_t next_file_id; -} VM; - -void vm_construct(VM* vm); -void vm_destroy(VM* vm); - -typedef uint8_t Reg; - -typedef struct { - uint64_t iregs[IREGS]; - double fregs[FREGS]; -} Regs; - -typedef struct { - uint64_t* caller_sb; - const uint32_t* return_ptr; -} Call; - -/// Runner function for the VM. -/// -/// 'program` is a program encoded according to the encoding rules. The program -/// is expected to exit before hitting the end, hence there's no size parameter. -int vm_run(VM* vm, const uint32_t* program); - -int vm_exec_builtin(VM* vm, Builtin builtin, Regs* regs); -int vm_open_file(VM* vm, uint64_t* id, const char* path, const char* mode); -void vm_close_file(VM* vm, uint64_t id); -FILE* vm_file_fp(VM* vm, uint64_t id); - -#endif