From f6a0bce9f0cfc122db6b55ecba2777092c52c2bd Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Wed, 16 Sep 2026 10:35:36 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20vm=20abi=E6=9B=B4=E6=96=B0=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E6=9B=B4=E5=A4=9A=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stage0/spl_mcode.h | 44 ++++++++++++++----------------------- stage1/spl_ast.c | 9 +++++--- stage1/spl_ast2ir.c | 28 +++++++++++++++++++++++- stage1/spl_ir2vm.c | 53 +++++++++++++++++++++++++++++++++++++++------ stage1/spl_sema.c | 37 +++++++++++++++++++++---------- stage1/spl_type.c | 13 ++++------- 6 files changed, 124 insertions(+), 60 deletions(-) diff --git a/stage0/spl_mcode.h b/stage0/spl_mcode.h index a71a0c6..ae7e0fb 100644 --- a/stage0/spl_mcode.h +++ b/stage0/spl_mcode.h @@ -115,38 +115,26 @@ typedef enum { * [strtab] each: slen, str(pad8) * [gdata] each: dsize(8), data(dsize bytes, padded to 8) * - * === Calling Convention === + * === Aggregate Return ABI (sret) === + * + * 凡返回值类型为聚合(struct / union / enum / array / shape), + * 采用调用者分配 / 被调用者填充的间接返回约定: * * Before CALL: - * - args pushed left-to-right - * - target address pushed last + * - caller 在自己的帧里 alloca 一块 RetTy 大小的空间 + * - 该空间的地址作为第 0 个实参先压栈 + * - 其余实参照常从左到右压栈 + * - target 地址最后压栈 + * - CALL imm = 普通实参个数 + 1 * - * CALL (imm = nargs): - * 1. pop target address - * 2. callstack[cp++] = {saved_fp, saved_ip, nargs} - * 3. fp = sp - nargs (fp points to arg0) - * 4. ip = target address + * Callee 进入后: + * - fp+0 存放 sret 指针 + * - 形参 i 位于 fp + 8*(i+1) + * - 返回值直接写入 *(fp+0),然后执行 RET void * - * ALLOC k: - * sp += k (slots zeroed; local[j] = stacks.data[fp + nargs + j]) - * - * LADDR imm: - * push &stacks.data[fp + imm] - * (imm < nargs accesses args; imm >= nargs accesses locals) - * - * GADDR imm: - * push prog->gdata[imm] (pointer to global data blob) - * - * RET: - * 1. pop retval if non-void type - * 2. sp = fp - * 3. pop frame; fp = saved_fp, ip = saved_ip - * 4. push retval if non-void type - * - * CALLI (indirect call): - * - stack before: ..., arg0, ..., argN-1, nargs, func_addr - * 1. pop func_addr, then pop nargs - * 2. same as CALL steps 2-4 + * Caller 侧: + * - 调用完成后,CALL 结果槽保存 sret 指针; + * 后续对聚合值的所有读取都通过该指针进行 */ #define SPL_BINFMT_MAGIC "SPLBIN\0\0" diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c index 3638efa..b1c7a47 100644 --- a/stage1/spl_ast.c +++ b/stage1/spl_ast.c @@ -175,11 +175,14 @@ static isize parse_int_literal(const spl_tok_t *t) { buf[j++] = t->lexeme[i]; } buf[j] = 0; + /* 字面量按无符号位模式解析,以容纳完整的 u64 值域 */ if (j >= 3 && buf[0] == '0' && (buf[1] == 'b' || buf[1] == 'B')) - return (isize)strtoll(buf + 2, NULL, 2); + return (isize)strtoull(buf + 2, NULL, 2); if (j >= 3 && buf[0] == '0' && (buf[1] == 'o' || buf[1] == 'O')) - return (isize)strtoll(buf + 2, NULL, 8); - return (isize)strtoll(buf, NULL, 0); + return (isize)strtoull(buf + 2, NULL, 8); + if (j >= 3 && buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) + return (isize)strtoull(buf, NULL, 16); + return (isize)strtoull(buf, NULL, 10); } static double parse_float_literal(const spl_tok_t *t) { diff --git a/stage1/spl_ast2ir.c b/stage1/spl_ast2ir.c index 0ea25cf..745bc5f 100644 --- a/stage1/spl_ast2ir.c +++ b/stage1/spl_ast2ir.c @@ -630,6 +630,16 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) return 0; } } + case SPL_OP_BOOL_OR: { + spl_ast_node_t *bmln = spl_ast_node(a->sema->ast, n->binary.left); + spl_type_id_t op_tid = bmln ? node_ir(a, bmln) : 0; + return spl_ir_builder_arith_or(a->ir, op_tid, l, r); + } + case SPL_OP_BOOL_AND: { + spl_ast_node_t *bmln = spl_ast_node(a->sema->ast, n->binary.left); + spl_type_id_t op_tid = bmln ? node_ir(a, bmln) : 0; + return spl_ir_builder_arith_and(a->ir, op_tid, l, r); + } default: return 0; } @@ -888,7 +898,23 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) 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); + /* base = 元素数据首地址 */ + spl_ir_node_ref_t base = 0; + if (obj_kind == SPL_LANG_TYPE_PTR) { + /* ptr 值本身就是首元素地址 */ + base = emit_expr(a, n->slice.obj); + } else if (obj_kind == SPL_LANG_TYPE_SLICE) { + /* 取 slice 的 ptr 字段 */ + spl_ir_node_ref_t slice_val = emit_expr(a, n->slice.obj); + if (!slice_val) + return 0; + spl_type_id_t ptr_ir = spl_type_builder_ptr((spl_type_t *)a->sema->type, elem_ir); + base = spl_ir_builder_agg_extract(a->ir, obj_ir, ptr_ir, SPL_SLICE_PTR_FIELD_IDX, + slice_val); + } else { + /* ARRAY:&arr 即首元素地址 */ + base = emit_lvalue(a, n->slice.obj); + } if (!base) return 0; diff --git a/stage1/spl_ir2vm.c b/stage1/spl_ir2vm.c index 52e0561..6a80eca 100644 --- a/stage1/spl_ir2vm.c +++ b/stage1/spl_ir2vm.c @@ -306,7 +306,10 @@ static void frame_build(frame_layout_t *fl, spl_ir2vm_t *ctx, spl_ir_func_ref_t 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); + spl_type_id_t ret_t = (ftn && ftn->kind == SPL_TYPE_FN) ? ftn->fn_type.ret : 0; + /* 聚合返回时 fp+0 是 caller 传入的 sret 指针,占用一个隐藏参数槽 */ + usize hidden_sret = ir_is_aggregate(ctx, ret_t) ? 1 : 0; + fl->args_bytes = (nargs + hidden_sret) * sizeof(spl_vm_val_t); usize off = fl->args_bytes; @@ -743,14 +746,35 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { 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)); + /* 聚合返回时 fp+0 是 sret 指针,实参从 fp+8 起 */ + spl_type_node_t *ftn = spl_type_node(ctx->type, cg->irf->fn_tid); + spl_type_id_t cur_ret = (ftn && ftn->kind == SPL_TYPE_FN) ? ftn->fn_type.ret : 0; + usize shift = ir_is_aggregate(ctx, cur_ret) ? 1 : 0; + CG_LADDR(cg, (idx + shift) * 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); + spl_type_id_t ret_tid = n->control_ret.tid; + if (ir_is_aggregate(ctx, ret_tid)) { + /* sret:把返回值写入 *(fp+0),然后以 void 返回 */ + if (n->control_ret.val) { + usize sz = ir_type_size(ctx, ret_tid); + CG_LADDR(cg, 0); + CG_LOAD(cg, SPL_PTR); + cg_load_slot(cg, n->control_ret.val, SPL_PTR); + CG_PUSH(cg, SPL_U64, sz); + int nat = get_or_add_native(ctx, "vm_memcpy"); + CG_PUSH(cg, SPL_U64, (spl_vm_val_t)nat); + emit(cg, SPL_NCALL, SPL_VOID, 3); + emit(cg, SPL_DROP, SPL_VOID, 0); + } + emit(cg, SPL_RET, SPL_VOID, 0); + break; + } + uint8_t k = vm_kind_of(ctx, 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); @@ -807,6 +831,14 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { else cg_store_slot(cg, ref, rk); } else { + spl_type_id_t ret_t = n->control_call.tid; + bool ret_is_sret = ir_is_aggregate(ctx, ret_t); + usize sret_off = 0; + + if (ret_is_sret) { + sret_off = vec_at(cg->frame.slots, ref).data_off; + CG_LADDR(cg, sret_off); + } 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); @@ -815,11 +847,18 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { cg_load_slot(cg, pref, pk); } cg_load_slot(cg, fref, SPL_PTR); - emit(cg, SPL_CALL, SPL_VOID, (spl_vm_val_t)nargs); + spl_vm_val_t actual_nargs = nargs + (ret_is_sret ? 1 : 0); + emit(cg, SPL_CALL, SPL_VOID, actual_nargs); - uint8_t rk = vm_kind_of(ctx, n->control_call.tid); - if (rk != SPL_VOID) - cg_store_slot(cg, ref, rk); + if (ret_is_sret) { + /* 结果槽保存 sret 指针,后续 agg_extract 把它当聚合首地址 */ + CG_LADDR(cg, sret_off); + cg_store_slot(cg, ref, SPL_PTR); + } else { + uint8_t rk = vm_kind_of(ctx, ret_t); + if (rk != SPL_VOID) + cg_store_slot(cg, ref, rk); + } } break; } diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index eeb55d8..2cc5f8b 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -260,7 +260,12 @@ static inline void sema_push_scope(spl_sema_t *sema) { } static inline void sema_pop_scope(spl_sema_t *sema) { - sema->scope->current_scope = sema->store_scope; + spl_scope_id_t cur = sema->scope->current_scope; + if (cur != 0 && cur < vec_size(sema->scope->scopes)) { + sema->scope->current_scope = vec_at(sema->scope->scopes, cur).parent; + } else { + sema->scope->current_scope = sema->store_scope; + } } static spl_lang_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_lang_type_id_t lang_tid) { @@ -869,18 +874,23 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, } case SPL_AST_EXPR_BLOCK: { + sema_push_scope(sema); for (usize i = 0; i < vec_size(n->block.stmts); ++i) sema_infer(sema, vec_at(n->block.stmts, i)); + spl_lang_type_id_t r = 0; if (n->block.tail_expr) { spl_lang_type_id_t t = sema_coerce(sema, n->block.tail_expr, expected); - if (!t) + if (!t) { + sema_pop_scope(sema); return 0; - n->resolved_lang_tid = t; - return t; + } + r = t; + } else { + r = spl_lang_make_unit(sema->type); } - spl_lang_type_id_t u = spl_lang_make_unit(sema->type); - n->resolved_lang_tid = u; - return u; + sema_pop_scope(sema); + n->resolved_lang_tid = r; + return r; } default: @@ -1218,11 +1228,12 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { if (!sema_coerce(sema, vec_at(n->call.args, i), pt)) return 0; } - /* varargs:默认提升到 isize */ + if (has_varargs) { - spl_lang_type_id_t vt = spl_lang_make_int(sema->type, sizeof(void *) * 8, 1); - for (usize i = fixed; i < nargs; ++i) - sema_coerce(sema, vec_at(n->call.args, i), vt); + for (usize i = fixed; i < nargs; ++i) { + if (!sema_infer(sema, vec_at(n->call.args, i))) + return 0; + } } spl_lang_type_id_t ret = fn->extra.fn.ret; @@ -1495,11 +1506,13 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { /* ---------- BLOCK ---------- */ case SPL_AST_EXPR_BLOCK: { + sema_push_scope(sema); spl_lang_type_id_t last = 0; for (usize i = 0; i < vec_size(n->block.stmts); ++i) - last = sema_infer(sema, vec_at(n->block.stmts, i)); + sema_infer(sema, vec_at(n->block.stmts, i)); if (n->block.tail_expr) last = sema_infer(sema, n->block.tail_expr); + sema_pop_scope(sema); n->resolved_lang_tid = last; return last; } diff --git a/stage1/spl_type.c b/stage1/spl_type.c index 8015aa3..1388491 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -575,20 +575,15 @@ bool spl_lang_mpa_int_fits(const spl_type_t *type, spl_lang_type_id_t target, sp if (bits == 0) return true; bool target_signed = ir->int_type.is_signed != 0; - - int64_t val = (int64_t)v.bits; + /* 字面量是无符号位模式:负号由 unary MINUS 承担 */ + uint64_t uval = v.bits; if (target_signed) { if (bits >= 64) return true; - int64_t lo = -((int64_t)1 << (bits - 1)); - int64_t hi = ((int64_t)1 << (bits - 1)) - 1; - return val >= lo && val <= hi; + uint64_t hi = ((uint64_t)1 << (bits - 1)) - 1; + return uval <= hi; } - - if (val < 0) - return false; - uint64_t uval = (uint64_t)val; if (bits >= 64) return true; uint64_t hi = ((uint64_t)1 << bits) - 1;