- 统一包名格式化,添加空格对齐 - 将依赖项从ir和lir重命名为hir,移除lir注释 - 为ast2ir模块添加正确的包名称"scc_ast2ir" - 更新依赖引用路径指向新的HIR库结构 - 移除注释掉的ir2mcode和sccf2target依赖项 refactor(ast2ir): 迁移到HIR中间表示替换IR表示 - 更新头文件包含,使用hir_builder.h替代ir_builder.h - 修改上下文结构体,将scc_ir_builder_t替换为scc_hir_builder_t - 更新函数签名,将参数类型从scc_ir_*转换为scc_hir_* - 调整返回值类型,将scc_ir_value_ref_t和scc_ir_type_ref_t 分别替换为scc_hir_value_ref_t和scc_hir_type_ref_t - 重新排列头文件包含顺序以满足依赖关系
708 lines
28 KiB
C
708 lines
28 KiB
C
#include <hir_dump.h>
|
||
#include <hir_prog.h>
|
||
#include <scc_tree_dump.h>
|
||
|
||
#define GET_MODULE(ctx) (&(ctx->cprog->module))
|
||
|
||
static const char *get_node_type_str(scc_hir_value_tag_t tag) {
|
||
static const char *node_types[] = {
|
||
[SCC_HIR_VALUE_TAG_NULLPTR] = "NullPtr",
|
||
[SCC_HIR_VALUE_TAG_BUILTIN] = "Builtin",
|
||
[SCC_HIR_VALUE_TAG_INTEGER] = "ConstInt",
|
||
[SCC_HIR_VALUE_TAG_DECIMAL] = "ConstFloat",
|
||
[SCC_HIR_VALUE_TAG_ARRAY] = "ConstArray",
|
||
[SCC_HIR_VALUE_TAG_AGGREGATE] = "Aggregate",
|
||
[SCC_HIR_VALUE_TAG_CONV] = "Convert",
|
||
[SCC_HIR_VALUE_TAG_FUNC_ARG_REF] = "FuncArgRef",
|
||
[SCC_HIR_VALUE_TAG_BLOCK_ARG_REF] = "BlockArgRef",
|
||
[SCC_HIR_VALUE_TAG_ALLOC] = "Alloc",
|
||
[SCC_HIR_VALUE_TAG_GLOBAL_ALLOC] = "GlobalAlloc",
|
||
[SCC_HIR_VALUE_TAG_LOAD] = "Load",
|
||
[SCC_HIR_VALUE_TAG_STORE] = "Store",
|
||
[SCC_HIR_VALUE_TAG_GET_ELEM_PTR] = "GetElemPtr",
|
||
[SCC_HIR_VALUE_TAG_OP] = "Op",
|
||
[SCC_HIR_VALUE_TAG_BRANCH] = "Branch",
|
||
[SCC_HIR_VALUE_TAG_JUMP] = "Jump",
|
||
[SCC_HIR_VALUE_TAG_CALL] = "Call",
|
||
[SCC_HIR_VALUE_TAG_RET] = "Ret",
|
||
};
|
||
if (tag >= 0 && (usize)tag < sizeof(node_types) / sizeof(node_types[0]) &&
|
||
node_types[tag])
|
||
return node_types[tag];
|
||
return "UnknownIRNode";
|
||
}
|
||
|
||
static const char *get_op_str(scc_hir_op_type_t op) {
|
||
static const char *ops[] = {
|
||
[SCC_HIR_OP_EMPTY] = "empty", [SCC_HIR_OP_NEQ] = "!=",
|
||
[SCC_HIR_OP_EQ] = "==", [SCC_HIR_OP_GT] = ">",
|
||
[SCC_HIR_OP_LT] = "<", [SCC_HIR_OP_GE] = ">=",
|
||
[SCC_HIR_OP_LE] = "<=", [SCC_HIR_OP_ADD] = "+",
|
||
[SCC_HIR_OP_SUB] = "-", [SCC_HIR_OP_MUL] = "*",
|
||
[SCC_HIR_OP_DIV] = "/", [SCC_HIR_OP_MOD] = "%",
|
||
[SCC_HIR_OP_AND] = "&", [SCC_HIR_OP_OR] = "|",
|
||
[SCC_HIR_OP_XOR] = "^", [SCC_HIR_OP_NOT] = "~",
|
||
[SCC_HIR_OP_SHL] = "<<", [SCC_HIR_OP_SHR] = ">>",
|
||
[SCC_HIR_OP_SAR] = ">>a",
|
||
};
|
||
if (op >= 0 && (usize)op < sizeof(ops) / sizeof(ops[0]) && ops[op])
|
||
return ops[op];
|
||
return "<unknown_op>";
|
||
}
|
||
|
||
static const char *get_type_tag_str(scc_hir_type_tag_t tag) {
|
||
static const char *type_tags[] = {
|
||
[SCC_HIR_TYPE_void] = "void", [SCC_HIR_TYPE_u8] = "u8",
|
||
[SCC_HIR_TYPE_u16] = "u16", [SCC_HIR_TYPE_u32] = "u32",
|
||
[SCC_HIR_TYPE_u64] = "u64", [SCC_HIR_TYPE_u128] = "u128",
|
||
[SCC_HIR_TYPE_i8] = "i8", [SCC_HIR_TYPE_i16] = "i16",
|
||
[SCC_HIR_TYPE_i32] = "i32", [SCC_HIR_TYPE_i64] = "i64",
|
||
[SCC_HIR_TYPE_i128] = "i128", [SCC_HIR_TYPE_f16] = "f16",
|
||
[SCC_HIR_TYPE_f32] = "f32", [SCC_HIR_TYPE_f64] = "f64",
|
||
[SCC_HIR_TYPE_f128] = "f128", [SCC_HIR_TYPE_PTR] = "ptr",
|
||
[SCC_HIR_TYPE_ARRAY] = "array", [SCC_HIR_TYPE_FUNC] = "func",
|
||
[SCC_HIR_TYPE_STRUCT] = "struct", [SCC_HIR_TYPE_VECTOR] = "vector",
|
||
};
|
||
if (tag >= 0 && (usize)tag < sizeof(type_tags) / sizeof(type_tags[0]) &&
|
||
type_tags[tag])
|
||
return type_tags[tag];
|
||
return "<unknown_type>";
|
||
}
|
||
|
||
static inline void dump_child_node_ref(scc_hir_dump_t *ctx,
|
||
scc_hir_value_ref_t child,
|
||
cbool is_last) {
|
||
if (!child)
|
||
return;
|
||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
||
scc_hir_dump_value(ctx, child);
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
|
||
static void dump_integer_node(scc_hir_dump_t *ctx,
|
||
const scc_hir_value_t *value) {
|
||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
// FIXME hack it
|
||
scc_tree_dump_value(ctx->dump_ctx, "%d", value->data.integer.data.digit);
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
|
||
static void dump_op_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
||
scc_tree_dump_push(ctx->dump_ctx, false);
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_tree_dump_node(ctx->dump_ctx, "op: ");
|
||
scc_tree_dump_value(ctx->dump_ctx, "%s", get_op_str(value->data.op.op));
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
|
||
if (value->data.op.lhs)
|
||
dump_child_node_ref(ctx, value->data.op.lhs,
|
||
value->data.op.rhs ? false : true);
|
||
if (value->data.op.rhs)
|
||
dump_child_node_ref(ctx, value->data.op.rhs, true);
|
||
}
|
||
|
||
static void dump_load_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
||
if (value->data.load.target)
|
||
dump_child_node_ref(ctx, value->data.load.target, true);
|
||
}
|
||
|
||
static void dump_store_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
||
if (value->data.store.target)
|
||
dump_child_node_ref(ctx, value->data.store.target, false);
|
||
if (value->data.store.value)
|
||
dump_child_node_ref(ctx, value->data.store.value, true);
|
||
}
|
||
|
||
static void dump_get_elem_ptr_node(scc_hir_dump_t *ctx,
|
||
const scc_hir_value_t *value) {
|
||
if (value->data.get_elem_ptr.src_addr)
|
||
dump_child_node_ref(ctx, value->data.get_elem_ptr.src_addr, false);
|
||
if (value->data.get_elem_ptr.index)
|
||
dump_child_node_ref(ctx, value->data.get_elem_ptr.index, true);
|
||
}
|
||
|
||
static void dump_branch_node(scc_hir_dump_t *ctx,
|
||
const scc_hir_value_t *value) {
|
||
if (value->data.branch.cond)
|
||
dump_child_node_ref(ctx, value->data.branch.cond, false);
|
||
|
||
if (value->data.branch.true_bblock) {
|
||
scc_hir_bblock_t *true_bblock = scc_hir_module_get_bblock(
|
||
GET_MODULE(ctx), value->data.branch.true_bblock);
|
||
if (true_bblock) {
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_tree_dump_node(ctx->dump_ctx, "TrueBlock: ");
|
||
scc_tree_dump_value(ctx->dump_ctx, "'%s'",
|
||
true_bblock->name ? true_bblock->name
|
||
: "<unnamed>");
|
||
}
|
||
}
|
||
if (value->data.branch.false_bblock) {
|
||
scc_hir_bblock_t *false_bblock = scc_hir_module_get_bblock(
|
||
GET_MODULE(ctx), value->data.branch.false_bblock);
|
||
if (false_bblock) {
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_tree_dump_node(ctx->dump_ctx, "FalseBlock: ");
|
||
scc_tree_dump_value(ctx->dump_ctx, "'%s'",
|
||
false_bblock->name ? false_bblock->name
|
||
: "<unnamed>");
|
||
}
|
||
}
|
||
}
|
||
|
||
static void dump_jump_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
if (value->data.jump.target_bblock) {
|
||
scc_hir_bblock_t *target = scc_hir_module_get_bblock(
|
||
GET_MODULE(ctx), value->data.jump.target_bblock);
|
||
if (target)
|
||
scc_tree_dump_value(ctx->dump_ctx, "to '%s'",
|
||
target->name ? target->name : "<unnamed>");
|
||
else
|
||
scc_tree_dump_value(ctx->dump_ctx, "to invalid block");
|
||
} else {
|
||
scc_tree_dump_value(ctx->dump_ctx, "to nullptr");
|
||
}
|
||
}
|
||
|
||
static void dump_call_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
if (value->data.call.callee) {
|
||
scc_hir_func_t *callee =
|
||
scc_hir_module_get_func(GET_MODULE(ctx), value->data.call.callee);
|
||
scc_tree_dump_value(ctx->dump_ctx, "func='%s'",
|
||
callee ? (callee->name ? callee->name : "<unnamed>")
|
||
: "<invalid>");
|
||
} else {
|
||
scc_tree_dump_value(ctx->dump_ctx, "func=nullptr");
|
||
}
|
||
|
||
for (usize i = 0; i < scc_vec_size(value->data.call.args); i++) {
|
||
cbool is_last = (i + 1 == scc_vec_size(value->data.call.args));
|
||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
||
scc_hir_value_ref_t arg = scc_vec_at(value->data.call.args, i);
|
||
dump_child_node_ref(ctx, arg, is_last);
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
}
|
||
|
||
static void dump_ret_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
||
if (value->data.ret.ret_val)
|
||
dump_child_node_ref(ctx, value->data.ret.ret_val, true);
|
||
}
|
||
|
||
void scc_hir_dump_ctx_init(scc_hir_dump_t *ctx, scc_tree_dump_t *td,
|
||
scc_hir_cprog_t *cprog) {
|
||
ctx->cprog = cprog;
|
||
ctx->dump_ctx = td;
|
||
}
|
||
|
||
void scc_hir_dump_value(scc_hir_dump_t *ctx, scc_hir_value_ref_t value_ref) {
|
||
scc_hir_value_t *value =
|
||
scc_hir_module_get_value(GET_MODULE(ctx), value_ref);
|
||
if (!value) {
|
||
LOG_ERROR("Invalid value ref");
|
||
return;
|
||
}
|
||
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_tree_dump_node(ctx->dump_ctx, "%s", get_node_type_str(value->tag));
|
||
if (value->name && value->name[0])
|
||
scc_tree_dump_value(ctx->dump_ctx, " [%s]", value->name);
|
||
if (value->type) {
|
||
scc_hir_type_t *type =
|
||
scc_hir_module_get_type(GET_MODULE(ctx), value->type);
|
||
if (type) {
|
||
scc_tree_dump_append(ctx->dump_ctx, " : ");
|
||
scc_tree_dump_value(ctx->dump_ctx, "%s",
|
||
get_type_tag_str(type->tag));
|
||
}
|
||
}
|
||
|
||
switch (value->tag) {
|
||
case SCC_HIR_VALUE_TAG_INTEGER:
|
||
dump_integer_node(ctx, value);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_ALLOC:
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_LOAD:
|
||
dump_load_node(ctx, value);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_STORE:
|
||
dump_store_node(ctx, value);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_GET_ELEM_PTR:
|
||
dump_get_elem_ptr_node(ctx, value);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_OP:
|
||
dump_op_node(ctx, value);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_BRANCH:
|
||
dump_branch_node(ctx, value);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_JUMP:
|
||
dump_jump_node(ctx, value);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_CALL:
|
||
dump_call_node(ctx, value);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_RET:
|
||
dump_ret_node(ctx, value);
|
||
break;
|
||
default:
|
||
scc_tree_dump_value(ctx->dump_ctx, "unknown");
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, " tag(%d)", value->tag);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void scc_hir_dump_type(scc_hir_dump_t *ctx, scc_hir_type_ref_t type_ref) {
|
||
if (!ctx || !type_ref) {
|
||
LOG_ERROR("invalid parameter");
|
||
return;
|
||
}
|
||
scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref);
|
||
if (!type) {
|
||
LOG_ERROR("invalid type ref");
|
||
return;
|
||
}
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_tree_dump_node(ctx->dump_ctx, "Type: ");
|
||
scc_tree_dump_value(ctx->dump_ctx, "%s", get_type_tag_str(type->tag));
|
||
|
||
switch (type->tag) {
|
||
case SCC_HIR_TYPE_PTR:
|
||
if (type->data.pointer.base) {
|
||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||
scc_hir_dump_type(ctx, type->data.pointer.base);
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
break;
|
||
case SCC_HIR_TYPE_ARRAY:
|
||
if (type->data.array.len > 0) {
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_tree_dump_node(ctx->dump_ctx, "Array Length: ");
|
||
scc_tree_dump_value(ctx->dump_ctx, "%zu", type->data.array.len);
|
||
scc_tree_dump_append(ctx->dump_ctx, "\n");
|
||
}
|
||
if (type->data.array.base) {
|
||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||
scc_hir_dump_type(ctx, type->data.array.base);
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
break;
|
||
case SCC_HIR_TYPE_FUNC:
|
||
for (usize i = 0; i < scc_vec_size(type->data.function.params); i++) {
|
||
cbool is_last = (i + 1 == scc_vec_size(type->data.function.params));
|
||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
||
scc_hir_dump_type(ctx, scc_vec_at(type->data.function.params, i));
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
if (type->data.function.ret_type) {
|
||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||
scc_hir_dump_type(ctx, type->data.function.ret_type);
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
void scc_hir_dump_bblock(scc_hir_dump_t *ctx, scc_hir_bblock_ref_t bblock_ref) {
|
||
if (!ctx || !bblock_ref) {
|
||
LOG_ERROR("invalid parameter");
|
||
return;
|
||
}
|
||
scc_hir_bblock_t *bblock =
|
||
scc_hir_module_get_bblock(GET_MODULE(ctx), bblock_ref);
|
||
if (!bblock) {
|
||
LOG_ERROR("invalid bblock ref");
|
||
return;
|
||
}
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_tree_dump_node(ctx->dump_ctx, "BasicBlock: ");
|
||
scc_tree_dump_value(ctx->dump_ctx, "'%s'",
|
||
bblock->name ? bblock->name : "<unnamed>");
|
||
scc_tree_dump_append(ctx->dump_ctx, "\n");
|
||
|
||
for (usize i = 0; i < scc_vec_size(SCC_HIR_BBLOCK_VALUES(*bblock)); i++) {
|
||
cbool is_last = (i + 1 == scc_vec_size(SCC_HIR_BBLOCK_VALUES(*bblock)));
|
||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
||
scc_hir_dump_value(ctx, scc_vec_at(SCC_HIR_BBLOCK_VALUES(*bblock), i));
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
}
|
||
|
||
void scc_hir_dump_func(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref) {
|
||
scc_hir_func_t *func = scc_hir_module_get_func(GET_MODULE(ctx), func_ref);
|
||
if (!ctx || !func) {
|
||
LOG_ERROR("invalid parameter");
|
||
return;
|
||
}
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_tree_dump_node(ctx->dump_ctx, "Function: ");
|
||
scc_tree_dump_value(ctx->dump_ctx, "'%s'",
|
||
func->name ? func->name : "<unnamed>");
|
||
scc_tree_dump_append(ctx->dump_ctx, "\n");
|
||
|
||
if (SCC_HIR_FUNC_META(*func)->type) {
|
||
scc_tree_dump_push(ctx->dump_ctx, false);
|
||
scc_hir_dump_type(ctx, SCC_HIR_FUNC_META(*func)->type);
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
for (usize i = 0; i < scc_vec_size(SCC_HIR_FUNC_META(*func)->params); i++) {
|
||
cbool is_last =
|
||
(i + 1 == scc_vec_size(SCC_HIR_FUNC_META(*func)->params));
|
||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
||
scc_hir_dump_value(ctx,
|
||
scc_vec_at(SCC_HIR_FUNC_META(*func)->params, i));
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
for (usize i = 0; i < scc_vec_size(func->bblocks); i++) {
|
||
cbool is_last = (i + 1 == scc_vec_size(func->bblocks));
|
||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
||
scc_hir_dump_bblock(ctx, scc_vec_at(func->bblocks, i));
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
}
|
||
|
||
void scc_hir_dump_cprog(scc_hir_dump_t *ctx) {
|
||
scc_tree_dump_node(ctx->dump_ctx, "Func defs:\n");
|
||
scc_vec_foreach(ctx->cprog->func_defs, i) {
|
||
cbool is_last = (i + 1 == scc_vec_size(ctx->cprog->func_defs));
|
||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
||
scc_hir_dump_func(ctx, scc_vec_at(ctx->cprog->func_defs, i));
|
||
scc_tree_dump_pop(ctx->dump_ctx);
|
||
}
|
||
}
|
||
|
||
// ----- 线性输出(保留原逻辑,改用新 API)-----
|
||
void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
|
||
scc_hir_type_ref_t type_ref) {
|
||
scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref);
|
||
if (!ctx || !type) {
|
||
LOG_ERROR("invalid parameter");
|
||
return;
|
||
}
|
||
switch (type->tag) {
|
||
case SCC_HIR_TYPE_unknown:
|
||
case SCC_HIR_TYPE_void:
|
||
case SCC_HIR_TYPE_i8:
|
||
case SCC_HIR_TYPE_i16:
|
||
case SCC_HIR_TYPE_i32:
|
||
case SCC_HIR_TYPE_i64:
|
||
case SCC_HIR_TYPE_i128:
|
||
case SCC_HIR_TYPE_u8:
|
||
case SCC_HIR_TYPE_u16:
|
||
case SCC_HIR_TYPE_u32:
|
||
case SCC_HIR_TYPE_u64:
|
||
case SCC_HIR_TYPE_u128:
|
||
case SCC_HIR_TYPE_f16:
|
||
case SCC_HIR_TYPE_f32:
|
||
case SCC_HIR_TYPE_f64:
|
||
case SCC_HIR_TYPE_f128:
|
||
scc_tree_dump_value(ctx->dump_ctx, "%s", get_type_tag_str(type->tag));
|
||
break;
|
||
case SCC_HIR_TYPE_ARRAY:
|
||
scc_tree_dump_append(ctx->dump_ctx, "[");
|
||
scc_hir_dump_type_linear(ctx, type->data.array.base);
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, ", %zu]", type->data.array.len);
|
||
break;
|
||
case SCC_HIR_TYPE_PTR:
|
||
scc_tree_dump_append(ctx->dump_ctx, "*");
|
||
scc_hir_dump_type_linear(ctx, type->data.pointer.base);
|
||
break;
|
||
case SCC_HIR_TYPE_FUNC:
|
||
scc_tree_dump_append(ctx->dump_ctx, "(");
|
||
for (usize i = 0; i < scc_vec_size(type->data.function.params); i++) {
|
||
if (i > 0)
|
||
scc_tree_dump_append(ctx->dump_ctx, ", ");
|
||
scc_hir_dump_type_linear(ctx,
|
||
scc_vec_at(type->data.function.params, i));
|
||
}
|
||
if (type->data.function.ret_type) {
|
||
scc_tree_dump_append(ctx->dump_ctx, ") -> ");
|
||
scc_hir_dump_type_linear(ctx, type->data.function.ret_type);
|
||
} else {
|
||
scc_tree_dump_append(ctx->dump_ctx, ")");
|
||
}
|
||
break;
|
||
default:
|
||
LOG_ERROR("invalid type tag");
|
||
break;
|
||
}
|
||
}
|
||
|
||
static void format_ref_or_value(scc_hir_dump_t *ctx,
|
||
scc_hir_value_ref_t value_ref) {
|
||
scc_hir_value_t *value =
|
||
scc_hir_module_get_value(GET_MODULE(ctx), value_ref);
|
||
if (!value) {
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "%%%u", value_ref);
|
||
return;
|
||
}
|
||
// FIXME
|
||
// if (value->tag == SCC_HIR_VALUE_TAG_INTEGER) {
|
||
// scc_tree_dump_append_fmt(ctx->dump_ctx, "%d",
|
||
// value->data.const_int.int32);
|
||
// return;
|
||
// }
|
||
if (value->name && value->name[0] != '\0') {
|
||
scc_tree_dump_node(ctx->dump_ctx, "%%%u[%s]", value_ref, value->name);
|
||
} else {
|
||
scc_tree_dump_node(ctx->dump_ctx, "%%%u", value_ref);
|
||
}
|
||
if (value->type != SCC_HIR_REF_nullptr) {
|
||
scc_tree_dump_append(ctx->dump_ctx, ":");
|
||
scc_hir_dump_type_linear(ctx, value->type);
|
||
}
|
||
}
|
||
|
||
void scc_hir_dump_value_linear(scc_hir_dump_t *ctx,
|
||
scc_hir_value_ref_t value_ref) {
|
||
scc_hir_value_t *value =
|
||
scc_hir_module_get_value(GET_MODULE(ctx), value_ref);
|
||
if (!value) {
|
||
scc_tree_dump_append(ctx->dump_ctx, "<invalid value>\n");
|
||
return;
|
||
}
|
||
|
||
cbool needs_equals = (value->tag != SCC_HIR_VALUE_TAG_BRANCH &&
|
||
value->tag != SCC_HIR_VALUE_TAG_JUMP &&
|
||
value->tag != SCC_HIR_VALUE_TAG_RET &&
|
||
value->tag != SCC_HIR_VALUE_TAG_STORE);
|
||
|
||
if (needs_equals) {
|
||
format_ref_or_value(ctx, value_ref);
|
||
scc_tree_dump_append(ctx->dump_ctx, " = ");
|
||
}
|
||
|
||
switch (value->tag) {
|
||
case SCC_HIR_VALUE_TAG_BUILTIN: {
|
||
scc_tree_dump_append(ctx->dump_ctx, "@scc::");
|
||
switch (value->data.builtin.tag) {
|
||
case SCC_HIR_BUILTIN_TAG_MEMCPY:
|
||
scc_tree_dump_append(ctx->dump_ctx, "memcpy");
|
||
scc_tree_dump_append(ctx->dump_ctx, "(");
|
||
format_ref_or_value(ctx, value->data.builtin.func.memcpy.dest);
|
||
scc_tree_dump_append(ctx->dump_ctx, ", ");
|
||
format_ref_or_value(ctx, value->data.builtin.func.memcpy.src);
|
||
scc_tree_dump_append(ctx->dump_ctx, ", ");
|
||
format_ref_or_value(ctx, value->data.builtin.func.memcpy.size);
|
||
scc_tree_dump_append(ctx->dump_ctx, ")");
|
||
break;
|
||
case SCC_HIR_BUILTIN_TAG_MEMSET:
|
||
scc_tree_dump_append(ctx->dump_ctx, "memset");
|
||
break;
|
||
case SCC_HIR_BUILTIN_TAG_VA_ARG:
|
||
scc_tree_dump_append(ctx->dump_ctx, "va_arg");
|
||
break;
|
||
case SCC_HIR_BUILTIN_TAG_VA_END:
|
||
scc_tree_dump_append(ctx->dump_ctx, "va_end");
|
||
break;
|
||
case SCC_HIR_BUILTIN_TAG_VA_COPY:
|
||
scc_tree_dump_append(ctx->dump_ctx, "va_copy");
|
||
break;
|
||
case SCC_HIR_BUILTIN_TAG_VA_START:
|
||
scc_tree_dump_append(ctx->dump_ctx, "va_start");
|
||
break;
|
||
default:
|
||
Panic("Unknown builtin tag");
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case SCC_HIR_VALUE_TAG_INTEGER:
|
||
// 值已经在 format 中输出,这里不需要再做
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_AGGREGATE:
|
||
// 聚合类型:递归输出每个元素(每个占一行)
|
||
scc_vec_foreach(value->data.aggregate.fields, i) {
|
||
scc_hir_dump_value_linear(
|
||
ctx, scc_vec_at(value->data.aggregate.fields, i));
|
||
scc_tree_dump_append(ctx->dump_ctx, "\n");
|
||
}
|
||
return;
|
||
case SCC_HIR_VALUE_TAG_ALLOC:
|
||
scc_tree_dump_append(ctx->dump_ctx, "alloc");
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_LOAD:
|
||
scc_tree_dump_append(ctx->dump_ctx, "load ");
|
||
format_ref_or_value(ctx, value->data.load.target);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_STORE:
|
||
scc_tree_dump_append(ctx->dump_ctx, "store ");
|
||
format_ref_or_value(ctx, value->data.store.value);
|
||
scc_tree_dump_append(ctx->dump_ctx, " -> ");
|
||
format_ref_or_value(ctx, value->data.store.target);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_GET_ELEM_PTR:
|
||
scc_tree_dump_append(ctx->dump_ctx, "getelemptr ");
|
||
format_ref_or_value(ctx, value->data.get_elem_ptr.src_addr);
|
||
scc_tree_dump_append(ctx->dump_ctx, ", ");
|
||
format_ref_or_value(ctx, value->data.get_elem_ptr.index);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_OP:
|
||
format_ref_or_value(ctx, value->data.op.lhs);
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, " %s ",
|
||
get_op_str(value->data.op.op));
|
||
format_ref_or_value(ctx, value->data.op.rhs);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_BRANCH:
|
||
if (value->data.branch.cond) {
|
||
scc_tree_dump_append(ctx->dump_ctx, "br ");
|
||
format_ref_or_value(ctx, value->data.branch.cond);
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx,
|
||
", label %%L%u, label %%L%u",
|
||
value->data.branch.true_bblock,
|
||
value->data.branch.false_bblock);
|
||
} else {
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "br label %%L%u",
|
||
value->data.branch.true_bblock);
|
||
}
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_JUMP:
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "jmp label %%L%u",
|
||
value->data.jump.target_bblock);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_CALL: {
|
||
scc_hir_func_t *func =
|
||
scc_hir_module_get_func(GET_MODULE(ctx), value->data.call.callee);
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "call @%s(",
|
||
func ? (func->name ? func->name : "<unnamed>")
|
||
: "<invalid>");
|
||
for (usize i = 0; i < scc_vec_size(value->data.call.args); i++) {
|
||
if (i > 0)
|
||
scc_tree_dump_append(ctx->dump_ctx, ", ");
|
||
format_ref_or_value(ctx, scc_vec_at(value->data.call.args, i));
|
||
}
|
||
scc_tree_dump_append(ctx->dump_ctx, ")");
|
||
break;
|
||
}
|
||
case SCC_HIR_VALUE_TAG_RET:
|
||
if (value->data.ret.ret_val != 0) {
|
||
scc_tree_dump_append(ctx->dump_ctx, "ret ");
|
||
format_ref_or_value(ctx, value->data.ret.ret_val);
|
||
} else {
|
||
scc_tree_dump_append(ctx->dump_ctx, "ret void");
|
||
}
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_FUNC_ARG_REF:
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "arg[%zu]",
|
||
value->data.arg_ref.idx);
|
||
break;
|
||
case SCC_HIR_VALUE_TAG_GLOBAL_ALLOC:
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "global %s", value->name);
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_hir_dump_value_linear(ctx, value->data.global_alloc.value);
|
||
return;
|
||
case SCC_HIR_VALUE_TAG_ARRAY:
|
||
scc_tree_dump_append(ctx->dump_ctx, "const_array ");
|
||
scc_hir_dump_type_linear(ctx, value->data.const_array.base_type);
|
||
scc_tree_dump_append(ctx->dump_ctx, " [");
|
||
scc_vec_foreach(value->data.const_array.fields, i) {
|
||
u8 ch = scc_vec_at(value->data.const_array.fields, i);
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, " `%c`, ", ch ? ch : ' ');
|
||
}
|
||
scc_tree_dump_append(ctx->dump_ctx, " ]");
|
||
break;
|
||
default:
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "<%s value %u>",
|
||
get_node_type_str(value->tag), value_ref);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void scc_hir_dump_bblock_linear(scc_hir_dump_t *ctx,
|
||
scc_hir_bblock_ref_t bblock_ref) {
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_hir_bblock_t *bblock =
|
||
scc_hir_module_get_bblock(GET_MODULE(ctx), bblock_ref);
|
||
if (!bblock) {
|
||
scc_tree_dump_append(ctx->dump_ctx, "<invalid block>");
|
||
return;
|
||
}
|
||
if (bblock->name && bblock->name[0] != '\0')
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "%%L%d %s:", bblock_ref,
|
||
bblock->name);
|
||
else
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "%%L%d <unnamed>:", bblock_ref);
|
||
|
||
for (usize i = 0; i < scc_vec_size(SCC_HIR_BBLOCK_VALUES(*bblock)); i++) {
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_tree_dump_append(ctx->dump_ctx, " ");
|
||
scc_hir_dump_value_linear(
|
||
ctx, scc_vec_at(SCC_HIR_BBLOCK_VALUES(*bblock), i));
|
||
}
|
||
}
|
||
|
||
void scc_hir_dump_func_linear(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref,
|
||
int is_decl) {
|
||
scc_hir_func_t *func = scc_hir_module_get_func(GET_MODULE(ctx), func_ref);
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
if (!func) {
|
||
scc_tree_dump_append(ctx->dump_ctx, "<invalid function>");
|
||
return;
|
||
}
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "func @%s",
|
||
(func->name && func->name[0]) ? func->name
|
||
: "<unnamed>");
|
||
|
||
if (scc_vec_size(SCC_HIR_FUNC_META(*func)->params) > 0) {
|
||
scc_tree_dump_append(ctx->dump_ctx, "(");
|
||
for (usize i = 0; i < scc_vec_size(SCC_HIR_FUNC_META(*func)->params);
|
||
i++) {
|
||
if (i > 0)
|
||
scc_tree_dump_append(ctx->dump_ctx, ", ");
|
||
scc_hir_value_ref_t param_ref =
|
||
scc_vec_at(SCC_HIR_FUNC_META(*func)->params, i);
|
||
scc_hir_value_t *param_node =
|
||
scc_hir_module_get_value(GET_MODULE(ctx), param_ref);
|
||
scc_tree_dump_append(ctx->dump_ctx, "%");
|
||
if (param_node && param_node->name && param_node->name[0] != '\0')
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "%u[%s]", param_ref,
|
||
param_node->name);
|
||
else
|
||
scc_tree_dump_append_fmt(ctx->dump_ctx, "%u", param_ref);
|
||
}
|
||
scc_tree_dump_append(ctx->dump_ctx, ")");
|
||
} else {
|
||
scc_tree_dump_append(ctx->dump_ctx, "()");
|
||
}
|
||
|
||
scc_tree_dump_append(ctx->dump_ctx, ": ");
|
||
scc_hir_dump_type_linear(ctx, SCC_HIR_FUNC_META(*func)->type);
|
||
|
||
if (is_decl) {
|
||
scc_tree_dump_append(ctx->dump_ctx, ";");
|
||
return;
|
||
}
|
||
|
||
scc_tree_dump_append(ctx->dump_ctx, " {");
|
||
for (usize i = 0; i < scc_vec_size(func->bblocks); i++) {
|
||
scc_hir_dump_bblock_linear(ctx, scc_vec_at(func->bblocks, i));
|
||
scc_tree_dump_append(ctx->dump_ctx, "");
|
||
}
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_tree_dump_append(ctx->dump_ctx, "}");
|
||
}
|
||
|
||
void scc_hir_dump_cprog_linear(scc_hir_dump_t *ctx) {
|
||
for (usize i = 0; i < scc_vec_size(ctx->cprog->global_vals); i++) {
|
||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||
scc_hir_dump_value_linear(ctx, scc_vec_at(ctx->cprog->global_vals, i));
|
||
}
|
||
for (usize i = 0; i < scc_vec_size(ctx->cprog->func_decls); i++) {
|
||
scc_hir_func_ref_t func_decl = scc_vec_at(ctx->cprog->func_decls, i);
|
||
scc_hir_func_t *func =
|
||
scc_hir_module_get_func(GET_MODULE(ctx), func_decl);
|
||
if (func && scc_vec_size(func->bblocks) == 0)
|
||
scc_hir_dump_func_linear(ctx, func_decl, 1);
|
||
}
|
||
for (usize i = 0; i < scc_vec_size(ctx->cprog->func_defs); i++) {
|
||
scc_hir_dump_func_linear(ctx, scc_vec_at(ctx->cprog->func_defs, i), 0);
|
||
}
|
||
}
|