1230 lines
46 KiB
C
1230 lines
46 KiB
C
#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 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;
|
||
switch (tn->kind) {
|
||
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: {
|
||
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, tid);
|
||
for (usize i = 0; i < tn->array_type.len; ++i) {
|
||
spl_ir_node_ref_t f = emit_zero_value(a, tn->array_type.element);
|
||
if (!f)
|
||
return 0;
|
||
spl_ir_builder_agg_construct_field(a->ir, node, f);
|
||
}
|
||
return node;
|
||
}
|
||
case SPL_TYPE_STRUCT:
|
||
case SPL_TYPE_SHAPE: {
|
||
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, tid);
|
||
for (usize i = 0; i < vec_size(tn->agg_type.variants); ++i) {
|
||
spl_ir_node_ref_t f = emit_zero_value(a, vec_at(tn->agg_type.variants, i).type_id);
|
||
if (!f)
|
||
return 0;
|
||
spl_ir_builder_agg_construct_field(a->ir, node, f);
|
||
}
|
||
return node;
|
||
}
|
||
case SPL_TYPE_UNION: {
|
||
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, tid);
|
||
if (vec_size(tn->agg_type.variants) == 0)
|
||
return node;
|
||
spl_ir_node_ref_t f = emit_zero_value(a, vec_at(tn->agg_type.variants, 0).type_id);
|
||
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_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;
|
||
}
|
||
|
||
for (usize i = 0; i < nfields; ++i) {
|
||
if (!vec_at(fields, i)) {
|
||
spl_type_id_t ftid = vec_at(tn->agg_type.variants, i).type_id;
|
||
spl_ir_node_ref_t f = emit_zero_value(a, ftid);
|
||
if (!f)
|
||
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)
|
||
Panic("agg_construct failed for aggregate literal");
|
||
|
||
for (usize i = 0; i < nfields; ++i) {
|
||
spl_ir_builder_agg_construct_field(a->ir, node, vec_at(fields, i));
|
||
}
|
||
|
||
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);
|
||
}
|