Files
scc/libs/ir/hir/src/scc_hir_dump.c
zzy 0acea43e4e feat(argparse): 支持列表类型参数解析
当参数指定为列表类型时,验证和处理逻辑现在会检查
vec_store 是否为空或大小为0,而不是检查 str_store。

fix(hir): 初始化聚合类型值的数据结构

在 HIR 值初始化过程中,为聚合类型添加适当的初始化逻辑,
确保其字段向量被正确初始化。

refactor(hir_builder): 优化指针类型创建和GEP操作实现

- 简化全局分配器中的指针类型创建代码
- 扩展 GEP 操作以支持结构体和联合体字段访问
- 添加字段偏移计算支持

feat(hir_dump): 增强HIR类型和值的线性转储功能

- 实现类型定义的线性转储输出
- 改进结构体和联合体的转储格式
- 优化聚合值的转储表示

perf(hir_layout): 优化类型布局计算性能

改进结构体、联合体和聚合类型的对齐和大小计算算法,
提高字段偏移计算的准确性。

fix(hir_module): 完善模块资源清理机制

在模块析构时正确释放结构体和联合体类型的字段向量内存。

docs(lir): 更新文档注释中的空值表示

将初始化数据参数的空值描述从 NULL 统一为 nullptr。

refactor(hir2lir): 改进HIR到LIR的类型转换逻辑

- 重构类型到LIR大小扩展的转换函数
- 修复STORE指令的类型推导逻辑
- 增强GEP指令的规模因子和偏移量计算
- 添加对结构体/联合体字段访问的支持

refactor(x86_isel): 优化x86-64地址加载指令生成

改进LOAD_ADDR指令生成,更好地支持结构体字段访问的零比例因子。

docs(ir2mcode): 统一空值表示文档注释

更新初始化数据参数的空值描述为nullptr。

refactor(lexer): 简化词法分析器非空白标记预览逻辑

优化非空白标记预览函数,减少不必要的标记消费和销毁操作。
2026-06-03 17:34:16 +08:00

