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

@@ -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自动生成

View File

@@ -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) \

View File

@@ -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__ */

View File

@@ -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;

View File

@@ -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);

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, "()");
}

View File

@@ -135,6 +135,9 @@ typedef enum {
/* 栈管理 */
SCC_LIR_ALLOCA,
/* 类型扩展 */
SCC_LIR_EXTEND,
SCC_LIR_NOP
} scc_lir_op_t;
@@ -208,6 +211,10 @@ typedef struct scc_lir_ins {
int align_bytes;
} alloca;
struct scc_lir_extend {
int from_size; // 源类型宽度(字节)
} extend;
struct {
scc_lir_val_t ap;
scc_lir_val_t last;

View File

@@ -428,21 +428,37 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value,
scc_lir_builder_add_instr(ctx, &instr);
} break;
case SCC_HIR_VALUE_TAG_CONV: {
// 类型转换:使用 MOV 指令配合扩展/截断
// 类型转换:使用 LIR_EXTEND 指令实现符号/零扩展
scc_lir_val_t src =
ir_value_to_lir_operand(ctx, value->data.conv.operand);
scc_lir_ext_t conv_ext = SCC_LIR_EXT_NONE;
if (value->data.conv.conv_type == CONV_SEXT)
if (value->data.conv.conv_type == SCC_HIR_CONV_SEXT)
conv_ext = SCC_LIR_EXT_SEXT;
else if (value->data.conv.conv_type == CONV_ZEXT)
else if (value->data.conv.conv_type == SCC_HIR_CONV_ZEXT)
conv_ext = SCC_LIR_EXT_ZEXT;
// TRUNC 用 NONE 即可(MOV 截断
scc_lir_instr_t instr = {.op = SCC_LIR_MOV,
.size = size,
.ext = conv_ext,
.to = SCC_LIR_VREG(dst_vreg),
.arg0 = src};
scc_lir_builder_add_instr(ctx, &instr);
// TRUNC 用 SCC_LIR_MOV 截断
if (value->data.conv.conv_type == SCC_HIR_CONV_TRUNC) {
scc_lir_instr_t instr = {.op = SCC_LIR_MOV,
.size = size,
.to = SCC_LIR_VREG(dst_vreg),
.arg0 = src};
scc_lir_builder_add_instr(ctx, &instr);
} else {
// 计算源类型宽度
scc_hir_type_t *src_type = scc_hir_module_get_type(
ctx->hir_module,
scc_hir_module_get_value(ctx->hir_module,
value->data.conv.operand)
->type);
int from_size = scc_hir_module_type_size(ctx->hir_module, src_type);
scc_lir_instr_t instr = {.op = SCC_LIR_EXTEND,
.size = size,
.ext = conv_ext,
.to = SCC_LIR_VREG(dst_vreg),
.arg0 = src,
.metadata.extend.from_size = from_size};
scc_lir_builder_add_instr(ctx, &instr);
}
} break;
case SCC_HIR_VALUE_TAG_BUILTIN: {
scc_hir_builtin_t *b = &value->data.builtin;
@@ -542,7 +558,7 @@ static void translate_func(ir2lir_ctx_t *ctx, scc_hir_func_t *ir_func) {
.attr = SCC_LIR_ATTR_NONE,
.frame_size = 0,
.vregs_count = 0,
.is_va_arg = false,
.is_va_arg = func_meta->is_variadic,
};
scc_vec_push(ctx->lir_module->func_metas, lir_func_meta);
ctx->current_func = ir_func;

View File

@@ -7,134 +7,65 @@
#include <scc_core.h>
static const char *op_to_string(scc_lir_op_t op) {
switch (op) {
case SCC_LIR_MOV:
return "mov";
case SCC_LIR_LOAD:
return "load";
case SCC_LIR_LOAD_ADDR:
return "load.addr";
case SCC_LIR_STORE:
return "store";
// case SCC_LIR_STORE_ADDR:
// return "store.addr";
case SCC_LIR_ADD:
return "add";
case SCC_LIR_SUB:
return "sub";
case SCC_LIR_MUL:
return "mul";
case SCC_LIR_DIV_S:
return "div.s";
case SCC_LIR_DIV_U:
return "div.u";
case SCC_LIR_REM_S:
return "rem.s";
case SCC_LIR_REM_U:
return "rem.u";
case SCC_LIR_AND:
return "and";
case SCC_LIR_OR:
return "or";
case SCC_LIR_XOR:
return "xor";
case SCC_LIR_SHL:
return "shl";
case SCC_LIR_SHR:
return "shr";
case SCC_LIR_SAR:
return "sar";
case SCC_LIR_NEG:
return "neg";
case SCC_LIR_NOT:
return "not";
case SCC_LIR_FADD:
return "fadd";
case SCC_LIR_FSUB:
return "fsub";
case SCC_LIR_FMUL:
return "fmul";
case SCC_LIR_FDIV:
return "fdiv";
case SCC_LIR_FNEG:
return "fneg";
case SCC_LIR_FCVT:
return "fcvt";
case SCC_LIR_CMP:
return "cmp";
case SCC_LIR_BR:
return "br";
case SCC_LIR_JMP:
return "jmp";
case SCC_LIR_JMP_INDIRECT:
return "jmp.indirect";
case SCC_LIR_CALL:
return "call";
case SCC_LIR_CALL_INDIRECT:
return "call.indirect";
case SCC_LIR_RET:
return "ret";
case SCC_LIR_PARALLEL_COPY:
return "parallel_copy";
case SCC_LIR_VA_START:
return "va_start";
case SCC_LIR_VA_ARG:
return "va_arg";
case SCC_LIR_VA_END:
return "va_end";
case SCC_LIR_VA_COPY:
return "va_copy";
case SCC_LIR_ALLOCA:
return "alloca";
case SCC_LIR_MEMCPY:
return "memcpy";
case SCC_LIR_MEMSET:
return "memset";
case SCC_LIR_NOP:
return "nop";
default:
return "???";
}
static const char *op_names[] = {
[SCC_LIR_MOV] = "mov",
[SCC_LIR_LOAD] = "load",
[SCC_LIR_LOAD_ADDR] = "load.addr",
[SCC_LIR_STORE] = "store",
[SCC_LIR_ADD] = "add",
[SCC_LIR_SUB] = "sub",
[SCC_LIR_MUL] = "mul",
[SCC_LIR_DIV_S] = "div.s",
[SCC_LIR_DIV_U] = "div.u",
[SCC_LIR_REM_S] = "rem.s",
[SCC_LIR_REM_U] = "rem.u",
[SCC_LIR_AND] = "and",
[SCC_LIR_OR] = "or",
[SCC_LIR_XOR] = "xor",
[SCC_LIR_SHL] = "shl",
[SCC_LIR_SHR] = "shr",
[SCC_LIR_SAR] = "sar",
[SCC_LIR_NEG] = "neg",
[SCC_LIR_NOT] = "not",
[SCC_LIR_FADD] = "fadd",
[SCC_LIR_FSUB] = "fsub",
[SCC_LIR_FMUL] = "fmul",
[SCC_LIR_FDIV] = "fdiv",
[SCC_LIR_FNEG] = "fneg",
[SCC_LIR_FCVT] = "fcvt",
[SCC_LIR_CMP] = "cmp",
[SCC_LIR_BR] = "br",
[SCC_LIR_JMP] = "jmp",
[SCC_LIR_JMP_INDIRECT] = "jmp.indirect",
[SCC_LIR_CALL] = "call",
[SCC_LIR_CALL_INDIRECT] = "call.indirect",
[SCC_LIR_RET] = "ret",
[SCC_LIR_PARALLEL_COPY] = "parallel_copy",
[SCC_LIR_VA_START] = "va_start",
[SCC_LIR_VA_ARG] = "va_arg",
[SCC_LIR_VA_END] = "va_end",
[SCC_LIR_VA_COPY] = "va_copy",
[SCC_LIR_ALLOCA] = "alloca",
[SCC_LIR_EXTEND] = "extend",
[SCC_LIR_MEMCPY] = "memcpy",
[SCC_LIR_MEMSET] = "memset",
[SCC_LIR_NOP] = "nop",
};
return op_names[op];
}
static const char *cond_to_string(scc_lir_cond_t cond) {
switch (cond) {
case SCC_LIR_COND_EQ:
return "eq";
case SCC_LIR_COND_NE:
return "ne";
case SCC_LIR_COND_SLT:
return "slt";
case SCC_LIR_COND_SLE:
return "sle";
case SCC_LIR_COND_SGT:
return "sgt";
case SCC_LIR_COND_SGE:
return "sge";
case SCC_LIR_COND_ULT:
return "ult";
case SCC_LIR_COND_ULE:
return "ule";
case SCC_LIR_COND_UGT:
return "ugt";
case SCC_LIR_COND_UGE:
return "uge";
case SCC_LIR_COND_FEQ:
return "feq";
case SCC_LIR_COND_FNE:
return "fne";
case SCC_LIR_COND_FLT:
return "flt";
case SCC_LIR_COND_FLE:
return "fle";
case SCC_LIR_COND_FGT:
return "fgt";
case SCC_LIR_COND_FGE:
return "fge";
default:
return "???";
}
static const char *names[] = {
[SCC_LIR_COND_EQ] = "eq", [SCC_LIR_COND_NE] = "ne",
[SCC_LIR_COND_SLT] = "slt", [SCC_LIR_COND_SLE] = "sle",
[SCC_LIR_COND_SGT] = "sgt", [SCC_LIR_COND_SGE] = "sge",
[SCC_LIR_COND_ULT] = "ult", [SCC_LIR_COND_ULE] = "ule",
[SCC_LIR_COND_UGT] = "ugt", [SCC_LIR_COND_UGE] = "uge",
[SCC_LIR_COND_FEQ] = "feq", [SCC_LIR_COND_FNE] = "fne",
[SCC_LIR_COND_FLT] = "flt", [SCC_LIR_COND_FLE] = "fle",
[SCC_LIR_COND_FGT] = "fgt", [SCC_LIR_COND_FGE] = "fge",
};
return names[cond];
}
static void dump_operand(scc_lir_dump_ctx_t *ctx, const scc_lir_val_t *op) {
@@ -150,9 +81,6 @@ static void dump_operand(scc_lir_dump_ctx_t *ctx, const scc_lir_val_t *op) {
case SCC_LIR_INSTR_KIND_VREG:
scc_tree_dump_append_fmt(td, "%%%u", op->data.reg);
break;
// case SCC_LIR_INSTR_KIND_PREG:
// scc_tree_dump_append_fmt(td, "Phy%u", op->data.reg);
// break;
case SCC_LIR_INSTR_KIND_IMM:
// TODO hack ap
scc_tree_dump_append_fmt(td, "%lld", op->data.imm.data.digit);
@@ -241,6 +169,26 @@ void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins) {
ins->metadata.alloca.align_bytes);
dump_operand(ctx, &ins->to);
break;
case SCC_LIR_EXTEND: {
const char *ext_name = "";
switch (ins->ext) {
case SCC_LIR_EXT_ZEXT:
ext_name = "zext";
break;
case SCC_LIR_EXT_SEXT:
ext_name = "sext";
break;
default:
ext_name = "ext";
break;
}
scc_tree_dump_append_fmt(td, "%s(%d<-%d) ", ext_name, ins->size * 8,
ins->metadata.extend.from_size * 8);
dump_operand(ctx, &ins->to);
scc_tree_dump_append(td, " <- ");
dump_operand(ctx, &ins->arg0);
break;
}
// case SCC_LIR_STORE_ADDR:
case SCC_LIR_STORE:
dump_operand(ctx, &ins->arg0);

View File

@@ -101,40 +101,6 @@ scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, scc_x86_iform_t opcode,
out->x86_instr.src_loc = pos;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_reg_mem(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_MEM);
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_MEMB
: SCC_X86_IFORM_MOV_GPRV_MEMV;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_mem_reg(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_MEM && op1.kind == SCC_X86_OPR_REG);
return op0.size == 1 ? SCC_X86_IFORM_MOV_MEMB_GPR8
: SCC_X86_IFORM_MOV_MEMV_GPRV;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_reg_reg(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_REG);
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_GPR8_8A
: SCC_X86_IFORM_MOV_GPRV_GPRV_8B;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_reg_imm(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_IMM);
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_IMMB_B0
: SCC_X86_IFORM_MOV_GPRV_IMMV;
}
void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
scc_x86_operand_value_t dst,
scc_x86_operand_value_t src);

