#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 vm_empty_args = {}; struct vmFrame { vmInterpreter *i; vmFrame * caller; ssaProcedure * proc; ssaBlock * block; ssaBlock * prev_block; isize instr_index; // For the current block Array env; // Index == instr id vmValue result; }; struct vmInterpreter { ssaModule * module; BaseTypeSizes sizes; gbArena stack_arena; gbAllocator stack_allocator; gbAllocator heap_allocator; Array frame_stack; Map 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 vm_prepare_call(vmFrame *f, ssaInstr *instr, vmValue *proc) { GB_ASSERT(instr->kind == ssaInstr_Call); *proc = vm_get_value(f, instr->Call.value); Array 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(" %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 args) { GB_PANIC("TODO(bill): vm_ext"); vmValue v = {}; return v; } vmValue vm_call(vmInterpreter *i, vmFrame *caller, ssaProcedure *proc, Array 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