1643 lines
60 KiB
C
1643 lines
60 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_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_implicit_cast(spl_ast2ir_t *a, spl_ast_node_t *n, 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->ir, 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_diag_error(a->diag, SPL_DIAG_KIND_INTRIN_ARG_COUNT, &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->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->ast, vec_at(*args, 1));
|
|
tt = node_ir(a, targ);
|
|
} else {
|
|
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->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->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->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->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->ir, 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->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;
|
|
return emit_expr(a, n->unary.operand);
|
|
}
|
|
case SPL_AST_EXPR_FIELD: {
|
|
spl_ast_node_t *obj = spl_ast_node(a->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->ir, 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->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->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->ir, 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->ir, 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->ir, ft);
|
|
spl_type_node_t *ts = spl_type_node(&a->sema->type->ir, 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_diag_error(a->diag, SPL_DIAG_KIND_INTERNAL, &n->dbg, "ast2ir: 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->ast, n->cast.expr);
|
|
spl_ast_node_t *dst = spl_ast_node(a->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->ir, ft, tt);
|
|
if (in == SPL_INTRIN_NONE) {
|
|
spl_diag_error(a->diag, SPL_DIAG_KIND_CAST_INVALID, &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->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, n, 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->ast, ref);
|
|
if (!n)
|
|
return 0;
|
|
|
|
switch (n->kind) {
|
|
case SPL_AST_EXPR_INT_LIT: {
|
|
spl_type_id_t it = node_ir(a, n);
|
|
spl_type_node_t *itn = spl_type_node(&a->sema->type->ir, 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->ir, 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->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->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->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->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: {
|
|
spl_ast_node_t *cmln = spl_ast_node(a->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->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->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->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)));
|
|
|
|
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->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->ir, 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->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->ir, 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->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->ir, 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->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);
|
|
|
|
spl_ir_node_ref_t base = 0;
|
|
if (obj_kind == SPL_LANG_TYPE_PTR) {
|
|
base = emit_expr(a, n->slice.obj);
|
|
} else if (obj_kind == SPL_LANG_TYPE_SLICE) {
|
|
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(&a->sema->type->ir, elem_ir);
|
|
base = spl_ir_builder_agg_extract(a->ir, obj_ir, ptr_ir, SPL_SLICE_PTR_FIELD_IDX,
|
|
slice_val);
|
|
} else {
|
|
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->ir, 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_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
|
spl_ast_node_t *n = spl_ast_node(a->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->ir, 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->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->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->ir, 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);
|
|
|
|
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.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->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->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;
|
|
|
|
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->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);
|
|
|
|
spl_ir_node_ref_t v = 0;
|
|
if (n->statement_ret.expr)
|
|
v = emit_expr(a, n->statement_ret.expr);
|
|
|
|
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->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->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->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->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->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->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->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->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->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->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->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->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->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->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_ast_node_t *n, 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->ir, ft);
|
|
spl_type_node_t *ts = spl_type_node(&a->sema->type->ir, 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_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_PTR)
|
|
return 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);
|
|
|
|
spl_diag_fatal(a->diag, SPL_DIAG_KIND_IMPLICIT_CAST_FAIL, &n->dbg,
|
|
"implicit cast: cannot convert type#%zu -> type#%zu", ft, tt);
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
ast2ir->ast = sema->ast;
|
|
map_init(ast2ir->def2ir_map, spl_int_map_hash, spl_int_map_cmp);
|
|
vec_init(ast2ir->loop_stack);
|
|
vec_init(ast2ir->defer_stack);
|
|
ast2ir->cur_ret_lang = 0;
|
|
ast2ir->cur_defer_base = 0;
|
|
|
|
ast2ir->diag = NULL;
|
|
}
|
|
|
|
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_ptr_vec_t ast_vec) {
|
|
usize n = vec_size(ast_vec);
|
|
|
|
for (usize i = 0; i < n; ++i) {
|
|
spl_ast_t *ast = vec_at(ast_vec, i);
|
|
if (!ast || !ast->root)
|
|
continue;
|
|
ast2ir->ast = ast;
|
|
spl_ast_node_t *root = spl_ast_node(ast, ast->root);
|
|
if (!root || root->kind != SPL_AST_ROOT)
|
|
continue;
|
|
emit_container_reserve(ast2ir, root->root.members);
|
|
}
|
|
|
|
for (usize i = 0; i < n; ++i) {
|
|
spl_ast_t *ast = vec_at(ast_vec, i);
|
|
if (!ast || !ast->root)
|
|
continue;
|
|
ast2ir->ast = ast;
|
|
spl_ast_node_t *root = spl_ast_node(ast, ast->root);
|
|
if (!root || root->kind != SPL_AST_ROOT)
|
|
continue;
|
|
emit_container_body(ast2ir, root->root.members);
|
|
}
|
|
|
|
vec_free(ast_vec);
|
|
}
|