#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); }