#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(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; } } 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 %%%zu", func->name ? func->name : "?", i); 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 // 从当前 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; if (b->current_block < vec_size(b->blocks)) { vec_at(b->blocks, b->current_block) = ref; } else { Panic("unknown bblock"); return 0; } 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, spl_ir_attr_t attr) { 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; f->attr = attr; 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("unknown reloc target bblock"); } 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"); } } #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_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 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) { return builder_alloc_node(b, SPL_IR_CONTROL_UNREACHABLE); } 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); }