feat(ast2ir): 实现C11类型提升系统并重构HIR基本块管理

- 新增 scc_ast2ir_promote.c 实现整数提升(6.3.1.1)和寻常算术转换(6.3.1.8)
- 重构 HIR Builder: bblock → create_bblock + append_bblock,引入BBList链表管理
- AST2IR 全面集成类型提升:二元运算、赋值、函数调用参数、自增/自减操作符
- 变参函数支持:跳过 ... 假参数,实现默认参数提升(float→double等)
- 简化 HIR Dump 实现
- MIR: Win64 ABI改进、x86指令选择优化
- 新增 printf 测试用例
This commit is contained in:
zzy
2026-05-24 15:46:22 +08:00
parent ea553718f0
commit cec96333e7
27 changed files with 1223 additions and 740 deletions

View File

@@ -3,9 +3,13 @@
#include <scc_tree_dump.h>
#define GET_MODULE(ctx) (&(ctx->cprog->module))
static void dump_type_with_visited(scc_hir_dump_t *ctx,
scc_hir_type_ref_t type_ref,
scc_hashtable_t *visited);
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",
@@ -71,337 +75,6 @@ static const char *get_type_tag_str(scc_hir_type_tag_t 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.func_ref) {
scc_hir_func_t *callee = scc_hir_module_get_func(
GET_MODULE(ctx), value->data.call.callee.func_ref);
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_init(scc_hir_dump_t *ctx, scc_tree_dump_t *td,
scc_hir_cprog_t *cprog) {
ctx->dump_ctx = td;
ctx->cprog = cprog;
}
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) {
scc_hashtable_t visited;
scc_hashtable_usize_init(&visited);
dump_type_with_visited(ctx, type_ref, &visited);
scc_hashtable_drop(&visited);
}
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");
scc_hir_value_ref_vec_t *values = SCC_HIR_BBLOCK_VALUES(bblock);
scc_vec_foreach(*values, i) {
cbool is_last = (i + 1 == scc_vec_size(*values));
scc_tree_dump_push(ctx->dump_ctx, is_last);
scc_hir_dump_value(ctx, scc_vec_at(*values, 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-----
// 在 scc_hir_dump.c 中添加以下静态辅助函数(放在文件前部,现有函数之前)
static void dump_type_linear_with_visited(scc_hir_dump_t *ctx,
scc_hir_type_ref_t type_ref,
scc_hashtable_t *visited);
static void dump_type_with_visited(scc_hir_dump_t *ctx,
scc_hir_type_ref_t type_ref,
scc_hashtable_t *visited) {
if (!ctx || !type_ref) {
LOG_ERROR("invalid parameter");
return;
}
// 检查循环
if (scc_hashtable_get(visited, (void *)(usize)type_ref)) {
scc_tree_dump_append(ctx->dump_ctx, " <recursive>");
return;
}
scc_hashtable_set(visited, (void *)(usize)type_ref, (void *)1);
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);
dump_type_with_visited(ctx, type->data.pointer.base, visited);
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);
dump_type_with_visited(ctx, type->data.array.base, visited);
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);
dump_type_with_visited(
ctx, scc_vec_at(type->data.function.params, i), visited);
scc_tree_dump_pop(ctx->dump_ctx);
}
if (type->data.function.ret_type) {
scc_tree_dump_push(ctx->dump_ctx, true);
dump_type_with_visited(ctx, type->data.function.ret_type, visited);
scc_tree_dump_pop(ctx->dump_ctx);
}
break;
default:
break;
}
}
static void dump_type_linear_with_visited(scc_hir_dump_t *ctx,
scc_hir_type_ref_t type_ref,
scc_hashtable_t *visited) {
@@ -653,7 +326,7 @@ void scc_hir_dump_value_linear(scc_hir_dump_t *ctx,
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;
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);
@@ -664,6 +337,19 @@ void scc_hir_dump_value_linear(scc_hir_dump_t *ctx,
}
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);
@@ -706,24 +392,8 @@ void scc_hir_dump_func_linear(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref,
(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, ")");
if (SCC_HIR_FUNC_META(func)->is_variadic) {
scc_tree_dump_append(ctx->dump_ctx, "(...)");
} else {
scc_tree_dump_append(ctx->dump_ctx, "()");
}