/* spl_ir.c — function-based SIR IR (arena 容器 + 文本 dump) */ #include "spl_ir.h" #include #include /* ---- 内置函数名字表(与 spl_ir_kind_t 枚举一一对应) ---- */ static const char *const ir_kind_names[] = { #define X(a, b, c) #a, SPL_IR_FN_TABLE #undef X }; void spl_ir_init(spl_ir_t *ir) { memset(ir, 0, sizeof *ir); vec_init(ir->funcs); vec_init(ir->gdata); /* func ref 0 保留为 error,占位 */ spl_ir_func_t f0; memset(&f0, 0, sizeof f0); vec_push(ir->funcs, f0); } 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) { for (usize i = 0; i < ir->funcs.size; i++) { spl_ir_func_t *f = &ir->funcs.data[i]; for (usize j = 0; j < f->nodes.size; j++) node_drop_vecs(&f->nodes.data[j]); vec_free(f->nodes); vec_free(f->labels); vec_free(f->dbg_vars); } vec_free(ir->funcs); for (usize i = 0; i < ir->gdata.size; i++) node_drop_vecs(&ir->gdata.data[i]); vec_free(ir->gdata); } spl_ir_func_ref_t spl_ir_alloc_fn(spl_ir_t *ir) { spl_ir_func_t f; memset(&f, 0, sizeof f); vec_init(f.nodes); vec_init(f.labels); vec_init(f.dbg_vars); vec_push(ir->funcs, f); return ir->funcs.size - 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 >= ir->funcs.size) return 0; spl_ir_func_t *f = &ir->funcs.data[fn_id]; spl_ir_node_t n; memset(&n, 0, sizeof n); if (f->nodes.size == 0) { vec_push(f->nodes, n); /* 占位:node ref 0 保留为 error */ } vec_push(f->nodes, n); return f->nodes.size - 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 >= ir->funcs.size) return NULL; spl_ir_func_t *f = &ir->funcs.data[fn_id]; if (!node_id || node_id >= f->nodes.size) return NULL; return &f->nodes.data[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 >= ir->funcs.size) return NULL; return &ir->funcs.data[fn_id]; } /* ================================================================ * dump * ================================================================ */ static void ir_type_dump(const spl_type_t *ty, spl_type_id_t tid) { spl_type_node_t *n = spl_type_node((spl_type_t *)ty, tid); if (!n) { printf("?"); return; } switch (n->kind) { case SPL_TYPE_VOID: printf("void"); break; case SPL_TYPE_BOOL: printf("bool"); break; case SPL_TYPE_INT: printf("%s%zu", n->int_type.is_signed ? "i" : "u", n->int_type.bits); break; case SPL_TYPE_FLOAT: printf("f%zu", n->float_type.bits); break; case SPL_TYPE_PTR: printf("*"); ir_type_dump(ty, n->ptr_pointee); break; case SPL_TYPE_SLICE: printf("[]"); ir_type_dump(ty, n->slice_element); break; case SPL_TYPE_RANGE: printf("range["); ir_type_dump(ty, n->range_element); printf("]"); break; case SPL_TYPE_ARRAY: printf("[%zu]", n->array_type.len); ir_type_dump(ty, n->array_type.element); break; case SPL_TYPE_STRUCT: printf("struct#%zu", tid); break; case SPL_TYPE_UNION: printf("union#%zu", tid); break; case SPL_TYPE_ENUM: printf("enum#%zu", tid); break; case SPL_TYPE_FN: printf("fn<"); for (usize i = 0; i < n->fn_type.params.size; i++) { if (i) printf(","); ir_type_dump(ty, n->fn_type.params.data[i]); } printf("->"); ir_type_dump(ty, n->fn_type.ret); printf(">"); break; case SPL_TYPE_ID: ir_type_dump(ty, n->type_id); break; default: printf("?%zu", tid); break; } } static const char *node_name(spl_ir_kind_t k) { if ((usize)k < sizeof(ir_kind_names) / sizeof(ir_kind_names[0])) return ir_kind_names[k]; return "?"; } static int node_produces_value(spl_ir_kind_t k) { switch (k) { case SPL_IR_MEM_STORE: case SPL_IR_MEM_COPY: case SPL_IR_MEM_SET: case SPL_IR_MEM_FENCE: case SPL_IR_CONTROL_BR: case SPL_IR_CONTROL_JMP: case SPL_IR_CONTROL_RET: case SPL_IR_CONTROL_UNREACHABLE: case SPL_IR_CONTROL_TRAP: case SPL_IR_DBG_BREAKPOINT: case SPL_IR_DBG_DECLARE: return 0; default: return 1; } } static void dump_ref(spl_ir_node_ref_t r) { printf("%%%zu", r); } static void dump_node(const spl_type_t *ty, const spl_ir_node_t *n) { switch (n->kind) { case SPL_IR_TYPE_CONST: printf("@type.const("); ir_type_dump(ty, n->type_const.tid); printf(")("); { spl_type_node_t *t = spl_type_node((spl_type_t *)ty, n->type_const.tid); if (t && t->kind == SPL_TYPE_INT) printf("%lld", (long long)n->type_const.int_lit); else if (t && t->kind == SPL_TYPE_FLOAT) printf("%g", 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 || t->kind == SPL_TYPE_SLICE)) { if (n->type_const.cstr_lit) printf("\"%s\"", n->type_const.cstr_lit); else printf("0"); } else if (t && t->kind == SPL_TYPE_BOOL) printf("%lld", (long long)n->type_const.int_lit); else printf("?"); } printf(")"); break; 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: printf("@%s(", node_name(n->kind)); ir_type_dump(ty, n->arith.tid); printf(")("); dump_ref(n->arith.left); if (n->arith.right) { printf(", "); dump_ref(n->arith.right); } printf(")"); break; case SPL_IR_ARITH_NEG: case SPL_IR_ARITH_ABS: case SPL_IR_ARITH_NOT: printf("@%s(", node_name(n->kind)); ir_type_dump(ty, n->arith.tid); printf(")("); dump_ref(n->arith.left); printf(")"); 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: printf("@%s(", node_name(n->kind)); ir_type_dump(ty, n->cmp.tid); printf(")("); dump_ref(n->cmp.a); printf(", "); dump_ref(n->cmp.b); printf(")"); 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("@%s(", node_name(n->kind)); ir_type_dump(ty, n->cast.from_tid); printf(", "); ir_type_dump(ty, n->cast.to_tid); printf(")("); dump_ref(n->cast.val); printf(")"); break; case SPL_IR_MEM_ALLOCA: printf("@mem.alloca("); ir_type_dump(ty, n->mem_alloc.tid); printf(")("); dump_ref(n->mem_alloc.count); printf(")"); break; case SPL_IR_MEM_LOAD: printf("@mem.load("); ir_type_dump(ty, n->mem_load.tid); printf(")("); dump_ref(n->mem_load.ptr); printf(")"); break; case SPL_IR_MEM_STORE: printf("@mem.store("); ir_type_dump(ty, n->mem_store.tid); printf(")("); dump_ref(n->mem_store.ptr); printf(", "); dump_ref(n->mem_store.val); printf(")"); break; case SPL_IR_MEM_OFFSET: printf("@mem.offset("); ir_type_dump(ty, n->mem_offset.tid); printf(")("); dump_ref(n->mem_offset.ptr); printf(", "); dump_ref(n->mem_offset.offset); printf(")"); break; case SPL_IR_MEM_FIELD_PTR: printf("@mem.field_ptr("); ir_type_dump(ty, n->mem_field_ptr.tid); printf(", %zu)(", (size_t)n->mem_field_ptr.field_idx); dump_ref(n->mem_field_ptr.agg); printf(")"); break; case SPL_IR_MEM_GLOBAL_ALLOC: printf("@mem.global_alloc(gdata[%zu])()", (size_t)n->mem_global_alloc.const_node); break; case SPL_IR_MEM_COPY: printf("@mem.copy()("); dump_ref(n->mem_copy.dst); printf(", "); dump_ref(n->mem_copy.src); printf(", "); dump_ref(n->mem_copy.size); printf(")"); break; case SPL_IR_MEM_SET: printf("@mem.set()("); dump_ref(n->mem_set.dst); printf(", "); dump_ref(n->mem_set.val); printf(", "); dump_ref(n->mem_set.size); printf(")"); break; case SPL_IR_MEM_FENCE: printf("@mem.fence()("); dump_ref(n->mem_fence.ordering); printf(")"); break; case SPL_IR_TYPE_BITSIZEOF: printf("@type.bitsizeof("); ir_type_dump(ty, n->bitsizeof.tid); printf(")()"); break; case SPL_IR_TYPE_SIZEOF: printf("@type.sizeof("); ir_type_dump(ty, n->ir_sizeof.tid); printf(")()"); break; case SPL_IR_TYPE_ALIGNOF: printf("@type.alignof("); ir_type_dump(ty, n->ir_alignof.tid); printf(")()"); break; case SPL_IR_TYPE_OFFSETOF: printf("@type.offsetof("); ir_type_dump(ty, n->ir_offsetof.tid); printf(")("); dump_ref(n->ir_offsetof.field_idx); printf(")"); break; case SPL_IR_TYPE_FIELD_COUNT: printf("@type.field_count("); ir_type_dump(ty, n->field_count.tid); printf(")()"); break; case SPL_IR_AGG_CONSTRUCT: printf("@agg.construct("); ir_type_dump(ty, n->agg_construct.tid); printf(")("); for (usize i = 0; i < n->agg_construct.fields.size; i++) { if (i) printf(", "); dump_ref(n->agg_construct.fields.data[i]); } printf(")"); break; case SPL_IR_AGG_EXTRACT: printf("@agg.extract("); ir_type_dump(ty, n->agg_extract.tid); printf(", %lld)(", (long long)n->agg_extract.field_idx); dump_ref(n->agg_extract.val); printf(")"); break; case SPL_IR_AGG_INSERT: printf("@agg.insert("); ir_type_dump(ty, n->agg_insert.tid); printf(", %lld)(", (long long)n->agg_insert.field_idx); dump_ref(n->agg_insert.agg); printf(", "); dump_ref(n->agg_insert.field); printf(")"); break; case SPL_IR_CONTROL_SELECT: printf("@control.select("); ir_type_dump(ty, n->control_select.tid); printf(")("); dump_ref(n->control_select.cond); printf(", "); dump_ref(n->control_select.true_val); printf(", "); dump_ref(n->control_select.false_val); printf(")"); break; case SPL_IR_CONTROL_BR: printf("@control.br()("); dump_ref(n->control_br.cond); printf(", "); dump_ref(n->control_br.true_label); printf(", "); dump_ref(n->control_br.false_label); printf(")"); break; case SPL_IR_CONTROL_JMP: printf("@control.jmp()("); dump_ref(n->control_jmp.label); printf(")"); break; case SPL_IR_CONTROL_CALL: printf("@control.call("); ir_type_dump(ty, n->control_call.tid); printf(")("); dump_ref(n->control_call.func); for (usize i = 0; i < n->control_call.params.size; i++) { printf(", "); dump_ref(n->control_call.params.data[i]); } printf(")"); break; case SPL_IR_CONTROL_PARAM: printf("@control.param("); ir_type_dump(ty, n->control_param.tid); printf(")(%lld)", (long long)n->control_param.idx); break; case SPL_IR_CONTROL_RET: printf("@control.ret("); ir_type_dump(ty, n->control_ret.tid); printf(")("); if (n->control_ret.val) dump_ref(n->control_ret.val); printf(")"); break; case SPL_IR_CONTROL_UNREACHABLE: printf("@control.unreachable()()"); break; case SPL_IR_CONTROL_TRAP: printf("@control.trap()()"); break; case SPL_IR_DBG_BREAKPOINT: printf("@dbg.breakpoint()()"); break; case SPL_IR_DBG_DECLARE: printf("@dbg.declare()()"); break; default: printf("@%s()()", node_name(n->kind)); break; } } static void dump_func(const spl_type_t *ty, const spl_ir_func_t *f) { printf("func @%s", f->name ? f->name : "?"); if (f->fn_tid) { spl_type_node_t *t = spl_type_node((spl_type_t *)ty, f->fn_tid); if (t && t->kind == SPL_TYPE_FN) { printf("("); for (usize i = 0; i < t->fn_type.params.size; i++) { if (i) printf(", "); ir_type_dump(ty, t->fn_type.params.data[i]); } printf(") -> "); ir_type_dump(ty, t->fn_type.ret); } } printf(" {\n"); usize li = 0; for (usize i = 1; i < f->nodes.size; i++) { if (li < f->labels.size && f->labels.data[li] == i) { printf("#bb%zu:\n", li); li++; } printf(" "); if (node_produces_value(f->nodes.data[i].kind)) printf("%%%zu = ", i); dump_node(ty, &f->nodes.data[i]); printf("\n"); } if (li < f->labels.size && f->labels.data[li] == f->nodes.size) printf("#bb%zu:\n", li); printf("}\n"); } void spl_ir_dump(spl_ir_t *ir, const spl_type_t *ty) { printf("; SPL IR module (%zu funcs)\n", ir->funcs.size - 1); for (usize i = 1; i < ir->funcs.size; i++) dump_func(ty, &ir->funcs.data[i]); if (ir->gdata.size) { printf("; global data (%zu)\n", ir->gdata.size); for (usize i = 0; i < ir->gdata.size; i++) { printf("; gdata[%zu] = ", i); dump_node(ty, &ir->gdata.data[i]); printf("\n"); } } } 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 "?"; }