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:
@@ -143,6 +143,17 @@ scc_hir_builder_integer(scc_hir_builder_t *builder, scc_hir_type_ref_t type,
|
||||
scc_hir_value_ref_t scc_hir_builder_const_string(scc_hir_builder_t *builder,
|
||||
const char *str, usize len);
|
||||
|
||||
/**
|
||||
* @brief 创建类型转换指令(SEXT/ZEXT/TRUNC)
|
||||
* @param operand 被转换的值
|
||||
* @param target_type 目标类型
|
||||
* @param conv_kind 转换种类(SCC_HIR_CONV_SEXT/ZEXT/TRUNC)
|
||||
*/
|
||||
scc_hir_value_ref_t scc_hir_builder_conv(scc_hir_builder_t *builder,
|
||||
scc_hir_value_ref_t operand,
|
||||
scc_hir_type_ref_t target_type,
|
||||
int conv_kind);
|
||||
|
||||
/**
|
||||
* @brief 开始构建函数
|
||||
* @param func_ref 函数引用
|
||||
@@ -171,6 +182,21 @@ scc_hir_func_ref_t scc_hir_builder_current_func(scc_hir_builder_t *builder);
|
||||
scc_hir_bblock_ref_t scc_hir_builder_bblock(scc_hir_builder_t *builder,
|
||||
const char *label);
|
||||
|
||||
/**
|
||||
* @brief 创建一个新的基本块(仅分配对象,不添加到当前函数的基本块列表)
|
||||
* @param label 基本块标签(可为 nullptr)
|
||||
* @return 基本块引用(真实 ID)
|
||||
*/
|
||||
scc_hir_bblock_ref_t scc_hir_builder_create_bblock(scc_hir_builder_t *builder,
|
||||
const char *label);
|
||||
|
||||
/**
|
||||
* @brief 将指定基本块追加到当前函数的基本块列表末尾
|
||||
* @param bblock 基本块引用
|
||||
*/
|
||||
void scc_hir_builder_append_bblock(scc_hir_builder_t *builder,
|
||||
scc_hir_bblock_ref_t bblock);
|
||||
|
||||
/**
|
||||
* @brief 开始构建新的基本块
|
||||
* @param label 基本块标签(可为nullptr,自动生成)
|
||||
|
||||
@@ -176,6 +176,13 @@ typedef struct {
|
||||
} func;
|
||||
} scc_hir_builtin_t;
|
||||
|
||||
typedef enum {
|
||||
SCC_HIR_CONV_NONE,
|
||||
SCC_HIR_CONV_SEXT,
|
||||
SCC_HIR_CONV_ZEXT,
|
||||
SCC_HIR_CONV_TRUNC,
|
||||
} scc_hir_conv_type_t;
|
||||
|
||||
struct scc_hir_value {
|
||||
scc_hir_type_ref_t type;
|
||||
const char *name;
|
||||
@@ -199,9 +206,9 @@ struct scc_hir_value {
|
||||
scc_hir_value_ref_t value;
|
||||
} global_alloc;
|
||||
struct {
|
||||
scc_hir_value_ref_t operand;
|
||||
scc_hir_value_ref_t operand; // 原始类型
|
||||
scc_hir_type_ref_t target_type; // 目标类型
|
||||
enum { CONV_SEXT, CONV_ZEXT, CONV_TRUNC } conv_type;
|
||||
scc_hir_conv_type_t conv_type;
|
||||
} conv;
|
||||
struct {
|
||||
scc_hir_value_ref_t target;
|
||||
@@ -250,6 +257,7 @@ typedef struct scc_hir_func_meta {
|
||||
scc_hir_type_ref_t type;
|
||||
scc_hir_value_ref_vec_t params;
|
||||
int defined;
|
||||
cbool is_variadic;
|
||||
} scc_hir_func_meta_t;
|
||||
|
||||
#define SCC_HIR_BBLOCK_VALUES(bblock) \
|
||||
|
||||
@@ -11,11 +11,6 @@ typedef struct {
|
||||
|
||||
void scc_hir_dump_init(scc_hir_dump_t *ctx, scc_tree_dump_t *tree_dump,
|
||||
scc_hir_cprog_t *cprog);
|
||||
void scc_hir_dump_value(scc_hir_dump_t *ctx, scc_hir_value_ref_t node_ref);
|
||||
void scc_hir_dump_type(scc_hir_dump_t *ctx, scc_hir_type_ref_t type_ref);
|
||||
void scc_hir_dump_bblock(scc_hir_dump_t *ctx, scc_hir_bblock_ref_t bblock_ref);
|
||||
void scc_hir_dump_func(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref);
|
||||
void scc_hir_dump_cprog(scc_hir_dump_t *ctx);
|
||||
void scc_hir_dump_cprog_linear(scc_hir_dump_t *ctx);
|
||||
|
||||
#endif /* __SCC_HIR_DUMP_H__ */
|
||||
|
||||
@@ -56,6 +56,8 @@ void scc_hir_func_init(scc_hir_func_t *in, const char *name) {
|
||||
in->name = name;
|
||||
scc_hir_func_meta_t *meta = SCC_HIR_FUNC_META(in);
|
||||
meta->type = SCC_HIR_REF_nullptr;
|
||||
meta->is_variadic = false;
|
||||
meta->defined = false;
|
||||
scc_vec_init(in->bblocks);
|
||||
scc_vec_init(meta->params);
|
||||
}
|
||||
@@ -110,6 +112,11 @@ void scc_hir_value_init(scc_hir_value_t *in, const char *name,
|
||||
case SCC_HIR_VALUE_TAG_RET:
|
||||
in->data.ret.ret_val = 0;
|
||||
break;
|
||||
case SCC_HIR_VALUE_TAG_CONV:
|
||||
in->data.conv.conv_type = SCC_HIR_CONV_NONE;
|
||||
in->data.conv.operand = 0;
|
||||
in->data.conv.target_type = 0;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
|
||||
@@ -188,7 +188,6 @@ scc_hir_func_ref_t scc_hir_builder_func(scc_hir_builder_t *builder,
|
||||
// 创建新函数
|
||||
scc_hir_func_t func;
|
||||
scc_hir_func_meta_t *meta = scc_malloc(sizeof(scc_hir_func_meta_t));
|
||||
meta->defined = 0;
|
||||
Assert(meta != nullptr);
|
||||
func.meta = meta;
|
||||
scc_hir_func_init(&func, name);
|
||||
@@ -231,6 +230,37 @@ scc_hir_bblock_ref_t scc_hir_builder_bblock(scc_hir_builder_t *builder,
|
||||
return bblock_ref;
|
||||
}
|
||||
|
||||
scc_hir_bblock_ref_t scc_hir_builder_create_bblock(scc_hir_builder_t *builder,
|
||||
const char *label) {
|
||||
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
||||
scc_hir_bblock_t bblock = {0};
|
||||
if (label) {
|
||||
bblock.name = label;
|
||||
}
|
||||
bblock.meta = nullptr;
|
||||
scc_vec_init(*SCC_HIR_BBLOCK_VALUES(&bblock));
|
||||
// 直接添加到模块,获得真实 ID,但不挂载到当前函数
|
||||
return scc_hir_module_add_bblock(scc_hir_builder_get_module(builder),
|
||||
&bblock);
|
||||
}
|
||||
|
||||
void scc_hir_builder_append_bblock(scc_hir_builder_t *builder,
|
||||
scc_hir_bblock_ref_t bblock) {
|
||||
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
||||
scc_hir_func_t *func = scc_hir_module_get_func(
|
||||
scc_hir_builder_get_module(builder), builder->current_func);
|
||||
if (!func) {
|
||||
LOG_ERROR("No current function");
|
||||
return;
|
||||
}
|
||||
// FIXME 检查是否已经挂载过(可选,防止重复挂载)
|
||||
for (usize i = 0; i < func->bblocks.size; i++) {
|
||||
if (func->bblocks.data[i] == bblock)
|
||||
return;
|
||||
}
|
||||
scc_vec_push(func->bblocks, bblock);
|
||||
}
|
||||
|
||||
scc_hir_type_ref_t scc_hir_builder_type(scc_hir_builder_t *builder,
|
||||
const scc_hir_type_t *type_desc) {
|
||||
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
||||
@@ -270,15 +300,55 @@ scc_hir_value_ref_t scc_hir_builder_const_string(scc_hir_builder_t *builder,
|
||||
.type = array_type_ref,
|
||||
.data.const_array.base_type = u8_type,
|
||||
};
|
||||
char *buff = scc_malloc(len - 1);
|
||||
Assert(buff);
|
||||
scc_str_t buf;
|
||||
scc_str_init(&buf);
|
||||
// FIXME content to real string
|
||||
for (usize i = 1; i < len - 1; i++) {
|
||||
buff[i - 1] = str[i];
|
||||
if (str[i] != '\\') {
|
||||
scc_str_append_ch(&buf, str[i]);
|
||||
} else {
|
||||
if (i + 1 < len) {
|
||||
i += 1;
|
||||
switch (str[i]) {
|
||||
case 'a':
|
||||
scc_str_append_ch(&buf, '\a');
|
||||
break;
|
||||
case 'b':
|
||||
scc_str_append_ch(&buf, '\b');
|
||||
break;
|
||||
case 'f':
|
||||
scc_str_append_ch(&buf, '\f');
|
||||
break;
|
||||
case 'n':
|
||||
scc_str_append_ch(&buf, '\n');
|
||||
break;
|
||||
case 't':
|
||||
scc_str_append_ch(&buf, '\t');
|
||||
break;
|
||||
case 'r':
|
||||
scc_str_append_ch(&buf, '\r');
|
||||
break;
|
||||
case '\\':
|
||||
scc_str_append_ch(&buf, '\\');
|
||||
break;
|
||||
case '"':
|
||||
scc_str_append_ch(&buf, '"');
|
||||
break;
|
||||
default:
|
||||
LOG_WARN("Unknown escape sequence: \\%c", str[i]);
|
||||
scc_str_append_ch(&buf, str[i]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
scc_str_append_ch(&buf, '\\');
|
||||
LOG_ERROR("invalid escape character");
|
||||
}
|
||||
}
|
||||
}
|
||||
buff[len - 2] = '\0';
|
||||
scc_str_append_ch(&buf, '\0');
|
||||
usize buf_len = scc_str_len(&buf);
|
||||
scc_vec_unsafe_from_buffer(const_array_value.data.const_array.fields,
|
||||
(u8 *)buff, len - 1);
|
||||
(u8 *)scc_str_move_cstr(&buf), buf_len);
|
||||
scc_hir_value_ref_t const_array_ref =
|
||||
scc_hir_module_add_value(GET_MODULE(builder), &const_array_value);
|
||||
Assert(const_array_ref != SCC_HIR_REF_nullptr);
|
||||
@@ -293,6 +363,23 @@ scc_hir_value_ref_t scc_hir_builder_const_string(scc_hir_builder_t *builder,
|
||||
return pointer_to_global_value;
|
||||
}
|
||||
|
||||
scc_hir_value_ref_t scc_hir_builder_conv(scc_hir_builder_t *builder,
|
||||
scc_hir_value_ref_t operand,
|
||||
scc_hir_type_ref_t target_type,
|
||||
int conv_kind) {
|
||||
Assert(builder != nullptr);
|
||||
scc_hir_value_t value;
|
||||
scc_hir_value_init(&value, nullptr, SCC_HIR_VALUE_TAG_CONV);
|
||||
value.type = target_type;
|
||||
value.data.conv.operand = operand;
|
||||
value.data.conv.target_type = target_type;
|
||||
value.data.conv.conv_type = conv_kind;
|
||||
scc_hir_value_ref_t ref =
|
||||
scc_hir_module_add_value(&builder->cprog->module, &value);
|
||||
scc_hir_builder_add_instr(builder, ref);
|
||||
return ref;
|
||||
}
|
||||
|
||||
void scc_hir_builder_begin_func(scc_hir_builder_t *builder,
|
||||
scc_hir_func_ref_t func_ref) {
|
||||
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
||||
|
||||
@@ -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, "()");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user