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

@@ -1,9 +1,9 @@
[package]
name = "ap"
version = "0.1.0"
authors = []
name = "ap"
version = "0.1.0"
authors = []
description = ""
# dependencies = []
dependencies = [{ name = "core", path = "../scc_core" }]
# features = {}
# default_features = []

View File

@@ -4,7 +4,7 @@
* @brief Arbitrary Precision Library
*
*/
#ifdef __SCC__
#ifndef __NO_SCC_RUNTIME__
#include <scc_core.h>
#define SCC_AP_DIGIT u64
#define SCC_AP_PANIC Panic
@@ -49,21 +49,21 @@ typedef struct {
} scc_ap_t;
static inline void scc_ap_init(scc_ap_t *ap) {
ap->len = 0;
ap->capacity = -1;
ap->len = 1;
ap->data.digit = 0;
}
static inline void scc_ap_set_int(scc_ap_t *ap, int val) {
ap->capacity = -1;
SCC_AP_ASSERT(sizeof(scc_ap_digit) >= sizeof(int));
if (val < 0) {
ap->len = -1;
ap->data.digit = (scc_ap_digit)(-(int64_t)val);
} else {
ap->len = 1;
ap->data.digit = (scc_ap_digit)val;
}
SCC_AP_ASSERT(sizeof(scc_ap_digit) >= sizeof(int));
ap->capacity = -1;
ap->data.digit = val;
}
void scc_ap_drop(scc_ap_t *ap);
@@ -77,13 +77,20 @@ void scc_ap_mul(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b);
void scc_ap_div(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b);
void scc_ap_mod(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b);
/**
* @brief equal
*
* @param a
* @param b
* @return int
*/
void scc_ap_shl(scc_ap_t *to, const scc_ap_t *from, unsigned shift);
void scc_ap_shr(scc_ap_t *to, const scc_ap_t *from, unsigned shift);
void scc_ap_lshr(scc_ap_t *to, const scc_ap_t *from, unsigned shift);
void scc_ap_and(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b);
void scc_ap_or(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b);
void scc_ap_xor(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b);
void scc_ap_not(scc_ap_t *to, const scc_ap_t *from);
void scc_ap_neg(scc_ap_t *to, const scc_ap_t *from);
int scc_ap_cmp(const scc_ap_t *a, const scc_ap_t *b);
int scc_ap_is_zero(const scc_ap_t *ap);
int scc_ap_eql(const scc_ap_t *a, const scc_ap_t *b);
typedef void (*ap_dump_fn)(const char ch, void *user_data);

View File

