Files
scc/runtime/ap/src/ap.c
zzy d2eafa9dc6 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): 修复赋值表达式返回值和数组大小计算问题

修正了赋值表达式的返回值处理,确保返回右侧值而不是存储指令引用。
使用新的常量表达式求值器替代原有的硬编码数组大小计算,提高了
数组声明的正确性。
2026-05-31 17:30:22 +08:00

395 lines
12 KiB
C

#include <ap.h>
/*
* Fast-path (hack) implementation: all values stored in single-digit mode.
* data.digit holds the absolute magnitude as u64, len sign indicates sign.
* Arithmetic is done via isize with explicit overflow checks — anything
* out of isize range triggers SCC_AP_PANIC.
*/
/* ---------- internal helpers ---------- */
/* Convert from sign-magnitude (digit mode) to isize */
static isize ap_to_isize(const scc_ap_t *ap) {
SCC_AP_ASSERT(ap != nullptr);
SCC_AP_ASSERT(ap->capacity == -1);
uint64_t mag = ap->data.digit;
if (ap->len < 0) {
if (mag == 0)
return 0;
if (mag == (uint64_t)INTPTR_MAX + 1)
return INTPTR_MIN;
SCC_AP_ASSERT(mag <= (uint64_t)INTPTR_MAX);
return -(isize)(int64_t)mag;
}
SCC_AP_ASSERT(mag <= (uint64_t)INTPTR_MAX);
return (isize)(int64_t)mag;
}
/* Store isize value into sign-magnitude (digit mode) */
static void ap_from_isize(scc_ap_t *ap, isize val) {
ap->capacity = -1;
if (val < 0) {
ap->len = -1;
ap->data.digit = (scc_ap_digit)(-(uint64_t)(int64_t)val);
} else {
ap->len = 1;
ap->data.digit = (scc_ap_digit)val;
}
}
/* Checked addition */
static isize ap_add_isize(isize a, isize b) {
if (b > 0 && a > INTPTR_MAX - b)
SCC_AP_PANIC("scc_ap_add: positive overflow");
if (b < 0 && a < INTPTR_MIN - b)
SCC_AP_PANIC("scc_ap_add: negative overflow");
return a + b;
}
/* Checked subtraction: a - b */
static isize ap_sub_isize(isize a, isize b) {
/* a - b = a + (-b); -INTPTR_MIN overflows, handle specially */
if (b == INTPTR_MIN) {
if (a < 0)
SCC_AP_PANIC("scc_ap_sub: overflow (a - INTPTR_MIN, a < 0)");
SCC_AP_PANIC("scc_ap_sub: overflow (a - INTPTR_MIN, a >= 0)");
}
return ap_add_isize(a, -b);
}
/* Checked multiplication */
static isize ap_mul_isize(isize a, isize b) {
if (a == 0 || b == 0)
return 0;
if (a == 1)
return b;
if (b == 1)
return a;
/* Determine sign of result */
int sign = ((a < 0) == (b < 0)) ? 1 : -1;
/* Absolute values as uint64 */
uint64_t ua = (a == INTPTR_MIN)
? (uint64_t)INTPTR_MAX + 1
: (uint64_t)(a < 0 ? -(int64_t)a : (int64_t)a);
uint64_t ub = (b == INTPTR_MIN)
? (uint64_t)INTPTR_MAX + 1
: (uint64_t)(b < 0 ? -(int64_t)b : (int64_t)b);
/* Overflow threshold */
uint64_t limit =
(sign > 0) ? (uint64_t)INTPTR_MAX : (uint64_t)INTPTR_MAX + 1;
if (ua != 0 && ub > limit / ua)
SCC_AP_PANIC("scc_ap_mul: overflow");
isize result = (isize)(ua * ub);
return (sign > 0) ? result : -result;
}
/* Checked division */
static isize ap_div_isize(isize a, isize b) {
if (b == 0)
SCC_AP_PANIC("scc_ap_div: division by zero");
if (a == INTPTR_MIN && b == -1)
SCC_AP_PANIC("scc_ap_div: overflow (INTPTR_MIN / -1)");
return a / b;
}
/* Checked modulo */
static isize ap_mod_isize(isize a, isize b) {
if (b == 0)
SCC_AP_PANIC("scc_ap_mod: modulo by zero");
if (a == INTPTR_MIN && b == -1)
SCC_AP_PANIC("scc_ap_mod: overflow (INTPTR_MIN %% -1)");
return a % b;
}
/* ---------- public API ---------- */
void scc_ap_drop(scc_ap_t *ap) {
SCC_AP_ASSERT(ap != nullptr);
/* In digit mode (capacity == -1), there's no heap allocation to free */
scc_ap_init(ap);
}
void scc_ap_with_bits(scc_ap_t *ap, int bits) {
SCC_AP_ASSERT(ap != nullptr);
if (bits > (int)(sizeof(scc_ap_digit) * 8))
SCC_AP_PANIC(
"scc_ap_with_bits: request %d bits but digit only has %zu bits",
bits, sizeof(scc_ap_digit) * 8);
(void)ap;
/* Fast path: always stays in digit mode */
}
void scc_ap_from_string(scc_ap_t *ap, const char *str, int len, int base) {
SCC_AP_ASSERT(ap != nullptr && str != nullptr);
/* len < 0 means null-terminated */
if (len < 0) {
len = 0;
while (str[len] != '\0')
len++;
}
if (len == 0) {
ap_from_isize(ap, 0);
return;
}
int i = 0;
int sign = 1;
/* Optional leading sign */
if (str[i] == '-') {
sign = -1;
i++;
} else if (str[i] == '+') {
i++;
}
if (i >= len) {
ap_from_isize(ap, 0);
return;
}
/* ---------- base auto-detection ---------- */
/* hex: 0x / 0X */
if ((base == 0 || base == 16) &&
(i + 2 < len && str[i] == '0' &&
(str[i + 1] == 'x' || str[i + 1] == 'X'))) {
base = 16;
i += 2;
}
/* binary: 0b / 0B */
if ((base == 0 || base == 2) &&
(i + 2 < len && str[i] == '0' &&
(str[i + 1] == 'b' || str[i + 1] == 'B'))) {
base = 2;
i += 2;
}
if (base == 0) {
if (i < len && str[i] == '0') {
base = 8;
i++;
} else {
base = 10;
}
}
/* ---------- parse digits ---------- */
uint64_t val = 0;
for (; i < len; i++) {
char ch = str[i];
unsigned d;
if (ch >= '0' && ch <= '9')
d = (unsigned)(ch - '0');
else if (ch >= 'a' && ch <= 'f')
d = (unsigned)(ch - 'a' + 10);
else if (ch >= 'A' && ch <= 'F')
d = (unsigned)(ch - 'A' + 10);
else
break;
if ((int)d >= base)
break;
/* overflow check: val * base + d <= UINT64_MAX */
if (val > (UINT64_MAX - d) / (unsigned)base)
SCC_AP_PANIC("scc_ap_from_string: overflow");
val = val * (unsigned)base + d;
}
ap->capacity = -1;
ap->data.digit = val;
ap->len = (sign < 0 && val > 0) ? -1 : 1;
}
void scc_ap_set_digit(scc_ap_t *ap, scc_ap_digit digit) {
SCC_AP_ASSERT(ap != nullptr);
if (digit > (scc_ap_digit)INTPTR_MAX)
SCC_AP_PANIC("scc_ap_set_digit: value %llu exceeds isize range",
(unsigned long long)digit);
ap->capacity = -1;
ap->data.digit = digit;
ap->len = 1;
}
void scc_ap_add(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
isize a = ap_to_isize(from_a);
isize b = ap_to_isize(from_b);
ap_from_isize(to, ap_add_isize(a, b));
}
void scc_ap_sub(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
isize a = ap_to_isize(from_a);
isize b = ap_to_isize(from_b);
ap_from_isize(to, ap_sub_isize(a, b));
}
void scc_ap_mul(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
isize a = ap_to_isize(from_a);
isize b = ap_to_isize(from_b);
ap_from_isize(to, ap_mul_isize(a, b));
}
void scc_ap_div(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
isize a = ap_to_isize(from_a);
isize b = ap_to_isize(from_b);
ap_from_isize(to, ap_div_isize(a, b));
}
void scc_ap_mod(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
isize a = ap_to_isize(from_a);
isize b = ap_to_isize(from_b);
ap_from_isize(to, ap_mod_isize(a, b));
}
void scc_ap_shl(scc_ap_t *to, const scc_ap_t *from, unsigned shift) {
SCC_AP_ASSERT(to != nullptr && from != nullptr);
SCC_AP_ASSERT(from->capacity == -1);
if (shift >= sizeof(scc_ap_digit) * 8)
SCC_AP_PANIC("scc_ap_shl: shift %u exceeds digit width (%zu bits)",
shift, sizeof(scc_ap_digit) * 8);
/* left shift = multiply by 2^shift */
isize val = ap_to_isize(from);
isize result = ap_mul_isize(val, (isize)1 << shift);
ap_from_isize(to, result);
}
void scc_ap_shr(scc_ap_t *to, const scc_ap_t *from, unsigned shift) {
SCC_AP_ASSERT(to != nullptr && from != nullptr);
SCC_AP_ASSERT(from->capacity == -1);
if (shift >= sizeof(scc_ap_digit) * 8)
SCC_AP_PANIC("scc_ap_shr: shift %u exceeds digit width (%zu bits)",
shift, sizeof(scc_ap_digit) * 8);
/* arithmetic right shift — uses >> on isize (arithmetic on GCC/MSVC/Clang) */
isize val = ap_to_isize(from);
ap_from_isize(to, val >> shift);
}
void scc_ap_lshr(scc_ap_t *to, const scc_ap_t *from, unsigned shift) {
SCC_AP_ASSERT(to != nullptr && from != nullptr);
SCC_AP_ASSERT(from->capacity == -1);
if (shift >= sizeof(scc_ap_digit) * 8)
SCC_AP_PANIC("scc_ap_lshr: shift %u exceeds digit width (%zu bits)",
shift, sizeof(scc_ap_digit) * 8);
/*
* logical right shift: reinterpret the signed value as uint64 bit pattern,
* shift right, store as non-negative magnitude.
*/
uint64_t bits;
if (from->len < 0) {
/* negative → two's complement bit pattern */
bits = -(uint64_t)(int64_t)from->data.digit;
} else {
bits = from->data.digit;
}
to->capacity = -1;
to->data.digit = bits >> shift;
to->len = 1;
}
/* ---------- bitwise ---------- */
void scc_ap_and(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b) {
SCC_AP_ASSERT(to != nullptr && a != nullptr && b != nullptr);
ap_from_isize(to, ap_to_isize(a) & ap_to_isize(b));
}
void scc_ap_or(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b) {
SCC_AP_ASSERT(to != nullptr && a != nullptr && b != nullptr);
ap_from_isize(to, ap_to_isize(a) | ap_to_isize(b));
}
void scc_ap_xor(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b) {
SCC_AP_ASSERT(to != nullptr && a != nullptr && b != nullptr);
ap_from_isize(to, ap_to_isize(a) ^ ap_to_isize(b));
}
void scc_ap_not(scc_ap_t *to, const scc_ap_t *from) {
SCC_AP_ASSERT(to != nullptr && from != nullptr);
ap_from_isize(to, ~ap_to_isize(from));
}
/* ---------- unary arithmetic ---------- */
void scc_ap_neg(scc_ap_t *to, const scc_ap_t *from) {
SCC_AP_ASSERT(to != nullptr && from != nullptr);
isize val = ap_to_isize(from);
if (val == INTPTR_MIN)
SCC_AP_PANIC("scc_ap_neg: overflow (INTPTR_MIN)");
ap_from_isize(to, -val);
}
/* ---------- comparison ---------- */
int scc_ap_cmp(const scc_ap_t *a, const scc_ap_t *b) {
SCC_AP_ASSERT(a != nullptr && b != nullptr);
isize va = ap_to_isize(a);
isize vb = ap_to_isize(b);
if (va < vb) return -1;
if (va > vb) return 1;
return 0;
}
int scc_ap_is_zero(const scc_ap_t *ap) {
SCC_AP_ASSERT(ap != nullptr);
return ap->data.digit == 0;
}
int scc_ap_eql(const scc_ap_t *a, const scc_ap_t *b) {
SCC_AP_ASSERT(a != nullptr && b != nullptr);
SCC_AP_ASSERT(a->capacity == -1 && b->capacity == -1);
if (a->len != b->len) {
/* -0 == +0 */
if (a->data.digit == 0 && b->data.digit == 0)
return 1;
return 0;
}
return a->data.digit == b->data.digit;
}
int scc_ap_dump(scc_ap_t *ap, ap_dump_fn dump_fn, void *user_data) {
SCC_AP_ASSERT(ap != nullptr && dump_fn != nullptr);
SCC_AP_ASSERT(ap->capacity == -1);
isize val = ap_to_isize(ap);
if (val == 0) {
dump_fn('0', user_data);
return 0;
}
/* Buffer large enough for INT64_MIN "-9223372036854775808" */
char buf[24];
int pos = sizeof(buf);
if (val < 0) {
dump_fn('-', user_data);
/* Work with positive magnitude to avoid overflow when printing */
uint64_t mag = ap->data.digit;
while (mag > 0) {
buf[--pos] = (char)('0' + (mag % 10));
mag /= 10;
}
} else {
uint64_t mag = (uint64_t)val;
while (mag > 0) {
buf[--pos] = (char)('0' + (mag % 10));
mag /= 10;
}
}
for (int i = pos; i < (int)sizeof(buf); i++)
dump_fn(buf[i], user_data);
return 0;
}