View File

@@ -29,6 +29,7 @@ typedef struct scc_mir_stack_slot {
int size; // 通常是 8 字节 (指针大小)
int alignment; // 对齐要求
int offset; // 相对于 RSP 的偏移 (最终确定)
int arg_idx; // == 0 means local slot, > 0 means argument slot
} scc_mir_stack_slot_t;
typedef SCC_VEC(scc_mir_stack_slot_t) scc_mir_stack_slot_vec_t;

View File

@@ -8,7 +8,7 @@
void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering);
void scc_win_pc_x64_reg_alloc_fill(scc_reg_alloc_op_t *ops);
void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx);
void scc_win_pc_x64_frame_layout_init(scc_frame_layout_t *ctx);
void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx);
#endif

View File

@@ -47,9 +47,14 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_func_t *func,
if (slot == nullptr) {
scc_tree_dump_append_fmt(td, "[slot:%d<null>]", slot_id);
} else {
scc_tree_dump_append_fmt(td, "[slot:%d(of=%d,sz=%d,al=%d)]",
slot_id, slot->offset, slot->size,
slot->alignment);
if (slot->arg_idx > 0) {
scc_tree_dump_append_fmt(td, "[slot:arg%d]",
slot->arg_idx);
} else {
scc_tree_dump_append_fmt(
td, "[slot:%d(of=%d,sz=%d,al=%d)]", slot_id,
slot->offset, slot->size, slot->alignment);
}
}
} else {
scc_tree_dump_append(td, "(");
@@ -137,29 +142,6 @@ scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
return op;
}
static scc_x86_operand_value_t build_mem_op(scc_x86_64_isel_t *isel,
scc_x86_operand_value_t base,
scc_x86_operand_value_t index,
int scale, i64 offset) {
(void)isel;
scc_x86_operand_value_t mem_op;
mem_op.kind = SCC_X86_OPR_MEM;
// base 必须为寄存器
Assert(base.kind == SCC_X86_OPR_REG);
mem_op.mem.base = base.reg;
// index 可选
if (index.kind == SCC_X86_OPR_REG) {
mem_op.mem.index = index.reg;
mem_op.mem.scale = scale;
} else {
mem_op.mem.index = SCC_X86_REG_INVALID;
mem_op.mem.scale = 1;
}
mem_op.mem.disp.displacement = offset;
mem_op.mem.disp.displacement_bits = 0;
return mem_op;
}
// 虚拟临时寄存器分配(简单递增)
static scc_x86_operand_value_t new_vreg_temp(scc_x86_64_isel_t *isel,
int size) {
@@ -247,20 +229,21 @@ void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst_reg,
void scc_x86_emit_load(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
scc_x86_operand_value_t src) {
scc_x86_operand_value_t tmp_reg = dst;
if (dst.kind != SCC_X86_OPR_REG) {
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, dst.size);
scc_x86_emit_move(isel, tmp_reg, dst);
dst = tmp_reg;
tmp_reg = new_vreg_temp(isel, src.size);
}
scc_x86_emit_load_to_vec(&isel->instrs, tmp_reg, src);
if (dst.kind != SCC_X86_OPR_REG) {
scc_x86_emit_move(isel, dst, tmp_reg);
}
scc_x86_emit_load_to_vec(&isel->instrs, dst, src);
}
void scc_x86_emit_store(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
scc_x86_operand_value_t src) {
if (src.kind != SCC_X86_OPR_REG) {
if (src.kind == SCC_X86_OPR_MEM) {
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, src.size);
scc_x86_emit_move(isel, tmp_reg, src);
scc_x86_emit_load(isel, tmp_reg, src);
src = tmp_reg;
}
scc_x86_emit_store_to_vec(&isel->instrs, dst, src);
@@ -279,52 +262,55 @@ static void emit_load_addr(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
// ---- 处理 base ----
scc_x86_operand_value_t base_reg = base;
if (base.kind != SCC_X86_OPR_REG) {
base_reg = new_vreg_temp(isel, size);
switch (base.kind) {
case SCC_X86_OPR_REG: {
base_reg = base;
} break;
case SCC_X86_OPR_RELOC: {
Assert(base.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL);
base_reg = new_vreg_temp(isel, 8);
scc_x86_emit_move(isel, base_reg, base);
} break;
case SCC_X86_OPR_MEM: {
base_reg = new_vreg_temp(isel, 8);
scc_x86_emit_move(isel, base_reg, base);
} break;
default: {
Panic("Unsupported base kind %d in load_addr", base.kind);
}
}
// ---- 处理 index * scale ----
scc_x86_operand_value_t scaled_index = index;
Assert(index.kind != SCC_X86_OPR_NONE);
// 确保 index 在寄存器中
if (index.kind != SCC_X86_OPR_REG) {
scc_x86_operand_value_t index_tmp = new_vreg_temp(isel, index.size);
scc_x86_emit_move(isel, index_tmp, index);
index = index_tmp;
scc_x86_operand_value_t index_reg = index;
switch (index.kind) {
case SCC_X86_OPR_REG: {
index_reg = index;
} break;
case SCC_X86_OPR_RELOC: {
Assert(index.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL);
index_reg = new_vreg_temp(isel, 8);
scc_x86_emit_move(isel, index_reg, index);
} break;
case SCC_X86_OPR_MEM: {
index_reg = new_vreg_temp(isel, 8);
scc_x86_emit_move(isel, index_reg, index);
} break;
case SCC_X86_OPR_IMM: {
index_reg = new_vreg_temp(isel, index.size);
scc_x86_emit_move(isel, index_reg, index);
} break;
default: {
Panic("Unsupported index kind %d in load_addr", base.kind);
}
}
// ---- 计算 base + scaled_index ----
scc_x86_operand_value_t sum = base_reg;
if (base_reg.kind == SCC_X86_OPR_REG &&
scaled_index.kind == SCC_X86_OPR_REG) {
if (dst.reg != base_reg.reg) {
scc_x86_emit_move(isel, dst, base_reg);
sum = dst;
}
add_instr_2(isel, SCC_X86_IFORM_ADD_GPRV_GPRV_03, sum, scaled_index);
} else if (base_reg.kind == SCC_X86_OPR_REG) {
if (dst.reg != base_reg.reg)
scc_x86_emit_move(isel, dst, base_reg);
sum = dst;
} else if (scaled_index.kind == SCC_X86_OPR_REG) {
scc_x86_emit_move(isel, dst, scaled_index);
sum = dst;
} else {
// base 和 index 都无效 => 结果为 0
scc_x86_emit_move(isel, dst, scc_x86_op_imm(0, size));
return;
}
// ---- 加上 offset ----
if (offset != 0) {
scc_x86_operand_value_t mem_op = build_mem_op(
isel, sum, (scc_x86_operand_value_t){.kind = SCC_X86_OPR_NONE}, 1,
offset);
scc_x86_emit_move(isel, dst, mem_op);
} else if (sum.reg != dst.reg) {
scc_x86_emit_move(isel, dst, sum);
}
scc_x86_operand_value_t mem_op =
scc_x86_op_mem((scc_x86_mem_t){.base = base_reg.reg,
.index = index_reg.reg,
.scale = scale,
.disp.displacement = offset,
.disp.displacement_bits = 8},
size);
scc_x86_emit_move(isel, dst, mem_op);
}
static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
@@ -455,8 +441,9 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
case SCC_LIR_CMP: {
Assert(src0.size == src1.size);
if (scc_x86_op_is_vreg(&src0) && src1.kind == SCC_X86_OPR_IMM)
// SCC_X86_IFORM_CMP_GPR8_IMMB_82R7 历史遗留指令在amd64中已不再使用
add_instr_2(isel,
src0.size == 1 ? SCC_X86_IFORM_CMP_GPR8_IMMB_82R7
src0.size == 1 ? SCC_X86_IFORM_CMP_GPR8_IMMB_80R7
: SCC_X86_IFORM_CMP_GPRV_IMMZ,
src0, src1);
else if (scc_x86_op_is_vreg(&src0) && scc_x86_op_is_vreg(&src1))
@@ -519,6 +506,44 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
break;
}
/* ---- 类型扩展 ---- */
case SCC_LIR_EXTEND: {
int from_size = instr->metadata.extend.from_size;
scc_x86_operand_value_t ext_src =
scc_x86_lir_val_to_mir_op(isel, &instr->arg0, from_size);
if (instr->ext == SCC_LIR_EXT_ZEXT) {
if (from_size == 4) {
// 32→64: x86-64 写32位寄存器自动零扩展到64位
scc_x86_emit_move(isel, dst, ext_src);
} else {
scc_x86_iform_t iform = (from_size == 1)
? SCC_X86_IFORM_MOVZX_GPRV_GPR8
: SCC_X86_IFORM_MOVZX_GPRV_GPR16;
add_instr_2(isel, iform, dst, ext_src);
}
} else if (instr->ext == SCC_LIR_EXT_SEXT) {
scc_x86_iform_t iform;
switch (from_size) {
case 1:
iform = SCC_X86_IFORM_MOVSX_GPRV_GPR8;
break;
case 2:
iform = SCC_X86_IFORM_MOVSX_GPRV_GPR16;
break;
case 4:
iform = SCC_X86_IFORM_MOVSXD_GPRV_GPRZ;
break;
default:
UNREACHABLE();
}
add_instr_2(isel, iform, dst, ext_src);
} else {
UNREACHABLE();
}
break;
}
/* ---- 其他(占位) ---- */
case SCC_LIR_NOP:
add_instr_0(isel, SCC_X86_IFORM_NOP_90);
@@ -575,11 +600,10 @@ static void sel_func(const scc_lir_module_t *lir_module,
scc_cfg_module_unsafe_get_bblock(&lir_module->cfg_module, id);
scc_lir_instr_vec_t *instrs = SCC_LIR_BBLOCK_VALUES(bb);
scc_vec_foreach(*instrs, i) {
const scc_lir_instr_t *ins = &scc_vec_at(*instrs, i);
scc_lir_instr_t *ins = &scc_vec_at(*instrs, i);
// HACK BR size
if (ins->op == SCC_LIR_CMP && i + 1 < scc_vec_size(*instrs) &&
scc_vec_at(*instrs, i + 1).op == SCC_LIR_BR) {
scc_vec_at(*instrs, i + 1).size = ins->size;
if (ins->op == SCC_LIR_BR) {
ins->size = scc_vec_at(*instrs, i - 1).size;
}
sel_mir(isel, ins);
}

View File

@@ -1,5 +1,47 @@
#include <arch/scc_x86_mir.h>
static inline scc_x86_iform_t
scc_mir_x86_mov_reg_mem(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_MEM);
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_MEMB
: SCC_X86_IFORM_MOV_GPRV_MEMV;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_reg_reg(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_REG);
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_GPR8_8A
: SCC_X86_IFORM_MOV_GPRV_GPRV_8B;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_reg_imm(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_IMM);
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_IMMB_B0
: SCC_X86_IFORM_MOV_GPRV_IMMV;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_mem_reg(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_MEM && op1.kind == SCC_X86_OPR_REG);
return op0.size == 1 ? SCC_X86_IFORM_MOV_MEMB_GPR8
: SCC_X86_IFORM_MOV_MEMV_GPRV;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_mem_imm(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_MEM && op1.kind == SCC_X86_OPR_IMM);
return op0.size == 1 ? SCC_X86_IFORM_MOV_MEMB_IMMB
: SCC_X86_IFORM_MOV_MEMV_IMMZ;
}
void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
scc_x86_operand_value_t dst,
scc_x86_operand_value_t src) {
@@ -7,21 +49,35 @@ void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
LOG_WARN("Mismatched register sizes for move %d != %d", dst.size,
src.size);
}
Assert(dst.kind == SCC_X86_OPR_REG);
scc_mir_x86_instr_t ins;
if (src.kind == SCC_X86_OPR_REG) {
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_reg(dst, src), dst, src,
scc_pos_create());
} else if (src.kind == SCC_X86_OPR_IMM) {
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_imm(dst, src), dst, src,
scc_pos_create());
} else if (src.kind == SCC_X86_OPR_MEM ||
(src.kind == SCC_X86_OPR_RELOC &&
src.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL)) {
scc_mir_x86_instr_2(&ins, SCC_X86_IFORM_LEA_GPRV_AGEN, dst, src,
scc_pos_create());
if (dst.kind == SCC_X86_OPR_REG) {
if (src.kind == SCC_X86_OPR_REG) {
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_reg(dst, src), dst,
src, scc_pos_create());
} else if (src.kind == SCC_X86_OPR_IMM) {
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_imm(dst, src), dst,
src, scc_pos_create());
} else if (src.kind == SCC_X86_OPR_MEM ||
(src.kind == SCC_X86_OPR_RELOC &&
src.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL)) {
Assert(dst.size == 8);
scc_mir_x86_instr_2(&ins, SCC_X86_IFORM_LEA_GPRV_AGEN, dst, src,
scc_pos_create());
} else {
Panic("emit_move: unsupported src kind %d", src.kind);
}
} else if (dst.kind == SCC_X86_OPR_MEM) {
if (src.kind == SCC_X86_OPR_IMM) {
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_imm(dst, src), dst,
src, scc_pos_create());
} else if (src.kind == SCC_X86_OPR_REG) {
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_reg(dst, src), dst,
src, scc_pos_create());
} else {
Panic("emit_move: unsupported src kind %d", src.kind);
}
} else {
Panic("emit_move: unsupported src kind %d", src.kind);
Panic("emit_move: unsupported dst kind %d", dst.kind);
}
scc_vec_push(*vec, ins);
}
@@ -65,7 +121,6 @@ void scc_x86_emit_store_to_vec(scc_mir_x86_instr_vec_t *vec,
LOG_WARN("Mismatched sizes for store %d != %d", dst_addr.size,
src.size);
}
Assert(src.kind == SCC_X86_OPR_REG);
scc_x86_operand_value_t mem_op;
if (dst_addr.kind == SCC_X86_OPR_REG) {
mem_op = (scc_x86_operand_value_t){
@@ -83,10 +138,17 @@ void scc_x86_emit_store_to_vec(scc_mir_x86_instr_vec_t *vec,
} else if (dst_addr.kind == SCC_X86_OPR_MEM) {
mem_op = dst_addr;
} else {
Panic("emit_store: dst_addr must be REG or MEM");
Panic("emit_store: dst_addr kind not supported %d", dst_addr.kind);
}
scc_mir_x86_instr_t ins;
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_reg(mem_op, src), mem_op, src,
scc_pos_create());
if (src.kind == SCC_X86_OPR_REG) {
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_reg(mem_op, src), mem_op,
src, scc_pos_create());
} else if (src.kind == SCC_X86_OPR_IMM) {
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_imm(mem_op, src), mem_op,
src, scc_pos_create());
} else {
Panic("unsupported src kind not supported %d", src.kind);
}
scc_vec_push(*vec, ins);
}
}

