Compare commits
4 Commits
68eac24152
...
aa4292a30e
| Author | SHA1 | Date | |
|---|---|---|---|
| aa4292a30e | |||
| c6e3bb2e20 | |||
| 2c13ac54df | |||
| 3df858fb85 |
@@ -61,6 +61,12 @@ void scc_abi_compute_ast_type_layout(const scc_abi_type_calc_t *ctx, void *type,
|
||||
case SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG:
|
||||
kind = SCC_ABI_TYPE_U_LONG_LONG;
|
||||
break;
|
||||
case SCC_AST_BUILTIN_TYPE_FLOAT:
|
||||
kind = SCC_ABI_TYPE_FLOAT;
|
||||
break;
|
||||
case SCC_AST_BUILTIN_TYPE_DOUBLE:
|
||||
kind = SCC_ABI_TYPE_DOUBLE;
|
||||
break;
|
||||
default:
|
||||
Panic("Unsupported AST type: %d",
|
||||
scc_ast_canon_type(ast_type)->builtin.type);
|
||||
|
||||
@@ -262,7 +262,7 @@ typedef enum scc_ast_expr_op {
|
||||
SCC_AST_OP_UNARY_PLUS, // + (一元)
|
||||
SCC_AST_OP_UNARY_MINUS, // - (一元)
|
||||
SCC_AST_OP_ADDRESS_OF, // &
|
||||
SCC_AST_OP_INDIRECTION, // *
|
||||
SCC_AST_OP_INDIRECTION, // * (取地址)
|
||||
SCC_AST_OP_BITWISE_NOT, // ~
|
||||
SCC_AST_OP_LOGICAL_NOT, // !
|
||||
SCC_AST_OP_PREFIX_INCREMENT, // ++ (前缀)
|
||||
|
||||
@@ -11,6 +11,7 @@ typedef struct {
|
||||
scc_hashtable_t break_cache; ///< break cache
|
||||
scc_hashtable_t continue_cache; ///< continue cache
|
||||
scc_hashtable_t symtab; ///< symbol to ir_ref
|
||||
scc_hashtable_t type_cache; ///< scc_ast_canon_type_t* -> scc_hir_type_ref_t
|
||||
// scc_strpool_t strpool; ///< string pool
|
||||
const scc_abi_type_calc_t *abi;
|
||||
cbool hint_using_value; // 转换时尽可能使用value而不是alloc
|
||||
|
||||
@@ -27,39 +27,24 @@ static scc_hir_type_ref_t parse_base_type(scc_ast2ir_ctx_t *ctx,
|
||||
return SCC_HIR_REF_nullptr;
|
||||
}
|
||||
|
||||
// static inline void parse_struct_union_layout(scc_ast_qual_type_t *type) {}
|
||||
|
||||
// 辅助函数:计算数组实际长度(如果原长度为0)
|
||||
static void resolve_array_length(scc_ast2ir_ctx_t *ctx,
|
||||
const scc_hir_type_t *orig_array_type,
|
||||
scc_hir_type_t *resolved_array_type,
|
||||
const scc_ast_expr_t *init_expr) {
|
||||
*resolved_array_type = *orig_array_type; // 拷贝
|
||||
Assert(orig_array_type->tag == SCC_HIR_TYPE_ARRAY);
|
||||
if (orig_array_type->data.array.len != 0)
|
||||
return; // 长度已知,无需推断
|
||||
|
||||
usize new_len = 0;
|
||||
switch (init_expr->base.type) {
|
||||
case SCC_AST_EXPR_STRING_LITERAL:
|
||||
// 字符串字面量:长度 = 字符串字符数 + 1('\0')
|
||||
// TODO: L"" \n \r 计算 暂不支持
|
||||
new_len = scc_strlen(init_expr->literal.lexme) + 1;
|
||||
break;
|
||||
case SCC_AST_EXPR_COMPOUND: {
|
||||
// 复合初始化:元素个数 = 初始化列表长度
|
||||
scc_vec_foreach(init_expr->compound.lhs_exprs, i) {
|
||||
scc_ast_expr_t *elem = scc_vec_at(init_expr->compound.lhs_exprs, i);
|
||||
// TODO: 支持嵌套的多维数组初始化(递归)
|
||||
// 这里简化:只统计顶层元素个数,假设是一维数组
|
||||
new_len++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
static inline bool scc_hir_type_is_signed(scc_hir_type_tag_t tag) {
|
||||
switch (tag) {
|
||||
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:
|
||||
return true;
|
||||
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:
|
||||
return false;
|
||||
default:
|
||||
Panic("unsupported initializer for zero-length array");
|
||||
// 指针可以视作无符号整数
|
||||
return false;
|
||||
}
|
||||
resolved_array_type->data.array.len = new_len;
|
||||
}
|
||||
|
||||
// 辅助函数:生成数组初始化代码
|
||||
@@ -123,6 +108,142 @@ static void emit_array_initialization(scc_ast2ir_ctx_t *ctx,
|
||||
// 这里简单忽略,实际可生成 memset 循环,但为简化暂不处理
|
||||
}
|
||||
|
||||
static void emit_aggregate_initialization(scc_ast2ir_ctx_t *ctx,
|
||||
scc_hir_value_ref_t base_ptr,
|
||||
const scc_hir_type_t *type,
|
||||
const scc_ast_expr_t *init_expr) {
|
||||
Assert(type->tag == SCC_HIR_TYPE_STRUCT || type->tag == SCC_HIR_TYPE_UNION);
|
||||
if (init_expr->base.type != SCC_AST_EXPR_COMPOUND) {
|
||||
Panic("expected compound initializer");
|
||||
}
|
||||
usize idx = 0;
|
||||
scc_vec_foreach(init_expr->compound.rhs_exprs, i) {
|
||||
if (idx >= type->data.aggregate.fields.size)
|
||||
break;
|
||||
scc_ast_expr_t *field_init =
|
||||
scc_vec_at(init_expr->compound.rhs_exprs, i);
|
||||
scc_hir_type_ref_t field_type_ref =
|
||||
scc_vec_at(type->data.aggregate.fields, idx);
|
||||
const scc_hir_type_t *field_type = scc_hir_module_get_type(
|
||||
&ctx->builder.cprog->module, field_type_ref);
|
||||
|
||||
scc_ap_t idx_ap;
|
||||
scc_ap_set_int(&idx_ap, idx);
|
||||
scc_hir_value_ref_t idx_val = scc_hir_builder_integer(
|
||||
&ctx->builder, scc_hir_builder_type_u64(&ctx->builder), &idx_ap);
|
||||
scc_hir_value_ref_t field_ptr =
|
||||
scc_hir_builder_get_elem_ptr(&ctx->builder, base_ptr, idx_val);
|
||||
|
||||
if (field_type->tag == SCC_HIR_TYPE_ARRAY) {
|
||||
emit_array_initialization(ctx, field_ptr, field_type, field_init);
|
||||
} else if (field_type->tag == SCC_HIR_TYPE_STRUCT ||
|
||||
field_type->tag == SCC_HIR_TYPE_UNION) {
|
||||
emit_aggregate_initialization(ctx, field_ptr, field_type,
|
||||
field_init);
|
||||
} else {
|
||||
scc_hir_value_ref_t val = scc_ast2ir_expr(ctx, field_init, false);
|
||||
scc_hir_builder_store(&ctx->builder, field_ptr, val);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
// static inline void parse_struct_union_layout(scc_ast_qual_type_t *type) {}
|
||||
|
||||
usize scc_hir_type_size(scc_ast2ir_ctx_t *ctx, const scc_hir_type_t *type) {
|
||||
switch (type->tag) {
|
||||
case SCC_HIR_TYPE_void:
|
||||
return 0;
|
||||
case SCC_HIR_TYPE_i8:
|
||||
return 1;
|
||||
case SCC_HIR_TYPE_i16:
|
||||
return 2;
|
||||
case SCC_HIR_TYPE_i32:
|
||||
return 4;
|
||||
case SCC_HIR_TYPE_i64:
|
||||
return 8;
|
||||
case SCC_HIR_TYPE_i128:
|
||||
return 16;
|
||||
case SCC_HIR_TYPE_u8:
|
||||
return 1;
|
||||
case SCC_HIR_TYPE_u16:
|
||||
return 2;
|
||||
case SCC_HIR_TYPE_u32:
|
||||
return 4;
|
||||
case SCC_HIR_TYPE_u64:
|
||||
return 8;
|
||||
case SCC_HIR_TYPE_u128:
|
||||
return 16;
|
||||
case SCC_HIR_TYPE_f16:
|
||||
return 2;
|
||||
case SCC_HIR_TYPE_f32:
|
||||
return 4;
|
||||
case SCC_HIR_TYPE_f64:
|
||||
return 8;
|
||||
case SCC_HIR_TYPE_f128:
|
||||
return 16;
|
||||
|
||||
case SCC_HIR_TYPE_PTR: {
|
||||
// 目标指针大小,可以定义为 8(64位)或从 ABI 获取
|
||||
// 假设你的目标架构是 64 位
|
||||
return 8;
|
||||
}
|
||||
|
||||
case SCC_HIR_TYPE_ARRAY: {
|
||||
usize elem_size = scc_hir_type_size(
|
||||
ctx, scc_hir_module_get_type(&ctx->builder.cprog->module,
|
||||
type->data.array.base));
|
||||
return elem_size * type->data.array.len;
|
||||
}
|
||||
|
||||
case SCC_HIR_TYPE_FUNC:
|
||||
// 函数类型大小一般是指针大小
|
||||
return 8;
|
||||
|
||||
case SCC_HIR_TYPE_STRUCT:
|
||||
case SCC_HIR_TYPE_UNION:
|
||||
// 暂时无法计算,保守返回 0 或报错
|
||||
LOG_ERROR("Cannot compute size of struct/union without layout info");
|
||||
return 0;
|
||||
|
||||
default:
|
||||
LOG_ERROR("Unknown type tag %d", type->tag);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:计算数组实际长度(如果原长度为0)
|
||||
static void resolve_array_length(scc_ast2ir_ctx_t *ctx,
|
||||
const scc_hir_type_t *orig_array_type,
|
||||
scc_hir_type_t *resolved_array_type,
|
||||
const scc_ast_expr_t *init_expr) {
|
||||
*resolved_array_type = *orig_array_type; // 拷贝
|
||||
Assert(orig_array_type->tag == SCC_HIR_TYPE_ARRAY);
|
||||
if (orig_array_type->data.array.len != 0)
|
||||
return; // 长度已知,无需推断
|
||||
|
||||
usize new_len = 0;
|
||||
switch (init_expr->base.type) {
|
||||
case SCC_AST_EXPR_STRING_LITERAL:
|
||||
// 字符串字面量:长度 = 字符串字符数 + 1('\0')
|
||||
// TODO: L"" \n \r 计算 暂不支持
|
||||
new_len = scc_strlen(init_expr->literal.lexme) + 1;
|
||||
break;
|
||||
case SCC_AST_EXPR_COMPOUND: {
|
||||
// 复合初始化:元素个数 = 初始化列表长度
|
||||
scc_vec_foreach(init_expr->compound.lhs_exprs, i) {
|
||||
scc_ast_expr_t *elem = scc_vec_at(init_expr->compound.lhs_exprs, i);
|
||||
// TODO: 支持嵌套的多维数组初始化(递归)
|
||||
// 这里简化:只统计顶层元素个数,假设是一维数组
|
||||
new_len++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Panic("unsupported initializer for zero-length array");
|
||||
}
|
||||
resolved_array_type->data.array.len = new_len;
|
||||
}
|
||||
|
||||
scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||||
const scc_ast_qual_type_t *ast_type) {
|
||||
if (ctx == nullptr || ast_type == nullptr) {
|
||||
@@ -189,22 +310,64 @@ scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||||
} break;
|
||||
case SCC_AST_TYPE_STRUCT:
|
||||
case SCC_AST_TYPE_UNION: {
|
||||
scc_hir_type_init(&ir_type, ast_type->base.type == SCC_AST_TYPE_STRUCT
|
||||
const scc_ast_canon_type_t *canon = scc_ast_canon_type(ast_type);
|
||||
|
||||
// === 1. 查缓存,如果已存在则直接返回(递归时一定会命中) ===
|
||||
scc_hir_type_ref_t cached =
|
||||
(scc_hir_type_ref_t)(usize)scc_hashtable_get(&ctx->type_cache,
|
||||
canon);
|
||||
if (cached != 0) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// === 2. 创建占位类型(字段为空) ===
|
||||
scc_hir_type_t placeholder;
|
||||
scc_hir_type_init(&placeholder,
|
||||
ast_type->base.type == SCC_AST_TYPE_STRUCT
|
||||
? SCC_HIR_TYPE_STRUCT
|
||||
: SCC_HIR_TYPE_UNION);
|
||||
if (scc_ast_canon_type(ast_type)->record.decl == nullptr) {
|
||||
Panic("%s record fields is nullptr",
|
||||
scc_ast_canon_type(ast_type)->record.name);
|
||||
// 可以给占位符一个调试名
|
||||
if (canon->record.name) {
|
||||
placeholder.name = canon->record.name;
|
||||
}
|
||||
scc_vec_foreach(
|
||||
scc_ast_canon_type(ast_type)->record.decl->record.fields, i) {
|
||||
scc_ast_decl_t *decl_field = scc_vec_at(
|
||||
scc_ast_canon_type(ast_type)->record.decl->record.fields, i);
|
||||
Assert(decl_field->base.type == SCC_AST_DECL_VAR);
|
||||
scc_hir_type_ref_t field_type =
|
||||
scc_ast2ir_type(ctx, decl_field->var.type);
|
||||
scc_vec_push(ir_type.data.aggregate.fields, field_type);
|
||||
|
||||
// === 3. 直接添加到模块,不经过 builder 的 uniquing ===
|
||||
// 因为此时我们不需要类型去重,只需要一个确定不移的引用
|
||||
scc_hir_type_ref_t place_ref =
|
||||
scc_hir_module_add_type(&ctx->builder.cprog->module, &placeholder);
|
||||
|
||||
// === 4. 将映射写入缓存(关键!必须在递归前) ===
|
||||
scc_hashtable_set(&ctx->type_cache, canon, (void *)(usize)place_ref);
|
||||
|
||||
// === 5. 递归解析所有字段 ===
|
||||
// 此时若字段类型指回本结构体,将直接通过缓存返回 place_ref
|
||||
scc_hir_type_ref_vec_t fields;
|
||||
scc_vec_init(fields);
|
||||
scc_ast_decl_t *decl = canon->record.decl;
|
||||
if (decl == nullptr) {
|
||||
Panic("struct/union declaration is missing");
|
||||
}
|
||||
scc_vec_foreach(decl->record.fields, i) {
|
||||
scc_ast_decl_t *field_decl = scc_vec_at(decl->record.fields, i);
|
||||
Assert(field_decl->base.type == SCC_AST_DECL_VAR);
|
||||
scc_hir_type_ref_t field_ir_type =
|
||||
scc_ast2ir_type(ctx, field_decl->var.type);
|
||||
scc_vec_push(fields, field_ir_type);
|
||||
}
|
||||
|
||||
// === 6. 将字段填入占位类型 ===
|
||||
scc_hir_type_t *place_type =
|
||||
scc_hir_module_get_type(&ctx->builder.cprog->module, place_ref);
|
||||
// 注意:scc_hir_type_init 已经为 struct/union 初始化了 fields 空向量
|
||||
// 这里直接 push 即可(也可以先 scc_vec_free 再 init,看需要)
|
||||
scc_vec_foreach(fields, i) {
|
||||
scc_vec_push(place_type->data.aggregate.fields,
|
||||
scc_vec_at(fields, i));
|
||||
}
|
||||
scc_vec_free(fields); // 释放临时向量
|
||||
|
||||
// === 7. 返回占位符的引用(现在已经变成完整类型) ===
|
||||
return place_ref;
|
||||
} break;
|
||||
case SCC_AST_TYPE_ENUM:
|
||||
scc_ast_canon_type_t *int_canon_type = scc_ast_ctx_get_builtin_type(
|
||||
@@ -337,7 +500,8 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
switch (expr->base.type) {
|
||||
case SCC_AST_EXPR_BINARY: {
|
||||
scc_ast_expr_t tmp_expr;
|
||||
scc_hir_value_ref_t lhs, rhs;
|
||||
scc_hir_value_ref_t lhs = SCC_HIR_REF_nullptr,
|
||||
rhs = SCC_HIR_REF_nullptr;
|
||||
switch (expr->binary.op) {
|
||||
case SCC_AST_OP_ASSIGN: // =
|
||||
rhs = scc_ast2ir_expr(ctx, expr->binary.rhs, false);
|
||||
@@ -407,6 +571,7 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
break;
|
||||
}
|
||||
if (is_assign) {
|
||||
Assert(rhs != SCC_HIR_REF_nullptr);
|
||||
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, true);
|
||||
return scc_hir_builder_store(&ctx->builder, lhs, rhs);
|
||||
}
|
||||
@@ -452,7 +617,7 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
}
|
||||
// 创建操作节点
|
||||
return scc_hir_builder_binop(&ctx->builder, op, lhs, rhs);
|
||||
}
|
||||
} break;
|
||||
case SCC_AST_EXPR_UNARY: {
|
||||
if (expr->unary.op == SCC_AST_OP_ADDRESS_OF) {
|
||||
return scc_ast2ir_expr(ctx, expr->unary.operand, true);
|
||||
@@ -470,17 +635,6 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
}
|
||||
scc_hir_value_ref_t operand =
|
||||
scc_ast2ir_expr(ctx, expr->unary.operand, is_lvalue);
|
||||
// /* 一元操作符 */
|
||||
// SCC_AST_OP_UNARY_PLUS, // + (一元)
|
||||
// SCC_AST_OP_UNARY_MINUS, // - (一元)
|
||||
// SCC_AST_OP_ADDRESS_OF, // &
|
||||
// SCC_AST_OP_INDIRECTION, // *
|
||||
// SCC_AST_OP_BITWISE_NOT, // ~
|
||||
// SCC_AST_OP_LOGICAL_NOT, // !
|
||||
// SCC_AST_OP_PREFIX_INCREMENT, // ++ (前缀)
|
||||
// SCC_AST_OP_PREFIX_DECREMENT, // -- (前缀)
|
||||
// SCC_AST_OP_POSTFIX_INCREMENT, // ++ (后缀)
|
||||
// SCC_AST_OP_POSTFIX_DECREMENT, // -- (后缀)
|
||||
switch (expr->unary.op) {
|
||||
case SCC_AST_OP_UNARY_PLUS:
|
||||
/* just pass */
|
||||
@@ -517,17 +671,138 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
return scc_hir_builder_binop(&ctx->builder, SCC_HIR_OP_EQ, zero_ref,
|
||||
operand);
|
||||
}
|
||||
case SCC_AST_OP_PREFIX_INCREMENT:
|
||||
case SCC_AST_OP_PREFIX_DECREMENT: {
|
||||
// 获取左值地址
|
||||
scc_hir_value_ref_t addr =
|
||||
scc_ast2ir_expr(ctx, expr->unary.operand, true);
|
||||
scc_hir_value_ref_t old_val =
|
||||
scc_hir_builder_load(&ctx->builder, addr);
|
||||
scc_hir_type_ref_t old_type =
|
||||
scc_hir_module_get_value(
|
||||
scc_hir_builder_get_module(&ctx->builder), old_val)
|
||||
->type;
|
||||
scc_hir_type_ref_t promoted_type = old_type;
|
||||
// scc_ast2ir_promoted_type(ctx, old_type);
|
||||
scc_hir_value_ref_t promoted = old_val;
|
||||
// scc_ast2ir_apply_promotion(ctx, old_val);
|
||||
|
||||
scc_hir_value_ref_t one = scc_hir_builder_integer(
|
||||
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder),
|
||||
&(scc_ap_t){.data.digit = 1, .capacity = -1});
|
||||
scc_hir_op_type_t op =
|
||||
(expr->unary.op == SCC_AST_OP_PREFIX_INCREMENT)
|
||||
? SCC_HIR_OP_ADD
|
||||
: SCC_HIR_OP_SUB;
|
||||
scc_hir_value_ref_t new_val =
|
||||
scc_hir_builder_binop(&ctx->builder, op, promoted, one);
|
||||
|
||||
// 如果原类型不是提升后的类型,需要截断回原类型再存储
|
||||
scc_hir_value_ref_t stored_val = new_val;
|
||||
// if (old_type != promoted_type) {
|
||||
// stored_val = scc_hir_builder_conv(&ctx->builder, new_val,
|
||||
// old_type, CONV_TRUNC);
|
||||
// }
|
||||
scc_hir_builder_store(&ctx->builder, addr, stored_val);
|
||||
Assert(new_val != SCC_HIR_REF_nullptr);
|
||||
return new_val; // 表达式的值是提升后的新值(符合 C 标准)
|
||||
} break;
|
||||
case SCC_AST_OP_POSTFIX_INCREMENT:
|
||||
case SCC_AST_OP_POSTFIX_DECREMENT: {
|
||||
// 获取左值地址
|
||||
scc_hir_value_ref_t addr =
|
||||
scc_ast2ir_expr(ctx, expr->unary.operand, true);
|
||||
scc_hir_value_ref_t old_val =
|
||||
scc_hir_builder_load(&ctx->builder, addr);
|
||||
scc_hir_type_ref_t old_type =
|
||||
scc_hir_module_get_value(
|
||||
scc_hir_builder_get_module(&ctx->builder), old_val)
|
||||
->type;
|
||||
scc_hir_type_ref_t promoted_type = old_type;
|
||||
// scc_ast2ir_promoted_type(ctx, old_type);
|
||||
scc_hir_value_ref_t promoted = old_val;
|
||||
// scc_ast2ir_apply_promotion(ctx, old_val);
|
||||
|
||||
scc_hir_value_ref_t one = scc_hir_builder_integer(
|
||||
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder),
|
||||
&(scc_ap_t){.data.digit = 1, .capacity = -1});
|
||||
scc_hir_op_type_t op =
|
||||
(expr->unary.op == SCC_AST_OP_POSTFIX_INCREMENT)
|
||||
? SCC_HIR_OP_ADD
|
||||
: SCC_HIR_OP_SUB;
|
||||
scc_hir_value_ref_t new_val =
|
||||
scc_hir_builder_binop(&ctx->builder, op, promoted, one);
|
||||
|
||||
scc_hir_value_ref_t stored_val = new_val;
|
||||
// if (old_type != promoted_type)
|
||||
// stored_val = trunc;
|
||||
scc_hir_builder_store(&ctx->builder, addr, stored_val);
|
||||
|
||||
// 后缀返回旧的、未提升的值(但 C
|
||||
// 要求返回提升后的旧值?实际是旧值按右值规则,应得到提升后的值)
|
||||
// 标准规定后缀++的结果是操作数原来的值,但会经过整数提升。
|
||||
// 所以需要返回 promoted(已提升的旧值)。
|
||||
Assert(promoted != SCC_HIR_REF_nullptr);
|
||||
return promoted; // 旧值,但类型已提升为
|
||||
// int 等
|
||||
} break;
|
||||
default:
|
||||
LOG_FATAL("Unsupported unary operator: %d", expr->unary.op);
|
||||
return 0;
|
||||
}
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
case SCC_AST_EXPR_COND: {
|
||||
TODO();
|
||||
break;
|
||||
scc_hir_type_ref_t true_type = SCC_HIR_REF_nullptr;
|
||||
scc_hir_type_ref_t false_type = SCC_HIR_REF_nullptr;
|
||||
|
||||
scc_hir_value_ref_t true_block =
|
||||
scc_hir_builder_bblock(&ctx->builder, "cond_true");
|
||||
scc_hir_value_ref_t false_block =
|
||||
scc_hir_builder_bblock(&ctx->builder, "cond_false");
|
||||
scc_hir_value_ref_t merge_block =
|
||||
scc_hir_builder_bblock(&ctx->builder, "cond_merge");
|
||||
|
||||
scc_hir_value_ref_t cond_node =
|
||||
scc_ast2ir_expr(ctx, expr->cond.cond, false);
|
||||
scc_hir_builder_branch(&ctx->builder, cond_node, true_block,
|
||||
false_block);
|
||||
|
||||
// 生成true分支
|
||||
scc_hir_builder_set_current_bblock(&ctx->builder, true_block);
|
||||
scc_hir_value_ref_t true_val =
|
||||
scc_ast2ir_expr(ctx, expr->cond.then_expr, false);
|
||||
|
||||
true_type = scc_hir_module_get_value(
|
||||
scc_hir_builder_get_module(&ctx->builder), true_val)
|
||||
->type;
|
||||
Assert(true_type != SCC_HIR_REF_nullptr);
|
||||
scc_hir_value_ref_t result_slot =
|
||||
scc_hir_builder_alloca(&ctx->builder, true_type, "cond_result");
|
||||
|
||||
scc_hir_builder_store(&ctx->builder, result_slot, true_val);
|
||||
scc_hir_builder_jump(&ctx->builder, merge_block);
|
||||
|
||||
// 生成false分支
|
||||
scc_hir_builder_set_current_bblock(&ctx->builder, false_block);
|
||||
scc_hir_value_ref_t false_val =
|
||||
scc_ast2ir_expr(ctx, expr->cond.else_expr, false);
|
||||
false_type = scc_hir_module_get_value(
|
||||
scc_hir_builder_get_module(&ctx->builder), false_val)
|
||||
->type;
|
||||
Assert(false_type != SCC_HIR_REF_nullptr);
|
||||
|
||||
scc_hir_builder_store(&ctx->builder, result_slot, false_val);
|
||||
scc_hir_builder_jump(&ctx->builder, merge_block);
|
||||
|
||||
// 合并并返回
|
||||
scc_hir_builder_set_current_bblock(&ctx->builder, merge_block);
|
||||
if (true_type != false_type) {
|
||||
LOG_ERROR("Type mismatch in conditional expression");
|
||||
// FIXME need panic
|
||||
}
|
||||
return scc_hir_builder_load(&ctx->builder, result_slot);
|
||||
} break;
|
||||
case SCC_AST_EXPR_CALL: {
|
||||
// 转换参数
|
||||
scc_hir_value_ref_vec_t args;
|
||||
@@ -610,12 +885,79 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
return scc_hir_builder_load(&ctx->builder, field_ptr);
|
||||
}
|
||||
case SCC_AST_EXPR_CAST: {
|
||||
TODO();
|
||||
} break;
|
||||
// 1. 转换操作数(右值)
|
||||
scc_hir_value_ref_t operand =
|
||||
scc_ast2ir_expr(ctx, expr->cast.expr, false);
|
||||
|
||||
// 2. 转换目标类型为 IR 类型
|
||||
scc_hir_type_ref_t target_type = scc_ast2ir_type(ctx, expr->cast.type);
|
||||
|
||||
// 3. 确定转换模式(SEXT / ZEXT / TRUNC)
|
||||
// 这里用简单的启发式:根据大小变化决定
|
||||
scc_hir_type_t *src_type = scc_hir_module_get_type_by_value(
|
||||
&ctx->builder.cprog->module, operand);
|
||||
scc_hir_type_t *dst_type =
|
||||
scc_hir_module_get_type(&ctx->builder.cprog->module, target_type);
|
||||
|
||||
usize src_size =
|
||||
scc_hir_type_size(ctx, src_type); // 你可能有这个函数,否则自行计算
|
||||
usize dst_size = scc_hir_type_size(ctx, dst_type);
|
||||
|
||||
int conv_kind;
|
||||
if (dst_size > src_size) {
|
||||
// 目标更大,需要扩展。根据源类型有无符号决定符号扩展还是零扩展
|
||||
conv_kind =
|
||||
scc_hir_type_is_signed(src_type->tag) ? CONV_SEXT : CONV_ZEXT;
|
||||
} else if (dst_size < src_size) {
|
||||
conv_kind = CONV_TRUNC;
|
||||
} else {
|
||||
// 同大小,可以视为 NOP 转换,或者直接返回操作数
|
||||
return operand; // 或创建一个 CONV_SEXT 也没问题
|
||||
}
|
||||
|
||||
// 4. 构造转换节点
|
||||
scc_hir_value_t conv_node = {
|
||||
.tag = SCC_HIR_VALUE_TAG_CONV,
|
||||
.type = target_type,
|
||||
.data.conv.operand = operand,
|
||||
.data.conv.target_type = target_type,
|
||||
.data.conv.conv_type = conv_kind,
|
||||
};
|
||||
return scc_hir_module_add_value(&ctx->builder.cprog->module,
|
||||
&conv_node);
|
||||
}
|
||||
case SCC_AST_EXPR_SIZE_OF: {
|
||||
TODO();
|
||||
// return scc_hir_builder_integer(
|
||||
// &ctx->builder, scc_hir_builder_type_u64(&ctx->builder), val);
|
||||
// 1. 将 sizeof 的操作数(类型或表达式)转换为 IR 类型
|
||||
scc_hir_type_ref_t hir_type;
|
||||
if (expr->attr_of.type) {
|
||||
// sizeof(type)
|
||||
hir_type = scc_ast2ir_type(ctx, expr->attr_of.type);
|
||||
} else if (expr->attr_of.expr) {
|
||||
// sizeof expression:计算表达式类型
|
||||
// 注意:sizeof
|
||||
// 不对表达式求值,只需类型,这里假设语义分析已经标注了类型
|
||||
scc_hir_value_ref_t dummy =
|
||||
scc_ast2ir_expr(ctx, expr->attr_of.expr, false);
|
||||
hir_type =
|
||||
scc_hir_module_get_value(&ctx->builder.cprog->module, dummy)
|
||||
->type;
|
||||
} else {
|
||||
scc_ap_t val;
|
||||
val.data.digit = 0;
|
||||
LOG_ERROR("[ast2ir] unsupported");
|
||||
return scc_hir_builder_integer(
|
||||
&ctx->builder, scc_hir_builder_type_u64(&ctx->builder), &val);
|
||||
}
|
||||
|
||||
// 2. 计算大小
|
||||
const scc_hir_type_t *type =
|
||||
scc_hir_module_get_type(&ctx->builder.cprog->module, hir_type);
|
||||
usize dst_size = scc_hir_type_size(ctx, type);
|
||||
|
||||
scc_ap_t val;
|
||||
val.data.digit = dst_size;
|
||||
return scc_hir_builder_integer(
|
||||
&ctx->builder, scc_hir_builder_type_u64(&ctx->builder), &val);
|
||||
}
|
||||
case SCC_AST_EXPR_ALIGN_OF: {
|
||||
TODO();
|
||||
@@ -623,10 +965,50 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
// &ctx->builder, scc_hir_builder_type_u64(&ctx->builder), val);
|
||||
}
|
||||
case SCC_AST_EXPR_COMPOUND: {
|
||||
TODO();
|
||||
// 1. 从 base 子节点取得类型(base 一定是 SCC_AST_EXPR_LVALUE)
|
||||
Assert(expr->compound.base != nullptr);
|
||||
Assert(expr->compound.base->base.type == SCC_AST_EXPR_LVALUE);
|
||||
scc_ast_qual_type_t *ast_type = expr->compound.base->lvalue.type;
|
||||
scc_hir_type_ref_t type_ref = scc_ast2ir_type(ctx, ast_type);
|
||||
const scc_hir_type_t *type =
|
||||
scc_hir_module_get_type(&ctx->builder.cprog->module, type_ref);
|
||||
|
||||
// 2. 分配栈上临时存储
|
||||
scc_hir_value_ref_t storage =
|
||||
scc_hir_builder_alloca(&ctx->builder, type_ref, "compound_literal");
|
||||
|
||||
// 3. 根据类型调用对应的初始化函数
|
||||
if (type->tag == SCC_HIR_TYPE_ARRAY) {
|
||||
emit_array_initialization(ctx, storage, type, expr);
|
||||
} else if (type->tag == SCC_HIR_TYPE_STRUCT ||
|
||||
type->tag == SCC_HIR_TYPE_UNION) {
|
||||
emit_aggregate_initialization(ctx, storage, type, expr);
|
||||
} else {
|
||||
// 标量:取初始化列表的第一个值
|
||||
Assert(expr->compound.rhs_exprs.size > 0);
|
||||
scc_ast_expr_t *init_expr = scc_vec_at(expr->compound.rhs_exprs, 0);
|
||||
scc_hir_value_ref_t val = scc_ast2ir_expr(ctx, init_expr, false);
|
||||
scc_hir_builder_store(&ctx->builder, storage, val);
|
||||
}
|
||||
|
||||
// 4. 根据左值 / 右值返回
|
||||
if (is_lvalue) {
|
||||
return storage; // 左值
|
||||
} else {
|
||||
// 右值:数组退化为首元素指针,结构体暂时返回地址
|
||||
if (type->tag == SCC_HIR_TYPE_ARRAY) {
|
||||
return scc_hir_builder_get_elem_ptr(&ctx->builder, storage,
|
||||
SCC_HIR_REF_nullptr);
|
||||
} else if (type->tag == SCC_HIR_TYPE_STRUCT ||
|
||||
type->tag == SCC_HIR_TYPE_UNION) {
|
||||
return storage; // 调用者会 memcpy
|
||||
} else {
|
||||
return scc_hir_builder_load(&ctx->builder, storage);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case SCC_AST_EXPR_LVALUE: {
|
||||
TODO();
|
||||
UNREACHABLE(); // should only appear as compound.base
|
||||
} break;
|
||||
case SCC_AST_EXPR_BUILTIN: {
|
||||
TODO();
|
||||
@@ -923,10 +1305,10 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
|
||||
break;
|
||||
}
|
||||
case SCC_AST_STMT_GOTO: {
|
||||
scc_hir_bblock_ref_t target = (usize)scc_hashtable_get(
|
||||
&ctx->ast2ir_cache, (void *)stmt->goto_stmt._target);
|
||||
Assert(target != SCC_HIR_REF_nullptr);
|
||||
scc_hir_builder_jump(&ctx->builder, target);
|
||||
// scc_hir_bblock_ref_t target = (usize)scc_hashtable_get(
|
||||
// &ctx->ast2ir_cache, (void *)stmt->goto_stmt._target);
|
||||
// Assert(target != SCC_HIR_REF_nullptr);
|
||||
// scc_hir_builder_jump(&ctx->builder, target);
|
||||
} break;
|
||||
case SCC_AST_STMT_LABEL: {
|
||||
scc_hir_value_ref_t label_block =
|
||||
@@ -1009,6 +1391,10 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
|
||||
if (type.tag == SCC_HIR_TYPE_ARRAY) {
|
||||
emit_array_initialization(ctx, alloc_val_node, &type,
|
||||
decl->var.init);
|
||||
} else if (type.tag == SCC_HIR_TYPE_STRUCT ||
|
||||
type.tag == SCC_HIR_TYPE_UNION) {
|
||||
emit_aggregate_initialization(ctx, alloc_val_node, &type,
|
||||
decl->var.init);
|
||||
} else {
|
||||
// 标量类型
|
||||
scc_hir_value_ref_t init_val =
|
||||
@@ -1023,9 +1409,11 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
|
||||
scc_ast2ir_type(ctx, decl->func.type);
|
||||
scc_hir_func_ref_t func_ref =
|
||||
(usize)scc_hashtable_get(&ctx->symtab, decl->name);
|
||||
|
||||
if (func_ref == SCC_HIR_REF_nullptr) {
|
||||
func_ref =
|
||||
scc_hir_builder_func(&ctx->builder, func_type_ref, decl->name);
|
||||
// TODO: add func to cache because function pointer is needed
|
||||
scc_hashtable_set(&ctx->symtab, decl->name,
|
||||
(void *)(usize)func_ref);
|
||||
}
|
||||
@@ -1149,6 +1537,7 @@ void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_abi_type_calc_t *abi,
|
||||
scc_hashtable_usize_init(&ctx->break_cache);
|
||||
scc_hashtable_usize_init(&ctx->continue_cache);
|
||||
scc_hashtable_cstr_init(&ctx->symtab);
|
||||
scc_hashtable_usize_init(&ctx->type_cache);
|
||||
ctx->hint_using_value = false;
|
||||
}
|
||||
|
||||
@@ -1157,5 +1546,6 @@ void scc_ast2ir_ctx_drop(scc_ast2ir_ctx_t *ctx) {
|
||||
scc_hashtable_drop(&ctx->ast2ir_cache);
|
||||
scc_hashtable_drop(&ctx->break_cache);
|
||||
scc_hashtable_drop(&ctx->continue_cache);
|
||||
scc_hashtable_drop(&ctx->type_cache);
|
||||
scc_hashtable_drop(&ctx->symtab);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,11 @@ void scc_hir_builder_init(scc_hir_builder_t *builder, scc_hir_cprog_t *cprog);
|
||||
*/
|
||||
void scc_hir_builder_drop(scc_hir_builder_t *builder);
|
||||
|
||||
static inline scc_hir_module_t *
|
||||
scc_hir_builder_get_module(scc_hir_builder_t *builder) {
|
||||
return &builder->cprog->module;
|
||||
}
|
||||
|
||||
scc_hir_func_ref_t scc_hir_builder_func(scc_hir_builder_t *builder,
|
||||
scc_hir_type_ref_t type_ref,
|
||||
const char *name);
|
||||
@@ -92,7 +97,7 @@ scc_hir_value_ref_t scc_hir_builder_alloca(scc_hir_builder_t *builder,
|
||||
const char *name);
|
||||
|
||||
#define SCC_HIR_BUILDER_TYPE_FUNC(scc_type) \
|
||||
[[maybe_unused]] static inline scc_hir_type_ref_t \
|
||||
SCC_MAYBE_UNUSED static inline scc_hir_type_ref_t \
|
||||
scc_hir_builder_type_##scc_type(scc_hir_builder_t *builder) { \
|
||||
scc_hir_type_t type_desc; \
|
||||
scc_hir_type_init(&type_desc, SCC_HIR_TYPE_##scc_type); \
|
||||
|
||||
@@ -89,7 +89,9 @@ typedef enum scc_hir_value_tag {
|
||||
SCC_HIR_VALUE_TAG_OP, ///< 二元运算
|
||||
SCC_HIR_VALUE_TAG_BRANCH, ///< 有条件分支
|
||||
SCC_HIR_VALUE_TAG_JUMP, ///< 无条件跳转
|
||||
SCC_HIR_VALUE_TAG_JUMP_INDIRECT, ///< 无条件跳转(地址)
|
||||
SCC_HIR_VALUE_TAG_CALL, ///< 调用函数
|
||||
SCC_HIR_VALUE_TAG_CALL_INDIRECT, ///< 调用函数(地址)
|
||||
SCC_HIR_VALUE_TAG_RET, ///< 函数返回
|
||||
} scc_hir_value_tag_t;
|
||||
|
||||
@@ -222,11 +224,15 @@ struct scc_hir_value {
|
||||
scc_hir_bblock_ref_t true_bblock;
|
||||
scc_hir_bblock_ref_t false_bblock;
|
||||
} branch;
|
||||
struct {
|
||||
union {
|
||||
scc_hir_value_ref_t target_ptr;
|
||||
scc_hir_bblock_ref_t target_bblock;
|
||||
} jump;
|
||||
struct {
|
||||
scc_hir_func_ref_t callee; // TODO function pointer call
|
||||
union {
|
||||
scc_hir_func_ref_t func_ref;
|
||||
scc_hir_value_ref_t ptr_ref;
|
||||
} callee;
|
||||
scc_hir_value_ref_vec_t args;
|
||||
} call;
|
||||
struct {
|
||||
|
||||
@@ -105,7 +105,7 @@ void scc_hir_value_init(scc_hir_value_t *in, const char *name,
|
||||
break;
|
||||
case SCC_HIR_VALUE_TAG_CALL:
|
||||
scc_vec_init(in->data.call.args);
|
||||
in->data.call.callee = 0;
|
||||
in->data.call.callee.func_ref = 0;
|
||||
break;
|
||||
case SCC_HIR_VALUE_TAG_RET:
|
||||
in->data.ret.ret_val = 0;
|
||||
|
||||
@@ -625,7 +625,7 @@ scc_hir_value_ref_t scc_hir_builder_call(scc_hir_builder_t *builder,
|
||||
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
||||
scc_hir_value_t call_node = {0};
|
||||
call_node.tag = SCC_HIR_VALUE_TAG_CALL;
|
||||
call_node.data.call.callee = callee;
|
||||
call_node.data.call.callee.func_ref = callee;
|
||||
|
||||
scc_vec_init(call_node.data.call.args);
|
||||
for (usize i = 0; i < arg_count; i++) {
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#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);
|
||||
static const char *get_node_type_str(scc_hir_value_tag_t tag) {
|
||||
static const char *node_types[] = {
|
||||
[SCC_HIR_VALUE_TAG_NULLPTR] = "NullPtr",
|
||||
@@ -168,9 +170,9 @@ static void dump_jump_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
||||
|
||||
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) {
|
||||
scc_hir_func_t *callee =
|
||||
scc_hir_module_get_func(GET_MODULE(ctx), value->data.call.callee);
|
||||
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>");
|
||||
@@ -256,60 +258,12 @@ void scc_hir_dump_value(scc_hir_dump_t *ctx, scc_hir_value_ref_t value_ref) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void scc_hir_dump_type(scc_hir_dump_t *ctx, scc_hir_type_ref_t type_ref) {
|
||||
if (!ctx || !type_ref) {
|
||||
LOG_ERROR("invalid parameter");
|
||||
return;
|
||||
scc_hashtable_t visited;
|
||||
scc_hashtable_usize_init(&visited);
|
||||
dump_type_with_visited(ctx, type_ref, &visited);
|
||||
scc_hashtable_drop(&visited);
|
||||
}
|
||||
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);
|
||||
scc_hir_dump_type(ctx, type->data.pointer.base);
|
||||
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);
|
||||
scc_hir_dump_type(ctx, type->data.array.base);
|
||||
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);
|
||||
scc_hir_dump_type(ctx, scc_vec_at(type->data.function.params, i));
|
||||
scc_tree_dump_pop(ctx->dump_ctx);
|
||||
}
|
||||
if (type->data.function.ret_type) {
|
||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
||||
scc_hir_dump_type(ctx, type->data.function.ret_type);
|
||||
scc_tree_dump_pop(ctx->dump_ctx);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -379,13 +333,94 @@ void scc_hir_dump_cprog(scc_hir_dump_t *ctx) {
|
||||
}
|
||||
|
||||
// ----- 线性输出(保留原逻辑,改用新 API)-----
|
||||
void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
|
||||
scc_hir_type_ref_t type_ref) {
|
||||
scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref);
|
||||
if (!ctx || !type) {
|
||||
|
||||
// 在 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) {
|
||||
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;
|
||||
}
|
||||
switch (type->tag) {
|
||||
case SCC_HIR_TYPE_unknown:
|
||||
case SCC_HIR_TYPE_void:
|
||||
@@ -407,24 +442,25 @@ void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
|
||||
break;
|
||||
case SCC_HIR_TYPE_ARRAY:
|
||||
scc_tree_dump_append(ctx->dump_ctx, "[");
|
||||
scc_hir_dump_type_linear(ctx, type->data.array.base);
|
||||
dump_type_linear_with_visited(ctx, type->data.array.base, visited);
|
||||
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, "*");
|
||||
scc_hir_dump_type_linear(ctx, type->data.pointer.base);
|
||||
dump_type_linear_with_visited(ctx, type->data.pointer.base, visited);
|
||||
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, ", ");
|
||||
scc_hir_dump_type_linear(ctx,
|
||||
scc_vec_at(type->data.function.params, i));
|
||||
dump_type_linear_with_visited(
|
||||
ctx, scc_vec_at(type->data.function.params, i), visited);
|
||||
}
|
||||
if (type->data.function.ret_type) {
|
||||
scc_tree_dump_append(ctx->dump_ctx, ") -> ");
|
||||
scc_hir_dump_type_linear(ctx, type->data.function.ret_type);
|
||||
dump_type_linear_with_visited(ctx, type->data.function.ret_type,
|
||||
visited);
|
||||
} else {
|
||||
scc_tree_dump_append(ctx->dump_ctx, ")");
|
||||
}
|
||||
@@ -434,9 +470,9 @@ void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
|
||||
scc_tree_dump_append_fmt(ctx->dump_ctx, "%s {",
|
||||
type->tag == SCC_HIR_TYPE_STRUCT ? "struct"
|
||||
: "union");
|
||||
scc_vec_foreach(type->data.aggregate.fields, i) {
|
||||
scc_hir_dump_type_linear(
|
||||
ctx, scc_vec_at(type->data.aggregate.fields, i));
|
||||
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);
|
||||
scc_tree_dump_append(ctx->dump_ctx, ";");
|
||||
}
|
||||
scc_tree_dump_append(ctx->dump_ctx, "}");
|
||||
@@ -447,6 +483,14 @@ void scc_hir_dump_type_linear(scc_hir_dump_t *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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 =
|
||||
@@ -580,8 +624,8 @@ void scc_hir_dump_value_linear(scc_hir_dump_t *ctx,
|
||||
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);
|
||||
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>");
|
||||
@@ -658,7 +702,7 @@ void scc_hir_dump_func_linear(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref,
|
||||
scc_tree_dump_append(ctx->dump_ctx, "<invalid function>");
|
||||
return;
|
||||
}
|
||||
scc_tree_dump_append_fmt(ctx->dump_ctx, "func @%s",
|
||||
scc_tree_dump_node(ctx->dump_ctx, "func @%s",
|
||||
(func->name && func->name[0]) ? func->name
|
||||
: "<unnamed>");
|
||||
|
||||
|
||||
@@ -358,8 +358,8 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value,
|
||||
break;
|
||||
}
|
||||
case SCC_HIR_VALUE_TAG_CALL: {
|
||||
scc_hir_func_t *callee =
|
||||
scc_hir_module_get_func(ctx->hir_module, value->data.call.callee);
|
||||
scc_hir_func_t *callee = scc_hir_module_get_func(
|
||||
ctx->hir_module, value->data.call.callee.func_ref);
|
||||
int arg_count = scc_vec_size(value->data.call.args);
|
||||
scc_lir_val_t *lir_args = scc_malloc(sizeof(scc_lir_val_t) * arg_count);
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
|
||||
69
libs/ir/mir/include/arch/scc_x86_isel.h
Normal file
69
libs/ir/mir/include/arch/scc_x86_isel.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#ifndef __SCC_X86_ISEL_H__
|
||||
#define __SCC_X86_ISEL_H__
|
||||
|
||||
#include <scc_lir_module.h>
|
||||
#include <scc_tree_dump.h>
|
||||
|
||||
#include "../core_pass/scc_abi_lowering.h"
|
||||
#include "scc_x86_mir.h"
|
||||
|
||||
typedef struct scc_x86_64_isel {
|
||||
scc_mir_x86_instr_vec_t instrs;
|
||||
scc_mir_func_t *func;
|
||||
scc_pos_t pos;
|
||||
scc_abi_lowering_t abi_lowering;
|
||||
} scc_x86_64_isel_t;
|
||||
|
||||
void scc_isel_x86_64(scc_mir_module_t *mir_module,
|
||||
const scc_lir_module_t *lir_module,
|
||||
scc_x86_64_isel_t *isel);
|
||||
|
||||
// Utils
|
||||
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src, u8 size);
|
||||
scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
||||
const scc_lir_val_t *val);
|
||||
static inline void emit_direct_call(scc_x86_64_isel_t *isel,
|
||||
const char *callee) {
|
||||
(void)callee;
|
||||
scc_mir_x86_instr_t instr = {0};
|
||||
scc_mir_x86_instr_1(&instr, SCC_X86_IFORM_CALL_NEAR_RELBRZ,
|
||||
scc_x86_op_relbr(0), scc_pos_create());
|
||||
scc_vec_push(isel->instrs, instr);
|
||||
}
|
||||
|
||||
static inline void emit_indirect_call(scc_x86_64_isel_t *isel,
|
||||
scc_x86_operand_value_t reg) {
|
||||
scc_mir_x86_instr_t instr = {0};
|
||||
scc_mir_x86_instr_1(&instr, SCC_X86_IFORM_CALL_NEAR_GPRV, reg,
|
||||
scc_pos_create());
|
||||
}
|
||||
|
||||
static inline void emit_ret(scc_x86_64_isel_t *isel) {
|
||||
scc_mir_x86_instr_t instr = {0};
|
||||
scc_mir_x86_instr_0(&instr, SCC_X86_IFORM_RET_NEAR, scc_pos_create());
|
||||
scc_vec_push(isel->instrs, instr);
|
||||
}
|
||||
|
||||
#define add_instr_0(isel, iform) \
|
||||
do { \
|
||||
scc_mir_x86_instr_t instr; \
|
||||
scc_mir_x86_instr_0(&instr, (iform), (isel)->pos); \
|
||||
scc_vec_push((isel)->instrs, instr); \
|
||||
} while (0)
|
||||
|
||||
#define add_instr_1(isel, iform, arg1) \
|
||||
do { \
|
||||
scc_mir_x86_instr_t instr; \
|
||||
scc_mir_x86_instr_1(&instr, (iform), (arg1), (isel)->pos); \
|
||||
scc_vec_push((isel)->instrs, instr); \
|
||||
} while (0)
|
||||
|
||||
#define add_instr_2(isel, iform, arg1, arg2) \
|
||||
do { \
|
||||
scc_mir_x86_instr_t instr; \
|
||||
scc_mir_x86_instr_2(&instr, (iform), (arg1), (arg2), (isel)->pos); \
|
||||
scc_vec_push((isel)->instrs, instr); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __SCC_X86_ISEL_H__ */
|
||||
134
libs/ir/mir/include/arch/scc_x86_mir.h
Normal file
134
libs/ir/mir/include/arch/scc_x86_mir.h
Normal file
@@ -0,0 +1,134 @@
|
||||
#ifndef __SCC_X86_MIR_H__
|
||||
#define __SCC_X86_MIR_H__
|
||||
|
||||
#include "../scc_mir.h"
|
||||
#include <scc_cfg.h>
|
||||
#include <scc_pos.h>
|
||||
#include <x86/scc_x86_encode.h>
|
||||
#include <x86/scc_x86_iform.h>
|
||||
#include <x86/scc_x86_reg.h>
|
||||
|
||||
typedef struct {
|
||||
int opcode;
|
||||
uint8_t num_operands;
|
||||
scc_x86_operand_value_t operands[6];
|
||||
scc_pos_t src_loc;
|
||||
} scc_x86_instr_t;
|
||||
|
||||
// x86 后端指令:首字段 int opcode(正 = scc_x86_iform_t,负 = 伪指令)
|
||||
typedef union scc_mir_x86_instr {
|
||||
scc_mir_instr_t instr;
|
||||
scc_x86_instr_t x86_instr;
|
||||
} scc_mir_x86_instr_t;
|
||||
|
||||
typedef SCC_VEC(scc_mir_x86_instr_t) scc_mir_x86_instr_vec_t;
|
||||
|
||||
// ── 基本块 values 强制转换 ──────────────────────────────────────────────
|
||||
|
||||
#define SCC_MIR_X86_BBLOCK_INSTRS(bb) ((scc_mir_x86_instr_vec_t *)&bb->values)
|
||||
#define SCC_MIR_X86_BBLOCK_INSTRS_C(bb) \
|
||||
((const scc_mir_x86_instr_vec_t *)&bb->values)
|
||||
|
||||
// ── vreg 编码 ──────────────────────────────────────────────────────────
|
||||
static inline bool scc_x86_op_is_vreg(const scc_x86_operand_value_t *op) {
|
||||
return op->kind == SCC_X86_OPR_REG &&
|
||||
(int)op->reg >= (int)SCC_X86_REG_COUNT;
|
||||
}
|
||||
static inline int scc_x86_op_get_vreg(const scc_x86_operand_value_t *op) {
|
||||
return (int)op->reg - (int)SCC_X86_REG_COUNT;
|
||||
}
|
||||
static inline void scc_x86_op_set_preg(scc_x86_operand_value_t *op,
|
||||
scc_x86_reg_t preg) {
|
||||
op->kind = SCC_X86_OPR_REG;
|
||||
op->reg = preg;
|
||||
}
|
||||
|
||||
// ── 未解析栈槽编码 (base=INVALID, disp=slot_id) ──────────────────────
|
||||
static inline bool scc_x86_op_is_slot(const scc_x86_operand_value_t *op) {
|
||||
return op->kind == SCC_X86_OPR_MEM && op->mem.base == SCC_X86_REG_INVALID;
|
||||
}
|
||||
static inline int scc_x86_op_slot_id(const scc_x86_operand_value_t *op) {
|
||||
return op->mem.disp;
|
||||
}
|
||||
|
||||
// ── 指令构建辅助 ──────────────────────────────────────────────────────
|
||||
static inline void scc_mir_x86_instr_0(scc_mir_x86_instr_t *out, int opcode,
|
||||
scc_pos_t pos) {
|
||||
out->x86_instr.opcode = opcode;
|
||||
out->x86_instr.num_operands = 0;
|
||||
out->x86_instr.src_loc = pos;
|
||||
}
|
||||
static inline void scc_mir_x86_instr_1(scc_mir_x86_instr_t *out, int opcode,
|
||||
scc_x86_operand_value_t op0,
|
||||
scc_pos_t pos) {
|
||||
out->x86_instr.opcode = opcode;
|
||||
out->x86_instr.num_operands = 1;
|
||||
out->x86_instr.operands[0] = op0;
|
||||
out->x86_instr.src_loc = pos;
|
||||
}
|
||||
static inline void scc_mir_x86_instr_2(scc_mir_x86_instr_t *out, int opcode,
|
||||
scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1,
|
||||
scc_pos_t pos) {
|
||||
out->x86_instr.opcode = opcode;
|
||||
out->x86_instr.num_operands = 2;
|
||||
out->x86_instr.operands[0] = op0;
|
||||
out->x86_instr.operands[1] = op1;
|
||||
out->x86_instr.src_loc = pos;
|
||||
}
|
||||
static inline void scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, int opcode,
|
||||
scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1,
|
||||
scc_x86_operand_value_t op2,
|
||||
scc_pos_t pos) {
|
||||
out->x86_instr.opcode = opcode;
|
||||
out->x86_instr.num_operands = 3;
|
||||
out->x86_instr.operands[0] = op0;
|
||||
out->x86_instr.operands[1] = op1;
|
||||
out->x86_instr.operands[2] = op2;
|
||||
out->x86_instr.src_loc = pos;
|
||||
}
|
||||
|
||||
// ── 常用操作数构造器 ──────────────────────────────────────────────────
|
||||
static inline scc_x86_operand_value_t scc_x86_op_preg(scc_x86_reg_t reg) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_REG, .reg = reg};
|
||||
return o;
|
||||
}
|
||||
static inline scc_x86_operand_value_t scc_x86_op_vreg(int vreg) {
|
||||
scc_x86_operand_value_t o = {
|
||||
.kind = SCC_X86_OPR_REG,
|
||||
.reg = (scc_x86_reg_t)((int)SCC_X86_REG_COUNT + vreg)};
|
||||
return o;
|
||||
}
|
||||
static inline scc_x86_operand_value_t scc_x86_op_relbr(i32 rel) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_RELBR, .imm = rel};
|
||||
return o;
|
||||
}
|
||||
static inline scc_x86_operand_value_t scc_x86_op_imm(i64 imm) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_IMM, .imm = imm};
|
||||
return o;
|
||||
}
|
||||
// slot_id 编码为 base=INVALID, disp=slot_id
|
||||
static inline scc_x86_operand_value_t scc_x86_op_slot(int slot_id) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_MEM};
|
||||
o.mem.base = SCC_X86_REG_INVALID;
|
||||
o.mem.index = SCC_X86_REG_INVALID;
|
||||
o.mem.scale = 1;
|
||||
o.mem.disp = slot_id;
|
||||
return o;
|
||||
}
|
||||
static inline scc_x86_operand_value_t scc_x86_op_symbol(const char *sym) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_IMM,
|
||||
.imm = (i64)(usize)sym};
|
||||
(void)o;
|
||||
// symbol 暂用一个近似值占位,编码阶段处理重定位
|
||||
return o;
|
||||
}
|
||||
static inline scc_x86_operand_value_t
|
||||
scc_x86_op_block(scc_cfg_bblock_id_t bid) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_RELBR, .imm = 0};
|
||||
(void)bid;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif /* __SCC_X86_MIR_H__ */
|
||||
8
libs/ir/mir/include/arch/scc_x86_reg_alloc.h
Normal file
8
libs/ir/mir/include/arch/scc_x86_reg_alloc.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef __SCC_X86_REG_ALLOC_H__
|
||||
#define __SCC_X86_REG_ALLOC_H__
|
||||
|
||||
#include "../core_pass/scc_reg_alloc.h"
|
||||
|
||||
void scc_reg_alloc_fill_arch_x86(scc_reg_alloc_op_t *ops);
|
||||
|
||||
#endif /* __SCC_X86_REG_ALLOC_H__ */
|
||||
@@ -1,66 +0,0 @@
|
||||
#ifndef __SCC_X86_64_ISEL_H__
|
||||
#define __SCC_X86_64_ISEL_H__
|
||||
|
||||
#include <scc_lir_module.h>
|
||||
#include <scc_tree_dump.h>
|
||||
|
||||
#include <x86/scc_x86_iform.h>
|
||||
#include <x86/scc_x86_reg.h>
|
||||
|
||||
#include "../core_pass/scc_abi_lowering.h"
|
||||
#include "../scc_mir_module.h"
|
||||
|
||||
typedef struct scc_x86_64_isel {
|
||||
scc_mir_instr_vec_t instrs;
|
||||
scc_mir_func_t *func;
|
||||
scc_abi_lowering_t abi_lowering;
|
||||
} scc_x86_64_isel_t;
|
||||
|
||||
void scc_isel_x86_64(scc_mir_module_t *mir_module,
|
||||
const scc_lir_module_t *lir_module,
|
||||
scc_x86_64_isel_t *isel);
|
||||
|
||||
static void add_instr(scc_x86_64_isel_t *isel, const scc_mir_instr_t *instr) {
|
||||
scc_vec_push(isel->instrs, *instr);
|
||||
}
|
||||
|
||||
static inline void add_instr_0(scc_x86_64_isel_t *isel,
|
||||
scc_x86_iform_t opcode) {
|
||||
scc_mir_instr_t out = {.opcode = opcode, .num_operands = 0};
|
||||
add_instr(isel, &out);
|
||||
}
|
||||
|
||||
static inline void add_instr_1(scc_x86_64_isel_t *isel, scc_x86_iform_t opcode,
|
||||
scc_mir_operand_t op1) {
|
||||
scc_mir_instr_t out = {.opcode = opcode, .num_operands = 1};
|
||||
out.operands[0] = op1;
|
||||
add_instr(isel, &out);
|
||||
}
|
||||
|
||||
static inline void add_instr_2(scc_x86_64_isel_t *isel, scc_x86_iform_t opcode,
|
||||
scc_mir_operand_t op1, scc_mir_operand_t op2) {
|
||||
scc_mir_instr_t out = {.opcode = opcode, .num_operands = 2};
|
||||
out.operands[0] = op1;
|
||||
out.operands[1] = op2;
|
||||
add_instr(isel, &out);
|
||||
}
|
||||
|
||||
static inline scc_mir_operand_t reg_operand(scc_x86_reg_t reg) {
|
||||
return (scc_mir_operand_t){.kind = SCC_MIR_OP_PREG, .preg = reg};
|
||||
}
|
||||
|
||||
// Utils
|
||||
|
||||
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
||||
scc_mir_operand_t src, u8 size);
|
||||
scc_mir_operand_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
||||
const scc_lir_val_t *val);
|
||||
static inline void emit_call(scc_x86_64_isel_t *isel, const char *callee) {
|
||||
scc_mir_operand_t sym = {.kind = SCC_MIR_OP_SYMBOL, .symbol = callee};
|
||||
add_instr_1(isel, SCC_X86_IFORM_CALL_NEAR_GPRV, sym);
|
||||
}
|
||||
static inline void emit_ret(scc_x86_64_isel_t *isel) {
|
||||
add_instr_0(isel, SCC_X86_IFORM_RET_NEAR);
|
||||
}
|
||||
|
||||
#endif /* __SCC_X86_64_ISEL_H__ */
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef __SCC_X86_64_REG_ALLOC_H__
|
||||
#define __SCC_X86_64_REG_ALLOC_H__
|
||||
|
||||
#include "../core_pass/scc_reg_alloc.h"
|
||||
|
||||
void scc_reg_alloc_fill_arch_x86(scc_reg_alloc_op_t *ops);
|
||||
|
||||
#endif /* __SCC_X86_64_REG_ALLOC_H__ */
|
||||
@@ -4,9 +4,12 @@
|
||||
#include "../scc_mir_module.h"
|
||||
#include <scc_lir_module.h>
|
||||
|
||||
// 所有回调通过 void* userdata / void* out_op 保持类型无关
|
||||
typedef void (*scc_abi_lower_fn)(void *user_data, const scc_lir_instr_t *instr);
|
||||
typedef scc_mir_operand_t (*scc_abi_lower_param_fn)(void *userdata,
|
||||
const scc_lir_val_t *val);
|
||||
// lower_param 将 LIR 值转化为后端操作数,写入 out_op(后端知道实际类型)
|
||||
typedef void (*scc_abi_lower_param_fn)(void *userdata,
|
||||
const scc_lir_val_t *val,
|
||||
void *out_op);
|
||||
|
||||
typedef struct scc_abi_lowering {
|
||||
scc_abi_lower_fn lower_call;
|
||||
|
||||
@@ -3,10 +3,15 @@
|
||||
|
||||
#include "../scc_mir_module.h"
|
||||
|
||||
typedef struct scc_frame_layout {
|
||||
scc_mir_func_t *func;
|
||||
} scc_frame_layout_t;
|
||||
struct scc_frame_layout;
|
||||
typedef struct scc_frame_layout scc_frame_layout_t;
|
||||
typedef void (*scc_frame_layout_impl_fn)(scc_frame_layout_t *ctx,
|
||||
scc_mir_module_t *mir_module,
|
||||
scc_mir_func_t *mir_func);
|
||||
|
||||
void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module);
|
||||
struct scc_frame_layout {
|
||||
scc_frame_layout_impl_fn impl_fn;
|
||||
int offset;
|
||||
};
|
||||
|
||||
#endif /* __SCC_FRAME_LAYOUT_H__ */
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#ifndef __SCC_PROLOG_EPILOG_H__
|
||||
#define __SCC_PROLOG_EPILOG_H__
|
||||
|
||||
#include "../scc_mir_module.h"
|
||||
#include <scc_lir_module.h>
|
||||
#include <scc_mir_module.h>
|
||||
typedef void (*scc_prolog_epilog_fn)(void *userdata,
|
||||
|
||||
typedef void (*scc_prolog_epilog_fn)(scc_mir_instr_vec_t *userdata,
|
||||
const scc_mir_func_t *func);
|
||||
typedef int (*scc_need_epilog_fn)(const scc_mir_instr_t *instr);
|
||||
|
||||
typedef struct scc_prolog_epilog {
|
||||
scc_prolog_epilog_fn prolog;
|
||||
scc_prolog_epilog_fn epilog;
|
||||
scc_need_epilog_fn need_epilog;
|
||||
} scc_prolog_epilog_t;
|
||||
|
||||
#endif /* __SCC_PROLOG_EPILOG_H__ */
|
||||
|
||||
@@ -7,37 +7,46 @@ typedef enum {
|
||||
SCC_REG_ALLOC_OP_ACCESS_READ = 0,
|
||||
SCC_REG_ALLOC_OP_ACCESS_WRITE = 1,
|
||||
SCC_REG_ALLOC_OP_ACCESS_READWRITE = 2,
|
||||
} scc_op_access_t;
|
||||
} scc_reg_op_access_t;
|
||||
|
||||
// 后端回调表 —— 框架通过回调获取/修改指令,不感知具体布局
|
||||
typedef struct scc_reg_alloc_op {
|
||||
// preg → [slot]
|
||||
void (*emit_spill)(scc_mir_instr_vec_t *ctx, int preg, int slot);
|
||||
// [slot] → preg
|
||||
void (*emit_reload)(scc_mir_instr_vec_t *ctx, int preg, int slot);
|
||||
// preg → preg
|
||||
void (*emit_copy)(scc_mir_instr_vec_t *ctx, int dst_preg, int src_preg,
|
||||
int size);
|
||||
|
||||
// 通用寄存器申请 / 释放
|
||||
int (*acquire_reg)(void *ctx); // 返回一个物理寄存器编号
|
||||
void (*release_reg)(void *ctx, int preg); // 归还该寄存器
|
||||
|
||||
// 显式标记某个寄存器已占用 / 未占用(用于隐式寄存器、固定分配等)
|
||||
// ── 寄存器池 ──
|
||||
int (*acquire_reg)(void *ctx);
|
||||
void (*release_reg)(void *ctx, int preg);
|
||||
void (*mark_reg_used)(void *ctx, int preg);
|
||||
void (*clean_mark_regs)(void *ctx);
|
||||
|
||||
// ---- 指令信息查询(只读) ----
|
||||
scc_op_access_t (*get_operand_access)(void *ctx, int opcode, int op_idx);
|
||||
// ── 指令信息 ──
|
||||
int (*instr_opcode)(const void *instr);
|
||||
int (*instr_num_operands)(const void *instr);
|
||||
bool (*op_is_vreg)(const void *instr, int idx);
|
||||
int (*op_get_vreg)(const void *instr, int idx);
|
||||
void (*op_set_preg)(void *instr, int idx, int preg);
|
||||
void (*op_set_slot)(void *instr, int idx, int slot);
|
||||
// 读写属性与隐式寄存器
|
||||
scc_reg_op_access_t (*get_operand_access)(void *ctx, int opcode,
|
||||
int op_idx);
|
||||
void (*get_implicit_regs)(void *ctx, int opcode, const int **out_uses,
|
||||
const int **out_defs);
|
||||
|
||||
// ── 伪指令处理 ──
|
||||
bool (*is_pseudo)(const void *instr);
|
||||
void (*handle_pseudo)(scc_mir_func_t *func, void *instr, void *out);
|
||||
|
||||
// ── 溢出/重载(写入 out 向量) ──
|
||||
void (*emit_spill)(void *out, int preg, int slot);
|
||||
void (*emit_reload)(void *out, int preg, int slot);
|
||||
void (*emit_copy)(void *out, int dst_preg, int src_preg, int size);
|
||||
} scc_reg_alloc_op_t;
|
||||
|
||||
typedef struct scc_reg_alloc_ctx {
|
||||
scc_reg_alloc_op_t ops;
|
||||
scc_mir_module_t *module;
|
||||
scc_mir_func_t *func;
|
||||
scc_mir_instr_vec_t *instrs;
|
||||
} scc_reg_alloc_ctx_t;
|
||||
|
||||
// 通用寄存器分配入口:遍历所有函数/基本块,对每条指令做 vreg → preg 分配
|
||||
void scc_reg_alloc(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module);
|
||||
|
||||
#endif /* __SCC_REG_ALLOC__ */
|
||||
#endif /* __SCC_REG_ALLOC_H__ */
|
||||
|
||||
@@ -1,51 +1,29 @@
|
||||
// scc_mir.h (示意)
|
||||
|
||||
#ifndef __SCC_MIR_H__
|
||||
#define __SCC_MIR_H__
|
||||
|
||||
#include <scc_lir.h>
|
||||
#include <scc_cfg.h>
|
||||
|
||||
// 伪指令 opcode(负数),所有后端通用约定
|
||||
typedef enum {
|
||||
SCC_MIR_OP_NONE,
|
||||
SCC_MIR_OP_MEM, // 内存访问
|
||||
SCC_MIR_OP_VREG, // 虚拟寄存器
|
||||
SCC_MIR_OP_PREG, // 物理寄存器
|
||||
SCC_MIR_OP_IMM, // 立即数
|
||||
SCC_MIR_OP_SYMBOL, // 符号地址(用于重定位)
|
||||
SCC_MIR_OP_BLOCK // 基本块引用(label)
|
||||
} scc_mir_op_kind_t;
|
||||
|
||||
typedef struct scc_mir_operand {
|
||||
scc_mir_op_kind_t kind;
|
||||
union {
|
||||
int vreg; // 虚拟寄存器索引
|
||||
int preg; // 物理寄存器
|
||||
i64 imm; // 立即数
|
||||
const char *symbol; // 符号名
|
||||
int stack_slot; // 栈槽 ID (由 FrameLayout 分配)
|
||||
scc_lir_bblock_id_t block_id; // 目标基本块
|
||||
};
|
||||
} scc_mir_operand_t;
|
||||
|
||||
typedef enum {
|
||||
SCC_MIR_PSUEDO_ALLOCA = -1,
|
||||
} scc_mir_psuedo_op_t;
|
||||
SCC_MIR_PSEUDO_NONE = 0,
|
||||
SCC_MIR_PSEUDO_ALLOCA = -1,
|
||||
SCC_MIR_PSEUDO_VA_START = -2,
|
||||
} scc_mir_pseudo_t;
|
||||
|
||||
typedef struct scc_mir_instr {
|
||||
int opcode; // 目标特定的指令编码 (如 X86::ADD32rr)
|
||||
int num_operands; // 实际使用的操作数个数
|
||||
scc_mir_operand_t
|
||||
operands[8]; // 固定小数组,RISC 风格指令通常不超过 4 操作数
|
||||
scc_pos_t src_loc; // 调试信息 (继承自 LIR)
|
||||
int opcode;
|
||||
union {
|
||||
struct {
|
||||
int size;
|
||||
int align;
|
||||
int vreg;
|
||||
} alloc;
|
||||
} data;
|
||||
} scc_mir_instr_t;
|
||||
typedef SCC_VEC(scc_mir_instr_t) scc_mir_instr_vec_t;
|
||||
|
||||
typedef scc_cfg_bblock_t scc_mir_bblock_t;
|
||||
typedef struct scc_mir_bblock_meta {
|
||||
} scc_mir_bblock_meta_t;
|
||||
#define SCC_MIR_BBLOCK_VALUES(bblock) \
|
||||
((scc_mir_instr_vec_t *)&((bblock)->values))
|
||||
#define SCC_MIR_BBLOCK_VALUES_PTR(bb) ((void *)(&(bb)->values))
|
||||
|
||||
// 栈槽信息(由 FrameLayout Pass 填充)
|
||||
typedef struct scc_mir_stack_slot {
|
||||
int slot_id;
|
||||
int size; // 通常是 8 字节 (指针大小)
|
||||
@@ -54,18 +32,23 @@ typedef struct scc_mir_stack_slot {
|
||||
} scc_mir_stack_slot_t;
|
||||
typedef SCC_VEC(scc_mir_stack_slot_t) scc_mir_stack_slot_vec_t;
|
||||
|
||||
typedef scc_cfg_bblock_t scc_mir_bblock_t;
|
||||
|
||||
// 函数元数据 —— 不包含任何指令结构,由各后端自行定义指令布局
|
||||
typedef scc_cfg_func_t scc_mir_func_t;
|
||||
typedef struct scc_mir_func_meta {
|
||||
// 栈帧信息 (由 FrameLayout Pass 填充)
|
||||
int need_va_args;
|
||||
int frame_size;
|
||||
int stack_alignment;
|
||||
int vregs_count;
|
||||
|
||||
// 寄存器分配信息
|
||||
void *target_data; // 目标后端私有数据,例如 x86_64_func_info_t*
|
||||
|
||||
scc_mir_stack_slot_vec_t stack_slots;
|
||||
// vreg -> phys reg and stack slot index
|
||||
// positive means stack slot index
|
||||
// negative means physic register
|
||||
// vreg -> phys reg / stack slot
|
||||
// 0 = not mapped (still a vreg)
|
||||
// >0 = stack slot index
|
||||
// <0 = physical register (negated)
|
||||
scc_hashtable_t vreg2physic;
|
||||
} scc_mir_func_meta_t;
|
||||
#define SCC_MIR_FUNC_META(func) ((scc_mir_func_meta_t *)(func)->meta)
|
||||
@@ -73,10 +56,32 @@ typedef struct scc_mir_func_meta {
|
||||
void scc_mir_func_meta_init(scc_mir_func_meta_t *func_meta);
|
||||
|
||||
int scc_mir_alloc_vreg(scc_mir_func_t *func);
|
||||
void scc_mir_vreg_op(const scc_mir_func_t *func, int vreg,
|
||||
scc_mir_operand_t *out);
|
||||
|
||||
void scc_mir_vreg_map2preg(scc_mir_func_t *func, int vreg, int preg);
|
||||
int scc_mir_vreg_map2slot(scc_mir_func_t *func, int vreg, int size, int align);
|
||||
|
||||
// 从 vreg2physic 表中查询映射结果:
|
||||
// 返回 0 → 该 vreg 仍为 vreg,未映射
|
||||
// 返回 1 → 已映射到物理寄存器,*out_preg 有效
|
||||
// 返回 -1 → 已溢出到栈槽,*out_slot 有效
|
||||
static inline int scc_mir_vreg_lookup(const scc_mir_func_t *func, int vreg,
|
||||
int *out) {
|
||||
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||
isize idx =
|
||||
(isize)scc_hashtable_get(&meta->vreg2physic, (void *)(usize)vreg);
|
||||
if (idx == 0)
|
||||
return 0;
|
||||
if (idx < 0) {
|
||||
*out = (int)-idx;
|
||||
return 1;
|
||||
}
|
||||
*out = (int)idx;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline scc_mir_stack_slot_t *
|
||||
scc_mir_unsafe_slot(const scc_mir_func_t *func, int slot) {
|
||||
Assert(slot > 0);
|
||||
return &scc_vec_at(SCC_MIR_FUNC_META(func)->stack_slots, slot);
|
||||
}
|
||||
|
||||
#endif /* __SCC_MIR_H__ */
|
||||
|
||||
@@ -4,9 +4,16 @@
|
||||
#include "scc_mir.h"
|
||||
#include <scc_lir_module.h>
|
||||
|
||||
typedef SCC_VEC(char) scc_mir_instr_vec_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} scc_mir_symbol_t;
|
||||
typedef scc_lir_symbol_meta_vec_t scc_mir_symbol_meta_vec_t;
|
||||
|
||||
typedef SCC_VEC(scc_mir_func_meta_t *) scc_mir_func_meta_vec_t;
|
||||
typedef struct scc_mir_module {
|
||||
usize instr_size;
|
||||
scc_cfg_module_t cfg_module;
|
||||
scc_mir_func_meta_vec_t func_metas;
|
||||
scc_mir_symbol_meta_vec_t symbol_metas;
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
#ifndef __SCC_WIN64_H__
|
||||
#define __SCC_WIN64_H__
|
||||
|
||||
#include "../arch/x86_64_isel.h"
|
||||
#include "../arch/scc_x86_isel.h"
|
||||
#include "../core_pass/scc_frame_layout.h"
|
||||
#include "../core_pass/scc_prolog_epilog.h"
|
||||
#include "../core_pass/scc_reg_alloc.h"
|
||||
|
||||
void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering);
|
||||
void scc_reg_alloc_fill_win_x64(scc_reg_alloc_op_t *ops);
|
||||
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_prolog_epilog_init(scc_prolog_epilog_t *ctx);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <arch/x86_64_isel.h>
|
||||
#include <arch/scc_x86_isel.h>
|
||||
|
||||
#include <x86/scc_x86_iform.c>
|
||||
#include <x86/scc_x86_reg.c>
|
||||
@@ -9,35 +9,40 @@ static const char *preg_name(int preg_id) {
|
||||
return scc_x86_reg_table[preg_id].display_str;
|
||||
}
|
||||
|
||||
void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_instr_t *instr) {
|
||||
scc_x86_iform_t iform = instr->opcode;
|
||||
void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_x86_instr_t *instr) {
|
||||
if (instr->x86_instr.opcode >= SCC_X86_IFORM_COUNT ||
|
||||
instr->x86_instr.opcode < 0) {
|
||||
scc_tree_dump_append_fmt(td, " ???");
|
||||
return;
|
||||
}
|
||||
scc_x86_iform_t iform = instr->x86_instr.opcode;
|
||||
const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform];
|
||||
scc_tree_dump_append_fmt(td, " %s", info->iform_name);
|
||||
// Assert(instr->num_operands == info->num_ops);
|
||||
for (int i = 0; i < instr->num_operands; i += 1) {
|
||||
for (int i = 0; i < instr->x86_instr.num_operands; i += 1) {
|
||||
if (i == 0)
|
||||
scc_tree_dump_append(td, " ");
|
||||
else
|
||||
scc_tree_dump_append_fmt(td, ", ");
|
||||
scc_mir_operand_t *op = &instr->operands[i];
|
||||
const scc_x86_operand_value_t *op = &instr->x86_instr.operands[i];
|
||||
switch (op->kind) {
|
||||
case SCC_MIR_OP_VREG:
|
||||
scc_tree_dump_append_fmt(td, "%%%d", op->vreg);
|
||||
case SCC_X86_OPR_REG:
|
||||
if (scc_x86_op_is_vreg(op))
|
||||
scc_tree_dump_append_fmt(td, "%%%d", scc_x86_op_get_vreg(op));
|
||||
else
|
||||
scc_tree_dump_append_fmt(td, "$%s", preg_name(op->reg));
|
||||
break;
|
||||
case SCC_MIR_OP_PREG:
|
||||
scc_tree_dump_append_fmt(td, "$%s", preg_name(op->preg));
|
||||
break;
|
||||
case SCC_MIR_OP_IMM:
|
||||
case SCC_X86_OPR_IMM:
|
||||
scc_tree_dump_append_fmt(td, "%ld", op->imm);
|
||||
break;
|
||||
case SCC_MIR_OP_BLOCK:
|
||||
scc_tree_dump_append_fmt(td, "#BB%d", op->block_id);
|
||||
case SCC_X86_OPR_MEM:
|
||||
if (scc_x86_op_is_slot(op))
|
||||
scc_tree_dump_append_fmt(td, "[slot:%d]",
|
||||
scc_x86_op_slot_id(op));
|
||||
else
|
||||
scc_tree_dump_append_fmt(td, "[sp%+d]", op->mem.disp);
|
||||
break;
|
||||
case SCC_MIR_OP_SYMBOL:
|
||||
scc_tree_dump_append_fmt(td, "@%s", op->symbol);
|
||||
break;
|
||||
case SCC_MIR_OP_MEM:
|
||||
scc_tree_dump_append_fmt(td, "[%d]", op->stack_slot);
|
||||
case SCC_X86_OPR_RELBR:
|
||||
scc_tree_dump_append(td, "label");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -45,35 +50,36 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_instr_t *instr) {
|
||||
}
|
||||
}
|
||||
|
||||
// 将 LIR 值转换为 MIR 操作数
|
||||
scc_mir_operand_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
||||
// 将 LIR 值转换为 x86 操作数
|
||||
scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
||||
const scc_lir_val_t *val) {
|
||||
scc_mir_operand_t op = {0};
|
||||
scc_x86_operand_value_t op = {0};
|
||||
switch (val->kind) {
|
||||
case SCC_LIR_INSTR_KIND_NONE:
|
||||
op.kind = SCC_MIR_OP_NONE;
|
||||
op.kind = SCC_X86_OPR_NONE;
|
||||
break;
|
||||
case SCC_LIR_INSTR_KIND_VREG:
|
||||
op.kind = SCC_MIR_OP_VREG;
|
||||
op.vreg = val->data.reg;
|
||||
op = scc_x86_op_vreg(val->data.reg);
|
||||
int id = 0;
|
||||
int ret = scc_mir_vreg_lookup(isel->func, val->data.reg, &id);
|
||||
if (ret > 0) {
|
||||
op = scc_x86_op_preg(id);
|
||||
} else if (ret < 0) {
|
||||
op = scc_x86_op_slot(id);
|
||||
}
|
||||
break;
|
||||
case SCC_LIR_INSTR_KIND_IMM:
|
||||
op.kind = SCC_MIR_OP_IMM;
|
||||
// FIXME hack ap
|
||||
op.imm = val->data.imm.data.digit;
|
||||
op = scc_x86_op_imm(val->data.imm.data.digit);
|
||||
break;
|
||||
case SCC_LIR_INSTR_KIND_FIMM:
|
||||
// 浮点立即数暂时作为普通立即数处理(后端需特殊处理)
|
||||
op.kind = SCC_MIR_OP_IMM;
|
||||
op.imm = *(i64 *)&val->data.fimm;
|
||||
op = scc_x86_op_imm(*(i64 *)&val->data.fimm);
|
||||
break;
|
||||
case SCC_LIR_INSTR_KIND_SYMBOL:
|
||||
op.kind = SCC_MIR_OP_SYMBOL;
|
||||
op.symbol = val->data.symbol;
|
||||
op = scc_x86_op_symbol(val->data.symbol);
|
||||
break;
|
||||
case SCC_LIR_INSTR_KIND_ARG:
|
||||
Assert(isel->abi_lowering.lower_param);
|
||||
op = isel->abi_lowering.lower_param(isel, val);
|
||||
isel->abi_lowering.lower_param(isel, val, &op);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@@ -82,39 +88,40 @@ scc_mir_operand_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
||||
}
|
||||
|
||||
// 虚拟临时寄存器分配(简单递增)
|
||||
static scc_mir_operand_t new_vreg_temp(scc_x86_64_isel_t *isel) {
|
||||
return (scc_mir_operand_t){.kind = SCC_MIR_OP_VREG,
|
||||
.vreg = scc_mir_alloc_vreg(isel->func)};
|
||||
static scc_x86_operand_value_t new_vreg_temp(scc_x86_64_isel_t *isel) {
|
||||
return scc_x86_op_vreg(scc_mir_alloc_vreg(isel->func));
|
||||
}
|
||||
|
||||
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
||||
scc_mir_operand_t src, u8 size) {
|
||||
if (dst.kind == SCC_MIR_OP_VREG || dst.kind == SCC_MIR_OP_PREG) {
|
||||
if (src.kind == SCC_MIR_OP_VREG || src.kind == SCC_MIR_OP_PREG) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89, dst, src);
|
||||
} else if (src.kind == SCC_MIR_OP_IMM) {
|
||||
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src, u8 size) {
|
||||
|
||||
if (dst.kind == SCC_X86_OPR_REG) {
|
||||
if (src.kind == SCC_X86_OPR_REG) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_8B, dst, src);
|
||||
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||
add_instr_2(isel,
|
||||
(size == 8) ? SCC_X86_IFORM_MOV_GPRV_IMMZ
|
||||
: SCC_X86_IFORM_MOV_GPRV_IMMV,
|
||||
dst, src);
|
||||
} else if (src.kind == SCC_MIR_OP_SYMBOL) {
|
||||
} else if (src.kind == SCC_X86_OPR_IMM && src.imm == 0) {
|
||||
// 特殊:符号作为立即数地址
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, dst, src);
|
||||
} else if (src.kind == SCC_MIR_OP_MEM) {
|
||||
} else if (src.kind == SCC_X86_OPR_MEM) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, src);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else if (dst.kind == SCC_MIR_OP_MEM) {
|
||||
if (src.kind == SCC_MIR_OP_VREG || src.kind == SCC_MIR_OP_PREG) {
|
||||
} else if (dst.kind == SCC_X86_OPR_MEM) {
|
||||
if (src.kind == SCC_X86_OPR_REG) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, src);
|
||||
} else if (src.kind == SCC_MIR_OP_IMM) {
|
||||
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_IMMZ, dst, src);
|
||||
} else if (src.kind == SCC_MIR_OP_SYMBOL) {
|
||||
scc_mir_operand_t temp = new_vreg_temp(isel);
|
||||
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||
scc_x86_operand_value_t temp = new_vreg_temp(isel);
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, temp, src);
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, temp);
|
||||
} else if (src.kind == SCC_MIR_OP_MEM) {
|
||||
scc_mir_operand_t temp = new_vreg_temp(isel);
|
||||
} else if (src.kind == SCC_X86_OPR_MEM) {
|
||||
scc_x86_operand_value_t temp = new_vreg_temp(isel);
|
||||
scc_x86_emit_move(isel, temp, src, size);
|
||||
scc_x86_emit_move(isel, dst, temp, size);
|
||||
} else {
|
||||
@@ -125,19 +132,18 @@ void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_compare(scc_x86_64_isel_t *isel, scc_mir_operand_t op0,
|
||||
scc_mir_operand_t op1, u8 size) {
|
||||
// cmp op0, op1 (注意 x86 是 cmp a, b 即 a - b)
|
||||
if (op0.kind == SCC_MIR_OP_VREG && op1.kind == SCC_MIR_OP_IMM) {
|
||||
static void emit_compare(scc_x86_64_isel_t *isel, scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1, u8 size) {
|
||||
(void)size;
|
||||
if (scc_x86_op_is_vreg(&op0) && op1.kind == SCC_X86_OPR_IMM) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_IMMZ, op0, op1);
|
||||
} else if (op0.kind == SCC_MIR_OP_VREG && op1.kind == SCC_MIR_OP_VREG) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_39, op0, op1);
|
||||
} else if (scc_x86_op_is_vreg(&op0) && scc_x86_op_is_vreg(&op1)) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_3B, op0, op1);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
/* 条件码到 setcc 指令的映射 */
|
||||
static scc_x86_iform_t cond_to_setcc(scc_lir_cond_t cond) {
|
||||
switch (cond) {
|
||||
case SCC_LIR_COND_EQ:
|
||||
@@ -149,58 +155,61 @@ static scc_x86_iform_t cond_to_setcc(scc_lir_cond_t cond) {
|
||||
case SCC_LIR_COND_SLE:
|
||||
return SCC_X86_IFORM_SETLE_GPR8;
|
||||
case SCC_LIR_COND_SGT:
|
||||
return SCC_X86_IFORM_SETNLE_GPR8; // SETG
|
||||
return SCC_X86_IFORM_SETNLE_GPR8;
|
||||
case SCC_LIR_COND_SGE:
|
||||
return SCC_X86_IFORM_SETNL_GPR8; // SETGE
|
||||
return SCC_X86_IFORM_SETNL_GPR8;
|
||||
case SCC_LIR_COND_ULT:
|
||||
return SCC_X86_IFORM_SETB_GPR8;
|
||||
case SCC_LIR_COND_ULE:
|
||||
return SCC_X86_IFORM_SETBE_GPR8;
|
||||
case SCC_LIR_COND_UGT:
|
||||
return SCC_X86_IFORM_SETNBE_GPR8; // SETA
|
||||
return SCC_X86_IFORM_SETNBE_GPR8;
|
||||
case SCC_LIR_COND_UGE:
|
||||
return SCC_X86_IFORM_SETNB_GPR8; // SETAE
|
||||
return SCC_X86_IFORM_SETNB_GPR8;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_copy_if_needed(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
||||
scc_mir_operand_t src0, u8 size) {
|
||||
if (dst.kind == SCC_MIR_OP_VREG && src0.kind == SCC_MIR_OP_VREG &&
|
||||
dst.vreg == src0.vreg) {
|
||||
static void emit_copy_if_needed(scc_x86_64_isel_t *isel,
|
||||
scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src0, u8 size) {
|
||||
if (scc_x86_op_is_vreg(&dst) && scc_x86_op_is_vreg(&src0) &&
|
||||
scc_x86_op_get_vreg(&dst) == scc_x86_op_get_vreg(&src0)) {
|
||||
return;
|
||||
}
|
||||
scc_x86_emit_move(isel, dst, src0, size);
|
||||
}
|
||||
|
||||
static void emit_binary_op(scc_x86_64_isel_t *isel, scc_lir_op_t op,
|
||||
scc_mir_operand_t dst, scc_mir_operand_t src0,
|
||||
scc_mir_operand_t src1, u8 size) {
|
||||
scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src0,
|
||||
scc_x86_operand_value_t src1, u8 size) {
|
||||
(void)size;
|
||||
emit_copy_if_needed(isel, dst, src0, size);
|
||||
|
||||
bool is_imm = (src1.kind == SCC_MIR_OP_IMM);
|
||||
bool is_imm = (src1.kind == SCC_X86_OPR_IMM);
|
||||
scc_x86_iform_t iform;
|
||||
switch (op) {
|
||||
case SCC_LIR_ADD:
|
||||
iform = is_imm ? SCC_X86_IFORM_ADD_GPRV_IMMZ
|
||||
: SCC_X86_IFORM_ADD_GPRV_GPRV_01;
|
||||
: SCC_X86_IFORM_ADD_GPRV_GPRV_03;
|
||||
break;
|
||||
case SCC_LIR_SUB:
|
||||
iform = is_imm ? SCC_X86_IFORM_SUB_GPRV_IMMZ
|
||||
: SCC_X86_IFORM_SUB_GPRV_GPRV_29;
|
||||
: SCC_X86_IFORM_SUB_GPRV_GPRV_2B;
|
||||
break;
|
||||
case SCC_LIR_AND:
|
||||
iform = is_imm ? SCC_X86_IFORM_AND_GPRV_IMMZ
|
||||
: SCC_X86_IFORM_AND_GPRV_GPRV_21;
|
||||
: SCC_X86_IFORM_AND_GPRV_GPRV_23;
|
||||
break;
|
||||
case SCC_LIR_OR:
|
||||
iform =
|
||||
is_imm ? SCC_X86_IFORM_OR_GPRV_IMMZ : SCC_X86_IFORM_OR_GPRV_GPRV_09;
|
||||
is_imm ? SCC_X86_IFORM_OR_GPRV_IMMZ : SCC_X86_IFORM_OR_GPRV_GPRV_0B;
|
||||
break;
|
||||
case SCC_LIR_XOR:
|
||||
iform = is_imm ? SCC_X86_IFORM_XOR_GPRV_IMMZ
|
||||
: SCC_X86_IFORM_XOR_GPRV_GPRV_31;
|
||||
: SCC_X86_IFORM_XOR_GPRV_GPRV_33;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@@ -208,32 +217,22 @@ static void emit_binary_op(scc_x86_64_isel_t *isel, scc_lir_op_t op,
|
||||
add_instr_2(isel, iform, dst, src1);
|
||||
}
|
||||
|
||||
static scc_mir_operand_t stack_slot_op(int offset) {
|
||||
return (scc_mir_operand_t){.kind = SCC_MIR_OP_MEM, .stack_slot = offset};
|
||||
static void emit_spill_load(scc_x86_64_isel_t *isel, int vreg, int slot) {
|
||||
scc_x86_operand_value_t dst = scc_x86_op_vreg(vreg);
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, scc_x86_op_slot(slot));
|
||||
}
|
||||
|
||||
static void emit_spill_load(scc_x86_64_isel_t *isel, int vreg, int offset) {
|
||||
scc_mir_operand_t dst = {.kind = SCC_MIR_OP_VREG, .vreg = vreg};
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, stack_slot_op(offset));
|
||||
static void emit_spill_store(scc_x86_64_isel_t *isel, int vreg, int slot) {
|
||||
scc_x86_operand_value_t src = scc_x86_op_vreg(vreg);
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, scc_x86_op_slot(slot), src);
|
||||
}
|
||||
|
||||
static void emit_spill_store(scc_x86_64_isel_t *isel, int vreg, int offset) {
|
||||
scc_mir_operand_t src = {.kind = SCC_MIR_OP_VREG, .vreg = vreg};
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, stack_slot_op(offset), src);
|
||||
}
|
||||
|
||||
// static void emit_alloca(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
||||
// i64 size) {
|
||||
// scc_mir_operand_t imm = {.kind = SCC_MIR_OP_IMM, .imm = size};
|
||||
// scc_mir_operand_t rsp = {.kind = SCC_MIR_OP_PREG, .preg =
|
||||
// SCC_X86_REG_RSP}; add_instr_2(isel, SCC_X86_IFORM_SUB_GPRV_IMMZ, rsp,
|
||||
// imm); scc_x86_emit_move(isel, dst, rsp, 8);
|
||||
// }
|
||||
|
||||
static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
scc_mir_operand_t dst = scc_x86_lir_val_to_mir_op(isel, &instr->to);
|
||||
scc_mir_operand_t src0 = scc_x86_lir_val_to_mir_op(isel, &instr->arg0);
|
||||
scc_mir_operand_t src1 = scc_x86_lir_val_to_mir_op(isel, &instr->arg1);
|
||||
scc_x86_operand_value_t dst = scc_x86_lir_val_to_mir_op(isel, &instr->to);
|
||||
scc_x86_operand_value_t src0 =
|
||||
scc_x86_lir_val_to_mir_op(isel, &instr->arg0);
|
||||
scc_x86_operand_value_t src1 =
|
||||
scc_x86_lir_val_to_mir_op(isel, &instr->arg1);
|
||||
u8 size = instr->size;
|
||||
|
||||
switch (instr->op) {
|
||||
@@ -241,23 +240,19 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
case SCC_LIR_MOV:
|
||||
scc_x86_emit_move(isel, dst, src0, size);
|
||||
break;
|
||||
|
||||
case SCC_LIR_LOAD:
|
||||
// 从 [addr] 加载到 vreg(addr 通常为 vreg)
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, src0);
|
||||
scc_x86_emit_move(isel, dst, src0, size);
|
||||
break;
|
||||
case SCC_LIR_STORE:
|
||||
scc_x86_emit_move(isel, src1, src0, size);
|
||||
break;
|
||||
|
||||
case SCC_LIR_STORE_ADDR:
|
||||
TODO();
|
||||
break;
|
||||
case SCC_LIR_STORE:
|
||||
// 将 src0 存入 [src1]
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, src1, src0);
|
||||
break;
|
||||
|
||||
case SCC_LIR_LEA:
|
||||
case SCC_LIR_LOAD_ADDR:
|
||||
// 地址计算,src0 是复杂地址(LIR 的 MEM 类型)
|
||||
add_instr_2(isel, SCC_X86_IFORM_LEA_GPRV_AGEN, dst, src0);
|
||||
break;
|
||||
|
||||
@@ -279,18 +274,21 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
break;
|
||||
|
||||
case SCC_LIR_MUL:
|
||||
// imul dst, src0, src1 → 需要 mov + imul
|
||||
emit_copy_if_needed(isel, dst, src0, size);
|
||||
if (src1.kind == SCC_X86_OPR_IMM) {
|
||||
scc_x86_operand_value_t op = new_vreg_temp(isel);
|
||||
scc_x86_emit_move(isel, op, src1, size);
|
||||
src1 = op;
|
||||
}
|
||||
add_instr_2(isel, SCC_X86_IFORM_IMUL_GPRV_GPRV, dst, src1);
|
||||
break;
|
||||
|
||||
case SCC_LIR_SHL:
|
||||
case SCC_LIR_SHR:
|
||||
case SCC_LIR_SAR: {
|
||||
// 双地址:dst = dst op count
|
||||
emit_copy_if_needed(isel, dst, src0, size);
|
||||
|
||||
if (src1.kind == SCC_MIR_OP_IMM) {
|
||||
if (src1.kind == SCC_X86_OPR_IMM) {
|
||||
scc_x86_iform_t iform;
|
||||
switch (instr->op) {
|
||||
case SCC_LIR_SHL:
|
||||
@@ -307,10 +305,8 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
}
|
||||
add_instr_2(isel, iform, dst, src1);
|
||||
} else {
|
||||
// 移位量在 CL(需要先 mov cl, src1)
|
||||
scc_mir_operand_t cl = {.kind = SCC_MIR_OP_PREG,
|
||||
.preg = SCC_X86_REG_CL};
|
||||
scc_x86_emit_move(isel, cl, src1, 1); // CL 是 8 位
|
||||
scc_x86_operand_value_t cl = scc_x86_op_preg(SCC_X86_REG_CL);
|
||||
scc_x86_emit_move(isel, cl, src1, 1);
|
||||
scc_x86_iform_t iform;
|
||||
switch (instr->op) {
|
||||
case SCC_LIR_SHL:
|
||||
@@ -334,19 +330,15 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
case SCC_LIR_DIV_U:
|
||||
case SCC_LIR_REM_S:
|
||||
case SCC_LIR_REM_U: {
|
||||
scc_mir_operand_t rax = {.kind = SCC_MIR_OP_PREG,
|
||||
.preg = SCC_X86_REG_RAX};
|
||||
scc_mir_operand_t rdx = {.kind = SCC_MIR_OP_PREG,
|
||||
.preg = SCC_X86_REG_RDX};
|
||||
scc_x86_operand_value_t rax = scc_x86_op_preg(SCC_X86_REG_RAX);
|
||||
scc_x86_operand_value_t rdx = scc_x86_op_preg(SCC_X86_REG_RDX);
|
||||
|
||||
scc_x86_emit_move(isel, rax, src0, size);
|
||||
|
||||
if (instr->op == SCC_LIR_DIV_S || instr->op == SCC_LIR_REM_S) {
|
||||
// 有符号扩展:cqo / cdq(根据 size 选择,这里简化为 64 位 cqo)
|
||||
add_instr_0(isel, SCC_X86_IFORM_CQO);
|
||||
} else {
|
||||
// 无符号:xor edx, edx
|
||||
scc_mir_operand_t zero = {.kind = SCC_MIR_OP_IMM, .imm = 0};
|
||||
scc_x86_operand_value_t zero = scc_x86_op_imm(0);
|
||||
scc_x86_emit_move(isel, rdx, zero, size);
|
||||
}
|
||||
|
||||
@@ -356,7 +348,6 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
: SCC_X86_IFORM_DIV_GPRV;
|
||||
add_instr_1(isel, div_if, src1);
|
||||
|
||||
// 结果:商在 RAX,余数在 RDX
|
||||
if (instr->op == SCC_LIR_REM_S || instr->op == SCC_LIR_REM_U)
|
||||
scc_x86_emit_move(isel, dst, rdx, size);
|
||||
else
|
||||
@@ -365,66 +356,57 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
|
||||
/* ---- 比较指令 ---- */
|
||||
case SCC_LIR_CMP: {
|
||||
// 1. 比较并设置标志位
|
||||
if (src0.kind == SCC_MIR_OP_VREG && src1.kind == SCC_MIR_OP_IMM)
|
||||
if (scc_x86_op_is_vreg(&src0) && src1.kind == SCC_X86_OPR_IMM)
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_IMMZ, src0, src1);
|
||||
else if (src0.kind == SCC_MIR_OP_VREG && src1.kind == SCC_MIR_OP_VREG)
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_39, src0, src1);
|
||||
else if (scc_x86_op_is_vreg(&src0) && scc_x86_op_is_vreg(&src1))
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_3B, src0, src1);
|
||||
else
|
||||
UNREACHABLE();
|
||||
|
||||
// 2. 标志位 -> 布尔值 (写入 dst)
|
||||
scc_x86_iform_t setcc = cond_to_setcc(instr->metadata.cond);
|
||||
add_instr_1(isel, setcc, dst); // 注意 setcc 只写低 8 位
|
||||
// 若需 32/64 位布尔值,可再 movzx dst, dst
|
||||
add_instr_1(isel, setcc, dst);
|
||||
if (size > 1) {
|
||||
// movzx dst, dst (假设 MOVZX_GPRV_GPR8 存在;这里临时用 and 模拟)
|
||||
// 简单处理:用 and dst, 1 清理高位
|
||||
scc_mir_operand_t one = {.kind = SCC_MIR_OP_IMM, .imm = 1};
|
||||
scc_x86_operand_value_t one = scc_x86_op_imm(1);
|
||||
add_instr_2(isel, SCC_X86_IFORM_AND_GPRV_IMMZ, dst, one);
|
||||
}
|
||||
} break;
|
||||
|
||||
/* ---- 条件分支 ---- */
|
||||
case SCC_LIR_BR: {
|
||||
// arg0 是 CMP 产生的布尔值 (0 或 1)
|
||||
// test src0, src0 ; jnz true_bb ; jmp false_bb
|
||||
scc_mir_operand_t true_bb = {.kind = SCC_MIR_OP_BLOCK,
|
||||
.block_id =
|
||||
instr->metadata.br.true_target};
|
||||
scc_mir_operand_t false_bb = {.kind = SCC_MIR_OP_BLOCK,
|
||||
.block_id =
|
||||
instr->metadata.br.false_target};
|
||||
scc_x86_operand_value_t true_bb =
|
||||
scc_x86_op_block(instr->metadata.br.true_target);
|
||||
scc_x86_operand_value_t false_bb =
|
||||
scc_x86_op_block(instr->metadata.br.false_target);
|
||||
|
||||
// test src0, src0
|
||||
add_instr_2(isel, SCC_X86_IFORM_TEST_GPRV_GPRV, src0, src0);
|
||||
// jnz true
|
||||
add_instr_1(isel, SCC_X86_IFORM_JNZ_RELBRZ, true_bb);
|
||||
// jmp false
|
||||
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, false_bb);
|
||||
} break;
|
||||
|
||||
case SCC_LIR_JMP: {
|
||||
add_instr_1(
|
||||
isel, SCC_X86_IFORM_JMP_RELBRZ,
|
||||
(scc_mir_operand_t){.kind = SCC_MIR_OP_BLOCK,
|
||||
.block_id = instr->metadata.jmp_target});
|
||||
scc_x86_operand_value_t jmp_bb =
|
||||
scc_x86_op_block(instr->metadata.jmp_target);
|
||||
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, jmp_bb);
|
||||
} break;
|
||||
|
||||
/* ---- 栈分配 ---- */
|
||||
case SCC_LIR_ALLOCA:
|
||||
// emit_alloca(isel, dst, instr->metadata.alloca.size_bytes);
|
||||
scc_mir_operand_t op = scc_x86_lir_val_to_mir_op(isel, &instr->to);
|
||||
add_instr_2(isel, (scc_x86_iform_t)SCC_MIR_PSUEDO_ALLOCA, op,
|
||||
(scc_mir_operand_t){
|
||||
.kind = SCC_MIR_OP_IMM,
|
||||
.imm = instr->size,
|
||||
});
|
||||
Assert(op.kind == SCC_MIR_OP_VREG);
|
||||
case SCC_LIR_ALLOCA: {
|
||||
scc_x86_operand_value_t op =
|
||||
scc_x86_lir_val_to_mir_op(isel, &instr->to);
|
||||
scc_mir_x86_instr_t x86instr;
|
||||
x86instr.instr.opcode = SCC_MIR_PSEUDO_ALLOCA;
|
||||
Assert(op.kind == SCC_X86_OPR_REG);
|
||||
x86instr.instr.data.alloc.vreg = op.reg;
|
||||
x86instr.instr.data.alloc.size = instr->size;
|
||||
x86instr.instr.data.alloc.align = 0;
|
||||
scc_vec_push(isel->instrs, x86instr);
|
||||
scc_mir_vreg_map2slot(isel->func, instr->to.data.reg, instr->size, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ---- 其他(占位) ---- */
|
||||
case SCC_LIR_NOP:
|
||||
add_instr_0(isel, SCC_X86_IFORM_NOP_90);
|
||||
break;
|
||||
|
||||
/* ---- 调用与返回 ---- */
|
||||
@@ -465,6 +447,7 @@ void scc_isel_x86_64(scc_mir_module_t *mir_module,
|
||||
const scc_lir_module_t *lir_module,
|
||||
scc_x86_64_isel_t *isel) {
|
||||
|
||||
mir_module->instr_size = sizeof(scc_mir_x86_instr_t);
|
||||
scc_vec_foreach(lir_module->cfg_module.funcs, i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
@@ -474,7 +457,6 @@ void scc_isel_x86_64(scc_mir_module_t *mir_module,
|
||||
scc_malloc(sizeof(scc_mir_func_meta_t));
|
||||
Assert(func_meta != nullptr);
|
||||
scc_mir_func_meta_init(func_meta);
|
||||
// FIXME
|
||||
func_meta->vregs_count = SCC_LIR_FUNC_META(func)->vregs_count;
|
||||
func->meta = func_meta;
|
||||
|
||||
201
libs/ir/mir/src/arch/scc_x86_reg_alloc.c
Normal file
201
libs/ir/mir/src/arch/scc_x86_reg_alloc.c
Normal file
@@ -0,0 +1,201 @@
|
||||
#include <arch/scc_x86_isel.h>
|
||||
#include <arch/scc_x86_mir.h>
|
||||
#include <arch/scc_x86_reg_alloc.h>
|
||||
#include <x86/scc_x86_iform.h>
|
||||
#include <x86/scc_x86_reg.h>
|
||||
|
||||
/* ========== 指令访问回调 ========== */
|
||||
|
||||
static int instr_opcode(const void *instr) {
|
||||
return ((const scc_mir_x86_instr_t *)instr)->x86_instr.opcode;
|
||||
}
|
||||
static int instr_num_operands(const void *instr) {
|
||||
return ((const scc_mir_x86_instr_t *)instr)->x86_instr.num_operands;
|
||||
}
|
||||
static bool op_is_vreg(const void *instr, int idx) {
|
||||
return scc_x86_op_is_vreg(
|
||||
&((const scc_mir_x86_instr_t *)instr)->x86_instr.operands[idx]);
|
||||
}
|
||||
static int op_get_vreg(const void *instr, int idx) {
|
||||
return scc_x86_op_get_vreg(
|
||||
&((const scc_mir_x86_instr_t *)instr)->x86_instr.operands[idx]);
|
||||
}
|
||||
static void op_set_preg(void *instr, int idx, int preg) {
|
||||
scc_x86_op_set_preg(
|
||||
&((scc_mir_x86_instr_t *)instr)->x86_instr.operands[idx],
|
||||
(scc_x86_reg_t)preg);
|
||||
}
|
||||
static void op_set_slot(void *instr, int idx, int slot) {
|
||||
((scc_mir_x86_instr_t *)instr)->x86_instr.operands[idx] =
|
||||
scc_x86_op_slot(slot);
|
||||
}
|
||||
|
||||
/* ========== 伪指令处理 ========== */
|
||||
|
||||
static bool is_pseudo(const void *instr) {
|
||||
return ((const scc_mir_x86_instr_t *)instr)->x86_instr.opcode < 0;
|
||||
}
|
||||
|
||||
static void handle_pseudo(scc_mir_func_t *func, void *instr, void *out) {
|
||||
scc_mir_x86_instr_t *ins = instr;
|
||||
scc_mir_x86_instr_vec_t *out_vec = out;
|
||||
if (ins->x86_instr.opcode == SCC_MIR_PSEUDO_ALLOCA) {
|
||||
// // 指令选择时已分配 slot,直接替换为 slot 操作数
|
||||
// if (scc_x86_op_is_vreg(&ins->x86_instr.operands[0])) {
|
||||
// int vreg = scc_x86_op_get_vreg(&ins->x86_instr.operands[0]);
|
||||
// int slot = scc_mir_vreg_map2slot(func, vreg, 8, 8);
|
||||
// ins->x86_instr.operands[0] = scc_x86_op_slot(slot);
|
||||
// }
|
||||
// scc_vec_push(*out_vec, *ins);
|
||||
} else {
|
||||
scc_vec_push(*out_vec, *ins);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== Spill / Reload / Copy ========== */
|
||||
|
||||
static void emit_spill(void *out, int preg, int slot) {
|
||||
scc_mir_x86_instr_vec_t *vec = out;
|
||||
scc_mir_x86_instr_t ins = {
|
||||
.x86_instr.opcode = SCC_X86_IFORM_MOV_MEMV_GPRV,
|
||||
.x86_instr.num_operands = 2,
|
||||
.x86_instr.operands = {scc_x86_op_slot(slot), scc_x86_op_preg(preg)}};
|
||||
scc_vec_push(*vec, ins);
|
||||
}
|
||||
|
||||
static void emit_reload(void *out, int preg, int slot) {
|
||||
scc_mir_x86_instr_vec_t *vec = out;
|
||||
scc_mir_x86_instr_t ins = {
|
||||
.x86_instr.opcode = SCC_X86_IFORM_MOV_GPRV_MEMV,
|
||||
.x86_instr.num_operands = 2,
|
||||
.x86_instr.operands = {scc_x86_op_preg(preg), scc_x86_op_slot(slot)}};
|
||||
scc_vec_push(*vec, ins);
|
||||
}
|
||||
|
||||
static void emit_copy(void *out, int dst_preg, int src_preg, int size) {
|
||||
(void)size;
|
||||
scc_mir_x86_instr_vec_t *vec = out;
|
||||
scc_mir_x86_instr_t ins = {
|
||||
.x86_instr.opcode = SCC_X86_IFORM_MOV_GPRV_GPRV_8B,
|
||||
.x86_instr.num_operands = 2,
|
||||
.x86_instr.operands = {scc_x86_op_preg(dst_preg),
|
||||
scc_x86_op_preg(src_preg)}};
|
||||
scc_vec_push(*vec, ins);
|
||||
}
|
||||
|
||||
/* ========== 操作数读写属性 ========== */
|
||||
|
||||
static scc_reg_op_access_t get_operand_access(void *ctx, int opcode,
|
||||
int op_idx) {
|
||||
(void)ctx;
|
||||
if (opcode >= 0 && opcode < SCC_X86_IFORM_COUNT) {
|
||||
const scc_x86_iform_info_t *info = &scc_x86_iform_table[opcode];
|
||||
if (op_idx >= info->num_ops || op_idx < 0)
|
||||
return SCC_REG_ALLOC_OP_ACCESS_READWRITE;
|
||||
if (info->ops[op_idx].rw[0] == 'r')
|
||||
return info->ops[op_idx].rw[1] == 'w'
|
||||
? SCC_REG_ALLOC_OP_ACCESS_READWRITE
|
||||
: SCC_REG_ALLOC_OP_ACCESS_READ;
|
||||
else if (info->ops[op_idx].rw[0] == 'w')
|
||||
return SCC_REG_ALLOC_OP_ACCESS_WRITE;
|
||||
}
|
||||
return SCC_REG_ALLOC_OP_ACCESS_READWRITE;
|
||||
}
|
||||
|
||||
/* ========== 隐式寄存器 ========== */
|
||||
|
||||
static void get_implicit_regs(void *ctx, int opcode, const int **uses,
|
||||
const int **defs) {
|
||||
(void)ctx;
|
||||
static const int empty[] = {-1};
|
||||
static const int rax[] = {SCC_X86_REG_RAX, -1};
|
||||
static const int rdx[] = {SCC_X86_REG_RDX, -1};
|
||||
static const int rax_rdx[] = {SCC_X86_REG_RAX, SCC_X86_REG_RDX, -1};
|
||||
static const int cl[] = {SCC_X86_REG_CL, -1};
|
||||
|
||||
switch (opcode) {
|
||||
case SCC_X86_IFORM_IDIV_GPRV:
|
||||
case SCC_X86_IFORM_DIV_GPRV:
|
||||
*uses = rax_rdx;
|
||||
*defs = rax_rdx;
|
||||
break;
|
||||
case SCC_X86_IFORM_CQO:
|
||||
*uses = rax;
|
||||
*defs = rax_rdx;
|
||||
break;
|
||||
case SCC_X86_IFORM_SAR_GPRV_CL:
|
||||
*uses = cl;
|
||||
*defs = empty;
|
||||
break;
|
||||
default:
|
||||
*uses = empty;
|
||||
*defs = empty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== 寄存器池 ========== */
|
||||
|
||||
static const int reg_pool[] = {
|
||||
SCC_X86_REG_R8, SCC_X86_REG_R9, SCC_X86_REG_R10, SCC_X86_REG_R11,
|
||||
SCC_X86_REG_R12, SCC_X86_REG_R13, SCC_X86_REG_R14, SCC_X86_REG_R15};
|
||||
static uint32_t reg_mask = 0;
|
||||
|
||||
static int acquire_reg(void *ctx) {
|
||||
(void)ctx;
|
||||
for (int i = 0; i < SCC_ARRLEN(reg_pool); i++)
|
||||
if (!(reg_mask & (1u << i))) {
|
||||
reg_mask |= (1u << i);
|
||||
return reg_pool[i];
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static void release_reg(void *ctx, int preg) {
|
||||
(void)ctx;
|
||||
for (int i = 0; i < SCC_ARRLEN(reg_pool); i++)
|
||||
if (reg_pool[i] == preg) {
|
||||
reg_mask &= ~(1u << i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_reg_used(void *ctx, int preg) {
|
||||
(void)ctx;
|
||||
for (int i = 0; i < SCC_ARRLEN(reg_pool); i++)
|
||||
if (reg_pool[i] == preg) {
|
||||
reg_mask |= (1u << i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void clean_mark_regs(void *ctx) {
|
||||
(void)ctx;
|
||||
reg_mask = 0;
|
||||
}
|
||||
|
||||
/* ========== 注册全部 x86 回调 ========== */
|
||||
|
||||
void scc_reg_alloc_fill_arch_x86(scc_reg_alloc_op_t *ops) {
|
||||
ops->acquire_reg = acquire_reg;
|
||||
ops->release_reg = release_reg;
|
||||
ops->mark_reg_used = mark_reg_used;
|
||||
ops->clean_mark_regs = clean_mark_regs;
|
||||
|
||||
ops->instr_opcode = instr_opcode;
|
||||
ops->instr_num_operands = instr_num_operands;
|
||||
ops->op_is_vreg = op_is_vreg;
|
||||
ops->op_get_vreg = op_get_vreg;
|
||||
ops->op_set_preg = op_set_preg;
|
||||
ops->op_set_slot = op_set_slot;
|
||||
|
||||
ops->get_operand_access = get_operand_access;
|
||||
ops->get_implicit_regs = get_implicit_regs;
|
||||
|
||||
ops->is_pseudo = is_pseudo;
|
||||
ops->handle_pseudo = handle_pseudo;
|
||||
|
||||
ops->emit_spill = emit_spill;
|
||||
ops->emit_reload = emit_reload;
|
||||
ops->emit_copy = emit_copy;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
#include <arch/x86_64_isel.h>
|
||||
#include <arch/x86_64_reg_alloc.h>
|
||||
|
||||
static void x86_emit_spill(scc_mir_instr_vec_t *ctx, int preg, int slot) {
|
||||
scc_mir_instr_t ins = {
|
||||
.opcode = SCC_X86_IFORM_MOV_MEMV_GPRV,
|
||||
.num_operands = 2,
|
||||
.operands = {{.kind = SCC_MIR_OP_MEM, .stack_slot = slot},
|
||||
{.kind = SCC_MIR_OP_PREG, .preg = preg}}};
|
||||
scc_vec_push(*ctx, ins);
|
||||
}
|
||||
|
||||
static void x86_emit_reload(scc_mir_instr_vec_t *ctx, int preg, int slot) {
|
||||
scc_mir_instr_t ins = {
|
||||
.opcode = SCC_X86_IFORM_MOV_GPRV_MEMV,
|
||||
.num_operands = 2,
|
||||
.operands = {{.kind = SCC_MIR_OP_PREG, .preg = preg},
|
||||
{.kind = SCC_MIR_OP_MEM, .stack_slot = slot}}};
|
||||
scc_vec_push(*ctx, ins);
|
||||
}
|
||||
|
||||
static void x86_emit_copy(scc_mir_instr_vec_t *ctx, int dst_preg, int src_preg,
|
||||
int size) {
|
||||
scc_mir_instr_t ins = {
|
||||
.opcode = SCC_X86_IFORM_MOV_GPRV_GPRV_89,
|
||||
.num_operands = 2,
|
||||
.operands = {{.kind = SCC_MIR_OP_PREG, .preg = dst_preg},
|
||||
{.kind = SCC_MIR_OP_PREG, .preg = src_preg}}};
|
||||
scc_vec_push(*ctx, ins);
|
||||
}
|
||||
|
||||
/* ---- 临时寄存器 ---- */
|
||||
static int x86_acquire_temp_reg(void *vctx) { return SCC_X86_REG_R11; }
|
||||
|
||||
static void x86_release_temp_reg(void *vctx, int preg) { /* 简单模式无需操作 */
|
||||
}
|
||||
|
||||
/* ---- 操作数读写属性 ---- */
|
||||
static scc_op_access_t x86_get_operand_access(void *vctx, int opcode,
|
||||
int op_idx) {
|
||||
switch (opcode) {
|
||||
default:
|
||||
return SCC_REG_ALLOC_OP_ACCESS_READWRITE; // 保守
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 隐式寄存器 ---- */
|
||||
static void x86_get_implicit_regs(void *vctx, int opcode, const int **uses,
|
||||
const int **defs) {
|
||||
static const int empty[] = {-1};
|
||||
static const int rax[] = {SCC_X86_REG_RAX, -1};
|
||||
static const int rdx[] = {SCC_X86_REG_RDX, -1};
|
||||
static const int rax_rdx[] = {SCC_X86_REG_RAX, SCC_X86_REG_RDX, -1};
|
||||
static const int cl[] = {SCC_X86_REG_CL, -1};
|
||||
|
||||
switch (opcode) {
|
||||
case SCC_X86_IFORM_IDIV_GPRV:
|
||||
case SCC_X86_IFORM_DIV_GPRV:
|
||||
*uses = rax_rdx;
|
||||
*defs = rax_rdx;
|
||||
break;
|
||||
case SCC_X86_IFORM_CQO:
|
||||
*uses = rax;
|
||||
*defs = rax_rdx;
|
||||
break;
|
||||
case SCC_X86_IFORM_SAR_GPRV_CL:
|
||||
*uses = cl;
|
||||
*defs = empty;
|
||||
break;
|
||||
default:
|
||||
*uses = empty;
|
||||
*defs = empty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void scc_reg_alloc_fill_arch_x86(scc_reg_alloc_op_t *ops) {
|
||||
ops->emit_spill = x86_emit_spill;
|
||||
ops->emit_reload = x86_emit_reload;
|
||||
ops->emit_copy = x86_emit_copy;
|
||||
ops->get_operand_access = x86_get_operand_access;
|
||||
ops->get_implicit_regs = x86_get_implicit_regs;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
#include <core_pass/scc_frame_layout.h>
|
||||
|
||||
void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) {}
|
||||
@@ -1,174 +1,76 @@
|
||||
#include <core_pass/scc_reg_alloc.h>
|
||||
#include <scc_hashtable.h>
|
||||
#include <scc_mir_module.h>
|
||||
|
||||
// static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
|
||||
// scc_mir_instr_vec_t *instr_vec,
|
||||
// scc_mir_instr_t *instr) {
|
||||
// const scc_reg_alloc_op_t *ops = &ctx->ops;
|
||||
// scc_mir_instr_vec_t before, after;
|
||||
// scc_vec_init(before);
|
||||
// scc_vec_init(after);
|
||||
|
||||
// // 1. 标记隐式寄存器为占用
|
||||
// const int *implicit_uses, *implicit_defs;
|
||||
// ops->get_implicit_regs(ctx, instr->opcode, &implicit_uses,
|
||||
// &implicit_defs); for (const int *p = implicit_uses; *p != -1; p++)
|
||||
// ops->mark_reg_used(ctx, *p);
|
||||
// for (const int *p = implicit_defs; *p != -1; p++)
|
||||
// ops->mark_reg_used(ctx, *p);
|
||||
|
||||
// SCC_VEC(int) preg_vec;
|
||||
// scc_vec_init(preg_vec);
|
||||
|
||||
// for (int i = 0; i < instr->num_operands; i++) {
|
||||
// if (instr->operands[i].kind != SCC_MIR_OP_VREG)
|
||||
// continue;
|
||||
|
||||
// int vreg = instr->operands[i].vreg;
|
||||
// scc_mir_vreg_op(ctx->func, vreg, &instr->operands[i]);
|
||||
|
||||
// if (instr->operands[i].kind != SCC_MIR_OP_VREG)
|
||||
// continue;
|
||||
|
||||
// // FIXME size alian
|
||||
// int slot = scc_mir_vreg_map2slot(ctx->func, vreg, 8, 8);
|
||||
// int preg = -1;
|
||||
// // if (implicit_uses && implicit_uses[0] != -1)
|
||||
// // preg = implicit_uses[0];
|
||||
// // else
|
||||
// preg = ops->acquire_reg(ctx);
|
||||
// scc_vec_push(preg_vec, preg);
|
||||
|
||||
// // 根据操作数读写属性决定是否需要 reload
|
||||
// scc_op_access_t acc = ops->get_operand_access(ctx, instr->opcode, i);
|
||||
// if (acc == SCC_REG_ALLOC_OP_ACCESS_READ ||
|
||||
// acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
|
||||
// ops->emit_reload(&before, preg, slot);
|
||||
// }
|
||||
|
||||
// if (acc == SCC_REG_ALLOC_OP_ACCESS_WRITE ||
|
||||
// acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
|
||||
// ops->emit_spill(&after, preg, slot);
|
||||
// }
|
||||
|
||||
// // 替换操作数为物理寄存器
|
||||
// instr->operands[i].kind = SCC_MIR_OP_PREG;
|
||||
// instr->operands[i].preg = preg;
|
||||
// }
|
||||
|
||||
// scc_vec_foreach(preg_vec, i) {
|
||||
// int preg = scc_vec_at(preg_vec, i);
|
||||
// ops->release_reg(ctx, preg);
|
||||
// }
|
||||
|
||||
// scc_vec_foreach(before, i) scc_vec_push(*instr_vec, scc_vec_at(before,
|
||||
// i)); scc_vec_push(*instr_vec, *instr); scc_vec_foreach(after, i)
|
||||
// scc_vec_push(*instr_vec, scc_vec_at(after, i));
|
||||
|
||||
// // 7. 取消隐式寄存器的占用标记
|
||||
// Assert(ops->mark_reg_used != nullptr);
|
||||
// for (const int *p = implicit_defs; *p != -1; p++)
|
||||
// ops->mark_reg_used(ctx, *p);
|
||||
// for (const int *p = implicit_uses; *p != -1; p++)
|
||||
// ops->release_reg(ctx, *p);
|
||||
|
||||
// scc_vec_free(before);
|
||||
// scc_vec_free(after);
|
||||
// }
|
||||
|
||||
static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
|
||||
scc_mir_instr_vec_t *instr_vec,
|
||||
scc_mir_instr_t *instr) {
|
||||
const scc_reg_alloc_op_t *ops = &ctx->ops;
|
||||
usize instr_size = ctx->module->instr_size;
|
||||
if (ops->is_pseudo(instr)) {
|
||||
ops->handle_pseudo(ctx->func, (void *)instr, instr_vec);
|
||||
return;
|
||||
}
|
||||
|
||||
scc_mir_instr_vec_t before, after;
|
||||
scc_vec_init(before);
|
||||
scc_vec_init(after);
|
||||
SCC_VEC(int) allocated;
|
||||
scc_vec_init(allocated);
|
||||
|
||||
// 隐式寄存器标记
|
||||
int opcode = ops->instr_opcode(instr);
|
||||
|
||||
// 标记隐式寄存器
|
||||
const int *implicit_uses, *implicit_defs;
|
||||
ops->get_implicit_regs(ctx, instr->opcode, &implicit_uses, &implicit_defs);
|
||||
ops->get_implicit_regs(ctx, opcode, &implicit_uses, &implicit_defs);
|
||||
for (const int *p = implicit_uses; *p != -1; p++)
|
||||
ops->mark_reg_used(ctx, *p);
|
||||
for (const int *p = implicit_defs; *p != -1; p++)
|
||||
ops->mark_reg_used(ctx, *p);
|
||||
|
||||
// 指令内 vreg→preg 的简单映射(操作数不超过 8 个)
|
||||
int local_vreg[8], local_preg[8];
|
||||
int local_cnt = 0;
|
||||
|
||||
SCC_VEC(int) allocated_pregs;
|
||||
scc_vec_init(allocated_pregs);
|
||||
|
||||
for (int i = 0; i < instr->num_operands; i++) {
|
||||
scc_mir_operand_t *op = &instr->operands[i];
|
||||
|
||||
// 只处理 vreg
|
||||
if (op->kind != SCC_MIR_OP_VREG)
|
||||
int num_ops = ops->instr_num_operands(instr);
|
||||
for (int op_i = 0; op_i < num_ops; op_i++) {
|
||||
if (!ops->op_is_vreg(instr, op_i))
|
||||
continue;
|
||||
|
||||
int vreg = op->vreg;
|
||||
int vreg = ops->op_get_vreg(instr, op_i);
|
||||
int id = 0;
|
||||
int mapping = scc_mir_vreg_lookup(ctx->func, vreg, &id);
|
||||
int preg = id, slot = id;
|
||||
|
||||
// 查询当前 vreg 的映射(可能已经被之前的分配改为 MEM 等,但我们只需要
|
||||
// slot)
|
||||
scc_mir_vreg_op(ctx->func, vreg, op);
|
||||
int slot;
|
||||
if (op->kind == SCC_MIR_OP_VREG) {
|
||||
// 还没有 slot → 分配一个
|
||||
if (mapping == 1) {
|
||||
// 已预着色
|
||||
ops->mark_reg_used(ctx, preg);
|
||||
ops->op_set_preg(instr, op_i, preg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mapping == 0)
|
||||
slot = scc_mir_vreg_map2slot(ctx->func, vreg, 8, 8);
|
||||
} else {
|
||||
// 已经是 MEM,直接用它的 slot
|
||||
Assert(op->kind == SCC_MIR_OP_MEM);
|
||||
slot = op->stack_slot;
|
||||
}
|
||||
|
||||
// 在本指令内查找是否已为这个 vreg 分配了 preg
|
||||
int preg = -1;
|
||||
for (int k = 0; k < local_cnt; k++) {
|
||||
if (local_vreg[k] == vreg) {
|
||||
preg = local_preg[k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (preg == -1) {
|
||||
// 新分配
|
||||
preg = ops->acquire_reg(ctx);
|
||||
scc_vec_push(allocated_pregs, preg);
|
||||
local_vreg[local_cnt] = vreg;
|
||||
local_preg[local_cnt] = preg;
|
||||
local_cnt++;
|
||||
}
|
||||
scc_vec_push(allocated, preg);
|
||||
|
||||
// 读写属性
|
||||
scc_op_access_t acc = ops->get_operand_access(ctx, instr->opcode, i);
|
||||
|
||||
// reload: slot → preg
|
||||
scc_reg_op_access_t acc = ops->get_operand_access(ctx, opcode, op_i);
|
||||
if (acc == SCC_REG_ALLOC_OP_ACCESS_READ ||
|
||||
acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
|
||||
acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE)
|
||||
ops->emit_reload(&before, preg, slot);
|
||||
}
|
||||
|
||||
// spill: preg → slot
|
||||
if (acc == SCC_REG_ALLOC_OP_ACCESS_WRITE ||
|
||||
acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
|
||||
acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE)
|
||||
ops->emit_spill(&after, preg, slot);
|
||||
}
|
||||
|
||||
// 替换操作数
|
||||
op->kind = SCC_MIR_OP_PREG;
|
||||
op->preg = preg;
|
||||
ops->op_set_preg(instr, op_i, preg);
|
||||
}
|
||||
|
||||
// 释放本指令分配的临时寄存器
|
||||
scc_vec_foreach(allocated_pregs, i)
|
||||
ops->release_reg(ctx, scc_vec_at(allocated_pregs, i));
|
||||
|
||||
// 合并指令流
|
||||
scc_vec_foreach(before, i) scc_vec_push(*instr_vec, scc_vec_at(before, i));
|
||||
scc_vec_push(*instr_vec, *instr);
|
||||
scc_vec_foreach(after, i) scc_vec_push(*instr_vec, scc_vec_at(after, i));
|
||||
scc_vec_foreach(before, i) scc_vec_sized_push(
|
||||
*instr_vec, instr_size, scc_vec_sized_at_ptr(before, instr_size, i),
|
||||
instr_size);
|
||||
scc_vec_sized_push(*instr_vec, instr_size, instr, instr_size);
|
||||
scc_vec_foreach(after, i) scc_vec_sized_push(
|
||||
*instr_vec, instr_size, scc_vec_sized_at_ptr(after, instr_size, i),
|
||||
instr_size);
|
||||
|
||||
// 隐式寄存器清理
|
||||
// 清理隐式寄存器
|
||||
for (const int *p = implicit_defs; *p != -1; p++)
|
||||
ops->mark_reg_used(ctx, *p);
|
||||
for (const int *p = implicit_uses; *p != -1; p++)
|
||||
@@ -176,58 +78,40 @@ static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
|
||||
|
||||
scc_vec_free(before);
|
||||
scc_vec_free(after);
|
||||
scc_vec_free(allocated_pregs);
|
||||
scc_vec_foreach(allocated, l)
|
||||
ops->release_reg(ctx, scc_vec_at(allocated, l));
|
||||
scc_vec_free(allocated);
|
||||
}
|
||||
|
||||
/* 对一个基本块执行分配 */
|
||||
static void alloc_bb(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module,
|
||||
scc_cfg_bblock_id_t bb_id) {
|
||||
void scc_reg_alloc(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module) {
|
||||
const scc_reg_alloc_op_t *ops = &ctx->ops;
|
||||
ctx->module = module;
|
||||
|
||||
scc_vec_foreach(module->cfg_module.funcs, i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
scc_mir_func_t *func = &scc_vec_at(module->cfg_module.funcs, i);
|
||||
|
||||
ops->clean_mark_regs(ctx);
|
||||
ctx->func = func;
|
||||
|
||||
scc_vec_foreach(func->bblocks, j) {
|
||||
scc_cfg_bblock_id_t bb_id = scc_vec_at(func->bblocks, j);
|
||||
scc_cfg_bblock_t *bb =
|
||||
scc_cfg_module_unsafe_get_bblock(&module->cfg_module, bb_id);
|
||||
Assert(bb != nullptr);
|
||||
scc_mir_instr_vec_t *old_instrs = SCC_MIR_BBLOCK_VALUES(bb);
|
||||
|
||||
scc_mir_instr_vec_t *old_instrs = SCC_MIR_BBLOCK_VALUES_PTR(bb);
|
||||
scc_mir_instr_vec_t new_instrs;
|
||||
scc_vec_init(new_instrs);
|
||||
|
||||
scc_vec_foreach(*old_instrs, i) {
|
||||
scc_mir_instr_t ins = scc_vec_at(*old_instrs, i);
|
||||
alloc_instr(ctx, &new_instrs, &ins);
|
||||
scc_vec_foreach(*old_instrs, k) {
|
||||
scc_mir_instr_t *instr = scc_vec_sized_at_ptr(
|
||||
*old_instrs, ctx->module->instr_size, k);
|
||||
alloc_instr(ctx, &new_instrs, instr);
|
||||
}
|
||||
|
||||
scc_vec_free(*old_instrs);
|
||||
*old_instrs = new_instrs;
|
||||
}
|
||||
|
||||
/* 对一个函数运行分配 */
|
||||
static void alloc_func(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module,
|
||||
scc_mir_func_t *func) {
|
||||
ctx->ops.clean_mark_regs(ctx);
|
||||
|
||||
ctx->func = func;
|
||||
scc_vec_foreach(func->bblocks, i) {
|
||||
scc_cfg_bblock_id_t bb_id = scc_vec_at(func->bblocks, i);
|
||||
alloc_bb(ctx, module, bb_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* 公开入口 */
|
||||
void scc_reg_alloc(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module) {
|
||||
Assert(ctx != nullptr && module != nullptr);
|
||||
|
||||
Assert(ctx->ops.acquire_reg != nullptr);
|
||||
Assert(ctx->ops.clean_mark_regs != nullptr);
|
||||
Assert(ctx->ops.emit_copy != nullptr);
|
||||
Assert(ctx->ops.emit_reload != nullptr);
|
||||
Assert(ctx->ops.emit_spill != nullptr);
|
||||
Assert(ctx->ops.get_implicit_regs != nullptr);
|
||||
Assert(ctx->ops.get_operand_access != nullptr);
|
||||
Assert(ctx->ops.mark_reg_used != nullptr);
|
||||
Assert(ctx->ops.release_reg != nullptr);
|
||||
|
||||
scc_vec_foreach(module->cfg_module.funcs, i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
alloc_func(ctx, module, &scc_vec_at(module->cfg_module.funcs, i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <arch/x86_64_isel.h>
|
||||
#include <arch/scc_x86_isel.h>
|
||||
#include <scc_lir2mir.h>
|
||||
#include <target/scc_win64.h>
|
||||
|
||||
void scc_lir2mir(scc_mir_module_t *mir_module,
|
||||
const scc_lir_module_t *lir_module) {
|
||||
// FIXME hack cfg module
|
||||
// Move
|
||||
mir_module->cfg_module = lir_module->cfg_module;
|
||||
|
||||
scc_x86_64_isel_t isel;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#include <scc_mir.h>
|
||||
|
||||
void scc_mir_func_meta_init(scc_mir_func_meta_t *func_meta) {
|
||||
func_meta->need_va_args = false;
|
||||
func_meta->frame_size = 0;
|
||||
func_meta->stack_alignment = 0;
|
||||
func_meta->vregs_count = 0;
|
||||
func_meta->target_data = nullptr;
|
||||
scc_vec_init(func_meta->stack_slots);
|
||||
|
||||
// For null stack slot
|
||||
@@ -16,24 +18,6 @@ int scc_mir_alloc_vreg(scc_mir_func_t *func) {
|
||||
return meta->vregs_count++;
|
||||
}
|
||||
|
||||
void scc_mir_vreg_op(const scc_mir_func_t *func, int vreg,
|
||||
scc_mir_operand_t *out) {
|
||||
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||
isize idx =
|
||||
(isize)scc_hashtable_get(&meta->vreg2physic, (void *)(usize)vreg);
|
||||
if (idx == 0) {
|
||||
out->kind = SCC_MIR_OP_VREG;
|
||||
out->vreg = vreg;
|
||||
} else if (idx < 0) {
|
||||
out->kind = SCC_MIR_OP_PREG;
|
||||
out->preg = (int)-idx;
|
||||
} else {
|
||||
out->kind = SCC_MIR_OP_MEM;
|
||||
Assert(idx < scc_vec_size(meta->stack_slots));
|
||||
out->stack_slot = (int)(usize)idx;
|
||||
}
|
||||
}
|
||||
|
||||
void scc_mir_vreg_map2preg(scc_mir_func_t *func, int vreg, int preg) {
|
||||
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||
isize val =
|
||||
|
||||
@@ -1,49 +1,34 @@
|
||||
#include <arch/scc_x86_mir.h>
|
||||
#include <scc_mir_dump.h>
|
||||
|
||||
void scc_x86_instr_dump(scc_tree_dump_t *dump, const scc_mir_instr_t *instr);
|
||||
|
||||
void scc_mir_dump_instr(scc_mir_dump_ctx_t *ctx, const scc_mir_instr_t *ins) {
|
||||
scc_tree_dump_t *td = ctx->dump_ctx;
|
||||
scc_tree_dump_begin_line(td);
|
||||
if (ins->opcode >= 0) {
|
||||
scc_x86_instr_dump(td, ins);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ins->opcode) {
|
||||
case SCC_MIR_PSUEDO_ALLOCA:
|
||||
scc_tree_dump_node(td, " @alloca");
|
||||
scc_tree_dump_append_fmt(td, "(%d)", ins->operands[1].imm);
|
||||
if (ins->operands[0].kind == SCC_MIR_OP_VREG) {
|
||||
scc_tree_dump_append_fmt(td, " %%%d", ins->operands[0].vreg);
|
||||
} else if (ins->operands[0].kind == SCC_MIR_OP_MEM) {
|
||||
scc_tree_dump_append_fmt(td, " [%d]", ins->operands[0].stack_slot);
|
||||
} else {
|
||||
scc_tree_dump_append(td, "<alloced>");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_x86_instr_t *instr);
|
||||
void scc_mir_dump_bblock(scc_mir_dump_ctx_t *ctx, const scc_mir_bblock_t *bb) {
|
||||
Assert(ctx != nullptr && bb != nullptr);
|
||||
scc_tree_dump_t *td = ctx->dump_ctx;
|
||||
|
||||
// 基本块头部
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_node(td, "#BB%zu", bb->id);
|
||||
scc_tree_dump_branch(td, "#BB%zu", bb->id);
|
||||
if (bb->name) {
|
||||
scc_tree_dump_append_fmt(td, " (%s)", bb->name);
|
||||
}
|
||||
scc_tree_dump_append(td, ":");
|
||||
|
||||
// 输出每条指令
|
||||
scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES(bb);
|
||||
scc_vec_foreach(*instrs, i) {
|
||||
const scc_mir_instr_t *ins = &scc_vec_at(*instrs, i);
|
||||
scc_mir_dump_instr(ctx, ins);
|
||||
for (int i = 0; i < scc_vec_size(bb->values); i += 1) {
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_mir_instr_t *instr =
|
||||
scc_vec_sized_at_ptr(bb->values, ctx->mir_module->instr_size, i);
|
||||
if (instr->opcode < 0) {
|
||||
switch (instr->opcode) {
|
||||
case SCC_MIR_PSEUDO_ALLOCA:
|
||||
scc_tree_dump_append_fmt(td, " alloca(%d)",
|
||||
instr->data.alloc.size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
scc_x86_instr_dump(td, (void *)instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,11 +37,9 @@ void scc_mir_dump_func(scc_mir_dump_ctx_t *ctx, const scc_mir_func_t *func) {
|
||||
scc_tree_dump_t *td = ctx->dump_ctx;
|
||||
|
||||
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||
// 函数头部
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_node(td, "func @%s", func->name ? func->name : "<anon>");
|
||||
|
||||
// 输出所有基本块
|
||||
scc_vec_foreach(func->bblocks, i) {
|
||||
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
|
||||
const scc_cfg_bblock_t *bb =
|
||||
@@ -67,7 +50,6 @@ void scc_mir_dump_func(scc_mir_dump_ctx_t *ctx, const scc_mir_func_t *func) {
|
||||
|
||||
void scc_mir_dump_module(scc_mir_dump_ctx_t *ctx) {
|
||||
scc_vec_foreach(ctx->mir_module->cfg_module.symbols, i) {
|
||||
// FIXME 0 is null
|
||||
if (i == 0)
|
||||
continue;
|
||||
scc_cfg_symbol_t *sym =
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "scc_mir_module.h"
|
||||
|
||||
void scc_mir_module_init(scc_mir_module_t *mir_module) {
|
||||
mir_module->instr_size = 0;
|
||||
mir_module->cfg_module = (scc_cfg_module_t){0};
|
||||
scc_vec_init(mir_module->func_metas);
|
||||
scc_vec_init(mir_module->symbol_metas);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,80 @@
|
||||
#include <arch/x86_64_reg_alloc.h>
|
||||
#include <arch/scc_x86_mir.h>
|
||||
#include <arch/scc_x86_reg_alloc.h>
|
||||
#include <target/scc_win64.h>
|
||||
|
||||
#include <core_pass/scc_frame_layout.h>
|
||||
#include <core_pass/scc_reg_alloc.h>
|
||||
// #include <core_pass/scc_frame_layout.h>
|
||||
// #include <core_pass/scc_prolog_epilog.h>
|
||||
// #include <core_pass/scc_reg_alloc.h>
|
||||
|
||||
#include <scc_mir_module.h>
|
||||
#include <scc_mir_pass.h>
|
||||
|
||||
void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) {
|
||||
Assert(ctx && ctx->impl_fn && 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));
|
||||
}
|
||||
}
|
||||
|
||||
void scc_prolog_epilog(scc_prolog_epilog_t *ctx, scc_mir_module_t *module) {
|
||||
Assert(ctx && ctx->epilog && ctx->prolog && module);
|
||||
scc_vec_foreach(module->cfg_module.funcs, i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
scc_mir_func_t *func = &scc_vec_at(module->cfg_module.funcs, i);
|
||||
scc_vec_foreach(func->bblocks, i) {
|
||||
scc_cfg_bblock_id_t bb_id = scc_vec_at(func->bblocks, i);
|
||||
scc_cfg_bblock_t *bb =
|
||||
scc_cfg_module_unsafe_get_bblock(&module->cfg_module, bb_id);
|
||||
Assert(bb != nullptr);
|
||||
scc_mir_instr_vec_t *old_instrs = SCC_MIR_BBLOCK_VALUES_PTR(bb);
|
||||
scc_mir_instr_vec_t new_instrs;
|
||||
scc_vec_init(new_instrs);
|
||||
|
||||
if (i == 0) {
|
||||
ctx->prolog(&new_instrs, func);
|
||||
}
|
||||
|
||||
scc_vec_foreach(*old_instrs, i) {
|
||||
scc_mir_instr_t *ins =
|
||||
scc_vec_sized_at_ptr(*old_instrs, module->instr_size, i);
|
||||
if (ins->opcode < 0) {
|
||||
continue;
|
||||
}
|
||||
if (ctx->need_epilog(ins)) {
|
||||
ctx->epilog(&new_instrs, func);
|
||||
}
|
||||
scc_vec_sized_push(new_instrs, module->instr_size, ins,
|
||||
module->instr_size);
|
||||
}
|
||||
scc_vec_free(*old_instrs);
|
||||
*old_instrs = new_instrs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage) {
|
||||
scc_reg_alloc_ctx_t reg_alloc_ctx = {
|
||||
.func = nullptr, .instrs = nullptr, .ops = {0}};
|
||||
scc_reg_alloc_ctx_t reg_alloc_ctx = {.func = nullptr, .ops = {0}};
|
||||
scc_reg_alloc_fill_arch_x86(®_alloc_ctx.ops);
|
||||
scc_reg_alloc_fill_win_x64(®_alloc_ctx.ops);
|
||||
scc_win_pc_x64_reg_alloc_fill(®_alloc_ctx.ops);
|
||||
|
||||
scc_reg_alloc(®_alloc_ctx, mir_module);
|
||||
if (stage == SCC_MIR_STAGE_REGALLOC) {
|
||||
return;
|
||||
}
|
||||
|
||||
scc_frame_layout_t frame_layout_ctx = {0};
|
||||
scc_win_pc_x64_frame_alloc_init(&frame_layout_ctx);
|
||||
scc_frame_layout(&frame_layout_ctx, mir_module);
|
||||
if (stage == SCC_MIR_STAGE_FRAME_LAYOUT) {
|
||||
return;
|
||||
}
|
||||
|
||||
scc_prolog_epilog_t prolog_epilog_ctx = {0};
|
||||
scc_win_pc_x64_prolog_epilog_init(&prolog_epilog_ctx);
|
||||
scc_prolog_epilog(&prolog_epilog_ctx, mir_module);
|
||||
if (stage == SCC_MIR_STAGE_PROLOGUE_EPILOGUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,60 +1,59 @@
|
||||
#include <scc_mir_module.h>
|
||||
#include <x86/scc_x86_iform.h>
|
||||
|
||||
#include <arch/x86_64_isel.h>
|
||||
#include <core_pass/scc_abi_lowering.h>
|
||||
#include <arch/scc_x86_isel.h>
|
||||
#include <core_pass/scc_prolog_epilog.h>
|
||||
#include <target/scc_win64.h>
|
||||
|
||||
static const int WIN64_DEFAULT_ALIGN = 8;
|
||||
static const int WIN64_STACK_ALIGN = 16;
|
||||
|
||||
typedef struct {
|
||||
scc_hashtable_t *vreg2slot;
|
||||
int offset;
|
||||
} frame_layout_ctx_t;
|
||||
|
||||
static void transit_vreg(scc_mir_func_meta_t *func, scc_mir_operand_t *op) {
|
||||
Assert(op->kind == SCC_MIR_OP_VREG);
|
||||
}
|
||||
|
||||
static void frame_alloc_impl(frame_layout_ctx_t *ctx,
|
||||
static void frame_alloc_impl(scc_frame_layout_t *ctx,
|
||||
scc_mir_module_t *mir_module,
|
||||
scc_mir_func_t *mir_func) {
|
||||
/*
|
||||
WIN ABI
|
||||
*/
|
||||
ctx->offset = 8; // called ret address
|
||||
|
||||
ctx->offset = 8;
|
||||
scc_mir_func_meta_t *func_meta = SCC_MIR_FUNC_META(mir_func);
|
||||
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_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES(bb);
|
||||
scc_mir_x86_instr_vec_t *instrs = SCC_MIR_X86_BBLOCK_INSTRS(bb);
|
||||
scc_vec_foreach(*instrs, j) {
|
||||
scc_mir_instr_t *ins = &scc_vec_at(*instrs, j);
|
||||
for (int k = 0; k < ins->num_operands; k += 1) {
|
||||
if (ins->operands[k].kind == SCC_MIR_OP_VREG) {
|
||||
transit_vreg(func_meta, &ins->operands[k]);
|
||||
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->offset == 0) {
|
||||
ctx->offset += slot->size;
|
||||
slot->offset = ctx->offset;
|
||||
}
|
||||
op->mem.base = SCC_X86_REG_RSP;
|
||||
op->mem.disp = -slot->offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Windows shadow space
|
||||
int total_size = ctx->offset + 32; // 加上影子空间
|
||||
// 16 字节栈对齐
|
||||
int total_size = ctx->offset + 32; // shadow space
|
||||
ctx->offset =
|
||||
(total_size + WIN64_STACK_ALIGN - 1) & ~(WIN64_STACK_ALIGN - 1);
|
||||
func_meta->frame_size = ctx->offset;
|
||||
}
|
||||
|
||||
void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx) {
|
||||
ctx->impl_fn = frame_alloc_impl;
|
||||
}
|
||||
|
||||
/*
|
||||
windows x86 prolog epilog
|
||||
https://learn.microsoft.com/zh-cn/cpp/build/prolog-and-epilog?view=msvc-180
|
||||
*/
|
||||
static void prologue(void *userdata, const scc_mir_func_t *func) {
|
||||
scc_x86_64_isel_t *isel = userdata;
|
||||
static void prologue(scc_mir_instr_vec_t *userdata,
|
||||
const scc_mir_func_t *func) {
|
||||
scc_mir_x86_instr_vec_t *instrs = (void *)userdata;
|
||||
scc_mir_x86_instr_t instr;
|
||||
/*
|
||||
mov [RSP + 8], RCX
|
||||
push R15
|
||||
@@ -65,25 +64,26 @@ static void prologue(void *userdata, const scc_mir_func_t *func) {
|
||||
...
|
||||
*/
|
||||
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||
int frame_size = meta->frame_size; // 之前计算好的
|
||||
int frame_size = meta->frame_size;
|
||||
|
||||
// 1. push rbp
|
||||
add_instr_1(isel, SCC_X86_IFORM_PUSH_GPRV_50, reg_operand(SCC_X86_REG_RBP));
|
||||
// va_arg
|
||||
if (meta->need_va_args) {
|
||||
/// FILL to shadow space
|
||||
}
|
||||
|
||||
// 2. mov rbp, rsp
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89,
|
||||
reg_operand(SCC_X86_REG_RBP), reg_operand(SCC_X86_REG_RSP));
|
||||
|
||||
// 3. sub rsp, frame_size
|
||||
// sub rsp, frame_size
|
||||
if (frame_size > 0) {
|
||||
scc_mir_operand_t imm = {.kind = SCC_MIR_OP_IMM, .imm = frame_size};
|
||||
add_instr_2(isel, SCC_X86_IFORM_SUB_GPRV_IMMZ,
|
||||
reg_operand(SCC_X86_REG_RSP), imm);
|
||||
scc_mir_x86_instr_2(&instr, SCC_X86_IFORM_SUB_GPRV_IMMZ,
|
||||
scc_x86_op_preg(SCC_X86_REG_RSP),
|
||||
scc_x86_op_imm(frame_size), scc_pos_create());
|
||||
scc_vec_push(*instrs, instr);
|
||||
}
|
||||
}
|
||||
|
||||
static void epilogue(void *userdata, const scc_mir_func_t *func) {
|
||||
scc_x86_64_isel_t *isel = userdata;
|
||||
static void epilogue(scc_mir_instr_vec_t *userdata,
|
||||
const scc_mir_func_t *func) {
|
||||
scc_mir_x86_instr_vec_t *instrs = (void *)userdata;
|
||||
scc_mir_x86_instr_t instr;
|
||||
/*
|
||||
add RSP, fixed-allocation-size
|
||||
pop R13
|
||||
@@ -91,91 +91,99 @@ static void epilogue(void *userdata, const scc_mir_func_t *func) {
|
||||
pop R15
|
||||
ret
|
||||
*/
|
||||
// 1. mov rsp, rbp
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89,
|
||||
reg_operand(SCC_X86_REG_RSP), reg_operand(SCC_X86_REG_RBP));
|
||||
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||
int frame_size = meta->frame_size;
|
||||
|
||||
// 2. pop rbp
|
||||
add_instr_1(isel, SCC_X86_IFORM_POP_GPRV_58, reg_operand(SCC_X86_REG_RBP));
|
||||
// add rsp, frame_size
|
||||
if (frame_size > 0) {
|
||||
scc_mir_x86_instr_2(&instr, SCC_X86_IFORM_ADD_GPRV_IMMZ,
|
||||
scc_x86_op_preg(SCC_X86_REG_RSP),
|
||||
scc_x86_op_imm(frame_size), scc_pos_create());
|
||||
scc_vec_push(*instrs, instr);
|
||||
}
|
||||
}
|
||||
|
||||
static int need_epilog(const scc_mir_instr_t *instr) {
|
||||
scc_mir_x86_instr_t *ins = (scc_mir_x86_instr_t *)instr;
|
||||
switch (ins->x86_instr.opcode) {
|
||||
case SCC_X86_IFORM_RET_FAR:
|
||||
case SCC_X86_IFORM_RET_NEAR:
|
||||
case SCC_X86_IFORM_RET_FAR_IMMW:
|
||||
case SCC_X86_IFORM_RET_NEAR_IMMW:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx) {
|
||||
ctx->prolog = prologue;
|
||||
ctx->epilog = epilogue;
|
||||
ctx->need_epilog = need_epilog;
|
||||
}
|
||||
|
||||
static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
|
||||
scc_x86_64_isel_t *isel = userdata;
|
||||
/*
|
||||
Windows x64 parameter passing
|
||||
https://learn.microsoft.com/zh-cn/cpp/build/x64-calling-convention?view=msvc-180#parameter-passing
|
||||
|
||||
eg.
|
||||
func1(int a, int b, int c, int d, int e, int f);
|
||||
// a in RCX, b in RDX, c in R8, d in R9, f then e passed on stack
|
||||
|
||||
func2(float a, double b, float c, double d, float e, float f);
|
||||
// a in XMM0, b in XMM1, c in XMM2, d in XMM3, f then e passed on stack
|
||||
|
||||
func3(int a, double b, int c, float d, int e, float f);
|
||||
// a in RCX, b in XMM1, c in R8, d in XMM3, f then e passed on stack
|
||||
|
||||
func4(__m64 a, __m128 b, struct c, float d, __m128 e, __m128 f);
|
||||
// a in RCX, ptr to b in RDX, ptr to c in R8, d in XMM3,
|
||||
// ptr to f passed on stack, then ptr to e passed on stack
|
||||
*/
|
||||
|
||||
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) {
|
||||
case 0:
|
||||
scc_x86_emit_move(isel, reg_operand(SCC_X86_REG_RCX),
|
||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RCX),
|
||||
scc_x86_lir_val_to_mir_op(isel, args), 8);
|
||||
break;
|
||||
case 1:
|
||||
scc_x86_emit_move(isel, reg_operand(SCC_X86_REG_RDX),
|
||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RDX),
|
||||
scc_x86_lir_val_to_mir_op(isel, args), 8);
|
||||
break;
|
||||
case 2:
|
||||
scc_x86_emit_move(isel, reg_operand(SCC_X86_REG_R8),
|
||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R8),
|
||||
scc_x86_lir_val_to_mir_op(isel, args), 8);
|
||||
break;
|
||||
case 3:
|
||||
scc_x86_emit_move(isel, reg_operand(SCC_X86_REG_R9),
|
||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R9),
|
||||
scc_x86_lir_val_to_mir_op(isel, args), 8);
|
||||
break;
|
||||
default:
|
||||
// Using stack
|
||||
scc_mir_operand_t op = scc_x86_lir_val_to_mir_op(isel, args);
|
||||
scc_x86_operand_value_t op = scc_x86_lir_val_to_mir_op(isel, args);
|
||||
add_instr_1(isel,
|
||||
op.kind == SCC_MIR_OP_PREG || op.kind == SCC_MIR_OP_VREG
|
||||
? SCC_X86_IFORM_PUSH_GPRV_50
|
||||
op.kind == SCC_X86_OPR_REG ? SCC_X86_IFORM_PUSH_GPRV_50
|
||||
: SCC_X86_IFORM_PUSH_IMMZ,
|
||||
op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit_call(isel, instr->metadata.call.callee);
|
||||
emit_direct_call(isel, instr->metadata.call.callee);
|
||||
|
||||
scc_mir_operand_t ret_reg = scc_x86_lir_val_to_mir_op(isel, &instr->to);
|
||||
if (ret_reg.kind == SCC_MIR_OP_VREG) {
|
||||
scc_x86_emit_move(isel, ret_reg, reg_operand(SCC_X86_REG_RAX), 8);
|
||||
} else {
|
||||
TODO();
|
||||
scc_x86_operand_value_t ret_reg =
|
||||
scc_x86_lir_val_to_mir_op(isel, &instr->to);
|
||||
if (ret_reg.kind != SCC_X86_OPR_NONE) {
|
||||
scc_x86_emit_move(isel, ret_reg, scc_x86_op_preg(SCC_X86_REG_RAX), 8);
|
||||
}
|
||||
}
|
||||
|
||||
static scc_mir_operand_t lower_param(void *userdata, const scc_lir_val_t *val) {
|
||||
scc_x86_64_isel_t *isel = userdata;
|
||||
static void lower_param(void *userdata, const scc_lir_val_t *val,
|
||||
void *out_op) {
|
||||
scc_x86_operand_value_t *out = out_op;
|
||||
Assert(val->kind == SCC_LIR_INSTR_KIND_ARG);
|
||||
switch (val->data.arg) {
|
||||
case 0:
|
||||
return reg_operand(SCC_X86_REG_RCX);
|
||||
*out = scc_x86_op_preg(SCC_X86_REG_RCX);
|
||||
break;
|
||||
case 1:
|
||||
return reg_operand(SCC_X86_REG_RDX);
|
||||
*out = scc_x86_op_preg(SCC_X86_REG_RDX);
|
||||
break;
|
||||
case 2:
|
||||
return reg_operand(SCC_X86_REG_R8);
|
||||
*out = scc_x86_op_preg(SCC_X86_REG_R8);
|
||||
break;
|
||||
case 3:
|
||||
return reg_operand(SCC_X86_REG_R9);
|
||||
*out = scc_x86_op_preg(SCC_X86_REG_R9);
|
||||
break;
|
||||
default:
|
||||
return (scc_mir_operand_t){.kind = SCC_MIR_OP_MEM,
|
||||
.stack_slot = -val->data.arg};
|
||||
*out = scc_x86_op_slot(-val->data.arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +191,7 @@ static void lower_ret(void *userdata, const scc_lir_instr_t *instr) {
|
||||
scc_x86_64_isel_t *isel = userdata;
|
||||
scc_lir_val_t ret_val = instr->metadata.ret_val;
|
||||
if (ret_val.kind != SCC_LIR_INSTR_KIND_NONE) {
|
||||
scc_x86_emit_move(isel, reg_operand(SCC_X86_REG_RAX),
|
||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RAX),
|
||||
scc_x86_lir_val_to_mir_op(isel, &ret_val), 8);
|
||||
}
|
||||
emit_ret(isel);
|
||||
@@ -200,45 +208,7 @@ void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering) {
|
||||
abi_lowering->lower_va_end = nullptr;
|
||||
}
|
||||
|
||||
static const int reg_pool[] = {
|
||||
SCC_X86_REG_R8, SCC_X86_REG_R9, SCC_X86_REG_R10, SCC_X86_REG_R11,
|
||||
SCC_X86_REG_R12, SCC_X86_REG_R13, SCC_X86_REG_R14, SCC_X86_REG_R15};
|
||||
static uint32_t reg_mask = 0; // 1 表示已占用
|
||||
|
||||
static int acquire_reg(void *ctx) {
|
||||
for (int i = 0; i < SCC_ARRLEN(reg_pool); i++)
|
||||
if (!(reg_mask & (1u << i))) {
|
||||
reg_mask |= (1u << i);
|
||||
return reg_pool[i];
|
||||
}
|
||||
UNREACHABLE(); // 可改为溢出逻辑
|
||||
}
|
||||
|
||||
static void release_reg(void *ctx, int preg) {
|
||||
for (int i = 0; i < SCC_ARRLEN(reg_pool); i++)
|
||||
if (reg_pool[i] == preg) {
|
||||
reg_mask &= ~(1u << i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_reg_used(void *ctx, int preg) {
|
||||
for (int i = 0; i < SCC_ARRLEN(reg_pool); i++)
|
||||
if (reg_pool[i] == preg) {
|
||||
reg_mask |= (1u << i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
static void clean_mark_regs(void *ctx) { reg_mask = 0; }
|
||||
|
||||
void scc_reg_alloc_fill_win_x64(scc_reg_alloc_op_t *ops) {
|
||||
ops->acquire_reg = acquire_reg;
|
||||
ops->release_reg = release_reg;
|
||||
ops->mark_reg_used = mark_reg_used;
|
||||
ops->clean_mark_regs = clean_mark_regs;
|
||||
}
|
||||
|
||||
void scc_win_pc_x64_prolog_epilog(scc_prolog_epilog_t *prolog_epilog) {
|
||||
prolog_epilog->prolog = prologue;
|
||||
prolog_epilog->epilog = epilogue;
|
||||
void scc_win_pc_x64_reg_alloc_fill(scc_reg_alloc_op_t *ops) {
|
||||
(void)ops;
|
||||
// 寄存器池已在 scc_reg_alloc_fill_arch_x86 中注册
|
||||
}
|
||||
|
||||
@@ -2,44 +2,30 @@
|
||||
#include <scc_mcode.h>
|
||||
#include <scc_mir_module.h>
|
||||
|
||||
#include <arch/scc_x86_mir.h>
|
||||
#include <x86/scc_x86_encode.h>
|
||||
#include <x86/scc_x86_iform.h>
|
||||
#include <x86/scc_x86_reg.h>
|
||||
|
||||
void mir_x86_to_mcode(scc_mcode_t *mcode, const scc_mir_instr_t *ins) {
|
||||
void mir_x86_to_mcode(scc_mcode_t *mcode, const scc_mir_x86_instr_t *_ins) {
|
||||
scc_x86_instr_t *ins = (void *)_ins;
|
||||
if (ins->opcode < 0 || ins->opcode >= SCC_X86_IFORM_COUNT) {
|
||||
return;
|
||||
}
|
||||
scc_x86_operand_value_t ops[8] = {0};
|
||||
for (int i = 0; i < ins->num_operands; i += 1) {
|
||||
switch (ins->operands[i].kind) {
|
||||
case SCC_MIR_OP_VREG:
|
||||
for (int i = 0; i < ins->num_operands; i++) {
|
||||
if (scc_x86_op_is_vreg(&ins->operands[i]))
|
||||
Panic("can't convert vreg to mcode");
|
||||
break;
|
||||
case SCC_MIR_OP_PREG:
|
||||
ops[i].kind = SCC_X86_OPR_REG;
|
||||
ops[i].reg = ins->operands[i].preg;
|
||||
break;
|
||||
case SCC_MIR_OP_MEM:
|
||||
Panic("can't convert mem to mcode");
|
||||
break;
|
||||
case SCC_MIR_OP_IMM:
|
||||
ops[i].kind = SCC_X86_OPR_IMM;
|
||||
ops[i].imm = ins->operands[i].imm;
|
||||
break;
|
||||
case SCC_MIR_OP_SYMBOL:
|
||||
case SCC_MIR_OP_BLOCK:
|
||||
ops[i].kind = SCC_X86_OPR_RELBR;
|
||||
ops[i].imm = 0;
|
||||
break;
|
||||
default:
|
||||
Panic("unsupported operand kind");
|
||||
};
|
||||
if (scc_x86_op_is_slot(&ins->operands[i]))
|
||||
Panic("can't convert unresolved slot to mcode");
|
||||
ops[i] = ins->operands[i];
|
||||
}
|
||||
scc_x86_encode_inst(mcode, ins->opcode, ops);
|
||||
}
|
||||
|
||||
void scc_ir2mcode_emit_instr(scc_mcode_t *mcode,
|
||||
const scc_mir_instr_t *mir_instr) {
|
||||
// TODO
|
||||
mir_x86_to_mcode(mcode, mir_instr);
|
||||
mir_x86_to_mcode(mcode, (const scc_mir_x86_instr_t *)mir_instr);
|
||||
}
|
||||
|
||||
void scc_ir2mcode(scc_mcode_t *mcode, const scc_mir_module_t *mir_module) {
|
||||
@@ -51,9 +37,11 @@ void scc_ir2mcode(scc_mcode_t *mcode, const scc_mir_module_t *mir_module) {
|
||||
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
|
||||
const scc_cfg_bblock_t *bb =
|
||||
scc_cfg_module_unsafe_get_bblock(&mir_module->cfg_module, id);
|
||||
scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES(bb);
|
||||
const scc_mir_x86_instr_vec_t *instrs =
|
||||
SCC_MIR_BBLOCK_VALUES_PTR(bb);
|
||||
scc_vec_foreach(*instrs, i) {
|
||||
const scc_mir_instr_t *ins = &scc_vec_at(*instrs, i);
|
||||
const scc_mir_instr_t *ins =
|
||||
scc_vec_sized_at_ptr(*instrs, mir_module->instr_size, i);
|
||||
scc_ir2mcode_emit_instr(mcode, ins);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@ static inline void scc_ir_sym_to_sccf_sym(const scc_cfg_symbol_t *symbol,
|
||||
switch (symbol->kind) {
|
||||
case SCC_CFG_SYMBOL_KIND_DATA:
|
||||
sym->sccf_sym_type = SCCF_SYM_TYPE_DATA;
|
||||
sym->sccf_sect_type = SCCF_SECT_DATA;
|
||||
break;
|
||||
case SCC_CFG_SYMBOL_KIND_FUNC:
|
||||
sym->sccf_sym_type = SCCF_SYM_TYPE_FUNC;
|
||||
sym->sccf_sect_type = SCCF_SECT_CODE;
|
||||
break;
|
||||
case SCC_CFG_SYMBOL_KIND_EXTERN:
|
||||
sym->sccf_sym_type = SCCF_SYM_TYPE_EXTERN;
|
||||
sym->sccf_sect_type = SCCF_SECT_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -42,6 +45,11 @@ void scc_ir2sccf(sccf_builder_t *builder, scc_mir_module_t *mir_module) {
|
||||
scc_vec_init(sect_data);
|
||||
|
||||
scc_vec_foreach(mir_module->cfg_module.symbols, i) {
|
||||
if (i == 0) {
|
||||
// FIXME
|
||||
continue;
|
||||
}
|
||||
|
||||
scc_cfg_symbol_t *symbol =
|
||||
&scc_vec_at(mir_module->cfg_module.symbols, i);
|
||||
|
||||
@@ -80,9 +88,10 @@ void scc_ir2sccf(sccf_builder_t *builder, scc_mir_module_t *mir_module) {
|
||||
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
|
||||
const scc_cfg_bblock_t *bb =
|
||||
scc_cfg_module_unsafe_get_bblock(&mir_module->cfg_module, id);
|
||||
scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES(bb);
|
||||
scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES_PTR(bb);
|
||||
scc_vec_foreach(*instrs, i) {
|
||||
const scc_mir_instr_t *ins = &scc_vec_at(*instrs, i);
|
||||
const scc_mir_instr_t *ins =
|
||||
scc_vec_sized_at_ptr(*instrs, mir_module->instr_size, i);
|
||||
// FIXME reloc symbol needed
|
||||
scc_ir2mcode_emit_instr(&mcode, ins);
|
||||
}
|
||||
|
||||
28
libs/mcode/include/x86/scc_x86_encode.h
Normal file
28
libs/mcode/include/x86/scc_x86_encode.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef __SCC_X86_ENCODE_H__
|
||||
#define __SCC_X86_ENCODE_H__
|
||||
|
||||
#include "../scc_mcode.h"
|
||||
#include "scc_x86_iform.h"
|
||||
#include "scc_x86_reg.h"
|
||||
|
||||
typedef struct {
|
||||
scc_x86_reg_t base;
|
||||
scc_x86_reg_t index;
|
||||
u8 scale; /* 1,2,4,8 */
|
||||
i32 disp;
|
||||
} scc_x86_mem_t;
|
||||
|
||||
typedef struct {
|
||||
scc_x86_operand_kind_t kind;
|
||||
union {
|
||||
scc_x86_reg_t reg;
|
||||
i64 imm;
|
||||
scc_x86_mem_t mem;
|
||||
};
|
||||
} scc_x86_operand_value_t;
|
||||
|
||||
/* 按 iform 发射一条指令,ops 数组长度需与 iform 定义的操作数数目一致 */
|
||||
int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
||||
const scc_x86_operand_value_t *ops);
|
||||
|
||||
#endif /* __SCC_X86_ENCODE_H__ */
|
||||
449
libs/mcode/src/scc_x86_encode.c
Normal file
449
libs/mcode/src/scc_x86_encode.c
Normal file
@@ -0,0 +1,449 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <x86/scc_x86_encode.h>
|
||||
#include <x86/scc_x86_iform.h>
|
||||
#include <x86/scc_x86_reg.h>
|
||||
|
||||
/* ---------- 内部辅助 ---------- */
|
||||
static inline void emit_u8(scc_mcode_t *m, uint8_t v) {
|
||||
scc_mcode_add_u8(m, v);
|
||||
}
|
||||
static inline void emit_u16(scc_mcode_t *m, uint16_t v) {
|
||||
scc_mcode_add_u16(m, v);
|
||||
}
|
||||
static inline void emit_u32(scc_mcode_t *m, uint32_t v) {
|
||||
scc_mcode_add_u32(m, v);
|
||||
}
|
||||
static inline void emit_u64(scc_mcode_t *m, uint64_t v) {
|
||||
scc_mcode_add_u64(m, v);
|
||||
}
|
||||
|
||||
/* ---------- 寄存器查询 ---------- */
|
||||
static inline uint16_t scc_reg_width(scc_x86_reg_t reg) {
|
||||
if (reg >= SCC_X86_REG_COUNT || reg == SCC_X86_REG_INVALID)
|
||||
return 0;
|
||||
return scc_x86_reg_table[reg].width;
|
||||
}
|
||||
static inline int scc_reg_ordinal(scc_x86_reg_t reg) {
|
||||
if (reg >= SCC_X86_REG_COUNT || reg == SCC_X86_REG_INVALID)
|
||||
return 0;
|
||||
return scc_x86_reg_table[reg].ordinal;
|
||||
}
|
||||
static int reg_low3(scc_x86_reg_t reg) {
|
||||
if (reg == SCC_X86_REG_INVALID)
|
||||
return 0;
|
||||
return scc_reg_ordinal(reg) & 7;
|
||||
}
|
||||
static int reg_rex_bit(scc_x86_reg_t reg) {
|
||||
if (reg == SCC_X86_REG_INVALID)
|
||||
return 0;
|
||||
if (reg >= SCC_X86_REG_AH && reg <= SCC_X86_REG_DH)
|
||||
return 0;
|
||||
return (scc_reg_ordinal(reg) >= 8) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* ---------- 操作数宽度推导 ---------- */
|
||||
static int infer_operand_width(const scc_x86_iform_info_t *info,
|
||||
const scc_x86_operand_value_t ops[]) {
|
||||
for (int i = 0; i < info->num_explicit_ops; i++) {
|
||||
if (ops[i].kind == SCC_X86_OPR_REG && !info->ops[i].is_implicit) {
|
||||
uint16_t w = scc_reg_width(ops[i].reg);
|
||||
if (w > 0)
|
||||
return w;
|
||||
}
|
||||
}
|
||||
const char *eosz = info->encode.eosz;
|
||||
int default_64 = info->encode.default_64b;
|
||||
if (!strcmp(eosz, "o16"))
|
||||
return 16;
|
||||
if (!strcmp(eosz, "o32"))
|
||||
return 32;
|
||||
if (!strcmp(eosz, "o64"))
|
||||
return 64;
|
||||
if (!strcmp(eosz, "oszall") || !strcmp(eosz, "osznot16"))
|
||||
return default_64 ? 64 : 32;
|
||||
return 32;
|
||||
}
|
||||
|
||||
/* ---------- 前缀决策 ---------- */
|
||||
static int need_rexw(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op,
|
||||
scc_x86_reg_t rm_op, scc_x86_reg_t base,
|
||||
scc_x86_reg_t idx) {
|
||||
/* 强制要求 / 明确禁止 优先级最高 */
|
||||
if (enc->rex_w == 1)
|
||||
return 1;
|
||||
if (enc->rex_w == 0)
|
||||
return 0;
|
||||
|
||||
/* 指令已隐含 64 位语义(如 PUSH/POP),但仍可能被 64 位操作数需要 W?例如
|
||||
* PUSH r64 不需要 W,但 PUSH r/m64 也不需要。总之 default_64b
|
||||
* 时一般无需额外 W,但若操作数明确是 64 位且模板没有禁止,我们仍加上以兼容
|
||||
* movabs 等 */
|
||||
int has_64bit_op = 0;
|
||||
if (reg_op != SCC_X86_REG_INVALID && scc_reg_width(reg_op) == 64)
|
||||
has_64bit_op = 1;
|
||||
if (rm_op != SCC_X86_REG_INVALID && scc_reg_width(rm_op) == 64)
|
||||
has_64bit_op = 1;
|
||||
if (base != SCC_X86_REG_INVALID && scc_reg_width(base) == 64)
|
||||
has_64bit_op = 1;
|
||||
if (idx != SCC_X86_REG_INVALID && scc_reg_width(idx) == 64)
|
||||
has_64bit_op = 1;
|
||||
|
||||
if (enc->default_64b) {
|
||||
/* 对于默认 64 位的指令(如 CALL, JMP),有些仍需要 REX.W
|
||||
* 访问扩展寄存器,但若 reg/rm 本身是 64 位且需要 REX.B/R 则一并设置 W
|
||||
* 来保证编码正确?这里简单处理:只要访问扩展寄存器就加 W */
|
||||
return (reg_op != SCC_X86_REG_INVALID && reg_rex_bit(reg_op)) ||
|
||||
(rm_op != SCC_X86_REG_INVALID && reg_rex_bit(rm_op)) ||
|
||||
(base != SCC_X86_REG_INVALID && reg_rex_bit(base)) ||
|
||||
(idx != SCC_X86_REG_INVALID && reg_rex_bit(idx))
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
/* 普通指令:有 64 位操作数即加 W */
|
||||
return has_64bit_op;
|
||||
}
|
||||
|
||||
static int need_66_prefix(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op,
|
||||
scc_x86_reg_t rm_op) {
|
||||
if (enc->osz_required)
|
||||
return 1;
|
||||
// 如果强制指定了操作大小,不自动加66
|
||||
if (!strcmp(enc->eosz, "o32") || !strcmp(enc->eosz, "o64"))
|
||||
return 0;
|
||||
if (reg_op != SCC_X86_REG_INVALID && scc_reg_width(reg_op) == 16)
|
||||
return 1;
|
||||
if (rm_op != SCC_X86_REG_INVALID && scc_reg_width(rm_op) == 16)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
static int need_67_prefix(const scc_x86_encoding_t *enc, scc_x86_reg_t base,
|
||||
scc_x86_reg_t idx) {
|
||||
(void)enc;
|
||||
(void)base;
|
||||
(void)idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void emit_legacy_prefixes(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
||||
scc_x86_reg_t reg_op, scc_x86_reg_t rm_op,
|
||||
scc_x86_reg_t base, scc_x86_reg_t idx) {
|
||||
if (enc->has_lock)
|
||||
emit_u8(m, 0xF0);
|
||||
if (enc->f2_required)
|
||||
emit_u8(m, 0xF2);
|
||||
if (enc->f3_required)
|
||||
emit_u8(m, 0xF3);
|
||||
if (need_66_prefix(enc, reg_op, rm_op))
|
||||
emit_u8(m, 0x66);
|
||||
if (need_67_prefix(enc, base, idx))
|
||||
emit_u8(m, 0x67);
|
||||
}
|
||||
|
||||
static void emit_rex(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
||||
scc_x86_reg_t reg_op, scc_x86_reg_t rm_op,
|
||||
scc_x86_reg_t base, scc_x86_reg_t idx) {
|
||||
int rex = 0x40;
|
||||
if (need_rexw(enc, reg_op, rm_op, base, idx))
|
||||
rex |= 8;
|
||||
if (reg_op != SCC_X86_REG_INVALID && reg_rex_bit(reg_op))
|
||||
rex |= 4;
|
||||
if (idx != SCC_X86_REG_INVALID && reg_rex_bit(idx))
|
||||
rex |= 2;
|
||||
scc_x86_reg_t b = (rm_op != SCC_X86_REG_INVALID) ? rm_op : base;
|
||||
if (b != SCC_X86_REG_INVALID && reg_rex_bit(b))
|
||||
rex |= 1;
|
||||
if (rex != 0x40) {
|
||||
LOG_INFO("[REX] emit 0x%02x", (uint8_t)rex);
|
||||
emit_u8(m, (uint8_t)rex);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_escape_map(scc_mcode_t *m, const scc_x86_encoding_t *enc) {
|
||||
if (enc->map == 1) {
|
||||
emit_u8(m, 0x0F);
|
||||
} else if (enc->map == 2) {
|
||||
emit_u8(m, 0x0F);
|
||||
emit_u8(m, 0x38);
|
||||
} else if (enc->map == 3) {
|
||||
emit_u8(m, 0x0F);
|
||||
emit_u8(m, 0x3A);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_opcode(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
||||
scc_x86_reg_t rm_reg, scc_x86_reg_t base_reg) {
|
||||
for (int i = 0; i < enc->opcode_len; i++) {
|
||||
uint8_t byte = enc->opcode[i];
|
||||
if (enc->partial_opcode && i == enc->opcode_len - 1) {
|
||||
scc_x86_reg_t target =
|
||||
(rm_reg != SCC_X86_REG_INVALID) ? rm_reg : base_reg;
|
||||
if (target != SCC_X86_REG_INVALID)
|
||||
byte |= (reg_low3(target) & 7);
|
||||
}
|
||||
emit_u8(m, byte);
|
||||
}
|
||||
}
|
||||
|
||||
static int scale_to_enc(uint8_t scale) {
|
||||
switch (scale) {
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1;
|
||||
case 4:
|
||||
return 2;
|
||||
case 8:
|
||||
return 3;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int disp_size(int32_t disp, scc_x86_reg_t base) {
|
||||
if (disp == 0 && base != SCC_X86_REG_RBP && base != SCC_X86_REG_R13)
|
||||
return 0;
|
||||
if (disp >= -128 && disp <= 127)
|
||||
return 8;
|
||||
return 32;
|
||||
}
|
||||
|
||||
/* ---------- 立即数发射(独立函数) ---------- */
|
||||
static void emit_immediate(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
||||
const scc_x86_operand_t *tmpl, int imm_idx,
|
||||
int64_t imm_val, int op_width) {
|
||||
const char *oc2 = tmpl[imm_idx].oc2;
|
||||
int imm_size = enc->imm_size;
|
||||
if (!strcmp(oc2, "b"))
|
||||
imm_size = 1;
|
||||
else if (!strcmp(oc2, "w"))
|
||||
imm_size = 2;
|
||||
else if (!strcmp(oc2, "z"))
|
||||
imm_size = (op_width <= 16) ? op_width / 8 : (op_width <= 32 ? 4 : 4);
|
||||
else if (!strcmp(oc2, "v"))
|
||||
imm_size = op_width / 8;
|
||||
else if (!strcmp(oc2, "d") || !strcmp(oc2, "ss"))
|
||||
imm_size = 4;
|
||||
else if (!strcmp(oc2, "q"))
|
||||
imm_size = 8;
|
||||
|
||||
LOG_INFO("[IMM] val=%lld size=%d", imm_val, imm_size);
|
||||
switch (imm_size) {
|
||||
case 1:
|
||||
emit_u8(m, (uint8_t)imm_val);
|
||||
break;
|
||||
case 2:
|
||||
emit_u16(m, (uint16_t)imm_val);
|
||||
break;
|
||||
case 4:
|
||||
emit_u32(m, (uint32_t)imm_val);
|
||||
break;
|
||||
case 8:
|
||||
emit_u64(m, (uint64_t)imm_val);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- ModR/M + SIB + 位移 + 立即数 ---------- */
|
||||
static void emit_modrm_sib_disp(scc_mcode_t *m,
|
||||
const scc_x86_iform_info_t *info,
|
||||
const scc_x86_operand_value_t ops[],
|
||||
int op_width) {
|
||||
const scc_x86_encoding_t *enc = &info->encode;
|
||||
const scc_x86_operand_t *tmpl = info->ops;
|
||||
int num_ops = info->num_explicit_ops;
|
||||
|
||||
scc_x86_reg_t reg_r = SCC_X86_REG_INVALID;
|
||||
scc_x86_reg_t reg_b = SCC_X86_REG_INVALID;
|
||||
int has_mem = 0;
|
||||
scc_x86_mem_t memdesc = {0};
|
||||
int64_t imm_val = 0;
|
||||
int imm_idx = -1;
|
||||
|
||||
for (int i = 0; i < num_ops; i++) {
|
||||
const char *tname = tmpl[i].name;
|
||||
if (ops[i].kind == SCC_X86_OPR_REG) {
|
||||
LOG_INFO("[OPD] %d: REG kind, name=\"%s\" reg=%d", i, tname,
|
||||
ops[i].reg);
|
||||
if (strncmp(tname, "REG0", 4) == 0)
|
||||
reg_r = ops[i].reg;
|
||||
else if (strncmp(tname, "REG1", 4) == 0)
|
||||
reg_b = ops[i].reg;
|
||||
else {
|
||||
if (reg_r == SCC_X86_REG_INVALID)
|
||||
reg_r = ops[i].reg;
|
||||
else if (reg_b == SCC_X86_REG_INVALID)
|
||||
reg_b = ops[i].reg;
|
||||
}
|
||||
} else if (ops[i].kind == SCC_X86_OPR_MEM) {
|
||||
has_mem = 1;
|
||||
memdesc = ops[i].mem;
|
||||
} else if (ops[i].kind == SCC_X86_OPR_IMM) {
|
||||
imm_val = ops[i].imm;
|
||||
imm_idx = i;
|
||||
}
|
||||
}
|
||||
LOG_INFO("[MODRM] reg_r=%d (ord=%d) reg_b=%d (ord=%d)", reg_r,
|
||||
scc_reg_ordinal(reg_r), reg_b, scc_reg_ordinal(reg_b));
|
||||
|
||||
uint8_t modrm = 0;
|
||||
if (has_mem) {
|
||||
if (reg_r != SCC_X86_REG_INVALID)
|
||||
modrm |= (reg_low3(reg_r) & 7) << 3;
|
||||
else if (enc->modrm_reg_fix >= 0)
|
||||
modrm |= (enc->modrm_reg_fix & 7) << 3;
|
||||
|
||||
int32_t disp = memdesc.disp;
|
||||
int dsize = disp_size(disp, memdesc.base);
|
||||
modrm |= (dsize == 0) ? 0 : (dsize == 8) ? 0x40 : 0x80;
|
||||
|
||||
if (memdesc.index != SCC_X86_REG_INVALID) {
|
||||
modrm |= 4;
|
||||
int idx_ord = scc_reg_ordinal(memdesc.index);
|
||||
int base_ord = scc_reg_ordinal(memdesc.base);
|
||||
int scale_enc = scale_to_enc(memdesc.scale);
|
||||
if (scale_enc < 0)
|
||||
return;
|
||||
uint8_t sib = (uint8_t)((scale_enc << 6) | ((idx_ord & 7) << 3) |
|
||||
(base_ord & 7));
|
||||
emit_u8(m, modrm);
|
||||
emit_u8(m, sib);
|
||||
if (dsize == 8)
|
||||
emit_u8(m, (uint8_t)disp);
|
||||
else if (dsize == 32)
|
||||
emit_u32(m, (uint32_t)disp);
|
||||
} else if (memdesc.base == SCC_X86_REG_INVALID) {
|
||||
modrm |= 5;
|
||||
emit_u8(m, modrm);
|
||||
emit_u32(m, (uint32_t)disp);
|
||||
} else {
|
||||
int base_ord = scc_reg_ordinal(memdesc.base);
|
||||
if (memdesc.base == SCC_X86_REG_RSP ||
|
||||
memdesc.base == SCC_X86_REG_R12) {
|
||||
modrm |= 4;
|
||||
uint8_t sib = (uint8_t)((base_ord & 7) | (4 << 3));
|
||||
emit_u8(m, modrm);
|
||||
emit_u8(m, sib);
|
||||
if (dsize == 8)
|
||||
emit_u8(m, (uint8_t)disp);
|
||||
else if (dsize == 32)
|
||||
emit_u32(m, (uint32_t)disp);
|
||||
} else {
|
||||
modrm |= (base_ord & 7);
|
||||
emit_u8(m, modrm);
|
||||
if (dsize == 8)
|
||||
emit_u8(m, (uint8_t)disp);
|
||||
else if (dsize == 32)
|
||||
emit_u32(m, (uint32_t)disp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
modrm = 0xC0;
|
||||
if (enc->modrm_reg_fix >= 0)
|
||||
modrm |= (enc->modrm_reg_fix & 7) << 3;
|
||||
else if (reg_r != SCC_X86_REG_INVALID)
|
||||
modrm |= (reg_low3(reg_r) & 7) << 3;
|
||||
|
||||
if (enc->modrm_rm_fix >= 0) {
|
||||
modrm |= enc->modrm_rm_fix & 7;
|
||||
} else if (reg_b != SCC_X86_REG_INVALID) {
|
||||
modrm |= reg_low3(reg_b) & 7;
|
||||
} else if (enc->modrm_reg_fix >= 0 && reg_r != SCC_X86_REG_INVALID) {
|
||||
modrm |= reg_low3(reg_r) & 7;
|
||||
} else if (reg_r != SCC_X86_REG_INVALID) {
|
||||
modrm |= reg_low3(reg_r) & 7;
|
||||
}
|
||||
emit_u8(m, modrm);
|
||||
}
|
||||
LOG_INFO("[MODRM] emit byte 0x%02x", modrm);
|
||||
|
||||
/* 立即数在 ModRM 后发射 */
|
||||
if (imm_idx >= 0) {
|
||||
emit_immediate(m, enc, tmpl, imm_idx, imm_val, op_width);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 主编码入口 ---------- */
|
||||
int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
||||
const scc_x86_operand_value_t *ops) {
|
||||
if (!mcode || !ops)
|
||||
return -1;
|
||||
|
||||
if (iform >= SCC_X86_IFORM_COUNT || iform < 0)
|
||||
Panic("invalid iform %d", iform);
|
||||
|
||||
const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform];
|
||||
const scc_x86_encoding_t *enc = &info->encode;
|
||||
const scc_x86_operand_t *tmpl = info->ops;
|
||||
int num_ops = info->num_explicit_ops;
|
||||
|
||||
LOG_INFO("[IFORM] %s, explicit_ops=%d (total=%d)", info->iform_name,
|
||||
num_ops, info->num_ops);
|
||||
|
||||
scc_x86_reg_t reg_field = SCC_X86_REG_INVALID;
|
||||
scc_x86_reg_t rm_field = SCC_X86_REG_INVALID;
|
||||
scc_x86_reg_t base_reg = SCC_X86_REG_INVALID;
|
||||
scc_x86_reg_t idx_reg = SCC_X86_REG_INVALID;
|
||||
|
||||
/* ---------- 收集立即数信息(用于无 ModRM 指令) ---------- */
|
||||
int64_t imm_val = 0;
|
||||
int imm_idx = -1;
|
||||
for (int i = 0; i < num_ops; i++) {
|
||||
const char *tname = tmpl[i].name;
|
||||
if (ops[i].kind == SCC_X86_OPR_REG) {
|
||||
if (strncmp(tname, "REG0", 4) == 0) {
|
||||
if (enc->modrm_reg_fix >= 0)
|
||||
rm_field = ops[i].reg; // reg固定 → REG0为rm
|
||||
else
|
||||
reg_field = ops[i].reg; // 否则为reg
|
||||
} else if (strncmp(tname, "REG1", 4) == 0) {
|
||||
if (enc->modrm_rm_fix >= 0)
|
||||
reg_field = ops[i].reg; // rm固定 → REG1为reg
|
||||
else
|
||||
rm_field = ops[i].reg; // 否则为rm
|
||||
} else {
|
||||
// 未命名的寄存器,按先 reg 后 rm 填充
|
||||
if (reg_field == SCC_X86_REG_INVALID)
|
||||
reg_field = ops[i].reg;
|
||||
else if (rm_field == SCC_X86_REG_INVALID)
|
||||
rm_field = ops[i].reg;
|
||||
}
|
||||
} else if (ops[i].kind == SCC_X86_OPR_MEM) {
|
||||
base_reg = ops[i].mem.base;
|
||||
idx_reg = ops[i].mem.index;
|
||||
} else if (ops[i].kind == SCC_X86_OPR_IMM ||
|
||||
ops[i].kind == SCC_X86_OPR_RELBR) {
|
||||
imm_val = ops[i].imm;
|
||||
imm_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
int op_width = infer_operand_width(info, ops);
|
||||
LOG_INFO("[OPWIDTH] %d bits", op_width);
|
||||
|
||||
// +++ 新增:无 ModRM 时,寄存器用 REX.B 扩展 +++
|
||||
if (!enc->has_modrm) {
|
||||
rm_field = reg_field;
|
||||
reg_field = SCC_X86_REG_INVALID;
|
||||
}
|
||||
|
||||
emit_legacy_prefixes(mcode, enc, reg_field, rm_field, base_reg, idx_reg);
|
||||
emit_rex(mcode, enc, reg_field, rm_field, base_reg, idx_reg);
|
||||
emit_escape_map(mcode, enc);
|
||||
|
||||
if (enc->has_modrm) {
|
||||
emit_opcode(mcode, enc, rm_field, base_reg);
|
||||
emit_modrm_sib_disp(mcode, info, ops, op_width);
|
||||
} else {
|
||||
// 无 ModRM:opcode 中的寄存器来自 rm_field
|
||||
emit_opcode(mcode, enc, rm_field, base_reg);
|
||||
if (imm_idx >= 0) {
|
||||
emit_immediate(mcode, enc, tmpl, imm_idx, imm_val, op_width);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __SCC_SEMA_H__
|
||||
|
||||
#include <scc_ast.h>
|
||||
#include <scc_utils.h>
|
||||
|
||||
typedef struct scc_sema_ctx scc_sema_ctx_t;
|
||||
/**
|
||||
@@ -13,6 +14,12 @@ typedef void (*scc_sema_callback_t)(scc_sema_ctx_t *context,
|
||||
typedef scc_ast_qual_type_t *(*scc_sema_got_type_t)(scc_sema_ctx_t *context,
|
||||
const char *name);
|
||||
|
||||
typedef struct scc_label_scope {
|
||||
int function_scope_depth;
|
||||
scc_hashtable_t labels; // 标签名 -> scc_ast_stmt_t* (LABEL节点)
|
||||
scc_ast_stmt_vec_t pending_gotos; // 尚未找到目标的goto语句
|
||||
} scc_sema_label_scope_t;
|
||||
|
||||
/**
|
||||
* @brief 语义分析回调集合
|
||||
*/
|
||||
@@ -26,6 +33,7 @@ struct scc_sema_ctx {
|
||||
|
||||
scc_ast_stmt_vec_t break_stack;
|
||||
scc_ast_stmt_vec_t continue_stack;
|
||||
scc_sema_label_scope_t label_scope;
|
||||
void *context;
|
||||
};
|
||||
|
||||
|
||||
@@ -290,7 +290,10 @@ CONTINUE:
|
||||
decl->var.init = scc_parse_initializer(parser, lvalue);
|
||||
} else if (tok_ptr->type == SCC_TOK_L_BRACE) {
|
||||
scc_parse_decl_sema(parser, decl);
|
||||
scc_sema_decl(parser, scc_ast_decl_t_BEGIN, nullptr);
|
||||
|
||||
// 进入函数作用域(用于参数和标签)
|
||||
scc_sema_decl(parser, scc_ast_decl_t_BEGIN, decl);
|
||||
|
||||
// FIXME hack struct
|
||||
scc_vec_foreach(decl->func.type->type->function.params, i) {
|
||||
scc_ast_decl_t *param =
|
||||
@@ -299,7 +302,10 @@ CONTINUE:
|
||||
scc_parse_decl_sema(parser, param);
|
||||
}
|
||||
scc_ast_stmt_t *body = scc_parse_statement(parser);
|
||||
scc_sema_decl(parser, scc_ast_decl_t_END, nullptr);
|
||||
|
||||
// 退出函数作用域
|
||||
scc_sema_decl(parser, scc_ast_decl_t_END, decl);
|
||||
|
||||
Assert(decl->base.type == SCC_AST_DECL_FUNC);
|
||||
decl->func.body = body;
|
||||
Assert(decl->func.type != nullptr);
|
||||
|
||||
@@ -73,6 +73,7 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
|
||||
if (decl != nullptr) {
|
||||
scc_vec_push(unit->declarations, decl);
|
||||
} else {
|
||||
parser->errcode = 1;
|
||||
break;
|
||||
}
|
||||
if (parser->errcode != 0) { // FIXME errcode
|
||||
|
||||
@@ -133,37 +133,72 @@ static void stmt_callback(scc_sema_ctx_t *sema_ctx,
|
||||
}
|
||||
scc_ast_stmt_t *stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node);
|
||||
switch (stmt->base.type) {
|
||||
case SCC_AST_STMT_BREAK:
|
||||
case SCC_AST_STMT_BREAK: {
|
||||
if (scc_vec_size(sema_ctx->break_stack) == 0)
|
||||
SCC_ERROR(stmt->base.loc, "break not in loop/switch");
|
||||
else
|
||||
stmt->jump._target = scc_vec_at(
|
||||
sema_ctx->break_stack, scc_vec_size(sema_ctx->break_stack) - 1);
|
||||
break;
|
||||
case SCC_AST_STMT_CONTINUE:
|
||||
} break;
|
||||
case SCC_AST_STMT_CONTINUE: {
|
||||
if (scc_vec_size(sema_ctx->continue_stack) == 0)
|
||||
SCC_ERROR(stmt->base.loc, "continue not in loop");
|
||||
else
|
||||
stmt->jump._target =
|
||||
scc_vec_at(sema_ctx->continue_stack,
|
||||
scc_vec_size(sema_ctx->continue_stack) - 1);
|
||||
case SCC_AST_STMT_GOTO:
|
||||
scc_ast_node_t *target_node =
|
||||
scc_sema_symtab_lookup_symbol(sema_symtab, stmt->goto_stmt.label);
|
||||
if (target_node == nullptr) {
|
||||
SCC_ERROR(stmt->base.loc, "");
|
||||
} break;
|
||||
case SCC_AST_STMT_GOTO: {
|
||||
scc_ast_stmt_t *goto_stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node);
|
||||
scc_sema_label_scope_t *scope = &sema_ctx->label_scope;
|
||||
if (scope->function_scope_depth != 1) {
|
||||
SCC_ERROR(goto_stmt->base.loc, "goto not inside any function");
|
||||
break;
|
||||
}
|
||||
if (!SCC_AST_IS_A(scc_ast_stmt_t, target_node)) {
|
||||
SCC_ERROR(stmt->base.loc, "");
|
||||
|
||||
// 尝试直接查找标签
|
||||
scc_ast_node_t *target =
|
||||
scc_hashtable_get(&scope->labels, goto_stmt->goto_stmt.label);
|
||||
if (target) {
|
||||
goto_stmt->goto_stmt._target =
|
||||
SCC_AST_CAST_TO(scc_ast_stmt_t, target);
|
||||
} else {
|
||||
// 未找到则加入待处理列表
|
||||
scc_vec_push(scope->pending_gotos, goto_stmt);
|
||||
}
|
||||
} break;
|
||||
case SCC_AST_STMT_LABEL: {
|
||||
scc_ast_stmt_t *label_stmt = SCC_AST_CAST_TO(scc_ast_stmt_t, node);
|
||||
scc_sema_label_scope_t *scope = &sema_ctx->label_scope;
|
||||
// 获取当前函数标签作用域
|
||||
if (scope->function_scope_depth != 1) {
|
||||
SCC_ERROR(label_stmt->base.loc, "label not inside any function");
|
||||
break;
|
||||
}
|
||||
stmt->goto_stmt._target = SCC_AST_CAST_TO(scc_ast_stmt_t, target_node);
|
||||
break;
|
||||
case SCC_AST_STMT_LABEL:
|
||||
scc_sema_symtab_add_symbol(sema_symtab, stmt->label_stmt.label,
|
||||
&stmt->base);
|
||||
|
||||
// 检查重复定义
|
||||
if (scc_hashtable_get(&scope->labels, label_stmt->label_stmt.label)) {
|
||||
SCC_ERROR(label_stmt->base.loc, "duplicate label '%s'",
|
||||
label_stmt->label_stmt.label);
|
||||
break;
|
||||
}
|
||||
|
||||
// 添加标签
|
||||
scc_hashtable_set(&scope->labels, label_stmt->label_stmt.label,
|
||||
&label_stmt->base);
|
||||
|
||||
// 检查是否有等待该标签的 goto
|
||||
scc_vec_foreach(scope->pending_gotos, i) {
|
||||
scc_ast_stmt_t *goto_stmt = scc_vec_at(scope->pending_gotos, i);
|
||||
if (goto_stmt == nullptr)
|
||||
continue;
|
||||
if (scc_strcmp(goto_stmt->goto_stmt.label,
|
||||
label_stmt->label_stmt.label) == 0) {
|
||||
goto_stmt->goto_stmt._target = label_stmt;
|
||||
scc_vec_at(scope->pending_gotos, i) = nullptr;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -175,10 +210,37 @@ static void decl_callback(scc_sema_ctx_t *sema_ctx,
|
||||
scc_sema_symtab_t *sema_symtab = sema_ctx->context;
|
||||
|
||||
// Function declaration scope
|
||||
// FIXME 使用 node_type 区分其他未来的scope
|
||||
if (node_type == scc_ast_decl_t_BEGIN) {
|
||||
// 创建标签作用域
|
||||
scc_sema_label_scope_t *scope = &sema_ctx->label_scope;
|
||||
scope->function_scope_depth += 1;
|
||||
scc_hashtable_cstr_init(&scope->labels);
|
||||
scc_vec_init(scope->pending_gotos);
|
||||
|
||||
// 进入普通符号表作用域(用于参数和局部变量)
|
||||
scc_sema_symtab_enter_scope(sema_symtab);
|
||||
return;
|
||||
} else if (node_type == scc_ast_decl_t_END) {
|
||||
scc_sema_label_scope_t *scope = &sema_ctx->label_scope;
|
||||
scope->function_scope_depth -= 1;
|
||||
|
||||
// 处理尚未绑定的 goto
|
||||
scc_vec_foreach(scope->pending_gotos, i) {
|
||||
scc_ast_stmt_t *goto_stmt = scc_vec_at(scope->pending_gotos, i);
|
||||
if (goto_stmt == nullptr) {
|
||||
continue;
|
||||
}
|
||||
// 标签未定义 -> 报错
|
||||
SCC_ERROR(goto_stmt->base.loc, "label '%s' used but not defined",
|
||||
goto_stmt->goto_stmt.label);
|
||||
}
|
||||
|
||||
// 清理
|
||||
scc_hashtable_drop(&scope->labels);
|
||||
scc_vec_free(scope->pending_gotos);
|
||||
|
||||
// 退出普通符号表作用域
|
||||
scc_sema_symtab_leave_scope(sema_symtab);
|
||||
return;
|
||||
}
|
||||
@@ -242,6 +304,7 @@ void scc_sema_init(scc_sema_ctx_t *sema_ctx, scc_ast_ctx_t *ast_ctx) {
|
||||
sema_ctx->on_stmt = stmt_callback;
|
||||
sema_ctx->on_type = type_callback;
|
||||
sema_ctx->got_type = got_type_callback;
|
||||
sema_ctx->label_scope = (scc_sema_label_scope_t){0};
|
||||
|
||||
scc_sema_symtab_init(sema_symtab);
|
||||
|
||||
|
||||
@@ -99,11 +99,11 @@ void scc_pproc_parse_include(scc_pproc_t *pp, scc_lexer_tok_t *include_tok,
|
||||
for (int i = 1; i < len - 1; i++) {
|
||||
scc_str_append_ch(&fname, includename[i]);
|
||||
}
|
||||
scc_str_drop(&line);
|
||||
int is_system = includename[0] == '<';
|
||||
if (switch_file_stack(pp, &fname, &pos, is_system)) {
|
||||
// LOG_ERROR()
|
||||
}
|
||||
scc_str_drop(&line);
|
||||
scc_str_drop(&fname);
|
||||
return;
|
||||
ERROR:
|
||||
|
||||
@@ -71,20 +71,17 @@ void scc_tree_dump_append(scc_tree_dump_t *td, const char *s);
|
||||
*/
|
||||
void scc_tree_dump_append_fmt(scc_tree_dump_t *td, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief 追加带节点颜色的文本
|
||||
*/
|
||||
#define scc_tree_dump_node(td, fmt, ...) \
|
||||
scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->node_color, \
|
||||
##__VA_ARGS__, (td)->reset_color)
|
||||
|
||||
/**
|
||||
* @brief 追加带值颜色的格式化文本
|
||||
*/
|
||||
#define scc_tree_dump_value(td, fmt, ...) \
|
||||
scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->value_color, \
|
||||
##__VA_ARGS__, (td)->reset_color)
|
||||
|
||||
#define scc_tree_dump_branch(td, fmt, ...) \
|
||||
scc_tree_dump_append_fmt(td, "%s" fmt "%s", (td)->branch_color, \
|
||||
##__VA_ARGS__, (td)->reset_color)
|
||||
/**
|
||||
* @brief 推入新层级
|
||||
* @param is_last 该层级是否是父节点的最后一个子节点
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#define DEFAULT_BRANCH "|-"
|
||||
#define DEFAULT_LAST_BRANCH "`-"
|
||||
#define DEFAULT_SPACE " "
|
||||
#define NODE_COLOR "\033[34m"
|
||||
#define VALUE_COLOR "\033[32m"
|
||||
#define BRANCH_COLOR "\033[33m"
|
||||
#define RESET_COLOR "\033[0m"
|
||||
#define NODE_COLOR ANSI_FG_GREEN
|
||||
#define VALUE_COLOR ANSI_FG_YELLOW
|
||||
#define BRANCH_COLOR ANSI_FG_CYAN
|
||||
#define RESET_COLOR ANSI_NONE
|
||||
|
||||
void scc_tree_dump_init(scc_tree_dump_t *td, cbool use_color) {
|
||||
scc_str_init(&td->buf);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @brief Arbitrary Precision Library
|
||||
*
|
||||
*/
|
||||
#ifdef __AP_SCC__
|
||||
#ifdef __SCC__
|
||||
#include <scc_core.h>
|
||||
#define SCC_AP_DIGIT u64
|
||||
#define SCC_AP_PANIC Panic
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#define __scc_log_unreachable() (__builtin_unreachable())
|
||||
#elif defined _MSC_VER // MSVC
|
||||
#define __scc_log_unreachable() (__assume(false))
|
||||
#elif defined __SCC_BUILTIN__ // The SCC Compiler (my compiler)
|
||||
#elif defined __SCC_BUILTIN_UNREACHEABLE__ // The SCC Compiler (my compiler)
|
||||
#define __scc_log_unreachable() (__scc_builtin_unreachable())
|
||||
#else
|
||||
#define __scc_log_unreachable() ((void)0)
|
||||
@@ -184,7 +184,7 @@ void log_set_handler(logger_t *logger, log_handler handler);
|
||||
* 或使用 _Static_assert (C11)
|
||||
*/
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#define StaticAssert static_assert
|
||||
#define StaticAssert _Static_assert
|
||||
#else
|
||||
#define StaticAssert(cond, msg) extern char __static_assertion[(cond) ? 1 : -1]
|
||||
#endif
|
||||
|
||||
@@ -13,4 +13,14 @@
|
||||
#define scc_min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define scc_max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define SCC_MAYBE_UNUSED __attribute__((unused))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SCC_MAYBE_UNUSED __pragma(warning(suppress : 4100))
|
||||
#elif defined(__clang__)
|
||||
#define SCC_MAYBE_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define SCC_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#endif // __SCC_CORE_MACRO_H__
|
||||
|
||||
@@ -15,13 +15,16 @@
|
||||
#include "scc_core_type.h"
|
||||
#define __scc_vec_realloc scc_realloc
|
||||
#define __scc_vec_free scc_free
|
||||
#define __scc_vec_memcpy scc_memcpy
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef size_t usize;
|
||||
#define __scc_vec_realloc realloc
|
||||
#define __scc_vec_free free
|
||||
#define __scc_vec_memcpy memcpy
|
||||
|
||||
#ifndef LOG_FATAL
|
||||
#include <stdio.h>
|
||||
@@ -169,4 +172,86 @@ typedef size_t usize;
|
||||
(vec).data = array; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_realloc(vec, elem_size, new_cap)
|
||||
* @brief 内部宏:按 elem_size 重新分配内存
|
||||
*/
|
||||
#define scc_vec_sized_realloc(vec, elem_size, new_cap) \
|
||||
do { \
|
||||
void *new_data = \
|
||||
__scc_vec_realloc((vec).data, (new_cap) * (elem_size)); \
|
||||
if (!new_data) \
|
||||
LOG_FATAL("scc_vec_sized_realloc: failed\n"); \
|
||||
(vec).data = new_data; \
|
||||
(vec).cap = new_cap; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_push(vec, elem_size, src_ptr)
|
||||
* @brief 添加一个元素(从 src_ptr 拷贝 elem_size 字节)
|
||||
* @param vec SCC_VEC(type) 定义的向量变量(type 可为 char 或 void)
|
||||
* @param elem_size 每个元素占用的字节数
|
||||
* @param src_ptr 源数据的指针
|
||||
* @param copy_size 要拷贝的字节数
|
||||
*
|
||||
* @note 使用前需确保 vec.data 类型与 src_ptr 无关,内部会按字节拷贝。
|
||||
* 推荐声明时为 `SCC_VEC(char)` 或 `SCC_VEC(unsigned char)`。
|
||||
*/
|
||||
#define scc_vec_sized_push(vec, elem_size, src_ptr, copy_size) \
|
||||
do { \
|
||||
if ((vec).size >= (vec).cap) { \
|
||||
usize new_cap = (vec).cap ? (vec).cap * 2 : 4; \
|
||||
scc_vec_sized_realloc(vec, elem_size, new_cap); \
|
||||
} \
|
||||
char *slot = (char *)(vec).data + (vec).size * (elem_size); \
|
||||
__scc_vec_memcpy(slot, (src_ptr), (copy_size)); \
|
||||
(vec).size++; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_at_ptr(vec, elem_size, idx)
|
||||
* @brief 获取第 idx 个元素的指针(void*)
|
||||
* @return 指向元素的指针,需转换为具体类型使用
|
||||
*/
|
||||
#define scc_vec_sized_at_ptr(vec, elem_size, idx) \
|
||||
((void *)((char *)(vec).data + (idx) * (elem_size)))
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_foreach(vec, elem_size, elem_ptr_var, block)
|
||||
* @brief 遍历所有元素
|
||||
* @param elem_ptr_var 循环内的变量名(void* 类型)
|
||||
* @param block 循环体语句块
|
||||
*/
|
||||
#define scc_vec_sized_foreach(vec, elem_size, elem_ptr_var, block) \
|
||||
do { \
|
||||
for (usize __i = 0; __i < (vec).size; ++__i) { \
|
||||
void *elem_ptr_var = scc_vec_sized_at_ptr(vec, elem_size, __i); \
|
||||
block; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_pop(vec, elem_size)
|
||||
* @brief 弹出最后一个元素(仅减小 size,不返回数据)
|
||||
*/
|
||||
#define scc_vec_sized_pop(vec, elem_size) \
|
||||
do { \
|
||||
if ((vec).size == 0) \
|
||||
LOG_FATAL("scc_vec_sized_pop: empty\n"); \
|
||||
(vec).size--; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_clear(vec)
|
||||
* @brief 清空向量(重置 size = 0,不释放内存)
|
||||
*/
|
||||
#define scc_vec_sized_clear(vec) ((vec).size = 0)
|
||||
|
||||
/**
|
||||
* @def scc_vec_sized_free(vec)
|
||||
* @brief 释放向量内存(与原始 scc_vec_free 相同,可复用)
|
||||
* @note 注意:如果元素内部有堆资源,需在释放前自行遍历调用析构函数。
|
||||
*/
|
||||
#define scc_vec_sized_free(vec) scc_vec_free(vec)
|
||||
|
||||
#endif /* __SCC_CORE_VEC_H__ */
|
||||
|
||||
@@ -39,8 +39,15 @@ usize scc_fread(scc_file_t file, void *buffer, usize size) {
|
||||
return scc_pal_fread(file, buffer, size);
|
||||
}
|
||||
|
||||
usize scc_fwrite(scc_file_t file, const void *buffer, usize size) {
|
||||
return scc_pal_fwrite(file, buffer, size);
|
||||
usize scc_fwrite(scc_file_t file, const void *buf, usize size) {
|
||||
if (file == scc_stdout) {
|
||||
scc_pal_write(buf, size);
|
||||
} else if (file == scc_stderr) {
|
||||
scc_pal_ewrite(buf, size);
|
||||
} else {
|
||||
return scc_pal_fwrite(file, buf, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cbool scc_fexists(const char *path) {
|
||||
|
||||
@@ -155,7 +155,6 @@ void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
|
||||
static const char *emit_stages[] = {
|
||||
[SCC_EMIT_STAGE_LEX] = "lex",
|
||||
[SCC_EMIT_STAGE_PP] = "pp",
|
||||
|
||||
[SCC_EMIT_STAGE_AST] = "ast", // -T
|
||||
[SCC_EMIT_STAGE_HIR] = "hir", // -H
|
||||
[SCC_EMIT_STAGE_LIR] = "lir", // -L
|
||||
|
||||
45
src/main.c
45
src/main.c
@@ -18,6 +18,8 @@
|
||||
#include <sccf2pe.h>
|
||||
|
||||
#include "config.h"
|
||||
void init_platform(void);
|
||||
#define GET_VALID_FP(fp) (fp == nullptr ? scc_stdout : fp)
|
||||
|
||||
static void print_ring(scc_lexer_tok_ring_t *ring, int verbose) {
|
||||
scc_lexer_tok_t tok = {0};
|
||||
@@ -66,10 +68,21 @@ static void print_file(scc_lexer_tok_ring_t *ring, scc_file_t fp) {
|
||||
static void tree_dump_output(const char *str, usize len, void *user) {
|
||||
scc_fprintf(user, "%.*s", (int)len, str);
|
||||
}
|
||||
static inline int mir_dump(scc_file_t fp, scc_mir_module_t *mir_module) {
|
||||
scc_tree_dump_t tree_dump;
|
||||
scc_mir_dump_ctx_t mir_dump_ctx;
|
||||
if (fp == nullptr) {
|
||||
scc_tree_dump_init(&tree_dump, true);
|
||||
} else {
|
||||
scc_tree_dump_init(&tree_dump, false);
|
||||
}
|
||||
scc_mir_dump_init(&mir_dump_ctx, &tree_dump, mir_module);
|
||||
scc_mir_dump_module(&mir_dump_ctx);
|
||||
|
||||
void init_platform(void);
|
||||
|
||||
#define GET_VALID_FP(fp) (fp == nullptr ? scc_stdout : fp)
|
||||
scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp));
|
||||
scc_tree_dump_drop(&tree_dump);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv, const char **envp) {
|
||||
init_platform();
|
||||
@@ -276,36 +289,20 @@ sstream_drop:
|
||||
|
||||
switch (config.emit_stage) {
|
||||
case SCC_EMIT_STAGE_MIR:
|
||||
goto mir_dump;
|
||||
return mir_dump(fp, &mir_module);
|
||||
case SCC_EMIT_STAGE_MIR_PASS_REG_ALLOC:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC);
|
||||
goto mir_dump;
|
||||
return mir_dump(fp, &mir_module);
|
||||
case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_FRAME_LAYOUT);
|
||||
goto mir_dump;
|
||||
return mir_dump(fp, &mir_module);
|
||||
case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_PROLOGUE_EPILOGUE);
|
||||
goto mir_dump;
|
||||
break;
|
||||
return mir_dump(fp, &mir_module);
|
||||
default:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_ANY);
|
||||
break;
|
||||
}
|
||||
do {
|
||||
mir_dump:
|
||||
scc_mir_dump_ctx_t mir_dump_ctx;
|
||||
scc_tree_dump_t tree_dump;
|
||||
if (fp == nullptr) {
|
||||
scc_tree_dump_init(&tree_dump, true);
|
||||
} else {
|
||||
scc_tree_dump_init(&tree_dump, false);
|
||||
}
|
||||
scc_mir_dump_init(&mir_dump_ctx, &tree_dump, &mir_module);
|
||||
scc_mir_dump_module(&mir_dump_ctx);
|
||||
|
||||
scc_tree_dump_flush(&tree_dump, tree_dump_output, GET_VALID_FP(fp));
|
||||
scc_tree_dump_drop(&tree_dump);
|
||||
return 0;
|
||||
} while (0);
|
||||
|
||||
if (config.emit_stage == SCC_EMIT_STAGE_FLATBIN) {
|
||||
scc_mcode_t mcode = {0};
|
||||
|
||||
Reference in New Issue
Block a user