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,
|
||||
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__ */
|
||||
|
||||
@@ -4,6 +4,26 @@
|
||||
#include <scc_hir_builder.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,
|
||||
const scc_ast_qual_type_t *ast_type) {
|
||||
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,
|
||||
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;
|
||||
|
||||
// 转换参数类型
|
||||
// 转换参数类型(跳过尾部的 ... 假参数)
|
||||
scc_hir_type_ref_vec_t params;
|
||||
scc_vec_init(params);
|
||||
scc_vec_foreach(scc_ast_canon_type(ast_type)->function.params, i) {
|
||||
scc_ast_decl_t *decl_param =
|
||||
scc_vec_at(scc_ast_canon_type(ast_type)->function.params, i);
|
||||
int n_fixed = fixed_param_count(scc_ast_canon_type(ast_type));
|
||||
scc_ast_decl_vec_t *ast_params =
|
||||
&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);
|
||||
scc_hir_type_ref_t tmp_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,
|
||||
const scc_ast_expr_t *expr,
|
||||
scc_hir_value_ref_t lhs,
|
||||
scc_hir_value_ref_t rhs) {
|
||||
const scc_ast_expr_t *expr) {
|
||||
// scc_hir_bblock_ref_t start_block =
|
||||
// scc_hir_builder_current_bblock(&ctx->builder);
|
||||
|
||||
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_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);
|
||||
@@ -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) {
|
||||
// a && b
|
||||
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(短路)
|
||||
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);
|
||||
|
||||
// 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_store(&ctx->builder, result_var, zero_val);
|
||||
scc_hir_builder_jump(&ctx->builder, end_block);
|
||||
|
||||
// right_block: 左边非0,计算右边
|
||||
scc_hir_builder_append_bblock(&ctx->builder, right_block);
|
||||
scc_hir_builder_set_current_bblock(&ctx->builder, right_block);
|
||||
scc_hir_value_ref_t right_val =
|
||||
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
|
||||
// a || b
|
||||
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(短路)
|
||||
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);
|
||||
|
||||
// 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_store(&ctx->builder, result_var, one_val);
|
||||
scc_hir_builder_jump(&ctx->builder, end_block);
|
||||
|
||||
// right_block: 左边为0,计算右边
|
||||
scc_hir_builder_append_bblock(&ctx->builder, right_block);
|
||||
scc_hir_builder_set_current_bblock(&ctx->builder, right_block);
|
||||
scc_hir_value_ref_t right_val =
|
||||
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);
|
||||
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) {
|
||||
Assert(rhs != SCC_HIR_REF_nullptr);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
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_AND: // &&
|
||||
return scc_ast2ir_logical_expr(ctx, expr, lhs, rhs);
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
/* clang-format on */
|
||||
default:
|
||||
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_builder_get_module(&ctx->builder), old_val)
|
||||
->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_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(
|
||||
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder),
|
||||
&ctx->builder, promoted_type_ref,
|
||||
&(scc_ap_t){.data.digit = 1, .capacity = -1});
|
||||
scc_hir_op_type_t op =
|
||||
(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;
|
||||
// if (old_type != promoted_type) {
|
||||
// stored_val = scc_hir_builder_conv(&ctx->builder, new_val,
|
||||
// old_type, CONV_TRUNC);
|
||||
// }
|
||||
if (promoted_type_ref != old_type) {
|
||||
stored_val = scc_ast2ir_emit_conversion(ctx, new_val, old_type);
|
||||
}
|
||||
scc_hir_builder_store(&ctx->builder, addr, stored_val);
|
||||
Assert(new_val != SCC_HIR_REF_nullptr);
|
||||
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_builder_get_module(&ctx->builder), old_val)
|
||||
->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_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(
|
||||
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder),
|
||||
&ctx->builder, promoted_type_ref,
|
||||
&(scc_ap_t){.data.digit = 1, .capacity = -1});
|
||||
scc_hir_op_type_t op =
|
||||
(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_value_ref_t stored_val = new_val;
|
||||
// if (old_type != promoted_type)
|
||||
// stored_val = trunc;
|
||||
if (promoted_type_ref != old_type) {
|
||||
stored_val = scc_ast2ir_emit_conversion(ctx, new_val, old_type);
|
||||
}
|
||||
scc_hir_builder_store(&ctx->builder, addr, stored_val);
|
||||
|
||||
// 后缀返回旧的、未提升的值(但 C
|
||||
// 要求返回提升后的旧值?实际是旧值按右值规则,应得到提升后的值)
|
||||
// 标准规定后缀++的结果是操作数原来的值,但会经过整数提升。
|
||||
// 所以需要返回 promoted(已提升的旧值)。
|
||||
Assert(promoted != SCC_HIR_REF_nullptr);
|
||||
return promoted; // 旧值,但类型已提升为
|
||||
// int 等
|
||||
// 后缀返回旧值的提升后版本(C11 6.5.2.4)
|
||||
return promoted;
|
||||
} break;
|
||||
default:
|
||||
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_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_ast_expr_t *arg_expr = scc_vec_at(expr->call.args, i);
|
||||
scc_hir_value_ref_t arg_node;
|
||||
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_hir_func_ref_t func = (scc_hir_value_ref_t)(usize)scc_hashtable_get(
|
||||
&ctx->symtab, expr->call.callee->identifier._target->name);
|
||||
if (!func) {
|
||||
if (!callee_func) {
|
||||
LOG_ERROR("Function %s not found",
|
||||
expr->call.callee->identifier._target->name);
|
||||
}
|
||||
scc_hir_value_ref_t node =
|
||||
scc_hir_builder_call(&ctx->builder, func, args.data, args.size);
|
||||
scc_hir_value_ref_t node = scc_hir_builder_call(
|
||||
&ctx->builder, callee_func, args.data, args.size);
|
||||
scc_vec_free(args);
|
||||
return node;
|
||||
}
|
||||
@@ -772,6 +936,18 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
// 2. 计算下标值
|
||||
scc_hir_value_ref_t index =
|
||||
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)
|
||||
scc_hir_value_ref_t elem_ptr =
|
||||
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;
|
||||
if (dst_size > src_size) {
|
||||
// 目标更大,需要扩展。根据源类型有无符号决定符号扩展还是零扩展
|
||||
conv_kind =
|
||||
scc_hir_type_is_signed(src_type->tag) ? CONV_SEXT : CONV_ZEXT;
|
||||
conv_kind = scc_hir_type_is_signed(src_type->tag)
|
||||
? SCC_HIR_CONV_SEXT
|
||||
: SCC_HIR_CONV_ZEXT;
|
||||
} else if (dst_size < src_size) {
|
||||
conv_kind = CONV_TRUNC;
|
||||
conv_kind = SCC_HIR_CONV_TRUNC;
|
||||
} else {
|
||||
// 同大小,可以视为 NOP 转换,或者直接返回操作数
|
||||
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, // 浮点字面量
|
||||
case SCC_AST_EXPR_CHAR_LITERAL: {
|
||||
// FIXME just 'a' '\n'
|
||||
scc_hir_type_ref_t type_ref = scc_hir_builder_type_i32(&ctx->builder);
|
||||
const char *lexme = expr->literal.lexme;
|
||||
Assert(lexme[0] == '\'');
|
||||
u8 int_lit = 0;
|
||||
i8 int_lit = 0;
|
||||
if (lexme[1] == '\\') {
|
||||
switch (lexme[2]) {
|
||||
case 'a':
|
||||
@@ -988,6 +1164,8 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
|
||||
int_lit = lexme[1];
|
||||
}
|
||||
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);
|
||||
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
|
||||
*/
|
||||
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_builder_bblock(&ctx->builder, "if_false");
|
||||
scc_hir_builder_create_bblock(&ctx->builder, "if_false");
|
||||
|
||||
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_ast2ir_expr(ctx, stmt->if_stmt.cond, false);
|
||||
scc_hir_builder_branch(&ctx->builder, cond_node, true_block,
|
||||
false_block);
|
||||
stmt->if_stmt.opt_else_stmt ? false_block
|
||||
: merge_block);
|
||||
|
||||
// 生成true分支
|
||||
scc_hir_builder_append_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_hir_builder_jump(&ctx->builder, merge_block);
|
||||
|
||||
// 生成false分支
|
||||
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_ast2ir_stmt(ctx, stmt->if_stmt.opt_else_stmt);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
case SCC_AST_STMT_WHILE: {
|
||||
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_builder_bblock(&ctx->builder, "while_body");
|
||||
scc_hir_builder_create_bblock(&ctx->builder, "while_body");
|
||||
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->continue_cache, stmt, (void *)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_value_ref_t cond_node =
|
||||
scc_ast2ir_expr(ctx, stmt->while_stmt.cond, false);
|
||||
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
|
||||
exit_block);
|
||||
|
||||
scc_hir_builder_append_bblock(&ctx->builder, body_block);
|
||||
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
||||
scc_ast2ir_stmt(ctx, stmt->while_stmt.body);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
case SCC_AST_STMT_DO_WHILE: {
|
||||
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_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_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->continue_cache, stmt, (void *)cond_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_ast2ir_stmt(ctx, stmt->while_stmt.body);
|
||||
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_value_ref_t cond_node =
|
||||
scc_ast2ir_expr(ctx, stmt->while_stmt.cond, false);
|
||||
scc_hir_builder_branch(&ctx->builder, cond_node, body_block,
|
||||
exit_block);
|
||||
|
||||
scc_hir_builder_append_bblock(&ctx->builder, exit_block);
|
||||
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
|
||||
break;
|
||||
}
|
||||
case SCC_AST_STMT_FOR: {
|
||||
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_builder_bblock(&ctx->builder, "for_body");
|
||||
scc_hir_builder_create_bblock(&ctx->builder, "for_body");
|
||||
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_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->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_append_bblock(&ctx->builder, cond_block);
|
||||
scc_hir_builder_set_current_bblock(&ctx->builder, cond_block);
|
||||
if (stmt->for_stmt.cond) {
|
||||
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_append_bblock(&ctx->builder, body_block);
|
||||
scc_hir_builder_set_current_bblock(&ctx->builder, body_block);
|
||||
scc_ast2ir_stmt(ctx, stmt->for_stmt.body);
|
||||
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);
|
||||
if (stmt->for_stmt.incr) {
|
||||
scc_ast2ir_expr(ctx, stmt->for_stmt.incr, false);
|
||||
}
|
||||
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);
|
||||
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) {
|
||||
scc_hir_value_ref_t ret_val_node =
|
||||
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);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
// 检测是否是可变参数函数(无论是否有函数体)
|
||||
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) {
|
||||
// function decl
|
||||
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
|
||||
Assert(SCC_HIR_FUNC_META(hir_func)->defined == false);
|
||||
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_bblock(&ctx->builder, "entry");
|
||||
|
||||
scc_vec_foreach(scc_ast_canon_type(decl->func.type)->function.params,
|
||||
i) {
|
||||
scc_ast_decl_t *param = scc_vec_at(
|
||||
scc_ast_canon_type(decl->func.type)->function.params, i);
|
||||
// 只处理固定参数,跳过尾部的 ... 假参数
|
||||
scc_ast_decl_vec_t *ast_params =
|
||||
&scc_ast_canon_type(decl->func.type)->function.params;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1395,11 +1612,15 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
|
||||
break;
|
||||
}
|
||||
case SCC_AST_DECL_PARAM: {
|
||||
// 跳过 void 参数和 ... 假参数(无名 VA_LIST)
|
||||
if (decl->param.type->base.type == SCC_AST_TYPE_BUILTIN &&
|
||||
scc_ast_canon_type(decl->param.type)->builtin.type ==
|
||||
SCC_AST_BUILTIN_TYPE_VOID) {
|
||||
break;
|
||||
}
|
||||
if (is_variadic_marker(decl)) {
|
||||
break;
|
||||
}
|
||||
scc_hir_type_ref_t parma_type_ref =
|
||||
scc_ast2ir_type(ctx, decl->param.type);
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user