709 lines
26 KiB
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);
|
|
} |