stage1 重制类型转换系统 修复问题 提供更多表达式
This commit is contained in:
1 parent
f6a0bce9f0
commit
7cbe2d2b9a
7 files changed
+509
-248
No files matched your search
+350
-223
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user