feat(ast2ir): 实现C11类型提升系统并重构HIR基本块管理
- 新增 scc_ast2ir_promote.c 实现整数提升(6.3.1.1)和寻常算术转换(6.3.1.8) - 重构 HIR Builder: bblock → create_bblock + append_bblock,引入BBList链表管理 - AST2IR 全面集成类型提升:二元运算、赋值、函数调用参数、自增/自减操作符 - 变参函数支持:跳过 ... 假参数,实现默认参数提升(float→double等) - 简化 HIR Dump 实现 - MIR: Win64 ABI改进、x86指令选择优化 - 新增 printf 测试用例
This commit is contained in:
@@ -38,4 +38,33 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt);
|
|||||||
scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||||||
const scc_ast_qual_type_t *ast_type);
|
const scc_ast_qual_type_t *ast_type);
|
||||||
|
|
||||||
|
// ====== 类型提升(Type Promotion)接口 ======
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 整数提升(C11 6.3.1.1)
|
||||||
|
* 对 _Bool、char、short 等秩低于 int 的类型提升为 int/unsigned int
|
||||||
|
* @param type_ref 原始类型引用
|
||||||
|
* @return 提升后的类型的引用,若无需提升则返回原始类型
|
||||||
|
*/
|
||||||
|
scc_hir_type_ref_t scc_ast2ir_integer_promotion(scc_ast2ir_ctx_t *ctx,
|
||||||
|
scc_hir_type_ref_t type_ref);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 寻常算术转换(C11 6.3.1.8)
|
||||||
|
* 对二元算术操作的两个操作数类型找到公共类型
|
||||||
|
* @return 公共类型的引用
|
||||||
|
*/
|
||||||
|
scc_hir_type_ref_t scc_ast2ir_usual_arithmetic_conversion(
|
||||||
|
scc_ast2ir_ctx_t *ctx, scc_hir_type_ref_t t1_ref,
|
||||||
|
scc_hir_type_ref_t t2_ref);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 插入类型转换指令
|
||||||
|
* 根据源类型和目标类型自动选择 SEXT/ZEXT/TRUNC/F2I/I2F/F2F
|
||||||
|
* @return 转换后的值引用
|
||||||
|
*/
|
||||||
|
scc_hir_value_ref_t scc_ast2ir_emit_conversion(scc_ast2ir_ctx_t *ctx,
|
||||||
|
scc_hir_value_ref_t value,
|
||||||
|
scc_hir_type_ref_t target_type);
|
||||||
|
|
||||||
#endif /* __SCC_AST2IR_H__ */
|
#endif /* __SCC_AST2IR_H__ */
|
||||||
|
|||||||
@@ -4,6 +4,26 @@
|
|||||||
#include <scc_hir_builder.h>
|
#include <scc_hir_builder.h>
|
||||||
#include <scc_hir_def.h>
|
#include <scc_hir_def.h>
|
||||||
|
|
||||||
|
// 判断 AST 参数是否为 ... 生成的假 VA_LIST 参数
|
||||||
|
static cbool is_variadic_marker(const scc_ast_decl_t *decl_param) {
|
||||||
|
return decl_param->name == nullptr &&
|
||||||
|
decl_param->param.type->base.type == SCC_AST_TYPE_BUILTIN &&
|
||||||
|
scc_ast_canon_type(decl_param->param.type)->builtin.type ==
|
||||||
|
SCC_AST_BUILTIN_TYPE_VA_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算函数类型中的固定参数个数(去掉尾部的 ... 标记)
|
||||||
|
static int fixed_param_count(const scc_ast_canon_type_t *canon) {
|
||||||
|
int n = (int)scc_vec_size(canon->function.params);
|
||||||
|
if (n > 0) {
|
||||||
|
const scc_ast_decl_t *last =
|
||||||
|
scc_vec_at(canon->function.params, (usize)(n - 1));
|
||||||
|
if (is_variadic_marker(last))
|
||||||
|
return n - 1;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
static scc_hir_type_ref_t parse_base_type(scc_ast2ir_ctx_t *ctx,
|
static scc_hir_type_ref_t parse_base_type(scc_ast2ir_ctx_t *ctx,
|
||||||
const scc_ast_qual_type_t *ast_type) {
|
const scc_ast_qual_type_t *ast_type) {
|
||||||
scc_abi_type_layout_t layout;
|
scc_abi_type_layout_t layout;
|
||||||
@@ -47,6 +67,29 @@ static inline bool scc_hir_type_is_signed(scc_hir_type_tag_t tag) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是否为算术类型(整数或浮点)
|
||||||
|
static cbool is_arithmetic_type(const scc_hir_type_t *type) {
|
||||||
|
switch (type->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:
|
||||||
|
case SCC_HIR_TYPE_u8:
|
||||||
|
case SCC_HIR_TYPE_u16:
|
||||||
|
case SCC_HIR_TYPE_u32:
|
||||||
|
case SCC_HIR_TYPE_u64:
|
||||||
|
case SCC_HIR_TYPE_u128:
|
||||||
|
case SCC_HIR_TYPE_f16:
|
||||||
|
case SCC_HIR_TYPE_f32:
|
||||||
|
case SCC_HIR_TYPE_f64:
|
||||||
|
case SCC_HIR_TYPE_f128:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 辅助函数:生成数组初始化代码
|
// 辅助函数:生成数组初始化代码
|
||||||
static void emit_array_initialization(scc_ast2ir_ctx_t *ctx,
|
static void emit_array_initialization(scc_ast2ir_ctx_t *ctx,
|
||||||
scc_hir_value_ref_t array_ptr,
|
scc_hir_value_ref_t array_ptr,
|
||||||
@@ -233,12 +276,14 @@ scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
|||||||
// 将返回类型添加到程序的类型容器中
|
// 将返回类型添加到程序的类型容器中
|
||||||
ir_type.data.function.ret_type = ret_type;
|
ir_type.data.function.ret_type = ret_type;
|
||||||
|
|
||||||
// 转换参数类型
|
// 转换参数类型(跳过尾部的 ... 假参数)
|
||||||
scc_hir_type_ref_vec_t params;
|
scc_hir_type_ref_vec_t params;
|
||||||
scc_vec_init(params);
|
scc_vec_init(params);
|
||||||
scc_vec_foreach(scc_ast_canon_type(ast_type)->function.params, i) {
|
int n_fixed = fixed_param_count(scc_ast_canon_type(ast_type));
|
||||||
scc_ast_decl_t *decl_param =
|
scc_ast_decl_vec_t *ast_params =
|
||||||
scc_vec_at(scc_ast_canon_type(ast_type)->function.params, i);
|
&scc_ast_canon_type(ast_type)->function.params;
|
||||||
|
for (int i = 0; i < n_fixed; i++) {
|
||||||
|
scc_ast_decl_t *decl_param = scc_vec_at(*ast_params, i);
|
||||||
Assert(decl_param->base.type == SCC_AST_DECL_PARAM);
|
Assert(decl_param->base.type == SCC_AST_DECL_PARAM);
|
||||||
scc_hir_type_ref_t tmp_type =
|
scc_hir_type_ref_t tmp_type =
|
||||||
scc_ast2ir_type(ctx, decl_param->param.type);
|
scc_ast2ir_type(ctx, decl_param->param.type);
|
||||||
@@ -328,16 +373,14 @@ scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
scc_hir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
|
scc_hir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
|
||||||
const scc_ast_expr_t *expr,
|
const scc_ast_expr_t *expr) {
|
||||||
scc_hir_value_ref_t lhs,
|
|
||||||
scc_hir_value_ref_t rhs) {
|
|
||||||
// scc_hir_bblock_ref_t start_block =
|
// scc_hir_bblock_ref_t start_block =
|
||||||
// scc_hir_builder_current_bblock(&ctx->builder);
|
// scc_hir_builder_current_bblock(&ctx->builder);
|
||||||
|
|
||||||
scc_hir_value_ref_t right_block =
|
scc_hir_value_ref_t right_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "logic_right");
|
scc_hir_builder_create_bblock(&ctx->builder, "logic_right");
|
||||||
scc_hir_value_ref_t end_block =
|
scc_hir_value_ref_t end_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "logic_end");
|
scc_hir_builder_create_bblock(&ctx->builder, "logic_end");
|
||||||
|
|
||||||
// 为结果创建临时存储空间
|
// 为结果创建临时存储空间
|
||||||
scc_hir_type_ref_t int32_type = scc_hir_builder_type_i32(&ctx->builder);
|
scc_hir_type_ref_t int32_type = scc_hir_builder_type_i32(&ctx->builder);
|
||||||
@@ -360,7 +403,7 @@ scc_hir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
if (expr->binary.op == SCC_AST_OP_LOGICAL_AND) {
|
if (expr->binary.op == SCC_AST_OP_LOGICAL_AND) {
|
||||||
// a && b
|
// a && b
|
||||||
scc_hir_value_ref_t false_block =
|
scc_hir_value_ref_t false_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "and_false");
|
scc_hir_builder_create_bblock(&ctx->builder, "and_false");
|
||||||
|
|
||||||
// 如果左操作数为0,结果为0(短路)
|
// 如果左操作数为0,结果为0(短路)
|
||||||
scc_hir_value_ref_t is_left_zero = scc_hir_builder_binop(
|
scc_hir_value_ref_t is_left_zero = scc_hir_builder_binop(
|
||||||
@@ -369,11 +412,13 @@ scc_hir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
right_block);
|
right_block);
|
||||||
|
|
||||||
// false_block: 左边为0,结果为0
|
// false_block: 左边为0,结果为0
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, false_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, false_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, false_block);
|
||||||
scc_hir_builder_store(&ctx->builder, result_var, zero_val);
|
scc_hir_builder_store(&ctx->builder, result_var, zero_val);
|
||||||
scc_hir_builder_jump(&ctx->builder, end_block);
|
scc_hir_builder_jump(&ctx->builder, end_block);
|
||||||
|
|
||||||
// right_block: 左边非0,计算右边
|
// right_block: 左边非0,计算右边
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, right_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, right_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, right_block);
|
||||||
scc_hir_value_ref_t right_val =
|
scc_hir_value_ref_t right_val =
|
||||||
scc_ast2ir_expr(ctx, expr->binary.rhs, false);
|
scc_ast2ir_expr(ctx, expr->binary.rhs, false);
|
||||||
@@ -388,7 +433,7 @@ scc_hir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
} else { // SCC_AST_OP_LOGICAL_OR
|
} else { // SCC_AST_OP_LOGICAL_OR
|
||||||
// a || b
|
// a || b
|
||||||
scc_hir_value_ref_t true_block =
|
scc_hir_value_ref_t true_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "or_true");
|
scc_hir_builder_create_bblock(&ctx->builder, "or_true");
|
||||||
|
|
||||||
// 如果左操作数非0,结果为1(短路)
|
// 如果左操作数非0,结果为1(短路)
|
||||||
scc_hir_value_ref_t is_left_nonzero = scc_hir_builder_binop(
|
scc_hir_value_ref_t is_left_nonzero = scc_hir_builder_binop(
|
||||||
@@ -397,11 +442,13 @@ scc_hir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
right_block);
|
right_block);
|
||||||
|
|
||||||
// true_block: 左边非0,结果为1
|
// true_block: 左边非0,结果为1
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, true_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, true_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, true_block);
|
||||||
scc_hir_builder_store(&ctx->builder, result_var, one_val);
|
scc_hir_builder_store(&ctx->builder, result_var, one_val);
|
||||||
scc_hir_builder_jump(&ctx->builder, end_block);
|
scc_hir_builder_jump(&ctx->builder, end_block);
|
||||||
|
|
||||||
// right_block: 左边为0,计算右边
|
// right_block: 左边为0,计算右边
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, right_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, right_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, right_block);
|
||||||
scc_hir_value_ref_t right_val =
|
scc_hir_value_ref_t right_val =
|
||||||
scc_ast2ir_expr(ctx, expr->binary.rhs, false);
|
scc_ast2ir_expr(ctx, expr->binary.rhs, false);
|
||||||
@@ -415,6 +462,7 @@ scc_hir_value_ref_t scc_ast2ir_logical_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设置结束块为当前块,并返回结果
|
// 设置结束块为当前块,并返回结果
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, end_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, end_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, end_block);
|
||||||
return scc_hir_builder_load(&ctx->builder, result_var);
|
return scc_hir_builder_load(&ctx->builder, result_var);
|
||||||
}
|
}
|
||||||
@@ -511,11 +559,61 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
if (is_assign) {
|
if (is_assign) {
|
||||||
Assert(rhs != SCC_HIR_REF_nullptr);
|
Assert(rhs != SCC_HIR_REF_nullptr);
|
||||||
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, true);
|
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, true);
|
||||||
|
// 将 RHS 转换为 LHS 指向的类型(C11 6.5.16.1 简单赋值)
|
||||||
|
scc_hir_type_t *lhs_ptr_type = scc_hir_module_get_type_by_value(
|
||||||
|
scc_ast2ir_mir_module(ctx), lhs);
|
||||||
|
if (lhs_ptr_type->tag == SCC_HIR_TYPE_PTR &&
|
||||||
|
is_arithmetic_type(
|
||||||
|
scc_hir_module_get_type(scc_ast2ir_mir_module(ctx),
|
||||||
|
lhs_ptr_type->data.pointer.base))) {
|
||||||
|
rhs = scc_ast2ir_emit_conversion(
|
||||||
|
ctx, rhs, lhs_ptr_type->data.pointer.base);
|
||||||
|
}
|
||||||
return scc_hir_builder_store(&ctx->builder, lhs, rhs);
|
return scc_hir_builder_store(&ctx->builder, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expr->binary.op == SCC_AST_OP_LOGICAL_AND ||
|
||||||
|
expr->binary.op == SCC_AST_OP_LOGICAL_OR) {
|
||||||
|
// TODO 类型提升
|
||||||
|
return scc_ast2ir_logical_expr(ctx, expr);
|
||||||
|
}
|
||||||
rhs = scc_ast2ir_expr(ctx, expr->binary.rhs, false);
|
rhs = scc_ast2ir_expr(ctx, expr->binary.rhs, false);
|
||||||
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, false);
|
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, false);
|
||||||
|
|
||||||
|
// 类型提升:对算术类型二元操作应用寻常算术转换(C11 6.3.1.8)
|
||||||
|
// 移位操作符不适用(仅对每个操作数单独整数提升)
|
||||||
|
cbool is_shift = (expr->binary.op == SCC_AST_OP_LEFT_SHIFT ||
|
||||||
|
expr->binary.op == SCC_AST_OP_RIGHT_SHIFT);
|
||||||
|
if (!is_shift && expr->binary.op != SCC_AST_OP_COMMA) {
|
||||||
|
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
|
||||||
|
scc_hir_type_ref_t lhs_type_ref =
|
||||||
|
scc_hir_module_get_value(module, lhs)->type;
|
||||||
|
scc_hir_type_ref_t rhs_type_ref =
|
||||||
|
scc_hir_module_get_value(module, rhs)->type;
|
||||||
|
scc_hir_type_t *lhs_type =
|
||||||
|
scc_hir_module_get_type(module, lhs_type_ref);
|
||||||
|
scc_hir_type_t *rhs_type =
|
||||||
|
scc_hir_module_get_type(module, rhs_type_ref);
|
||||||
|
if (is_arithmetic_type(lhs_type) && is_arithmetic_type(rhs_type)) {
|
||||||
|
scc_hir_type_ref_t common =
|
||||||
|
scc_ast2ir_usual_arithmetic_conversion(ctx, lhs_type_ref,
|
||||||
|
rhs_type_ref);
|
||||||
|
if (common != 0) {
|
||||||
|
lhs = scc_ast2ir_emit_conversion(ctx, lhs, common);
|
||||||
|
rhs = scc_ast2ir_emit_conversion(ctx, rhs, common);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (is_shift) {
|
||||||
|
// 移位操作符:只进行整数提升(C11 6.5.7)
|
||||||
|
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
|
||||||
|
scc_hir_type_ref_t lhs_type_ref =
|
||||||
|
scc_hir_module_get_value(module, lhs)->type;
|
||||||
|
scc_hir_type_ref_t promoted =
|
||||||
|
scc_ast2ir_integer_promotion(ctx, lhs_type_ref);
|
||||||
|
if (promoted != 0)
|
||||||
|
lhs = scc_ast2ir_emit_conversion(ctx, lhs, promoted);
|
||||||
|
}
|
||||||
|
|
||||||
// 映射操作符
|
// 映射操作符
|
||||||
scc_hir_op_type_t op;
|
scc_hir_op_type_t op;
|
||||||
switch (expr->binary.op) {
|
switch (expr->binary.op) {
|
||||||
@@ -547,7 +645,8 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
/* 逻辑操作符 */
|
/* 逻辑操作符 */
|
||||||
case SCC_AST_OP_LOGICAL_OR: // ||
|
case SCC_AST_OP_LOGICAL_OR: // ||
|
||||||
case SCC_AST_OP_LOGICAL_AND: // &&
|
case SCC_AST_OP_LOGICAL_AND: // &&
|
||||||
return scc_ast2ir_logical_expr(ctx, expr, lhs, rhs);
|
UNREACHABLE();
|
||||||
|
return 0;
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
default:
|
default:
|
||||||
LOG_FATAL("Unsupported binary operator: %d", expr->binary.op);
|
LOG_FATAL("Unsupported binary operator: %d", expr->binary.op);
|
||||||
@@ -620,13 +719,20 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
scc_hir_module_get_value(
|
scc_hir_module_get_value(
|
||||||
scc_hir_builder_get_module(&ctx->builder), old_val)
|
scc_hir_builder_get_module(&ctx->builder), old_val)
|
||||||
->type;
|
->type;
|
||||||
scc_hir_type_ref_t promoted_type = old_type;
|
|
||||||
// scc_ast2ir_promoted_type(ctx, old_type);
|
// 整数提升:C11 6.3.1.1,对 short/char 等类型提升为 int
|
||||||
|
scc_hir_type_ref_t promoted_type_ref =
|
||||||
|
scc_ast2ir_integer_promotion(ctx, old_type);
|
||||||
scc_hir_value_ref_t promoted = old_val;
|
scc_hir_value_ref_t promoted = old_val;
|
||||||
// scc_ast2ir_apply_promotion(ctx, old_val);
|
if (promoted_type_ref != 0) {
|
||||||
|
promoted =
|
||||||
|
scc_ast2ir_emit_conversion(ctx, old_val, promoted_type_ref);
|
||||||
|
} else {
|
||||||
|
promoted_type_ref = old_type;
|
||||||
|
}
|
||||||
|
|
||||||
scc_hir_value_ref_t one = scc_hir_builder_integer(
|
scc_hir_value_ref_t one = scc_hir_builder_integer(
|
||||||
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder),
|
&ctx->builder, promoted_type_ref,
|
||||||
&(scc_ap_t){.data.digit = 1, .capacity = -1});
|
&(scc_ap_t){.data.digit = 1, .capacity = -1});
|
||||||
scc_hir_op_type_t op =
|
scc_hir_op_type_t op =
|
||||||
(expr->unary.op == SCC_AST_OP_PREFIX_INCREMENT)
|
(expr->unary.op == SCC_AST_OP_PREFIX_INCREMENT)
|
||||||
@@ -637,10 +743,9 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
|
|
||||||
// 如果原类型不是提升后的类型,需要截断回原类型再存储
|
// 如果原类型不是提升后的类型,需要截断回原类型再存储
|
||||||
scc_hir_value_ref_t stored_val = new_val;
|
scc_hir_value_ref_t stored_val = new_val;
|
||||||
// if (old_type != promoted_type) {
|
if (promoted_type_ref != old_type) {
|
||||||
// stored_val = scc_hir_builder_conv(&ctx->builder, new_val,
|
stored_val = scc_ast2ir_emit_conversion(ctx, new_val, old_type);
|
||||||
// old_type, CONV_TRUNC);
|
}
|
||||||
// }
|
|
||||||
scc_hir_builder_store(&ctx->builder, addr, stored_val);
|
scc_hir_builder_store(&ctx->builder, addr, stored_val);
|
||||||
Assert(new_val != SCC_HIR_REF_nullptr);
|
Assert(new_val != SCC_HIR_REF_nullptr);
|
||||||
return new_val; // 表达式的值是提升后的新值(符合 C 标准)
|
return new_val; // 表达式的值是提升后的新值(符合 C 标准)
|
||||||
@@ -656,13 +761,20 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
scc_hir_module_get_value(
|
scc_hir_module_get_value(
|
||||||
scc_hir_builder_get_module(&ctx->builder), old_val)
|
scc_hir_builder_get_module(&ctx->builder), old_val)
|
||||||
->type;
|
->type;
|
||||||
scc_hir_type_ref_t promoted_type = old_type;
|
|
||||||
// scc_ast2ir_promoted_type(ctx, old_type);
|
// 整数提升(C11 6.3.1.1)
|
||||||
|
scc_hir_type_ref_t promoted_type_ref =
|
||||||
|
scc_ast2ir_integer_promotion(ctx, old_type);
|
||||||
scc_hir_value_ref_t promoted = old_val;
|
scc_hir_value_ref_t promoted = old_val;
|
||||||
// scc_ast2ir_apply_promotion(ctx, old_val);
|
if (promoted_type_ref != 0) {
|
||||||
|
promoted =
|
||||||
|
scc_ast2ir_emit_conversion(ctx, old_val, promoted_type_ref);
|
||||||
|
} else {
|
||||||
|
promoted_type_ref = old_type;
|
||||||
|
}
|
||||||
|
|
||||||
scc_hir_value_ref_t one = scc_hir_builder_integer(
|
scc_hir_value_ref_t one = scc_hir_builder_integer(
|
||||||
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder),
|
&ctx->builder, promoted_type_ref,
|
||||||
&(scc_ap_t){.data.digit = 1, .capacity = -1});
|
&(scc_ap_t){.data.digit = 1, .capacity = -1});
|
||||||
scc_hir_op_type_t op =
|
scc_hir_op_type_t op =
|
||||||
(expr->unary.op == SCC_AST_OP_POSTFIX_INCREMENT)
|
(expr->unary.op == SCC_AST_OP_POSTFIX_INCREMENT)
|
||||||
@@ -672,17 +784,13 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
scc_hir_builder_binop(&ctx->builder, op, promoted, one);
|
scc_hir_builder_binop(&ctx->builder, op, promoted, one);
|
||||||
|
|
||||||
scc_hir_value_ref_t stored_val = new_val;
|
scc_hir_value_ref_t stored_val = new_val;
|
||||||
// if (old_type != promoted_type)
|
if (promoted_type_ref != old_type) {
|
||||||
// stored_val = trunc;
|
stored_val = scc_ast2ir_emit_conversion(ctx, new_val, old_type);
|
||||||
|
}
|
||||||
scc_hir_builder_store(&ctx->builder, addr, stored_val);
|
scc_hir_builder_store(&ctx->builder, addr, stored_val);
|
||||||
|
|
||||||
// 后缀返回旧的、未提升的值(但 C
|
// 后缀返回旧值的提升后版本(C11 6.5.2.4)
|
||||||
// 要求返回提升后的旧值?实际是旧值按右值规则,应得到提升后的值)
|
return promoted;
|
||||||
// 标准规定后缀++的结果是操作数原来的值,但会经过整数提升。
|
|
||||||
// 所以需要返回 promoted(已提升的旧值)。
|
|
||||||
Assert(promoted != SCC_HIR_REF_nullptr);
|
|
||||||
return promoted; // 旧值,但类型已提升为
|
|
||||||
// int 等
|
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
LOG_FATAL("Unsupported unary operator: %d", expr->unary.op);
|
LOG_FATAL("Unsupported unary operator: %d", expr->unary.op);
|
||||||
@@ -746,22 +854,78 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
scc_hir_value_ref_vec_t args;
|
scc_hir_value_ref_vec_t args;
|
||||||
scc_vec_init(args);
|
scc_vec_init(args);
|
||||||
|
|
||||||
|
// 获取函数类型信息用于参数转换。注意:不能长期持有指向 types 向量
|
||||||
|
// 内部的指针(如 ft->data.function.params),因为递归的
|
||||||
|
// scc_ast2ir_expr 可能触发 scc_hir_module_add_type 导致 realloc。
|
||||||
|
// 改为通过 func_type_ref(稳定的索引)每次需要时重新获取指针。
|
||||||
|
scc_hir_func_ref_t callee_func =
|
||||||
|
(scc_hir_func_ref_t)(usize)scc_hashtable_get(
|
||||||
|
&ctx->symtab, expr->call.callee->identifier._target->name);
|
||||||
|
scc_hir_type_ref_t func_type_ref = SCC_HIR_REF_nullptr;
|
||||||
|
cbool is_variadic = false;
|
||||||
|
int fixed_count = 0;
|
||||||
|
if (callee_func != SCC_HIR_REF_nullptr) {
|
||||||
|
scc_hir_func_t *hir_func = scc_hir_module_get_func(
|
||||||
|
scc_ast2ir_mir_module(ctx), callee_func);
|
||||||
|
scc_hir_func_meta_t *meta = SCC_HIR_FUNC_META(hir_func);
|
||||||
|
is_variadic = meta->is_variadic;
|
||||||
|
func_type_ref = meta->type;
|
||||||
|
if (func_type_ref != SCC_HIR_REF_nullptr) {
|
||||||
|
const scc_hir_type_t *ft = scc_hir_module_get_type(
|
||||||
|
scc_ast2ir_mir_module(ctx), func_type_ref);
|
||||||
|
if (ft != nullptr && ft->tag == SCC_HIR_TYPE_FUNC)
|
||||||
|
fixed_count = (int)ft->data.function.params.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scc_vec_foreach(expr->call.args, i) {
|
scc_vec_foreach(expr->call.args, i) {
|
||||||
scc_ast_expr_t *arg_expr = scc_vec_at(expr->call.args, i);
|
scc_ast_expr_t *arg_expr = scc_vec_at(expr->call.args, i);
|
||||||
scc_hir_value_ref_t arg_node;
|
scc_hir_value_ref_t arg_node;
|
||||||
arg_node = scc_ast2ir_expr(ctx, arg_expr, false);
|
arg_node = scc_ast2ir_expr(ctx, arg_expr, false);
|
||||||
|
if ((int)i < fixed_count) {
|
||||||
|
// 固定参数:转换为形参类型
|
||||||
|
// 每次迭代重新获取指针(scc_ast2ir_expr 可能触发 types 向量 realloc)
|
||||||
|
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
|
||||||
|
const scc_hir_type_t *ft = scc_hir_module_get_type(
|
||||||
|
module, func_type_ref);
|
||||||
|
scc_hir_type_ref_t param_type =
|
||||||
|
scc_vec_at(ft->data.function.params, i);
|
||||||
|
arg_node =
|
||||||
|
scc_ast2ir_emit_conversion(ctx, arg_node, param_type);
|
||||||
|
} else if (is_variadic) {
|
||||||
|
// 可变参数:只应用默认参数提升(C11 6.5.2.2)
|
||||||
|
// 整数提升:char/short → int
|
||||||
|
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
|
||||||
|
scc_hir_type_ref_t arg_type_ref =
|
||||||
|
scc_hir_module_get_value(module, arg_node)->type;
|
||||||
|
scc_hir_type_tag_t arg_tag =
|
||||||
|
scc_hir_module_get_type(module, arg_type_ref)->tag;
|
||||||
|
scc_hir_type_ref_t promoted =
|
||||||
|
scc_ast2ir_integer_promotion(ctx, arg_type_ref);
|
||||||
|
if (promoted != 0) {
|
||||||
|
arg_node =
|
||||||
|
scc_ast2ir_emit_conversion(ctx, arg_node, promoted);
|
||||||
|
} else if (arg_tag == SCC_HIR_TYPE_f32) {
|
||||||
|
// float → double(默认参数提升)
|
||||||
|
scc_hir_type_t f64_desc;
|
||||||
|
scc_hir_type_init(&f64_desc, SCC_HIR_TYPE_f64);
|
||||||
|
scc_hir_type_ref_t f64_ref =
|
||||||
|
scc_hir_builder_type(&ctx->builder, &f64_desc);
|
||||||
|
arg_node =
|
||||||
|
scc_ast2ir_emit_conversion(ctx, arg_node, f64_ref);
|
||||||
|
}
|
||||||
|
// 指针、i32/i64 等保持不变
|
||||||
|
}
|
||||||
scc_vec_push(args, arg_node);
|
scc_vec_push(args, arg_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建调用节点(需要查找函数定义)
|
// 创建调用节点(需要查找函数定义)
|
||||||
scc_hir_func_ref_t func = (scc_hir_value_ref_t)(usize)scc_hashtable_get(
|
if (!callee_func) {
|
||||||
&ctx->symtab, expr->call.callee->identifier._target->name);
|
|
||||||
if (!func) {
|
|
||||||
LOG_ERROR("Function %s not found",
|
LOG_ERROR("Function %s not found",
|
||||||
expr->call.callee->identifier._target->name);
|
expr->call.callee->identifier._target->name);
|
||||||
}
|
}
|
||||||
scc_hir_value_ref_t node =
|
scc_hir_value_ref_t node = scc_hir_builder_call(
|
||||||
scc_hir_builder_call(&ctx->builder, func, args.data, args.size);
|
&ctx->builder, callee_func, args.data, args.size);
|
||||||
scc_vec_free(args);
|
scc_vec_free(args);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -772,6 +936,18 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
// 2. 计算下标值
|
// 2. 计算下标值
|
||||||
scc_hir_value_ref_t index =
|
scc_hir_value_ref_t index =
|
||||||
scc_ast2ir_expr(ctx, expr->subscript.index, false);
|
scc_ast2ir_expr(ctx, expr->subscript.index, false);
|
||||||
|
// 保证 index 至少 64 位,防止后端寄存器分配时宽度错误
|
||||||
|
scc_hir_type_t *idx_type =
|
||||||
|
scc_hir_module_get_type_by_value(scc_ast2ir_mir_module(ctx), index);
|
||||||
|
if (idx_type != nullptr &&
|
||||||
|
scc_hir_module_type_size(scc_ast2ir_mir_module(ctx), idx_type) <
|
||||||
|
sizeof(void *)) {
|
||||||
|
scc_hir_type_t ptrw_desc;
|
||||||
|
scc_hir_type_init(&ptrw_desc, SCC_HIR_TYPE_u64);
|
||||||
|
scc_hir_type_ref_t ptrw_ref =
|
||||||
|
scc_hir_builder_type(&ctx->builder, &ptrw_desc);
|
||||||
|
index = scc_ast2ir_emit_conversion(ctx, index, ptrw_ref);
|
||||||
|
}
|
||||||
// 3. 生成 getptr(GEP)
|
// 3. 生成 getptr(GEP)
|
||||||
scc_hir_value_ref_t elem_ptr =
|
scc_hir_value_ref_t elem_ptr =
|
||||||
scc_hir_builder_get_elem_ptr(&ctx->builder, base_ptr, index);
|
scc_hir_builder_get_elem_ptr(&ctx->builder, base_ptr, index);
|
||||||
@@ -846,10 +1022,11 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
int conv_kind;
|
int conv_kind;
|
||||||
if (dst_size > src_size) {
|
if (dst_size > src_size) {
|
||||||
// 目标更大,需要扩展。根据源类型有无符号决定符号扩展还是零扩展
|
// 目标更大,需要扩展。根据源类型有无符号决定符号扩展还是零扩展
|
||||||
conv_kind =
|
conv_kind = scc_hir_type_is_signed(src_type->tag)
|
||||||
scc_hir_type_is_signed(src_type->tag) ? CONV_SEXT : CONV_ZEXT;
|
? SCC_HIR_CONV_SEXT
|
||||||
|
: SCC_HIR_CONV_ZEXT;
|
||||||
} else if (dst_size < src_size) {
|
} else if (dst_size < src_size) {
|
||||||
conv_kind = CONV_TRUNC;
|
conv_kind = SCC_HIR_CONV_TRUNC;
|
||||||
} else {
|
} else {
|
||||||
// 同大小,可以视为 NOP 转换,或者直接返回操作数
|
// 同大小,可以视为 NOP 转换,或者直接返回操作数
|
||||||
return operand; // 或创建一个 CONV_SEXT 也没问题
|
return operand; // 或创建一个 CONV_SEXT 也没问题
|
||||||
@@ -963,10 +1140,9 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
// SCC_AST_EXPR_FLOAT_LITERAL, // 浮点字面量
|
// SCC_AST_EXPR_FLOAT_LITERAL, // 浮点字面量
|
||||||
case SCC_AST_EXPR_CHAR_LITERAL: {
|
case SCC_AST_EXPR_CHAR_LITERAL: {
|
||||||
// FIXME just 'a' '\n'
|
// FIXME just 'a' '\n'
|
||||||
scc_hir_type_ref_t type_ref = scc_hir_builder_type_i32(&ctx->builder);
|
|
||||||
const char *lexme = expr->literal.lexme;
|
const char *lexme = expr->literal.lexme;
|
||||||
Assert(lexme[0] == '\'');
|
Assert(lexme[0] == '\'');
|
||||||
u8 int_lit = 0;
|
i8 int_lit = 0;
|
||||||
if (lexme[1] == '\\') {
|
if (lexme[1] == '\\') {
|
||||||
switch (lexme[2]) {
|
switch (lexme[2]) {
|
||||||
case 'a':
|
case 'a':
|
||||||
@@ -988,6 +1164,8 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
|||||||
int_lit = lexme[1];
|
int_lit = lexme[1];
|
||||||
}
|
}
|
||||||
scc_ap_t value;
|
scc_ap_t value;
|
||||||
|
// FIXME i32 maybe false, we need i8 or u8
|
||||||
|
scc_hir_type_ref_t type_ref = scc_hir_builder_type_i32(&ctx->builder);
|
||||||
scc_ap_set_int(&value, int_lit);
|
scc_ap_set_int(&value, int_lit);
|
||||||
return scc_hir_builder_integer(&ctx->builder, type_ref, &value);
|
return scc_hir_builder_integer(&ctx->builder, type_ref, &value);
|
||||||
}
|
}
|
||||||
@@ -1079,95 +1257,105 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
|
|||||||
merge_block
|
merge_block
|
||||||
*/
|
*/
|
||||||
scc_hir_value_ref_t true_block =
|
scc_hir_value_ref_t true_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "if_true");
|
scc_hir_builder_create_bblock(&ctx->builder, "if_true");
|
||||||
|
|
||||||
scc_hir_value_ref_t false_block =
|
scc_hir_value_ref_t false_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "if_false");
|
scc_hir_builder_create_bblock(&ctx->builder, "if_false");
|
||||||
|
|
||||||
scc_hir_value_ref_t merge_block =
|
scc_hir_value_ref_t merge_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "if_merge");
|
scc_hir_builder_create_bblock(&ctx->builder, "if_merge");
|
||||||
|
|
||||||
scc_hir_value_ref_t cond_node =
|
scc_hir_value_ref_t cond_node =
|
||||||
scc_ast2ir_expr(ctx, stmt->if_stmt.cond, false);
|
scc_ast2ir_expr(ctx, stmt->if_stmt.cond, false);
|
||||||
scc_hir_builder_branch(&ctx->builder, cond_node, true_block,
|
scc_hir_builder_branch(&ctx->builder, cond_node, true_block,
|
||||||
false_block);
|
stmt->if_stmt.opt_else_stmt ? false_block
|
||||||
|
: merge_block);
|
||||||
|
|
||||||
// 生成true分支
|
// 生成true分支
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, true_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, true_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, true_block);
|
||||||
scc_ast2ir_stmt(ctx, stmt->if_stmt.then_stmt);
|
scc_ast2ir_stmt(ctx, stmt->if_stmt.then_stmt);
|
||||||
scc_hir_builder_jump(&ctx->builder, merge_block);
|
scc_hir_builder_jump(&ctx->builder, merge_block);
|
||||||
|
|
||||||
// 生成false分支
|
// 生成false分支
|
||||||
if (stmt->if_stmt.opt_else_stmt) {
|
if (stmt->if_stmt.opt_else_stmt) {
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, false_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, false_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, false_block);
|
||||||
scc_ast2ir_stmt(ctx, stmt->if_stmt.opt_else_stmt);
|
scc_ast2ir_stmt(ctx, stmt->if_stmt.opt_else_stmt);
|
||||||
scc_hir_builder_jump(&ctx->builder, merge_block);
|
scc_hir_builder_jump(&ctx->builder, merge_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, merge_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, merge_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, merge_block);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCC_AST_STMT_WHILE: {
|
case SCC_AST_STMT_WHILE: {
|
||||||
scc_hir_value_ref_t cond_block =
|
scc_hir_value_ref_t cond_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "while_cond");
|
scc_hir_builder_create_bblock(&ctx->builder, "while_cond");
|
||||||
scc_hir_value_ref_t body_block =
|
scc_hir_value_ref_t body_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "while_body");
|
scc_hir_builder_create_bblock(&ctx->builder, "while_body");
|
||||||
scc_hir_value_ref_t exit_block =
|
scc_hir_value_ref_t exit_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "while_exit");
|
scc_hir_builder_create_bblock(&ctx->builder, "while_exit");
|
||||||
|
|
||||||
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
|
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
|
||||||
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)cond_block);
|
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)cond_block);
|
||||||
|
|
||||||
scc_hir_builder_jump(&ctx->builder, cond_block);
|
scc_hir_builder_jump(&ctx->builder, cond_block);
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, cond_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
|
||||||
scc_hir_value_ref_t cond_node =
|
scc_hir_value_ref_t cond_node =
|
||||||
scc_ast2ir_expr(ctx, stmt->while_stmt.cond, false);
|
scc_ast2ir_expr(ctx, stmt->while_stmt.cond, false);
|
||||||
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
|
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
|
||||||
exit_block);
|
exit_block);
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, body_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
||||||
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
|
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
|
||||||
scc_hir_builder_jump(&ctx->builder, cond_block);
|
scc_hir_builder_jump(&ctx->builder, cond_block);
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, exit_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCC_AST_STMT_DO_WHILE: {
|
case SCC_AST_STMT_DO_WHILE: {
|
||||||
scc_hir_value_ref_t cond_block =
|
scc_hir_value_ref_t cond_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "do_while_cond");
|
scc_hir_builder_create_bblock(&ctx->builder, "do_while_cond");
|
||||||
scc_hir_value_ref_t body_block =
|
scc_hir_value_ref_t body_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "do_while_body");
|
scc_hir_builder_create_bblock(&ctx->builder, "do_while_body");
|
||||||
scc_hir_value_ref_t exit_block =
|
scc_hir_value_ref_t exit_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "do_while_exit");
|
scc_hir_builder_create_bblock(&ctx->builder, "do_while_exit");
|
||||||
|
|
||||||
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
|
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
|
||||||
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)cond_block);
|
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)cond_block);
|
||||||
|
|
||||||
scc_hir_builder_jump(&ctx->builder, body_block);
|
scc_hir_builder_jump(&ctx->builder, body_block);
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, body_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
||||||
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
|
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
|
||||||
scc_hir_builder_jump(&ctx->builder, cond_block);
|
scc_hir_builder_jump(&ctx->builder, cond_block);
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, cond_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
|
||||||
scc_hir_value_ref_t cond_node =
|
scc_hir_value_ref_t cond_node =
|
||||||
scc_ast2ir_expr(ctx, stmt->while_stmt.cond, false);
|
scc_ast2ir_expr(ctx, stmt->while_stmt.cond, false);
|
||||||
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
|
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
|
||||||
exit_block);
|
exit_block);
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, exit_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCC_AST_STMT_FOR: {
|
case SCC_AST_STMT_FOR: {
|
||||||
scc_hir_value_ref_t cond_block =
|
scc_hir_value_ref_t cond_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "for_cond");
|
scc_hir_builder_create_bblock(&ctx->builder, "for_cond");
|
||||||
scc_hir_value_ref_t body_block =
|
scc_hir_value_ref_t body_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "for_body");
|
scc_hir_builder_create_bblock(&ctx->builder, "for_body");
|
||||||
scc_hir_value_ref_t incr_block =
|
scc_hir_value_ref_t incr_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "for_incr");
|
scc_hir_builder_create_bblock(&ctx->builder, "for_incr");
|
||||||
scc_hir_value_ref_t exit_block =
|
scc_hir_value_ref_t exit_block =
|
||||||
scc_hir_builder_bblock(&ctx->builder, "for_exit");
|
scc_hir_builder_create_bblock(&ctx->builder, "for_exit");
|
||||||
|
|
||||||
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
|
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
|
||||||
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)incr_block);
|
scc_hashtable_set(&ctx->continue_cache, stmt, (void *)incr_block);
|
||||||
@@ -1188,6 +1376,7 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
|
|||||||
|
|
||||||
scc_hir_builder_jump(&ctx->builder, cond_block);
|
scc_hir_builder_jump(&ctx->builder, cond_block);
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, cond_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
|
||||||
if (stmt->for_stmt.cond) {
|
if (stmt->for_stmt.cond) {
|
||||||
scc_hir_value_ref_t cond_node =
|
scc_hir_value_ref_t cond_node =
|
||||||
@@ -1198,16 +1387,19 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
|
|||||||
scc_hir_builder_jump(&ctx->builder, body_block);
|
scc_hir_builder_jump(&ctx->builder, body_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, body_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
||||||
scc_ast2ir_stmt(ctx, stmt->for_stmt.body);
|
scc_ast2ir_stmt(ctx, stmt->for_stmt.body);
|
||||||
scc_hir_builder_jump(&ctx->builder, incr_block);
|
scc_hir_builder_jump(&ctx->builder, incr_block);
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, incr_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, incr_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, incr_block);
|
||||||
if (stmt->for_stmt.incr) {
|
if (stmt->for_stmt.incr) {
|
||||||
scc_ast2ir_expr(ctx, stmt->for_stmt.incr, false);
|
scc_ast2ir_expr(ctx, stmt->for_stmt.incr, false);
|
||||||
}
|
}
|
||||||
scc_hir_builder_jump(&ctx->builder, cond_block);
|
scc_hir_builder_jump(&ctx->builder, cond_block);
|
||||||
|
|
||||||
|
scc_hir_builder_append_bblock(&ctx->builder, exit_block);
|
||||||
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
|
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1238,6 +1430,23 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
|
|||||||
if (stmt->return_stmt.expr) {
|
if (stmt->return_stmt.expr) {
|
||||||
scc_hir_value_ref_t ret_val_node =
|
scc_hir_value_ref_t ret_val_node =
|
||||||
scc_ast2ir_expr(ctx, stmt->return_stmt.expr, false);
|
scc_ast2ir_expr(ctx, stmt->return_stmt.expr, false);
|
||||||
|
// 将返回值转换为函数返回值类型
|
||||||
|
scc_hir_func_ref_t func = ctx->builder.current_func;
|
||||||
|
if (func != SCC_HIR_REF_nullptr) {
|
||||||
|
scc_hir_func_t *hir_func =
|
||||||
|
scc_hir_module_get_func(scc_ast2ir_mir_module(ctx), func);
|
||||||
|
scc_hir_func_meta_t *meta = SCC_HIR_FUNC_META(hir_func);
|
||||||
|
if (meta->type != SCC_HIR_REF_nullptr) {
|
||||||
|
const scc_hir_type_t *func_type = scc_hir_module_get_type(
|
||||||
|
scc_ast2ir_mir_module(ctx), meta->type);
|
||||||
|
if (func_type != nullptr &&
|
||||||
|
func_type->tag == SCC_HIR_TYPE_FUNC) {
|
||||||
|
ret_val_node = scc_ast2ir_emit_conversion(
|
||||||
|
ctx, ret_val_node,
|
||||||
|
func_type->data.function.ret_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
scc_hir_builder_ret(&ctx->builder, ret_val_node);
|
scc_hir_builder_ret(&ctx->builder, ret_val_node);
|
||||||
} else {
|
} else {
|
||||||
scc_hir_builder_ret_void(&ctx->builder);
|
scc_hir_builder_ret_void(&ctx->builder);
|
||||||
@@ -1357,14 +1566,21 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
|
|||||||
(void *)(usize)func_ref);
|
(void *)(usize)func_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检测是否是可变参数函数(无论是否有函数体)
|
||||||
|
scc_hir_func_t *hir_func =
|
||||||
|
scc_hir_module_get_func(&ctx->builder.cprog->module, func_ref);
|
||||||
|
int n_fixed = fixed_param_count(scc_ast_canon_type(decl->func.type));
|
||||||
|
int n_total = (int)scc_vec_size(
|
||||||
|
scc_ast_canon_type(decl->func.type)->function.params);
|
||||||
|
if (n_total > n_fixed) {
|
||||||
|
SCC_HIR_FUNC_META(hir_func)->is_variadic = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (decl->func.body == nullptr) {
|
if (decl->func.body == nullptr) {
|
||||||
// function decl
|
// function decl
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_hir_func_t *hir_func =
|
|
||||||
scc_hir_module_get_func(&ctx->builder.cprog->module, func_ref);
|
|
||||||
Assert(hir_func != nullptr);
|
|
||||||
// TODO this is double check defined
|
// TODO this is double check defined
|
||||||
Assert(SCC_HIR_FUNC_META(hir_func)->defined == false);
|
Assert(SCC_HIR_FUNC_META(hir_func)->defined == false);
|
||||||
SCC_HIR_FUNC_META(hir_func)->defined = true;
|
SCC_HIR_FUNC_META(hir_func)->defined = true;
|
||||||
@@ -1372,10 +1588,11 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
|
|||||||
scc_hir_builder_begin_func(&ctx->builder, func_ref);
|
scc_hir_builder_begin_func(&ctx->builder, func_ref);
|
||||||
scc_hir_builder_begin_bblock(&ctx->builder, "entry");
|
scc_hir_builder_begin_bblock(&ctx->builder, "entry");
|
||||||
|
|
||||||
scc_vec_foreach(scc_ast_canon_type(decl->func.type)->function.params,
|
// 只处理固定参数,跳过尾部的 ... 假参数
|
||||||
i) {
|
scc_ast_decl_vec_t *ast_params =
|
||||||
scc_ast_decl_t *param = scc_vec_at(
|
&scc_ast_canon_type(decl->func.type)->function.params;
|
||||||
scc_ast_canon_type(decl->func.type)->function.params, i);
|
for (int i = 0; i < n_fixed; i++) {
|
||||||
|
scc_ast_decl_t *param = scc_vec_at(*ast_params, i);
|
||||||
scc_ast2ir_decl(ctx, param, false);
|
scc_ast2ir_decl(ctx, param, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1395,11 +1612,15 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCC_AST_DECL_PARAM: {
|
case SCC_AST_DECL_PARAM: {
|
||||||
|
// 跳过 void 参数和 ... 假参数(无名 VA_LIST)
|
||||||
if (decl->param.type->base.type == SCC_AST_TYPE_BUILTIN &&
|
if (decl->param.type->base.type == SCC_AST_TYPE_BUILTIN &&
|
||||||
scc_ast_canon_type(decl->param.type)->builtin.type ==
|
scc_ast_canon_type(decl->param.type)->builtin.type ==
|
||||||
SCC_AST_BUILTIN_TYPE_VOID) {
|
SCC_AST_BUILTIN_TYPE_VOID) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (is_variadic_marker(decl)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
scc_hir_type_ref_t parma_type_ref =
|
scc_hir_type_ref_t parma_type_ref =
|
||||||
scc_ast2ir_type(ctx, decl->param.type);
|
scc_ast2ir_type(ctx, decl->param.type);
|
||||||
scc_hir_value_ref_t param_ref = scc_hir_builder_func_arg_ref(
|
scc_hir_value_ref_t param_ref = scc_hir_builder_func_arg_ref(
|
||||||
|
|||||||
321
libs/ast2ir/src/scc_ast2ir_promote.c
Normal file
321
libs/ast2ir/src/scc_ast2ir_promote.c
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
#include <scc_ast2ir.h>
|
||||||
|
|
||||||
|
// 判断是否为整数类型(不包括指针、浮点)
|
||||||
|
static cbool is_integer_type(const scc_hir_type_t *type) {
|
||||||
|
switch (type->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:
|
||||||
|
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 true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为浮点类型
|
||||||
|
static cbool is_floating_type(const scc_hir_type_t *type) {
|
||||||
|
switch (type->tag) {
|
||||||
|
case SCC_HIR_TYPE_f16:
|
||||||
|
case SCC_HIR_TYPE_f32:
|
||||||
|
case SCC_HIR_TYPE_f64:
|
||||||
|
case SCC_HIR_TYPE_f128:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取整数等级(rank),参考 C11 6.3.1.1
|
||||||
|
static int integer_tag_rank(scc_hir_type_tag_t tag) {
|
||||||
|
switch (tag) {
|
||||||
|
case SCC_HIR_TYPE_i8:
|
||||||
|
case SCC_HIR_TYPE_u8:
|
||||||
|
return 1;
|
||||||
|
case SCC_HIR_TYPE_i16:
|
||||||
|
case SCC_HIR_TYPE_u16:
|
||||||
|
return 2;
|
||||||
|
case SCC_HIR_TYPE_i32:
|
||||||
|
case SCC_HIR_TYPE_u32:
|
||||||
|
return 3;
|
||||||
|
case SCC_HIR_TYPE_i64:
|
||||||
|
case SCC_HIR_TYPE_u64:
|
||||||
|
return 4;
|
||||||
|
case SCC_HIR_TYPE_i128:
|
||||||
|
case SCC_HIR_TYPE_u128:
|
||||||
|
return 5;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取浮点等级(等级越高精度越高)
|
||||||
|
static int floating_rank(const scc_hir_type_t *type) {
|
||||||
|
switch (type->tag) {
|
||||||
|
case SCC_HIR_TYPE_f16:
|
||||||
|
return 1;
|
||||||
|
case SCC_HIR_TYPE_f32:
|
||||||
|
return 2;
|
||||||
|
case SCC_HIR_TYPE_f64:
|
||||||
|
return 3;
|
||||||
|
case SCC_HIR_TYPE_f128:
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取类型是否为有符号
|
||||||
|
static cbool is_signed_tag(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;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取无符号版本的 tag
|
||||||
|
static scc_hir_type_tag_t unsigned_tag(scc_hir_type_tag_t tag) {
|
||||||
|
switch (tag) {
|
||||||
|
case SCC_HIR_TYPE_i8:
|
||||||
|
case SCC_HIR_TYPE_u8:
|
||||||
|
return SCC_HIR_TYPE_u8;
|
||||||
|
case SCC_HIR_TYPE_i16:
|
||||||
|
case SCC_HIR_TYPE_u16:
|
||||||
|
return SCC_HIR_TYPE_u16;
|
||||||
|
case SCC_HIR_TYPE_i32:
|
||||||
|
case SCC_HIR_TYPE_u32:
|
||||||
|
return SCC_HIR_TYPE_u32;
|
||||||
|
case SCC_HIR_TYPE_i64:
|
||||||
|
case SCC_HIR_TYPE_u64:
|
||||||
|
return SCC_HIR_TYPE_u64;
|
||||||
|
case SCC_HIR_TYPE_i128:
|
||||||
|
case SCC_HIR_TYPE_u128:
|
||||||
|
return SCC_HIR_TYPE_u128;
|
||||||
|
default:
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取有符号版本的 tag
|
||||||
|
static scc_hir_type_tag_t signed_tag(scc_hir_type_tag_t tag) {
|
||||||
|
switch (tag) {
|
||||||
|
case SCC_HIR_TYPE_i8:
|
||||||
|
case SCC_HIR_TYPE_u8:
|
||||||
|
return SCC_HIR_TYPE_i8;
|
||||||
|
case SCC_HIR_TYPE_i16:
|
||||||
|
case SCC_HIR_TYPE_u16:
|
||||||
|
return SCC_HIR_TYPE_i16;
|
||||||
|
case SCC_HIR_TYPE_i32:
|
||||||
|
case SCC_HIR_TYPE_u32:
|
||||||
|
return SCC_HIR_TYPE_i32;
|
||||||
|
case SCC_HIR_TYPE_i64:
|
||||||
|
case SCC_HIR_TYPE_u64:
|
||||||
|
return SCC_HIR_TYPE_i64;
|
||||||
|
case SCC_HIR_TYPE_i128:
|
||||||
|
case SCC_HIR_TYPE_u128:
|
||||||
|
return SCC_HIR_TYPE_i128;
|
||||||
|
default:
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过 tag 快速创建类型引用
|
||||||
|
static scc_hir_type_ref_t make_type(scc_ast2ir_ctx_t *ctx,
|
||||||
|
scc_hir_type_tag_t tag) {
|
||||||
|
scc_hir_type_t desc;
|
||||||
|
scc_hir_type_init(&desc, tag);
|
||||||
|
return scc_hir_builder_type(&ctx->builder, &desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 整数提升(C11 6.3.1.1)
|
||||||
|
*
|
||||||
|
* 如果 int 可以表示原始类型的所有值,则提升为 int;
|
||||||
|
* 否则提升为 unsigned int。
|
||||||
|
*
|
||||||
|
* 对于秩 >= int 的类型,不做提升。
|
||||||
|
*/
|
||||||
|
scc_hir_type_ref_t scc_ast2ir_integer_promotion(scc_ast2ir_ctx_t *ctx,
|
||||||
|
scc_hir_type_ref_t type_ref) {
|
||||||
|
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
|
||||||
|
scc_hir_type_t *type = scc_hir_module_get_type(module, type_ref);
|
||||||
|
if (type == nullptr || !is_integer_type(type))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int rank = integer_tag_rank(type->tag);
|
||||||
|
|
||||||
|
// 秩 >= int(rank >= 3),无需提升
|
||||||
|
if (rank >= 3)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return make_type(ctx, SCC_HIR_TYPE_i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 寻常算术转换(C11 6.3.1.8)
|
||||||
|
*
|
||||||
|
* 确定二元算术操作中两个操作数的公共类型。
|
||||||
|
*
|
||||||
|
* 规则:
|
||||||
|
* 1. 如果任一操作数是 long double,另一操作数转换为 long double
|
||||||
|
* 2. 如果任一操作数是 double,另一操作数转换为 double
|
||||||
|
* 3. 如果任一操作数是 float,另一操作数转换为 float
|
||||||
|
* 4. 否则,对两个操作数应用整数提升,然后:
|
||||||
|
* a. 如果两个类型相同,无需转换
|
||||||
|
* b. 如果两个都是有符号或无符号,较小秩的转换为较大秩的
|
||||||
|
* c. 如果无符号类型的秩 >= 有符号类型的秩,有符号转换为无符号
|
||||||
|
* d. 如果有符号类型可以表示无符号类型的所有值,无符号转换为有符号
|
||||||
|
* e. 否则,两个都转换为有符号类型的无符号版本
|
||||||
|
*/
|
||||||
|
scc_hir_type_ref_t scc_ast2ir_usual_arithmetic_conversion(
|
||||||
|
scc_ast2ir_ctx_t *ctx, scc_hir_type_ref_t t1_ref,
|
||||||
|
scc_hir_type_ref_t t2_ref) {
|
||||||
|
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
|
||||||
|
scc_hir_type_t *t1 = scc_hir_module_get_type(module, t1_ref);
|
||||||
|
scc_hir_type_t *t2 = scc_hir_module_get_type(module, t2_ref);
|
||||||
|
|
||||||
|
// --- 浮点类型处理 ---
|
||||||
|
if (is_floating_type(t1) || is_floating_type(t2)) {
|
||||||
|
int r1 = is_floating_type(t1) ? floating_rank(t1) : 0;
|
||||||
|
int r2 = is_floating_type(t2) ? floating_rank(t2) : 0;
|
||||||
|
scc_hir_type_tag_t wider = (r1 >= r2) ? t1->tag : t2->tag;
|
||||||
|
return make_type(ctx, wider);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 整数类型处理 ---
|
||||||
|
// 应用整数提升:得到提升后的 tag
|
||||||
|
scc_hir_type_ref_t p1_ref = scc_ast2ir_integer_promotion(ctx, t1_ref);
|
||||||
|
scc_hir_type_ref_t p2_ref = scc_ast2ir_integer_promotion(ctx, t2_ref);
|
||||||
|
|
||||||
|
scc_hir_type_tag_t tag1 =
|
||||||
|
(p1_ref != 0)
|
||||||
|
? scc_hir_module_get_type(module, p1_ref)->tag
|
||||||
|
: t1->tag;
|
||||||
|
scc_hir_type_tag_t tag2 =
|
||||||
|
(p2_ref != 0)
|
||||||
|
? scc_hir_module_get_type(module, p2_ref)->tag
|
||||||
|
: t2->tag;
|
||||||
|
|
||||||
|
// 如果提升后相同,直接返回
|
||||||
|
if (tag1 == tag2)
|
||||||
|
return make_type(ctx, tag1);
|
||||||
|
|
||||||
|
cbool s1 = is_signed_tag(tag1);
|
||||||
|
cbool s2 = is_signed_tag(tag2);
|
||||||
|
int r1 = integer_tag_rank(tag1);
|
||||||
|
int r2 = integer_tag_rank(tag2);
|
||||||
|
|
||||||
|
// 两个都是有符号,或两个都是无符号:较小秩转换为较大秩
|
||||||
|
if (s1 == s2) {
|
||||||
|
return make_type(ctx, (r1 >= r2) ? tag1 : tag2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 一个有符号一个无符号
|
||||||
|
scc_hir_type_tag_t unsigned_t =
|
||||||
|
s1 ? unsigned_tag(tag1) : unsigned_tag(tag2);
|
||||||
|
scc_hir_type_tag_t signed_t = s1 ? tag1 : tag2;
|
||||||
|
scc_hir_type_tag_t unsigned_other = s1 ? tag2 : tag1; // 无符号的那个
|
||||||
|
int unsigned_rank = integer_tag_rank(unsigned_other);
|
||||||
|
|
||||||
|
// 如果无符号类型的秩 >= 有符号类型的秩:有符号转换为无符号
|
||||||
|
if (unsigned_rank >= integer_tag_rank(signed_t)) {
|
||||||
|
return make_type(ctx, unsigned_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有符号类型可以表示无符号类型的所有值:无符号转换为有符号
|
||||||
|
if (integer_tag_rank(signed_t) > integer_tag_rank(unsigned_other)) {
|
||||||
|
return make_type(ctx, signed_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return make_type(ctx, unsigned_tag(signed_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 确定类型转换的种类
|
||||||
|
*
|
||||||
|
* 根据源类型和目标类型选择合适的转换方式:
|
||||||
|
* - SEXT: 源有符号且目标更大
|
||||||
|
* - ZEXT: 源无符号且目标更大
|
||||||
|
* - TRUNC: 目标更小
|
||||||
|
* - 返回 -1 表示无需转换(同类型同大小)
|
||||||
|
*/
|
||||||
|
static int determine_conv_kind(scc_hir_type_tag_t src, scc_hir_type_tag_t dst) {
|
||||||
|
if (src == dst)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
static const int size_map[] = {
|
||||||
|
[SCC_HIR_TYPE_i8] = 1, [SCC_HIR_TYPE_u8] = 1,
|
||||||
|
[SCC_HIR_TYPE_i16] = 2, [SCC_HIR_TYPE_u16] = 2,
|
||||||
|
[SCC_HIR_TYPE_i32] = 4, [SCC_HIR_TYPE_u32] = 4,
|
||||||
|
[SCC_HIR_TYPE_i64] = 8, [SCC_HIR_TYPE_u64] = 8,
|
||||||
|
[SCC_HIR_TYPE_i128] = 16, [SCC_HIR_TYPE_u128] = 16,
|
||||||
|
[SCC_HIR_TYPE_f32] = 4, [SCC_HIR_TYPE_f64] = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
cbool src_float = (src == SCC_HIR_TYPE_f32 || src == SCC_HIR_TYPE_f64);
|
||||||
|
cbool dst_float = (dst == SCC_HIR_TYPE_f32 || dst == SCC_HIR_TYPE_f64);
|
||||||
|
|
||||||
|
if (src_float && dst_float) {
|
||||||
|
if (size_map[src] < size_map[dst])
|
||||||
|
return SCC_HIR_CONV_SEXT;
|
||||||
|
else
|
||||||
|
return SCC_HIR_CONV_TRUNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_float && !dst_float)
|
||||||
|
return SCC_HIR_CONV_SEXT;
|
||||||
|
|
||||||
|
if (!src_float && dst_float)
|
||||||
|
return SCC_HIR_CONV_SEXT;
|
||||||
|
|
||||||
|
int src_size = size_map[src];
|
||||||
|
int dst_size = size_map[dst];
|
||||||
|
|
||||||
|
if (dst_size > src_size) {
|
||||||
|
return is_signed_tag(src) ? SCC_HIR_CONV_SEXT : SCC_HIR_CONV_ZEXT;
|
||||||
|
} else if (dst_size < src_size) {
|
||||||
|
return SCC_HIR_CONV_TRUNC;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 插入类型转换指令
|
||||||
|
*
|
||||||
|
* 在 IR 中插入一个 conv 节点将 value 转换为 target_type。
|
||||||
|
* 自动选择 SEXT/ZEXT/TRUNC 或直接返回(无需转换时)。
|
||||||
|
*/
|
||||||
|
scc_hir_value_ref_t scc_ast2ir_emit_conversion(scc_ast2ir_ctx_t *ctx,
|
||||||
|
scc_hir_value_ref_t value,
|
||||||
|
scc_hir_type_ref_t target_type) {
|
||||||
|
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
|
||||||
|
scc_hir_type_t *src_type =
|
||||||
|
scc_hir_module_get_type_by_value(module, value);
|
||||||
|
scc_hir_type_t *dst_type =
|
||||||
|
scc_hir_module_get_type(module, target_type);
|
||||||
|
|
||||||
|
if (src_type == nullptr || dst_type == nullptr)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
if (src_type->tag == dst_type->tag)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
int kind = determine_conv_kind(src_type->tag, dst_type->tag);
|
||||||
|
if (kind < 0)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
return scc_hir_builder_conv(&ctx->builder, value, target_type, kind);
|
||||||
|
}
|
||||||
@@ -143,6 +143,17 @@ scc_hir_builder_integer(scc_hir_builder_t *builder, scc_hir_type_ref_t type,
|
|||||||
scc_hir_value_ref_t scc_hir_builder_const_string(scc_hir_builder_t *builder,
|
scc_hir_value_ref_t scc_hir_builder_const_string(scc_hir_builder_t *builder,
|
||||||
const char *str, usize len);
|
const char *str, usize len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建类型转换指令(SEXT/ZEXT/TRUNC)
|
||||||
|
* @param operand 被转换的值
|
||||||
|
* @param target_type 目标类型
|
||||||
|
* @param conv_kind 转换种类(SCC_HIR_CONV_SEXT/ZEXT/TRUNC)
|
||||||
|
*/
|
||||||
|
scc_hir_value_ref_t scc_hir_builder_conv(scc_hir_builder_t *builder,
|
||||||
|
scc_hir_value_ref_t operand,
|
||||||
|
scc_hir_type_ref_t target_type,
|
||||||
|
int conv_kind);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 开始构建函数
|
* @brief 开始构建函数
|
||||||
* @param func_ref 函数引用
|
* @param func_ref 函数引用
|
||||||
@@ -171,6 +182,21 @@ scc_hir_func_ref_t scc_hir_builder_current_func(scc_hir_builder_t *builder);
|
|||||||
scc_hir_bblock_ref_t scc_hir_builder_bblock(scc_hir_builder_t *builder,
|
scc_hir_bblock_ref_t scc_hir_builder_bblock(scc_hir_builder_t *builder,
|
||||||
const char *label);
|
const char *label);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建一个新的基本块(仅分配对象,不添加到当前函数的基本块列表)
|
||||||
|
* @param label 基本块标签(可为 nullptr)
|
||||||
|
* @return 基本块引用(真实 ID)
|
||||||
|
*/
|
||||||
|
scc_hir_bblock_ref_t scc_hir_builder_create_bblock(scc_hir_builder_t *builder,
|
||||||
|
const char *label);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将指定基本块追加到当前函数的基本块列表末尾
|
||||||
|
* @param bblock 基本块引用
|
||||||
|
*/
|
||||||
|
void scc_hir_builder_append_bblock(scc_hir_builder_t *builder,
|
||||||
|
scc_hir_bblock_ref_t bblock);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 开始构建新的基本块
|
* @brief 开始构建新的基本块
|
||||||
* @param label 基本块标签(可为nullptr,自动生成)
|
* @param label 基本块标签(可为nullptr,自动生成)
|
||||||
|
|||||||
@@ -176,6 +176,13 @@ typedef struct {
|
|||||||
} func;
|
} func;
|
||||||
} scc_hir_builtin_t;
|
} scc_hir_builtin_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SCC_HIR_CONV_NONE,
|
||||||
|
SCC_HIR_CONV_SEXT,
|
||||||
|
SCC_HIR_CONV_ZEXT,
|
||||||
|
SCC_HIR_CONV_TRUNC,
|
||||||
|
} scc_hir_conv_type_t;
|
||||||
|
|
||||||
struct scc_hir_value {
|
struct scc_hir_value {
|
||||||
scc_hir_type_ref_t type;
|
scc_hir_type_ref_t type;
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -199,9 +206,9 @@ struct scc_hir_value {
|
|||||||
scc_hir_value_ref_t value;
|
scc_hir_value_ref_t value;
|
||||||
} global_alloc;
|
} global_alloc;
|
||||||
struct {
|
struct {
|
||||||
scc_hir_value_ref_t operand;
|
scc_hir_value_ref_t operand; // 原始类型
|
||||||
scc_hir_type_ref_t target_type; // 目标类型
|
scc_hir_type_ref_t target_type; // 目标类型
|
||||||
enum { CONV_SEXT, CONV_ZEXT, CONV_TRUNC } conv_type;
|
scc_hir_conv_type_t conv_type;
|
||||||
} conv;
|
} conv;
|
||||||
struct {
|
struct {
|
||||||
scc_hir_value_ref_t target;
|
scc_hir_value_ref_t target;
|
||||||
@@ -250,6 +257,7 @@ typedef struct scc_hir_func_meta {
|
|||||||
scc_hir_type_ref_t type;
|
scc_hir_type_ref_t type;
|
||||||
scc_hir_value_ref_vec_t params;
|
scc_hir_value_ref_vec_t params;
|
||||||
int defined;
|
int defined;
|
||||||
|
cbool is_variadic;
|
||||||
} scc_hir_func_meta_t;
|
} scc_hir_func_meta_t;
|
||||||
|
|
||||||
#define SCC_HIR_BBLOCK_VALUES(bblock) \
|
#define SCC_HIR_BBLOCK_VALUES(bblock) \
|
||||||
|
|||||||
@@ -11,11 +11,6 @@ typedef struct {
|
|||||||
|
|
||||||
void scc_hir_dump_init(scc_hir_dump_t *ctx, scc_tree_dump_t *tree_dump,
|
void scc_hir_dump_init(scc_hir_dump_t *ctx, scc_tree_dump_t *tree_dump,
|
||||||
scc_hir_cprog_t *cprog);
|
scc_hir_cprog_t *cprog);
|
||||||
void scc_hir_dump_value(scc_hir_dump_t *ctx, scc_hir_value_ref_t node_ref);
|
|
||||||
void scc_hir_dump_type(scc_hir_dump_t *ctx, scc_hir_type_ref_t type_ref);
|
|
||||||
void scc_hir_dump_bblock(scc_hir_dump_t *ctx, scc_hir_bblock_ref_t bblock_ref);
|
|
||||||
void scc_hir_dump_func(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref);
|
|
||||||
void scc_hir_dump_cprog(scc_hir_dump_t *ctx);
|
|
||||||
void scc_hir_dump_cprog_linear(scc_hir_dump_t *ctx);
|
void scc_hir_dump_cprog_linear(scc_hir_dump_t *ctx);
|
||||||
|
|
||||||
#endif /* __SCC_HIR_DUMP_H__ */
|
#endif /* __SCC_HIR_DUMP_H__ */
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ void scc_hir_func_init(scc_hir_func_t *in, const char *name) {
|
|||||||
in->name = name;
|
in->name = name;
|
||||||
scc_hir_func_meta_t *meta = SCC_HIR_FUNC_META(in);
|
scc_hir_func_meta_t *meta = SCC_HIR_FUNC_META(in);
|
||||||
meta->type = SCC_HIR_REF_nullptr;
|
meta->type = SCC_HIR_REF_nullptr;
|
||||||
|
meta->is_variadic = false;
|
||||||
|
meta->defined = false;
|
||||||
scc_vec_init(in->bblocks);
|
scc_vec_init(in->bblocks);
|
||||||
scc_vec_init(meta->params);
|
scc_vec_init(meta->params);
|
||||||
}
|
}
|
||||||
@@ -110,6 +112,11 @@ void scc_hir_value_init(scc_hir_value_t *in, const char *name,
|
|||||||
case SCC_HIR_VALUE_TAG_RET:
|
case SCC_HIR_VALUE_TAG_RET:
|
||||||
in->data.ret.ret_val = 0;
|
in->data.ret.ret_val = 0;
|
||||||
break;
|
break;
|
||||||
|
case SCC_HIR_VALUE_TAG_CONV:
|
||||||
|
in->data.conv.conv_type = SCC_HIR_CONV_NONE;
|
||||||
|
in->data.conv.operand = 0;
|
||||||
|
in->data.conv.target_type = 0;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -188,7 +188,6 @@ scc_hir_func_ref_t scc_hir_builder_func(scc_hir_builder_t *builder,
|
|||||||
// 创建新函数
|
// 创建新函数
|
||||||
scc_hir_func_t func;
|
scc_hir_func_t func;
|
||||||
scc_hir_func_meta_t *meta = scc_malloc(sizeof(scc_hir_func_meta_t));
|
scc_hir_func_meta_t *meta = scc_malloc(sizeof(scc_hir_func_meta_t));
|
||||||
meta->defined = 0;
|
|
||||||
Assert(meta != nullptr);
|
Assert(meta != nullptr);
|
||||||
func.meta = meta;
|
func.meta = meta;
|
||||||
scc_hir_func_init(&func, name);
|
scc_hir_func_init(&func, name);
|
||||||
@@ -231,6 +230,37 @@ scc_hir_bblock_ref_t scc_hir_builder_bblock(scc_hir_builder_t *builder,
|
|||||||
return bblock_ref;
|
return bblock_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scc_hir_bblock_ref_t scc_hir_builder_create_bblock(scc_hir_builder_t *builder,
|
||||||
|
const char *label) {
|
||||||
|
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
||||||
|
scc_hir_bblock_t bblock = {0};
|
||||||
|
if (label) {
|
||||||
|
bblock.name = label;
|
||||||
|
}
|
||||||
|
bblock.meta = nullptr;
|
||||||
|
scc_vec_init(*SCC_HIR_BBLOCK_VALUES(&bblock));
|
||||||
|
// 直接添加到模块,获得真实 ID,但不挂载到当前函数
|
||||||
|
return scc_hir_module_add_bblock(scc_hir_builder_get_module(builder),
|
||||||
|
&bblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void scc_hir_builder_append_bblock(scc_hir_builder_t *builder,
|
||||||
|
scc_hir_bblock_ref_t bblock) {
|
||||||
|
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
||||||
|
scc_hir_func_t *func = scc_hir_module_get_func(
|
||||||
|
scc_hir_builder_get_module(builder), builder->current_func);
|
||||||
|
if (!func) {
|
||||||
|
LOG_ERROR("No current function");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// FIXME 检查是否已经挂载过(可选,防止重复挂载)
|
||||||
|
for (usize i = 0; i < func->bblocks.size; i++) {
|
||||||
|
if (func->bblocks.data[i] == bblock)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scc_vec_push(func->bblocks, bblock);
|
||||||
|
}
|
||||||
|
|
||||||
scc_hir_type_ref_t scc_hir_builder_type(scc_hir_builder_t *builder,
|
scc_hir_type_ref_t scc_hir_builder_type(scc_hir_builder_t *builder,
|
||||||
const scc_hir_type_t *type_desc) {
|
const scc_hir_type_t *type_desc) {
|
||||||
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
||||||
@@ -270,15 +300,55 @@ scc_hir_value_ref_t scc_hir_builder_const_string(scc_hir_builder_t *builder,
|
|||||||
.type = array_type_ref,
|
.type = array_type_ref,
|
||||||
.data.const_array.base_type = u8_type,
|
.data.const_array.base_type = u8_type,
|
||||||
};
|
};
|
||||||
char *buff = scc_malloc(len - 1);
|
scc_str_t buf;
|
||||||
Assert(buff);
|
scc_str_init(&buf);
|
||||||
// FIXME content to real string
|
// FIXME content to real string
|
||||||
for (usize i = 1; i < len - 1; i++) {
|
for (usize i = 1; i < len - 1; i++) {
|
||||||
buff[i - 1] = str[i];
|
if (str[i] != '\\') {
|
||||||
|
scc_str_append_ch(&buf, str[i]);
|
||||||
|
} else {
|
||||||
|
if (i + 1 < len) {
|
||||||
|
i += 1;
|
||||||
|
switch (str[i]) {
|
||||||
|
case 'a':
|
||||||
|
scc_str_append_ch(&buf, '\a');
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
scc_str_append_ch(&buf, '\b');
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
scc_str_append_ch(&buf, '\f');
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
scc_str_append_ch(&buf, '\n');
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
scc_str_append_ch(&buf, '\t');
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
scc_str_append_ch(&buf, '\r');
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
scc_str_append_ch(&buf, '\\');
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
scc_str_append_ch(&buf, '"');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_WARN("Unknown escape sequence: \\%c", str[i]);
|
||||||
|
scc_str_append_ch(&buf, str[i]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
buff[len - 2] = '\0';
|
} else {
|
||||||
|
scc_str_append_ch(&buf, '\\');
|
||||||
|
LOG_ERROR("invalid escape character");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scc_str_append_ch(&buf, '\0');
|
||||||
|
usize buf_len = scc_str_len(&buf);
|
||||||
scc_vec_unsafe_from_buffer(const_array_value.data.const_array.fields,
|
scc_vec_unsafe_from_buffer(const_array_value.data.const_array.fields,
|
||||||
(u8 *)buff, len - 1);
|
(u8 *)scc_str_move_cstr(&buf), buf_len);
|
||||||
scc_hir_value_ref_t const_array_ref =
|
scc_hir_value_ref_t const_array_ref =
|
||||||
scc_hir_module_add_value(GET_MODULE(builder), &const_array_value);
|
scc_hir_module_add_value(GET_MODULE(builder), &const_array_value);
|
||||||
Assert(const_array_ref != SCC_HIR_REF_nullptr);
|
Assert(const_array_ref != SCC_HIR_REF_nullptr);
|
||||||
@@ -293,6 +363,23 @@ scc_hir_value_ref_t scc_hir_builder_const_string(scc_hir_builder_t *builder,
|
|||||||
return pointer_to_global_value;
|
return pointer_to_global_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scc_hir_value_ref_t scc_hir_builder_conv(scc_hir_builder_t *builder,
|
||||||
|
scc_hir_value_ref_t operand,
|
||||||
|
scc_hir_type_ref_t target_type,
|
||||||
|
int conv_kind) {
|
||||||
|
Assert(builder != nullptr);
|
||||||
|
scc_hir_value_t value;
|
||||||
|
scc_hir_value_init(&value, nullptr, SCC_HIR_VALUE_TAG_CONV);
|
||||||
|
value.type = target_type;
|
||||||
|
value.data.conv.operand = operand;
|
||||||
|
value.data.conv.target_type = target_type;
|
||||||
|
value.data.conv.conv_type = conv_kind;
|
||||||
|
scc_hir_value_ref_t ref =
|
||||||
|
scc_hir_module_add_value(&builder->cprog->module, &value);
|
||||||
|
scc_hir_builder_add_instr(builder, ref);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
void scc_hir_builder_begin_func(scc_hir_builder_t *builder,
|
void scc_hir_builder_begin_func(scc_hir_builder_t *builder,
|
||||||
scc_hir_func_ref_t func_ref) {
|
scc_hir_func_ref_t func_ref) {
|
||||||
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
SCC_HIR_BUILDER_CHECK_NO_BORROW(builder);
|
||||||
|
|||||||
@@ -3,9 +3,13 @@
|
|||||||
#include <scc_tree_dump.h>
|
#include <scc_tree_dump.h>
|
||||||
|
|
||||||
#define GET_MODULE(ctx) (&(ctx->cprog->module))
|
#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,
|
void scc_hir_dump_init(scc_hir_dump_t *ctx, scc_tree_dump_t *td,
|
||||||
scc_hashtable_t *visited);
|
scc_hir_cprog_t *cprog) {
|
||||||
|
ctx->dump_ctx = td;
|
||||||
|
ctx->cprog = cprog;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *get_node_type_str(scc_hir_value_tag_t tag) {
|
static const char *get_node_type_str(scc_hir_value_tag_t tag) {
|
||||||
static const char *node_types[] = {
|
static const char *node_types[] = {
|
||||||
[SCC_HIR_VALUE_TAG_NULLPTR] = "NullPtr",
|
[SCC_HIR_VALUE_TAG_NULLPTR] = "NullPtr",
|
||||||
@@ -71,337 +75,6 @@ static const char *get_type_tag_str(scc_hir_type_tag_t tag) {
|
|||||||
return "<unknown_type>";
|
return "<unknown_type>";
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void dump_child_node_ref(scc_hir_dump_t *ctx,
|
|
||||||
scc_hir_value_ref_t child,
|
|
||||||
cbool is_last) {
|
|
||||||
if (!child)
|
|
||||||
return;
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
|
||||||
scc_hir_dump_value(ctx, child);
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_integer_node(scc_hir_dump_t *ctx,
|
|
||||||
const scc_hir_value_t *value) {
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
// FIXME hack it
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "%d", value->data.integer.data.digit);
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_op_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, false);
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
scc_tree_dump_node(ctx->dump_ctx, "op: ");
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "%s", get_op_str(value->data.op.op));
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
|
|
||||||
if (value->data.op.lhs)
|
|
||||||
dump_child_node_ref(ctx, value->data.op.lhs,
|
|
||||||
value->data.op.rhs ? false : true);
|
|
||||||
if (value->data.op.rhs)
|
|
||||||
dump_child_node_ref(ctx, value->data.op.rhs, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_load_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
|
||||||
if (value->data.load.target)
|
|
||||||
dump_child_node_ref(ctx, value->data.load.target, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_store_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
|
||||||
if (value->data.store.target)
|
|
||||||
dump_child_node_ref(ctx, value->data.store.target, false);
|
|
||||||
if (value->data.store.value)
|
|
||||||
dump_child_node_ref(ctx, value->data.store.value, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_get_elem_ptr_node(scc_hir_dump_t *ctx,
|
|
||||||
const scc_hir_value_t *value) {
|
|
||||||
if (value->data.get_elem_ptr.src_addr)
|
|
||||||
dump_child_node_ref(ctx, value->data.get_elem_ptr.src_addr, false);
|
|
||||||
if (value->data.get_elem_ptr.index)
|
|
||||||
dump_child_node_ref(ctx, value->data.get_elem_ptr.index, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_branch_node(scc_hir_dump_t *ctx,
|
|
||||||
const scc_hir_value_t *value) {
|
|
||||||
if (value->data.branch.cond)
|
|
||||||
dump_child_node_ref(ctx, value->data.branch.cond, false);
|
|
||||||
|
|
||||||
if (value->data.branch.true_bblock) {
|
|
||||||
scc_hir_bblock_t *true_bblock = scc_hir_module_get_bblock(
|
|
||||||
GET_MODULE(ctx), value->data.branch.true_bblock);
|
|
||||||
if (true_bblock) {
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
scc_tree_dump_node(ctx->dump_ctx, "TrueBlock: ");
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "'%s'",
|
|
||||||
true_bblock->name ? true_bblock->name
|
|
||||||
: "<unnamed>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (value->data.branch.false_bblock) {
|
|
||||||
scc_hir_bblock_t *false_bblock = scc_hir_module_get_bblock(
|
|
||||||
GET_MODULE(ctx), value->data.branch.false_bblock);
|
|
||||||
if (false_bblock) {
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
scc_tree_dump_node(ctx->dump_ctx, "FalseBlock: ");
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "'%s'",
|
|
||||||
false_bblock->name ? false_bblock->name
|
|
||||||
: "<unnamed>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_jump_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
if (value->data.jump.target_bblock) {
|
|
||||||
scc_hir_bblock_t *target = scc_hir_module_get_bblock(
|
|
||||||
GET_MODULE(ctx), value->data.jump.target_bblock);
|
|
||||||
if (target)
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "to '%s'",
|
|
||||||
target->name ? target->name : "<unnamed>");
|
|
||||||
else
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "to invalid block");
|
|
||||||
} else {
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "to nullptr");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_call_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
if (value->data.call.callee.func_ref) {
|
|
||||||
scc_hir_func_t *callee = scc_hir_module_get_func(
|
|
||||||
GET_MODULE(ctx), value->data.call.callee.func_ref);
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "func='%s'",
|
|
||||||
callee ? (callee->name ? callee->name : "<unnamed>")
|
|
||||||
: "<invalid>");
|
|
||||||
} else {
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "func=nullptr");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (usize i = 0; i < scc_vec_size(value->data.call.args); i++) {
|
|
||||||
cbool is_last = (i + 1 == scc_vec_size(value->data.call.args));
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
|
||||||
scc_hir_value_ref_t arg = scc_vec_at(value->data.call.args, i);
|
|
||||||
dump_child_node_ref(ctx, arg, is_last);
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_ret_node(scc_hir_dump_t *ctx, const scc_hir_value_t *value) {
|
|
||||||
if (value->data.ret.ret_val)
|
|
||||||
dump_child_node_ref(ctx, value->data.ret.ret_val, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void scc_hir_dump_init(scc_hir_dump_t *ctx, scc_tree_dump_t *td,
|
|
||||||
scc_hir_cprog_t *cprog) {
|
|
||||||
ctx->dump_ctx = td;
|
|
||||||
ctx->cprog = cprog;
|
|
||||||
}
|
|
||||||
|
|
||||||
void scc_hir_dump_value(scc_hir_dump_t *ctx, scc_hir_value_ref_t value_ref) {
|
|
||||||
scc_hir_value_t *value =
|
|
||||||
scc_hir_module_get_value(GET_MODULE(ctx), value_ref);
|
|
||||||
if (!value) {
|
|
||||||
LOG_ERROR("Invalid value ref");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
scc_tree_dump_node(ctx->dump_ctx, "%s", get_node_type_str(value->tag));
|
|
||||||
if (value->name && value->name[0])
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, " [%s]", value->name);
|
|
||||||
if (value->type) {
|
|
||||||
scc_hir_type_t *type =
|
|
||||||
scc_hir_module_get_type(GET_MODULE(ctx), value->type);
|
|
||||||
if (type) {
|
|
||||||
scc_tree_dump_append(ctx->dump_ctx, " : ");
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "%s",
|
|
||||||
get_type_tag_str(type->tag));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (value->tag) {
|
|
||||||
case SCC_HIR_VALUE_TAG_INTEGER:
|
|
||||||
dump_integer_node(ctx, value);
|
|
||||||
break;
|
|
||||||
case SCC_HIR_VALUE_TAG_ALLOC:
|
|
||||||
break;
|
|
||||||
case SCC_HIR_VALUE_TAG_LOAD:
|
|
||||||
dump_load_node(ctx, value);
|
|
||||||
break;
|
|
||||||
case SCC_HIR_VALUE_TAG_STORE:
|
|
||||||
dump_store_node(ctx, value);
|
|
||||||
break;
|
|
||||||
case SCC_HIR_VALUE_TAG_GET_ELEM_PTR:
|
|
||||||
dump_get_elem_ptr_node(ctx, value);
|
|
||||||
break;
|
|
||||||
case SCC_HIR_VALUE_TAG_OP:
|
|
||||||
dump_op_node(ctx, value);
|
|
||||||
break;
|
|
||||||
case SCC_HIR_VALUE_TAG_BRANCH:
|
|
||||||
dump_branch_node(ctx, value);
|
|
||||||
break;
|
|
||||||
case SCC_HIR_VALUE_TAG_JUMP:
|
|
||||||
dump_jump_node(ctx, value);
|
|
||||||
break;
|
|
||||||
case SCC_HIR_VALUE_TAG_CALL:
|
|
||||||
dump_call_node(ctx, value);
|
|
||||||
break;
|
|
||||||
case SCC_HIR_VALUE_TAG_RET:
|
|
||||||
dump_ret_node(ctx, value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "unknown");
|
|
||||||
scc_tree_dump_append_fmt(ctx->dump_ctx, " tag(%d)", value->tag);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void scc_hir_dump_type(scc_hir_dump_t *ctx, scc_hir_type_ref_t type_ref) {
|
|
||||||
scc_hashtable_t visited;
|
|
||||||
scc_hashtable_usize_init(&visited);
|
|
||||||
dump_type_with_visited(ctx, type_ref, &visited);
|
|
||||||
scc_hashtable_drop(&visited);
|
|
||||||
}
|
|
||||||
void scc_hir_dump_bblock(scc_hir_dump_t *ctx, scc_hir_bblock_ref_t bblock_ref) {
|
|
||||||
if (!ctx || !bblock_ref) {
|
|
||||||
LOG_ERROR("invalid parameter");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scc_hir_bblock_t *bblock =
|
|
||||||
scc_hir_module_get_bblock(GET_MODULE(ctx), bblock_ref);
|
|
||||||
if (!bblock) {
|
|
||||||
LOG_ERROR("invalid bblock ref");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
scc_tree_dump_node(ctx->dump_ctx, "BasicBlock: ");
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "'%s'",
|
|
||||||
bblock->name ? bblock->name : "<unnamed>");
|
|
||||||
scc_tree_dump_append(ctx->dump_ctx, "\n");
|
|
||||||
|
|
||||||
scc_hir_value_ref_vec_t *values = SCC_HIR_BBLOCK_VALUES(bblock);
|
|
||||||
scc_vec_foreach(*values, i) {
|
|
||||||
cbool is_last = (i + 1 == scc_vec_size(*values));
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
|
||||||
scc_hir_dump_value(ctx, scc_vec_at(*values, i));
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void scc_hir_dump_func(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref) {
|
|
||||||
scc_hir_func_t *func = scc_hir_module_get_func(GET_MODULE(ctx), func_ref);
|
|
||||||
if (!ctx || !func) {
|
|
||||||
LOG_ERROR("invalid parameter");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
scc_tree_dump_node(ctx->dump_ctx, "Function: ");
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "'%s'",
|
|
||||||
func->name ? func->name : "<unnamed>");
|
|
||||||
scc_tree_dump_append(ctx->dump_ctx, "\n");
|
|
||||||
|
|
||||||
if (SCC_HIR_FUNC_META(func)->type) {
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, false);
|
|
||||||
scc_hir_dump_type(ctx, SCC_HIR_FUNC_META(func)->type);
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
for (usize i = 0; i < scc_vec_size(SCC_HIR_FUNC_META(func)->params); i++) {
|
|
||||||
cbool is_last =
|
|
||||||
(i + 1 == scc_vec_size(SCC_HIR_FUNC_META(func)->params));
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
|
||||||
scc_hir_dump_value(ctx, scc_vec_at(SCC_HIR_FUNC_META(func)->params, i));
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
for (usize i = 0; i < scc_vec_size(func->bblocks); i++) {
|
|
||||||
cbool is_last = (i + 1 == scc_vec_size(func->bblocks));
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
|
||||||
scc_hir_dump_bblock(ctx, scc_vec_at(func->bblocks, i));
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void scc_hir_dump_cprog(scc_hir_dump_t *ctx) {
|
|
||||||
scc_tree_dump_node(ctx->dump_ctx, "Func defs:\n");
|
|
||||||
scc_vec_foreach(ctx->cprog->func_defs, i) {
|
|
||||||
cbool is_last = (i + 1 == scc_vec_size(ctx->cprog->func_defs));
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
|
||||||
scc_hir_dump_func(ctx, scc_vec_at(ctx->cprog->func_defs, i));
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- 线性输出(保留原逻辑,改用新 API)-----
|
|
||||||
|
|
||||||
// 在 scc_hir_dump.c 中添加以下静态辅助函数(放在文件前部,现有函数之前)
|
|
||||||
|
|
||||||
static void dump_type_linear_with_visited(scc_hir_dump_t *ctx,
|
|
||||||
scc_hir_type_ref_t type_ref,
|
|
||||||
scc_hashtable_t *visited);
|
|
||||||
static void dump_type_with_visited(scc_hir_dump_t *ctx,
|
|
||||||
scc_hir_type_ref_t type_ref,
|
|
||||||
scc_hashtable_t *visited) {
|
|
||||||
if (!ctx || !type_ref) {
|
|
||||||
LOG_ERROR("invalid parameter");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 检查循环
|
|
||||||
if (scc_hashtable_get(visited, (void *)(usize)type_ref)) {
|
|
||||||
scc_tree_dump_append(ctx->dump_ctx, " <recursive>");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scc_hashtable_set(visited, (void *)(usize)type_ref, (void *)1);
|
|
||||||
|
|
||||||
scc_hir_type_t *type = scc_hir_module_get_type(GET_MODULE(ctx), type_ref);
|
|
||||||
if (!type) {
|
|
||||||
LOG_ERROR("invalid type ref");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
scc_tree_dump_node(ctx->dump_ctx, "Type: ");
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "%s", get_type_tag_str(type->tag));
|
|
||||||
|
|
||||||
switch (type->tag) {
|
|
||||||
case SCC_HIR_TYPE_PTR:
|
|
||||||
if (type->data.pointer.base) {
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
|
||||||
dump_type_with_visited(ctx, type->data.pointer.base, visited);
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SCC_HIR_TYPE_ARRAY:
|
|
||||||
if (type->data.array.len > 0) {
|
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
|
||||||
scc_tree_dump_node(ctx->dump_ctx, "Array Length: ");
|
|
||||||
scc_tree_dump_value(ctx->dump_ctx, "%zu", type->data.array.len);
|
|
||||||
scc_tree_dump_append(ctx->dump_ctx, "\n");
|
|
||||||
}
|
|
||||||
if (type->data.array.base) {
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
|
||||||
dump_type_with_visited(ctx, type->data.array.base, visited);
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SCC_HIR_TYPE_FUNC:
|
|
||||||
for (usize i = 0; i < scc_vec_size(type->data.function.params); i++) {
|
|
||||||
cbool is_last = (i + 1 == scc_vec_size(type->data.function.params));
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, is_last);
|
|
||||||
dump_type_with_visited(
|
|
||||||
ctx, scc_vec_at(type->data.function.params, i), visited);
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
if (type->data.function.ret_type) {
|
|
||||||
scc_tree_dump_push(ctx->dump_ctx, true);
|
|
||||||
dump_type_with_visited(ctx, type->data.function.ret_type, visited);
|
|
||||||
scc_tree_dump_pop(ctx->dump_ctx);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dump_type_linear_with_visited(scc_hir_dump_t *ctx,
|
static void dump_type_linear_with_visited(scc_hir_dump_t *ctx,
|
||||||
scc_hir_type_ref_t type_ref,
|
scc_hir_type_ref_t type_ref,
|
||||||
scc_hashtable_t *visited) {
|
scc_hashtable_t *visited) {
|
||||||
@@ -653,7 +326,7 @@ void scc_hir_dump_value_linear(scc_hir_dump_t *ctx,
|
|||||||
scc_tree_dump_append_fmt(ctx->dump_ctx, "global %s", value->name);
|
scc_tree_dump_append_fmt(ctx->dump_ctx, "global %s", value->name);
|
||||||
scc_tree_dump_begin_line(ctx->dump_ctx);
|
scc_tree_dump_begin_line(ctx->dump_ctx);
|
||||||
scc_hir_dump_value_linear(ctx, value->data.global_alloc.value);
|
scc_hir_dump_value_linear(ctx, value->data.global_alloc.value);
|
||||||
return;
|
break;
|
||||||
case SCC_HIR_VALUE_TAG_ARRAY:
|
case SCC_HIR_VALUE_TAG_ARRAY:
|
||||||
scc_tree_dump_append(ctx->dump_ctx, "const_array ");
|
scc_tree_dump_append(ctx->dump_ctx, "const_array ");
|
||||||
scc_hir_dump_type_linear(ctx, value->data.const_array.base_type);
|
scc_hir_dump_type_linear(ctx, value->data.const_array.base_type);
|
||||||
@@ -664,6 +337,19 @@ void scc_hir_dump_value_linear(scc_hir_dump_t *ctx,
|
|||||||
}
|
}
|
||||||
scc_tree_dump_append(ctx->dump_ctx, " ]");
|
scc_tree_dump_append(ctx->dump_ctx, " ]");
|
||||||
break;
|
break;
|
||||||
|
case SCC_HIR_VALUE_TAG_CONV:
|
||||||
|
static const char *conv_name[] = {
|
||||||
|
[SCC_HIR_CONV_NONE] = "null",
|
||||||
|
[SCC_HIR_CONV_SEXT] = "sext",
|
||||||
|
[SCC_HIR_CONV_ZEXT] = "zext",
|
||||||
|
[SCC_HIR_CONV_TRUNC] = "trunc",
|
||||||
|
};
|
||||||
|
scc_tree_dump_append_fmt(ctx->dump_ctx, "conv.%s(",
|
||||||
|
conv_name[value->data.conv.conv_type]);
|
||||||
|
scc_hir_dump_type_linear(ctx, value->data.conv.target_type);
|
||||||
|
scc_tree_dump_append(ctx->dump_ctx, ") ");
|
||||||
|
format_ref_or_value(ctx, value->data.conv.operand);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
scc_tree_dump_append_fmt(ctx->dump_ctx, "<%s value %u>",
|
scc_tree_dump_append_fmt(ctx->dump_ctx, "<%s value %u>",
|
||||||
get_node_type_str(value->tag), value_ref);
|
get_node_type_str(value->tag), value_ref);
|
||||||
@@ -706,24 +392,8 @@ void scc_hir_dump_func_linear(scc_hir_dump_t *ctx, scc_hir_func_ref_t func_ref,
|
|||||||
(func->name && func->name[0]) ? func->name
|
(func->name && func->name[0]) ? func->name
|
||||||
: "<unnamed>");
|
: "<unnamed>");
|
||||||
|
|
||||||
if (scc_vec_size(SCC_HIR_FUNC_META(func)->params) > 0) {
|
if (SCC_HIR_FUNC_META(func)->is_variadic) {
|
||||||
scc_tree_dump_append(ctx->dump_ctx, "(");
|
scc_tree_dump_append(ctx->dump_ctx, "(...)");
|
||||||
for (usize i = 0; i < scc_vec_size(SCC_HIR_FUNC_META(func)->params);
|
|
||||||
i++) {
|
|
||||||
if (i > 0)
|
|
||||||
scc_tree_dump_append(ctx->dump_ctx, ", ");
|
|
||||||
scc_hir_value_ref_t param_ref =
|
|
||||||
scc_vec_at(SCC_HIR_FUNC_META(func)->params, i);
|
|
||||||
scc_hir_value_t *param_node =
|
|
||||||
scc_hir_module_get_value(GET_MODULE(ctx), param_ref);
|
|
||||||
scc_tree_dump_append(ctx->dump_ctx, "%");
|
|
||||||
if (param_node && param_node->name && param_node->name[0] != '\0')
|
|
||||||
scc_tree_dump_append_fmt(ctx->dump_ctx, "%u[%s]", param_ref,
|
|
||||||
param_node->name);
|
|
||||||
else
|
|
||||||
scc_tree_dump_append_fmt(ctx->dump_ctx, "%u", param_ref);
|
|
||||||
}
|
|
||||||
scc_tree_dump_append(ctx->dump_ctx, ")");
|
|
||||||
} else {
|
} else {
|
||||||
scc_tree_dump_append(ctx->dump_ctx, "()");
|
scc_tree_dump_append(ctx->dump_ctx, "()");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,6 +135,9 @@ typedef enum {
|
|||||||
/* 栈管理 */
|
/* 栈管理 */
|
||||||
SCC_LIR_ALLOCA,
|
SCC_LIR_ALLOCA,
|
||||||
|
|
||||||
|
/* 类型扩展 */
|
||||||
|
SCC_LIR_EXTEND,
|
||||||
|
|
||||||
SCC_LIR_NOP
|
SCC_LIR_NOP
|
||||||
} scc_lir_op_t;
|
} scc_lir_op_t;
|
||||||
|
|
||||||
@@ -208,6 +211,10 @@ typedef struct scc_lir_ins {
|
|||||||
int align_bytes;
|
int align_bytes;
|
||||||
} alloca;
|
} alloca;
|
||||||
|
|
||||||
|
struct scc_lir_extend {
|
||||||
|
int from_size; // 源类型宽度(字节)
|
||||||
|
} extend;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
scc_lir_val_t ap;
|
scc_lir_val_t ap;
|
||||||
scc_lir_val_t last;
|
scc_lir_val_t last;
|
||||||
|
|||||||
@@ -428,21 +428,37 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value,
|
|||||||
scc_lir_builder_add_instr(ctx, &instr);
|
scc_lir_builder_add_instr(ctx, &instr);
|
||||||
} break;
|
} break;
|
||||||
case SCC_HIR_VALUE_TAG_CONV: {
|
case SCC_HIR_VALUE_TAG_CONV: {
|
||||||
// 类型转换:使用 MOV 指令配合扩展/截断
|
// 类型转换:使用 LIR_EXTEND 指令实现符号/零扩展
|
||||||
scc_lir_val_t src =
|
scc_lir_val_t src =
|
||||||
ir_value_to_lir_operand(ctx, value->data.conv.operand);
|
ir_value_to_lir_operand(ctx, value->data.conv.operand);
|
||||||
scc_lir_ext_t conv_ext = SCC_LIR_EXT_NONE;
|
scc_lir_ext_t conv_ext = SCC_LIR_EXT_NONE;
|
||||||
if (value->data.conv.conv_type == CONV_SEXT)
|
if (value->data.conv.conv_type == SCC_HIR_CONV_SEXT)
|
||||||
conv_ext = SCC_LIR_EXT_SEXT;
|
conv_ext = SCC_LIR_EXT_SEXT;
|
||||||
else if (value->data.conv.conv_type == CONV_ZEXT)
|
else if (value->data.conv.conv_type == SCC_HIR_CONV_ZEXT)
|
||||||
conv_ext = SCC_LIR_EXT_ZEXT;
|
conv_ext = SCC_LIR_EXT_ZEXT;
|
||||||
// TRUNC 用 NONE 即可(MOV 截断)
|
// TRUNC 用 SCC_LIR_MOV 截断
|
||||||
|
if (value->data.conv.conv_type == SCC_HIR_CONV_TRUNC) {
|
||||||
scc_lir_instr_t instr = {.op = SCC_LIR_MOV,
|
scc_lir_instr_t instr = {.op = SCC_LIR_MOV,
|
||||||
.size = size,
|
.size = size,
|
||||||
.ext = conv_ext,
|
|
||||||
.to = SCC_LIR_VREG(dst_vreg),
|
.to = SCC_LIR_VREG(dst_vreg),
|
||||||
.arg0 = src};
|
.arg0 = src};
|
||||||
scc_lir_builder_add_instr(ctx, &instr);
|
scc_lir_builder_add_instr(ctx, &instr);
|
||||||
|
} else {
|
||||||
|
// 计算源类型宽度
|
||||||
|
scc_hir_type_t *src_type = scc_hir_module_get_type(
|
||||||
|
ctx->hir_module,
|
||||||
|
scc_hir_module_get_value(ctx->hir_module,
|
||||||
|
value->data.conv.operand)
|
||||||
|
->type);
|
||||||
|
int from_size = scc_hir_module_type_size(ctx->hir_module, src_type);
|
||||||
|
scc_lir_instr_t instr = {.op = SCC_LIR_EXTEND,
|
||||||
|
.size = size,
|
||||||
|
.ext = conv_ext,
|
||||||
|
.to = SCC_LIR_VREG(dst_vreg),
|
||||||
|
.arg0 = src,
|
||||||
|
.metadata.extend.from_size = from_size};
|
||||||
|
scc_lir_builder_add_instr(ctx, &instr);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
case SCC_HIR_VALUE_TAG_BUILTIN: {
|
case SCC_HIR_VALUE_TAG_BUILTIN: {
|
||||||
scc_hir_builtin_t *b = &value->data.builtin;
|
scc_hir_builtin_t *b = &value->data.builtin;
|
||||||
@@ -542,7 +558,7 @@ static void translate_func(ir2lir_ctx_t *ctx, scc_hir_func_t *ir_func) {
|
|||||||
.attr = SCC_LIR_ATTR_NONE,
|
.attr = SCC_LIR_ATTR_NONE,
|
||||||
.frame_size = 0,
|
.frame_size = 0,
|
||||||
.vregs_count = 0,
|
.vregs_count = 0,
|
||||||
.is_va_arg = false,
|
.is_va_arg = func_meta->is_variadic,
|
||||||
};
|
};
|
||||||
scc_vec_push(ctx->lir_module->func_metas, lir_func_meta);
|
scc_vec_push(ctx->lir_module->func_metas, lir_func_meta);
|
||||||
ctx->current_func = ir_func;
|
ctx->current_func = ir_func;
|
||||||
|
|||||||
@@ -7,134 +7,65 @@
|
|||||||
#include <scc_core.h>
|
#include <scc_core.h>
|
||||||
|
|
||||||
static const char *op_to_string(scc_lir_op_t op) {
|
static const char *op_to_string(scc_lir_op_t op) {
|
||||||
switch (op) {
|
static const char *op_names[] = {
|
||||||
case SCC_LIR_MOV:
|
[SCC_LIR_MOV] = "mov",
|
||||||
return "mov";
|
[SCC_LIR_LOAD] = "load",
|
||||||
case SCC_LIR_LOAD:
|
[SCC_LIR_LOAD_ADDR] = "load.addr",
|
||||||
return "load";
|
[SCC_LIR_STORE] = "store",
|
||||||
case SCC_LIR_LOAD_ADDR:
|
[SCC_LIR_ADD] = "add",
|
||||||
return "load.addr";
|
[SCC_LIR_SUB] = "sub",
|
||||||
case SCC_LIR_STORE:
|
[SCC_LIR_MUL] = "mul",
|
||||||
return "store";
|
[SCC_LIR_DIV_S] = "div.s",
|
||||||
// case SCC_LIR_STORE_ADDR:
|
[SCC_LIR_DIV_U] = "div.u",
|
||||||
// return "store.addr";
|
[SCC_LIR_REM_S] = "rem.s",
|
||||||
case SCC_LIR_ADD:
|
[SCC_LIR_REM_U] = "rem.u",
|
||||||
return "add";
|
[SCC_LIR_AND] = "and",
|
||||||
case SCC_LIR_SUB:
|
[SCC_LIR_OR] = "or",
|
||||||
return "sub";
|
[SCC_LIR_XOR] = "xor",
|
||||||
case SCC_LIR_MUL:
|
[SCC_LIR_SHL] = "shl",
|
||||||
return "mul";
|
[SCC_LIR_SHR] = "shr",
|
||||||
case SCC_LIR_DIV_S:
|
[SCC_LIR_SAR] = "sar",
|
||||||
return "div.s";
|
[SCC_LIR_NEG] = "neg",
|
||||||
case SCC_LIR_DIV_U:
|
[SCC_LIR_NOT] = "not",
|
||||||
return "div.u";
|
[SCC_LIR_FADD] = "fadd",
|
||||||
case SCC_LIR_REM_S:
|
[SCC_LIR_FSUB] = "fsub",
|
||||||
return "rem.s";
|
[SCC_LIR_FMUL] = "fmul",
|
||||||
case SCC_LIR_REM_U:
|
[SCC_LIR_FDIV] = "fdiv",
|
||||||
return "rem.u";
|
[SCC_LIR_FNEG] = "fneg",
|
||||||
case SCC_LIR_AND:
|
[SCC_LIR_FCVT] = "fcvt",
|
||||||
return "and";
|
[SCC_LIR_CMP] = "cmp",
|
||||||
case SCC_LIR_OR:
|
[SCC_LIR_BR] = "br",
|
||||||
return "or";
|
[SCC_LIR_JMP] = "jmp",
|
||||||
case SCC_LIR_XOR:
|
[SCC_LIR_JMP_INDIRECT] = "jmp.indirect",
|
||||||
return "xor";
|
[SCC_LIR_CALL] = "call",
|
||||||
case SCC_LIR_SHL:
|
[SCC_LIR_CALL_INDIRECT] = "call.indirect",
|
||||||
return "shl";
|
[SCC_LIR_RET] = "ret",
|
||||||
case SCC_LIR_SHR:
|
[SCC_LIR_PARALLEL_COPY] = "parallel_copy",
|
||||||
return "shr";
|
[SCC_LIR_VA_START] = "va_start",
|
||||||
case SCC_LIR_SAR:
|
[SCC_LIR_VA_ARG] = "va_arg",
|
||||||
return "sar";
|
[SCC_LIR_VA_END] = "va_end",
|
||||||
case SCC_LIR_NEG:
|
[SCC_LIR_VA_COPY] = "va_copy",
|
||||||
return "neg";
|
[SCC_LIR_ALLOCA] = "alloca",
|
||||||
case SCC_LIR_NOT:
|
[SCC_LIR_EXTEND] = "extend",
|
||||||
return "not";
|
[SCC_LIR_MEMCPY] = "memcpy",
|
||||||
case SCC_LIR_FADD:
|
[SCC_LIR_MEMSET] = "memset",
|
||||||
return "fadd";
|
[SCC_LIR_NOP] = "nop",
|
||||||
case SCC_LIR_FSUB:
|
};
|
||||||
return "fsub";
|
return op_names[op];
|
||||||
case SCC_LIR_FMUL:
|
|
||||||
return "fmul";
|
|
||||||
case SCC_LIR_FDIV:
|
|
||||||
return "fdiv";
|
|
||||||
case SCC_LIR_FNEG:
|
|
||||||
return "fneg";
|
|
||||||
case SCC_LIR_FCVT:
|
|
||||||
return "fcvt";
|
|
||||||
case SCC_LIR_CMP:
|
|
||||||
return "cmp";
|
|
||||||
case SCC_LIR_BR:
|
|
||||||
return "br";
|
|
||||||
case SCC_LIR_JMP:
|
|
||||||
return "jmp";
|
|
||||||
case SCC_LIR_JMP_INDIRECT:
|
|
||||||
return "jmp.indirect";
|
|
||||||
case SCC_LIR_CALL:
|
|
||||||
return "call";
|
|
||||||
case SCC_LIR_CALL_INDIRECT:
|
|
||||||
return "call.indirect";
|
|
||||||
case SCC_LIR_RET:
|
|
||||||
return "ret";
|
|
||||||
case SCC_LIR_PARALLEL_COPY:
|
|
||||||
return "parallel_copy";
|
|
||||||
case SCC_LIR_VA_START:
|
|
||||||
return "va_start";
|
|
||||||
case SCC_LIR_VA_ARG:
|
|
||||||
return "va_arg";
|
|
||||||
case SCC_LIR_VA_END:
|
|
||||||
return "va_end";
|
|
||||||
case SCC_LIR_VA_COPY:
|
|
||||||
return "va_copy";
|
|
||||||
case SCC_LIR_ALLOCA:
|
|
||||||
return "alloca";
|
|
||||||
|
|
||||||
case SCC_LIR_MEMCPY:
|
|
||||||
return "memcpy";
|
|
||||||
case SCC_LIR_MEMSET:
|
|
||||||
return "memset";
|
|
||||||
case SCC_LIR_NOP:
|
|
||||||
return "nop";
|
|
||||||
default:
|
|
||||||
return "???";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *cond_to_string(scc_lir_cond_t cond) {
|
static const char *cond_to_string(scc_lir_cond_t cond) {
|
||||||
switch (cond) {
|
static const char *names[] = {
|
||||||
case SCC_LIR_COND_EQ:
|
[SCC_LIR_COND_EQ] = "eq", [SCC_LIR_COND_NE] = "ne",
|
||||||
return "eq";
|
[SCC_LIR_COND_SLT] = "slt", [SCC_LIR_COND_SLE] = "sle",
|
||||||
case SCC_LIR_COND_NE:
|
[SCC_LIR_COND_SGT] = "sgt", [SCC_LIR_COND_SGE] = "sge",
|
||||||
return "ne";
|
[SCC_LIR_COND_ULT] = "ult", [SCC_LIR_COND_ULE] = "ule",
|
||||||
case SCC_LIR_COND_SLT:
|
[SCC_LIR_COND_UGT] = "ugt", [SCC_LIR_COND_UGE] = "uge",
|
||||||
return "slt";
|
[SCC_LIR_COND_FEQ] = "feq", [SCC_LIR_COND_FNE] = "fne",
|
||||||
case SCC_LIR_COND_SLE:
|
[SCC_LIR_COND_FLT] = "flt", [SCC_LIR_COND_FLE] = "fle",
|
||||||
return "sle";
|
[SCC_LIR_COND_FGT] = "fgt", [SCC_LIR_COND_FGE] = "fge",
|
||||||
case SCC_LIR_COND_SGT:
|
};
|
||||||
return "sgt";
|
return names[cond];
|
||||||
case SCC_LIR_COND_SGE:
|
|
||||||
return "sge";
|
|
||||||
case SCC_LIR_COND_ULT:
|
|
||||||
return "ult";
|
|
||||||
case SCC_LIR_COND_ULE:
|
|
||||||
return "ule";
|
|
||||||
case SCC_LIR_COND_UGT:
|
|
||||||
return "ugt";
|
|
||||||
case SCC_LIR_COND_UGE:
|
|
||||||
return "uge";
|
|
||||||
case SCC_LIR_COND_FEQ:
|
|
||||||
return "feq";
|
|
||||||
case SCC_LIR_COND_FNE:
|
|
||||||
return "fne";
|
|
||||||
case SCC_LIR_COND_FLT:
|
|
||||||
return "flt";
|
|
||||||
case SCC_LIR_COND_FLE:
|
|
||||||
return "fle";
|
|
||||||
case SCC_LIR_COND_FGT:
|
|
||||||
return "fgt";
|
|
||||||
case SCC_LIR_COND_FGE:
|
|
||||||
return "fge";
|
|
||||||
default:
|
|
||||||
return "???";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_operand(scc_lir_dump_ctx_t *ctx, const scc_lir_val_t *op) {
|
static void dump_operand(scc_lir_dump_ctx_t *ctx, const scc_lir_val_t *op) {
|
||||||
@@ -150,9 +81,6 @@ static void dump_operand(scc_lir_dump_ctx_t *ctx, const scc_lir_val_t *op) {
|
|||||||
case SCC_LIR_INSTR_KIND_VREG:
|
case SCC_LIR_INSTR_KIND_VREG:
|
||||||
scc_tree_dump_append_fmt(td, "%%%u", op->data.reg);
|
scc_tree_dump_append_fmt(td, "%%%u", op->data.reg);
|
||||||
break;
|
break;
|
||||||
// case SCC_LIR_INSTR_KIND_PREG:
|
|
||||||
// scc_tree_dump_append_fmt(td, "Phy%u", op->data.reg);
|
|
||||||
// break;
|
|
||||||
case SCC_LIR_INSTR_KIND_IMM:
|
case SCC_LIR_INSTR_KIND_IMM:
|
||||||
// TODO hack ap
|
// TODO hack ap
|
||||||
scc_tree_dump_append_fmt(td, "%lld", op->data.imm.data.digit);
|
scc_tree_dump_append_fmt(td, "%lld", op->data.imm.data.digit);
|
||||||
@@ -241,6 +169,26 @@ void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins) {
|
|||||||
ins->metadata.alloca.align_bytes);
|
ins->metadata.alloca.align_bytes);
|
||||||
dump_operand(ctx, &ins->to);
|
dump_operand(ctx, &ins->to);
|
||||||
break;
|
break;
|
||||||
|
case SCC_LIR_EXTEND: {
|
||||||
|
const char *ext_name = "";
|
||||||
|
switch (ins->ext) {
|
||||||
|
case SCC_LIR_EXT_ZEXT:
|
||||||
|
ext_name = "zext";
|
||||||
|
break;
|
||||||
|
case SCC_LIR_EXT_SEXT:
|
||||||
|
ext_name = "sext";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ext_name = "ext";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
scc_tree_dump_append_fmt(td, "%s(%d<-%d) ", ext_name, ins->size * 8,
|
||||||
|
ins->metadata.extend.from_size * 8);
|
||||||
|
dump_operand(ctx, &ins->to);
|
||||||
|
scc_tree_dump_append(td, " <- ");
|
||||||
|
dump_operand(ctx, &ins->arg0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
// case SCC_LIR_STORE_ADDR:
|
// case SCC_LIR_STORE_ADDR:
|
||||||
case SCC_LIR_STORE:
|
case SCC_LIR_STORE:
|
||||||
dump_operand(ctx, &ins->arg0);
|
dump_operand(ctx, &ins->arg0);
|
||||||
|
|||||||
@@ -101,40 +101,6 @@ scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, scc_x86_iform_t opcode,
|
|||||||
out->x86_instr.src_loc = pos;
|
out->x86_instr.src_loc = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline scc_x86_iform_t
|
|
||||||
scc_mir_x86_mov_reg_mem(scc_x86_operand_value_t op0,
|
|
||||||
scc_x86_operand_value_t op1) {
|
|
||||||
Assert(op0.size == op1.size);
|
|
||||||
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_MEM);
|
|
||||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_MEMB
|
|
||||||
: SCC_X86_IFORM_MOV_GPRV_MEMV;
|
|
||||||
}
|
|
||||||
static inline scc_x86_iform_t
|
|
||||||
scc_mir_x86_mov_mem_reg(scc_x86_operand_value_t op0,
|
|
||||||
scc_x86_operand_value_t op1) {
|
|
||||||
Assert(op0.size == op1.size);
|
|
||||||
Assert(op0.kind == SCC_X86_OPR_MEM && op1.kind == SCC_X86_OPR_REG);
|
|
||||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_MEMB_GPR8
|
|
||||||
: SCC_X86_IFORM_MOV_MEMV_GPRV;
|
|
||||||
}
|
|
||||||
static inline scc_x86_iform_t
|
|
||||||
scc_mir_x86_mov_reg_reg(scc_x86_operand_value_t op0,
|
|
||||||
scc_x86_operand_value_t op1) {
|
|
||||||
Assert(op0.size == op1.size);
|
|
||||||
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_REG);
|
|
||||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_GPR8_8A
|
|
||||||
: SCC_X86_IFORM_MOV_GPRV_GPRV_8B;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline scc_x86_iform_t
|
|
||||||
scc_mir_x86_mov_reg_imm(scc_x86_operand_value_t op0,
|
|
||||||
scc_x86_operand_value_t op1) {
|
|
||||||
Assert(op0.size == op1.size);
|
|
||||||
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_IMM);
|
|
||||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_IMMB_B0
|
|
||||||
: SCC_X86_IFORM_MOV_GPRV_IMMV;
|
|
||||||
}
|
|
||||||
|
|
||||||
void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
|
void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
|
||||||
scc_x86_operand_value_t dst,
|
scc_x86_operand_value_t dst,
|
||||||
scc_x86_operand_value_t src);
|
scc_x86_operand_value_t src);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ typedef struct scc_mir_stack_slot {
|
|||||||
int size; // 通常是 8 字节 (指针大小)
|
int size; // 通常是 8 字节 (指针大小)
|
||||||
int alignment; // 对齐要求
|
int alignment; // 对齐要求
|
||||||
int offset; // 相对于 RSP 的偏移 (最终确定)
|
int offset; // 相对于 RSP 的偏移 (最终确定)
|
||||||
|
int arg_idx; // == 0 means local slot, > 0 means argument slot
|
||||||
} scc_mir_stack_slot_t;
|
} scc_mir_stack_slot_t;
|
||||||
typedef SCC_VEC(scc_mir_stack_slot_t) scc_mir_stack_slot_vec_t;
|
typedef SCC_VEC(scc_mir_stack_slot_t) scc_mir_stack_slot_vec_t;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering);
|
void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering);
|
||||||
void scc_win_pc_x64_reg_alloc_fill(scc_reg_alloc_op_t *ops);
|
void scc_win_pc_x64_reg_alloc_fill(scc_reg_alloc_op_t *ops);
|
||||||
void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx);
|
void scc_win_pc_x64_frame_layout_init(scc_frame_layout_t *ctx);
|
||||||
void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx);
|
void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -47,9 +47,14 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_func_t *func,
|
|||||||
if (slot == nullptr) {
|
if (slot == nullptr) {
|
||||||
scc_tree_dump_append_fmt(td, "[slot:%d<null>]", slot_id);
|
scc_tree_dump_append_fmt(td, "[slot:%d<null>]", slot_id);
|
||||||
} else {
|
} else {
|
||||||
scc_tree_dump_append_fmt(td, "[slot:%d(of=%d,sz=%d,al=%d)]",
|
if (slot->arg_idx > 0) {
|
||||||
slot_id, slot->offset, slot->size,
|
scc_tree_dump_append_fmt(td, "[slot:arg%d]",
|
||||||
slot->alignment);
|
slot->arg_idx);
|
||||||
|
} else {
|
||||||
|
scc_tree_dump_append_fmt(
|
||||||
|
td, "[slot:%d(of=%d,sz=%d,al=%d)]", slot_id,
|
||||||
|
slot->offset, slot->size, slot->alignment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scc_tree_dump_append(td, "(");
|
scc_tree_dump_append(td, "(");
|
||||||
@@ -137,29 +142,6 @@ scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
|||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
static scc_x86_operand_value_t build_mem_op(scc_x86_64_isel_t *isel,
|
|
||||||
scc_x86_operand_value_t base,
|
|
||||||
scc_x86_operand_value_t index,
|
|
||||||
int scale, i64 offset) {
|
|
||||||
(void)isel;
|
|
||||||
scc_x86_operand_value_t mem_op;
|
|
||||||
mem_op.kind = SCC_X86_OPR_MEM;
|
|
||||||
// base 必须为寄存器
|
|
||||||
Assert(base.kind == SCC_X86_OPR_REG);
|
|
||||||
mem_op.mem.base = base.reg;
|
|
||||||
// index 可选
|
|
||||||
if (index.kind == SCC_X86_OPR_REG) {
|
|
||||||
mem_op.mem.index = index.reg;
|
|
||||||
mem_op.mem.scale = scale;
|
|
||||||
} else {
|
|
||||||
mem_op.mem.index = SCC_X86_REG_INVALID;
|
|
||||||
mem_op.mem.scale = 1;
|
|
||||||
}
|
|
||||||
mem_op.mem.disp.displacement = offset;
|
|
||||||
mem_op.mem.disp.displacement_bits = 0;
|
|
||||||
return mem_op;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 虚拟临时寄存器分配(简单递增)
|
// 虚拟临时寄存器分配(简单递增)
|
||||||
static scc_x86_operand_value_t new_vreg_temp(scc_x86_64_isel_t *isel,
|
static scc_x86_operand_value_t new_vreg_temp(scc_x86_64_isel_t *isel,
|
||||||
int size) {
|
int size) {
|
||||||
@@ -247,20 +229,21 @@ void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst_reg,
|
|||||||
|
|
||||||
void scc_x86_emit_load(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
void scc_x86_emit_load(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
||||||
scc_x86_operand_value_t src) {
|
scc_x86_operand_value_t src) {
|
||||||
|
scc_x86_operand_value_t tmp_reg = dst;
|
||||||
if (dst.kind != SCC_X86_OPR_REG) {
|
if (dst.kind != SCC_X86_OPR_REG) {
|
||||||
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, dst.size);
|
tmp_reg = new_vreg_temp(isel, src.size);
|
||||||
scc_x86_emit_move(isel, tmp_reg, dst);
|
}
|
||||||
dst = tmp_reg;
|
scc_x86_emit_load_to_vec(&isel->instrs, tmp_reg, src);
|
||||||
|
if (dst.kind != SCC_X86_OPR_REG) {
|
||||||
|
scc_x86_emit_move(isel, dst, tmp_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_x86_emit_load_to_vec(&isel->instrs, dst, src);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void scc_x86_emit_store(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
void scc_x86_emit_store(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
||||||
scc_x86_operand_value_t src) {
|
scc_x86_operand_value_t src) {
|
||||||
if (src.kind != SCC_X86_OPR_REG) {
|
if (src.kind == SCC_X86_OPR_MEM) {
|
||||||
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, src.size);
|
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, src.size);
|
||||||
scc_x86_emit_move(isel, tmp_reg, src);
|
scc_x86_emit_load(isel, tmp_reg, src);
|
||||||
src = tmp_reg;
|
src = tmp_reg;
|
||||||
}
|
}
|
||||||
scc_x86_emit_store_to_vec(&isel->instrs, dst, src);
|
scc_x86_emit_store_to_vec(&isel->instrs, dst, src);
|
||||||
@@ -279,52 +262,55 @@ static void emit_load_addr(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
|||||||
|
|
||||||
// ---- 处理 base ----
|
// ---- 处理 base ----
|
||||||
scc_x86_operand_value_t base_reg = base;
|
scc_x86_operand_value_t base_reg = base;
|
||||||
if (base.kind != SCC_X86_OPR_REG) {
|
switch (base.kind) {
|
||||||
base_reg = new_vreg_temp(isel, size);
|
case SCC_X86_OPR_REG: {
|
||||||
|
base_reg = base;
|
||||||
|
} break;
|
||||||
|
case SCC_X86_OPR_RELOC: {
|
||||||
|
Assert(base.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL);
|
||||||
|
base_reg = new_vreg_temp(isel, 8);
|
||||||
scc_x86_emit_move(isel, base_reg, base);
|
scc_x86_emit_move(isel, base_reg, base);
|
||||||
|
} break;
|
||||||
|
case SCC_X86_OPR_MEM: {
|
||||||
|
base_reg = new_vreg_temp(isel, 8);
|
||||||
|
scc_x86_emit_move(isel, base_reg, base);
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
Panic("Unsupported base kind %d in load_addr", base.kind);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- 处理 index * scale ----
|
scc_x86_operand_value_t index_reg = index;
|
||||||
scc_x86_operand_value_t scaled_index = index;
|
switch (index.kind) {
|
||||||
Assert(index.kind != SCC_X86_OPR_NONE);
|
case SCC_X86_OPR_REG: {
|
||||||
// 确保 index 在寄存器中
|
index_reg = index;
|
||||||
if (index.kind != SCC_X86_OPR_REG) {
|
} break;
|
||||||
scc_x86_operand_value_t index_tmp = new_vreg_temp(isel, index.size);
|
case SCC_X86_OPR_RELOC: {
|
||||||
scc_x86_emit_move(isel, index_tmp, index);
|
Assert(index.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL);
|
||||||
index = index_tmp;
|
index_reg = new_vreg_temp(isel, 8);
|
||||||
|
scc_x86_emit_move(isel, index_reg, index);
|
||||||
|
} break;
|
||||||
|
case SCC_X86_OPR_MEM: {
|
||||||
|
index_reg = new_vreg_temp(isel, 8);
|
||||||
|
scc_x86_emit_move(isel, index_reg, index);
|
||||||
|
} break;
|
||||||
|
case SCC_X86_OPR_IMM: {
|
||||||
|
index_reg = new_vreg_temp(isel, index.size);
|
||||||
|
scc_x86_emit_move(isel, index_reg, index);
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
Panic("Unsupported index kind %d in load_addr", base.kind);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- 计算 base + scaled_index ----
|
scc_x86_operand_value_t mem_op =
|
||||||
scc_x86_operand_value_t sum = base_reg;
|
scc_x86_op_mem((scc_x86_mem_t){.base = base_reg.reg,
|
||||||
if (base_reg.kind == SCC_X86_OPR_REG &&
|
.index = index_reg.reg,
|
||||||
scaled_index.kind == SCC_X86_OPR_REG) {
|
.scale = scale,
|
||||||
if (dst.reg != base_reg.reg) {
|
.disp.displacement = offset,
|
||||||
scc_x86_emit_move(isel, dst, base_reg);
|
.disp.displacement_bits = 8},
|
||||||
sum = dst;
|
size);
|
||||||
}
|
|
||||||
add_instr_2(isel, SCC_X86_IFORM_ADD_GPRV_GPRV_03, sum, scaled_index);
|
|
||||||
} else if (base_reg.kind == SCC_X86_OPR_REG) {
|
|
||||||
if (dst.reg != base_reg.reg)
|
|
||||||
scc_x86_emit_move(isel, dst, base_reg);
|
|
||||||
sum = dst;
|
|
||||||
} else if (scaled_index.kind == SCC_X86_OPR_REG) {
|
|
||||||
scc_x86_emit_move(isel, dst, scaled_index);
|
|
||||||
sum = dst;
|
|
||||||
} else {
|
|
||||||
// base 和 index 都无效 => 结果为 0
|
|
||||||
scc_x86_emit_move(isel, dst, scc_x86_op_imm(0, size));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- 加上 offset ----
|
|
||||||
if (offset != 0) {
|
|
||||||
scc_x86_operand_value_t mem_op = build_mem_op(
|
|
||||||
isel, sum, (scc_x86_operand_value_t){.kind = SCC_X86_OPR_NONE}, 1,
|
|
||||||
offset);
|
|
||||||
scc_x86_emit_move(isel, dst, mem_op);
|
scc_x86_emit_move(isel, dst, mem_op);
|
||||||
} else if (sum.reg != dst.reg) {
|
|
||||||
scc_x86_emit_move(isel, dst, sum);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||||
@@ -455,8 +441,9 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
|||||||
case SCC_LIR_CMP: {
|
case SCC_LIR_CMP: {
|
||||||
Assert(src0.size == src1.size);
|
Assert(src0.size == src1.size);
|
||||||
if (scc_x86_op_is_vreg(&src0) && src1.kind == SCC_X86_OPR_IMM)
|
if (scc_x86_op_is_vreg(&src0) && src1.kind == SCC_X86_OPR_IMM)
|
||||||
|
// SCC_X86_IFORM_CMP_GPR8_IMMB_82R7 历史遗留指令在amd64中已不再使用
|
||||||
add_instr_2(isel,
|
add_instr_2(isel,
|
||||||
src0.size == 1 ? SCC_X86_IFORM_CMP_GPR8_IMMB_82R7
|
src0.size == 1 ? SCC_X86_IFORM_CMP_GPR8_IMMB_80R7
|
||||||
: SCC_X86_IFORM_CMP_GPRV_IMMZ,
|
: SCC_X86_IFORM_CMP_GPRV_IMMZ,
|
||||||
src0, src1);
|
src0, src1);
|
||||||
else if (scc_x86_op_is_vreg(&src0) && scc_x86_op_is_vreg(&src1))
|
else if (scc_x86_op_is_vreg(&src0) && scc_x86_op_is_vreg(&src1))
|
||||||
@@ -519,6 +506,44 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- 类型扩展 ---- */
|
||||||
|
case SCC_LIR_EXTEND: {
|
||||||
|
int from_size = instr->metadata.extend.from_size;
|
||||||
|
scc_x86_operand_value_t ext_src =
|
||||||
|
scc_x86_lir_val_to_mir_op(isel, &instr->arg0, from_size);
|
||||||
|
|
||||||
|
if (instr->ext == SCC_LIR_EXT_ZEXT) {
|
||||||
|
if (from_size == 4) {
|
||||||
|
// 32→64: x86-64 写32位寄存器自动零扩展到64位
|
||||||
|
scc_x86_emit_move(isel, dst, ext_src);
|
||||||
|
} else {
|
||||||
|
scc_x86_iform_t iform = (from_size == 1)
|
||||||
|
? SCC_X86_IFORM_MOVZX_GPRV_GPR8
|
||||||
|
: SCC_X86_IFORM_MOVZX_GPRV_GPR16;
|
||||||
|
add_instr_2(isel, iform, dst, ext_src);
|
||||||
|
}
|
||||||
|
} else if (instr->ext == SCC_LIR_EXT_SEXT) {
|
||||||
|
scc_x86_iform_t iform;
|
||||||
|
switch (from_size) {
|
||||||
|
case 1:
|
||||||
|
iform = SCC_X86_IFORM_MOVSX_GPRV_GPR8;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
iform = SCC_X86_IFORM_MOVSX_GPRV_GPR16;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
iform = SCC_X86_IFORM_MOVSXD_GPRV_GPRZ;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
add_instr_2(isel, iform, dst, ext_src);
|
||||||
|
} else {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- 其他(占位) ---- */
|
/* ---- 其他(占位) ---- */
|
||||||
case SCC_LIR_NOP:
|
case SCC_LIR_NOP:
|
||||||
add_instr_0(isel, SCC_X86_IFORM_NOP_90);
|
add_instr_0(isel, SCC_X86_IFORM_NOP_90);
|
||||||
@@ -575,11 +600,10 @@ static void sel_func(const scc_lir_module_t *lir_module,
|
|||||||
scc_cfg_module_unsafe_get_bblock(&lir_module->cfg_module, id);
|
scc_cfg_module_unsafe_get_bblock(&lir_module->cfg_module, id);
|
||||||
scc_lir_instr_vec_t *instrs = SCC_LIR_BBLOCK_VALUES(bb);
|
scc_lir_instr_vec_t *instrs = SCC_LIR_BBLOCK_VALUES(bb);
|
||||||
scc_vec_foreach(*instrs, i) {
|
scc_vec_foreach(*instrs, i) {
|
||||||
const scc_lir_instr_t *ins = &scc_vec_at(*instrs, i);
|
scc_lir_instr_t *ins = &scc_vec_at(*instrs, i);
|
||||||
// HACK BR size
|
// HACK BR size
|
||||||
if (ins->op == SCC_LIR_CMP && i + 1 < scc_vec_size(*instrs) &&
|
if (ins->op == SCC_LIR_BR) {
|
||||||
scc_vec_at(*instrs, i + 1).op == SCC_LIR_BR) {
|
ins->size = scc_vec_at(*instrs, i - 1).size;
|
||||||
scc_vec_at(*instrs, i + 1).size = ins->size;
|
|
||||||
}
|
}
|
||||||
sel_mir(isel, ins);
|
sel_mir(isel, ins);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,47 @@
|
|||||||
#include <arch/scc_x86_mir.h>
|
#include <arch/scc_x86_mir.h>
|
||||||
|
|
||||||
|
static inline scc_x86_iform_t
|
||||||
|
scc_mir_x86_mov_reg_mem(scc_x86_operand_value_t op0,
|
||||||
|
scc_x86_operand_value_t op1) {
|
||||||
|
Assert(op0.size == op1.size);
|
||||||
|
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_MEM);
|
||||||
|
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_MEMB
|
||||||
|
: SCC_X86_IFORM_MOV_GPRV_MEMV;
|
||||||
|
}
|
||||||
|
static inline scc_x86_iform_t
|
||||||
|
scc_mir_x86_mov_reg_reg(scc_x86_operand_value_t op0,
|
||||||
|
scc_x86_operand_value_t op1) {
|
||||||
|
Assert(op0.size == op1.size);
|
||||||
|
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_REG);
|
||||||
|
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_GPR8_8A
|
||||||
|
: SCC_X86_IFORM_MOV_GPRV_GPRV_8B;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline scc_x86_iform_t
|
||||||
|
scc_mir_x86_mov_reg_imm(scc_x86_operand_value_t op0,
|
||||||
|
scc_x86_operand_value_t op1) {
|
||||||
|
Assert(op0.size == op1.size);
|
||||||
|
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_IMM);
|
||||||
|
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_IMMB_B0
|
||||||
|
: SCC_X86_IFORM_MOV_GPRV_IMMV;
|
||||||
|
}
|
||||||
|
static inline scc_x86_iform_t
|
||||||
|
scc_mir_x86_mov_mem_reg(scc_x86_operand_value_t op0,
|
||||||
|
scc_x86_operand_value_t op1) {
|
||||||
|
Assert(op0.size == op1.size);
|
||||||
|
Assert(op0.kind == SCC_X86_OPR_MEM && op1.kind == SCC_X86_OPR_REG);
|
||||||
|
return op0.size == 1 ? SCC_X86_IFORM_MOV_MEMB_GPR8
|
||||||
|
: SCC_X86_IFORM_MOV_MEMV_GPRV;
|
||||||
|
}
|
||||||
|
static inline scc_x86_iform_t
|
||||||
|
scc_mir_x86_mov_mem_imm(scc_x86_operand_value_t op0,
|
||||||
|
scc_x86_operand_value_t op1) {
|
||||||
|
Assert(op0.size == op1.size);
|
||||||
|
Assert(op0.kind == SCC_X86_OPR_MEM && op1.kind == SCC_X86_OPR_IMM);
|
||||||
|
return op0.size == 1 ? SCC_X86_IFORM_MOV_MEMB_IMMB
|
||||||
|
: SCC_X86_IFORM_MOV_MEMV_IMMZ;
|
||||||
|
}
|
||||||
|
|
||||||
void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
|
void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
|
||||||
scc_x86_operand_value_t dst,
|
scc_x86_operand_value_t dst,
|
||||||
scc_x86_operand_value_t src) {
|
scc_x86_operand_value_t src) {
|
||||||
@@ -7,22 +49,36 @@ void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
|
|||||||
LOG_WARN("Mismatched register sizes for move %d != %d", dst.size,
|
LOG_WARN("Mismatched register sizes for move %d != %d", dst.size,
|
||||||
src.size);
|
src.size);
|
||||||
}
|
}
|
||||||
Assert(dst.kind == SCC_X86_OPR_REG);
|
|
||||||
scc_mir_x86_instr_t ins;
|
scc_mir_x86_instr_t ins;
|
||||||
|
if (dst.kind == SCC_X86_OPR_REG) {
|
||||||
if (src.kind == SCC_X86_OPR_REG) {
|
if (src.kind == SCC_X86_OPR_REG) {
|
||||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_reg(dst, src), dst, src,
|
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_reg(dst, src), dst,
|
||||||
scc_pos_create());
|
src, scc_pos_create());
|
||||||
} else if (src.kind == SCC_X86_OPR_IMM) {
|
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_imm(dst, src), dst, src,
|
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_imm(dst, src), dst,
|
||||||
scc_pos_create());
|
src, scc_pos_create());
|
||||||
} else if (src.kind == SCC_X86_OPR_MEM ||
|
} else if (src.kind == SCC_X86_OPR_MEM ||
|
||||||
(src.kind == SCC_X86_OPR_RELOC &&
|
(src.kind == SCC_X86_OPR_RELOC &&
|
||||||
src.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL)) {
|
src.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL)) {
|
||||||
|
Assert(dst.size == 8);
|
||||||
scc_mir_x86_instr_2(&ins, SCC_X86_IFORM_LEA_GPRV_AGEN, dst, src,
|
scc_mir_x86_instr_2(&ins, SCC_X86_IFORM_LEA_GPRV_AGEN, dst, src,
|
||||||
scc_pos_create());
|
scc_pos_create());
|
||||||
} else {
|
} else {
|
||||||
Panic("emit_move: unsupported src kind %d", src.kind);
|
Panic("emit_move: unsupported src kind %d", src.kind);
|
||||||
}
|
}
|
||||||
|
} else if (dst.kind == SCC_X86_OPR_MEM) {
|
||||||
|
if (src.kind == SCC_X86_OPR_IMM) {
|
||||||
|
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_imm(dst, src), dst,
|
||||||
|
src, scc_pos_create());
|
||||||
|
} else if (src.kind == SCC_X86_OPR_REG) {
|
||||||
|
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_reg(dst, src), dst,
|
||||||
|
src, scc_pos_create());
|
||||||
|
} else {
|
||||||
|
Panic("emit_move: unsupported src kind %d", src.kind);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Panic("emit_move: unsupported dst kind %d", dst.kind);
|
||||||
|
}
|
||||||
scc_vec_push(*vec, ins);
|
scc_vec_push(*vec, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +121,6 @@ void scc_x86_emit_store_to_vec(scc_mir_x86_instr_vec_t *vec,
|
|||||||
LOG_WARN("Mismatched sizes for store %d != %d", dst_addr.size,
|
LOG_WARN("Mismatched sizes for store %d != %d", dst_addr.size,
|
||||||
src.size);
|
src.size);
|
||||||
}
|
}
|
||||||
Assert(src.kind == SCC_X86_OPR_REG);
|
|
||||||
scc_x86_operand_value_t mem_op;
|
scc_x86_operand_value_t mem_op;
|
||||||
if (dst_addr.kind == SCC_X86_OPR_REG) {
|
if (dst_addr.kind == SCC_X86_OPR_REG) {
|
||||||
mem_op = (scc_x86_operand_value_t){
|
mem_op = (scc_x86_operand_value_t){
|
||||||
@@ -83,10 +138,17 @@ void scc_x86_emit_store_to_vec(scc_mir_x86_instr_vec_t *vec,
|
|||||||
} else if (dst_addr.kind == SCC_X86_OPR_MEM) {
|
} else if (dst_addr.kind == SCC_X86_OPR_MEM) {
|
||||||
mem_op = dst_addr;
|
mem_op = dst_addr;
|
||||||
} else {
|
} else {
|
||||||
Panic("emit_store: dst_addr must be REG or MEM");
|
Panic("emit_store: dst_addr kind not supported %d", dst_addr.kind);
|
||||||
}
|
}
|
||||||
scc_mir_x86_instr_t ins;
|
scc_mir_x86_instr_t ins;
|
||||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_reg(mem_op, src), mem_op, src,
|
if (src.kind == SCC_X86_OPR_REG) {
|
||||||
scc_pos_create());
|
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_reg(mem_op, src), mem_op,
|
||||||
|
src, scc_pos_create());
|
||||||
|
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||||
|
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_imm(mem_op, src), mem_op,
|
||||||
|
src, scc_pos_create());
|
||||||
|
} else {
|
||||||
|
Panic("unsupported src kind not supported %d", src.kind);
|
||||||
|
}
|
||||||
scc_vec_push(*vec, ins);
|
scc_vec_push(*vec, ins);
|
||||||
}
|
}
|
||||||
@@ -39,8 +39,11 @@ int scc_mir_vreg_map2slot(scc_mir_func_t *func, int vreg, int size, int align) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int new_slot = scc_vec_size(meta->stack_slots);
|
int new_slot = scc_vec_size(meta->stack_slots);
|
||||||
scc_mir_stack_slot_t s = {
|
scc_mir_stack_slot_t s = {.slot_id = new_slot,
|
||||||
.slot_id = new_slot, .size = size, .alignment = align, .offset = 0};
|
.size = size,
|
||||||
|
.alignment = align,
|
||||||
|
.offset = 0,
|
||||||
|
.arg_idx = 0};
|
||||||
scc_vec_push(meta->stack_slots, s);
|
scc_vec_push(meta->stack_slots, s);
|
||||||
scc_hashtable_set(&meta->vreg2physic, (void *)(usize)vreg,
|
scc_hashtable_set(&meta->vreg2physic, (void *)(usize)vreg,
|
||||||
(void *)(usize)new_slot);
|
(void *)(usize)new_slot);
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) {
|
|||||||
scc_vec_foreach(module->cfg_module.funcs, i) {
|
scc_vec_foreach(module->cfg_module.funcs, i) {
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
continue;
|
continue;
|
||||||
ctx->impl_fn(ctx, module, &scc_vec_at(module->cfg_module.funcs, i));
|
scc_mir_func_t *func = &scc_vec_at(module->cfg_module.funcs, i);
|
||||||
|
ctx->offset = SCC_MIR_FUNC_META(func)->frame_size;
|
||||||
|
ctx->impl_fn(ctx, module, func);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +71,7 @@ void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage) {
|
|||||||
// scc_x86_peephole_optimize(mir_module);
|
// scc_x86_peephole_optimize(mir_module);
|
||||||
|
|
||||||
scc_frame_layout_t frame_layout_ctx = {0};
|
scc_frame_layout_t frame_layout_ctx = {0};
|
||||||
scc_win_pc_x64_frame_alloc_init(&frame_layout_ctx);
|
scc_win_pc_x64_frame_layout_init(&frame_layout_ctx);
|
||||||
scc_frame_layout(&frame_layout_ctx, mir_module);
|
scc_frame_layout(&frame_layout_ctx, mir_module);
|
||||||
if (stage == SCC_MIR_STAGE_FRAME_LAYOUT) {
|
if (stage == SCC_MIR_STAGE_FRAME_LAYOUT) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -7,11 +7,13 @@
|
|||||||
|
|
||||||
static const int WIN64_STACK_ALIGN = 16;
|
static const int WIN64_STACK_ALIGN = 16;
|
||||||
|
|
||||||
static void frame_alloc_impl(scc_frame_layout_t *ctx,
|
static void frame_layout_impl(scc_frame_layout_t *ctx,
|
||||||
scc_mir_module_t *mir_module,
|
scc_mir_module_t *mir_module,
|
||||||
scc_mir_func_t *mir_func) {
|
scc_mir_func_t *mir_func) {
|
||||||
ctx->offset = 8;
|
ctx->offset += 8; // call return address frame
|
||||||
scc_mir_func_meta_t *func_meta = SCC_MIR_FUNC_META(mir_func);
|
scc_mir_func_meta_t *func_meta = SCC_MIR_FUNC_META(mir_func);
|
||||||
|
|
||||||
|
// Pass 1: 处理局部变量槽 (arg_idx == 0),从 RSP 向上分配偏移
|
||||||
scc_vec_foreach(mir_func->bblocks, i) {
|
scc_vec_foreach(mir_func->bblocks, i) {
|
||||||
scc_cfg_bblock_id_t id = scc_vec_at(mir_func->bblocks, i);
|
scc_cfg_bblock_id_t id = scc_vec_at(mir_func->bblocks, i);
|
||||||
scc_cfg_bblock_t *bb =
|
scc_cfg_bblock_t *bb =
|
||||||
@@ -25,16 +27,17 @@ static void frame_alloc_impl(scc_frame_layout_t *ctx,
|
|||||||
int slot_id = scc_x86_op_slot_id(op);
|
int slot_id = scc_x86_op_slot_id(op);
|
||||||
scc_mir_stack_slot_t *slot =
|
scc_mir_stack_slot_t *slot =
|
||||||
scc_mir_unsafe_slot(mir_func, slot_id);
|
scc_mir_unsafe_slot(mir_func, slot_id);
|
||||||
|
if (slot->arg_idx > 0)
|
||||||
|
continue; // 传入参数槽,Pass 2 处理
|
||||||
if (slot->offset == 0) {
|
if (slot->offset == 0) {
|
||||||
ctx->offset += slot->size;
|
|
||||||
slot->offset = ctx->offset;
|
slot->offset = ctx->offset;
|
||||||
|
ctx->offset += slot->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
*op = scc_x86_op_mem(
|
*op = scc_x86_op_mem(
|
||||||
(scc_x86_mem_t){
|
(scc_x86_mem_t){
|
||||||
.seg = SCC_X86_REG_INVALID,
|
.seg = SCC_X86_REG_INVALID,
|
||||||
.base = SCC_X86_REG_RSP,
|
.base = SCC_X86_REG_RSP,
|
||||||
.disp = {.displacement = -slot->offset},
|
.disp = {.displacement = slot->offset},
|
||||||
.index = SCC_X86_REG_INVALID,
|
.index = SCC_X86_REG_INVALID,
|
||||||
.scale = 1,
|
.scale = 1,
|
||||||
},
|
},
|
||||||
@@ -44,14 +47,50 @@ static void frame_alloc_impl(scc_frame_layout_t *ctx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_size = ctx->offset + 32; // shadow space
|
int total_size = ctx->offset;
|
||||||
ctx->offset =
|
ctx->offset =
|
||||||
(total_size + WIN64_STACK_ALIGN - 1) & ~(WIN64_STACK_ALIGN - 1);
|
(total_size + WIN64_STACK_ALIGN - 1) & ~(WIN64_STACK_ALIGN - 1);
|
||||||
func_meta->frame_size = ctx->offset;
|
func_meta->frame_size = ctx->offset;
|
||||||
|
|
||||||
|
// Pass 2: 处理传入参数槽 (arg_idx > 0)
|
||||||
|
// 在 Win64 布局中,栈上参数位于 return address + 8 + arg_idx * 8
|
||||||
|
// 即 RSP + frame_size + 8 + arg_idx * 8
|
||||||
|
scc_vec_foreach(mir_func->bblocks, i) {
|
||||||
|
scc_cfg_bblock_id_t id = scc_vec_at(mir_func->bblocks, i);
|
||||||
|
scc_cfg_bblock_t *bb =
|
||||||
|
scc_cfg_module_unsafe_get_bblock(&mir_module->cfg_module, id);
|
||||||
|
scc_mir_x86_instr_vec_t *instrs = SCC_MIR_X86_BBLOCK_INSTRS(bb);
|
||||||
|
scc_vec_foreach(*instrs, j) {
|
||||||
|
scc_mir_x86_instr_t *ins = &scc_vec_at(*instrs, j);
|
||||||
|
for (int k = 0; k < ins->x86_instr.num_operands; k++) {
|
||||||
|
scc_x86_operand_value_t *op = &ins->x86_instr.operands[k];
|
||||||
|
if (scc_x86_op_is_slot(op)) {
|
||||||
|
int slot_id = scc_x86_op_slot_id(op);
|
||||||
|
scc_mir_stack_slot_t *slot =
|
||||||
|
scc_mir_unsafe_slot(mir_func, slot_id);
|
||||||
|
if (slot->arg_idx == 0)
|
||||||
|
continue; // 局部变量槽,Pass 1 已处理
|
||||||
|
if (slot->offset == 0) {
|
||||||
|
slot->offset =
|
||||||
|
func_meta->frame_size + 8 + slot->arg_idx * 8;
|
||||||
|
}
|
||||||
|
*op = scc_x86_op_mem(
|
||||||
|
(scc_x86_mem_t){
|
||||||
|
.seg = SCC_X86_REG_INVALID,
|
||||||
|
.base = SCC_X86_REG_RSP,
|
||||||
|
.disp = {.displacement = slot->offset},
|
||||||
|
.index = SCC_X86_REG_INVALID,
|
||||||
|
.scale = 1,
|
||||||
|
},
|
||||||
|
op->size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx) {
|
void scc_win_pc_x64_frame_layout_init(scc_frame_layout_t *ctx) {
|
||||||
ctx->impl_fn = frame_alloc_impl;
|
ctx->impl_fn = frame_layout_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -136,6 +175,15 @@ static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
|
|||||||
scc_x86_64_isel_t *isel = userdata;
|
scc_x86_64_isel_t *isel = userdata;
|
||||||
|
|
||||||
u8 size = 8;
|
u8 size = 8;
|
||||||
|
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(isel->func);
|
||||||
|
int call_stack_size = instr->metadata.call.arg_count * 8;
|
||||||
|
if (meta->frame_size < call_stack_size) {
|
||||||
|
meta->frame_size = call_stack_size;
|
||||||
|
}
|
||||||
|
if (meta->frame_size < 32) {
|
||||||
|
meta->frame_size = 32; // Windows X64 shadow space
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = instr->metadata.call.arg_count - 1; i >= 0; i -= 1) {
|
for (int i = instr->metadata.call.arg_count - 1; i >= 0; i -= 1) {
|
||||||
scc_lir_val_t *args = &instr->metadata.call.args[i];
|
scc_lir_val_t *args = &instr->metadata.call.args[i];
|
||||||
switch (i) {
|
switch (i) {
|
||||||
@@ -156,10 +204,15 @@ static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
|
|||||||
scc_x86_lir_val_to_mir_op(isel, args, size));
|
scc_x86_lir_val_to_mir_op(isel, args, size));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
scc_x86_operand_value_t op =
|
scc_x86_emit_move(
|
||||||
scc_x86_lir_val_to_mir_op(isel, args, size);
|
isel,
|
||||||
TODO();
|
scc_x86_op_mem((scc_x86_mem_t){.base = SCC_X86_REG_RSP,
|
||||||
add_instr_1(isel, SCC_X86_ICLASS_PUSH, op);
|
.index = SCC_X86_REG_INVALID,
|
||||||
|
.scale = 1,
|
||||||
|
.disp.displacement = i * 8,
|
||||||
|
.disp.displacement_bits = 8},
|
||||||
|
size),
|
||||||
|
scc_x86_lir_val_to_mir_op(isel, args, size));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,14 +229,34 @@ static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
|
|||||||
Panic("unhandled opcode");
|
Panic("unhandled opcode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ret_size = instr->size;
|
||||||
scc_x86_operand_value_t ret_reg =
|
scc_x86_operand_value_t ret_reg =
|
||||||
scc_x86_lir_val_to_mir_op(isel, &instr->to, size);
|
scc_x86_lir_val_to_mir_op(isel, &instr->to, ret_size);
|
||||||
if (ret_reg.kind != SCC_X86_OPR_NONE) {
|
if (ret_reg.kind != SCC_X86_OPR_NONE && ret_size != 0) {
|
||||||
scc_x86_emit_move(isel, ret_reg,
|
scc_x86_emit_move(isel, ret_reg,
|
||||||
scc_x86_op_preg(SCC_X86_REG_RAX, size));
|
scc_x86_op_preg(SCC_X86_REG_RAX, ret_size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查找或创建传入参数的栈槽 (arg_idx > 0 表示栈上传入参数)
|
||||||
|
static int get_or_create_arg_slot(scc_mir_func_t *func, int arg_idx, int size) {
|
||||||
|
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||||
|
scc_vec_foreach(meta->stack_slots, i) {
|
||||||
|
scc_mir_stack_slot_t *s = &scc_vec_at(meta->stack_slots, i);
|
||||||
|
if (s->arg_idx == arg_idx)
|
||||||
|
return s->slot_id;
|
||||||
|
}
|
||||||
|
int slot_id = (int)scc_vec_size(meta->stack_slots);
|
||||||
|
scc_vec_push(meta->stack_slots, ((scc_mir_stack_slot_t){
|
||||||
|
.slot_id = slot_id,
|
||||||
|
.size = size,
|
||||||
|
.alignment = 8,
|
||||||
|
.offset = 0,
|
||||||
|
.arg_idx = arg_idx,
|
||||||
|
}));
|
||||||
|
return slot_id;
|
||||||
|
}
|
||||||
|
|
||||||
static void lower_param(void *userdata, const scc_lir_val_t *val,
|
static void lower_param(void *userdata, const scc_lir_val_t *val,
|
||||||
void *out_op) {
|
void *out_op) {
|
||||||
scc_x86_operand_value_t *out = out_op;
|
scc_x86_operand_value_t *out = out_op;
|
||||||
@@ -202,10 +275,13 @@ static void lower_param(void *userdata, const scc_lir_val_t *val,
|
|||||||
case 3:
|
case 3:
|
||||||
*out = scc_x86_op_preg(SCC_X86_REG_R9, size);
|
*out = scc_x86_op_preg(SCC_X86_REG_R9, size);
|
||||||
break;
|
break;
|
||||||
default:
|
default: {
|
||||||
*out = scc_x86_op_slot(-val->data.arg, size);
|
scc_x86_64_isel_t *isel = userdata;
|
||||||
|
int slot_id = get_or_create_arg_slot(isel->func, val->data.arg, size);
|
||||||
|
*out = scc_x86_op_slot(slot_id, size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lower_ret(void *userdata, const scc_lir_instr_t *instr) {
|
static void lower_ret(void *userdata, const scc_lir_instr_t *instr) {
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ static void emit_mir_module(sccf_builder_t *builder, scc_mcode_t *mcode,
|
|||||||
scc_hashtable_usize_init(&bblock_offset);
|
scc_hashtable_usize_init(&bblock_offset);
|
||||||
scc_reloc_vec_t relocs;
|
scc_reloc_vec_t relocs;
|
||||||
scc_vec_init(relocs);
|
scc_vec_init(relocs);
|
||||||
scc_vec_foreach(func->bblocks, i) {
|
scc_vec_foreach(func->bblocks, j) {
|
||||||
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
|
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, j);
|
||||||
const scc_cfg_bblock_t *bb =
|
const scc_cfg_bblock_t *bb =
|
||||||
scc_cfg_module_unsafe_get_bblock(&mir_module->cfg_module, id);
|
scc_cfg_module_unsafe_get_bblock(&mir_module->cfg_module, id);
|
||||||
|
|
||||||
@@ -72,20 +72,21 @@ static void emit_mir_module(sccf_builder_t *builder, scc_mcode_t *mcode,
|
|||||||
(void *)scc_mcode_size(mcode));
|
(void *)scc_mcode_size(mcode));
|
||||||
|
|
||||||
scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES_PTR(bb);
|
scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES_PTR(bb);
|
||||||
scc_vec_foreach(*instrs, i) {
|
scc_vec_foreach(*instrs, k) {
|
||||||
const scc_mir_instr_t *ins =
|
const scc_mir_instr_t *ins =
|
||||||
scc_vec_sized_at_ptr(*instrs, mir_module->instr_size, i);
|
scc_vec_sized_at_ptr(*instrs, mir_module->instr_size, k);
|
||||||
// FIXME reloc symbol needed
|
// FIXME reloc symbol needed
|
||||||
scc_ir2mcode_emit_instr(mcode, &relocs, ins);
|
scc_ir2mcode_emit_instr(mcode, &relocs, ins);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_vec_foreach(relocs, i) {
|
scc_vec_foreach(relocs, j) {
|
||||||
scc_reloc_t *reloc = &scc_vec_at(relocs, i);
|
scc_reloc_t *reloc = &scc_vec_at(relocs, j);
|
||||||
if (reloc->target_kind == SCC_RELOC_TARGET_BBLOCK) {
|
if (reloc->target_kind == SCC_RELOC_TARGET_BBLOCK) {
|
||||||
reloc->target_kind = SCC_RELOC_TARGET_NONE;
|
reloc->target_kind = SCC_RELOC_TARGET_NONE;
|
||||||
usize addr = (usize)scc_hashtable_get(
|
usize addr = (usize)scc_hashtable_get(
|
||||||
&bblock_offset, (void *)(usize)reloc->bblock_id);
|
&bblock_offset, (void *)(usize)reloc->bblock_id);
|
||||||
|
Assert(addr != 0);
|
||||||
scc_ir2mcode_patch(mcode, reloc, addr);
|
scc_ir2mcode_patch(mcode, reloc, addr);
|
||||||
} else if (reloc->target_kind == SCC_RELOC_TARGET_SYMBOL) {
|
} else if (reloc->target_kind == SCC_RELOC_TARGET_SYMBOL) {
|
||||||
usize sym_idx =
|
usize sym_idx =
|
||||||
|
|||||||
@@ -120,11 +120,11 @@ static inline int scc_x86_patch_imm0_ex(scc_mcode_t *mcode, usize offset,
|
|||||||
|
|
||||||
static inline void scc_x86_patch(scc_mcode_t *mcode,
|
static inline void scc_x86_patch(scc_mcode_t *mcode,
|
||||||
scc_x86_patch_type_t patch_type, u64 offset,
|
scc_x86_patch_type_t patch_type, u64 offset,
|
||||||
i64 value) {
|
u64 value) {
|
||||||
switch (patch_type) {
|
switch (patch_type) {
|
||||||
case SCC_X86_PATCH_PC32:
|
case SCC_X86_PATCH_PC32:
|
||||||
scc_x86_patch_brdisp(mcode, offset - 4,
|
i32 rel = value - offset;
|
||||||
scc_x86_op_relbr(value - offset));
|
scc_x86_patch_brdisp(mcode, offset - 4, scc_x86_op_relbr(rel));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TODO();
|
TODO();
|
||||||
|
|||||||
@@ -218,9 +218,13 @@ static int scale_to_enc(uint8_t scale) {
|
|||||||
|
|
||||||
/* 修正:位移大小只由数值范围决定,与基址寄存器无关 */
|
/* 修正:位移大小只由数值范围决定,与基址寄存器无关 */
|
||||||
static int disp_size(int32_t disp, scc_x86_reg_t base) {
|
static int disp_size(int32_t disp, scc_x86_reg_t base) {
|
||||||
(void)base;
|
if (disp == 0) {
|
||||||
if (disp == 0)
|
/* RBP/R13 with disp=0: must use mod=01 + disp8=0,
|
||||||
|
because mod=00 + r/m=101 means RIP-relative */
|
||||||
|
if (base == SCC_X86_REG_RBP || base == SCC_X86_REG_R13)
|
||||||
|
return 8;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
if (disp >= -128 && disp <= 127)
|
if (disp >= -128 && disp <= 127)
|
||||||
return 8;
|
return 8;
|
||||||
return 32;
|
return 32;
|
||||||
@@ -496,10 +500,12 @@ int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
|||||||
} else if (ops[i].kind == SCC_X86_OPR_MEM) {
|
} else if (ops[i].kind == SCC_X86_OPR_MEM) {
|
||||||
base_reg = ops[i].mem.base;
|
base_reg = ops[i].mem.base;
|
||||||
idx_reg = ops[i].mem.index;
|
idx_reg = ops[i].mem.index;
|
||||||
} else if (ops[i].kind == SCC_X86_OPR_IMM ||
|
} else if (ops[i].kind == SCC_X86_OPR_IMM) {
|
||||||
ops[i].kind == SCC_X86_OPR_RELBR) {
|
|
||||||
imm_val = ops[i].imm0;
|
imm_val = ops[i].imm0;
|
||||||
imm_idx = i;
|
imm_idx = i;
|
||||||
|
} else if (ops[i].kind == SCC_X86_OPR_RELBR) {
|
||||||
|
imm_val = ops[i].brdisp; // i32 → i64 自动符号扩展
|
||||||
|
imm_idx = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ static void load_from_def(pe_idata_lib_ctx_t *ctx, const char *file_path,
|
|||||||
const char *fname = scc_str_as_cstr(&fpath);
|
const char *fname = scc_str_as_cstr(&fpath);
|
||||||
scc_file_t fp = scc_fopen(fname, SCC_FILE_READ);
|
scc_file_t fp = scc_fopen(fname, SCC_FILE_READ);
|
||||||
if (fp == nullptr) {
|
if (fp == nullptr) {
|
||||||
LOG_ERROR("load_from_def file read error: %s", fname);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
LOG_TRACE("load_from_def file read sucessful: %s", fname);
|
||||||
|
|
||||||
usize fsize = scc_fsize(fp);
|
usize fsize = scc_fsize(fp);
|
||||||
char *buffer = scc_malloc(fsize);
|
char *buffer = scc_malloc(fsize);
|
||||||
@@ -152,7 +152,7 @@ void sccf2pe(scc_pe_builder_t *builder, const sccf_t *sccf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pe_idata_lib_ctx_t idata_lib_ctx;
|
pe_idata_lib_ctx_t idata_lib_ctx;
|
||||||
pe_idata_lib_init(&idata_lib_ctx, __FILE__ "/../../.dll_def");
|
pe_idata_lib_init(&idata_lib_ctx, "./.scc_dll");
|
||||||
scc_vec_foreach(symtab, i) {
|
scc_vec_foreach(symtab, i) {
|
||||||
sccf_sym_t *sym = &scc_vec_at(symtab, i);
|
sccf_sym_t *sym = &scc_vec_at(symtab, i);
|
||||||
if (sym->sccf_sym_type == SCCF_SYM_TYPE_EXTERN) {
|
if (sym->sccf_sym_type == SCCF_SYM_TYPE_EXTERN) {
|
||||||
|
|||||||
@@ -23,3 +23,4 @@
|
|||||||
"./return_val_cases/19_goto.c" = 219
|
"./return_val_cases/19_goto.c" = 219
|
||||||
[stdout_val_cases]
|
[stdout_val_cases]
|
||||||
"./stdout_val_cases/01_include.c" = "Hello World!\n"
|
"./stdout_val_cases/01_include.c" = "Hello World!\n"
|
||||||
|
"./stdout_val_cases/02_printf.c" = "Hello printf: 123\n"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
puts("hello world");
|
puts("hello world!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
6
tests/simple/stdout_val_cases/02_printf.c
Normal file
6
tests/simple/stdout_val_cases/02_printf.c
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("hello printf: %d\n", 123);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user