@@ -1,48 +1,394 @@
#include <ap.h>
static void *scc_ap_alloc(size_t size) {
void *p = SCC_AP_MALLOC(size);
SCC_AP_ASSERT(p != NULL);
return p;
/*
* 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;
}
/* 重新分配内存 */
static void *scc_ap_realloc_data(void *old, size_t new_size) {
void *p = SCC_AP_REALLOC(old, new_size);
SCC_AP_ASSERT(p != NULL);
return p;
/* 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);
// SCC_AP_FREE(ap->data);
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) {}
void scc_ap_from_string(scc_ap_t *ap, const char *str, int len, int base) {
SCC_AP_ASSERT(base == 10);
SCC_AP_ASSERT(ap && str);
if (len == 0) {
scc_ap_set_int(ap, 0);
}
// FIXME
int int_lit = 0;
for (int i = 0; i < len; i += 1) {
int_lit = int_lit * 10 + (str[i] - '0');
}
scc_ap_set_int(ap, int_lit);
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_set_digit(scc_ap_t *ap, scc_ap_digit digit) {}
void scc_ap_from_string(scc_ap_t *ap, const char *str, int len, int base) {
SCC_AP_ASSERT(ap != nullptr && str != nullptr);
void scc_ap_add_impl(scc_ap_t *to, const scc_ap_t *from_a,
const scc_ap_t *from_b) {}
/* len < 0 means null-terminated */
if (len < 0) {
len = 0;
while (str[len] != '\0')
len++;
}
if (len == 0) {
ap_from_isize(ap, 0);
return;
}
void scc_ap_add(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {}
int i = 0;
int sign = 1;
void scc_ap_sub(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {}
/* Optional leading sign */
if (str[i] == '-') {
sign = -1;
i++;
} else if (str[i] == '+') {
i++;
}
typedef void (*ap_dump_fn)(const char ch, void *user_data);
int scc_ap_dump(scc_ap_t *ap, ap_dump_fn dump_fn, void *user_data) { return 0; }
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;
}

1028
runtime/ap/tests/test_ap.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
#include <ap.h>
#include <stdio.h>
#include <string.h>
#include <utest/acutest.h>
/*
* Panic / overflow tests — each test calls SCC_AP_PANIC which aborts the
* process. Run this file separately from the normal tests.
*/
/* ---------- helper: attempt an operation and report result ---------- */
#define TRY_PANIC(call, label) \
do { \
fprintf(stderr, " " label " ... "); \
call; \
fprintf(stderr, "FAIL (no panic)\n"); \
TEST_CHECK(0 && "expected panic"); \
} while (0)
void test_add_overflow_positive(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_from_string(&a, "9223372036854775807", -1, 10);
scc_ap_set_int(&b, 1);
TRY_PANIC(scc_ap_add(&r, &a, &b), "INTPTR_MAX + 1");
}
void test_add_overflow_negative(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_from_string(&a, "-9223372036854775808", -1, 10);
scc_ap_set_int(&b, -1);
TRY_PANIC(scc_ap_add(&r, &a, &b), "INTPTR_MIN + (-1)");
}
void test_mul_overflow(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_from_string(&a, "4611686018427387904", -1, 10); /* INT64_MAX/2 + 1 */
scc_ap_set_int(&b, 2);
TRY_PANIC(scc_ap_mul(&r, &a, &b), "(INT64_MAX/2+1) * 2");
}
void test_div_by_zero(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 1);
scc_ap_set_int(&b, 0);
TRY_PANIC(scc_ap_div(&r, &a, &b), "1 / 0");
}
void test_mod_by_zero(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_set_int(&a, 1);
scc_ap_set_int(&b, 0);
TRY_PANIC(scc_ap_mod(&r, &a, &b), "1 % 0");
}
void test_from_string_overflow(void) {
scc_ap_t ap;
scc_ap_init(&ap);
TRY_PANIC(scc_ap_from_string(&ap, "18446744073709551615", -1, 10),
"UINT64_MAX as string");
}
void test_set_digit_overflow(void) {
scc_ap_t ap;
scc_ap_init(&ap);
TRY_PANIC(scc_ap_set_digit(&ap, (scc_ap_digit)18446744073709551615ULL),
"set_digit(UINT64_MAX)");
}
void test_sub_underflow(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_from_string(&a, "-9223372036854775808", -1, 10);
scc_ap_set_int(&b, 1);
TRY_PANIC(scc_ap_sub(&r, &a, &b), "INTPTR_MIN - 1");
}
void test_div_overflow(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_from_string(&a, "-9223372036854775808", -1, 10);
scc_ap_set_int(&b, -1);
TRY_PANIC(scc_ap_div(&r, &a, &b), "INTPTR_MIN / -1");
}
void test_mod_overflow(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_from_string(&a, "-9223372036854775808", -1, 10);
scc_ap_set_int(&b, -1);
TRY_PANIC(scc_ap_mod(&r, &a, &b), "INTPTR_MIN % -1");
}
void test_mul_overflow_neg_limit(void) {
scc_ap_t a, b, r;
scc_ap_init(&a);
scc_ap_init(&b);
scc_ap_init(&r);
scc_ap_from_string(&a, "-9223372036854775808", -1, 10);
scc_ap_set_int(&b, 2);
TRY_PANIC(scc_ap_mul(&r, &a, &b), "INTPTR_MIN * 2");
}
void test_with_bits_overflow(void) {
scc_ap_t ap;
scc_ap_init(&ap);
TRY_PANIC(scc_ap_with_bits(&ap, 65), "with_bits(65)");
}
/* ---------- shift overflow tests ---------- */
void test_shl_overflow(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_from_string(&a, "4611686018427387904", -1, 10); /* INT64_MAX/2+1 */
TRY_PANIC(scc_ap_shl(&r, &a, 1), "(INT64_MAX/2+1) << 1");
}
void test_shl_shift_ge_64(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 1);
TRY_PANIC(scc_ap_shl(&r, &a, 64), "1 << 64");
}
void test_shr_shift_ge_64(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 1);
TRY_PANIC(scc_ap_shr(&r, &a, 64), "1 >> 64");
}
void test_lshr_shift_ge_64(void) {
scc_ap_t a, r;
scc_ap_init(&a);
scc_ap_init(&r);
scc_ap_set_int(&a, 1);
TRY_PANIC(scc_ap_lshr(&r, &a, 64), "1 lshr 64");
}
TEST_LIST = {
{"test_add_overflow_positive", test_add_overflow_positive},
{"test_add_overflow_negative", test_add_overflow_negative},
{"test_mul_overflow", test_mul_overflow},
{"test_mul_overflow_neg_limit", test_mul_overflow_neg_limit},
{"test_div_by_zero", test_div_by_zero},
{"test_div_overflow", test_div_overflow},
{"test_mod_by_zero", test_mod_by_zero},
{"test_mod_overflow", test_mod_overflow},
{"test_sub_underflow", test_sub_underflow},
{"test_from_string_overflow", test_from_string_overflow},
{"test_set_digit_overflow", test_set_digit_overflow},
{"test_with_bits_overflow", test_with_bits_overflow},
/* shift overflow */
{"test_shl_overflow", test_shl_overflow},
{"test_shl_shift_ge_64", test_shl_shift_ge_64},
{"test_shr_shift_ge_64", test_shr_shift_ge_64},
{"test_lshr_shift_ge_64", test_lshr_shift_ge_64},
{nullptr, nullptr},
};