Files
spl/stage1/spl_ir.c

507 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* spl_ir.c — function-based SIR IR (arena 容器 + 文本 dump) */
#include "spl_ir.h"
#include <stdio.h>
#include <string.h>
/* ---- 内置函数名字表(与 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(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_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");
}
}
}