diff --git a/nob.c b/nob.c index 2152b75..d1da8cc 100644 --- a/nob.c +++ b/nob.c @@ -31,8 +31,9 @@ static const char *splc0_srcs[] = { "stage1/spl_intrin.c", "stage1/spl_ir.c", "stage1/spl_ast2ir.c", - // "stage1/spl_ir2vm.c", - // "stage0/spl_mcode.c", + "stage1/spl_layout.c", + "stage1/spl_ir2vm.c", + "stage0/spl_mcode.c", }; /* clang-format on */ @@ -182,7 +183,7 @@ static void parse_expect(const char *name, Nob_Cmd_Result *expect) { if (rest.count == 0) continue; - if (nob_sv_starts_with(rest, nob_sv_from_cstr("Expect"))) { + if (!nob_sv_starts_with(rest, nob_sv_from_cstr("Expect"))) { break; } rest = nob_sv_from_parts(rest.data + 6, rest.count - 6); @@ -198,6 +199,7 @@ static void parse_expect(const char *name, Nob_Cmd_Result *expect) { for (size_t i = 0; i < value.count && isdigit(value.data[i]); ++i) { val = val * 10 + (value.data[i] - '0'); } + // printf("expected code %d\n", val); expect->exit_code = val; } else if (nob_sv_eq(key, nob_sv_from_cstr("stdout"))) { } @@ -229,14 +231,14 @@ static bool test_once(const char *fname, void *user_data) { cmd.count = 0; nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", cli_path)); nob_cmd_append(&cmd, target_sir); - nob_cmd_run(&cmd); + // nob_cmd_run(&cmd); Nob_Cmd_Result result = {0}; - Nob_String_Builder cmd_str = {0}; nob_cmd_render(cmd, &cmd_str); - nob_sb_append_null(&cmd_str); - nob_cmd_capture_popen(cmd_str.items, &result); + + Nob_String_View sv = nob_sb_to_sv(cmd_str); + nob_cmd_capture_popen(nob_temp_sv_to_cstr(sv), &result); // Expect retcode = number Nob_Cmd_Result expect = {0}; @@ -268,6 +270,10 @@ typedef bool (*test_fn_t)(const char *fname, void *user_data); static bool run_test(Nob_Files *files, test_fn_t test_once, void *user_data) { const char *test_folder = "./tests/stage1/"; + if (!prepare_build()) { + return 1; + } + Nob_File_Paths paths = {0}; nob_read_entire_dir(test_folder, &paths); for (int i = 0; i < files->count; i += 1) { @@ -284,10 +290,6 @@ static bool run_test(Nob_Files *files, test_fn_t test_once, void *user_data) { } } - if (!prepare_build()) { - return 1; - } - return true; } @@ -320,7 +322,7 @@ int main(int argc, char **argv) { #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); #endif - NOB_GO_REBUILD_URSELF_PLUS(argc, argv, "nob.h"); + NOB_GO_REBUILD_URSELF_PLUS(argc, argv, "nob.h", "nob_popen.h"); set_log_handler(nob_cancer_log_handler); const char *program_name = nob_shift(argv, argc); diff --git a/nob_popen.h b/nob_popen.h index bd4c850..1b52628 100644 --- a/nob_popen.h +++ b/nob_popen.h @@ -15,34 +15,125 @@ typedef struct { int count; } Nob_Files; -// 运行命令,捕获 stdout 和退出码(不支持 stdin 和 stderr) +// 运行命令,捕获 stdout(Windows 下会合并 stderr)和真实退出码。 +// 返回 true 仅表示命令成功启动并完成,不代表 exit_code == 0。 bool nob_cmd_capture_popen(const char *tname, Nob_Cmd_Result *res) { memset(res, 0, sizeof(*res)); #ifdef _WIN32 - FILE *fp = _popen(tname, "r"); -#else - FILE *fp = popen(tname, "r"); -#endif + // ---------- Windows: CreateProcessA + 匿名管道 ---------- + SECURITY_ATTRIBUTES sa = {0}; + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + HANDLE hRead = NULL; + HANDLE hWrite = NULL; + if (!CreatePipe(&hRead, &hWrite, &sa, 0)) { + nob_log(NOB_ERROR, "CreatePipe failed: %s", nob_win32_error_message(GetLastError())); + return false; + } + + // 读端不能被继承,否则父进程 ReadFile 永远等不到 EOF + if (!SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0)) { + nob_log(NOB_ERROR, "SetHandleInformation failed: %s", + nob_win32_error_message(GetLastError())); + CloseHandle(hRead); + CloseHandle(hWrite); + return false; + } + + STARTUPINFOA si = {0}; + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.hStdOutput = hWrite; + si.hStdError = hWrite; // 把 stderr 也并入 out,需要分离的话另开一条管道 + + PROCESS_INFORMATION pi = {0}; + + // CreateProcessA 会就地修改 lpCommandLine,必须传可写缓冲 + char *cmdline = NULL; + { + size_t n = strlen(tname) + 1; + cmdline = (char *)malloc(n); + if (!cmdline) { + CloseHandle(hRead); + CloseHandle(hWrite); + nob_log(NOB_ERROR, "malloc failed"); + return false; + } + memcpy(cmdline, tname, n); + } + + BOOL ok = CreateProcessA(NULL, // lpApplicationName: 让系统从 lpCommandLine 里解析 + cmdline, // lpCommandLine + NULL, // lpProcessAttributes + NULL, // lpThreadAttributes + TRUE, // bInheritHandles: 必须为 TRUE,才能继承管道写端 + CREATE_NO_WINDOW, // 不弹黑窗;想弹就传 0 + NULL, // lpEnvironment + NULL, // lpCurrentDirectory + &si, &pi); + + free(cmdline); + + // 无论成功与否,父进程都不再需要写端(子进程已持有自己的副本) + CloseHandle(hWrite); + + if (!ok) { + nob_log(NOB_ERROR, "CreateProcessA failed for \"%s\": %s", tname, + nob_win32_error_message(GetLastError())); + CloseHandle(hRead); + return false; + } + + // ---------- 读取 stdout ---------- + { + char buffer[4096]; + DWORD n = 0; + while (ReadFile(hRead, buffer, sizeof(buffer), &n, NULL) && n > 0) { + nob_sb_append_buf(&res->out, buffer, (size_t)n); + } + } + CloseHandle(hRead); + + // ---------- 等待并取真实退出码 ---------- + WaitForSingleObject(pi.hProcess, INFINITE); + DWORD code = 0; + if (!GetExitCodeProcess(pi.hProcess, &code)) { + nob_log(NOB_ERROR, "GetExitCodeProcess failed: %s", + nob_win32_error_message(GetLastError())); + code = (DWORD)-1; + } + res->exit_code = (int)code; + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + +#else + // ---------- POSIX: popen ---------- + FILE *fp = popen(tname, "r"); if (!fp) { - nob_log(NOB_ERROR, "popen failed"); + nob_log(NOB_ERROR, "popen failed: %s", strerror(errno)); return false; } - // 读取输出到 String_Builder char buffer[4096]; while (fgets(buffer, sizeof(buffer), fp)) { nob_sb_append_cstr(&res->out, buffer); } - // 获取退出码 -#ifdef _WIN32 - res->exit_code = _pclose(fp); -#else - res->exit_code = pclose(fp); - if (WIFEXITED(res->exit_code)) - res->exit_code = WEXITSTATUS(res->exit_code); + int status = pclose(fp); + if (status == -1) { + nob_log(NOB_ERROR, "pclose failed: %s", strerror(errno)); + return false; + } + if (WIFEXITED(status)) + status = WEXITSTATUS(status); + else if (WIFSIGNALED(status)) + status = 128 + WTERMSIG(status); + res->exit_code = status; #endif res->ok = true; diff --git a/stage1/spl_ast2ir.c b/stage1/spl_ast2ir.c index b0bb4aa..477167d 100644 --- a/stage1/spl_ast2ir.c +++ b/stage1/spl_ast2ir.c @@ -106,8 +106,8 @@ static spl_ir_node_ref_t ast2ir_intrin_len(spl_ast2ir_t *a, spl_ast_node_t *n) { spl_ir_node_ref_t slice_val = emit_expr(a, n->field.obj); if (!slice_val) return 0; - return spl_ir_builder_agg_extract(a->ir, usize_ir, usize_ir, SPL_SLICE_LEN_FIELD_IDX, - slice_val); + return spl_ir_builder_agg_extract(a->ir, recv->ir_type_id, usize_ir, + SPL_SLICE_LEN_FIELD_IDX, slice_val); } default: return 0; @@ -160,12 +160,7 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { if (!spl_type_agg_member_idx(a->sema->type, agg_ir, n->field.field, &idx)) return 0; - spl_type_node_t *agg_n = spl_type_node(a->sema->type, agg_ir); - if (!agg_n) - return 0; - spl_type_id_t field_ir = vec_at(agg_n->agg_type.variants, idx).type_id; - - return spl_ir_builder_mem_field(a->ir, field_ir, base, idx); + return spl_ir_builder_mem_field(a->ir, agg_ir, base, idx); } case SPL_AST_EXPR_INDEX: { spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->index.obj); @@ -442,16 +437,26 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) spl_ir_node_ref_t fn = emit_expr(a, n->call.callee); if (!fn) return 0; + + /* 先求所有参数 */ + usize nargs = vec_size(n->call.args); + spl_ir_node_ref_vec_t arg_refs; + vec_init(arg_refs); + for (usize i = 0; i < nargs; ++i) + vec_push(arg_refs, emit_expr(a, vec_at(n->call.args, i))); + + /* 再创建 call 节点 */ spl_type_id_t ret_t = node_ir(a, n); spl_ir_node_ref_t call = spl_ir_builder_control_call(a->ir, ret_t, fn); - if (!call) + if (!call) { + vec_free(arg_refs); return 0; - for (usize i = 0; i < vec_size(n->call.args); ++i) { - spl_ir_node_ref_t arg = emit_expr(a, vec_at(n->call.args, i)); - if (!arg) - return 0; - spl_ir_builder_control_call_param(a->ir, call, arg); } + + for (usize i = 0; i < vec_size(arg_refs); ++i) + spl_ir_builder_control_call_param(a->ir, call, vec_at(arg_refs, i)); + vec_free(arg_refs); + return call; } case SPL_AST_EXPR_FIELD: { @@ -478,15 +483,25 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) return emit_cast(a, n); case SPL_AST_EXPR_TUPLE: { spl_type_id_t t = node_ir(a, n); - spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t); - if (!node) - return 0; - for (usize i = 0; i < vec_size(n->tuple.elems); ++i) { + usize nelems = vec_size(n->tuple.elems); + + spl_ir_node_ref_vec_t field_refs; + vec_init(field_refs); + for (usize i = 0; i < nelems; ++i) { spl_ir_node_ref_t f = emit_expr(a, vec_at(n->tuple.elems, i)); if (!f) - return 0; - spl_ir_builder_agg_construct_field(a->ir, node, f); + Panic("tuple element emit failed"); + vec_push(field_refs, f); } + + spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t); + if (!node) + Panic("agg_construct failed for tuple"); + + for (usize i = 0; i < nelems; ++i) + spl_ir_builder_agg_construct_field(a->ir, node, vec_at(field_refs, i)); + + vec_free(field_refs); return node; } case SPL_AST_EXPR_ARRAY_LIT: { @@ -494,16 +509,25 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) if (!t) Panic("array literal has no type after sema"); + usize nelems = vec_size(n->array_literal.elems); + + spl_ir_node_ref_vec_t field_refs; + vec_init(field_refs); + for (usize i = 0; i < nelems; ++i) { + spl_ir_node_ref_t f = emit_expr(a, vec_at(n->array_literal.elems, i)); + if (!f) + Panic("array element emit failed"); + vec_push(field_refs, f); + } + spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t); if (!node) Panic("agg_construct failed for array literal"); - for (usize i = 0; i < vec_size(n->array_literal.elems); ++i) { - spl_ir_node_ref_t f = emit_expr(a, vec_at(n->array_literal.elems, i)); - if (!f) - Panic("array element emit failed"); - spl_ir_builder_agg_construct_field(a->ir, node, f); - } + for (usize i = 0; i < nelems; ++i) + spl_ir_builder_agg_construct_field(a->ir, node, vec_at(field_refs, i)); + + vec_free(field_refs); return node; } case SPL_AST_EXPR_AGGREGATE_LIT: { @@ -575,41 +599,53 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) if (!obj_ln) return 0; - /* 目前只处理数组->切片的完整形式 arr[..](无 begin / end) - 或 arr[begin..end] 的通用形式。简化实现只做完整切片。 */ - spl_type_id_t slice_ir = node_ir(a, n); /* struct{ptr, len} */ + spl_type_id_t slice_ir = node_ir(a, n); if (!slice_ir) return 0; - spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, slice_ir); - if (!node) - return 0; + spl_lang_type_id_t elem_lang = obj_ln->extra.elem; + spl_type_id_t elem_ir = to_ir_type(a, elem_lang); + spl_lang_type_id_t usize_lang = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0); + spl_type_id_t usize_ir = to_ir_type(a, usize_lang); - /* 取数组元素指针 */ spl_ir_node_ref_t base = emit_lvalue(a, n->slice.obj); if (!base) return 0; - spl_type_id_t ptr_ir = - spl_type_builder_ptr(a->sema->type, to_ir_type(a, obj_ln->extra.elem)); + spl_ir_node_ref_t begin_v = 0; + if (n->slice.begin) + begin_v = emit_expr(a, n->slice.begin); + else + begin_v = spl_ir_builder_type_const_int(a->ir, usize_ir, 0); + if (!begin_v) + return 0; - /* 字段 0:ptr */ - spl_ir_builder_agg_construct_field(a->ir, node, base); + spl_ir_node_ref_t ptr = spl_ir_builder_mem_offset(a->ir, elem_ir, base, begin_v); + if (!ptr) + return 0; - /* 字段 1:len —— 数组取 len,切片取原切片 len */ - spl_ir_node_ref_t len = 0; - if (obj_ln->kind == SPL_LANG_TYPE_ARRAY) { + spl_ir_node_ref_t end_v = 0; + if (n->slice.end) { + end_v = emit_expr(a, n->slice.end); + } else if (obj_ln->kind == SPL_LANG_TYPE_ARRAY) { spl_type_node_t *arr = spl_type_node(a->sema->type, obj_ln->ir_type_id); - spl_lang_type_id_t usize = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0); - len = spl_ir_builder_type_const_int(a->ir, to_ir_type(a, usize), arr->array_type.len); + end_v = spl_ir_builder_type_const_int(a->ir, usize_ir, arr->array_type.len); } else if (obj_ln->kind == SPL_LANG_TYPE_SLICE) { spl_ir_node_ref_t slice_val = emit_expr(a, n->slice.obj); - spl_lang_type_id_t usize = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0); - len = spl_ir_builder_agg_extract(a->ir, to_ir_type(a, usize), to_ir_type(a, usize), - SPL_SLICE_LEN_FIELD_IDX, slice_val); + end_v = spl_ir_builder_agg_extract(a->ir, obj_ln->ir_type_id, usize_ir, + SPL_SLICE_LEN_FIELD_IDX, slice_val); } else { return 0; } + if (!end_v) + return 0; + + spl_ir_node_ref_t len = spl_ir_builder_arith_sub(a->ir, usize_ir, end_v, begin_v); + + spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, slice_ir); + if (!node) + return 0; + spl_ir_builder_agg_construct_field(a->ir, node, ptr); spl_ir_builder_agg_construct_field(a->ir, node, len); return node; } diff --git a/stage1/spl_ir.c b/stage1/spl_ir.c index d6dd85c..bf66de6 100644 --- a/stage1/spl_ir.c +++ b/stage1/spl_ir.c @@ -196,8 +196,8 @@ static void ir_dump_node(const spl_type_t *ty, spl_ir_node_t *n) { printf(" float=%f", n->type_const.float_lit); } else if (t && t->kind == SPL_TYPE_FN) { printf(" fn#%zu", n->type_const.fn); - } else if (t && t->kind == SPL_TYPE_PTR) { - printf(" str=\"%s\"", n->type_const.cstr_lit ? n->type_const.cstr_lit : "?"); + // } else if (t && t->kind == SPL_TYPE_PTR) { + // printf(" str=\"%s\"", n->type_const.cstr_lit ? n->type_const.cstr_lit : "?"); } else if (t && t->kind == SPL_TYPE_INT && t->int_type.bits == 8) { printf(" char='%c'", n->type_const.ch_lit); } else { @@ -592,7 +592,8 @@ spl_ir_node_ref_t spl_ir_builder_type_const_cstr(spl_ir_builder_t *b, spl_type_i spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_CONST); spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref); n->type_const.tid = tid; - n->type_const.cstr_lit = val; + TODO(); + // n->type_const.cstr_lit = val; return ref; } diff --git a/stage1/spl_ir.h b/stage1/spl_ir.h index 8b3f413..79c6ae7 100644 --- a/stage1/spl_ir.h +++ b/stage1/spl_ir.h @@ -145,7 +145,7 @@ typedef struct { void *ptr_lit; usize int_lit; double float_lit; - const char *cstr_lit; + // const char *cstr_lit; char ch_lit; spl_ir_func_ref_t fn; }; diff --git a/stage1/spl_ir2vm.c b/stage1/spl_ir2vm.c index b315ba8..e56efb0 100644 --- a/stage1/spl_ir2vm.c +++ b/stage1/spl_ir2vm.c @@ -1,45 +1,966 @@ #include "spl_ir2vm.h" +#include "spl_layout.h" -static int emit_instr(spl_ir2vm_t *ctx, spl_ir_func_t *fn, spl_ir_node_t *node) { - int pos = 0; - switch (node->kind) { - case SPL_IR_TYPE_CONST: - break; - case SPL_IR_CONTROL_RET: - spl_type_node_t *tn = spl_type_node(ctx->type, node->control_ret.tid); - spl_ir_node_t *ret_node = &vec_at(fn->nodes, node->control_ret.val); - switch (tn->kind) { - case SPL_TYPE_INT: - break; +static usize ir_type_size(spl_ir2vm_t *ctx, spl_type_id_t tid) { + spl_type_node_t *tn = spl_type_node(ctx->type, tid); + if (!tn) + return 8; + switch (tn->kind) { + case SPL_TYPE_UNIT: + return 0; + case SPL_TYPE_BOOL: + return 1; + case SPL_TYPE_INT: + return (tn->int_type.bits + 7) / 8; + case SPL_TYPE_FLOAT: + return (tn->float_type.bits + 7) / 8; + case SPL_TYPE_PTR: + return sizeof(void *); + case SPL_TYPE_FN: + return sizeof(void *); + case SPL_TYPE_ARRAY: + return ir_type_size(ctx, tn->array_type.element) * tn->array_type.len; + case SPL_TYPE_STRUCT: + case SPL_TYPE_UNION: { + usize s = 0; + for (usize i = 0; i < vec_size(tn->agg_type.variants); ++i) + s += ir_type_size(ctx, vec_at(tn->agg_type.variants, i).type_id); + return s; + } + default: + return 8; + } +} + +static bool ir_is_aggregate(spl_ir2vm_t *ctx, spl_type_id_t tid) { + spl_type_node_t *tn = spl_type_node(ctx->type, tid); + if (!tn) + return false; + return tn->kind == SPL_TYPE_ARRAY || tn->kind == SPL_TYPE_STRUCT || + tn->kind == SPL_TYPE_UNION || tn->kind == SPL_TYPE_ENUM || tn->kind == SPL_TYPE_SHAPE; +} + +static spl_type_id_t ir_agg_field_tid(spl_ir2vm_t *ctx, spl_type_id_t tid, usize idx) { + spl_type_node_t *tn = spl_type_node(ctx->type, tid); + if (!tn) + return 0; + if (tn->kind == SPL_TYPE_STRUCT || tn->kind == SPL_TYPE_UNION) { + if (idx < vec_size(tn->agg_type.variants)) + return vec_at(tn->agg_type.variants, idx).type_id; + } else if (tn->kind == SPL_TYPE_ARRAY) { + return tn->array_type.element; + } + return 0; +} + +static usize ir_agg_field_off(spl_ir2vm_t *ctx, spl_type_id_t tid, usize idx) { + spl_type_node_t *tn = spl_type_node(ctx->type, tid); + if (!tn) + return 0; + if (tn->kind == SPL_TYPE_STRUCT || tn->kind == SPL_TYPE_UNION) { + usize off = 0; + for (usize i = 0; i < idx && i < vec_size(tn->agg_type.variants); ++i) + off += ir_type_size(ctx, vec_at(tn->agg_type.variants, i).type_id); + return off; + } + if (tn->kind == SPL_TYPE_ARRAY) + return idx * ir_type_size(ctx, tn->array_type.element); + return 0; +} + +static uint8_t vm_kind_of(spl_ir2vm_t *ctx, spl_type_id_t tid) { + spl_type_node_t *tn = spl_type_node(ctx->type, tid); + if (!tn) + return SPL_VOID; + switch (tn->kind) { + case SPL_TYPE_UNIT: + return SPL_VOID; + case SPL_TYPE_BOOL: + return SPL_BOOL; + case SPL_TYPE_INT: + if (tn->int_type.bits == 0) + return SPL_I32; + switch (tn->int_type.bits) { + case 8: + return tn->int_type.is_signed ? SPL_I8 : SPL_U8; + case 16: + return tn->int_type.is_signed ? SPL_I16 : SPL_U16; + case 32: + return tn->int_type.is_signed ? SPL_I32 : SPL_U32; default: - UNREACHABLE(); + return tn->int_type.is_signed ? SPL_I64 : SPL_U64; } - // if (is_agg(ty, tid)) { - // if (n->control_ret.val) { - // emit_value(fc, n->control_ret.val); - // emit_laddr(fc, fc->sret_off); - // emit_load_insn(fc, SPL_PTR); - // add_insn(fc, SPL_SWAP, SPL_VOID, 0); - // emit_memcpy(fc, type_size(ty, tid)); - // } - // add_insn(fc, SPL_RET, SPL_VOID, 0); - // } else if (!is_void(ty, tid)) { - // if (n->control_ret.val) - // emit_value(fc, n->control_ret.val); - // else - // emit_push(fc, 0); /* 空体函数:返回未定义0 */ - // add_insn(fc, SPL_RET, vm_tag(ty, tid), 0); - // } else { - // add_insn(fc, SPL_RET, SPL_VOID, 0); - // } + case SPL_TYPE_FLOAT: + return tn->float_type.bits == 32 ? SPL_F32 : SPL_F64; + default: + return SPL_PTR; + } +} - spl_prog_add_instr(&ctx->prog, SPL_PUSH, SPL_I32, 0); - spl_prog_add_instr(&ctx->prog, SPL_RET, SPL_I32, 0); +static spl_type_id_t ir_result_tid(const spl_ir_node_t *n) { + switch (n->kind) { + case SPL_IR_ARITH_ADD: + case SPL_IR_ARITH_SUB: + case SPL_IR_ARITH_MUL: + case SPL_IR_ARITH_DIV: + case SPL_IR_ARITH_REM: + case SPL_IR_ARITH_AND: + case SPL_IR_ARITH_OR: + case SPL_IR_ARITH_XOR: + case SPL_IR_ARITH_SHL: + case SPL_IR_ARITH_SHR: + case SPL_IR_ARITH_NEG: + case SPL_IR_ARITH_ABS: + case SPL_IR_ARITH_NOT: + return n->arith.tid; + case SPL_IR_CMP_EQ: + case SPL_IR_CMP_NE: + case SPL_IR_CMP_LT: + case SPL_IR_CMP_LE: + case SPL_IR_CMP_GT: + case SPL_IR_CMP_GE: + return n->cmp.tid; + case SPL_IR_CAST_TRUNC: + case SPL_IR_CAST_ZEXT: + case SPL_IR_CAST_SEXT: + case SPL_IR_CAST_FEXT: + case SPL_IR_CAST_FTRUNC: + case SPL_IR_CAST_BITCAST: + case SPL_IR_CAST_PTR2INT: + case SPL_IR_CAST_INT2PTR: + case SPL_IR_CAST_BOOL2INT: + case SPL_IR_CASE_INT2FLOAT: + case SPL_IR_CASE_FLOAT2INT: + return n->cast.to_tid; + case SPL_IR_MEM_ALLOCA: + return n->mem_alloc.tid; + case SPL_IR_MEM_GLOBAL_ALLOC: + return n->mem_global_alloc.tid; + case SPL_IR_MEM_LOAD: + return n->mem_load.tid; + case SPL_IR_MEM_OFFSET: + return n->mem_offset.tid; + case SPL_IR_MEM_FIELD_PTR: + return n->mem_field_ptr.tid; + case SPL_IR_TYPE_CONST: + return n->type_const.tid; + case SPL_IR_TYPE_BITSIZEOF: + return n->bitsizeof.tid; + case SPL_IR_TYPE_SIZEOF: + return n->ir_sizeof.tid; + case SPL_IR_TYPE_ALIGNOF: + return n->ir_alignof.tid; + case SPL_IR_TYPE_OFFSETOF: + return n->ir_offsetof.tid; + case SPL_IR_TYPE_FIELD_COUNT: + return n->field_count.tid; + case SPL_IR_AGG_CONSTRUCT: + return n->agg_construct.tid; + case SPL_IR_AGG_EXTRACT: + return n->agg_extract.field_tid; + case SPL_IR_AGG_INSERT: + return n->agg_insert.tid; + case SPL_IR_CONTROL_SELECT: + return n->control_select.tid; + case SPL_IR_CONTROL_CALL: + return n->control_call.tid; + case SPL_IR_CONTROL_PARAM: + return n->control_param.tid; + default: + return 0; + } +} + +static usize align_up(usize x, usize a) { + if (a <= 1) + return x; + return (x + a - 1) / a * a; +} + +typedef struct { + usize result_off; + usize data_off; +} slot_t; + +typedef struct { + VEC(slot_t) slots; + usize args_bytes; + usize frame_bytes; +} frame_layout_t; + +static usize node_data_size(spl_ir2vm_t *ctx, const spl_ir_func_t *f, const spl_ir_node_t *node) { + switch (node->kind) { + case SPL_IR_MEM_ALLOCA: { + usize count = 1; + if (node->mem_alloc.count < vec_size(f->nodes)) { + const spl_ir_node_t *cn = &vec_at(f->nodes, node->mem_alloc.count); + if (cn->kind == SPL_IR_TYPE_CONST) + count = (usize)cn->type_const.int_lit; + } + if (count == 0) + count = 1; + usize sz = ir_type_size(ctx, node->mem_alloc.tid); + if (sz == 0) + sz = 1; + return sz * count; + } + case SPL_IR_AGG_CONSTRUCT: + case SPL_IR_AGG_INSERT: { + usize sz = ir_type_size(ctx, node->agg_construct.tid); + return sz ? sz : 8; + } + case SPL_IR_AGG_EXTRACT: + if (ir_is_aggregate(ctx, node->agg_extract.field_tid)) + return ir_type_size(ctx, node->agg_extract.field_tid); + return 0; + case SPL_IR_MEM_LOAD: + if (ir_is_aggregate(ctx, node->mem_load.tid)) + return ir_type_size(ctx, node->mem_load.tid); + return 0; + case SPL_IR_CONTROL_CALL: + if (ir_is_aggregate(ctx, node->control_call.tid)) + return ir_type_size(ctx, node->control_call.tid); + return 0; + case SPL_IR_TYPE_CONST: { + spl_type_node_t *tn = spl_type_node(ctx->type, node->type_const.tid); + if (tn && (tn->kind == SPL_TYPE_STRUCT || tn->kind == SPL_TYPE_ARRAY || + tn->kind == SPL_TYPE_UNION)) + return ir_type_size(ctx, node->type_const.tid); + return 0; + } + default: + return 0; + } +} + +static void frame_build(frame_layout_t *fl, spl_ir2vm_t *ctx, spl_ir_func_ref_t fid) { + vec_init(fl->slots); + fl->args_bytes = 0; + fl->frame_bytes = 0; + + const spl_ir_func_t *f = spl_ir_func((spl_ir_t *)ctx->ir, fid); + if (!f) + return; + + usize n = vec_size(f->nodes); + for (usize i = 0; i < n; ++i) + vec_push(fl->slots, (slot_t){0}); + + spl_type_node_t *ftn = spl_type_node(ctx->type, f->fn_tid); + usize nargs = (ftn && ftn->kind == SPL_TYPE_FN) ? vec_size(ftn->fn_type.params) : 0; + fl->args_bytes = nargs * sizeof(spl_vm_val_t); + + usize off = fl->args_bytes; + + for (usize i = 1; i < n; ++i) { + const spl_ir_node_t *node = &vec_at(f->nodes, i); + if (ir_result_tid(node)) { + vec_at(fl->slots, i).result_off = off; + off += sizeof(spl_vm_val_t); + } + usize extra = node_data_size(ctx, f, node); + if (extra) { + off = align_up(off, 8); + vec_at(fl->slots, i).data_off = off; + off += align_up(extra, 8); + } + } + + fl->frame_bytes = align_up(off, 8); +} + +static void frame_drop(frame_layout_t *fl) { vec_free(fl->slots); } + +typedef enum { + FIX_JMP, + FIX_FNADDR, +} fix_kind_t; + +typedef struct { + fix_kind_t kind; + usize ins_idx; + spl_ir_node_ref_t node_target; + spl_ir_func_ref_t fn_target; +} fix_t; +typedef VEC(fix_t) fix_vec_t; + +typedef struct { + spl_ir2vm_t *ctx; + spl_ir_func_ref_t fid; + const spl_ir_func_t *irf; + frame_layout_t frame; + VEC(usize) node_ip; + fix_vec_t *fixups; +} cgen_t; + +static void emit(cgen_t *cg, uint8_t op, uint8_t ty, spl_vm_val_t imm) { + spl_vm_ins_t ins = {.opcode = op, .type = ty, .imm = imm}; + vec_push(cg->ctx->prog.insns, ins); +} + +static usize ip_of(cgen_t *cg) { return vec_size(cg->ctx->prog.insns); } + +static void CG_LADDR(cgen_t *cg, usize off) { emit(cg, SPL_LADDR, SPL_VOID, off); } +static void CG_LOAD(cgen_t *cg, uint8_t k) { emit(cg, SPL_LOAD, k, 0); } +static void CG_STORE(cgen_t *cg, uint8_t k) { emit(cg, SPL_STORE, k, 0); } +static void CG_PUSH(cgen_t *cg, uint8_t k, spl_vm_val_t v) { emit(cg, SPL_PUSH, k, v); } +static void CG_OP(cgen_t *cg, uint8_t op, uint8_t k) { emit(cg, op, k, 0); } +static void CG_SWAP(cgen_t *cg) { emit(cg, SPL_SWAP, SPL_VOID, 0); } +static void CG_GADDR(cgen_t *cg, spl_vm_val_t idx) { emit(cg, SPL_GADDR, SPL_VOID, idx); } + +static void cg_load_slot(cgen_t *cg, usize ref, uint8_t k) { + CG_LADDR(cg, vec_at(cg->frame.slots, ref).result_off); + CG_LOAD(cg, k); +} + +static void cg_store_slot(cgen_t *cg, usize ref, uint8_t k) { + CG_LADDR(cg, vec_at(cg->frame.slots, ref).result_off); + CG_SWAP(cg); + CG_STORE(cg, k); +} + +static void cg_store_at(cgen_t *cg, usize addr, uint8_t k) { + CG_LADDR(cg, addr); + CG_SWAP(cg); + CG_STORE(cg, k); +} + +typedef struct { + bool indirect; + usize off; + usize base; +} data_loc_t; + +static data_loc_t direct_data(usize off) { + return (data_loc_t){.indirect = false, .off = off, .base = 0}; +} +static data_loc_t direct_data_base(usize off, usize base) { + return (data_loc_t){.indirect = false, .off = off, .base = base}; +} +static data_loc_t ptr_slot(usize slot_off) { + return (data_loc_t){.indirect = true, .off = slot_off, .base = 0}; +} +static data_loc_t ptr_slot_base(usize slot_off, usize base) { + return (data_loc_t){.indirect = true, .off = slot_off, .base = base}; +} + +static void cg_push_addr(cgen_t *cg, data_loc_t loc, usize extra) { + usize delta = loc.base + extra; + if (loc.indirect) { + CG_LADDR(cg, loc.off); + CG_LOAD(cg, SPL_PTR); + if (delta) { + CG_PUSH(cg, SPL_U64, delta); + CG_OP(cg, SPL_ADD, SPL_PTR); + } + } else { + CG_LADDR(cg, loc.off + delta); + } +} + +static void cg_copy_agg(cgen_t *cg, data_loc_t src, data_loc_t dst, spl_type_id_t tid) { + usize sz = ir_type_size(cg->ctx, tid); + usize done = 0; + while (sz - done >= 8) { + cg_push_addr(cg, dst, done); + cg_push_addr(cg, src, done); + CG_LOAD(cg, SPL_U64); + CG_STORE(cg, SPL_U64); + done += 8; + } + while (done < sz) { + cg_push_addr(cg, dst, done); + cg_push_addr(cg, src, done); + CG_LOAD(cg, SPL_U8); + CG_STORE(cg, SPL_U8); + done += 1; + } +} + +static void cg_add_fix(cgen_t *cg, usize ins_idx, fix_kind_t kind, spl_ir_node_ref_t node_target, + spl_ir_func_ref_t fn_target) { + fix_t fx = { + .kind = kind, .ins_idx = ins_idx, .node_target = node_target, .fn_target = fn_target}; + vec_push(*cg->fixups, fx); +} + +static void cg_binop(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) { + uint8_t k = vm_kind_of(cg->ctx, n->arith.tid); + cg_load_slot(cg, n->arith.left, k); + cg_load_slot(cg, n->arith.right, k); + CG_OP(cg, op, k); + cg_store_slot(cg, ref, k); +} + +static void cg_unop(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) { + uint8_t k = vm_kind_of(cg->ctx, n->arith.tid); + cg_load_slot(cg, n->arith.left, k); + CG_OP(cg, op, k); + cg_store_slot(cg, ref, k); +} + +static void cg_cmp(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) { + uint8_t k = vm_kind_of(cg->ctx, n->cmp.tid); + cg_load_slot(cg, n->cmp.a, k); + cg_load_slot(cg, n->cmp.b, k); + CG_OP(cg, op, k); + cg_store_slot(cg, ref, SPL_BOOL); +} + +static void cg_const(cgen_t *cg, usize ref, const spl_ir_node_t *n) { + spl_ir2vm_t *ctx = cg->ctx; + spl_type_id_t tid = n->type_const.tid; + spl_type_node_t *tn = spl_type_node(ctx->type, tid); + if (!tn) + return; + + if (tn->kind == SPL_TYPE_FN) { + usize idx = ip_of(cg); + CG_PUSH(cg, SPL_PTR, 0); + cg_add_fix(cg, idx, FIX_FNADDR, 0, n->type_const.fn); + cg_store_slot(cg, ref, SPL_PTR); + return; + } + + if (tn->kind == SPL_TYPE_STRUCT || tn->kind == SPL_TYPE_ARRAY || tn->kind == SPL_TYPE_UNION) { + const char *bytes = (const char *)n->type_const.ptr_lit; + if (!bytes) + bytes = ""; + usize len = strlen(bytes); + usize data_idx = (usize)spl_prog_add_data(&ctx->prog, (void *)bytes, len + 1); + usize base = vec_at(cg->frame.slots, ref).data_off; + usize ptr_off = ir_agg_field_off(ctx, tid, 0); + usize len_off = ir_agg_field_off(ctx, tid, 1); + + CG_GADDR(cg, data_idx); + cg_store_at(cg, base + ptr_off, SPL_PTR); + + CG_PUSH(cg, SPL_U64, len); + cg_store_at(cg, base + len_off, SPL_U64); + + CG_LADDR(cg, base); + cg_store_slot(cg, ref, SPL_PTR); + return; + } + + uint8_t k = vm_kind_of(ctx, tid); + spl_vm_val_t imm = 0; + switch (tn->kind) { + case SPL_TYPE_BOOL: + imm = n->type_const.bool_lit ? 1 : 0; break; + case SPL_TYPE_INT: + if (tn->int_type.bits == 8) + imm = (spl_vm_val_t)(unsigned char)n->type_const.ch_lit; + else + imm = (spl_vm_val_t)n->type_const.int_lit; + break; + case SPL_TYPE_FLOAT: + memcpy(&imm, &n->type_const.float_lit, sizeof(double)); + break; + case SPL_TYPE_PTR: + imm = (spl_vm_val_t)(usize)n->type_const.ptr_lit; + break; + case SPL_TYPE_UNIT: + return; default: break; } - return pos; + CG_PUSH(cg, k, imm); + cg_store_slot(cg, ref, k); +} + +static void cg_cast(cgen_t *cg, usize ref, const spl_ir_node_t *n) { + spl_ir2vm_t *ctx = cg->ctx; + spl_type_node_t *ft = spl_type_node(ctx->type, n->cast.from_tid); + spl_type_node_t *tt = spl_type_node(ctx->type, n->cast.to_tid); + if (!ft || !tt) + return; + + uint8_t fk = vm_kind_of(ctx, n->cast.from_tid); + uint8_t tk = vm_kind_of(ctx, n->cast.to_tid); + + cg_load_slot(cg, n->cast.val, fk); + + if (ft->kind == SPL_TYPE_INT && tt->kind == SPL_TYPE_INT) { + usize fb = ft->int_type.bits; + usize tb = tt->int_type.bits; + if (fb > tb) + emit(cg, SPL_TRUNC, SPL_VOID, tb); + else if (fb < tb) + emit(cg, ft->int_type.is_signed ? SPL_SEXT : SPL_ZEXT, SPL_VOID, fb); + } else if (ft->kind == SPL_TYPE_BOOL && tt->kind == SPL_TYPE_INT) { + emit(cg, SPL_ZEXT, SPL_VOID, 1); + } + + cg_store_slot(cg, ref, tk); +} + +static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) { + spl_ir2vm_t *ctx = cg->ctx; + switch (n->kind) { + + case SPL_IR_MEM_ALLOCA: { + CG_LADDR(cg, vec_at(cg->frame.slots, ref).data_off); + cg_store_slot(cg, ref, SPL_PTR); + break; + } + + case SPL_IR_MEM_LOAD: { + spl_type_id_t tid = n->mem_load.tid; + if (ir_is_aggregate(ctx, tid)) { + usize data = vec_at(cg->frame.slots, ref).data_off; + cg_copy_agg(cg, ptr_slot(vec_at(cg->frame.slots, n->mem_load.ptr).result_off), + direct_data(data), tid); + CG_LADDR(cg, data); + cg_store_slot(cg, ref, SPL_PTR); + } else { + uint8_t k = vm_kind_of(ctx, tid); + cg_load_slot(cg, n->mem_load.ptr, SPL_PTR); + CG_LOAD(cg, k); + cg_store_slot(cg, ref, k); + } + break; + } + + case SPL_IR_MEM_STORE: { + spl_type_id_t tid = n->mem_store.tid; + if (ir_is_aggregate(ctx, tid)) { + cg_copy_agg(cg, ptr_slot(vec_at(cg->frame.slots, n->mem_store.val).result_off), + ptr_slot(vec_at(cg->frame.slots, n->mem_store.ptr).result_off), tid); + } else { + uint8_t k = vm_kind_of(ctx, tid); + cg_load_slot(cg, n->mem_store.ptr, SPL_PTR); + cg_load_slot(cg, n->mem_store.val, k); + CG_STORE(cg, k); + } + break; + } + + case SPL_IR_MEM_OFFSET: { + usize elem_size = ir_type_size(ctx, n->mem_offset.tid); + if (elem_size == 0) + elem_size = 1; + cg_load_slot(cg, n->mem_offset.ptr, SPL_PTR); + cg_load_slot(cg, n->mem_offset.offset, SPL_U64); + CG_PUSH(cg, SPL_U64, elem_size); + CG_OP(cg, SPL_MUL, SPL_U64); + CG_OP(cg, SPL_ADD, SPL_PTR); + cg_store_slot(cg, ref, SPL_PTR); + break; + } + + case SPL_IR_MEM_FIELD_PTR: { + spl_type_id_t agg_tid = n->mem_field_ptr.tid; + usize off = ir_agg_field_off(ctx, agg_tid, n->mem_field_ptr.field_idx); + cg_load_slot(cg, n->mem_field_ptr.agg, SPL_PTR); + if (off) { + CG_PUSH(cg, SPL_U64, off); + CG_OP(cg, SPL_ADD, SPL_PTR); + } + cg_store_slot(cg, ref, SPL_PTR); + break; + } + + default: + break; + } +} + +static void cg_agg(cgen_t *cg, usize ref, const spl_ir_node_t *n) { + spl_ir2vm_t *ctx = cg->ctx; + switch (n->kind) { + + case SPL_IR_AGG_CONSTRUCT: { + usize base = vec_at(cg->frame.slots, ref).data_off; + spl_type_id_t agg_t = n->agg_construct.tid; + + for (usize i = 0; i < vec_size(n->agg_construct.fields); ++i) { + spl_ir_node_ref_t fref = vec_at(n->agg_construct.fields, i); + spl_type_id_t ftid = ir_agg_field_tid(ctx, agg_t, i); + if (!ftid) + continue; + usize foff = ir_agg_field_off(ctx, agg_t, i); + + if (ir_is_aggregate(ctx, ftid)) { + cg_copy_agg(cg, ptr_slot(vec_at(cg->frame.slots, fref).result_off), + direct_data_base(base, foff), ftid); + } else { + uint8_t fk = vm_kind_of(ctx, ftid); + cg_load_slot(cg, fref, fk); + cg_store_at(cg, base + foff, fk); + } + } + CG_LADDR(cg, base); + cg_store_slot(cg, ref, SPL_PTR); + break; + } + + case SPL_IR_AGG_EXTRACT: { + spl_type_id_t agg_t = n->agg_extract.tid; + spl_type_id_t ftid = n->agg_extract.field_tid; + usize foff = ir_agg_field_off(ctx, agg_t, n->agg_extract.field_idx); + + if (ir_is_aggregate(ctx, ftid)) { + usize data = vec_at(cg->frame.slots, ref).data_off; + cg_copy_agg(cg, + ptr_slot_base(vec_at(cg->frame.slots, n->agg_extract.val).result_off, foff), + direct_data(data), ftid); + CG_LADDR(cg, data); + cg_store_slot(cg, ref, SPL_PTR); + } else { + uint8_t fk = vm_kind_of(ctx, ftid); + cg_load_slot(cg, n->agg_extract.val, SPL_PTR); + if (foff) { + CG_PUSH(cg, SPL_U64, foff); + CG_OP(cg, SPL_ADD, SPL_PTR); + } + CG_LOAD(cg, fk); + cg_store_slot(cg, ref, fk); + } + break; + } + + case SPL_IR_AGG_INSERT: { + usize base = vec_at(cg->frame.slots, ref).data_off; + spl_type_id_t agg_t = n->agg_insert.tid; + + cg_copy_agg(cg, ptr_slot(vec_at(cg->frame.slots, n->agg_insert.agg).result_off), + direct_data(base), agg_t); + + usize foff = ir_agg_field_off(ctx, agg_t, n->agg_insert.field_idx); + spl_type_id_t ftid = ir_agg_field_tid(ctx, agg_t, n->agg_insert.field_idx); + if (ftid) { + if (ir_is_aggregate(ctx, ftid)) { + cg_copy_agg(cg, ptr_slot(vec_at(cg->frame.slots, n->agg_insert.field).result_off), + direct_data_base(base, foff), ftid); + } else { + uint8_t fk = vm_kind_of(ctx, ftid); + cg_load_slot(cg, n->agg_insert.field, fk); + cg_store_at(cg, base + foff, fk); + } + } + + CG_LADDR(cg, base); + cg_store_slot(cg, ref, SPL_PTR); + break; + } + + default: + break; + } +} + +static void cg_typeop(cgen_t *cg, usize ref, const spl_ir_node_t *n) { + spl_ir2vm_t *ctx = cg->ctx; + usize v = 0; + switch (n->kind) { + case SPL_IR_TYPE_SIZEOF: + v = ir_type_size(ctx, n->ir_sizeof.tid); + break; + case SPL_IR_TYPE_BITSIZEOF: + v = ir_type_size(ctx, n->bitsizeof.tid) * 8; + break; + case SPL_IR_TYPE_ALIGNOF: + v = ir_type_size(ctx, n->ir_alignof.tid); + break; + default: + return; + } + CG_PUSH(cg, SPL_U64, v); + cg_store_slot(cg, ref, SPL_U64); +} + +static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { + spl_ir2vm_t *ctx = cg->ctx; + switch (n->kind) { + + case SPL_IR_CONTROL_PARAM: { + uint8_t k = vm_kind_of(ctx, n->control_param.tid); + usize idx = 0; + if (n->control_param.idx < vec_size(cg->irf->nodes)) { + const spl_ir_node_t *idx_node = &vec_at(cg->irf->nodes, n->control_param.idx); + if (idx_node->kind == SPL_IR_TYPE_CONST) + idx = (usize)idx_node->type_const.int_lit; + } + CG_LADDR(cg, idx * sizeof(spl_vm_val_t)); + CG_LOAD(cg, k); + cg_store_slot(cg, ref, k); + break; + } + + case SPL_IR_CONTROL_RET: { + uint8_t k = vm_kind_of(ctx, n->control_ret.tid); + if (k != SPL_VOID && n->control_ret.val) + cg_load_slot(cg, n->control_ret.val, k); + emit(cg, SPL_RET, k, 0); + break; + } + + case SPL_IR_CONTROL_BR: { + cg_load_slot(cg, n->control_br.cond, SPL_BOOL); + usize bz_idx = ip_of(cg); + emit(cg, SPL_BZ, SPL_VOID, 0); + cg_add_fix(cg, bz_idx, FIX_JMP, n->control_br.false_label, 0); + usize jmp_idx = ip_of(cg); + emit(cg, SPL_JMP, SPL_VOID, 0); + cg_add_fix(cg, jmp_idx, FIX_JMP, n->control_br.true_label, 0); + break; + } + + case SPL_IR_CONTROL_JMP: { + usize idx = ip_of(cg); + emit(cg, SPL_JMP, SPL_VOID, 0); + cg_add_fix(cg, idx, FIX_JMP, n->control_jmp.label, 0); + break; + } + + case SPL_IR_CONTROL_CALL: { + usize nargs = vec_size(n->control_call.params); + for (usize i = 0; i < nargs; ++i) { + spl_ir_node_ref_t pref = vec_at(n->control_call.params, i); + const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref); + spl_type_id_t ptid = ir_result_tid(pn); + uint8_t pk = vm_kind_of(ctx, ptid); + cg_load_slot(cg, pref, pk); + } + + bool direct = false; + spl_ir_node_ref_t fref = n->control_call.func; + if (fref < vec_size(cg->irf->nodes)) { + const spl_ir_node_t *fn_node = &vec_at(cg->irf->nodes, fref); + if (fn_node->kind == SPL_IR_TYPE_CONST) { + spl_type_node_t *ftn = spl_type_node(ctx->type, fn_node->type_const.tid); + if (ftn && ftn->kind == SPL_TYPE_FN) { + usize idx = ip_of(cg); + CG_PUSH(cg, SPL_PTR, 0); + cg_add_fix(cg, idx, FIX_FNADDR, 0, fn_node->type_const.fn); + emit(cg, SPL_CALL, SPL_VOID, nargs); + direct = true; + } + } + } + if (!direct) + emit(cg, SPL_HALT, SPL_VOID, 0); + + spl_type_id_t rtid = n->control_call.tid; + if (ir_is_aggregate(ctx, rtid)) { + cg_store_slot(cg, ref, SPL_PTR); + usize data = vec_at(cg->frame.slots, ref).data_off; + cg_copy_agg(cg, ptr_slot(vec_at(cg->frame.slots, ref).result_off), direct_data(data), + rtid); + CG_LADDR(cg, data); + cg_store_slot(cg, ref, SPL_PTR); + } else { + uint8_t rk = vm_kind_of(ctx, rtid); + if (rk != SPL_VOID) + cg_store_slot(cg, ref, rk); + } + break; + } + + case SPL_IR_CONTROL_UNREACHABLE: + case SPL_IR_CONTROL_TRAP: + emit(cg, SPL_HALT, SPL_VOID, 0); + break; + + default: + break; + } +} + +static void cg_node(cgen_t *cg, usize ref, const spl_ir_node_t *n) { + switch (n->kind) { + case SPL_IR_TYPE_CONST: + cg_const(cg, ref, n); + break; + + case SPL_IR_ARITH_ADD: + cg_binop(cg, ref, n, SPL_ADD); + break; + case SPL_IR_ARITH_SUB: + cg_binop(cg, ref, n, SPL_SUB); + break; + case SPL_IR_ARITH_MUL: + cg_binop(cg, ref, n, SPL_MUL); + break; + case SPL_IR_ARITH_DIV: { + spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->arith.tid); + bool sgn = tn && tn->kind == SPL_TYPE_INT && tn->int_type.is_signed; + cg_binop(cg, ref, n, sgn ? SPL_DIV_S : SPL_DIV_U); + break; + } + case SPL_IR_ARITH_REM: { + spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->arith.tid); + bool sgn = tn && tn->kind == SPL_TYPE_INT && tn->int_type.is_signed; + cg_binop(cg, ref, n, sgn ? SPL_REM_S : SPL_REM_U); + break; + } + case SPL_IR_ARITH_AND: + cg_binop(cg, ref, n, SPL_AND); + break; + case SPL_IR_ARITH_OR: + cg_binop(cg, ref, n, SPL_OR); + break; + case SPL_IR_ARITH_XOR: + cg_binop(cg, ref, n, SPL_XOR); + break; + case SPL_IR_ARITH_SHL: + cg_binop(cg, ref, n, SPL_SHL); + break; + case SPL_IR_ARITH_SHR: { + spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->arith.tid); + bool sgn = tn && tn->kind == SPL_TYPE_INT && tn->int_type.is_signed; + cg_binop(cg, ref, n, sgn ? SPL_SHR_S : SPL_SHR_U); + break; + } + case SPL_IR_ARITH_NEG: + cg_unop(cg, ref, n, SPL_NEG); + break; + case SPL_IR_ARITH_NOT: + cg_unop(cg, ref, n, SPL_NOT); + break; + case SPL_IR_ARITH_ABS: + break; + + case SPL_IR_CMP_EQ: + cg_cmp(cg, ref, n, SPL_EQ); + break; + case SPL_IR_CMP_NE: + cg_cmp(cg, ref, n, SPL_NE); + break; + case SPL_IR_CMP_LT: { + spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->cmp.tid); + bool sgn = tn && tn->kind == SPL_TYPE_INT && tn->int_type.is_signed; + cg_cmp(cg, ref, n, sgn ? SPL_SLT : SPL_ULT); + break; + } + case SPL_IR_CMP_LE: { + spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->cmp.tid); + bool sgn = tn && tn->kind == SPL_TYPE_INT && tn->int_type.is_signed; + cg_cmp(cg, ref, n, sgn ? SPL_SLE : SPL_ULE); + break; + } + case SPL_IR_CMP_GT: { + spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->cmp.tid); + bool sgn = tn && tn->kind == SPL_TYPE_INT && tn->int_type.is_signed; + cg_cmp(cg, ref, n, sgn ? SPL_SGT : SPL_UGT); + break; + } + case SPL_IR_CMP_GE: { + spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->cmp.tid); + bool sgn = tn && tn->kind == SPL_TYPE_INT && tn->int_type.is_signed; + cg_cmp(cg, ref, n, sgn ? SPL_SGE : SPL_UGE); + break; + } + + case SPL_IR_CAST_TRUNC: + case SPL_IR_CAST_ZEXT: + case SPL_IR_CAST_SEXT: + case SPL_IR_CAST_FEXT: + case SPL_IR_CAST_FTRUNC: + case SPL_IR_CAST_BITCAST: + case SPL_IR_CAST_PTR2INT: + case SPL_IR_CAST_INT2PTR: + case SPL_IR_CAST_BOOL2INT: + case SPL_IR_CASE_INT2FLOAT: + case SPL_IR_CASE_FLOAT2INT: + cg_cast(cg, ref, n); + break; + + case SPL_IR_MEM_ALLOCA: + case SPL_IR_MEM_LOAD: + case SPL_IR_MEM_STORE: + case SPL_IR_MEM_OFFSET: + case SPL_IR_MEM_FIELD_PTR: + cg_mem(cg, ref, n); + break; + + case SPL_IR_AGG_CONSTRUCT: + case SPL_IR_AGG_EXTRACT: + case SPL_IR_AGG_INSERT: + cg_agg(cg, ref, n); + break; + + case SPL_IR_TYPE_SIZEOF: + case SPL_IR_TYPE_BITSIZEOF: + case SPL_IR_TYPE_ALIGNOF: + cg_typeop(cg, ref, n); + break; + + case SPL_IR_CONTROL_PARAM: + case SPL_IR_CONTROL_RET: + case SPL_IR_CONTROL_BR: + case SPL_IR_CONTROL_JMP: + case SPL_IR_CONTROL_CALL: + case SPL_IR_CONTROL_UNREACHABLE: + case SPL_IR_CONTROL_TRAP: + cg_control(cg, ref, n); + break; + + case SPL_IR_DBG_BREAKPOINT: + emit(cg, SPL_BK, SPL_VOID, 0); + break; + + default: + break; + } +} + +static usize translate_function(spl_ir2vm_t *ctx, spl_ir_func_ref_t fid, fix_vec_t *all_fixups) { + const spl_ir_func_t *irf = spl_ir_func((spl_ir_t *)ctx->ir, fid); + if (!irf) + return 0; + + cgen_t cg = {0}; + cg.ctx = ctx; + cg.fid = fid; + cg.irf = irf; + frame_build(&cg.frame, ctx, fid); + + fix_vec_t local_fixups; + vec_init(local_fixups); + cg.fixups = &local_fixups; + + usize func_ip = ip_of(&cg); + + spl_vm_func_t entry = {0}; + entry.name = strdup(irf->name ? irf->name : ""); + entry.idx_of_strtab = 0; + spl_type_node_t *ftn = spl_type_node(ctx->type, irf->fn_tid); + entry.nargs = (ftn && ftn->kind == SPL_TYPE_FN) ? vec_size(ftn->fn_type.params) : 0; + entry.ninsns = 0; + entry.address = func_ip; + vec_push(ctx->prog.funcs, entry); + + usize local_slots = (cg.frame.frame_bytes - cg.frame.args_bytes + 7) / 8; + emit(&cg, SPL_ALLOC, SPL_VOID, local_slots); + + usize nnodes = vec_size(irf->nodes); + vec_init(cg.node_ip); + for (usize i = 0; i < nnodes; ++i) + vec_push(cg.node_ip, 0); + + for (usize i = 1; i < nnodes; ++i) { + vec_at(cg.node_ip, i) = ip_of(&cg); + cg_node(&cg, i, &vec_at(irf->nodes, i)); + } + + for (usize i = 0; i < vec_size(local_fixups); ++i) { + fix_t *fx = &vec_at(local_fixups, i); + if (fx->kind == FIX_JMP) { + spl_vm_ins_t *ins = &vec_at(ctx->prog.insns, fx->ins_idx); + usize target_ip = (fx->node_target < nnodes) ? vec_at(cg.node_ip, fx->node_target) : 0; + ins->imm = (spl_vm_val_t)(isize)(target_ip - fx->ins_idx - 1); + } else if (fx->kind == FIX_FNADDR) { + vec_push(*all_fixups, *fx); + } + } + + vec_free(cg.node_ip); + vec_free(local_fixups); + frame_drop(&cg.frame); + return func_ip; } void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type) { @@ -48,28 +969,47 @@ void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type spl_prog_init(&ctx->prog); } -void spl_ir2vm_drop(spl_ir2vm_t *ctx) { (void)ctx; } +void spl_ir2vm_drop(spl_ir2vm_t *ctx) { spl_prog_drop(&ctx->prog); } -int spl_ir2vm_run(spl_ir2vm_t *ctx) { - int addr = 0; - vec_for(ctx->ir->funcs, i) { - if (i == 0) { - continue; - } - spl_ir_func_t *fn = &vec_at(ctx->ir->funcs, i); - Assert(fn != NULL); - spl_vm_func_t vm_fn = {0}; - vm_fn.name = (char *)fn->name; // FIXME - vm_fn.address = addr; - vm_fn.nargs = 0; - vm_fn.ninsns = 0; - vec_for(fn->nodes, j) { - spl_ir_node_t *node = &vec_at(fn->nodes, j); - emit_instr(ctx, fn, node); - } - spl_prog_add_func(&ctx->prog, &vm_fn); - } +int spl_ir2vm_run_func(spl_ir2vm_t *ctx, spl_ir_func_ref_t ref) { + fix_vec_t all_fixups; + vec_init(all_fixups); + translate_function(ctx, ref, &all_fixups); + vec_free(all_fixups); return 0; } -void spl_ir2vm_dump(spl_ir2vm_t *ctx) { (void)ctx; } +int spl_ir2vm_run(spl_ir2vm_t *ctx) { + usize n = vec_size(ctx->ir->funcs); + if (n <= 1) + return 0; + + usize *fid_ip = calloc(n, sizeof(usize)); + fix_vec_t all_fixups; + vec_init(all_fixups); + + for (spl_ir_func_ref_t i = 1; i < n; ++i) + fid_ip[i] = translate_function(ctx, i, &all_fixups); + + for (usize i = 0; i < vec_size(all_fixups); ++i) { + fix_t *fx = &vec_at(all_fixups, i); + if (fx->kind != FIX_FNADDR) + continue; + spl_vm_ins_t *ins = &vec_at(ctx->prog.insns, fx->ins_idx); + usize target_ip = (fx->fn_target > 0 && fx->fn_target < n) ? fid_ip[fx->fn_target] : 0; + ins->imm = (spl_vm_val_t)target_ip; + } + + for (usize i = 0; i < vec_size(ctx->prog.funcs); ++i) { + spl_vm_func_t *f = &vec_at(ctx->prog.funcs, i); + usize next = (i + 1 < vec_size(ctx->prog.funcs)) ? vec_at(ctx->prog.funcs, i + 1).address + : vec_size(ctx->prog.insns); + f->ninsns = (spl_vm_val_t)(next - f->address); + } + + free(fid_ip); + vec_free(all_fixups); + return 0; +} + +void spl_ir2vm_dump(spl_ir2vm_t *ctx) { spl_prog_dump(&ctx->prog); } diff --git a/stage1/spl_ir2vm.h b/stage1/spl_ir2vm.h index 0c12908..012f1a0 100644 --- a/stage1/spl_ir2vm.h +++ b/stage1/spl_ir2vm.h @@ -24,6 +24,7 @@ typedef struct { void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type); void spl_ir2vm_drop(spl_ir2vm_t *ctx); +int spl_ir2vm_run_func(spl_ir2vm_t *ctx, spl_ir_func_ref_t ref); int spl_ir2vm_run(spl_ir2vm_t *ctx); void spl_ir2vm_dump(spl_ir2vm_t *ctx); diff --git a/stage1/spl_layout.c b/stage1/spl_layout.c index e69de29..9acd7e9 100644 --- a/stage1/spl_layout.c +++ b/stage1/spl_layout.c @@ -0,0 +1,266 @@ +#include "spl_layout.h" + +static void infos_grow(spl_layout_t *layout, usize n) { + while (vec_size(layout->infos) < n) { + spl_layout_info_t info = {0}; + vec_init(info.field_bit_offsets); + vec_init(info.field_bit_sizes); + vec_push(layout->infos, info); + } +} + +static spl_layout_info_t *infos_at(spl_layout_t *layout, spl_type_id_t id) { + if (id == 0 || id >= vec_size(layout->infos)) + return NULL; + return &vec_at(layout->infos, id); +} + +void spl_layout_add_scalar(spl_layout_t *layout, usize size, usize abi_align) { + spl_layout_scalar_t s = {0}; + s.size = size; + s.abi_align = abi_align; + s.pref_align = abi_align; + vec_init(s.invalid_values); + vec_push(layout->scalars, s); +} + +void spl_layout_add_ptr(spl_layout_t *layout, usize addr_space, usize size, usize align) { + spl_layout_ptr_t p = {0}; + p.add_space = addr_space; + p.ptr_size = size; + p.ptr_align = align; + vec_push(layout->pointers, p); +} + +void spl_layout_init(spl_layout_t *layout, spl_layout_target_t *target) { + vec_init(layout->scalars); + vec_init(layout->pointers); + vec_init(layout->infos); + layout->target = target; + + /* 默认聚合策略:按最大字段对齐,不允许重排 */ + layout->aggregate.allow_field_reordering = false; + layout->aggregate.align_rule = ALIGN_MAX; + layout->aggregate.fixed_align = 0; + + /* 常见 64 位平台的默认布局。 + 若目标平台不适用,调用者 clear 后自行 add_*。 */ + spl_layout_add_scalar(layout, 1, 1); /* i8 / u8 / bool */ + spl_layout_add_scalar(layout, 2, 2); /* i16 / u16 */ + spl_layout_add_scalar(layout, 4, 4); /* i32 / u32 / f32 */ + spl_layout_add_scalar(layout, 8, 8); /* i64 / u64 / f64 */ + + usize ps = sizeof(void *); + spl_layout_add_ptr(layout, 0, ps, ps); +} + +void spl_layout_drop(spl_layout_t *layout) { + for (usize i = 0; i < vec_size(layout->scalars); ++i) + vec_free(vec_at(layout->scalars, i).invalid_values); + vec_free(layout->scalars); + + vec_free(layout->pointers); + + for (usize i = 0; i < vec_size(layout->infos); ++i) { + vec_free(vec_at(layout->infos, i).field_bit_offsets); + vec_free(vec_at(layout->infos, i).field_bit_sizes); + } + vec_free(layout->infos); +} + +static const spl_layout_scalar_t *scalar_for_size(spl_layout_t *layout, usize size_bytes) { + for (usize i = 0; i < vec_size(layout->scalars); ++i) { + spl_layout_scalar_t *s = &vec_at(layout->scalars, i); + if (s->size == size_bytes) + return s; + } + return NULL; +} + +static const spl_layout_ptr_t *default_ptr(spl_layout_t *layout) { + if (vec_size(layout->pointers) == 0) + return NULL; + return &vec_at(layout->pointers, 0); +} + +static bool layout_scalar(spl_layout_t *layout, spl_type_node_t *tn, spl_layout_info_t *out) { + usize size_bits = 0; + switch (tn->kind) { + case SPL_TYPE_INT: + if (tn->int_type.bits == 0) + return false; /* comptime_int 未落地 */ + size_bits = tn->int_type.bits; + break; + case SPL_TYPE_FLOAT: + if (tn->float_type.bits == 0) + return false; /* comptime_float 未落地 */ + size_bits = tn->float_type.bits; + break; + case SPL_TYPE_BOOL: + size_bits = 8; + break; + default: + return false; + } + usize size_bytes = (size_bits + 7) / 8; + const spl_layout_scalar_t *sl = scalar_for_size(layout, size_bytes); + if (!sl) + return false; + + out->size_bits = sl->size * 8; + out->align_bits = sl->abi_align * 8; + return true; +} + +static bool layout_ptr(spl_layout_t *layout, spl_layout_info_t *out) { + const spl_layout_ptr_t *pl = default_ptr(layout); + if (!pl) + return false; + out->size_bits = pl->ptr_size * 8; + out->align_bits = pl->ptr_align * 8; + return true; +} + +static usize round_up_bits(usize x, usize align_bits) { + if (align_bits <= 1) + return x; + usize a = align_bits; + return (x + a - 1) / a * a; +} + +static bool layout_agg(spl_layout_t *layout, spl_type_node_t *tn, spl_layout_info_t *out) { + usize n = vec_size(tn->agg_type.variants); + if (n == 0) { + out->size_bits = 0; + out->align_bits = 8; + return true; + } + + usize max_align_bits = 8; + usize offset_bits = 0; + bool is_union = (tn->kind == SPL_TYPE_UNION); + + for (usize i = 0; i < n; ++i) { + spl_type_member_t *m = &vec_at(tn->agg_type.variants, i); + spl_layout_info_t *fi = infos_at(layout, m->type_id); + if (!fi || !fi->resolved) + return false; + + usize field_align_bits = fi->align_bits ? fi->align_bits : 8; + + if (is_union) { + vec_push(out->field_bit_offsets, 0); + vec_push(out->field_bit_sizes, fi->size_bits); + if (fi->size_bits > out->size_bits) + out->size_bits = fi->size_bits; + } else { + offset_bits = round_up_bits(offset_bits, field_align_bits); + vec_push(out->field_bit_offsets, offset_bits); + vec_push(out->field_bit_sizes, fi->size_bits); + offset_bits += fi->size_bits; + } + if (field_align_bits > max_align_bits) + max_align_bits = field_align_bits; + } + + /* 聚合对齐策略 */ + usize final_align_bits = max_align_bits; + if (layout->aggregate.align_rule == ALIGN_FIXED) { + final_align_bits = layout->aggregate.fixed_align * 8; + } else if (layout->aggregate.align_rule == ALIGN_MAX_WITH_MIN) { + usize min_bits = layout->aggregate.fixed_align * 8; + if (final_align_bits < min_bits) + final_align_bits = min_bits; + } + + if (is_union) + out->size_bits = round_up_bits(out->size_bits, final_align_bits); + else + out->size_bits = round_up_bits(offset_bits, final_align_bits); + out->align_bits = final_align_bits; + return true; +} + +static void resolve_type(spl_layout_t *layout, spl_type_t *type, spl_type_id_t id) { + spl_layout_info_t *info = infos_at(layout, id); + if (!info || info->resolved) + return; + + spl_type_node_t *tn = spl_type_node(type, id); + if (!tn) + return; + + /* 先标记已解析:自引用类型(通过 ptr)不会无限递归, + 但保持防御性写法。 */ + info->resolved = true; + + switch (tn->kind) { + case SPL_TYPE_ERROR: + case SPL_TYPE_INFER: + case SPL_TYPE_FORALL: + case SPL_TYPE_EXISTS: + case SPL_TYPE_NEVER: + case SPL_TYPE_UNIT: + info->size_bits = 0; + info->align_bits = 8; + return; + + case SPL_TYPE_ANY: + /* 顶层类型:stage1 按不透明指针处理 */ + layout_ptr(layout, info); + return; + + case SPL_TYPE_BOOL: + case SPL_TYPE_INT: + case SPL_TYPE_FLOAT: + layout_scalar(layout, tn, info); + return; + + case SPL_TYPE_PTR: + layout_ptr(layout, info); + return; + + case SPL_TYPE_ARRAY: { + resolve_type(layout, type, tn->array_type.element); + spl_layout_info_t *elem = infos_at(layout, tn->array_type.element); + if (!elem || !elem->resolved) + return; + info->size_bits = elem->size_bits * tn->array_type.len; + info->align_bits = elem->align_bits; + return; + } + + case SPL_TYPE_STRUCT: + case SPL_TYPE_UNION: + case SPL_TYPE_ENUM: + case SPL_TYPE_SHAPE: { + for (usize i = 0; i < vec_size(tn->agg_type.variants); ++i) { + spl_type_member_t *m = &vec_at(tn->agg_type.variants, i); + resolve_type(layout, type, m->type_id); + } + layout_agg(layout, tn, info); + return; + } + + case SPL_TYPE_FN: + /* 函数类型按函数指针布局 */ + for (usize i = 0; i < vec_size(tn->fn_type.params); ++i) + resolve_type(layout, type, vec_at(tn->fn_type.params, i)); + resolve_type(layout, type, tn->fn_type.ret); + layout_ptr(layout, info); + return; + } +} + +void spl_layout_resolve(spl_layout_t *layout, spl_type_t *type) { + infos_grow(layout, vec_size(type->type_table)); + for (usize i = 1; i < vec_size(type->type_table); ++i) + resolve_type(layout, type, i); +} + +const spl_layout_info_t *spl_layout_info_of(spl_layout_t *layout, spl_type_id_t id) { + spl_layout_info_t *info = infos_at(layout, id); + if (!info || !info->resolved) + return NULL; + return info; +} diff --git a/stage1/spl_layout.h b/stage1/spl_layout.h index e69de29..820d41c 100644 --- a/stage1/spl_layout.h +++ b/stage1/spl_layout.h @@ -0,0 +1,56 @@ +#ifndef __SPL_LAYOUT_H__ +#define __SPL_LAYOUT_H__ + +#include "spl_type.h" + +typedef struct { + usize size; + usize abi_align; + usize pref_align; + VEC(usize) invalid_values; +} spl_layout_scalar_t; + +typedef struct { + usize add_space; + usize ptr_size; + usize ptr_align; +} spl_layout_ptr_t; + +typedef struct { + bool allow_field_reordering; + enum { ALIGN_MAX, ALIGN_FIXED, ALIGN_MAX_WITH_MIN } align_rule; + usize fixed_align; +} spl_layout_agg_t; + +typedef struct { + usize size_bits; + usize align_bits; + VEC(usize) field_bit_offsets; + VEC(usize) field_bit_sizes; + bool resolved; +} spl_layout_info_t; + +typedef struct { + enum { SPL_BIG_ENDIAN, SPL_LITTLE_ENDIAN } endian; // TODO 更多位存储方式 + +} spl_layout_target_t; + +typedef struct { + VEC(spl_layout_scalar_t) scalars; + VEC(spl_layout_ptr_t) pointers; + spl_layout_agg_t aggregate; + VEC(spl_layout_info_t) infos; + spl_layout_target_t *target; +} spl_layout_t; + +void spl_layout_init(spl_layout_t *layout, spl_layout_target_t *target); +void spl_layout_drop(spl_layout_t *layout); + +void spl_layout_resolve(spl_layout_t *layout, spl_type_t *type); + +void spl_layout_add_scalar(spl_layout_t *layout, usize size, usize abi_align); +void spl_layout_add_ptr(spl_layout_t *layout, usize addr_space, usize size, usize align); + +const spl_layout_info_t *spl_layout_info_of(spl_layout_t *layout, spl_type_id_t id); + +#endif /* __SPL_LAYOUT_H__ */ diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index f63d9b7..bf7e977 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -309,58 +309,31 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, return bt; } - /* 比较:数值类型允许异构比较;其他走 balance */ if (op == SPL_OP_CMP_EQ || op == SPL_OP_CMP_NE || op == SPL_OP_CMP_LT || op == SPL_OP_CMP_LE || op == SPL_OP_CMP_GT || op == SPL_OP_CMP_GE) { - + /* 比较:结果 bool,节点存操作数类型;不依赖 expected */ spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); spl_lang_type_id_t rt = sema_infer(sema, n->binary.right); if (!lt || !rt) return 0; - spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt); - spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt); - bool l_num = ln && (ln->kind == SPL_LANG_TYPE_INT || ln->kind == SPL_LANG_TYPE_FLOAT); - bool r_num = rn && (rn->kind == SPL_LANG_TYPE_INT || rn->kind == SPL_LANG_TYPE_FLOAT); - - if (l_num && r_num) { - /* 数值比较:允许异构。仅当一侧 comptime 时把另一侧具体类型下推 */ - if (ln->kind == SPL_LANG_TYPE_INT && rn->kind == SPL_LANG_TYPE_INT) { - spl_type_node_t *lir = spl_type_node(sema->type, ln->ir_type_id); - spl_type_node_t *rir = spl_type_node(sema->type, rn->ir_type_id); - if (lir && lir->int_type.bits == 0) - sema_check(sema, n->binary.left, rt); - else if (rir && rir->int_type.bits == 0) - sema_check(sema, n->binary.right, lt); - } else if (ln->kind == SPL_LANG_TYPE_FLOAT && rn->kind == SPL_LANG_TYPE_FLOAT) { - spl_type_node_t *lir = spl_type_node(sema->type, ln->ir_type_id); - spl_type_node_t *rir = spl_type_node(sema->type, rn->ir_type_id); - if (lir && lir->float_type.bits == 0) - sema_check(sema, n->binary.left, rt); - else if (rir && rir->float_type.bits == 0) - sema_check(sema, n->binary.right, lt); - } - } else { - /* 非数值:要求 coerce 到共同类型 */ - spl_lang_type_id_t common = - (lt == rt) ? lt : spl_lang_type_balance(sema->type, lt, rt); - if (!common) { - SPL_ERROR(&n->dbg, "comparison operands type mismatch"); - sema->error_count++; - return 0; - } - if (!sema_check(sema, n->binary.left, common)) - return 0; - if (!sema_check(sema, n->binary.right, common)) - return 0; + spl_lang_type_id_t common = 0; + if (lt == rt) + common = lt; + else + common = spl_lang_type_balance(sema->type, lt, rt); + if (!common) { + SPL_ERROR(&n->dbg, "comparison operands type mismatch"); + sema->error_count++; + return 0; } - spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); - n->resolved_lang_tid = bt; - n->expected_lang_tid = 0; - return bt; - } + sema_check(sema, n->binary.left, common); + sema_check(sema, n->binary.right, common); + n->resolved_lang_tid = common; + return spl_lang_make_bool(sema->type); + } /* 算术 / 位 / 移位:两侧 check 到 expected */ if (!sema_check(sema, n->binary.left, expected)) return 0; @@ -665,25 +638,29 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { return bt; } - /* 比较 */ if (op == SPL_OP_CMP_EQ || op == SPL_OP_CMP_NE || op == SPL_OP_CMP_LT || op == SPL_OP_CMP_LE || op == SPL_OP_CMP_GT || op == SPL_OP_CMP_GE) { spl_lang_type_id_t lt = sema_infer(sema, n->binary.left); spl_lang_type_id_t rt = sema_infer(sema, n->binary.right); if (!lt || !rt) return 0; + spl_lang_type_id_t common = 0; if (lt == rt) common = lt; else common = spl_lang_type_balance(sema->type, lt, rt); - if (common) { - sema_check(sema, n->binary.left, common); - sema_check(sema, n->binary.right, common); + if (!common) { + SPL_ERROR(&n->dbg, "comparison operands type mismatch"); + sema->error_count++; + return 0; } - spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); - n->resolved_lang_tid = bt; - return bt; + + sema_check(sema, n->binary.left, common); + sema_check(sema, n->binary.right, common); + + n->resolved_lang_tid = common; + return spl_lang_make_bool(sema->type); } /* Range */ diff --git a/stage1/splc0.c b/stage1/splc0.c index 078b310..7eb288f 100644 --- a/stage1/splc0.c +++ b/stage1/splc0.c @@ -129,25 +129,25 @@ static int compile_spl(const char *src, const char *fname, const char *outpath, return 0; } - // spl_ir2vm_t ir2vm; - // spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, sema.type); - // int rc = spl_ir2vm_run(&ir2vm); - // if (rc != 0) { - // printf("ir2vm error %d", rc); - // return rc; - // } - // if (dump == DUMP_VM) { - // spl_prog_dump(&ir2vm.prog); - // // memory leak - // return 0; - // } + spl_ir2vm_t ir2vm; + spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, sema.type); + int rc = spl_ir2vm_run(&ir2vm); + if (rc != 0) { + printf("ir2vm error %d", rc); + return rc; + } + if (dump == DUMP_VM) { + spl_prog_dump(&ir2vm.prog); + // memory leak + return 0; + } - // spl_prog_store_to_file(outpath, &ir2vm.prog); + spl_prog_store_to_file(outpath, &ir2vm.prog); - // spl_ir2vm_drop(&ir2vm); - // spl_ast2ir_drop(&a2ir); - // spl_sema_drop(&sema); - // spl_ast_drop(&ast); + spl_ir2vm_drop(&ir2vm); + spl_ast2ir_drop(&a2ir); + spl_sema_drop(&sema); + spl_ast_drop(&ast); return 0; }