#include "spl_ast2ir.h" #include "spl_intrin.h" static spl_type_id_t to_ir_type(spl_ast2ir_t *a, spl_lang_type_id_t lang) { if (!lang) return 0; return spl_lang_type_get_ir_type(a->sema->type, lang); } static spl_lang_type_id_t node_lang(spl_ast2ir_t *a, spl_ast_node_t *n) { if (!n) return 0; if (n->kind == SPL_AST_EXPR_IDENT) return spl_def_get_lang_id(a->sema->type, n->resolved_def_id); return n->resolved_type_id; } static spl_type_id_t node_ir(spl_ast2ir_t *a, spl_ast_node_t *n) { return to_ir_type(a, node_lang(a, n)); } static spl_ir_node_ref_t const_usize(spl_ast2ir_t *a, usize v) { spl_lang_type_id_t t = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0); return spl_ir_builder_type_const_int(a->ir, to_ir_type(a, t), v); } 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); static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref); static void emit_fn(spl_ast2ir_t *a, spl_ast_node_t *n); static void emit_container(spl_ast2ir_t *a, spl_ast_node_ref_t ref); static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n); static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in); static spl_ir_node_ref_t ast2ir_intrin_field(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in); static spl_ir_node_ref_t ast2ir_intrin_len(spl_ast2ir_t *a, spl_ast_node_t *n); static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in) { switch (in) { case SPL_INTRIN_SIZEOF: { spl_ast_node_t *arg = spl_ast_node(a->sema->ast, vec_at(n->call.args, 0)); return spl_ir_builder_type_sizeof(a->ir, node_ir(a, arg)); } case SPL_INTRIN_ALIGNOF: { spl_ast_node_t *arg = spl_ast_node(a->sema->ast, vec_at(n->call.args, 0)); return spl_ir_builder_type_alignof(a->ir, node_ir(a, arg)); } case SPL_INTRIN_ASSERT: { /* 目前 SEMA 只做类型检查,emit 阶段留空, @assert 展开需待 control.trap 语义明确后再实现 */ return 0; } default: UNREACHABLE(); } return 0; } static spl_ir_node_ref_t ast2ir_intrin_field(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in) { switch (in) { case SPL_INTRIN_LEN: return ast2ir_intrin_len(a, n); default: UNREACHABLE(); } return 0; } static spl_ir_node_ref_t ast2ir_intrin_len(spl_ast2ir_t *a, spl_ast_node_t *n) { spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->field.obj); spl_lang_type_id_t recv_lang = node_lang(a, obj); spl_lang_type_node_t *recv = spl_lang_type_node(a->sema->type, recv_lang); if (!recv) return 0; 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); switch (recv->kind) { case SPL_LANG_TYPE_ARRAY: { spl_type_node_t *arr = spl_type_node(a->sema->type, recv->ir_type_id); if (!arr) return 0; return spl_ir_builder_type_const_int(a->ir, usize_ir, arr->array_type.len); } case SPL_LANG_TYPE_SLICE: { 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); } default: return 0; } } static spl_ir_node_ref_t emit_lvalue(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; switch (n->kind) { case SPL_AST_EXPR_IDENT: { spl_def_node_t *def = spl_def_node(a->sema->type, n->resolved_def_id); if (def && def->kind == SPL_DEF_FN) return 0; spl_ir_node_ref_t slot = 0; if (!map_get(a->def2ir_map, n->resolved_def_id, &slot)) return 0; return slot; } case SPL_AST_EXPR_FIELD: { spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->field.obj); if (!obj) return 0; spl_lang_type_id_t obj_lang = node_lang(a, obj); spl_lang_type_node_t *obj_ln = spl_lang_type_node(a->sema->type, obj_lang); if (!obj_ln) return 0; if (spl_intrin_lookup_field(obj_ln->kind, n->field.field) != SPL_INTRIN_NONE) return 0; /* 内建字段不是左值 */ spl_ir_node_ref_t base = 0; spl_lang_type_id_t agg_lang = 0; if (obj_ln->kind == SPL_LANG_TYPE_PTR) { base = emit_expr(a, n->field.obj); agg_lang = obj_ln->extra.elem; } else { base = emit_lvalue(a, n->field.obj); agg_lang = obj_lang; } if (!base) return 0; spl_type_id_t agg_ir = to_ir_type(a, agg_lang); if (!agg_ir) return 0; usize idx = 0; 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); } case SPL_AST_EXPR_INDEX: { spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->index.obj); if (!obj) return 0; spl_lang_type_id_t obj_lang = node_lang(a, obj); spl_lang_type_node_t *obj_ln = spl_lang_type_node(a->sema->type, obj_lang); if (!obj_ln) return 0; spl_ir_node_ref_t base = 0; spl_lang_type_id_t elem_lang = 0; if (obj_ln->kind == SPL_LANG_TYPE_PTR) { base = emit_expr(a, n->index.obj); elem_lang = obj_ln->extra.elem; } else if (obj_ln->kind == SPL_LANG_TYPE_ARRAY) { base = emit_lvalue(a, n->index.obj); elem_lang = obj_ln->extra.elem; } else if (obj_ln->kind == SPL_LANG_TYPE_SLICE) { /* 切片:取出切片值,再 agg_extract 出 ptr 字段 */ spl_ir_node_ref_t slice_val = emit_expr(a, n->index.obj); if (!slice_val) return 0; spl_lang_type_id_t elem = obj_ln->extra.elem; spl_type_id_t ptr_ir = spl_type_builder_ptr(a->sema->type, to_ir_type(a, elem)); spl_ir_node_ref_t ptr = spl_ir_builder_agg_extract(a->ir, ptr_ir, ptr_ir, SPL_SLICE_PTR_FIELD_IDX, slice_val); base = ptr; elem_lang = elem; } else { return 0; } if (!base) return 0; spl_ir_node_ref_t idx = emit_expr(a, n->index.index); if (!idx) return 0; spl_type_id_t elem_ir = to_ir_type(a, elem_lang); if (!elem_ir) return 0; return spl_ir_builder_mem_offset(a->ir, elem_ir, base, idx); } default: 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(a, n->cast.expr); if (!v) return 0; spl_ast_node_t *src = spl_ast_node(a->sema->ast, n->cast.expr); 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) 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); } 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); } static spl_ir_node_ref_t emit_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) return 0; switch (n->kind) { case SPL_AST_EXPR_INT_LIT: return spl_ir_builder_type_const_int(a->ir, node_ir(a, n), (usize)n->int_lit.val); case SPL_AST_EXPR_FLOAT_LIT: return spl_ir_builder_type_const_float(a->ir, node_ir(a, n), n->float_lit.val); case SPL_AST_EXPR_CHAR_LIT: return spl_ir_builder_type_const_char(a->ir, node_ir(a, n), n->char_lit.val); case SPL_AST_EXPR_STRING_LIT: return spl_ir_builder_type_const_cstr(a->ir, node_ir(a, n), n->string_lit.data); case SPL_AST_EXPR_BOOL_LIT: return spl_ir_builder_type_const_bool(a->ir, node_ir(a, n), n->bool_lit.val); case SPL_AST_EXPR_NULL_LIT: return spl_ir_builder_type_const_ptr(a->ir, node_ir(a, n), NULL); case SPL_AST_EXPR_UNDEFINED_LIT: return 0; case SPL_AST_EXPR_IDENT: { spl_def_node_t *def = spl_def_node(a->sema->type, n->resolved_def_id); if (def && def->kind == SPL_DEF_FN) { spl_ir_node_ref_t fn_ref = 0; if (!map_get(a->def2ir_map, n->resolved_def_id, &fn_ref)) return 0; return spl_ir_builder_type_const_fn(a->ir, node_ir(a, n), (spl_ir_func_ref_t)fn_ref); } spl_ir_node_ref_t slot = 0; if (!map_get(a->def2ir_map, n->resolved_def_id, &slot)) return 0; return spl_ir_builder_mem_load(a->ir, node_ir(a, n), slot); } case SPL_AST_EXPR_UNARY: { if (n->unary.op == SPL_UNARY_OP_ADDRESS) return emit_lvalue(a, n->unary.operand); spl_ir_node_ref_t v = emit_expr(a, n->unary.operand); if (!v) return 0; spl_type_id_t t = node_ir(a, n); switch (n->unary.op) { case SPL_UNARY_OP_MINUS: return spl_ir_builder_arith_neg(a->ir, t, v); case SPL_UNARY_OP_NOT: case SPL_UNARY_OP_BIT_NOT: return spl_ir_builder_arith_not(a->ir, t, v); default: return 0; } } case SPL_AST_EXPR_BINARY: { spl_binary_op_t op = n->binary.op; if (op == SPL_OP_ASSIGN) { spl_ir_node_ref_t ptr = emit_lvalue(a, n->binary.left); spl_ir_node_ref_t v = emit_expr(a, n->binary.right); if (!ptr || !v) return 0; spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->binary.left); spl_type_id_t t = node_ir(a, ln); spl_ir_builder_mem_store(a->ir, t, ptr, v); return v; } if (op >= SPL_OP_ASSIGN_ADD && op <= SPL_OP_ASSIGN_RSHIFT) { spl_ir_node_ref_t ptr = emit_lvalue(a, n->binary.left); if (!ptr) return 0; spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->binary.left); spl_type_id_t t = node_ir(a, ln); spl_ir_node_ref_t lv = spl_ir_builder_mem_load(a->ir, t, ptr); spl_ir_node_ref_t rv = emit_expr(a, n->binary.right); if (!lv || !rv) return 0; spl_ir_node_ref_t res = 0; switch (op) { case SPL_OP_ASSIGN_ADD: res = spl_ir_builder_arith_add(a->ir, t, lv, rv); break; case SPL_OP_ASSIGN_SUB: res = spl_ir_builder_arith_sub(a->ir, t, lv, rv); break; case SPL_OP_ASSIGN_MUL: res = spl_ir_builder_arith_mul(a->ir, t, lv, rv); break; case SPL_OP_ASSIGN_DIV: res = spl_ir_builder_arith_div(a->ir, t, lv, rv); break; case SPL_OP_ASSIGN_MOD: res = spl_ir_builder_arith_rem(a->ir, t, lv, rv); break; case SPL_OP_ASSIGN_AND: res = spl_ir_builder_arith_and(a->ir, t, lv, rv); break; case SPL_OP_ASSIGN_OR: res = spl_ir_builder_arith_or(a->ir, t, lv, rv); break; case SPL_OP_ASSIGN_XOR: res = spl_ir_builder_arith_xor(a->ir, t, lv, rv); break; case SPL_OP_ASSIGN_LSHIFT: res = spl_ir_builder_arith_shl(a->ir, t, lv, rv); break; case SPL_OP_ASSIGN_RSHIFT: res = spl_ir_builder_arith_shr(a->ir, t, lv, rv); break; default: return 0; } if (!res) return 0; spl_ir_builder_mem_store(a->ir, t, ptr, res); return res; } spl_ir_node_ref_t l = emit_expr(a, n->binary.left); spl_ir_node_ref_t r = emit_expr(a, n->binary.right); if (!l || !r) return 0; spl_type_id_t t = node_ir(a, n); switch (op) { case SPL_OP_ADD: return spl_ir_builder_arith_add(a->ir, t, l, r); case SPL_OP_SUB: return spl_ir_builder_arith_sub(a->ir, t, l, r); case SPL_OP_MUL: return spl_ir_builder_arith_mul(a->ir, t, l, r); case SPL_OP_DIV: return spl_ir_builder_arith_div(a->ir, t, l, r); case SPL_OP_MOD: return spl_ir_builder_arith_rem(a->ir, t, l, r); case SPL_OP_BIT_AND: return spl_ir_builder_arith_and(a->ir, t, l, r); case SPL_OP_BIT_OR: return spl_ir_builder_arith_or(a->ir, t, l, r); case SPL_OP_BIT_XOR: return spl_ir_builder_arith_xor(a->ir, t, l, r); case SPL_OP_LSHIFT: return spl_ir_builder_arith_shl(a->ir, t, l, r); case SPL_OP_RSHIFT: return spl_ir_builder_arith_shr(a->ir, t, l, r); case SPL_OP_CMP_EQ: return spl_ir_builder_cmp_eq(a->ir, t, l, r); case SPL_OP_CMP_NE: return spl_ir_builder_cmp_ne(a->ir, t, l, r); case SPL_OP_CMP_LT: return spl_ir_builder_cmp_lt(a->ir, t, l, r); case SPL_OP_CMP_LE: return spl_ir_builder_cmp_le(a->ir, t, l, r); case SPL_OP_CMP_GT: return spl_ir_builder_cmp_gt(a->ir, t, l, r); case SPL_OP_CMP_GE: return spl_ir_builder_cmp_ge(a->ir, t, l, r); default: return 0; } } case SPL_AST_EXPR_CALL: { spl_ast_node_t *callee = spl_ast_node(a->sema->ast, n->call.callee); if (callee && callee->kind == SPL_AST_EXPR_IDENT) { spl_intrin_t in = spl_intrin_lookup_call(callee->ident.name); if (in != SPL_INTRIN_NONE) return ast2ir_intrin_call(a, n, in); } spl_ir_node_ref_t fn = emit_expr(a, n->call.callee); if (!fn) return 0; 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) 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); } return call; } case SPL_AST_EXPR_FIELD: { spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->field.obj); spl_lang_type_id_t obj_lang = node_lang(a, obj); spl_lang_type_node_t *obj_ln = spl_lang_type_node(a->sema->type, obj_lang); if (obj_ln) { spl_intrin_t in = spl_intrin_lookup_field(obj_ln->kind, n->field.field); if (in != SPL_INTRIN_NONE) return ast2ir_intrin_field(a, n, in); } spl_ir_node_ref_t ptr = emit_lvalue(a, ref); if (!ptr) return 0; return spl_ir_builder_mem_load(a->ir, node_ir(a, n), ptr); } case SPL_AST_EXPR_INDEX: { spl_ir_node_ref_t ptr = emit_lvalue(a, ref); if (!ptr) return 0; return spl_ir_builder_mem_load(a->ir, node_ir(a, n), ptr); } case SPL_AST_EXPR_CAST: 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) { 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); } return node; } case SPL_AST_EXPR_ARRAY_LIT: { spl_type_id_t t = node_ir(a, n); if (!t) Panic("array literal has no type after sema"); 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); } return node; } case SPL_AST_EXPR_AGGREGATE_LIT: { spl_type_id_t t = node_ir(a, n); if (!t) Panic("aggregate literal has no type after sema"); spl_type_node_t *tn = spl_type_node(a->sema->type, t); if (!tn) Panic("aggregate type node missing"); usize nfields = vec_size(tn->agg_type.variants); /* 按字段名定位到 index,缺省值填 0(sema 已保证无缺省) */ spl_ir_node_ref_vec_t fields; vec_init(fields); for (usize i = 0; i < nfields; ++i) vec_push(fields, 0); for (usize i = 0; i < vec_size(n->aggregate_literal.fields); ++i) { spl_ast_node_t *item = spl_ast_node(a->sema->ast, vec_at(n->aggregate_literal.fields, i)); if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM) continue; usize idx = 0; if (!spl_type_agg_member_idx(a->sema->type, t, item->struct_init_item.name, &idx)) Panic("aggregate field `%s` not found (sema should have caught this)", item->struct_init_item.name); spl_ir_node_ref_t f = emit_expr(a, item->struct_init_item.expr); if (!f) Panic("aggregate field emit failed"); vec_at(fields, idx) = f; } spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t); if (!node) Panic("agg_construct failed for aggregate literal"); /* 顺序非常关键:agg_construct_field 是 vec_push, 必须严格按字段 index 0..n-1 顺序 push */ for (usize i = 0; i < nfields; ++i) { spl_ir_node_ref_t f = vec_at(fields, i); if (!f) Panic("aggregate field #%zu missing (sema should have caught this)", i); spl_ir_builder_agg_construct_field(a->ir, node, f); } vec_free(fields); return node; } case SPL_AST_EXPR_BLOCK: { for (usize i = 0; i < vec_size(n->block.stmts); ++i) emit_stmt(a, vec_at(n->block.stmts, i)); if (n->block.tail_expr) return emit_expr(a, n->block.tail_expr); return 0; } case SPL_AST_EXPR_IF: case SPL_AST_EXPR_IFVAR: case SPL_AST_EXPR_WHILE: case SPL_AST_EXPR_LOOP: { emit_stmt(a, ref); return 0; } 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); spl_lang_type_node_t *obj_ln = spl_lang_type_node(a->sema->type, obj_lang); if (!obj_ln) return 0; /* 目前只处理数组->切片的完整形式 arr[..](无 begin / end) 或 arr[begin..end] 的通用形式。简化实现只做完整切片。 */ spl_type_id_t slice_ir = node_ir(a, n); /* struct{ptr, len} */ 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_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)); /* 字段 0:ptr */ spl_ir_builder_agg_construct_field(a->ir, node, base); /* 字段 1:len —— 数组取 len,切片取原切片 len */ spl_ir_node_ref_t len = 0; 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); } 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); } else { return 0; } spl_ir_builder_agg_construct_field(a->ir, node, len); return node; } case SPL_AST_EXPR_COMPTIME_CALL: // TODO return 0; default: TODO(); return 0; } } 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) return; switch (n->kind) { case SPL_AST_STATEMENT_RET: { while (vec_size(a->defer_stack) > 0) { spl_ast_node_ref_t d = vec_pop(a->defer_stack); emit_stmt(a, d); } spl_type_id_t ret_ir = to_ir_type(a, a->cur_ret_lang); if (n->statement_ret.expr) { spl_ir_node_ref_t v = emit_expr(a, n->statement_ret.expr); spl_ir_builder_control_ret(a->ir, ret_ir, v); } else { spl_ir_builder_control_ret(a->ir, ret_ir, 0); } return; } case SPL_AST_STATEMENT_BREAK: { if (vec_size(a->loop_stack) == 0) return; spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir); vec_push(vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).breaks, jmp); return; } case SPL_AST_STATEMENT_CONTINUE: { if (vec_size(a->loop_stack) == 0) return; spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir); usize cont = vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).cont_blk; spl_ir_builder_control_jmp_fixup(a->ir, jmp, cont); return; } case SPL_AST_STATEMENT_DEFER: if (n->statement_defer.body) vec_push(a->defer_stack, n->statement_defer.body); return; case SPL_AST_STATEMENT_COMPTIME: if (n->statement_comptime.body) emit_expr(a, n->statement_comptime.body); return; case SPL_AST_STATEMENT_DECL: if (n->statement_decl.decl) emit_decl(a, n->statement_decl.decl); return; case SPL_AST_STATEMENT_EXPR: 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_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; 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); return; } 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; 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); return; } case SPL_AST_EXPR_BLOCK: emit_expr(a, ref); return; default: emit_expr(a, ref); return; } } static void emit_decl(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; switch (n->kind) { case SPL_AST_VAR_DECL: case SPL_AST_CONST_DECL: { if (!a->ir->current_fn) return; if (!n->resolved_def_id) return; spl_ast_node_t *pat = spl_ast_node(a->sema->ast, n->var_const_decl.pattern); if (!pat || pat->kind != SPL_AST_PATTERN_IDENT) return; spl_lang_type_id_t var_lang = spl_def_get_lang_id(a->sema->type, n->resolved_def_id); spl_type_id_t var_ir = to_ir_type(a, var_lang); if (!var_ir) return; spl_ir_node_ref_t one = const_usize(a, 1); spl_ir_node_ref_t slot = spl_ir_builder_mem_alloca(a->ir, var_ir, one); map_put(a->def2ir_map, n->resolved_def_id, slot); if (n->var_const_decl.init_expr) { spl_ir_node_ref_t v = emit_expr(a, n->var_const_decl.init_expr); if (v) spl_ir_builder_mem_store(a->ir, var_ir, slot, v); } return; } case SPL_AST_FN_DECL: emit_fn(a, n); return; default: return; } } static void emit_fn(spl_ast2ir_t *a, spl_ast_node_t *n) { if (!n->resolved_def_id) return; spl_lang_type_id_t fn_lang = spl_def_get_lang_id(a->sema->type, n->resolved_def_id); spl_lang_type_node_t *fn_ln = spl_lang_type_node(a->sema->type, fn_lang); if (!fn_ln || fn_ln->kind != SPL_LANG_TYPE_FN) return; spl_type_id_t fn_ir = fn_ln->ir_type_id; if (!fn_ir) return; spl_ir_attr_t attr = {.kind = SPL_IR_ATTR_NONE}; spl_ir_func_ref_t fn_ref = spl_ir_builder_fn_begin(a->ir, n->fn_decl.name, fn_ir, attr); map_put(a->def2ir_map, n->resolved_def_id, (spl_ir_node_ref_t)fn_ref); spl_lang_type_id_t saved_ret = a->cur_ret_lang; a->cur_ret_lang = fn_ln->extra.fn.ret; usize defer_base = vec_size(a->defer_stack); usize loop_base = vec_size(a->loop_stack); spl_ir_builder_block_begin(a->ir); for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) { spl_ast_node_ref_t pref = vec_at(n->fn_decl.params, i); spl_ast_node_t *pd = spl_ast_node(a->sema->ast, pref); if (!pd || pd->kind != SPL_AST_PARAM_DECL) continue; if (!pd->resolved_def_id) continue; spl_lang_type_id_t p_lang = spl_def_get_lang_id(a->sema->type, pd->resolved_def_id); spl_type_id_t p_ir = to_ir_type(a, p_lang); if (!p_ir) continue; spl_ir_node_ref_t idx = const_usize(a, i); spl_ir_node_ref_t pv = spl_ir_builder_control_param(a->ir, p_ir, idx); spl_ir_node_ref_t one = const_usize(a, 1); spl_ir_node_ref_t slot = spl_ir_builder_mem_alloca(a->ir, p_ir, one); spl_ir_builder_mem_store(a->ir, p_ir, slot, pv); map_put(a->def2ir_map, pd->resolved_def_id, slot); } if (n->fn_decl.body) emit_expr(a, n->fn_decl.body); if (!a->ir->terminated) { while (vec_size(a->defer_stack) > defer_base) { spl_ast_node_ref_t d = vec_pop(a->defer_stack); emit_stmt(a, d); } spl_lang_type_id_t ret_lang = fn_ln->extra.fn.ret; spl_lang_type_node_t *ret_ln = spl_lang_type_node(a->sema->type, ret_lang); if (ret_ln && ret_ln->kind == SPL_LANG_TYPE_UNIT) { spl_ir_builder_control_ret(a->ir, to_ir_type(a, ret_lang), 0); } else { spl_ir_builder_control_unreachable(a->ir); } } /* 兜底清理: * - 若 body 已显式 return,defer 栈可能已被清空到 defer_base 之下 * (被 return 逻辑弹过),此时 vec_size <= defer_base,无需处理。 * - 若 body 里开了 loop 却没关(理论上不会,sema 已保证), * 这里的 while 只是防止异常路径残留。 */ while (vec_size(a->defer_stack) > defer_base) { spl_ast_node_ref_t d = vec_pop(a->defer_stack); (void)d; } while (vec_size(a->loop_stack) > loop_base) { spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1); vec_free(top->breaks); vec_pop(a->loop_stack); } a->cur_ret_lang = saved_ret; spl_ir_builder_block_end(a->ir); spl_ir_builder_fn_end(a->ir); } static void emit_container(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; if (n->kind == SPL_AST_TOP_LEVEL_BLOCK) { if (n->top_level_block.block) emit_container(a, n->top_level_block.block); return; } if (n->kind != SPL_AST_CONTAINER_MEMBERS) return; for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) { spl_ast_node_ref_t dref = vec_at(n->container_members.declarations, i); spl_ast_node_t *d = spl_ast_node(a->sema->ast, dref); if (!d) continue; switch (d->kind) { case SPL_AST_FN_DECL: emit_fn(a, d); break; case SPL_AST_TOP_LEVEL_BLOCK: emit_container(a, dref); break; default: break; } } } static usize spl_int_map_hash(usize k) { return MAP_HASH_INT(k); } static int spl_int_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); } void spl_ast2ir_init(spl_ast2ir_t *ast2ir, spl_ir_builder_t *ir, const spl_sema_t *sema) { ast2ir->sema = sema; ast2ir->ir = ir; map_init(ast2ir->def2ir_map, spl_int_map_hash, spl_int_map_cmp); vec_init(ast2ir->loop_stack); vec_init(ast2ir->defer_stack); ast2ir->err_count = 0; ast2ir->cur_ret_lang = 0; } void spl_ast2ir_drop(spl_ast2ir_t *ast2ir) { for (usize i = 0; i < vec_size(ast2ir->loop_stack); ++i) vec_free(vec_at(ast2ir->loop_stack, i).breaks); vec_free(ast2ir->loop_stack); vec_free(ast2ir->defer_stack); map_free(ast2ir->def2ir_map); } void spl_ast2ir_run(spl_ast2ir_t *ast2ir) { spl_ast_t *ast = ast2ir->sema->ast; if (!ast || !ast->root) return; spl_ast_node_t *root = spl_ast_node(ast, ast->root); if (!root || root->kind != SPL_AST_ROOT) return; emit_container(ast2ir, root->root.members); }