Files
spl/stage1/spl_ast2ir.c
T

1174 lines
44 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_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 emit_expr_raw(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 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_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_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_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;
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_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_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);
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_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:
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: {
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);
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, &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);
}
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");
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;
spl_type_id_t slice_ir = node_ir(a, n);
if (!slice_ir)
return 0;
spl_lang_type_id_t elem_lang = obj_ln->extra.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);
spl_ir_node_ref_t 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_ln->kind == SPL_LANG_TYPE_ARRAY) {
spl_type_node_t *arr = spl_type_node(a->sema->type, obj_ln->ir_type_id);
end_v = spl_ir_builder_type_const_int(a->ir, usize_ir, 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);
end_v = spl_ir_builder_agg_extract(a->ir, obj_ln->ir_type_id, 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 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_func_ref_t fn_ref = spl_ir_builder_fn_begin(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);
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 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;
}
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);
}