- 实现了IR的线性转储功能,包括类型、节点、基本块和函数的线性表示 - 添加了scc_ir_dump_ctx_init函数用于初始化转储上下文 - 为AST函数类型添加了变参标记注释说明 - 改进了AST转储中函数类型的参数和返回值显示逻辑 - 统一了AST解析中节点类型的声明为通用的scc_ast_node_t指针类型 fix(lexer): 改进词法分析器错误信息显示 - 在不支持字符的错误信息中添加十六进制编码显示 - 便于调试时识别特殊不可打印字符
826 lines
28 KiB
C
826 lines
28 KiB
C
#include <ir_ctx.h>
|
||
#include <ir_dump.h>
|
||
|
||
#define PRINT_VALUE(ctx, fmt, value) \
|
||
SCC_TREE_DUMP_PRINT_PURE(ctx, ctx->value_color, fmt, value)
|
||
|
||
#define PRINT_NODE(ctx, name) \
|
||
SCC_TREE_DUMP_PRINT_PURE(ctx, ctx->node_color, "%s", name)
|
||
|
||
#define PRINT_QUOTED_VALUE(ctx, str) \
|
||
SCC_TREE_DUMP_PRINT_AROUND(ctx, ctx->value_color, "'", "%s", str)
|
||
|
||
// 获取IR节点类型的字符串表示
|
||
static const char *get_node_type_str(scc_ir_node_tag_t tag) {
|
||
static const char *node_types[] = {
|
||
[SCC_IR_NODE_NULL] = "Null", [SCC_IR_NODE_CONST_INT] = "ConstInt",
|
||
[SCC_IR_NODE_ALLOC] = "Alloc", [SCC_IR_NODE_LOAD] = "Load",
|
||
[SCC_IR_NODE_STORE] = "Store", [SCC_IR_NODE_GET_PTR] = "GetElementPtr",
|
||
[SCC_IR_NODE_OP] = "Op", [SCC_IR_NODE_BRANCH] = "Branch",
|
||
[SCC_IR_NODE_JUMP] = "Jump", [SCC_IR_NODE_CALL] = "Call",
|
||
[SCC_IR_NODE_RET] = "Return",
|
||
};
|
||
|
||
if (tag >= 0 && tag < sizeof(node_types) / sizeof(node_types[0]) &&
|
||
node_types[tag] != NULL) {
|
||
return node_types[tag];
|
||
}
|
||
return "UnknownIRNode";
|
||
}
|
||
|
||
// 获取操作符字符串
|
||
static const char *get_op_str(scc_ir_op_type_t op) {
|
||
static const char *ops[] = {
|
||
[IR_OP_EMPTY] = "empty", [IR_OP_NEQ] = "!=", [IR_OP_EQ] = "==",
|
||
[IR_OP_GT] = ">", [IR_OP_LT] = "<", [IR_OP_GE] = ">=",
|
||
[IR_OP_LE] = "<=", [IR_OP_ADD] = "+", [IR_OP_SUB] = "-",
|
||
[IR_OP_MUL] = "*", [IR_OP_DIV] = "/", [IR_OP_MOD] = "%",
|
||
[IR_OP_AND] = "&", [IR_OP_OR] = "|", [IR_OP_XOR] = "^",
|
||
[IR_OP_NOT] = "~", [IR_OP_SHL] = "<<", [IR_OP_SHR] = ">>",
|
||
[IR_OP_SAR] = ">>a", // Arithmetic shift right
|
||
};
|
||
|
||
if (op >= 0 && op < sizeof(ops) / sizeof(ops[0]) && ops[op] != NULL) {
|
||
return ops[op];
|
||
}
|
||
return "<unknown_op>";
|
||
}
|
||
|
||
// 获取类型标签字符串
|
||
static const char *get_type_tag_str(scc_ir_type_tag_t tag) {
|
||
static const char *type_tags[] = {
|
||
[SCC_IR_TYPE_VOID] = "void", [SCC_IR_TYPE_I1] = "i1",
|
||
[SCC_IR_TYPE_I8] = "i8", [SCC_IR_TYPE_I16] = "i16",
|
||
[SCC_IR_TYPE_I32] = "i32", [SCC_IR_TYPE_I64] = "i64",
|
||
[SCC_IR_TYPE_I128] = "i128", [SCC_IR_TYPE_F16] = "f16",
|
||
[SCC_IR_TYPE_F32] = "f32", [SCC_IR_TYPE_F64] = "f64",
|
||
[SCC_IR_TYPE_F128] = "f128", [SCC_IR_TYPE_PTR] = "ptr",
|
||
[SCC_IR_TYPE_ARRAY] = "array", [SCC_IR_TYPE_FUNC] = "func",
|
||
[SCC_IR_TYPE_STRUCT] = "struct", [SCC_IR_TYPE_VECTOR] = "vector",
|
||
};
|
||
|
||
if (tag >= 0 && tag < sizeof(type_tags) / sizeof(type_tags[0]) &&
|
||
type_tags[tag] != NULL) {
|
||
return type_tags[tag];
|
||
}
|
||
return "<unknown_type>";
|
||
}
|
||
|
||
// 递归转储辅助函数(使用引用)
|
||
static inline void dump_child_node_ref(scc_ir_dump_ctx_t *ctx,
|
||
scc_ir_node_ref_t child_ref,
|
||
cbool is_last) {
|
||
if (!child_ref)
|
||
return;
|
||
scc_tree_dump_push_level(ctx->dump_ctx, is_last);
|
||
scc_ir_dump_node(ctx, child_ref);
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
|
||
// 转储常量整数节点
|
||
static void dump_const_int_node(scc_ir_dump_ctx_t *ctx,
|
||
const scc_ir_node_t *node) {
|
||
scc_tree_dump_push_level(ctx->dump_ctx, true);
|
||
scc_tree_print_indent(ctx->dump_ctx);
|
||
scc_printf("%d\n", node->data.const_int.int32);
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
|
||
// 转储操作节点
|
||
static void dump_op_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
|
||
// 打印操作符
|
||
scc_tree_dump_push_level(ctx->dump_ctx, false);
|
||
scc_tree_print_indent(ctx->dump_ctx);
|
||
SCC_TREE_DUMP_PRINT_PURE(ctx->dump_ctx, ctx->dump_ctx->node_color,
|
||
"op: %s\n", get_op_str(node->data.op.op));
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
|
||
// 左操作数
|
||
if (node->data.op.lhs) {
|
||
dump_child_node_ref(ctx, node->data.op.lhs,
|
||
node->data.op.rhs ? false : true);
|
||
}
|
||
|
||
// 右操作数
|
||
if (node->data.op.rhs) {
|
||
dump_child_node_ref(ctx, node->data.op.rhs, true);
|
||
}
|
||
}
|
||
|
||
// 转储加载节点
|
||
static void dump_load_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
|
||
// PRINT_NODE(ctx->dump_ctx, "load");
|
||
if (node->data.load.target) {
|
||
dump_child_node_ref(ctx, node->data.load.target, true);
|
||
}
|
||
}
|
||
|
||
// 转储存储节点
|
||
static void dump_store_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
|
||
// PRINT_NODE(ctx->dump_ctx, "store");
|
||
|
||
// 输出存储位置
|
||
if (node->data.store.target) {
|
||
dump_child_node_ref(ctx, node->data.store.target, false);
|
||
}
|
||
|
||
// 输出存储的值
|
||
if (node->data.store.value) {
|
||
dump_child_node_ref(ctx, node->data.store.value, true);
|
||
}
|
||
}
|
||
|
||
// 转储获取指针节点
|
||
static void dump_get_ptr_node(scc_ir_dump_ctx_t *ctx,
|
||
const scc_ir_node_t *node) {
|
||
// PRINT_NODE(ctx->dump_ctx, "get_ptr");
|
||
// 输出源地址
|
||
if (node->data.get_ptr.src_addr) {
|
||
dump_child_node_ref(ctx, node->data.get_ptr.src_addr, false);
|
||
}
|
||
|
||
// 输出索引
|
||
if (node->data.get_ptr.index) {
|
||
dump_child_node_ref(ctx, node->data.get_ptr.index, true);
|
||
}
|
||
}
|
||
|
||
// 转储分支节点
|
||
static void dump_branch_node(scc_ir_dump_ctx_t *ctx,
|
||
const scc_ir_node_t *node) {
|
||
// PRINT_NODE(ctx->dump_ctx, "branch");
|
||
|
||
// 输出条件
|
||
if (node->data.branch.cond) {
|
||
dump_child_node_ref(ctx, node->data.branch.cond, false);
|
||
}
|
||
|
||
// 输出真分支块
|
||
if (node->data.branch.true_bblock) {
|
||
scc_ir_bblock_t *true_bblock =
|
||
scc_ir_ctx_get_bblock(ctx->ir_ctx, node->data.branch.true_bblock);
|
||
if (true_bblock) {
|
||
scc_tree_print_indent(ctx->dump_ctx);
|
||
PRINT_NODE(ctx->dump_ctx, "TrueBlock: ");
|
||
PRINT_QUOTED_VALUE(ctx->dump_ctx, true_bblock->label
|
||
? true_bblock->label
|
||
: "<unnamed>");
|
||
}
|
||
}
|
||
|
||
// 输出假分支块
|
||
if (node->data.branch.false_bblock) {
|
||
scc_ir_bblock_t *false_bblock =
|
||
scc_ir_ctx_get_bblock(ctx->ir_ctx, node->data.branch.false_bblock);
|
||
if (false_bblock) {
|
||
scc_tree_print_indent(ctx->dump_ctx);
|
||
PRINT_NODE(ctx->dump_ctx, "FalseBlock: ");
|
||
PRINT_QUOTED_VALUE(ctx->dump_ctx, false_bblock->label
|
||
? false_bblock->label
|
||
: "<unnamed>");
|
||
}
|
||
}
|
||
}
|
||
|
||
// 转储跳转节点
|
||
static void dump_jump_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
|
||
// PRINT_NODE(ctx->dump_ctx, "jump");
|
||
if (node->data.jump.target_bblock) {
|
||
scc_ir_bblock_t *target_bblock =
|
||
scc_ir_ctx_get_bblock(ctx->ir_ctx, node->data.jump.target_bblock);
|
||
if (target_bblock) {
|
||
scc_printf("to '%s'", target_bblock->label ? target_bblock->label
|
||
: "<unnamed>");
|
||
} else {
|
||
scc_printf("to invalid block");
|
||
}
|
||
} else {
|
||
scc_printf("to NULL");
|
||
}
|
||
}
|
||
|
||
// 转储调用节点
|
||
static void dump_call_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
|
||
// PRINT_NODE(ctx->dump_ctx, "call");
|
||
if (node->data.call.callee) {
|
||
scc_ir_func_t *callee =
|
||
scc_ir_ctx_get_func(ctx->ir_ctx, node->data.call.callee);
|
||
if (callee) {
|
||
scc_printf("func='%s'", callee->name ? callee->name : "<unnamed>");
|
||
} else {
|
||
scc_printf("func=<invalid>");
|
||
}
|
||
} else {
|
||
scc_printf("func=NULL");
|
||
}
|
||
|
||
if (scc_vec_size(node->data.call.args) > 0) {
|
||
scc_printf("\n");
|
||
}
|
||
|
||
// 输出参数
|
||
for (usize i = 0; i < scc_vec_size(node->data.call.args); i++) {
|
||
cbool is_last = (i + 1 == scc_vec_size(node->data.call.args));
|
||
scc_tree_dump_push_level(ctx->dump_ctx, is_last);
|
||
|
||
scc_ir_node_ref_t arg_ref = scc_vec_at(node->data.call.args, i);
|
||
dump_child_node_ref(ctx, arg_ref, is_last);
|
||
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
}
|
||
|
||
// 转储返回节点
|
||
static void dump_ret_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
|
||
// PRINT_NODE(ctx->dump_ctx, "ret");
|
||
if (node->data.ret.ret_val) {
|
||
dump_child_node_ref(ctx, node->data.ret.ret_val, true);
|
||
}
|
||
}
|
||
|
||
void scc_ir_dump_ctx_init(scc_ir_dump_ctx_t *ctx,
|
||
scc_tree_dump_ctx_t *tree_dump, scc_ir_cprog_t *cprog,
|
||
scc_ir_cprog_ctx_t *ir_ctx) {
|
||
ctx->cprog = cprog;
|
||
ctx->dump_ctx = tree_dump;
|
||
ctx->ir_ctx = ir_ctx;
|
||
}
|
||
|
||
void scc_ir_dump_node(scc_ir_dump_ctx_t *ctx, scc_ir_node_ref_t node_ref) {
|
||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||
if (!node) {
|
||
LOG_ERROR("Invalid node ref");
|
||
return;
|
||
}
|
||
|
||
scc_tree_print_indent(ctx->dump_ctx);
|
||
PRINT_NODE(ctx->dump_ctx, get_node_type_str(node->tag));
|
||
|
||
if (node->name && node->name[0]) {
|
||
PRINT_VALUE(ctx->dump_ctx, " [%s]", node->name);
|
||
}
|
||
|
||
if (node->type) {
|
||
scc_printf(" : ");
|
||
scc_ir_type_t *type = scc_ir_ctx_get_type(ctx->ir_ctx, node->type);
|
||
if (type) {
|
||
PRINT_VALUE(ctx->dump_ctx, "%s", get_type_tag_str(type->tag));
|
||
}
|
||
}
|
||
|
||
scc_printf("\n");
|
||
|
||
// 根据节点类型输出特定信息
|
||
switch (node->tag) {
|
||
case SCC_IR_NODE_NULL:
|
||
break;
|
||
case SCC_IR_NODE_CONST_INT:
|
||
dump_const_int_node(ctx, node);
|
||
break;
|
||
case SCC_IR_NODE_ALLOC:
|
||
break;
|
||
case SCC_IR_NODE_LOAD:
|
||
dump_load_node(ctx, node);
|
||
break;
|
||
case SCC_IR_NODE_STORE:
|
||
dump_store_node(ctx, node);
|
||
break;
|
||
case SCC_IR_NODE_GET_PTR:
|
||
dump_get_ptr_node(ctx, node);
|
||
break;
|
||
case SCC_IR_NODE_OP:
|
||
dump_op_node(ctx, node);
|
||
break;
|
||
case SCC_IR_NODE_BRANCH:
|
||
dump_branch_node(ctx, node);
|
||
break;
|
||
case SCC_IR_NODE_JUMP:
|
||
dump_jump_node(ctx, node);
|
||
break;
|
||
case SCC_IR_NODE_CALL:
|
||
dump_call_node(ctx, node);
|
||
break;
|
||
case SCC_IR_NODE_RET:
|
||
dump_ret_node(ctx, node);
|
||
break;
|
||
default:
|
||
PRINT_QUOTED_VALUE(ctx->dump_ctx, "unknown");
|
||
scc_printf("tag(%d)", node->tag);
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 转储类型信息
|
||
void scc_ir_dump_type(scc_ir_dump_ctx_t *ctx, scc_ir_type_ref_t type_ref) {
|
||
if (!ctx || !type_ref) {
|
||
LOG_ERROR("invalid parameter");
|
||
return;
|
||
}
|
||
|
||
scc_ir_type_t *type = scc_ir_ctx_get_type(ctx->ir_ctx, type_ref);
|
||
if (!type) {
|
||
LOG_ERROR("invalid type ref");
|
||
return;
|
||
}
|
||
scc_tree_print_indent(ctx->dump_ctx);
|
||
PRINT_NODE(ctx->dump_ctx, "Type: ");
|
||
PRINT_QUOTED_VALUE(ctx->dump_ctx, get_type_tag_str(type->tag));
|
||
scc_printf("\n");
|
||
|
||
// 递归转储子类型
|
||
switch (type->tag) {
|
||
case SCC_IR_TYPE_PTR:
|
||
if (type->data.pointer.base) {
|
||
scc_tree_dump_push_level(ctx->dump_ctx, true);
|
||
scc_ir_dump_type(ctx, type->data.pointer.base);
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
break;
|
||
case SCC_IR_TYPE_ARRAY:
|
||
if (type->data.array.len > 0) {
|
||
scc_tree_print_indent(ctx->dump_ctx);
|
||
SCC_TREE_DUMP_PRINT_PURE(ctx->dump_ctx, ctx->dump_ctx->node_color,
|
||
"Array Length: %zu\n",
|
||
type->data.array.len);
|
||
}
|
||
if (type->data.array.base) {
|
||
scc_tree_dump_push_level(ctx->dump_ctx, true);
|
||
scc_ir_dump_type(ctx, type->data.array.base);
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
break;
|
||
case SCC_IR_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_level(ctx->dump_ctx, is_last);
|
||
|
||
scc_ir_type_ref_t param_type_ref =
|
||
scc_vec_at(type->data.function.params, i);
|
||
scc_ir_dump_type(ctx, param_type_ref);
|
||
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
|
||
// 再输出返回类型
|
||
if (type->data.function.ret_type) {
|
||
scc_tree_dump_push_level(ctx->dump_ctx, true);
|
||
scc_ir_dump_type(ctx, type->data.function.ret_type);
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
break;
|
||
case SCC_IR_TYPE_STRUCT:
|
||
// 结构体处理
|
||
break;
|
||
case SCC_IR_TYPE_VECTOR:
|
||
// 向量处理
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 转储基本块
|
||
void scc_ir_dump_bblock(scc_ir_dump_ctx_t *ctx,
|
||
scc_ir_bblock_ref_t bblock_ref) {
|
||
if (!ctx || !bblock_ref) {
|
||
LOG_ERROR("invalid parameter");
|
||
return;
|
||
}
|
||
|
||
scc_ir_bblock_t *bblock = scc_ir_ctx_get_bblock(ctx->ir_ctx, bblock_ref);
|
||
if (!bblock) {
|
||
LOG_ERROR("invalid bblock ref");
|
||
return;
|
||
}
|
||
|
||
scc_tree_print_indent(ctx->dump_ctx);
|
||
PRINT_NODE(ctx->dump_ctx, "BasicBlock: ");
|
||
PRINT_QUOTED_VALUE(ctx->dump_ctx,
|
||
bblock->label ? bblock->label : "<unnamed>");
|
||
scc_printf("\n");
|
||
|
||
// 转储基本块中的指令
|
||
for (usize i = 0; i < scc_vec_size(bblock->instrs); i++) {
|
||
cbool is_last = (i + 1 == scc_vec_size(bblock->instrs));
|
||
scc_tree_dump_push_level(ctx->dump_ctx, is_last);
|
||
|
||
scc_ir_node_ref_t instr_ref = scc_vec_at(bblock->instrs, i);
|
||
scc_ir_dump_node(ctx, instr_ref);
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
}
|
||
|
||
// 转储函数
|
||
void scc_ir_dump_func(scc_ir_dump_ctx_t *ctx, scc_ir_func_ref_t func_ref) {
|
||
scc_ir_func_t *func = scc_ir_ctx_get_func(ctx->ir_ctx, func_ref);
|
||
if (!ctx || !func) {
|
||
LOG_ERROR("invalid parameter");
|
||
return;
|
||
}
|
||
|
||
scc_tree_print_indent(ctx->dump_ctx);
|
||
PRINT_NODE(ctx->dump_ctx, "Function: ");
|
||
PRINT_QUOTED_VALUE(ctx->dump_ctx, func->name ? func->name : "<unnamed>");
|
||
scc_printf("\n");
|
||
|
||
// 输出函数类型
|
||
if (func->type) {
|
||
scc_tree_dump_push_level(ctx->dump_ctx, false);
|
||
scc_ir_dump_type(ctx, func->type);
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
|
||
// 输出函数参数
|
||
for (usize i = 0; i < scc_vec_size(func->params); i++) {
|
||
cbool is_last = (i + 1 == scc_vec_size(func->params));
|
||
scc_tree_dump_push_level(ctx->dump_ctx, is_last);
|
||
|
||
scc_ir_node_ref_t param_ref = scc_vec_at(func->params, i);
|
||
scc_ir_dump_node(ctx, param_ref);
|
||
scc_tree_dump_pop_level(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_level(ctx->dump_ctx, is_last);
|
||
|
||
scc_ir_bblock_ref_t bblock_ref = scc_vec_at(func->bblocks, i);
|
||
scc_ir_dump_bblock(ctx, bblock_ref);
|
||
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
}
|
||
|
||
// 转储整个程序
|
||
void scc_ir_dump_cprog(scc_ir_dump_ctx_t *ctx) {
|
||
// 输出全局值
|
||
|
||
// if (scc_vec_size(program->global_vals) > 0) {
|
||
// print_indented(ctx, "Global Values:", "");
|
||
|
||
// for (usize i = 0; i < scc_vec_size(program->global_vals); i++) {
|
||
// cbool is_last = (i + 1 ==
|
||
// scc_vec_size(program->global_vals));
|
||
// scc_tree_dump_push_level(ctx->dump_ctx, is_last);
|
||
|
||
// scc_ir_node_ref_t global_ref =
|
||
// scc_vec_at(program->global_vals, i); scc_ir_node_t
|
||
// *global_node =
|
||
// scc_ir_ctx_get_node(ir_ctx, global_ref);
|
||
// if (global_node) {
|
||
// scc_ir_dump_node(ctx, ir_ctx, global_node);
|
||
// }
|
||
|
||
// scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
// }
|
||
// }
|
||
|
||
// // 输出函数定义
|
||
// if (scc_vec_size(ir_ctx->funcs) > 0) {
|
||
// print_indented(ctx, "Functions:", "");
|
||
|
||
// for (usize i = 0; i < scc_vec_size(ir_ctx->funcs); i++) {
|
||
// cbool is_last = (i + 1 == scc_vec_size(ir_ctx->funcs));
|
||
// scc_tree_dump_push_level(ctx->dump_ctx, is_last);
|
||
|
||
// scc_ir_func_t func_ref = scc_vec_at(ir_ctx->funcs, i);
|
||
// if (func_ref.type != 0) {
|
||
// // TODO hack it
|
||
// dump_func_ref(ir_ctx, ctx, i + 1);
|
||
// }
|
||
|
||
// scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
// }
|
||
// }
|
||
PRINT_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_level(ctx->dump_ctx, is_last);
|
||
scc_ir_dump_func(ctx, scc_vec_at(ctx->cprog->func_defs, i));
|
||
scc_tree_dump_pop_level(ctx->dump_ctx);
|
||
}
|
||
}
|
||
|
||
void scc_ir_dump_type_linear(scc_ir_dump_ctx_t *ctx,
|
||
scc_ir_type_ref_t type_ref) {
|
||
scc_ir_type_t *type = scc_ir_ctx_get_type(ctx->ir_ctx, type_ref);
|
||
if (!ctx || !type) {
|
||
LOG_ERROR("invalid parameter");
|
||
return;
|
||
}
|
||
#define PRINT_TYPE(ctx, name) PRINT_VALUE(ctx, "%s", name)
|
||
switch (type->tag) {
|
||
case SCC_IR_TYPE_I32:
|
||
PRINT_TYPE(ctx->dump_ctx, "i32");
|
||
break;
|
||
case SCC_IR_TYPE_VOID:
|
||
PRINT_TYPE(ctx->dump_ctx, "void");
|
||
break;
|
||
case SCC_IR_TYPE_ARRAY:
|
||
PRINT_TYPE(ctx->dump_ctx, "[");
|
||
scc_ir_dump_type_linear(ctx, type->data.array.base);
|
||
PRINT_TYPE(ctx->dump_ctx, ", ");
|
||
PRINT_TYPE(ctx->dump_ctx, type->data.array.len);
|
||
PRINT_TYPE(ctx->dump_ctx, "]");
|
||
break;
|
||
case SCC_IR_TYPE_PTR:
|
||
PRINT_TYPE(ctx->dump_ctx, "*");
|
||
scc_ir_dump_type_linear(ctx, type->data.pointer.base);
|
||
break;
|
||
case SCC_IR_TYPE_FUNC:
|
||
PRINT_TYPE(ctx->dump_ctx, "(");
|
||
cbool is_first = true;
|
||
scc_vec_foreach(type->data.function.params, i) {
|
||
if (!is_first) {
|
||
PRINT_TYPE(ctx->dump_ctx, ", ");
|
||
}
|
||
scc_ir_dump_type_linear(ctx,
|
||
scc_vec_at(type->data.function.params, i));
|
||
is_first = false;
|
||
}
|
||
if (type->data.function.ret_type) {
|
||
PRINT_TYPE(ctx->dump_ctx, ") -> ");
|
||
scc_ir_dump_type_linear(ctx, type->data.function.ret_type);
|
||
} else {
|
||
PRINT_TYPE(ctx->dump_ctx, ")");
|
||
}
|
||
default:
|
||
LOG_ERROR("invalid type tag");
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 辅助函数:输出节点引用或值到缓冲区
|
||
static usize format_node_ref_or_value(scc_ir_dump_ctx_t *ctx, char *buf,
|
||
usize size, scc_ir_node_ref_t node_ref) {
|
||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||
if (!node) {
|
||
return scc_snprintf(buf, size, "%%%u", node_ref);
|
||
}
|
||
|
||
// 如果是常量整数,直接输出值
|
||
if (node->tag == SCC_IR_NODE_CONST_INT) {
|
||
return scc_snprintf(buf, size, "%d", node->data.const_int.int32);
|
||
}
|
||
|
||
// 其他节点输出引用和名称
|
||
if (node->name && node->name[0] != '\0') {
|
||
return scc_snprintf(buf, size, "%%%u[%s]", node_ref, node->name);
|
||
} else {
|
||
return scc_snprintf(buf, size, "%%%u", node_ref);
|
||
}
|
||
}
|
||
|
||
// 线性输出节点信息(SSA IR风格)
|
||
void scc_ir_dump_node_linear(scc_ir_dump_ctx_t *ctx,
|
||
scc_ir_node_ref_t node_ref) {
|
||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||
if (node == null) {
|
||
LOG_ERROR("invalid node ref");
|
||
return;
|
||
}
|
||
|
||
static char buff[512]; // 更大的缓冲区处理复杂的指令
|
||
char *p = buff;
|
||
usize remaining = sizeof(buff);
|
||
|
||
// 判断是否需要输出等号
|
||
cbool needs_equals =
|
||
(node->tag != SCC_IR_NODE_BRANCH && node->tag != SCC_IR_NODE_JUMP &&
|
||
node->tag != SCC_IR_NODE_RET && node->tag != SCC_IR_NODE_STORE);
|
||
|
||
if (needs_equals) {
|
||
// 输出左值和类型
|
||
if (node->name && node->name[0] != '\0') {
|
||
p += scc_snprintf(p, remaining, "%%%u[%s]", node_ref, node->name);
|
||
} else {
|
||
p += scc_snprintf(p, remaining, "%%%u", node_ref);
|
||
}
|
||
|
||
remaining = sizeof(buff) - (p - buff);
|
||
|
||
if (node->type != 0) {
|
||
p += scc_snprintf(p, remaining, " `");
|
||
remaining = sizeof(buff) - (p - buff);
|
||
// p += dump_type_to_buf(ctx, p, remaining, node->type);
|
||
// remaining = sizeof(buff) - (p - buff);
|
||
p += scc_snprintf(p, remaining, "`");
|
||
remaining = sizeof(buff) - (p - buff);
|
||
}
|
||
|
||
p += scc_snprintf(p, remaining, " = ");
|
||
remaining = sizeof(buff) - (p - buff);
|
||
}
|
||
|
||
// 构建操作部分
|
||
switch (node->tag) {
|
||
case SCC_IR_NODE_CONST_INT:
|
||
// 常量节点定义,直接输出值
|
||
p += scc_snprintf(p, remaining, "%d", node->data.const_int.int32);
|
||
break;
|
||
|
||
case SCC_IR_NODE_ALLOC:
|
||
p += scc_snprintf(p, remaining, "alloc");
|
||
break;
|
||
|
||
case SCC_IR_NODE_LOAD: {
|
||
char operand_buf[64];
|
||
format_node_ref_or_value(ctx, operand_buf, sizeof(operand_buf),
|
||
node->data.load.target);
|
||
p += scc_snprintf(p, remaining, "load %s", operand_buf);
|
||
break;
|
||
}
|
||
|
||
case SCC_IR_NODE_STORE: {
|
||
char value_buf[64], target_buf[64];
|
||
format_node_ref_or_value(ctx, value_buf, sizeof(value_buf),
|
||
node->data.store.value);
|
||
format_node_ref_or_value(ctx, target_buf, sizeof(target_buf),
|
||
node->data.store.target);
|
||
p +=
|
||
scc_snprintf(p, remaining, "store %s -> %s", value_buf, target_buf);
|
||
break;
|
||
}
|
||
|
||
case SCC_IR_NODE_GET_PTR: {
|
||
char src_buf[64], idx_buf[64];
|
||
format_node_ref_or_value(ctx, src_buf, sizeof(src_buf),
|
||
node->data.get_ptr.src_addr);
|
||
format_node_ref_or_value(ctx, idx_buf, sizeof(idx_buf),
|
||
node->data.get_ptr.index);
|
||
p += scc_snprintf(p, remaining, "getelemptr %s, %s", src_buf, idx_buf);
|
||
break;
|
||
}
|
||
|
||
case SCC_IR_NODE_OP: {
|
||
char lhs_buf[64], rhs_buf[64];
|
||
format_node_ref_or_value(ctx, lhs_buf, sizeof(lhs_buf),
|
||
node->data.op.lhs);
|
||
format_node_ref_or_value(ctx, rhs_buf, sizeof(rhs_buf),
|
||
node->data.op.rhs);
|
||
p += scc_snprintf(p, remaining, "%s %s %s", lhs_buf,
|
||
get_op_str(node->data.op.op), rhs_buf);
|
||
break;
|
||
}
|
||
|
||
case SCC_IR_NODE_BRANCH:
|
||
if (node->data.branch.cond) {
|
||
char cond_buf[64];
|
||
format_node_ref_or_value(ctx, cond_buf, sizeof(cond_buf),
|
||
node->data.branch.cond);
|
||
p += scc_snprintf(p, remaining, "br %s, label %%%u, label %%%u",
|
||
cond_buf, node->data.branch.true_bblock,
|
||
node->data.branch.false_bblock);
|
||
} else {
|
||
p += scc_snprintf(p, remaining, "br label %%%u",
|
||
node->data.branch.true_bblock);
|
||
}
|
||
break;
|
||
|
||
case SCC_IR_NODE_JUMP:
|
||
p += scc_snprintf(p, remaining, "jmp label %%%u",
|
||
node->data.jump.target_bblock);
|
||
break;
|
||
|
||
case SCC_IR_NODE_CALL: {
|
||
char args_buf[256] = "";
|
||
char *args_p = args_buf;
|
||
usize args_remaining = sizeof(args_buf);
|
||
|
||
for (usize i = 0; i < scc_vec_size(node->data.call.args); i++) {
|
||
if (i > 0) {
|
||
args_p += scc_snprintf(args_p, args_remaining, ", ");
|
||
args_remaining = sizeof(args_buf) - (args_p - args_buf);
|
||
}
|
||
|
||
char arg_buf[64];
|
||
format_node_ref_or_value(ctx, arg_buf, sizeof(arg_buf),
|
||
scc_vec_at(node->data.call.args, i));
|
||
|
||
args_p += scc_snprintf(args_p, args_remaining, "%s", arg_buf);
|
||
args_remaining = sizeof(args_buf) - (args_p - args_buf);
|
||
}
|
||
|
||
p += scc_snprintf(p, remaining, "call @%%%u(%s)",
|
||
node->data.call.callee, args_buf);
|
||
break;
|
||
}
|
||
|
||
case SCC_IR_NODE_RET:
|
||
if (node->data.ret.ret_val != 0) {
|
||
char ret_buf[64];
|
||
format_node_ref_or_value(ctx, ret_buf, sizeof(ret_buf),
|
||
node->data.ret.ret_val);
|
||
p += scc_snprintf(p, remaining, "ret %s", ret_buf);
|
||
} else {
|
||
p += scc_snprintf(p, remaining, "ret void");
|
||
}
|
||
break;
|
||
|
||
default:
|
||
p += scc_snprintf(p, remaining, "<%s node %u>",
|
||
get_node_type_str(node->tag), node_ref);
|
||
break;
|
||
}
|
||
(void)p;
|
||
// 打印完整行
|
||
PRINT_NODE(ctx->dump_ctx, buff);
|
||
}
|
||
|
||
// 线性输出基本块信息
|
||
void scc_ir_dump_bblock_linear(scc_ir_dump_ctx_t *ctx,
|
||
scc_ir_bblock_ref_t bblock_ref) {
|
||
scc_ir_bblock_t *bblock = scc_ir_ctx_get_bblock(ctx->ir_ctx, bblock_ref);
|
||
|
||
if (bblock == null) {
|
||
PRINT_NODE(ctx->dump_ctx, "<invalid block>\n");
|
||
return;
|
||
}
|
||
|
||
// 打印基本块标签
|
||
static char label_buff[128];
|
||
if (bblock->label && bblock->label[0] != '\0') {
|
||
scc_snprintf(label_buff, sizeof(label_buff), "%%%s:", bblock->label);
|
||
} else {
|
||
scc_snprintf(label_buff, sizeof(label_buff), "<unnamed>:");
|
||
}
|
||
PRINT_NODE(ctx->dump_ctx, label_buff);
|
||
|
||
// 打印基本块中的每条指令
|
||
for (usize i = 0; i < scc_vec_size(bblock->instrs); i++) {
|
||
scc_ir_node_ref_t node_ref = scc_vec_at(bblock->instrs, i);
|
||
PRINT_NODE(ctx->dump_ctx, "\n ");
|
||
scc_ir_dump_node_linear(ctx, node_ref);
|
||
}
|
||
}
|
||
|
||
// 线性输出函数信息
|
||
void scc_ir_dump_func_linear(scc_ir_dump_ctx_t *ctx,
|
||
scc_ir_func_ref_t func_ref) {
|
||
scc_ir_func_t *func = scc_ir_ctx_get_func(ctx->ir_ctx, func_ref);
|
||
if (!func) {
|
||
LOG_ERROR("invalid function reference");
|
||
return;
|
||
}
|
||
|
||
static char buff[256];
|
||
|
||
// 打印函数签名
|
||
if (func->name && func->name[0] != '\0') {
|
||
scc_snprintf(buff, sizeof(buff), "func @%s", func->name);
|
||
} else {
|
||
scc_snprintf(buff, sizeof(buff), "func @<unnamed>");
|
||
}
|
||
PRINT_NODE(ctx->dump_ctx, buff);
|
||
|
||
// 打印函数参数列表
|
||
if (scc_vec_size(func->params) > 0) {
|
||
PRINT_NODE(ctx->dump_ctx, "(");
|
||
for (usize i = 0; i < scc_vec_size(func->params); i++) {
|
||
if (i > 0)
|
||
PRINT_NODE(ctx->dump_ctx, ", ");
|
||
scc_ir_node_ref_t param_ref = scc_vec_at(func->params, i);
|
||
PRINT_NODE(ctx->dump_ctx, "%%");
|
||
scc_ir_node_t *param_node =
|
||
scc_ir_ctx_get_node(ctx->ir_ctx, param_ref);
|
||
if (param_node && param_node->name && param_node->name[0] != '\0') {
|
||
scc_snprintf(buff, sizeof(buff), "%u[%s]", param_ref,
|
||
param_node->name);
|
||
PRINT_NODE(ctx->dump_ctx, buff);
|
||
} else {
|
||
scc_snprintf(buff, sizeof(buff), "%u", param_ref);
|
||
PRINT_NODE(ctx->dump_ctx, buff);
|
||
}
|
||
}
|
||
PRINT_NODE(ctx->dump_ctx, ")");
|
||
} else {
|
||
PRINT_NODE(ctx->dump_ctx, "()");
|
||
}
|
||
|
||
// 如果有返回类型
|
||
if (func->type != 0) {
|
||
PRINT_NODE(ctx->dump_ctx, " -> ");
|
||
scc_ir_dump_type_linear(ctx, func->type);
|
||
}
|
||
|
||
PRINT_NODE(ctx->dump_ctx, " {\n");
|
||
|
||
// 打印基本块
|
||
for (usize i = 0; i < scc_vec_size(func->bblocks); i++) {
|
||
scc_ir_bblock_ref_t bblock_ref = scc_vec_at(func->bblocks, i);
|
||
scc_ir_dump_bblock_linear(ctx, bblock_ref);
|
||
PRINT_NODE(ctx->dump_ctx, "\n");
|
||
}
|
||
|
||
PRINT_NODE(ctx->dump_ctx, "}\n");
|
||
}
|
||
|
||
// 线性输出整个程序
|
||
void scc_ir_dump_cprog_linear(scc_ir_dump_ctx_t *ctx) {
|
||
scc_vec_foreach(ctx->cprog->func_defs, i) {
|
||
scc_ir_dump_func_linear(ctx, scc_vec_at(ctx->cprog->func_defs, i));
|
||
}
|
||
}
|