refactor(ast2ir): 移除废弃的ABI依赖并优化类型转换处理

移除了对scc_abi包的依赖,将相关头文件从libs/abi移动到libs/ast2ir目录下。
重构了基本类型解析功能,将parse_base_type函数提取为独立的
scc_ast2ir_parse_base_type实现,并支持有符号/无符号类型区分。

feat(ast2ir): 实现整数常量表达式求值器

新增了完整的整数常量表达式求值功能,支持C11标准中的常量表达式规则,
包括字面量、标识符、sizeof/_Alignof、一元/二元运算、条件表达式和
类型转换等操作。该功能用于数组大小和枚举值的编译期计算验证。

refactor(ast2ir): 完善类型提升和算术转换机制

改进了整数提升和寻常算术转换的实现,修复了移位操作的符号处理问题,
添加了无符号比较操作的支持,增强了类型安全检查,统一了错误处理流程。

fix(ast2ir): 修复赋值表达式返回值和数组大小计算问题

修正了赋值表达式的返回值处理,确保返回右侧值而不是存储指令引用。
使用新的常量表达式求值器替代原有的硬编码数组大小计算,提高了
数组声明的正确性。
This commit is contained in:
zzy
2026-05-31 17:30:22 +08:00
parent c4467b8420
commit d2eafa9dc6
27 changed files with 2579 additions and 218 deletions

View File

