From 7cbe2d2b9a0a8f735370e84f4f3964eaef71c9c3 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Wed, 16 Sep 2026 11:36:29 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E9=87=8D=E5=88=B6=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E7=B3=BB=E7=BB=9F=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20=E6=8F=90=E4=BE=9B=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stage1/spl_ast2ir.c | 573 +++++++++++++++++++++++++++----------------- stage1/spl_ast2ir.h | 2 + stage1/spl_intrin.c | 51 ++++ stage1/spl_intrin.h | 15 +- stage1/spl_ir2vm.c | 2 +- stage1/spl_sema.c | 113 +++++++-- stage1/spl_sema.h | 1 + 7 files changed, 509 insertions(+), 248 deletions(-) diff --git a/stage1/spl_ast2ir.c b/stage1/spl_ast2ir.c index 745bc5f..7c5b2a9 100644 --- a/stage1/spl_ast2ir.c +++ b/stage1/spl_ast2ir.c @@ -21,6 +21,10 @@ static spl_ir_node_ref_t const_usize(spl_ast2ir_t *a, usize v) { return spl_ir_builder_type_const_int(a->ir, to_ir_type(a, t), v); } +static spl_ir_node_ref_t emit_if_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref); +static spl_ir_node_ref_t emit_loop_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref); +static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n); + static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref); static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref); static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref); @@ -30,8 +34,12 @@ static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n); static void emit_container_reserve(spl_ast2ir_t *a, spl_ast_node_ref_t ref); static void emit_container_body(spl_ast2ir_t *a, spl_ast_node_ref_t ref); +static spl_ir_node_ref_t ast2ir_emit_cast_builtin(spl_ast2ir_t *a, spl_ast_node_t *n, + spl_intrin_t in, spl_type_id_t ft, + spl_type_id_t tt, spl_ir_node_ref_t v); static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n); static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref); +static spl_ir_node_ref_t emit_if_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref); static spl_ir_node_ref_t emit_implicit_cast(spl_ast2ir_t *a, spl_type_id_t ft, spl_type_id_t tt, spl_ir_node_ref_t v); @@ -123,6 +131,32 @@ static void copy_attrs_to_ir_func(spl_ast2ir_t *a, spl_ast_node_t *n, spl_ir_fun vec_push(irf->attrs, vec_at(n->attrs, i)); } +static spl_ir_node_ref_t ast2ir_intrin_cast(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in, + spl_ast_node_ref_vec_t *args) { + usize nargs = vec_size(*args); + if (nargs < 1) { + SPL_ERROR(&n->dbg, "cast builtin requires at least 1 argument"); + return 0; + } + spl_ir_node_ref_t v = emit_expr(a, vec_at(*args, 0)); + if (!v) + return 0; + spl_ast_node_t *src = spl_ast_node(a->sema->ast, vec_at(*args, 0)); + spl_type_id_t ft = node_ir(a, src); + + spl_type_id_t tt = 0; + if (nargs >= 2) { + spl_ast_node_t *targ = spl_ast_node(a->sema->ast, vec_at(*args, 1)); + tt = node_ir(a, targ); + } else { + /* 单参数形式:目标类型由 sema 在节点上标好的 resolved 类型给出 */ + tt = node_ir(a, n); + } + if (!ft || !tt) + return 0; + return ast2ir_emit_cast_builtin(a, n, in, ft, tt, v); +} + static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in, spl_ast_node_ref_vec_t *args) { switch (in) { @@ -177,6 +211,17 @@ static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n, spl_ir_builder_control_br_fixup(a->ir, br, panic_blk, cont_blk); return 0; } + case SPL_INTRIN_INT_CAST: + case SPL_INTRIN_TRUNCATE: + case SPL_INTRIN_BIT_CAST: + case SPL_INTRIN_FLOAT_CAST: + case SPL_INTRIN_INT_FROM_FLOAT: + case SPL_INTRIN_FLOAT_FROM_INT: + case SPL_INTRIN_INT_FROM_BOOL: + case SPL_INTRIN_INT_FROM_PTR: + case SPL_INTRIN_PTR_FROM_INT: + case SPL_INTRIN_PTR_CAST: + return ast2ir_intrin_cast(a, n, in, args); case SPL_INTRIN_BREAKPOINT: return spl_ir_builder_dbg_breakpoint(a->ir); default: @@ -351,6 +396,45 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { } } +static spl_ir_node_ref_t ast2ir_emit_cast_builtin(spl_ast2ir_t *a, spl_ast_node_t *n, + spl_intrin_t in, spl_type_id_t ft, + spl_type_id_t tt, spl_ir_node_ref_t v) { + switch (in) { + case SPL_INTRIN_INT_CAST: { + spl_type_node_t *fs = spl_type_node(a->sema->type, ft); + if (fs && fs->int_type.is_signed) + return spl_ir_builder_cast_sext(a->ir, ft, tt, v); + return spl_ir_builder_cast_zext(a->ir, ft, tt, v); + } + case SPL_INTRIN_TRUNCATE: + return spl_ir_builder_cast_trunc(a->ir, ft, tt, v); + case SPL_INTRIN_BIT_CAST: + return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v); + case SPL_INTRIN_FLOAT_CAST: { + spl_type_node_t *fs = spl_type_node(a->sema->type, ft); + spl_type_node_t *ts = spl_type_node(a->sema->type, tt); + if (fs && ts && fs->float_type.bits > ts->float_type.bits) + return spl_ir_builder_cast_ftrunc(a->ir, ft, tt, v); + return spl_ir_builder_cast_fext(a->ir, ft, tt, v); + } + case SPL_INTRIN_INT_FROM_FLOAT: + return spl_ir_builder_case_float2int(a->ir, ft, tt, v); + case SPL_INTRIN_FLOAT_FROM_INT: + return spl_ir_builder_case_int2float(a->ir, ft, tt, v); + case SPL_INTRIN_INT_FROM_BOOL: + return spl_ir_builder_cast_bool2int(a->ir, ft, tt, v); + case SPL_INTRIN_INT_FROM_PTR: + return spl_ir_builder_cast_ptr2int(a->ir, ft, tt, v); + case SPL_INTRIN_PTR_FROM_INT: + return spl_ir_builder_cast_int2ptr(a->ir, ft, tt, v); + case SPL_INTRIN_PTR_CAST: + return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v); + default: + SPL_ERROR(&n->dbg, "as: unknown cast builtin"); + return 0; + } +} + static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n) { spl_ir_node_ref_t v = emit_expr_raw(a, n->cast.expr); if (!v) @@ -359,36 +443,15 @@ static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n) { spl_ast_node_t *dst = spl_ast_node(a->sema->ast, n->cast.type); spl_type_id_t ft = node_ir(a, src); spl_type_id_t tt = node_ir(a, dst); - spl_type_node_t *fs = spl_type_node(a->sema->type, ft); - spl_type_node_t *ts = spl_type_node(a->sema->type, tt); - if (!fs || !ts) + if (!ft || !tt) return 0; - if (fs->kind == SPL_TYPE_INT && ts->kind == SPL_TYPE_INT) { - if (fs->int_type.bits == ts->int_type.bits) - return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v); - if (fs->int_type.bits > ts->int_type.bits) - return spl_ir_builder_cast_trunc(a->ir, ft, tt, v); - if (fs->int_type.is_signed) - return spl_ir_builder_cast_sext(a->ir, ft, tt, v); - return spl_ir_builder_cast_zext(a->ir, ft, tt, v); + spl_intrin_t in = spl_intrin_lookup_cast(a->sema->type, ft, tt); + if (in == SPL_INTRIN_NONE) { + SPL_ERROR(&n->dbg, "as: no conversion between the given types"); + return 0; } - if (fs->kind == SPL_TYPE_INT && ts->kind == SPL_TYPE_FLOAT) - return spl_ir_builder_case_int2float(a->ir, ft, tt, v); - if (fs->kind == SPL_TYPE_FLOAT && ts->kind == SPL_TYPE_INT) - return spl_ir_builder_case_float2int(a->ir, ft, tt, v); - if (fs->kind == SPL_TYPE_FLOAT && ts->kind == SPL_TYPE_FLOAT) { - if (fs->float_type.bits > ts->float_type.bits) - return spl_ir_builder_cast_ftrunc(a->ir, ft, tt, v); - return spl_ir_builder_cast_fext(a->ir, ft, tt, v); - } - if (fs->kind == SPL_TYPE_BOOL && ts->kind == SPL_TYPE_INT) - return spl_ir_builder_cast_bool2int(a->ir, ft, tt, v); - if (fs->kind == SPL_TYPE_PTR && ts->kind == SPL_TYPE_INT) - return spl_ir_builder_cast_ptr2int(a->ir, ft, tt, v); - if (fs->kind == SPL_TYPE_INT && ts->kind == SPL_TYPE_PTR) - return spl_ir_builder_cast_int2ptr(a->ir, ft, tt, v); - return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v); + return ast2ir_emit_cast_builtin(a, n, in, ft, tt, v); } static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { @@ -873,11 +936,10 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) } case SPL_AST_EXPR_IF: case SPL_AST_EXPR_IFVAR: + return emit_if_like(a, ref); case SPL_AST_EXPR_WHILE: - case SPL_AST_EXPR_LOOP: { - emit_stmt(a, ref); - return 0; - } + case SPL_AST_EXPR_LOOP: + return emit_loop_like(a, ref); case SPL_AST_EXPR_SLICE: { spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->slice.obj); spl_lang_type_id_t obj_lang = node_lang(a, obj); @@ -970,6 +1032,257 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) } } +static spl_ir_node_ref_t emit_if_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref); + if (!n || n->kind != SPL_AST_EXPR_IF) + return 0; + + spl_type_id_t if_t = node_ir(a, n); + spl_type_node_t *if_tn = if_t ? spl_type_node(a->sema->type, if_t) : NULL; + /* 只有 when 有非 unit 值时(作为表达式使用),才分配 result_slot */ + bool need_result = if_tn && if_tn->kind != SPL_TYPE_UNIT; + + spl_ir_node_ref_t result_slot = 0; + if (need_result) + result_slot = spl_ir_builder_mem_alloca(a->ir, if_t, const_usize(a, 1)); + + spl_ir_node_ref_t cond = emit_expr(a, n->if_expr.cond); + if (!cond) + Panic("if cond emit failed"); + spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond); + spl_ir_builder_block_end(a->ir); + + usize then_blk = spl_ir_builder_block_begin(a->ir); + spl_ir_node_ref_t then_v = 0; + if (n->if_expr.then_block) + then_v = emit_expr(a, n->if_expr.then_block); + if (result_slot && then_v) + spl_ir_builder_mem_store(a->ir, if_t, result_slot, then_v); + spl_ir_node_ref_t then_end = 0; + if (!a->ir->terminated) + then_end = spl_ir_builder_control_jmp(a->ir); + spl_ir_builder_block_end(a->ir); + + usize else_blk = spl_ir_builder_block_begin(a->ir); + spl_ir_node_ref_t else_v = 0; + if (n->if_expr.else_branch) + else_v = emit_expr(a, n->if_expr.else_branch); + if (result_slot && else_v) + spl_ir_builder_mem_store(a->ir, if_t, result_slot, else_v); + spl_ir_node_ref_t else_end = 0; + if (!a->ir->terminated) + else_end = spl_ir_builder_control_jmp(a->ir); + spl_ir_builder_block_end(a->ir); + + usize merge_blk = spl_ir_builder_block_begin(a->ir); + spl_ir_builder_control_br_fixup(a->ir, br, then_blk, else_blk); + if (then_end) + spl_ir_builder_control_jmp_fixup(a->ir, then_end, merge_blk); + if (else_end) + spl_ir_builder_control_jmp_fixup(a->ir, else_end, merge_blk); + + if (!result_slot) + return 0; + return spl_ir_builder_mem_load(a->ir, if_t, result_slot); +} + +static spl_ir_node_ref_t emit_if_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref); + if (!n) + return 0; + bool is_ifvar = (n->kind == SPL_AST_EXPR_IFVAR); + + spl_type_id_t result_t = node_ir(a, n); + spl_type_node_t *rtn = result_t ? spl_type_node(a->sema->type, result_t) : NULL; + bool need_result = rtn && rtn->kind != SPL_TYPE_UNIT; + + spl_ir_node_ref_t result_slot = 0; + if (need_result) + result_slot = spl_ir_builder_mem_alloca(a->ir, result_t, const_usize(a, 1)); + + spl_ir_node_ref_t cond = 0; + spl_ast_node_ref_t then_ref = 0; + spl_ast_node_ref_t else_ref = 0; + + if (is_ifvar) { + emit_decl(a, n->ifvar_expr.var_decl); + spl_ast_node_t *vd = spl_ast_node(a->sema->ast, n->ifvar_expr.var_decl); + if (!vd || !vd->var_const_decl.init_expr) + Panic("ifvar requires initializer"); + spl_ir_node_ref_t slot = 0; + if (!map_get(a->def2ir_map, vd->resolved_def_id, &slot)) + Panic("ifvar var slot not found"); + cond = spl_ir_builder_mem_load(a->ir, node_ir(a, vd), slot); + then_ref = n->ifvar_expr.then_block; + else_ref = n->ifvar_expr.else_branch; + } else { + cond = emit_expr(a, n->if_expr.cond); + then_ref = n->if_expr.then_block; + else_ref = n->if_expr.else_branch; + } + if (!cond) + Panic("if cond emit failed"); + + spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond); + spl_ir_builder_block_end(a->ir); + + usize then_blk = spl_ir_builder_block_begin(a->ir); + spl_ir_node_ref_t then_v = 0; + if (then_ref) + then_v = emit_expr(a, then_ref); + if (result_slot && then_v) + spl_ir_builder_mem_store(a->ir, result_t, result_slot, then_v); + spl_ir_node_ref_t then_end = 0; + if (!a->ir->terminated) + then_end = spl_ir_builder_control_jmp(a->ir); + spl_ir_builder_block_end(a->ir); + + usize else_blk = spl_ir_builder_block_begin(a->ir); + spl_ir_node_ref_t else_v = 0; + if (else_ref) + else_v = emit_expr(a, else_ref); + if (result_slot && else_v) + spl_ir_builder_mem_store(a->ir, result_t, result_slot, else_v); + spl_ir_node_ref_t else_end = 0; + if (!a->ir->terminated) + else_end = spl_ir_builder_control_jmp(a->ir); + spl_ir_builder_block_end(a->ir); + + usize merge_blk = spl_ir_builder_block_begin(a->ir); + spl_ir_builder_control_br_fixup(a->ir, br, then_blk, else_blk); + if (then_end) + spl_ir_builder_control_jmp_fixup(a->ir, then_end, merge_blk); + if (else_end) + spl_ir_builder_control_jmp_fixup(a->ir, else_end, merge_blk); + + if (!result_slot) + return 0; + return spl_ir_builder_mem_load(a->ir, result_t, result_slot); +} + +static spl_ir_node_ref_t emit_loop_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { + spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref); + if (!n) + return 0; + bool is_while = (n->kind == SPL_AST_EXPR_WHILE); + + spl_type_id_t result_t = node_ir(a, n); + spl_type_node_t *rtn = result_t ? spl_type_node(a->sema->type, result_t) : NULL; + bool need_result = rtn && rtn->kind != SPL_TYPE_UNIT; + + spl_ir_node_ref_t result_slot = 0; + if (need_result) + result_slot = spl_ir_builder_mem_alloca(a->ir, result_t, const_usize(a, 1)); + + spl_ir_node_ref_t pre_jmp = 0; + if (!a->ir->terminated) + pre_jmp = spl_ir_builder_control_jmp(a->ir); + spl_ir_builder_block_end(a->ir); + + /* while 需要独立 head 块(含 cond + br); + loop 没有头块,body_blk 同时是入口和回跳目标 */ + usize head_blk = 0; + spl_ir_node_ref_t br = 0; + + if (is_while) { + head_blk = spl_ir_builder_block_begin(a->ir); + spl_ir_node_ref_t cond = emit_expr(a, n->while_expr.cond); + if (!cond) + Panic("while cond emit failed"); + br = spl_ir_builder_control_br(a->ir, cond); + spl_ir_builder_block_end(a->ir); + } + + usize body_blk = spl_ir_builder_block_begin(a->ir); + usize cont_blk = is_while ? head_blk : body_blk; + + spl_loop_ctx_t ctx = {0}; + ctx.cont_blk = cont_blk; + ctx.brk_blk = 0; + ctx.label = NULL; + ctx.result_slot = result_slot; + ctx.result_tid = result_t; + + spl_ast_node_ref_t label_ref = is_while ? n->while_expr.label : n->loop_expr.label; + if (label_ref) { + spl_ast_node_t *ln = spl_ast_node(a->sema->ast, label_ref); + if (ln && ln->kind == SPL_AST_LABEL) + ctx.label = ln->label.name; + } + vec_init(ctx.breaks); + vec_push(a->loop_stack, ctx); + + spl_ast_node_ref_t body_ref = is_while ? n->while_expr.body : n->loop_expr.body; + if (body_ref) + emit_expr(a, body_ref); + + spl_ir_node_ref_t body_end = 0; + if (!a->ir->terminated) + body_end = spl_ir_builder_control_jmp(a->ir); + spl_ir_builder_block_end(a->ir); + + usize after_blk = spl_ir_builder_block_begin(a->ir); + spl_ir_node_ref_t else_v = 0; + if (is_while && n->while_expr.else_branch) + else_v = emit_expr(a, n->while_expr.else_branch); + if (result_slot && else_v) + spl_ir_builder_mem_store(a->ir, result_t, result_slot, else_v); + + if (pre_jmp) + spl_ir_builder_control_jmp_fixup(a->ir, pre_jmp, cont_blk); + if (br) + spl_ir_builder_control_br_fixup(a->ir, br, body_blk, after_blk); + if (body_end) + spl_ir_builder_control_jmp_fixup(a->ir, body_end, cont_blk); + + spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1); + for (usize i = 0; i < vec_size(top->breaks); ++i) + spl_ir_builder_control_jmp_fixup(a->ir, vec_at(top->breaks, i), after_blk); + vec_free(top->breaks); + vec_pop(a->loop_stack); + + if (!result_slot) + return 0; + return spl_ir_builder_mem_load(a->ir, result_t, result_slot); +} + +static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n) { + if (vec_size(a->loop_stack) == 0) + return; + + const char *lbl = NULL; + if (n->statement_break.label) { + spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->statement_break.label); + if (ln && ln->kind == SPL_AST_LABEL) + lbl = ln->label.name; + } + + spl_loop_ctx_t *target = NULL; + if (lbl) { + for (usize i = vec_size(a->loop_stack); i > 0; --i) { + spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1); + if (c->label && strcmp(c->label, lbl) == 0) { + target = c; + break; + } + } + } else { + target = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1); + } + if (!target) + return; + + /* 有值 loop:先把 break 值写入 result_slot 再跳转 */ + if (n->statement_break.expr && target->result_slot) { + spl_ir_node_ref_t bv = emit_expr(a, n->statement_break.expr); + if (bv) + spl_ir_builder_mem_store(a->ir, target->result_tid, target->result_slot, bv); + } + + spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir); + vec_push(target->breaks, jmp); +} + static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref); if (!n) @@ -1009,205 +1322,19 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { if (n->statement_expr.expr) emit_expr(a, n->statement_expr.expr); return; - case SPL_AST_EXPR_IF: { - spl_type_id_t if_t = node_ir(a, n); - spl_ir_node_ref_t result_slot = 0; - if (if_t) - result_slot = spl_ir_builder_mem_alloca(a->ir, if_t, const_usize(a, 1)); - - spl_ir_node_ref_t cond = emit_expr(a, n->if_expr.cond); - if (!cond) - Panic("if cond emit failed"); - spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond); - spl_ir_builder_block_end(a->ir); - - usize then_blk = spl_ir_builder_block_begin(a->ir); - spl_ir_node_ref_t then_v = 0; - if (n->if_expr.then_block) - then_v = emit_expr(a, n->if_expr.then_block); - if (result_slot && then_v) - spl_ir_builder_mem_store(a->ir, if_t, result_slot, then_v); - spl_ir_node_ref_t then_end = 0; - if (!a->ir->terminated) - then_end = spl_ir_builder_control_jmp(a->ir); - spl_ir_builder_block_end(a->ir); - - usize else_blk = spl_ir_builder_block_begin(a->ir); - spl_ir_node_ref_t else_v = 0; - if (n->if_expr.else_branch) - else_v = emit_expr(a, n->if_expr.else_branch); - if (result_slot && else_v) - spl_ir_builder_mem_store(a->ir, if_t, result_slot, else_v); - spl_ir_node_ref_t else_end = 0; - if (!a->ir->terminated) - else_end = spl_ir_builder_control_jmp(a->ir); - spl_ir_builder_block_end(a->ir); - - usize merge_blk = spl_ir_builder_block_begin(a->ir); - spl_ir_builder_control_br_fixup(a->ir, br, then_blk, else_blk); - if (then_end) - spl_ir_builder_control_jmp_fixup(a->ir, then_end, merge_blk); - if (else_end) - spl_ir_builder_control_jmp_fixup(a->ir, else_end, merge_blk); - return; - } + case SPL_AST_EXPR_IF: case SPL_AST_EXPR_IFVAR: { - emit_decl(a, n->ifvar_expr.var_decl); - spl_ast_node_t *vd = spl_ast_node(a->sema->ast, n->ifvar_expr.var_decl); - if (!vd || !vd->var_const_decl.init_expr) - Panic("ifvar requires initializer"); - - spl_ir_node_ref_t slot = 0; - if (!map_get(a->def2ir_map, vd->resolved_def_id, &slot)) - Panic("ifvar var slot not found"); - spl_ir_node_ref_t cond = spl_ir_builder_mem_load(a->ir, node_ir(a, vd), slot); - - spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond); - spl_ir_builder_block_end(a->ir); - - usize then_blk = spl_ir_builder_block_begin(a->ir); - if (n->ifvar_expr.then_block) - emit_expr(a, n->ifvar_expr.then_block); - spl_ir_node_ref_t then_end = 0; - if (!a->ir->terminated) - then_end = spl_ir_builder_control_jmp(a->ir); - spl_ir_builder_block_end(a->ir); - - usize else_blk = spl_ir_builder_block_begin(a->ir); - if (n->ifvar_expr.else_branch) - emit_expr(a, n->ifvar_expr.else_branch); - spl_ir_node_ref_t else_end = 0; - if (!a->ir->terminated) - else_end = spl_ir_builder_control_jmp(a->ir); - spl_ir_builder_block_end(a->ir); - - usize merge_blk = spl_ir_builder_block_begin(a->ir); - spl_ir_builder_control_br_fixup(a->ir, br, then_blk, else_blk); - if (then_end) - spl_ir_builder_control_jmp_fixup(a->ir, then_end, merge_blk); - if (else_end) - spl_ir_builder_control_jmp_fixup(a->ir, else_end, merge_blk); - return; - } - case SPL_AST_EXPR_WHILE: { - spl_ir_node_ref_t pre_jmp = 0; - if (!a->ir->terminated) - pre_jmp = spl_ir_builder_control_jmp(a->ir); - spl_ir_builder_block_end(a->ir); - - usize head_blk = spl_ir_builder_block_begin(a->ir); - spl_ir_node_ref_t cond = emit_expr(a, n->while_expr.cond); - if (!cond) - Panic("while cond emit failed"); - spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond); - spl_ir_builder_block_end(a->ir); - - usize body_blk = spl_ir_builder_block_begin(a->ir); - - spl_loop_ctx_t ctx = {0}; - ctx.cont_blk = head_blk; - ctx.brk_blk = 0; - ctx.label = NULL; - if (n->while_expr.label) { - spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->while_expr.label); - if (ln && ln->kind == SPL_AST_LABEL) - ctx.label = ln->label.name; - } - vec_init(ctx.breaks); - vec_push(a->loop_stack, ctx); - - if (n->while_expr.body) - emit_expr(a, n->while_expr.body); - spl_ir_node_ref_t body_end = 0; - if (!a->ir->terminated) - body_end = spl_ir_builder_control_jmp(a->ir); - spl_ir_builder_block_end(a->ir); - - usize after_blk = spl_ir_builder_block_begin(a->ir); - if (n->while_expr.else_branch) - emit_expr(a, n->while_expr.else_branch); - - if (pre_jmp) - spl_ir_builder_control_jmp_fixup(a->ir, pre_jmp, head_blk); - spl_ir_builder_control_br_fixup(a->ir, br, body_blk, after_blk); - if (body_end) - spl_ir_builder_control_jmp_fixup(a->ir, body_end, head_blk); - - spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1); - for (usize i = 0; i < vec_size(top->breaks); ++i) - spl_ir_builder_control_jmp_fixup(a->ir, vec_at(top->breaks, i), after_blk); - vec_free(top->breaks); - vec_pop(a->loop_stack); + (void)emit_if_like(a, ref); return; } + case SPL_AST_EXPR_WHILE: case SPL_AST_EXPR_LOOP: { - spl_ir_node_ref_t pre_jmp = 0; - if (!a->ir->terminated) - pre_jmp = spl_ir_builder_control_jmp(a->ir); - spl_ir_builder_block_end(a->ir); - - usize head_blk = spl_ir_builder_block_begin(a->ir); - - spl_loop_ctx_t ctx = {0}; - ctx.cont_blk = head_blk; - ctx.brk_blk = 0; - ctx.label = NULL; - if (n->loop_expr.label) { - spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->loop_expr.label); - if (ln && ln->kind == SPL_AST_LABEL) - ctx.label = ln->label.name; - } - vec_init(ctx.breaks); - vec_push(a->loop_stack, ctx); - - if (n->loop_expr.body) - emit_expr(a, n->loop_expr.body); - spl_ir_node_ref_t body_end = 0; - if (!a->ir->terminated) - body_end = spl_ir_builder_control_jmp(a->ir); - spl_ir_builder_block_end(a->ir); - - usize after_blk = spl_ir_builder_block_begin(a->ir); - - if (pre_jmp) - spl_ir_builder_control_jmp_fixup(a->ir, pre_jmp, head_blk); - if (body_end) - spl_ir_builder_control_jmp_fixup(a->ir, body_end, head_blk); - - spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1); - for (usize i = 0; i < vec_size(top->breaks); ++i) - spl_ir_builder_control_jmp_fixup(a->ir, vec_at(top->breaks, i), after_blk); - vec_free(top->breaks); - vec_pop(a->loop_stack); + (void)emit_loop_like(a, ref); return; } - case SPL_AST_STATEMENT_BREAK: { - if (vec_size(a->loop_stack) == 0) - return; - - const char *lbl = NULL; - if (n->statement_break.label) { - spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->statement_break.label); - if (ln && ln->kind == SPL_AST_LABEL) - lbl = ln->label.name; - } - - spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir); - - if (lbl) { - for (usize i = vec_size(a->loop_stack); i > 0; --i) { - spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1); - if (c->label && strcmp(c->label, lbl) == 0) { - vec_push(c->breaks, jmp); - return; - } - } - return; - } - - vec_push(vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).breaks, jmp); + case SPL_AST_STATEMENT_BREAK: + emit_break_stmt(a, n); return; - } case SPL_AST_STATEMENT_CONTINUE: { if (vec_size(a->loop_stack) == 0) return; diff --git a/stage1/spl_ast2ir.h b/stage1/spl_ast2ir.h index 45f0a89..a012641 100644 --- a/stage1/spl_ast2ir.h +++ b/stage1/spl_ast2ir.h @@ -11,6 +11,8 @@ typedef struct { usize brk_blk; const char *label; spl_ir_node_ref_vec_t breaks; + spl_ir_node_ref_t result_slot; + spl_type_id_t result_tid; } spl_loop_ctx_t; typedef VEC(spl_loop_ctx_t) spl_loop_ctx_vec_t; diff --git a/stage1/spl_intrin.c b/stage1/spl_intrin.c index 0784bbb..3cd85fc 100644 --- a/stage1/spl_intrin.c +++ b/stage1/spl_intrin.c @@ -12,6 +12,26 @@ static const spl_intrin_info_t g_intrin_table[] = { SPL_INTRIN_RESULT_UNIT}, [SPL_INTRIN_LEN] = {"len", SPL_INTRIN_LEN, SPL_INTRIN_FORM_FIELD, 0, 0, SPL_INTRIN_RESULT_USIZE}, + [SPL_INTRIN_INT_CAST] = {"@int_cast", SPL_INTRIN_INT_CAST, SPL_INTRIN_FORM_CALL, 2, 2, + SPL_INTRIN_RESULT_UNIT}, + [SPL_INTRIN_TRUNCATE] = {"@truncate", SPL_INTRIN_TRUNCATE, SPL_INTRIN_FORM_CALL, 2, 2, + SPL_INTRIN_RESULT_UNIT}, + [SPL_INTRIN_BIT_CAST] = {"@bit_cast", SPL_INTRIN_BIT_CAST, SPL_INTRIN_FORM_CALL, 2, 2, + SPL_INTRIN_RESULT_UNIT}, + [SPL_INTRIN_FLOAT_CAST] = {"@float_cast", SPL_INTRIN_FLOAT_CAST, SPL_INTRIN_FORM_CALL, 2, 2, + SPL_INTRIN_RESULT_UNIT}, + [SPL_INTRIN_INT_FROM_FLOAT] = {"@int_from_float", SPL_INTRIN_INT_FROM_FLOAT, + SPL_INTRIN_FORM_CALL, 2, 2, SPL_INTRIN_RESULT_UNIT}, + [SPL_INTRIN_FLOAT_FROM_INT] = {"@float_from_int", SPL_INTRIN_FLOAT_FROM_INT, + SPL_INTRIN_FORM_CALL, 2, 2, SPL_INTRIN_RESULT_UNIT}, + [SPL_INTRIN_INT_FROM_BOOL] = {"@int_from_bool", SPL_INTRIN_INT_FROM_BOOL, SPL_INTRIN_FORM_CALL, + 1, 2, SPL_INTRIN_RESULT_UNIT}, + [SPL_INTRIN_INT_FROM_PTR] = {"@int_from_ptr", SPL_INTRIN_INT_FROM_PTR, SPL_INTRIN_FORM_CALL, 1, + 2, SPL_INTRIN_RESULT_UNIT}, + [SPL_INTRIN_PTR_FROM_INT] = {"@ptr_from_int", SPL_INTRIN_PTR_FROM_INT, SPL_INTRIN_FORM_CALL, 2, + 2, SPL_INTRIN_RESULT_UNIT}, + [SPL_INTRIN_PTR_CAST] = {"@ptr_cast", SPL_INTRIN_PTR_CAST, SPL_INTRIN_FORM_CALL, 2, 2, + SPL_INTRIN_RESULT_UNIT}, }; static const usize g_intrin_count = sizeof(g_intrin_table) / sizeof(g_intrin_table[0]); @@ -46,3 +66,34 @@ spl_intrin_t spl_intrin_lookup_field(spl_lang_type_kind_t recv_kind, const char } return SPL_INTRIN_NONE; } + +spl_intrin_t spl_intrin_lookup_cast(spl_type_t *type, spl_type_id_t ft, spl_type_id_t tt) { + /* 这是 `as` 的展开规则表。要调整 as 的语义,改这里。 */ + spl_type_node_t *f = spl_type_node(type, ft); + spl_type_node_t *t = spl_type_node(type, tt); + if (!f || !t) + return SPL_INTRIN_NONE; + + if (f->kind == SPL_TYPE_INT && t->kind == SPL_TYPE_INT) { + usize fb = f->int_type.bits; + usize tb = t->int_type.bits; + if (fb == tb) + return SPL_INTRIN_BIT_CAST; + if (fb > tb) + return SPL_INTRIN_TRUNCATE; + return SPL_INTRIN_INT_CAST; + } + if (f->kind == SPL_TYPE_FLOAT && t->kind == SPL_TYPE_FLOAT) + return SPL_INTRIN_FLOAT_CAST; + if (f->kind == SPL_TYPE_BOOL && t->kind == SPL_TYPE_INT) + return SPL_INTRIN_INT_FROM_BOOL; + if (f->kind == SPL_TYPE_PTR && t->kind == SPL_TYPE_INT) + return SPL_INTRIN_INT_FROM_PTR; + if (f->kind == SPL_TYPE_INT && t->kind == SPL_TYPE_PTR) + return SPL_INTRIN_PTR_FROM_INT; + if (f->kind == SPL_TYPE_PTR && t->kind == SPL_TYPE_PTR) + return SPL_INTRIN_PTR_CAST; + + /* int float 刻意不在这里:只能通过显式 builtin 调用。 */ + return SPL_INTRIN_NONE; +} \ No newline at end of file diff --git a/stage1/spl_intrin.h b/stage1/spl_intrin.h index 70f292b..0508bab 100644 --- a/stage1/spl_intrin.h +++ b/stage1/spl_intrin.h @@ -11,6 +11,16 @@ typedef enum { SPL_INTRIN_ASSERT, SPL_INTRIN_BREAKPOINT, SPL_INTRIN_LEN, + SPL_INTRIN_INT_CAST, + SPL_INTRIN_TRUNCATE, + SPL_INTRIN_BIT_CAST, + SPL_INTRIN_FLOAT_CAST, + SPL_INTRIN_INT_FROM_FLOAT, + SPL_INTRIN_FLOAT_FROM_INT, + SPL_INTRIN_INT_FROM_BOOL, + SPL_INTRIN_INT_FROM_PTR, + SPL_INTRIN_PTR_FROM_INT, + SPL_INTRIN_PTR_CAST, } spl_intrin_t; typedef enum { @@ -33,13 +43,10 @@ typedef struct { spl_intrin_result_t result; } spl_intrin_info_t; -/* 统一入口:名字 → 枚举。name 允许带或不带 '@'。 */ spl_intrin_t spl_intrin_lookup_call(const char *name); - -/* 统一入口:字段形态,按接收者类型分派。 */ spl_intrin_t spl_intrin_lookup_field(spl_lang_type_kind_t recv_kind, const char *field); +spl_intrin_t spl_intrin_lookup_cast(spl_type_t *type, spl_type_id_t ft, spl_type_id_t tt); -/* 从枚举取得元数据,SEMA/AST2IR 都从这里读。 */ const spl_intrin_info_t *spl_intrin_info(spl_intrin_t kind); /* ---- 与 IR 侧共享的类型布局约定 ---- */ diff --git a/stage1/spl_ir2vm.c b/stage1/spl_ir2vm.c index 6a80eca..f7b2c8b 100644 --- a/stage1/spl_ir2vm.c +++ b/stage1/spl_ir2vm.c @@ -193,7 +193,7 @@ static spl_type_id_t ir_result_tid(spl_ir2vm_t *ctx, const spl_ir_node_t *n) { case SPL_IR_CASE_FLOAT2INT: return n->cast.to_tid; case SPL_IR_MEM_ALLOCA: - return n->mem_alloc.tid; + return spl_type_builder_ptr((spl_type_t *)ctx->type, n->mem_alloc.tid); case SPL_IR_MEM_GLOBAL_ALLOC: return n->mem_global_alloc.tid; case SPL_IR_MEM_LOAD: diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index 2cc5f8b..19edd8c 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -581,7 +581,7 @@ static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, switch (in) { case SPL_INTRIN_SIZEOF: case SPL_INTRIN_ALIGNOF: { - sema_infer(sema, vec_at(*args, 0)); /* 求类型表达式的值 */ + sema_infer(sema, vec_at(*args, 0)); return spl_lang_make_int(sema->type, sizeof(void *) * 8, 0); } case SPL_INTRIN_ASSERT: { @@ -591,6 +591,48 @@ static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, sema_infer(sema, vec_at(*args, 1)); return spl_lang_make_unit(sema->type); } + case SPL_INTRIN_INT_CAST: + case SPL_INTRIN_TRUNCATE: + case SPL_INTRIN_BIT_CAST: + case SPL_INTRIN_FLOAT_CAST: + case SPL_INTRIN_INT_FROM_FLOAT: + case SPL_INTRIN_FLOAT_FROM_INT: + case SPL_INTRIN_PTR_FROM_INT: + case SPL_INTRIN_PTR_CAST: { + /* 双参数形式:源表达式 + 目标类型 */ + spl_lang_type_id_t src_lang = sema_infer(sema, vec_at(*args, 0)); + if (!src_lang) + return 0; + spl_lang_type_id_t dst_lang = sema_infer(sema, vec_at(*args, 1)); + if (!dst_lang) + return 0; + spl_type_id_t ft = spl_lang_type_get_ir_type(sema->type, src_lang); + spl_type_id_t tt = spl_lang_type_get_ir_type(sema->type, dst_lang); + spl_intrin_t expected = spl_intrin_lookup_cast(sema->type, ft, tt); + if (expected == SPL_INTRIN_NONE) { + SPL_ERROR(&n->dbg, "`%s`: incompatible types", info->name); + sema->error_count++; + return 0; + } + /* 允许显式 builtin 覆盖 as 的默认选择(例如用 @int_cast 代替 @truncate) */ + n->resolved_lang_tid = dst_lang; + return dst_lang; + } + case SPL_INTRIN_INT_FROM_BOOL: + case SPL_INTRIN_INT_FROM_PTR: { + /* 单参数:目标类型默认 usize;双参数时以第二参数为准 */ + sema_infer(sema, vec_at(*args, 0)); + if (nargs >= 2) { + spl_lang_type_id_t dst = sema_infer(sema, vec_at(*args, 1)); + if (!dst) + return 0; + n->resolved_lang_tid = dst; + return dst; + } + spl_lang_type_id_t r = spl_lang_make_int(sema->type, sizeof(void *) * 8, 0); + n->resolved_lang_tid = r; + return r; + } default: UNREACHABLE(); } @@ -873,6 +915,15 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, return expected; } + case SPL_AST_EXPR_LOOP: { + spl_lang_type_id_t saved = sema->current_loop_break_tid; + sema->current_loop_break_tid = expected; + sema_infer(sema, ref); + sema->current_loop_break_tid = saved; + n->resolved_lang_tid = expected; + return expected; + } + case SPL_AST_EXPR_BLOCK: { sema_push_scope(sema); for (usize i = 0; i < vec_size(n->block.stmts); ++i) @@ -1361,33 +1412,48 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { /* ---------- CAST ---------- */ case SPL_AST_EXPR_CAST: { - spl_lang_type_id_t dst = sema_infer(sema, n->cast.type); - if (!dst) + spl_lang_type_id_t dst_lang = sema_infer(sema, n->cast.type); + if (!dst_lang) return 0; - spl_lang_type_id_t src = sema_infer(sema, n->cast.expr); - if (!src) + spl_lang_type_id_t src_lang = sema_infer(sema, n->cast.expr); + if (!src_lang) return 0; - /* 仅当 src 是 comptime 时收紧到 dst;具体类型间的 as 直接放行(截断/扩展由 ast2ir 生成) */ - spl_lang_type_node_t *sn = spl_lang_type_node(sema->type, src); + spl_lang_type_node_t *sn = spl_lang_type_node(sema->type, src_lang); spl_type_node_t *sir = sn ? spl_type_node(sema->type, sn->ir_type_id) : NULL; - bool src_comptime = - (sn && sn->kind == SPL_LANG_TYPE_INT && sir && sir->int_type.bits == 0) || - (sn && sn->kind == SPL_LANG_TYPE_FLOAT && sir && sir->float_type.bits == 0); - if (src_comptime) { - if (!sema_coerce(sema, n->cast.expr, dst)) + bool src_is_literal_int = + sn && sn->kind == SPL_LANG_TYPE_INT && sir && sir->int_type.bits == 0; + bool src_is_literal_float = + sn && sn->kind == SPL_LANG_TYPE_FLOAT && sir && sir->float_type.bits == 0; + + if (src_is_literal_int || src_is_literal_float) { + /* 字面量目标物化:允许任意宽度,as 会按其语义处理 */ + spl_ast_node_t *src_node = spl_ast_node(sema->ast, n->cast.expr); + if (src_node && (src_node->kind == SPL_AST_EXPR_INT_LIT || + src_node->kind == SPL_AST_EXPR_FLOAT_LIT)) { + src_node->resolved_lang_tid = dst_lang; + } else if (!sema_coerce(sema, n->cast.expr, dst_lang)) { return 0; + } + n->resolved_lang_tid = dst_lang; + return dst_lang; } - if (sn && !(sn->kind == SPL_LANG_TYPE_INT || sn->kind == SPL_LANG_TYPE_FLOAT || - sn->kind == SPL_LANG_TYPE_BOOL || sn->kind == SPL_LANG_TYPE_PTR)) { - SPL_ERROR(&n->dbg, "invalid cast from non-primitive type"); + spl_type_id_t ft = spl_lang_type_get_ir_type(sema->type, src_lang); + spl_type_id_t tt = spl_lang_type_get_ir_type(sema->type, dst_lang); + if (!ft || !tt) { + SPL_ERROR(&n->dbg, "as: unresolved source or target type"); sema->error_count++; return 0; } - - n->resolved_lang_tid = dst; - return dst; + spl_intrin_t in = spl_intrin_lookup_cast(sema->type, ft, tt); + if (in == SPL_INTRIN_NONE) { + SPL_ERROR(&n->dbg, "as: invalid conversion (not supported by as)"); + sema->error_count++; + return 0; + } + n->resolved_lang_tid = dst_lang; + return dst_lang; } /* ---------- TUPLE ---------- */ @@ -1912,8 +1978,14 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { sema->error_count++; } } - if (n->statement_break.expr) - sema_infer(sema, n->statement_break.expr); + if (n->statement_break.expr) { + /* 有值 loop:break 值 coerce 到 loop 的期望类型 */ + if (sema->current_loop_break_tid != 0) { + sema_coerce(sema, n->statement_break.expr, sema->current_loop_break_tid); + } else { + sema_infer(sema, n->statement_break.expr); + } + } return 0; } case SPL_AST_STATEMENT_CONTINUE: { @@ -1981,6 +2053,7 @@ void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope sema->error_count = 0; sema->current_fn_ret_tid = 0; sema->current_aggregate_lang = 0; + sema->current_loop_break_tid = 0; sema->attr = attr; sema->root = (spl_symbol_t){0}; sema->store_scope = 0; diff --git a/stage1/spl_sema.h b/stage1/spl_sema.h index da0d4db..08cd6b1 100644 --- a/stage1/spl_sema.h +++ b/stage1/spl_sema.h @@ -50,6 +50,7 @@ typedef struct { spl_attr_t *attr; spl_lang_type_id_t current_aggregate_lang; spl_lang_type_id_t current_fn_ret_tid; + spl_lang_type_id_t current_loop_break_tid; spl_symbol_path_t label_stack; } spl_sema_t;