View File

@@ -39,8 +39,11 @@ int scc_mir_vreg_map2slot(scc_mir_func_t *func, int vreg, int size, int align) {
return 0;
}
int new_slot = scc_vec_size(meta->stack_slots);
scc_mir_stack_slot_t s = {
.slot_id = new_slot, .size = size, .alignment = align, .offset = 0};
scc_mir_stack_slot_t s = {.slot_id = new_slot,
.size = size,
.alignment = align,
.offset = 0,
.arg_idx = 0};
scc_vec_push(meta->stack_slots, s);
scc_hashtable_set(&meta->vreg2physic, (void *)(usize)vreg,
(void *)(usize)new_slot);

View File

@@ -14,7 +14,9 @@ void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) {
scc_vec_foreach(module->cfg_module.funcs, i) {
if (i == 0)
continue;
ctx->impl_fn(ctx, module, &scc_vec_at(module->cfg_module.funcs, i));
scc_mir_func_t *func = &scc_vec_at(module->cfg_module.funcs, i);
ctx->offset = SCC_MIR_FUNC_META(func)->frame_size;
ctx->impl_fn(ctx, module, func);
}
}
@@ -69,7 +71,7 @@ void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage) {
// scc_x86_peephole_optimize(mir_module);
scc_frame_layout_t frame_layout_ctx = {0};
scc_win_pc_x64_frame_alloc_init(&frame_layout_ctx);
scc_win_pc_x64_frame_layout_init(&frame_layout_ctx);
scc_frame_layout(&frame_layout_ctx, mir_module);
if (stage == SCC_MIR_STAGE_FRAME_LAYOUT) {
return;

View File

@@ -7,11 +7,13 @@
static const int WIN64_STACK_ALIGN = 16;
static void frame_alloc_impl(scc_frame_layout_t *ctx,
scc_mir_module_t *mir_module,
scc_mir_func_t *mir_func) {
ctx->offset = 8;
static void frame_layout_impl(scc_frame_layout_t *ctx,
scc_mir_module_t *mir_module,
scc_mir_func_t *mir_func) {
ctx->offset += 8; // call return address frame
scc_mir_func_meta_t *func_meta = SCC_MIR_FUNC_META(mir_func);
// Pass 1: 处理局部变量槽 (arg_idx == 0),从 RSP 向上分配偏移
scc_vec_foreach(mir_func->bblocks, i) {
scc_cfg_bblock_id_t id = scc_vec_at(mir_func->bblocks, i);
scc_cfg_bblock_t *bb =
@@ -25,16 +27,17 @@ static void frame_alloc_impl(scc_frame_layout_t *ctx,
int slot_id = scc_x86_op_slot_id(op);
scc_mir_stack_slot_t *slot =
scc_mir_unsafe_slot(mir_func, slot_id);
if (slot->arg_idx > 0)
continue; // 传入参数槽Pass 2 处理
if (slot->offset == 0) {
ctx->offset += slot->size;
slot->offset = ctx->offset;
ctx->offset += slot->size;
}
*op = scc_x86_op_mem(
(scc_x86_mem_t){
.seg = SCC_X86_REG_INVALID,
.base = SCC_X86_REG_RSP,
.disp = {.displacement = -slot->offset},
.disp = {.displacement = slot->offset},
.index = SCC_X86_REG_INVALID,
.scale = 1,
},
@@ -44,14 +47,50 @@ static void frame_alloc_impl(scc_frame_layout_t *ctx,
}
}
int total_size = ctx->offset + 32; // shadow space
int total_size = ctx->offset;
ctx->offset =
(total_size + WIN64_STACK_ALIGN - 1) & ~(WIN64_STACK_ALIGN - 1);
func_meta->frame_size = ctx->offset;
// Pass 2: 处理传入参数槽 (arg_idx > 0)
// 在 Win64 布局中,栈上参数位于 return address + 8 + arg_idx * 8
// 即 RSP + frame_size + 8 + arg_idx * 8
scc_vec_foreach(mir_func->bblocks, i) {
scc_cfg_bblock_id_t id = scc_vec_at(mir_func->bblocks, i);
scc_cfg_bblock_t *bb =
scc_cfg_module_unsafe_get_bblock(&mir_module->cfg_module, id);
scc_mir_x86_instr_vec_t *instrs = SCC_MIR_X86_BBLOCK_INSTRS(bb);
scc_vec_foreach(*instrs, j) {
scc_mir_x86_instr_t *ins = &scc_vec_at(*instrs, j);
for (int k = 0; k < ins->x86_instr.num_operands; k++) {
scc_x86_operand_value_t *op = &ins->x86_instr.operands[k];
if (scc_x86_op_is_slot(op)) {
int slot_id = scc_x86_op_slot_id(op);
scc_mir_stack_slot_t *slot =
scc_mir_unsafe_slot(mir_func, slot_id);
if (slot->arg_idx == 0)
continue; // 局部变量槽Pass 1 已处理
if (slot->offset == 0) {
slot->offset =
func_meta->frame_size + 8 + slot->arg_idx * 8;
}
*op = scc_x86_op_mem(
(scc_x86_mem_t){
.seg = SCC_X86_REG_INVALID,
.base = SCC_X86_REG_RSP,
.disp = {.displacement = slot->offset},
.index = SCC_X86_REG_INVALID,
.scale = 1,
},
op->size);
}
}
}
}
}
void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx) {
ctx->impl_fn = frame_alloc_impl;
void scc_win_pc_x64_frame_layout_init(scc_frame_layout_t *ctx) {
ctx->impl_fn = frame_layout_impl;
}
/*
@@ -136,6 +175,15 @@ static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
scc_x86_64_isel_t *isel = userdata;
u8 size = 8;
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(isel->func);
int call_stack_size = instr->metadata.call.arg_count * 8;
if (meta->frame_size < call_stack_size) {
meta->frame_size = call_stack_size;
}
if (meta->frame_size < 32) {
meta->frame_size = 32; // Windows X64 shadow space
}
for (int i = instr->metadata.call.arg_count - 1; i >= 0; i -= 1) {
scc_lir_val_t *args = &instr->metadata.call.args[i];
switch (i) {
@@ -156,10 +204,15 @@ static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
scc_x86_lir_val_to_mir_op(isel, args, size));
break;
default:
scc_x86_operand_value_t op =
scc_x86_lir_val_to_mir_op(isel, args, size);
TODO();
add_instr_1(isel, SCC_X86_ICLASS_PUSH, op);
scc_x86_emit_move(
isel,
scc_x86_op_mem((scc_x86_mem_t){.base = SCC_X86_REG_RSP,
.index = SCC_X86_REG_INVALID,
.scale = 1,
.disp.displacement = i * 8,
.disp.displacement_bits = 8},
size),
scc_x86_lir_val_to_mir_op(isel, args, size));
break;
}
}
@@ -176,14 +229,34 @@ static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
Panic("unhandled opcode");
}
int ret_size = instr->size;
scc_x86_operand_value_t ret_reg =
scc_x86_lir_val_to_mir_op(isel, &instr->to, size);
if (ret_reg.kind != SCC_X86_OPR_NONE) {
scc_x86_lir_val_to_mir_op(isel, &instr->to, ret_size);
if (ret_reg.kind != SCC_X86_OPR_NONE && ret_size != 0) {
scc_x86_emit_move(isel, ret_reg,
scc_x86_op_preg(SCC_X86_REG_RAX, size));
scc_x86_op_preg(SCC_X86_REG_RAX, ret_size));
}
}
// 查找或创建传入参数的栈槽 (arg_idx > 0 表示栈上传入参数)
static int get_or_create_arg_slot(scc_mir_func_t *func, int arg_idx, int size) {
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
scc_vec_foreach(meta->stack_slots, i) {
scc_mir_stack_slot_t *s = &scc_vec_at(meta->stack_slots, i);
if (s->arg_idx == arg_idx)
return s->slot_id;
}
int slot_id = (int)scc_vec_size(meta->stack_slots);
scc_vec_push(meta->stack_slots, ((scc_mir_stack_slot_t){
.slot_id = slot_id,
.size = size,
.alignment = 8,
.offset = 0,
.arg_idx = arg_idx,
}));
return slot_id;
}
static void lower_param(void *userdata, const scc_lir_val_t *val,
void *out_op) {
scc_x86_operand_value_t *out = out_op;
@@ -202,10 +275,13 @@ static void lower_param(void *userdata, const scc_lir_val_t *val,
case 3:
*out = scc_x86_op_preg(SCC_X86_REG_R9, size);
break;
default:
*out = scc_x86_op_slot(-val->data.arg, size);
default: {
scc_x86_64_isel_t *isel = userdata;
int slot_id = get_or_create_arg_slot(isel->func, val->data.arg, size);
*out = scc_x86_op_slot(slot_id, size);
break;
}
}
}
static void lower_ret(void *userdata, const scc_lir_instr_t *instr) {