@@ -24,29 +24,6 @@ static int fixed_param_count(const scc_ast_canon_type_t *canon) {
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;
// 映射内置类型
ctx->abi->compute_type_layout(ctx->abi, (void *)ast_type, &layout);
switch (layout.size) {
case 0:
return scc_hir_builder_type_void(&ctx->builder);
case 1:
return scc_hir_builder_type_i8(&ctx->builder);
case 2:
return scc_hir_builder_type_i16(&ctx->builder);
case 4:
return scc_hir_builder_type_i32(&ctx->builder);
case 8:
return scc_hir_builder_type_i64(&ctx->builder);
break;
default:
break;
}
return SCC_HIR_REF_nullptr;
}
static inline bool scc_hir_type_is_signed(scc_hir_type_tag_t tag) {
switch (tag) {
case SCC_HIR_TYPE_i8:
@@ -69,6 +46,7 @@ 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) {
Assert(type != nullptr);
switch (type->tag) {
case SCC_HIR_TYPE_i8:
case SCC_HIR_TYPE_i16:
@@ -235,7 +213,7 @@ scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
switch (ast_type->base.type) {
case SCC_AST_TYPE_BUILTIN: {
return parse_base_type(ctx, ast_type);
return scc_ast2ir_parse_base_type(ctx, ast_type);
}
case SCC_AST_TYPE_POINTER: {
scc_hir_type_init(&ir_type, SCC_HIR_TYPE_PTR);
@@ -253,16 +231,11 @@ scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
ir_type.data.array.base = element_type;
ir_type.data.array.len = 0;
if (scc_ast_canon_type(ast_type)->array.size) {
// TODO constant expression
if (scc_ast_canon_type(ast_type)->array.size->base.type !=
SCC_AST_EXPR_INT_LITERAL) {
Panic("TODO: array size expression");
}
scc_ap_t value;
scc_ap_from_cstr(
&value, scc_ast_canon_type(ast_type)->array.size->literal.lexme,
10);
// FIXME hack
if (!scc_ast2ir_eval_constant_int(
ctx, &value, scc_ast_canon_type(ast_type)->array.size)) {
Panic("array size is not a constant expression");
}
ir_type.data.array.len = value.data.digit;
}
} break;
@@ -359,7 +332,7 @@ scc_hir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
.base.type = SCC_AST_TYPE_BUILTIN,
.type = int_canon_type,
};
return parse_base_type(ctx, &int_type);
return scc_ast2ir_parse_base_type(ctx, &int_type);
case SCC_AST_TYPE_TYPEDEF:
// TODO maybe using cache
return scc_ast2ir_type(
@@ -569,7 +542,8 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
rhs = scc_ast2ir_emit_conversion(
ctx, rhs, lhs_ptr_type->data.pointer.base);
}
return scc_hir_builder_store(&ctx->builder, lhs, rhs);
scc_hir_builder_store(&ctx->builder, lhs, rhs);
return rhs;
}
if (expr->binary.op == SCC_AST_OP_LOGICAL_AND ||
@@ -577,30 +551,36 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
// 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);
if (expr->binary.op == SCC_AST_OP_COMMA) {
lhs = scc_ast2ir_expr(ctx, expr->binary.lhs, false);
rhs = scc_ast2ir_expr(ctx, expr->binary.rhs, false);
} else {
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);
scc_hir_type_ref_t common_type = 0;
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;
Assert(lhs_type_ref != 0 && rhs_type_ref != 0);
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);
common_type = scc_ast2ir_usual_arithmetic_conversion(
ctx, lhs_type_ref, rhs_type_ref);
if (common_type != 0) {
lhs = scc_ast2ir_emit_conversion(ctx, lhs, common_type);
rhs = scc_ast2ir_emit_conversion(ctx, rhs, common_type);
}
}
} else if (is_shift) {
@@ -628,16 +608,42 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
case SCC_AST_OP_BITWISE_XOR: op = SCC_HIR_OP_XOR; break;
case SCC_AST_OP_LEFT_SHIFT: op = SCC_HIR_OP_SHL; break;
case SCC_AST_OP_RIGHT_SHIFT: {
op = SCC_HIR_OP_SHR;
// FIXME op = SCC_HIR_OP_SAR;
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
scc_hir_type_ref_t type_ref = scc_hir_module_get_value(module, lhs)->type;
scc_hir_type_t *type = scc_hir_module_get_type(module, type_ref);
op = scc_hir_type_is_signed(type->tag) ? SCC_HIR_OP_SAR : SCC_HIR_OP_SHR;
break;
}
case SCC_AST_OP_EQUAL: op = SCC_HIR_OP_EQ; break;
case SCC_AST_OP_NOT_EQUAL: op = SCC_HIR_OP_NEQ; break;
case SCC_AST_OP_LESS: op = SCC_HIR_OP_LT; break;
case SCC_AST_OP_LESS_EQUAL: op = SCC_HIR_OP_LE; break;
case SCC_AST_OP_GREATER: op = SCC_HIR_OP_GT; break;
case SCC_AST_OP_GREATER_EQUAL: op = SCC_HIR_OP_GE; break;
case SCC_AST_OP_LESS: {
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
scc_hir_type_ref_t tr = common_type ? common_type : scc_hir_module_get_value(module, lhs)->type;
scc_hir_type_t *t = scc_hir_module_get_type(module, tr);
op = scc_hir_type_is_signed(t->tag) ? SCC_HIR_OP_LT : SCC_HIR_OP_ULT;
break;
}
case SCC_AST_OP_LESS_EQUAL: {
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
scc_hir_type_ref_t tr = common_type ? common_type : scc_hir_module_get_value(module, lhs)->type;
scc_hir_type_t *t = scc_hir_module_get_type(module, tr);
op = scc_hir_type_is_signed(t->tag) ? SCC_HIR_OP_LE : SCC_HIR_OP_ULE;
break;
}
case SCC_AST_OP_GREATER: {
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
scc_hir_type_ref_t tr = common_type ? common_type : scc_hir_module_get_value(module, lhs)->type;
scc_hir_type_t *t = scc_hir_module_get_type(module, tr);
op = scc_hir_type_is_signed(t->tag) ? SCC_HIR_OP_GT : SCC_HIR_OP_UGT;
break;
}
case SCC_AST_OP_GREATER_EQUAL: {
scc_hir_module_t *module = scc_ast2ir_mir_module(ctx);
scc_hir_type_ref_t tr = common_type ? common_type : scc_hir_module_get_value(module, lhs)->type;
scc_hir_type_t *t = scc_hir_module_get_type(module, tr);
op = scc_hir_type_is_signed(t->tag) ? SCC_HIR_OP_GE : SCC_HIR_OP_UGE;
break;
}
case SCC_AST_OP_COMMA: {
// 逗号运算符:计算左表达式,丢弃结果,返回右表达式
return rhs;
@@ -854,28 +860,24 @@ 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;
}
Assert(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) {
@@ -897,8 +899,11 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
// 可变参数只应用默认参数提升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_value_t *arg_value =
scc_hir_module_get_value(module, arg_node);
Assert(arg_value != nullptr);
scc_hir_type_ref_t arg_type_ref = arg_value->type;
Assert(arg_type_ref != 0);
scc_hir_type_tag_t arg_tag =
scc_hir_module_get_type(module, arg_type_ref)->tag;
@@ -1136,7 +1141,7 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
// FIXME maybe using some array to int;
scc_hir_type_ref_t type_ref = scc_hir_builder_type_i32(&ctx->builder);
scc_ap_t value;
scc_ap_from_cstr(&value, expr->literal.lexme, 10);
scc_ap_from_cstr(&value, expr->literal.lexme, 0);
return scc_hir_builder_integer(&ctx->builder, type_ref, &value);
}
// SCC_AST_EXPR_FLOAT_LITERAL, // 浮点字面量
@@ -1655,24 +1660,23 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
} break;
case SCC_AST_DECL_ENUM: {
scc_ap_t val;
int idx = 0;
scc_ap_set_int(&val, idx);
scc_ap_set_int(&val, 0);
scc_vec_foreach(decl->record.fields, i) {
scc_ast_decl_t *item = scc_vec_at(decl->record.fields, i);
Assert(item->base.type == SCC_AST_DECL_VAR);
if (item->var.init) {
Assert(item->var.init->base.type == SCC_AST_EXPR_INT_LITERAL);
scc_ap_from_cstr(&val, item->var.init->literal.lexme, 10);
if (!scc_ast2ir_eval_constant_int(ctx, &val, item->var.init)) {
Panic("enum value is not a constant expression");
}
}
scc_hir_value_ref_t item_val_ref = scc_hir_builder_integer(
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder), &val);
scc_hashtable_set(&ctx->ast2ir_cache, item,
(void *)(usize)item_val_ref);
// FIXME hack ap
idx = val.data.digit;
idx += 1;
// scc_ap_add 1 ();
scc_ap_set_int(&val, idx);
/* next = val + 1 */
scc_ap_t one;
scc_ap_set_int(&one, 1);
scc_ap_add(&val, &val, &one);
}
} break;
case SCC_AST_DECL_TYPEDEF: