Files
spl/stage1/spl_ast2ir.c
T

1691 lines
62 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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) {
(void)a;
return n ? n->resolved_lang_tid : 0;
}
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_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);
static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
static void emit_fn_reserve(spl_ast2ir_t *a, spl_ast_node_t *n);
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);
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);
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 emit_zero_value(spl_ast2ir_t *a, spl_type_id_t tid) {
spl_type_node_t *tn = spl_type_node(a->sema->type, tid);
if (!tn)
return 0;
spl_type_node_kind_t tk = tn->kind;
switch (tk) {
case SPL_TYPE_BOOL:
return spl_ir_builder_type_const_bool(a->ir, tid, false);
case SPL_TYPE_INT:
return spl_ir_builder_type_const_int(a->ir, tid, 0);
case SPL_TYPE_FLOAT:
return spl_ir_builder_type_const_float(a->ir, tid, 0.0);
case SPL_TYPE_PTR:
case SPL_TYPE_FN:
return spl_ir_builder_type_const_ptr(a->ir, tid, NULL);
case SPL_TYPE_ARRAY: {
usize arr_len = tn->array_type.len;
spl_type_id_t arr_elem = tn->array_type.element;
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, tid);
for (usize i = 0; i < arr_len; ++i) {
spl_ir_node_ref_t f = emit_zero_value(a, arr_elem);
if (!f)
return 0;
spl_ir_builder_agg_construct_field(a->ir, node, f);
}
return node;
}
case SPL_TYPE_STRUCT:
case SPL_TYPE_SHAPE: {
usize nfield = vec_size(tn->agg_type.variants);
spl_type_id_vec_t field_tids;
vec_init(field_tids);
for (usize i = 0; i < nfield; ++i)
vec_push(field_tids, vec_at(tn->agg_type.variants, i).type_id);
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, tid);
for (usize i = 0; i < nfield; ++i) {
spl_ir_node_ref_t f = emit_zero_value(a, vec_at(field_tids, i));
if (!f) {
vec_free(field_tids);
return 0;
}
spl_ir_builder_agg_construct_field(a->ir, node, f);
}
vec_free(field_tids);
return node;
}
case SPL_TYPE_UNION: {
usize nfield = vec_size(tn->agg_type.variants);
if (nfield == 0)
return spl_ir_builder_agg_construct(a->ir, tid);
spl_type_id_t first_tid = vec_at(tn->agg_type.variants, 0).type_id;
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, tid);
spl_ir_node_ref_t f = emit_zero_value(a, first_tid);
if (!f)
return 0;
spl_ir_builder_agg_construct_field(a->ir, node, f);
return node;
}
default:
return 0;
}
}
static void copy_attrs_to_ir_node(spl_ast2ir_t *a, spl_ast_node_t *n, spl_ir_node_ref_t ir_ref) {
if (!ir_ref || !n || vec_size(n->attrs) == 0)
return;
spl_ir_node_t *irn = spl_ir_node(&a->ir->ir, a->ir->current_fn, ir_ref);
if (!irn)
return;
for (usize i = 0; i < vec_size(n->attrs); ++i)
vec_push(irn->attrs, vec_at(n->attrs, i));
}
static void copy_attrs_to_ir_func(spl_ast2ir_t *a, spl_ast_node_t *n, spl_ir_func_ref_t fn_ref) {
if (!fn_ref || !n || vec_size(n->attrs) == 0)
return;
spl_ir_func_t *irf = spl_ir_func(&a->ir->ir, fn_ref);
if (!irf)
return;
for (usize i = 0; i < vec_size(n->attrs); ++i)
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) {
case SPL_INTRIN_SIZEOF: {
spl_ast_node_t *arg = spl_ast_node(a->sema->ast, vec_at(*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(*args, 0));
return spl_ir_builder_type_alignof(a->ir, node_ir(a, arg));
}
case SPL_INTRIN_ASSERT: {
spl_ir_node_ref_t cond = emit_expr(a, vec_at(*args, 0));
if (!cond)
return 0;
spl_lang_type_id_t b = spl_lang_make_bool(a->sema->type);
spl_ir_node_ref_t notc = spl_ir_builder_arith_not(a->ir, to_ir_type(a, b), cond);
spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, notc);
spl_ir_builder_block_end(a->ir);
usize panic_blk = spl_ir_builder_block_begin(a->ir);
const char *fname = n->dbg.fname ? n->dbg.fname : "?";
const char *user_msg = NULL;
if (vec_size(*args) == 2) {
spl_ast_node_t *mn = spl_ast_node(a->sema->ast, vec_at(*args, 1));
if (mn && mn->kind == SPL_AST_EXPR_STRING_LIT && mn->string_lit.data)
user_msg = mn->string_lit.data;
}
char *msg;
int need;
if (user_msg) {
need = snprintf(NULL, 0, "%s:%d:%d: assert failed: %s", fname, n->dbg.line, n->dbg.col,
user_msg);
msg = malloc((usize)need + 1);
snprintf(msg, (usize)need + 1, "%s:%d:%d: assert failed: %s", fname, n->dbg.line,
n->dbg.col, user_msg);
} else {
need = snprintf(NULL, 0, "%s:%d:%d: assert failed", fname, n->dbg.line, n->dbg.col);
msg = malloc((usize)need + 1);
snprintf(msg, (usize)need + 1, "%s:%d:%d: assert failed", fname, n->dbg.line,
n->dbg.col);
}
spl_ir_builder_dbg_panic(a->ir, msg, (usize)need);
spl_ir_builder_control_trap(a->ir);
spl_ir_builder_block_end(a->ir);
usize cont_blk = spl_ir_builder_block_begin(a->ir);
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:
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, recv->ir_type_id, 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_UNARY: {
if (n->unary.op != SPL_UNARY_OP_DEREF)
return 0;
/* *p 作为左值,地址就是指针 p 的值 */
return emit_expr(a, n->unary.operand);
}
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;
spl_lang_type_kind_t obj_kind = obj_ln->kind;
spl_lang_type_id_t obj_elem = (obj_kind == SPL_LANG_TYPE_PTR) ? obj_ln->extra.elem : 0;
if (spl_intrin_lookup_field(obj_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_kind == SPL_LANG_TYPE_PTR) {
base = emit_expr(a, n->field.obj);
agg_lang = obj_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_lang_type_node_t *agg_ln = spl_lang_type_node(a->sema->type, agg_lang);
if (agg_ln && agg_ln->kind == SPL_LANG_TYPE_ENUM)
idx += 1;
return spl_ir_builder_mem_field(a->ir, agg_ir, base, idx);
}
case SPL_AST_EXPR_INDEX: {
spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->index.obj);
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_lang_type_kind_t obj_kind = obj_ln->kind;
spl_lang_type_id_t obj_elem = 0;
if (obj_kind == SPL_LANG_TYPE_PTR || obj_kind == SPL_LANG_TYPE_ARRAY ||
obj_kind == SPL_LANG_TYPE_SLICE)
obj_elem = obj_ln->extra.elem;
if (obj_kind == SPL_LANG_TYPE_TUPLE) {
spl_ast_node_t *idx_node = spl_ast_node(a->sema->ast, n->index.index);
if (!idx_node || idx_node->kind != SPL_AST_EXPR_INT_LIT)
return 0;
usize i = (usize)idx_node->int_lit.bits;
spl_ir_node_ref_t base = emit_lvalue(a, n->index.obj);
if (!base)
return 0;
spl_type_id_t tuple_ir = to_ir_type(a, obj_lang);
if (!tuple_ir)
return 0;
return spl_ir_builder_mem_field(a->ir, tuple_ir, base, i);
}
spl_ir_node_ref_t base = 0;
spl_lang_type_id_t elem_lang = 0;
if (obj_kind == SPL_LANG_TYPE_PTR) {
base = emit_expr(a, n->index.obj);
elem_lang = obj_elem;
} else if (obj_kind == SPL_LANG_TYPE_ARRAY) {
base = emit_lvalue(a, n->index.obj);
elem_lang = obj_elem;
} else if (obj_kind == SPL_LANG_TYPE_SLICE) {
spl_ir_node_ref_t slice_val = emit_expr(a, n->index.obj);
if (!slice_val)
return 0;
spl_type_id_t ptr_ir = spl_type_builder_ptr(a->sema->type, to_ir_type(a, obj_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 = obj_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 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)
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);
if (!ft || !tt)
return 0;
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;
}
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) {
spl_ir_node_ref_t val = emit_expr_raw(a, ref);
if (!val)
return 0;
spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref);
if (!n || n->expected_lang_tid == 0)
return val;
copy_attrs_to_ir_node(a, n, val);
spl_lang_type_id_t from = n->resolved_lang_tid;
spl_lang_type_id_t to = n->expected_lang_tid;
if (!from || from == to)
return val;
spl_type_id_t from_ir = to_ir_type(a, from);
spl_type_id_t to_ir = to_ir_type(a, to);
if (!from_ir || !to_ir || from_ir == to_ir)
return val;
return emit_implicit_cast(a, from_ir, to_ir, val);
}
static spl_ir_node_ref_t emit_expr_raw(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: {
/* 节点经 coerce 后 resolved 可能是具体 int 或 float。
* 值始终存在 int_lit.bits(补码);按 resolved 决定如何构造 IR 常量。 */
spl_type_id_t it = node_ir(a, n);
spl_type_node_t *itn = spl_type_node(a->sema->type, it);
if (itn && itn->kind == SPL_TYPE_FLOAT) {
double d = (double)(int64_t)n->int_lit.bits;
return spl_ir_builder_type_const_float(a->ir, it, d);
}
return spl_ir_builder_type_const_int(a->ir, it, (usize)n->int_lit.bits);
}
case SPL_AST_EXPR_FLOAT_LIT:
return spl_ir_builder_type_const_float(a->ir, node_ir(a, n), n->float_lit.bits);
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: {
usize len = n->string_lit.len;
spl_lang_type_id_t u8_lang = spl_lang_make_int(a->sema->type, 8, 0);
spl_type_id_t u8_ir = to_ir_type(a, u8_lang);
spl_type_id_t ptr_u8_ir = spl_type_builder_ptr(a->sema->type, u8_ir);
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_lang_type_id_t arr_lang = spl_lang_make_array(a->sema->type, u8_lang, len);
spl_type_id_t arr_ir = to_ir_type(a, arr_lang);
spl_ir_node_ref_t raw =
spl_ir_builder_type_const_bytes(a->ir, arr_ir, n->string_lit.data, n->string_lit.len);
spl_ir_node_ref_t ptr = spl_ir_builder_mem_global_alloc(a->ir, ptr_u8_ir, raw);
spl_ir_node_ref_t len_c = spl_ir_builder_type_const_int(a->ir, usize_ir, len);
spl_type_id_t slice_ir = node_ir(a, n);
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, slice_ir);
spl_ir_builder_agg_construct_field(a->ir, node, ptr);
spl_ir_builder_agg_construct_field(a->ir, node, len_c);
return node;
}
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);
if (n->unary.op == SPL_UNARY_OP_DEREF) {
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);
}
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_ast_node_t *ln = spl_ast_node(a->sema->ast, n->binary.left);
spl_lang_type_id_t lt = node_lang(a, ln);
spl_lang_type_node_t *lln = spl_lang_type_node(a->sema->type, lt);
if (lln && lln->kind == SPL_LANG_TYPE_PTR && (op == SPL_OP_ADD || op == SPL_OP_SUB)) {
spl_lang_type_id_t elem_lang = lln->extra.elem;
spl_type_id_t elem_ir = to_ir_type(a, elem_lang);
spl_type_id_t rt_ir = node_ir(a, spl_ast_node(a->sema->ast, n->binary.right));
spl_ir_node_ref_t off = r;
if (op == SPL_OP_SUB)
off = spl_ir_builder_arith_neg(a->ir, rt_ir, r);
return spl_ir_builder_mem_offset(a->ir, elem_ir, l, off);
}
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:
case SPL_OP_CMP_NE:
case SPL_OP_CMP_LT:
case SPL_OP_CMP_LE:
case SPL_OP_CMP_GT:
case SPL_OP_CMP_GE: {
/* 比较的操作数类型从左侧子节点读(sema 已 coerce 到共同类型) */
spl_ast_node_t *cmln = spl_ast_node(a->sema->ast, n->binary.left);
spl_type_id_t op_tid = cmln ? node_ir(a, cmln) : 0;
switch (op) {
case SPL_OP_CMP_EQ:
return spl_ir_builder_cmp_eq(a->ir, op_tid, l, r);
case SPL_OP_CMP_NE:
return spl_ir_builder_cmp_ne(a->ir, op_tid, l, r);
case SPL_OP_CMP_LT:
return spl_ir_builder_cmp_lt(a->ir, op_tid, l, r);
case SPL_OP_CMP_LE:
return spl_ir_builder_cmp_le(a->ir, op_tid, l, r);
case SPL_OP_CMP_GT:
return spl_ir_builder_cmp_gt(a->ir, op_tid, l, r);
case SPL_OP_CMP_GE:
return spl_ir_builder_cmp_ge(a->ir, op_tid, l, r);
default:
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;
}
}
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, &n->call.args);
}
spl_ir_node_ref_t fn = emit_expr(a, n->call.callee);
if (!fn)
return 0;
/* 先求所有参数 */
usize nargs = vec_size(n->call.args);
spl_ir_node_ref_vec_t arg_refs;
vec_init(arg_refs);
for (usize i = 0; i < nargs; ++i)
vec_push(arg_refs, emit_expr(a, vec_at(n->call.args, i)));
/* 再创建 call 节点 */
spl_type_id_t ret_t = node_ir(a, n);
spl_ir_node_ref_t call = spl_ir_builder_control_call(a->ir, ret_t, fn);
if (!call) {
vec_free(arg_refs);
return 0;
}
for (usize i = 0; i < vec_size(arg_refs); ++i)
spl_ir_builder_control_call_param(a->ir, call, vec_at(arg_refs, i));
vec_free(arg_refs);
return call;
}
case SPL_AST_EXPR_FIELD: {
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);
}
if (n->resolved_def_id) {
spl_def_node_t *fd = spl_def_node(a->sema->type, n->resolved_def_id);
if (fd && fd->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 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);
usize nelems = vec_size(n->tuple.elems);
spl_ir_node_ref_vec_t field_refs;
vec_init(field_refs);
for (usize i = 0; i < nelems; ++i) {
spl_ir_node_ref_t f = emit_expr(a, vec_at(n->tuple.elems, i));
if (!f)
Panic("tuple element emit failed");
vec_push(field_refs, f);
}
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t);
if (!node)
Panic("agg_construct failed for tuple");
for (usize i = 0; i < nelems; ++i)
spl_ir_builder_agg_construct_field(a->ir, node, vec_at(field_refs, i));
vec_free(field_refs);
return node;
}
case SPL_AST_EXPR_ARRAY_LIT: {
spl_type_id_t t = node_ir(a, n);
if (!t)
Panic("array literal has no type after sema");
usize nelems = vec_size(n->array_literal.elems);
spl_ir_node_ref_vec_t field_refs;
vec_init(field_refs);
for (usize i = 0; i < nelems; ++i) {
spl_ir_node_ref_t f = emit_expr(a, vec_at(n->array_literal.elems, i));
if (!f)
Panic("array element emit failed");
vec_push(field_refs, f);
}
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t);
if (!node)
Panic("agg_construct failed for array literal");
for (usize i = 0; i < nelems; ++i)
spl_ir_builder_agg_construct_field(a->ir, node, vec_at(field_refs, i));
vec_free(field_refs);
return node;
}
case SPL_AST_EXPR_AGGREGATE_LIT: {
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");
spl_type_node_kind_t tn_kind = tn->kind;
if (tn_kind == SPL_TYPE_ENUM) {
if (vec_size(n->aggregate_literal.fields) != 1)
Panic("enum literal must have exactly one variant");
spl_ast_node_t *item =
spl_ast_node(a->sema->ast, vec_at(n->aggregate_literal.fields, 0));
if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM)
Panic("invalid enum literal");
usize vidx = 0;
if (!spl_type_agg_member_idx(a->sema->type, t, item->struct_init_item.name, &vidx))
Panic("enum variant `%s` not found (sema should have caught this)",
item->struct_init_item.name);
spl_type_id_t tag_ir = tn->agg_type.tag_type;
spl_type_id_t payload_ir = vec_at(tn->agg_type.variants, vidx).type_id;
spl_ir_node_ref_t eptr = spl_ir_builder_mem_alloca(a->ir, t, const_usize(a, 1));
spl_ir_node_ref_t tptr =
spl_ir_builder_mem_field(a->ir, t, eptr, SPL_ENUM_TAG_FIELD_IDX);
spl_ir_node_ref_t tag_val = spl_ir_builder_type_const_int(a->ir, tag_ir, vidx);
spl_ir_builder_mem_store(a->ir, tag_ir, tptr, tag_val);
spl_ir_node_ref_t pptr = spl_ir_builder_mem_field(a->ir, t, eptr, vidx + 1);
spl_ir_node_ref_t payload = emit_expr(a, item->struct_init_item.expr);
if (!payload)
Panic("enum payload emit failed");
spl_ir_builder_mem_store(a->ir, payload_ir, pptr, payload);
return eptr;
}
usize nfields = vec_size(tn->agg_type.variants);
spl_type_id_vec_t field_tids;
vec_init(field_tids);
for (usize i = 0; i < nfields; ++i)
vec_push(field_tids, vec_at(tn->agg_type.variants, i).type_id);
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;
}
for (usize i = 0; i < nfields; ++i) {
if (!vec_at(fields, i)) {
spl_ir_node_ref_t f = emit_zero_value(a, vec_at(field_tids, i));
if (!f) {
vec_free(field_tids);
vec_free(fields);
Panic("cannot zero-init aggregate field #%zu", i);
}
vec_at(fields, i) = f;
}
}
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t);
if (!node) {
vec_free(field_tids);
vec_free(fields);
Panic("agg_construct failed for aggregate literal");
}
for (usize i = 0; i < nfields; ++i) {
spl_ir_node_ref_t f = vec_at(fields, i);
if (!f) {
vec_free(field_tids);
vec_free(fields);
Panic("aggregate field #%zu missing (sema should have caught this)", i);
}
spl_ir_builder_agg_construct_field(a->ir, node, f);
}
vec_free(field_tids);
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:
return emit_if_like(a, ref);
case SPL_AST_EXPR_WHILE:
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);
spl_lang_type_node_t *obj_ln = spl_lang_type_node(a->sema->type, obj_lang);
if (!obj_ln)
return 0;
spl_lang_type_kind_t obj_kind = obj_ln->kind;
spl_lang_type_id_t obj_elem = obj_ln->extra.elem;
spl_type_id_t obj_ir = obj_ln->ir_type_id;
spl_type_id_t slice_ir = node_ir(a, n);
if (!slice_ir)
return 0;
spl_lang_type_id_t elem_lang = obj_elem;
spl_type_id_t elem_ir = to_ir_type(a, elem_lang);
spl_lang_type_id_t usize_lang = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0);
spl_type_id_t usize_ir = to_ir_type(a, usize_lang);
/* 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;
spl_ir_node_ref_t begin_v = 0;
if (n->slice.begin)
begin_v = emit_expr(a, n->slice.begin);
else
begin_v = spl_ir_builder_type_const_int(a->ir, usize_ir, 0);
if (!begin_v)
return 0;
spl_ir_node_ref_t ptr = spl_ir_builder_mem_offset(a->ir, elem_ir, base, begin_v);
if (!ptr)
return 0;
spl_ir_node_ref_t end_v = 0;
if (n->slice.end) {
end_v = emit_expr(a, n->slice.end);
} else if (obj_kind == SPL_LANG_TYPE_ARRAY) {
spl_type_node_t *arr = spl_type_node(a->sema->type, obj_ir);
if (!arr)
return 0;
usize arr_len = arr->array_type.len;
end_v = spl_ir_builder_type_const_int(a->ir, usize_ir, arr_len);
} else if (obj_kind == SPL_LANG_TYPE_SLICE) {
spl_ir_node_ref_t slice_val = emit_expr(a, n->slice.obj);
end_v = spl_ir_builder_agg_extract(a->ir, obj_ir, usize_ir, SPL_SLICE_LEN_FIELD_IDX,
slice_val);
} else {
return 0;
}
if (!end_v)
return 0;
spl_ir_node_ref_t len = spl_ir_builder_arith_sub(a->ir, usize_ir, end_v, begin_v);
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, slice_ir);
if (!node)
return 0;
spl_ir_builder_agg_construct_field(a->ir, node, ptr);
spl_ir_builder_agg_construct_field(a->ir, node, len);
return node;
}
case SPL_AST_EXPR_COMPTIME_CALL: {
spl_intrin_t in = spl_intrin_lookup_call(n->comptime_call.name);
if (in == SPL_INTRIN_NONE)
return 0;
return ast2ir_intrin_call(a, n, in, &n->comptime_call.args);
}
default:
TODO();
return 0;
}
}
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)
return;
switch (n->kind) {
case SPL_AST_STATEMENT_RET: {
spl_type_id_t ret_ir = to_ir_type(a, a->cur_ret_lang);
/* 先求值 ret 表达式,结果保存在 v 中 */
spl_ir_node_ref_t v = 0;
if (n->statement_ret.expr)
v = emit_expr(a, n->statement_ret.expr);
/* 再执行 defer(LIFO),只清空当前函数注册的 defer */
while (vec_size(a->defer_stack) > a->cur_defer_base) {
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
emit_stmt(a, d);
}
spl_ir_builder_control_ret(a->ir, ret_ir, v);
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:
case SPL_AST_EXPR_IFVAR: {
(void)emit_if_like(a, ref);
return;
}
case SPL_AST_EXPR_WHILE:
case SPL_AST_EXPR_LOOP: {
(void)emit_loop_like(a, ref);
return;
}
case SPL_AST_STATEMENT_BREAK:
emit_break_stmt(a, n);
return;
case SPL_AST_STATEMENT_CONTINUE: {
if (vec_size(a->loop_stack) == 0)
return;
const char *lbl = NULL;
if (n->statement_continue.label) {
spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->statement_continue.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) {
spl_ir_builder_control_jmp_fixup(a->ir, jmp, c->cont_blk);
return;
}
}
return;
}
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_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;
}
default:
return;
}
}
static void emit_fn_reserve(spl_ast2ir_t *a, spl_ast_node_t *n) {
if (!n || !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_func_ref_t fn_ref = spl_ir_builder_fn_reserve(a->ir, n->fn_decl.name, fn_ir);
map_put(a->def2ir_map, n->resolved_def_id, (spl_ir_node_ref_t)fn_ref);
copy_attrs_to_ir_func(a, n, fn_ref);
}
static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n) {
if (!n || !n->resolved_def_id)
return;
spl_ir_func_ref_t fn_ref = 0;
if (!map_get(a->def2ir_map, n->resolved_def_id, &fn_ref))
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_lang_type_id_t ret_lang = fn_ln->extra.fn.ret;
spl_type_id_t ret_ir = to_ir_type(a, ret_lang);
spl_lang_type_node_t *ret_ln = spl_lang_type_node(a->sema->type, ret_lang);
int ret_is_unit = (ret_ln && ret_ln->kind == SPL_LANG_TYPE_UNIT) ? 1 : 0;
spl_ir_builder_fn_begin_at(a->ir, fn_ref);
spl_lang_type_id_t saved_ret = a->cur_ret_lang;
a->cur_ret_lang = ret_lang;
usize saved_defer_base = a->cur_defer_base;
a->cur_defer_base = vec_size(a->defer_stack);
usize defer_base = a->cur_defer_base;
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);
}
if (ret_is_unit) {
spl_ir_builder_control_ret(a->ir, ret_ir, 0);
} else if (ret_ir) {
spl_ir_node_ref_t zero = emit_zero_value(a, ret_ir);
spl_ir_builder_control_ret(a->ir, ret_ir, zero);
} else {
spl_ir_builder_control_unreachable(a->ir);
}
}
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;
a->cur_defer_base = saved_defer_base;
spl_ir_builder_block_end(a->ir);
spl_ir_builder_fn_end(a->ir);
}
static void emit_aggregate_fns_reserve(spl_ast2ir_t *a, spl_ast_node_t *te) {
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
spl_ast_node_t *mn = spl_ast_node(a->sema->ast, vec_at(te->type_aggregate.members, i));
if (!mn)
continue;
if (mn->kind == SPL_AST_FN_DECL) {
emit_fn_reserve(a, mn);
} else if (mn->kind == SPL_AST_MEMBER_DECL && mn->member_decl.type_expr) {
spl_ast_node_t *mt = spl_ast_node(a->sema->ast, mn->member_decl.type_expr);
if (mt && mt->kind == SPL_AST_TYPE_AGGREGATE)
emit_aggregate_fns_reserve(a, mt);
}
}
}
static void emit_aggregate_fns_body(spl_ast2ir_t *a, spl_ast_node_t *te) {
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
spl_ast_node_t *mn = spl_ast_node(a->sema->ast, vec_at(te->type_aggregate.members, i));
if (!mn)
continue;
if (mn->kind == SPL_AST_FN_DECL) {
emit_fn_body(a, mn);
} else if (mn->kind == SPL_AST_MEMBER_DECL && mn->member_decl.type_expr) {
spl_ast_node_t *mt = spl_ast_node(a->sema->ast, mn->member_decl.type_expr);
if (mt && mt->kind == SPL_AST_TYPE_AGGREGATE)
emit_aggregate_fns_body(a, mt);
}
}
}
static void emit_container_reserve(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_reserve(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_reserve(a, d);
break;
case SPL_AST_TYPE_DECL: {
spl_ast_node_t *te = spl_ast_node(a->sema->ast, d->type_decl.type_expr);
if (te && te->kind == SPL_AST_TYPE_AGGREGATE)
emit_aggregate_fns_reserve(a, te);
break;
}
case SPL_AST_TOP_LEVEL_BLOCK:
emit_container_reserve(a, dref);
break;
default:
break;
}
}
}
static void emit_container_body(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_body(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_body(a, d);
break;
case SPL_AST_TYPE_DECL: {
spl_ast_node_t *te = spl_ast_node(a->sema->ast, d->type_decl.type_expr);
if (te && te->kind == SPL_AST_TYPE_AGGREGATE)
emit_aggregate_fns_body(a, te);
break;
}
case SPL_AST_TOP_LEVEL_BLOCK:
emit_container_body(a, dref);
break;
default:
break;
}
}
}
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) {
if (!ft || !tt || ft == tt)
return v;
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 v;
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 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;
ast2ir->cur_defer_base = 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_reserve(ast2ir, root->root.members);
emit_container_body(ast2ir, root->root.members);
}