mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-14 08:45:28 +00:00
357 lines
6.6 KiB
C++
357 lines
6.6 KiB
C++
#if 0
|
|
// TODO(bill): COMPLETELY REWORK THIS ENTIRE INTERPRETER
|
|
#include "dyncall/include/dyncall.h"
|
|
|
|
struct vmInterpreter;
|
|
|
|
/*
|
|
Types:
|
|
boolean
|
|
integer
|
|
float
|
|
pointer
|
|
string
|
|
any
|
|
array
|
|
vector
|
|
slice
|
|
maybe
|
|
struct
|
|
union
|
|
raw_union
|
|
enum
|
|
tuple
|
|
proc
|
|
*/
|
|
|
|
struct vmProcedure {
|
|
Type * type;
|
|
String name;
|
|
b32 is_external;
|
|
};
|
|
|
|
struct vmValue {
|
|
void *data;
|
|
i32 id;
|
|
Type *type;
|
|
union {
|
|
i64 v_int;
|
|
f32 v_f32;
|
|
f64 v_f64;
|
|
vmProcedure * v_proc;
|
|
};
|
|
};
|
|
|
|
Array<vmValue> vm_empty_args = {};
|
|
|
|
struct vmFrame {
|
|
vmInterpreter *i;
|
|
vmFrame * caller;
|
|
ssaProcedure * proc;
|
|
ssaBlock * block;
|
|
ssaBlock * prev_block;
|
|
isize instr_index; // For the current block
|
|
|
|
Array<void *> env; // Index == instr id
|
|
vmValue result;
|
|
};
|
|
|
|
struct vmInterpreter {
|
|
ssaModule * module;
|
|
BaseTypeSizes sizes;
|
|
gbArena stack_arena;
|
|
gbAllocator stack_allocator;
|
|
gbAllocator heap_allocator;
|
|
|
|
Array<vmFrame> frame_stack;
|
|
Map<vmValue> globals;
|
|
};
|
|
|
|
enum vmContinuation {
|
|
vmContinuation_Next,
|
|
vmContinuation_Return,
|
|
vmContinuation_Branch,
|
|
};
|
|
|
|
|
|
|
|
|
|
i64 vm_size_of(vmInterpreter *i, Type *type) {
|
|
return type_size_of(i->sizes, i->heap_allocator, type);
|
|
}
|
|
i64 vm_align_of(vmInterpreter *i, Type *type) {
|
|
return type_align_of(i->sizes, i->heap_allocator, type);
|
|
}
|
|
i64 vm_offset_of(vmInterpreter *i, Type *type, i64 index) {
|
|
return type_offset_of(i->sizes, i->heap_allocator, type, index);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Array<vmValue> vm_prepare_call(vmFrame *f, ssaInstr *instr, vmValue *proc) {
|
|
GB_ASSERT(instr->kind == ssaInstr_Call);
|
|
|
|
*proc = vm_get_value(f, instr->Call.value);
|
|
|
|
Array<vmValue> args = {};
|
|
array_init_count(&args, f->i->stack_allocator, instr->Call.arg_count);
|
|
|
|
for (isize i = 0; i < instr->Call.arg_count; i++) {
|
|
args[i] = vm_get_value(f, instr->Call.args[i]);
|
|
}
|
|
|
|
return args;
|
|
}
|
|
|
|
|
|
vmContinuation vm_visit_instr(vmFrame *f, ssaValue *value) {
|
|
ssaInstr *instr = &value->Instr;
|
|
#if 1
|
|
if (instr->kind != ssaInstr_Comment) {
|
|
gb_printf("instr: %.*s\n", LIT(ssa_instr_strings[instr->kind]));
|
|
}
|
|
#endif
|
|
switch (instr->kind) {
|
|
case ssaInstr_StartupRuntime: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_Comment: break;
|
|
|
|
case ssaInstr_Local: {
|
|
Type *type = ssa_type(value);
|
|
GB_ASSERT(is_type_pointer(type));
|
|
i64 size = gb_max(1, vm_size_of(f->i, type));
|
|
i64 align = gb_max(1, vm_align_of(f->i, type));
|
|
void *mem = gb_alloc_align(f->i->stack_allocator, size, align);
|
|
|
|
array_add(&f->locals, mem);
|
|
} break;
|
|
|
|
case ssaInstr_ZeroInit: {
|
|
Type *pt = ssa_type(instr->ZeroInit.address);
|
|
GB_ASSERT(is_type_pointer(pt));
|
|
vmValue addr = vm_get_value(f, instr->ZeroInit.address);
|
|
GB_ASSERT(are_types_identical(addr.type, ptr));
|
|
i64 size = vm_size_of(vm, type_deref(pt));
|
|
gb_zero(addr.v_ptr, size);
|
|
} break;
|
|
|
|
case ssaInstr_Store: {
|
|
ssaValue *addr = instr->Store.Address;
|
|
ssaValue *value = instr->Store.Value;
|
|
} break;
|
|
|
|
case ssaInstr_Load: {
|
|
ssaValue *addr = instr->Load.Address;
|
|
} break;
|
|
|
|
case ssaInstr_ArrayElementPtr: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_StructElementPtr: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_PtrOffset: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_Phi:
|
|
for_array(i, f->block->preds) {
|
|
ssaBlock *pred = f->block->preds[i];
|
|
if (f->prev_block == pred) {
|
|
vmValue edge = vm_get_value(f, instr->Phi.edges[i]);
|
|
// vm_set_value(f, value, edge);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ssaInstr_ArrayExtractValue: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_StructExtractValue: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_Jump:
|
|
f->prev_block = f->block;
|
|
f->block = instr->Jump.block;
|
|
return vmContinuation_Branch;
|
|
|
|
case ssaInstr_If:
|
|
f->prev_block = f->block;
|
|
if (vm_get_value(f, instr->If.cond).v_int != 0) {
|
|
f->block = instr->If.true_block;
|
|
} else {
|
|
f->block = instr->If.false_block;
|
|
}
|
|
return vmContinuation_Branch;
|
|
|
|
case ssaInstr_Return:
|
|
if (instr->Return.value != NULL) {
|
|
Type *type = base_type(ssa_type(instr->Return.value));
|
|
GB_ASSERT(is_type_tuple(type));
|
|
f->result = vm_get_value(f, instr->Return.value);
|
|
if (type->Tuple.variable_count == 1) {
|
|
f->result.type = type->Tuple.variables[0]->type;
|
|
}
|
|
}
|
|
f->block = NULL;
|
|
return vmContinuation_Return;
|
|
|
|
case ssaInstr_Conv: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_Unreachable: {
|
|
GB_PANIC("Unreachable");
|
|
} break;
|
|
|
|
case ssaInstr_BinaryOp: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_Call: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_Select: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_VectorExtractElement: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_VectorInsertElement: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_VectorShuffle: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_BoundsCheck: {
|
|
|
|
} break;
|
|
|
|
case ssaInstr_SliceBoundsCheck: {
|
|
|
|
} break;
|
|
|
|
default: {
|
|
GB_PANIC("<unknown instr> %d\n", instr->kind);
|
|
} break;
|
|
}
|
|
|
|
return vmContinuation_Next;
|
|
}
|
|
|
|
|
|
void vm_run_frame(vmFrame *f) {
|
|
for (;;) {
|
|
for_array(i, f->block->instrs) {
|
|
ssaValue *v = f->block->instrs[i];
|
|
GB_ASSERT(v->kind == ssaValue_Instr);
|
|
switch (vm_visit_instr(f, v)) {
|
|
case vmContinuation_Return:
|
|
return;
|
|
case vmContinuation_Next:
|
|
// Do nothing
|
|
break;
|
|
case vmContinuation_Branch:
|
|
goto end;
|
|
}
|
|
}
|
|
end:
|
|
;
|
|
}
|
|
}
|
|
|
|
ssaProcedure *vm_lookup_proc(vmInterpreter *i, String name) {
|
|
ssaValue **found = map_get(&i->module->members, hash_string(name));
|
|
if (found == NULL) {
|
|
return NULL;
|
|
}
|
|
ssaValue *v = *found;
|
|
if (v->kind != ssaValue_Proc) {
|
|
return NULL;
|
|
}
|
|
|
|
return &v->Proc;
|
|
}
|
|
|
|
vmValue vm_ext(vmFrame *caller, Array<vmValue> args) {
|
|
GB_PANIC("TODO(bill): vm_ext");
|
|
vmValue v = {};
|
|
return v;
|
|
}
|
|
|
|
vmValue vm_call(vmInterpreter *i, vmFrame *caller, ssaProcedure *proc, Array<vmValue> args) {
|
|
if (proc == NULL) {
|
|
GB_PANIC("Call to NULL procedure");
|
|
}
|
|
|
|
gb_printf("Call: %.*s", LIT(proc->name));
|
|
|
|
vmFrame f = {};
|
|
f.i = i;
|
|
f.caller = caller;
|
|
f.proc = proc;
|
|
if (proc->body == NULL) {
|
|
return vm_ext(&f, args);
|
|
}
|
|
f.block = proc->blocks[0];
|
|
|
|
map_init_with_reserve(&f.env, i->heap_allocator, 1.5*proc->instr_count);
|
|
defer (map_destroy(&f.env));
|
|
|
|
array_init_count(&f.locals, i->heap_allocator, proc->local_count);
|
|
defer (array_free(&f.locals));
|
|
|
|
for_array(i, proc->params) {
|
|
map_set(&f.env, hash_pointer(proc->params[i]), args[i]);
|
|
}
|
|
|
|
while (f.block != NULL) {
|
|
vm_run_frame(&f);
|
|
}
|
|
|
|
return f.result;
|
|
}
|
|
|
|
i32 vm_interpret(ssaModule *m) {
|
|
i32 exit_code = 2;
|
|
|
|
vmInterpreter i = {};
|
|
|
|
i.module = m;
|
|
i.sizes = m->sizes;
|
|
|
|
gb_arena_init_from_allocator(&i.stack_arena, heap_allocator(), gb_megabytes(64));
|
|
defer (gb_arena_free(&i.stack_arena));
|
|
|
|
i.stack_allocator = gb_arena_allocator(&i.stack_arena);
|
|
i.heap_allocator = heap_allocator();
|
|
|
|
ssaProcedure *main_proc = vm_lookup_proc(&i, make_string("main"));
|
|
if (main_proc != NULL) {
|
|
vm_call(&i, NULL, main_proc, vm_empty_args);
|
|
exit_code = 0;
|
|
} else {
|
|
gb_printf_err("No main procedure.");
|
|
exit_code = 1;
|
|
}
|
|
|
|
return exit_code;
|
|
}
|
|
|
|
#endif
|