483 lines
19 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.
#include <scc_hir_dump.h>
#include <scc_hir_prog.h>
#include <scc_tree_dump.h>
#define GET_MODULE(ctx) (&(ctx->cprog->module))
void scc_hir_dump_init(scc_hir_dump_t *ctx, scc_tree_dump_t *td,
scc_hir_cprog_t *cprog) {
ctx->dump_ctx = td;
ctx->cprog = cprog;
}
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", [SCC_HIR_OP_ULT] = "u<",
[SCC_HIR_OP_ULE] = "u<=", [SCC_HIR_OP_UGT] = "u>",
[SCC_HIR_OP_UGE] = "u>=",
};
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 void dump_type_linear_with_visited(scc_hir_dump_t *ctx,
scc_hir_type_ref_t type_ref,
scc_hashtable_t *visited,
cbool extened) {
if (!ctx || !type_ref) {
LOG_ERROR("invalid parameter");
return;
}
// 检查循环
if (scc_hashtable_get(visited, (void *)(usize)type_ref)) {
extened = false;
}
scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref);
if (!type) {
LOG_ERROR("invalid type ref");
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, "[");
dump_type_linear_with_visited(ctx, type->data.array.base, visited,
extened);
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, "*");
dump_type_linear_with_visited(ctx, type->data.pointer.base, visited,
extened);
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, ", ");
dump_type_linear_with_visited(
ctx, scc_vec_at(type->data.function.params, i), visited,
extened);
}
if (type->data.function.ret_type) {
scc_tree_dump_append(ctx->dump_ctx, ") -> ");
dump_type_linear_with_visited(ctx, type->data.function.ret_type,
visited, extened);
} else {
scc_tree_dump_append(ctx->dump_ctx, ")");
}
break;
case SCC_HIR_TYPE_STRUCT:
case SCC_HIR_TYPE_UNION:
scc_hashtable_set(visited, (void *)(usize)type_ref, (void *)1);
const char *tag_name =
type->tag == SCC_HIR_TYPE_STRUCT ? "struct" : "union";
if (type->name) {
scc_tree_dump_append_fmt(ctx->dump_ctx, "%s %s {", tag_name,
type->name);
} else {
scc_tree_dump_append_fmt(ctx->dump_ctx, "%s T%u {", tag_name,
type_ref);
}
if (extened) {
for (usize i = 0; i < scc_vec_size(type->data.aggregate.fields);
i++) {
dump_type_linear_with_visited(
ctx, scc_vec_at(type->data.aggregate.fields, i), visited,
extened);
scc_tree_dump_append(ctx->dump_ctx, ";");
}
} else {
scc_tree_dump_append(ctx->dump_ctx, "...");
}
scc_tree_dump_append(ctx->dump_ctx, "}");
break;
default:
LOG_ERROR("invalid type tag");
break;
}
}
void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
scc_hir_type_ref_t type_ref) {
scc_hashtable_t visited;
scc_hashtable_usize_init(&visited);
dump_type_linear_with_visited(ctx, type_ref, &visited, false);
scc_hashtable_drop(&visited);
}
static void scc_hir_dump_types_linear(scc_hir_dump_t *ctx) {
scc_hir_module_t *module = GET_MODULE(ctx);
// 遍历所有类型跳过索引0保留给无效引用
for (usize i = 1; i < scc_vec_size(module->types); i++) {
scc_hir_type_t *type = &module->types.data[i];
if (type->tag == SCC_HIR_TYPE_unknown)
continue;
scc_hashtable_t visited;
scc_hashtable_usize_init(&visited);
scc_tree_dump_begin_line(ctx->dump_ctx);
scc_tree_dump_node(ctx->dump_ctx, "T%u", (unsigned)i);
scc_tree_dump_append(ctx->dump_ctx, " = ");
dump_type_linear_with_visited(ctx, (scc_hir_type_ref_t)i, &visited,
true);
scc_hashtable_drop(&visited);
}
}
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;
}
if (value->tag == SCC_HIR_VALUE_TAG_INTEGER) {
// FIXME hack ap
scc_tree_dump_append_fmt(ctx->dump_ctx, "%d",
value->data.integer.data.digit);
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_tree_dump_append(ctx->dump_ctx, "{");
if (scc_vec_size(value->data.aggregate.fields) > 0) {
scc_tree_dump_push(ctx->dump_ctx, true);
scc_vec_foreach(value->data.aggregate.fields, i) {
scc_tree_dump_begin_line(ctx->dump_ctx);
scc_hir_dump_value_linear(
ctx, scc_vec_at(value->data.aggregate.fields, i));
}
scc_tree_dump_pop(ctx->dump_ctx);
scc_tree_dump_begin_line(ctx->dump_ctx);
}
scc_tree_dump_append(ctx->dump_ctx, "}");
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.func_ref);
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_tree_dump_append(ctx->dump_ctx, " ");
if (value->data.global_alloc.value) {
scc_hir_dump_value_linear(ctx, value->data.global_alloc.value);
} else {
scc_tree_dump_append(ctx->dump_ctx, "<zero initializer>");
}
break;
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;
case SCC_HIR_VALUE_TAG_CONV:
static const char *conv_name[] = {
[SCC_HIR_CONV_NONE] = "null",
[SCC_HIR_CONV_SEXT] = "sext",
[SCC_HIR_CONV_ZEXT] = "zext",
[SCC_HIR_CONV_TRUNC] = "trunc",
};
scc_tree_dump_append_fmt(ctx->dump_ctx, "conv.%s(",
conv_name[value->data.conv.conv_type]);
scc_hir_dump_type_linear(ctx, value->data.conv.target_type);
scc_tree_dump_append(ctx->dump_ctx, ") ");
format_ref_or_value(ctx, value->data.conv.operand);
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);
scc_hir_value_ref_vec_t *values = SCC_HIR_BBLOCK_VALUES(bblock);
for (usize i = 0; i < scc_vec_size(*values); 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(*values, 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_node(ctx->dump_ctx, "func @%s",
(func->name && func->name[0]) ? func->name
: "<unnamed>");
if (SCC_HIR_FUNC_META(func)->is_variadic) {
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) {
scc_hir_dump_types_linear(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);
}
}