Files
spl/stage1/spl_ir.c

709 lines
26 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 "?";
}
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;
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) { node_drop_vecs(&vec_at(f->nodes, j)); }
vec_free(f->nodes);
vec_free(f->labels);
}
vec_free(ir->funcs);
vec_for(ir->gdata, i) { node_drop_vecs(&vec_at(ir->gdata, i)); }
vec_free(ir->gdata);
}
spl_ir_func_ref_t spl_ir_alloc_fn(spl_ir_t *ir) {
spl_ir_func_t f = {0};
vec_init(f.nodes);
vec_init(f.labels);
vec_push(f.nodes, (spl_ir_node_t){0}); /* 0 = error 哨兵 */
vec_push(ir->funcs, f);
return vec_size(ir->funcs) - 1;
}
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;
}
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);
}
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:
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);
ir_dump_ref(n->arith.right);
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_SLICE) {
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;
}
}
void spl_ir_dump(spl_ir_t *ir, const spl_type_t *ty) {
vec_for(ir->funcs, i) {
if (i == 0)
continue;
spl_ir_func_t *func = &vec_at(ir->funcs, i);
printf("func %s", func->name ? func->name : "?");
printf(" tid=");
spl_type_pure_dump((spl_type_t *)ty, func->fn_tid);
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);
printf("\n");
}
if (vec_size(func->nodes) == 0)
printf(" (extern)\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
static spl_ir_node_ref_t builder_alloc_node(spl_ir_builder_t *b, spl_ir_kind_t kind) {
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;
b->current_node = ref;
return ref;
}
static spl_ir_func_t *builder_cur_func(spl_ir_builder_t *b) {
return spl_ir_func(&b->ir, b->current_fn);
}
static void builder_reloc_add(spl_ir_builder_t *b, spl_ir_node_ref_t label) {
if (label == 0) {
LOG_WARN("reloc null lable");
return;
}
spl_ir_func_t *f = builder_cur_func(b);
if (f && label < vec_size(f->nodes)) {
// resolved
return;
}
vec_for(b->reloc_label, i) {
if (vec_at(b->reloc_label, i) == label) {
return;
}
}
vec_push(b->reloc_label, label);
}
static void builder_reloc_check(spl_ir_builder_t *b) {
spl_ir_func_t *f = builder_cur_func(b);
if (!f)
return;
vec_for(b->reloc_label, i) {
spl_ir_node_ref_t label = vec_at(b->reloc_label, i);
if (label >= vec_size(f->nodes)) {
LOG_ERROR("fn `%s`: forward label %%%zu unresolved", f->name ? f->name : "?", label);
}
}
b->reloc_label.size = 0;
}
void spl_ir_builder_init(spl_ir_builder_t *b) {
spl_ir_init(&b->ir);
b->current_fn = 0;
b->current_node = 0;
b->dbg = (spl_dbg_node_t){0};
vec_init(b->reloc_label);
}
void spl_ir_builder_drop(spl_ir_builder_t *b) {
spl_ir_drop(&b->ir);
vec_free(b->reloc_label);
}
spl_ir_func_ref_t spl_ir_builder_fn_new(spl_ir_builder_t *b, const char *name,
spl_type_id_t fn_tid) {
if (b->current_fn) {
builder_reloc_check(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;
f->fn_tid = fn_tid;
b->current_fn = fid;
b->current_node = 0;
return fid;
}
spl_ir_func_ref_t spl_ir_builder_cur_fn(const spl_ir_builder_t *b) { return b->current_fn; }
void spl_ir_builder_set_dbg(spl_ir_builder_t *b, spl_dbg_node_t dbg) { b->dbg = dbg; }
spl_ir_node_ref_t spl_ir_builder_block_new(spl_ir_builder_t *b) {
spl_ir_func_t *f = builder_cur_func(b);
Assert(f != NULL);
return vec_size(f->nodes);
}
#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_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_cstr(spl_ir_builder_t *b, spl_type_id_t tid,
const 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.cstr_lit = val;
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 true_label,
spl_ir_node_ref_t false_label) {
builder_reloc_add(b, true_label);
builder_reloc_add(b, false_label);
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 = true_label;
n->control_br.false_label = false_label;
return ref;
}
spl_ir_node_ref_t spl_ir_builder_control_jmp(spl_ir_builder_t *b, spl_ir_node_ref_t label) {
builder_reloc_add(b, label);
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 = label;
return ref;
}
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 node,
spl_ir_node_ref_t arg) {
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, 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;
return ref;
}
spl_ir_node_ref_t spl_ir_builder_control_unreachable(spl_ir_builder_t *b) {
return builder_alloc_node(b, SPL_IR_CONTROL_UNREACHABLE);
}
spl_ir_node_ref_t spl_ir_builder_control_trap(spl_ir_builder_t *b) {
return builder_alloc_node(b, SPL_IR_CONTROL_TRAP);
}
spl_ir_node_ref_t spl_ir_builder_dbg_breakpoint(spl_ir_builder_t *b) {
return builder_alloc_node(b, SPL_IR_DBG_BREAKPOINT);
}