feat(ir): 添加线性IR转储功能并改进AST转储
- 实现了IR的线性转储功能,包括类型、节点、基本块和函数的线性表示 - 添加了scc_ir_dump_ctx_init函数用于初始化转储上下文 - 为AST函数类型添加了变参标记注释说明 - 改进了AST转储中函数类型的参数和返回值显示逻辑 - 统一了AST解析中节点类型的声明为通用的scc_ast_node_t指针类型 fix(lexer): 改进词法分析器错误信息显示 - 在不支持字符的错误信息中添加十六进制编码显示 - 便于调试时识别特殊不可打印字符
This commit is contained in:
@@ -238,6 +238,14 @@ static void dump_ret_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -304,32 +312,6 @@ void scc_ir_dump_node(scc_ir_dump_ctx_t *ctx, scc_ir_node_ref_t node_ref) {
|
||||
|
||||
// 转储类型信息
|
||||
void scc_ir_dump_type(scc_ir_dump_ctx_t *ctx, scc_ir_type_ref_t type_ref) {
|
||||
// impl fmt::Display for TypeKind {
|
||||
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// match self {
|
||||
// TypeKind::Int32 => write!(f, "i32"),
|
||||
// TypeKind::Unit => write!(f, "unit"),
|
||||
// TypeKind::Array(t, len) => write!(f, "[{}, {}]", t, len),
|
||||
// TypeKind::Pointer(t) => write!(f, "*{}", t),
|
||||
// TypeKind::Function(params, ret) => {
|
||||
// write!(f, "(")?;
|
||||
// let mut first = true;
|
||||
// for param in params {
|
||||
// if !first {
|
||||
// write!(f, ", ")?;
|
||||
// }
|
||||
// write!(f, "{}", param)?;
|
||||
// first = false;
|
||||
// }
|
||||
// if !ret.is_unit() {
|
||||
// write!(f, "): {}", ret)
|
||||
// } else {
|
||||
// write!(f, ")")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (!ctx || !type_ref) {
|
||||
LOG_ERROR("invalid parameter");
|
||||
return;
|
||||
@@ -520,3 +502,324 @@ void scc_ir_dump_cprog(scc_ir_dump_ctx_t *ctx) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user