829 lines
30 KiB
C
829 lines
30 KiB
C
#include "spl_ir.h"
|
|
|
|
const char *spl_ir_kind_name(spl_ir_kind_t kind) {
|
|
static const char *const names[] = {
|
|
#define X(a, b, c) #a,
|
|
SPL_IR_FN_TABLE
|
|
#undef X
|
|
};
|
|
if ((usize)kind < sizeof(names) / sizeof(names[0]))
|
|
return names[kind];
|
|
return "?";
|
|
}
|
|
|
|
#define SPL_ENUM_TAG_FIELD_IDX 0
|
|
|
|
void spl_ir_init(spl_ir_t *ir) {
|
|
vec_init(ir->funcs);
|
|
vec_push(ir->funcs, (spl_ir_func_t){0});
|
|
// vec_init(ir->gdata);
|
|
// vec_push(ir->gdata, (spl_ir_node_t){0});
|
|
}
|
|
|
|
static void node_drop_vecs(spl_ir_node_t *n) {
|
|
if (!n)
|
|
return;
|
|
switch (n->kind) {
|
|
case SPL_IR_AGG_CONSTRUCT:
|
|
vec_free(n->agg_construct.fields);
|
|
break;
|
|
case SPL_IR_CONTROL_CALL:
|
|
vec_free(n->control_call.params);
|
|
break;
|
|
case SPL_IR_DBG_PANIC:
|
|
free((char *)n->dbg_panic.msg);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void spl_ir_drop(spl_ir_t *ir) {
|
|
vec_for(ir->funcs, i) {
|
|
spl_ir_func_t *f = &vec_at(ir->funcs, i);
|
|
vec_for(f->nodes, j) {
|
|
vec_free(vec_at(f->nodes, j).attrs);
|
|
node_drop_vecs(&vec_at(f->nodes, j));
|
|
}
|
|
vec_free(f->attrs);
|
|
vec_free(f->nodes);
|
|
}
|
|
vec_free(ir->funcs);
|
|
// vec_for(ir->gdata, i) { node_drop_vecs(&vec_at(ir->gdata, i)); }
|
|
// vec_free(ir->gdata);
|
|
}
|
|
|
|
// 申请空的 ir_func 返回 id
|
|
spl_ir_func_ref_t spl_ir_alloc_fn(spl_ir_t *ir) {
|
|
if (ir == NULL) {
|
|
return 0;
|
|
}
|
|
spl_ir_func_t f = {0};
|
|
vec_init(f.nodes);
|
|
vec_push(f.nodes, (spl_ir_node_t){0});
|
|
vec_push(ir->funcs, f);
|
|
return vec_size(ir->funcs) - 1;
|
|
}
|
|
|
|
// 从 fn_id 申请空的 ir_node 返回 id
|
|
spl_ir_node_ref_t spl_ir_alloc_node(spl_ir_t *ir, spl_ir_func_ref_t fn_id) {
|
|
if (!fn_id || fn_id >= vec_size(ir->funcs)) {
|
|
return 0;
|
|
}
|
|
spl_ir_func_t *f = &vec_at(ir->funcs, fn_id);
|
|
spl_ir_node_t n = {0};
|
|
vec_push(f->nodes, n);
|
|
return vec_size(f->nodes) - 1;
|
|
}
|
|
|
|
// 从 fn_id 里通过 node_id 获取 ir_node
|
|
spl_ir_node_t *spl_ir_node(spl_ir_t *ir, spl_ir_func_ref_t fn_id, spl_ir_node_ref_t node_id) {
|
|
if (!fn_id || fn_id >= vec_size(ir->funcs)) {
|
|
return NULL;
|
|
}
|
|
spl_ir_func_t *f = &vec_at(ir->funcs, fn_id);
|
|
if (!node_id || node_id >= vec_size(f->nodes)) {
|
|
return NULL;
|
|
}
|
|
return &vec_at(f->nodes, node_id);
|
|
}
|
|
|
|
// 从 fn_id 获取 ir_func
|
|
spl_ir_func_t *spl_ir_func(spl_ir_t *ir, spl_ir_func_ref_t fn_id) {
|
|
if (!fn_id || fn_id >= vec_size(ir->funcs)) {
|
|
return NULL;
|
|
}
|
|
return &vec_at(ir->funcs, fn_id);
|
|
}
|
|
|
|
static inline void ir_dump_type(const spl_type_t *ty, spl_type_id_t tid) {
|
|
printf("(");
|
|
spl_type_pure_dump((spl_type_t *)ty, tid);
|
|
printf(")");
|
|
}
|
|
|
|
static inline void ir_dump_ref(spl_ir_node_ref_t ref) {
|
|
if (ref == 0) {
|
|
printf(" _");
|
|
} else {
|
|
printf(" %%%zu", ref);
|
|
}
|
|
}
|
|
|
|
static void ir_dump_node(const spl_type_t *ty, spl_ir_node_t *n) {
|
|
switch (n->kind) {
|
|
case SPL_IR_ARITH_ADD:
|
|
case SPL_IR_ARITH_SUB:
|
|
case SPL_IR_ARITH_MUL:
|
|
case SPL_IR_ARITH_DIV:
|
|
case SPL_IR_ARITH_REM:
|
|
case SPL_IR_ARITH_AND:
|
|
case SPL_IR_ARITH_OR:
|
|
case SPL_IR_ARITH_XOR:
|
|
case SPL_IR_ARITH_SHL:
|
|
case SPL_IR_ARITH_SHR:
|
|
ir_dump_type(ty, n->arith.tid);
|
|
ir_dump_ref(n->arith.left);
|
|
ir_dump_ref(n->arith.right);
|
|
break;
|
|
case SPL_IR_ARITH_NEG:
|
|
case SPL_IR_ARITH_ABS:
|
|
case SPL_IR_ARITH_NOT:
|
|
ir_dump_type(ty, n->arith.tid);
|
|
ir_dump_ref(n->arith.left);
|
|
break;
|
|
case SPL_IR_CMP_EQ:
|
|
case SPL_IR_CMP_NE:
|
|
case SPL_IR_CMP_LT:
|
|
case SPL_IR_CMP_LE:
|
|
case SPL_IR_CMP_GT:
|
|
case SPL_IR_CMP_GE:
|
|
ir_dump_type(ty, n->cmp.tid);
|
|
ir_dump_ref(n->cmp.a);
|
|
ir_dump_ref(n->cmp.b);
|
|
break;
|
|
case SPL_IR_CAST_TRUNC:
|
|
case SPL_IR_CAST_ZEXT:
|
|
case SPL_IR_CAST_SEXT:
|
|
case SPL_IR_CAST_FEXT:
|
|
case SPL_IR_CAST_FTRUNC:
|
|
case SPL_IR_CAST_BITCAST:
|
|
case SPL_IR_CAST_PTR2INT:
|
|
case SPL_IR_CAST_INT2PTR:
|
|
case SPL_IR_CAST_BOOL2INT:
|
|
case SPL_IR_CASE_INT2FLOAT:
|
|
case SPL_IR_CASE_FLOAT2INT:
|
|
printf(" ");
|
|
spl_type_pure_dump((spl_type_t *)ty, n->cast.from_tid);
|
|
printf(" -> ");
|
|
spl_type_pure_dump((spl_type_t *)ty, n->cast.to_tid);
|
|
ir_dump_ref(n->cast.val);
|
|
break;
|
|
case SPL_IR_MEM_ALLOCA:
|
|
ir_dump_type(ty, n->mem_alloc.tid);
|
|
ir_dump_ref(n->mem_alloc.count);
|
|
break;
|
|
case SPL_IR_MEM_GLOBAL_ALLOC:
|
|
ir_dump_type(ty, n->mem_global_alloc.tid);
|
|
printf(" g#%zu", n->mem_global_alloc.const_node);
|
|
break;
|
|
case SPL_IR_MEM_LOAD:
|
|
ir_dump_type(ty, n->mem_load.tid);
|
|
ir_dump_ref(n->mem_load.ptr);
|
|
break;
|
|
case SPL_IR_MEM_STORE:
|
|
ir_dump_type(ty, n->mem_store.tid);
|
|
ir_dump_ref(n->mem_store.ptr);
|
|
ir_dump_ref(n->mem_store.val);
|
|
break;
|
|
case SPL_IR_MEM_OFFSET:
|
|
ir_dump_type(ty, n->mem_offset.tid);
|
|
ir_dump_ref(n->mem_offset.ptr);
|
|
ir_dump_ref(n->mem_offset.offset);
|
|
break;
|
|
case SPL_IR_MEM_FIELD_PTR:
|
|
ir_dump_type(ty, n->mem_field_ptr.tid);
|
|
ir_dump_ref(n->mem_field_ptr.agg);
|
|
printf(" #%zu", n->mem_field_ptr.field_idx);
|
|
break;
|
|
case SPL_IR_MEM_COPY:
|
|
ir_dump_type(ty, n->mem_copy.tid);
|
|
ir_dump_ref(n->mem_copy.dst);
|
|
ir_dump_ref(n->mem_copy.src);
|
|
ir_dump_ref(n->mem_copy.size);
|
|
break;
|
|
case SPL_IR_MEM_SET:
|
|
ir_dump_type(ty, n->mem_set.tid);
|
|
ir_dump_ref(n->mem_set.dst);
|
|
ir_dump_ref(n->mem_set.val);
|
|
ir_dump_ref(n->mem_set.size);
|
|
break;
|
|
case SPL_IR_TYPE_CONST: {
|
|
ir_dump_type(ty, n->type_const.tid);
|
|
spl_type_node_t *t = spl_type_node((spl_type_t *)ty, n->type_const.tid);
|
|
if (t && t->kind == SPL_TYPE_FLOAT) {
|
|
printf(" float=%f", n->type_const.float_lit);
|
|
} else if (t && t->kind == SPL_TYPE_FN) {
|
|
printf(" fn#%zu", n->type_const.fn);
|
|
// } else if (t && t->kind == SPL_TYPE_PTR) {
|
|
// printf(" str=\"%s\"", n->type_const.cstr_lit ? n->type_const.cstr_lit : "?");
|
|
} else if (t && t->kind == SPL_TYPE_INT && t->int_type.bits == 8) {
|
|
printf(" char='%c'", n->type_const.ch_lit);
|
|
} else {
|
|
printf(" int=%zu", n->type_const.int_lit);
|
|
}
|
|
break;
|
|
}
|
|
case SPL_IR_TYPE_BITSIZEOF:
|
|
ir_dump_type(ty, n->bitsizeof.tid);
|
|
break;
|
|
case SPL_IR_TYPE_SIZEOF:
|
|
ir_dump_type(ty, n->ir_sizeof.tid);
|
|
break;
|
|
case SPL_IR_TYPE_ALIGNOF:
|
|
ir_dump_type(ty, n->ir_alignof.tid);
|
|
break;
|
|
case SPL_IR_TYPE_OFFSETOF:
|
|
ir_dump_type(ty, n->ir_offsetof.tid);
|
|
ir_dump_ref(n->ir_offsetof.field_idx);
|
|
break;
|
|
case SPL_IR_TYPE_FIELD_COUNT:
|
|
ir_dump_type(ty, n->field_count.tid);
|
|
break;
|
|
case SPL_IR_AGG_CONSTRUCT:
|
|
ir_dump_type(ty, n->agg_construct.tid);
|
|
vec_for(n->agg_construct.fields, i) ir_dump_ref(vec_at(n->agg_construct.fields, i));
|
|
break;
|
|
case SPL_IR_AGG_EXTRACT:
|
|
ir_dump_type(ty, n->agg_extract.tid);
|
|
printf(" #%zu", n->agg_extract.field_idx);
|
|
ir_dump_ref(n->agg_extract.val);
|
|
break;
|
|
case SPL_IR_AGG_INSERT:
|
|
ir_dump_type(ty, n->agg_insert.tid);
|
|
printf(" #%zu", n->agg_insert.field_idx);
|
|
ir_dump_ref(n->agg_insert.agg);
|
|
ir_dump_ref(n->agg_insert.field);
|
|
break;
|
|
case SPL_IR_CONTROL_SELECT:
|
|
ir_dump_type(ty, n->control_select.tid);
|
|
ir_dump_ref(n->control_select.cond);
|
|
ir_dump_ref(n->control_select.true_val);
|
|
ir_dump_ref(n->control_select.false_val);
|
|
break;
|
|
case SPL_IR_CONTROL_BR:
|
|
ir_dump_ref(n->control_br.cond);
|
|
ir_dump_ref(n->control_br.true_label);
|
|
ir_dump_ref(n->control_br.false_label);
|
|
break;
|
|
case SPL_IR_CONTROL_JMP:
|
|
ir_dump_ref(n->control_jmp.label);
|
|
break;
|
|
case SPL_IR_CONTROL_CALL:
|
|
ir_dump_type(ty, n->control_call.tid);
|
|
ir_dump_ref(n->control_call.func);
|
|
vec_for(n->control_call.params, i) ir_dump_ref(vec_at(n->control_call.params, i));
|
|
break;
|
|
case SPL_IR_CONTROL_PARAM:
|
|
ir_dump_type(ty, n->control_param.tid);
|
|
ir_dump_ref(n->control_param.idx);
|
|
break;
|
|
case SPL_IR_CONTROL_RET:
|
|
ir_dump_type(ty, n->control_ret.tid);
|
|
ir_dump_ref(n->control_ret.val);
|
|
break;
|
|
case SPL_IR_CONTROL_UNREACHABLE:
|
|
case SPL_IR_CONTROL_TRAP:
|
|
case SPL_IR_DBG_BREAKPOINT:
|
|
break;
|
|
case SPL_IR_DBG_PANIC:
|
|
printf(" \"%.*s\"", (int)n->dbg_panic.len, n->dbg_panic.msg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void ir_dump_attr_list(const spl_attr_t *attr, spl_attr_id_vec_t *ids) {
|
|
if (!attr || !ids || vec_size(*ids) == 0)
|
|
return;
|
|
printf(" attrs=[");
|
|
for (usize i = 0; i < vec_size(*ids); ++i) {
|
|
if (i > 0)
|
|
printf(", ");
|
|
spl_attr_dump_id(attr, vec_at(*ids, i));
|
|
}
|
|
printf("]");
|
|
}
|
|
|
|
void spl_ir_dump(spl_ir_t *ir, const spl_type_t *ty, const spl_attr_t *attr) {
|
|
vec_for(ir->funcs, i) {
|
|
if (i == 0)
|
|
continue;
|
|
spl_ir_func_t *func = &vec_at(ir->funcs, i);
|
|
printf("func %s %%%zu", func->name ? func->name : "?", i);
|
|
printf(" tid = ");
|
|
spl_type_pure_dump((spl_type_t *)ty, func->fn_tid);
|
|
ir_dump_attr_list(attr, &func->attrs);
|
|
printf("\n");
|
|
|
|
vec_for(func->nodes, j) {
|
|
if (j == 0)
|
|
continue;
|
|
spl_ir_node_t *node = &vec_at(func->nodes, j);
|
|
printf(" #%zu ", j);
|
|
printf("%s", spl_ir_kind_name(node->kind));
|
|
ir_dump_node(ty, node);
|
|
ir_dump_attr_list(attr, &node->attrs);
|
|
printf("\n");
|
|
}
|
|
}
|
|
// if (vec_size(ir->gdata) > 1) {
|
|
// printf("gdata:\n");
|
|
// vec_for(ir->gdata, i) {
|
|
// if (i == 0)
|
|
// continue;
|
|
// spl_ir_node_t *node = &vec_at(ir->gdata, i);
|
|
// printf(" #%zu ", i);
|
|
// printf("%s", spl_ir_kind_name(node->kind));
|
|
// ir_dump_node(ty, node);
|
|
// printf("\n");
|
|
// }
|
|
// }
|
|
}
|
|
|
|
// IR Builder
|
|
|
|
// 从当前 fn 申请新的 node 并注入到当前基本块
|
|
static spl_ir_node_ref_t builder_alloc_node(spl_ir_builder_t *b, spl_ir_kind_t kind) {
|
|
Assert(!b->terminated && "emit into a terminated block");
|
|
spl_ir_node_ref_t ref = spl_ir_alloc_node(&b->ir, b->current_fn);
|
|
Assert(ref != 0);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->kind = kind;
|
|
n->dbg = b->dbg;
|
|
vec_init(n->attrs);
|
|
|
|
if (b->current_block >= vec_size(b->blocks)) {
|
|
Panic("unknown bblock");
|
|
return 0;
|
|
}
|
|
|
|
spl_ir_node_ref_t *slot = &vec_at(b->blocks, b->current_block);
|
|
if (*slot == 0)
|
|
*slot = ref;
|
|
|
|
return ref;
|
|
}
|
|
|
|
void spl_ir_builder_init(spl_ir_builder_t *b) {
|
|
spl_ir_init(&b->ir);
|
|
b->current_fn = 0;
|
|
b->dbg = (spl_dbg_node_t){0};
|
|
vec_init(b->blocks);
|
|
b->current_block = 0;
|
|
vec_init(b->fixups);
|
|
b->terminated = false;
|
|
}
|
|
|
|
void spl_ir_builder_drop(spl_ir_builder_t *b) {
|
|
spl_ir_drop(&b->ir);
|
|
vec_free(b->blocks);
|
|
vec_free(b->fixups);
|
|
}
|
|
|
|
spl_ir_func_ref_t spl_ir_builder_fn_begin(spl_ir_builder_t *b, const char *name,
|
|
spl_type_id_t fn_tid) {
|
|
if (b->current_fn) {
|
|
spl_ir_builder_fn_end(b);
|
|
}
|
|
spl_ir_func_ref_t fid = spl_ir_alloc_fn(&b->ir);
|
|
spl_ir_func_t *f = spl_ir_func(&b->ir, fid);
|
|
f->name = name;
|
|
vec_init(f->attrs);
|
|
f->fn_tid = fn_tid;
|
|
|
|
b->current_fn = fid;
|
|
b->current_block = 0;
|
|
b->blocks.size = 0;
|
|
b->fixups.size = 0;
|
|
b->terminated = false;
|
|
return fid;
|
|
}
|
|
|
|
void spl_ir_builder_fn_end(spl_ir_builder_t *b) {
|
|
spl_ir_func_t *f = spl_ir_func(&b->ir, b->current_fn);
|
|
if (!f) {
|
|
Panic("ir func not found");
|
|
return;
|
|
}
|
|
|
|
vec_for(b->fixups, i) {
|
|
spl_ir_fix_t *fx = &vec_at(b->fixups, i);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, fx->node);
|
|
if (!n) {
|
|
SPL_ERROR(&n->dbg, "unknown node in func");
|
|
continue;
|
|
}
|
|
spl_ir_node_ref_t target = 0;
|
|
if (fx->block < vec_size(b->blocks)) {
|
|
target = vec_at(b->blocks, fx->block);
|
|
}
|
|
if (target == 0) {
|
|
Panic("reloc to empty/unknown bblock #%zu", fx->block);
|
|
}
|
|
switch (fx->slot) {
|
|
case SPL_IR_FIX_BR_TRUE:
|
|
n->control_br.true_label = target;
|
|
break;
|
|
case SPL_IR_FIX_BR_FALSE:
|
|
n->control_br.false_label = target;
|
|
break;
|
|
case SPL_IR_FIX_JMP:
|
|
n->control_jmp.label = target;
|
|
break;
|
|
}
|
|
}
|
|
|
|
b->current_block = 0;
|
|
b->blocks.size = 0;
|
|
b->fixups.size = 0;
|
|
b->terminated = false;
|
|
}
|
|
|
|
usize spl_ir_builder_block_begin(spl_ir_builder_t *b) {
|
|
vec_push(b->blocks, (spl_ir_block_t){0});
|
|
usize block = vec_size(b->blocks) - 1;
|
|
b->current_block = block;
|
|
b->terminated = false;
|
|
return block;
|
|
}
|
|
|
|
void spl_ir_builder_block_end(spl_ir_builder_t *b) {
|
|
if (!b->terminated) {
|
|
Panic("bblock must be end of terminated");
|
|
}
|
|
if (b->current_block != 0 && b->current_block < vec_size(b->blocks) &&
|
|
vec_at(b->blocks, b->current_block) == 0) {
|
|
Panic("bblock #%zu is empty (no entry node emitted)", b->current_block);
|
|
}
|
|
}
|
|
|
|
#define X(name, kind) \
|
|
spl_ir_node_ref_t spl_ir_builder_##name(spl_ir_builder_t *builder, spl_type_id_t x_tid, \
|
|
spl_ir_node_ref_t x_left, spl_ir_node_ref_t x_right) { \
|
|
spl_ir_node_ref_t ref = builder_alloc_node(builder, kind); \
|
|
spl_ir_node_t *n = spl_ir_node(&builder->ir, builder->current_fn, ref); \
|
|
n->arith.tid = x_tid; \
|
|
n->arith.left = x_left; \
|
|
n->arith.right = x_right; \
|
|
return ref; \
|
|
}
|
|
SPL_IR_BIN_ARITH_TABLE
|
|
#undef X
|
|
|
|
#define X(name, kind) \
|
|
spl_ir_node_ref_t spl_ir_builder_##name(spl_ir_builder_t *builder, spl_type_id_t x_tid, \
|
|
spl_ir_node_ref_t x_val) { \
|
|
spl_ir_node_ref_t ref = builder_alloc_node(builder, kind); \
|
|
spl_ir_node_t *n = spl_ir_node(&builder->ir, builder->current_fn, ref); \
|
|
n->arith.tid = x_tid; \
|
|
n->arith.left = x_val; \
|
|
n->arith.right = 0; \
|
|
return ref; \
|
|
}
|
|
SPL_IR_UN_ARITH_TABLE
|
|
#undef X
|
|
|
|
#define X(name, kind) \
|
|
spl_ir_node_ref_t spl_ir_builder_##name(spl_ir_builder_t *builder, spl_type_id_t x_tid, \
|
|
spl_ir_node_ref_t x_a, spl_ir_node_ref_t x_b) { \
|
|
spl_ir_node_ref_t ref = builder_alloc_node(builder, kind); \
|
|
spl_ir_node_t *n = spl_ir_node(&builder->ir, builder->current_fn, ref); \
|
|
n->cmp.tid = x_tid; \
|
|
n->cmp.a = x_a; \
|
|
n->cmp.b = x_b; \
|
|
return ref; \
|
|
}
|
|
SPL_IR_CMP_TABLE
|
|
#undef X
|
|
|
|
#define X(name, kind) \
|
|
spl_ir_node_ref_t spl_ir_builder_##name(spl_ir_builder_t *builder, spl_type_id_t x_from, \
|
|
spl_type_id_t x_to, spl_ir_node_ref_t x_val) { \
|
|
spl_ir_node_ref_t ref = builder_alloc_node(builder, kind); \
|
|
spl_ir_node_t *n = spl_ir_node(&builder->ir, builder->current_fn, ref); \
|
|
n->cast.from_tid = x_from; \
|
|
n->cast.to_tid = x_to; \
|
|
n->cast.val = x_val; \
|
|
return ref; \
|
|
}
|
|
SPL_IR_CAST_TABLE
|
|
#undef X
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_mem_alloca(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t count) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_MEM_ALLOCA);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->mem_alloc.tid = tid;
|
|
n->mem_alloc.count = count;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_mem_global_alloc(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t const_node) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_MEM_GLOBAL_ALLOC);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->mem_global_alloc.tid = tid;
|
|
n->mem_global_alloc.const_node = const_node;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_mem_load(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t ptr) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_MEM_LOAD);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->mem_load.tid = tid;
|
|
n->mem_load.ptr = ptr;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_mem_store(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t ptr, spl_ir_node_ref_t val) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_MEM_STORE);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->mem_store.tid = tid;
|
|
n->mem_store.ptr = ptr;
|
|
n->mem_store.val = val;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_mem_offset(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t ptr, spl_ir_node_ref_t offset) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_MEM_OFFSET);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->mem_offset.tid = tid;
|
|
n->mem_offset.ptr = ptr;
|
|
n->mem_offset.offset = offset;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_mem_field(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t agg, usize field_idx) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_MEM_FIELD_PTR);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->mem_field_ptr.tid = tid;
|
|
n->mem_field_ptr.agg = agg;
|
|
n->mem_field_ptr.field_idx = field_idx;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_mem_copy(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t dst, spl_ir_node_ref_t src,
|
|
spl_ir_node_ref_t size) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_MEM_COPY);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->mem_copy.tid = tid;
|
|
n->mem_copy.dst = dst;
|
|
n->mem_copy.src = src;
|
|
n->mem_copy.size = size;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_mem_set(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t dst, spl_ir_node_ref_t val,
|
|
spl_ir_node_ref_t size) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_MEM_SET);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->mem_set.tid = tid;
|
|
n->mem_set.dst = dst;
|
|
n->mem_set.val = val;
|
|
n->mem_set.size = size;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_const_bool(spl_ir_builder_t *b, spl_type_id_t tid, bool val) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_CONST);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->type_const.tid = tid;
|
|
n->type_const.bool_lit = val;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_const_ptr(spl_ir_builder_t *b, spl_type_id_t tid, void *val) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_CONST);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->type_const.tid = tid;
|
|
n->type_const.ptr_lit = val;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_const_int(spl_ir_builder_t *b, spl_type_id_t tid, usize val) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_CONST);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->type_const.tid = tid;
|
|
n->type_const.int_lit = val;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_const_float(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
double val) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_CONST);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->type_const.tid = tid;
|
|
n->type_const.float_lit = val;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_const_bytes(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
const void *data, usize len) {
|
|
(void)len;
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_CONST);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->type_const.tid = tid;
|
|
n->type_const.ptr_lit = (void *)data;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_const_char(spl_ir_builder_t *b, spl_type_id_t tid, char val) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_CONST);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->type_const.tid = tid;
|
|
n->type_const.ch_lit = val;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_const_fn(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_func_ref_t val) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_CONST);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->type_const.tid = tid;
|
|
n->type_const.fn = val;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_bitsizeof(spl_ir_builder_t *b, spl_type_id_t tid) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_BITSIZEOF);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->bitsizeof.tid = tid;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_sizeof(spl_ir_builder_t *b, spl_type_id_t tid) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_SIZEOF);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->ir_sizeof.tid = tid;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_alignof(spl_ir_builder_t *b, spl_type_id_t tid) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_ALIGNOF);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->ir_alignof.tid = tid;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_offsetof(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t field_idx) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_OFFSETOF);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->ir_offsetof.tid = tid;
|
|
n->ir_offsetof.field_idx = field_idx;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_type_field_count(spl_ir_builder_t *b, spl_type_id_t tid) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_FIELD_COUNT);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->field_count.tid = tid;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_agg_construct(spl_ir_builder_t *b, spl_type_id_t tid) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_AGG_CONSTRUCT);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->agg_construct.tid = tid;
|
|
vec_init(n->agg_construct.fields);
|
|
return ref;
|
|
}
|
|
|
|
void spl_ir_builder_agg_construct_field(spl_ir_builder_t *b, spl_ir_node_ref_t node,
|
|
spl_ir_node_ref_t field) {
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, node);
|
|
Assert(n != NULL);
|
|
vec_push(n->agg_construct.fields, field);
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_agg_extract(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_type_id_t field_tid, usize field_idx,
|
|
spl_ir_node_ref_t val) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_AGG_EXTRACT);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->agg_extract.tid = tid;
|
|
n->agg_extract.field_tid = field_tid;
|
|
n->agg_extract.field_idx = field_idx;
|
|
n->agg_extract.val = val;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_agg_insert(spl_ir_builder_t *b, spl_type_id_t tid, usize field_idx,
|
|
spl_ir_node_ref_t agg, spl_ir_node_ref_t field) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_AGG_INSERT);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->agg_insert.tid = tid;
|
|
n->agg_insert.field_idx = field_idx;
|
|
n->agg_insert.agg = agg;
|
|
n->agg_insert.field = field;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_control_select(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t cond, spl_ir_node_ref_t true_val,
|
|
spl_ir_node_ref_t false_val) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_CONTROL_SELECT);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->control_select.tid = tid;
|
|
n->control_select.cond = cond;
|
|
n->control_select.true_val = true_val;
|
|
n->control_select.false_val = false_val;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_control_br(spl_ir_builder_t *b, spl_ir_node_ref_t cond) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_CONTROL_BR);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->control_br.cond = cond;
|
|
n->control_br.true_label = 0;
|
|
n->control_br.false_label = 0;
|
|
b->terminated = true;
|
|
return ref;
|
|
}
|
|
|
|
void spl_ir_builder_control_br_fixup(spl_ir_builder_t *b, spl_ir_node_ref_t ref, usize true_block,
|
|
usize false_block) {
|
|
spl_ir_node_t *node = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
if (!(node && node->kind == SPL_IR_CONTROL_BR)) {
|
|
Panic("fixup must be valid jmp ir node");
|
|
}
|
|
spl_ir_fix_t f1 = {.node = ref, .slot = SPL_IR_FIX_BR_TRUE, .block = true_block};
|
|
vec_push(b->fixups, f1);
|
|
spl_ir_fix_t f2 = {.node = ref, .slot = SPL_IR_FIX_BR_FALSE, .block = false_block};
|
|
vec_push(b->fixups, f2);
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_control_jmp(spl_ir_builder_t *b) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_CONTROL_JMP);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->control_jmp.label = 0;
|
|
b->terminated = true;
|
|
return ref;
|
|
}
|
|
|
|
void spl_ir_builder_control_jmp_fixup(spl_ir_builder_t *b, spl_ir_node_ref_t ref,
|
|
usize target_block) {
|
|
spl_ir_node_t *node = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
if (!(node && node->kind == SPL_IR_CONTROL_JMP)) {
|
|
Panic("fixup must be valid jmp ir node");
|
|
}
|
|
spl_ir_fix_t fx = {.node = ref, .slot = SPL_IR_FIX_JMP, .block = target_block};
|
|
vec_push(b->fixups, fx);
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_control_call(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t func) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_CONTROL_CALL);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->control_call.tid = tid;
|
|
n->control_call.func = func;
|
|
vec_init(n->control_call.params);
|
|
return ref;
|
|
}
|
|
|
|
void spl_ir_builder_control_call_param(spl_ir_builder_t *b, spl_ir_node_ref_t call_node,
|
|
spl_ir_node_ref_t arg) {
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, call_node);
|
|
Assert(n != NULL);
|
|
vec_push(n->control_call.params, arg);
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_control_param(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t idx) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_CONTROL_PARAM);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->control_param.tid = tid;
|
|
n->control_param.idx = idx;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_control_ret(spl_ir_builder_t *b, spl_type_id_t tid,
|
|
spl_ir_node_ref_t val) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_CONTROL_RET);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->control_ret.tid = tid;
|
|
n->control_ret.val = val;
|
|
b->terminated = true;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_control_unreachable(spl_ir_builder_t *b) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_CONTROL_UNREACHABLE);
|
|
b->terminated = true;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_control_trap(spl_ir_builder_t *b) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_CONTROL_TRAP);
|
|
b->terminated = true;
|
|
return ref;
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_dbg_breakpoint(spl_ir_builder_t *b) {
|
|
return builder_alloc_node(b, SPL_IR_DBG_BREAKPOINT);
|
|
}
|
|
|
|
spl_ir_node_ref_t spl_ir_builder_dbg_panic(spl_ir_builder_t *b, const char *msg, usize len) {
|
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_DBG_PANIC);
|
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
|
n->dbg_panic.msg = msg;
|
|
n->dbg_panic.len = len;
|
|
return ref;
|
|
}
|