Local/arg fixes, allow passing funcs as args

This commit is contained in:
2021-04-07 00:03:42 +03:00
parent bb616a2d31
commit 7790f1befb
9 changed files with 93 additions and 28 deletions
+37 -12
View File
@@ -63,6 +63,29 @@ void emit_function(struct context *ctx, struct function *fn) {
}
// Obligatory program return
emit_insn(fn, OP(OP_RET, 0));
if (ctx->parent) {
fn->local_count = ctx->var_counter;
} else {
// Root function
fn->local_count = 0;
}
}
static void emit_store(struct function *fn, int kind, size_t index) {
switch (kind) {
case NAME_LOCAL:
emit_insn(fn, OP(OP_STL, index));
break;
case NAME_GLOBAL:
emit_insn(fn, OP(OP_STG, index));
break;
case NAME_ARGUMENT:
emit_insn(fn, OP(OP_STARG, index));
break;
default:
abort();
}
}
void emit(struct function *fn, struct context *ctx, struct node *expr) {
@@ -93,21 +116,17 @@ void emit(struct function *fn, struct context *ctx, struct node *expr) {
int kind;
size_t index;
assert(ctx_lookup_name(ctx, n0->n_ident, &kind, &index) == 0);
if (ctx_lookup_name(ctx, n0->n_ident, &kind, &index) != 0) {
fprintf(stderr, "Unresolved reference to %s\n", n0->n_ident);
abort();
}
n1 = caddr(expr);
assert(null_q(cdr(cddr(expr))));
// (define ident value)
// Emit value for n1
emit(fn, ctx, n1);
switch (kind) {
case NAME_LOCAL:
emit_insn(fn, OP(OP_STL, index));
break;
case NAME_GLOBAL:
emit_insn(fn, OP(OP_STG, index));
break;
}
emit_store(fn, kind, index);
} else if (cons_q(n0)) {
struct node *name = car(n0);
struct node *args = cdr(n0);
@@ -125,7 +144,10 @@ void emit(struct function *fn, struct context *ctx, struct node *expr) {
struct context new_ctx;
new_fn->args = args;
new_fn->body = body;
new_fn->local_count = 0;
assert(!ctx->parent);
ctx_init(&new_ctx, ctx);
new_ctx.var_counter = 0;
new_ctx.owner = new_fn;
emit_function(&new_ctx, new_fn);
@@ -142,10 +164,9 @@ void emit(struct function *fn, struct context *ctx, struct node *expr) {
size_t index;
assert(ctx_lookup_name(ctx, n0->n_ident, &kind, &index) == 0);
assert(kind == NAME_GLOBAL);
emit(fn, ctx, n1);
emit_insn(fn, OP(OP_STG, index));
emit_store(fn, kind, index);
return;
} else if (!strcmp(n0->n_ident, "use")) {
// Ignore
@@ -279,6 +300,10 @@ void emit(struct function *fn, struct context *ctx, struct node *expr) {
case NAME_LOCAL:
emit_insn(fn, OP(OP_LCALL, index));
break;
case NAME_ARGUMENT:
emit_insn(fn, OP(OP_LDARG, index));
emit_insn(fn, OP(OP_CALL, 0));
break;
case NAME_GLOBAL:
emit_insn(fn, OP(OP_GCALL, index));
break;
+1
View File
@@ -35,6 +35,7 @@ struct ext_unit {
struct function {
size_t index;
size_t local_count;
struct node *args, *body;
struct vector bytecode;
};
+1
View File
@@ -117,6 +117,7 @@ static void write_unit(FILE *fp, struct unit *u) {
++argc;
}
bin_func.argc = argc;
bin_func.local_count = fn->local_count;
bin_func.len = fn->bytecode.size * sizeof(uint32_t);
fwrite(&bin_func, 1, sizeof(struct bin_func_entry), fp);
fwrite(fn->bytecode.data, 1, fn->bytecode.size * sizeof(uint32_t), fp);
-1
View File
@@ -65,7 +65,6 @@ int ctx_lookup_name(struct context *ctx, const char *name, int *kind, size_t *in
p = hash_lookup(&ctx->vars, name);
if (p) {
if (ctx->parent) {
// TODO only look into level-1 local contexts
*kind = NAME_LOCAL;
} else {
*kind = NAME_GLOBAL;
+1
View File
@@ -29,6 +29,7 @@ struct bin_ref_entry {
struct bin_func_entry {
uint32_t argc;
uint32_t local_count;
uint32_t len;
uint32_t data[0];
};
+5 -3
View File
@@ -28,6 +28,7 @@
#define OP_ISZ 0x46
#define OP_LDARG 0x4B
#define OP_STARG 0x4C
#define OP_LDG 0x4E
#define OP_STG 0x4F
#define OP_LDF 0x50
@@ -37,7 +38,8 @@
#define OP_XCALL 0x60
#define OP_LCALL 0x61
#define OP_GCALL 0x62
#define OP_JMP 0x63
#define OP_BT 0x64
#define OP_BF 0x65
#define OP_CALL 0x63
#define OP_JMP 0x64
#define OP_BT 0x65
#define OP_BF 0x66
#define OP_RET 0x6F
+4 -3
View File
@@ -5,6 +5,7 @@
#include "vector.h"
#define MAXARG 12
#define MAXLOC 64
struct vm_value;
@@ -17,7 +18,9 @@ struct vm_ref_entry {
};
struct vm_func_entry {
size_t argc;
size_t argc, local_count;
uint64_t local_regs[MAXLOC];
uint64_t arg_regs[MAXARG];
uint32_t *bytecode;
};
@@ -28,8 +31,6 @@ struct vm_state {
uint64_t *call_stack;
size_t csp, call_stack_size;
uint64_t arg_regs[MAXARG];
struct vector ref_table;
struct vector functions;
+6 -1
View File
@@ -103,14 +103,19 @@ found:
for (size_t i = 0; i < hdr.func_table_size; ++i) {
struct bin_func_entry ent;
uint32_t *bytecode;
fread(&ent, 1, sizeof(struct bin_ref_entry), fp);
fread(&ent, 1, sizeof(struct bin_func_entry), fp);
bytecode = malloc(ent.len);
assert(bytecode);
fread(bytecode, 1, ent.len, fp);
struct vm_func_entry *func = vm_add_function(&vm);
if (i == 0) {
assert(!func->local_count);
}
assert(ent.local_count <= MAXLOC);
func->argc = ent.argc;
func->bytecode = bytecode;
func->local_count = ent.local_count;
}
fclose(fp);
+38 -8
View File
@@ -97,8 +97,9 @@ struct vm_func_entry *vm_add_function(struct vm_state *vm) {
void vm_call_index(struct vm_state *vm, size_t index) {
struct vm_func_entry *func;
assert(index < vm->functions.size);
assert(vm->csp);
assert(vm->csp > 2);
vm->call_stack[--vm->csp] = vm->fp;
vm->call_stack[--vm->csp] = vm->ip;
vm->fp = index;
vm->ip = 0;
@@ -106,7 +107,7 @@ void vm_call_index(struct vm_state *vm, size_t index) {
func = vector_ref(&vm->functions, index);
assert(func->argc <= MAXARG);
for (size_t i = 0; i < func->argc; ++i) {
vm->arg_regs[i] = pop(vm);
func->arg_regs[i] = pop(vm);
}
}
@@ -116,13 +117,19 @@ void vm_call_ref(struct vm_state *vm, struct vm_value *ref) {
vm_call_index(vm, ref->v_func.fn_index);
}
int vm_eval_opcode(struct vm_state *vm, uint32_t opcode) {
int vm_eval_opcode(struct vm_state *vm, struct vm_func_entry *func, uint32_t opcode) {
uint64_t w0, w1;
int64_t sw0, sw1;
size_t i0;
ssize_t ii0;
struct vm_ref_entry *r0;
switch (opcode >> 24) {
case OP_ADD:
sw0 = pop_integer(vm);
sw1 = pop_integer(vm);
push_integer(vm, sw0 + sw1);
return 0;
case OP_NOT:
w0 = pop(vm);
if (null_q(w0)) {
@@ -169,7 +176,13 @@ int vm_eval_opcode(struct vm_state *vm, uint32_t opcode) {
case OP_LDARG:
i0 = opcode & 0xFFFFFF;
assert(i0 < MAXARG);
push(vm, vm->arg_regs[i0]);
push(vm, func->arg_regs[i0]);
return 0;
case OP_STARG:
i0 = opcode & 0xFFFFFF;
w0 = pop(vm);
assert(i0 < MAXARG);
func->arg_regs[i0] = w0;
return 0;
case OP_LDG:
i0 = opcode & 0xFFFFFF;
@@ -188,9 +201,15 @@ int vm_eval_opcode(struct vm_state *vm, uint32_t opcode) {
push_ref(vm, vm_func(0, i0));
return 0;
case OP_STL:
i0 = opcode & 0xFFFFFF;
assert(i0 < func->local_count);
func->local_regs[i0] = pop(vm);
return 0;
case OP_LDL:
printf("TODO implement local values\n");
abort();
i0 = opcode & 0xFFFFFF;
assert(i0 < func->local_count);
push(vm, func->local_regs[i0]);
return 0;
//
case OP_ISZ:
w0 = pop(vm);
@@ -217,6 +236,11 @@ int vm_eval_opcode(struct vm_state *vm, uint32_t opcode) {
assert(func_q(w0));
vm_call_ref(vm, getref(w0));
return 0;
case OP_CALL:
w0 = pop(vm);
assert(func_q(w0));
vm_call_ref(vm, getref(w0));
return 0;
case OP_BF:
w0 = pop(vm);
ii0 = sximm(opcode & 0xFFFFFF);
@@ -231,7 +255,13 @@ int vm_eval_opcode(struct vm_state *vm, uint32_t opcode) {
vm->ip += ii0 - 1;
return 0;
case OP_RET:
return -1;
if (vm->csp == vm->call_stack_size) {
// Return from main
return -1;
}
vm->ip = vm->call_stack[vm->csp++];
vm->fp = vm->call_stack[vm->csp++];
return 0;
default:
fprintf(stderr, "Undefined opcode: 0x%02hhx\n", opcode >> 24);
abort();
@@ -242,5 +272,5 @@ int vm_eval_step(struct vm_state *vm) {
assert(vm->fp < vm->functions.size);
struct vm_func_entry *func = vector_ref(&vm->functions, vm->fp);
uint32_t opcode = func->bytecode[vm->ip++];
return vm_eval_opcode(vm, opcode);
return vm_eval_opcode(vm, func, opcode);
}