Use better terminology for overflow and integer 'underflow'

This commit is contained in:
jun 2025-05-15 09:11:31 +02:00
parent ec074d5753
commit 466982ffcb
3 changed files with 301 additions and 303 deletions

File diff suppressed because it is too large Load Diff

View File

@ -28,31 +28,31 @@ void CkdIntTest::test_ckd()
const guf_math_ckd_result ckd_add = guf_ckd_add_i8((int8_t)a, (int8_t)b); const guf_math_ckd_result ckd_add = guf_ckd_add_i8((int8_t)a, (int8_t)b);
TEST_CHECK(ckd_add == guf_ckd_add_i8((int8_t)b, (int8_t)a)); TEST_CHECK(ckd_add == guf_ckd_add_i8((int8_t)b, (int8_t)a));
if (add_res > INT8_MAX) { if (add_res > INT8_MAX) {
TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW_POS);
int8_t saturated, saturated2; int8_t saturated, saturated2;
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(saturated == INT8_MAX); TEST_CHECK(saturated == INT8_MAX);
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(saturated == saturated2); TEST_CHECK(saturated == saturated2);
int8_t wrapped, wrapped2; int8_t wrapped, wrapped2;
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MIN + (add_res % (INT8_MAX + 1))); TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MIN + (add_res % (INT8_MAX + 1)));
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(wrapped == wrapped2); TEST_CHECK(wrapped == wrapped2);
} }
else if (add_res < INT8_MIN) { else if (add_res < INT8_MIN) {
TEST_CHECK(ckd_add == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW_NEG);
int8_t saturated, saturated2; int8_t saturated, saturated2;
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(saturated == INT8_MIN); TEST_CHECK(saturated == INT8_MIN);
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(saturated == saturated2); TEST_CHECK(saturated == saturated2);
int8_t wrapped, wrapped2; int8_t wrapped, wrapped2;
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MAX - (-add_res % (-INT8_MIN + 1))); TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MAX - (-add_res % (-INT8_MIN + 1)));
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(wrapped == wrapped2); TEST_CHECK(wrapped == wrapped2);
} }
else { else {
@ -73,20 +73,20 @@ void CkdIntTest::test_ckd()
const int32_t sub_res = a - b; const int32_t sub_res = a - b;
const guf_math_ckd_result ckd_sub = guf_ckd_sub_i8((int8_t)a, (int8_t)b); const guf_math_ckd_result ckd_sub = guf_ckd_sub_i8((int8_t)a, (int8_t)b);
if (sub_res > INT8_MAX) { if (sub_res > INT8_MAX) {
TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW_POS);
int8_t saturated; int8_t saturated;
TEST_CHECK(guf_saturating_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_saturating_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(saturated == INT8_MAX); TEST_CHECK(saturated == INT8_MAX);
int8_t wrapped; int8_t wrapped;
TEST_CHECK(guf_wrapping_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MIN + (sub_res % (INT8_MAX + 1))); TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MIN + (sub_res % (INT8_MAX + 1)));
} else if (sub_res < INT8_MIN) { } else if (sub_res < INT8_MIN) {
TEST_CHECK(ckd_sub == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW_NEG);
int8_t saturated; int8_t saturated;
TEST_CHECK(guf_saturating_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_saturating_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(saturated == INT8_MIN); TEST_CHECK(saturated == INT8_MIN);
int8_t wrapped; int8_t wrapped;
TEST_CHECK(guf_wrapping_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_wrapping_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MAX - (-sub_res % (-INT8_MIN + 1))); TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MAX - (-sub_res % (-INT8_MIN + 1)));
} else { } else {
TEST_CHECK(ckd_sub == GUF_MATH_CKD_SUCCESS); TEST_CHECK(ckd_sub == GUF_MATH_CKD_SUCCESS);
@ -102,31 +102,31 @@ void CkdIntTest::test_ckd()
const guf_math_ckd_result ckd_mul = guf_ckd_mul_i8((int8_t)a, (int8_t)b); const guf_math_ckd_result ckd_mul = guf_ckd_mul_i8((int8_t)a, (int8_t)b);
TEST_CHECK(ckd_mul == guf_ckd_mul_i8((int8_t)b, (int8_t)a)); TEST_CHECK(ckd_mul == guf_ckd_mul_i8((int8_t)b, (int8_t)a));
if (mul_res > INT8_MAX) { if (mul_res > INT8_MAX) {
TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW_POS);
int8_t saturated, saturated2; int8_t saturated, saturated2;
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(saturated == INT8_MAX); TEST_CHECK(saturated == INT8_MAX);
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(saturated == saturated2); TEST_CHECK(saturated == saturated2);
int8_t wrapped, wrapped2; int8_t wrapped, wrapped2;
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(wrapped == wrapped2); TEST_CHECK(wrapped == wrapped2);
// TODO: check wrapped // TODO: check wrapped
} else if (mul_res < INT8_MIN) { } else if (mul_res < INT8_MIN) {
TEST_CHECK(ckd_mul == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW_NEG);
int8_t saturated, saturated2; int8_t saturated, saturated2;
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(saturated == INT8_MIN); TEST_CHECK(saturated == INT8_MIN);
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(saturated == saturated2); TEST_CHECK(saturated == saturated2);
int8_t wrapped, wrapped2; int8_t wrapped, wrapped2;
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(wrapped == wrapped2); TEST_CHECK(wrapped == wrapped2);
// TODO: check wrapped // TODO: check wrapped
} else { } else {
@ -148,10 +148,10 @@ void CkdIntTest::test_ckd()
} }
int8_t mul_i8_res = -1; int8_t mul_i8_res = -1;
TEST_CHECK(guf_wrapping_mul_i8(42, 5, &mul_i8_res) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_mul_i8(42, 5, &mul_i8_res) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(mul_i8_res == -46); TEST_CHECK(mul_i8_res == -46);
mul_i8_res = -1; mul_i8_res = -1;
TEST_CHECK(guf_wrapping_mul_i8(5, 42, &mul_i8_res) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_mul_i8(5, 42, &mul_i8_res) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(mul_i8_res == -46); TEST_CHECK(mul_i8_res == -46);
/* /*
@ -167,10 +167,10 @@ void CkdIntTest::test_ckd()
*/ */
int32_t mul_i32_res = -1; int32_t mul_i32_res = -1;
TEST_CHECK(guf_wrapping_mul_i32(42002718, 314159265, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_mul_i32(42002718, 314159265, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(mul_i32_res == -972735522); TEST_CHECK(mul_i32_res == -972735522);
mul_i32_res = -1; mul_i32_res = -1;
TEST_CHECK(guf_wrapping_mul_i32(314159265, 42002718, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_mul_i32(314159265, 42002718, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(mul_i32_res == -972735522); TEST_CHECK(mul_i32_res == -972735522);
mul_i32_res = 12345; mul_i32_res = 12345;
@ -202,14 +202,14 @@ void CkdIntTest::test_ckd()
TEST_CHECK(mul_i32_res == 1693839360); TEST_CHECK(mul_i32_res == 1693839360);
ptrdiff_t ptrdiff_res = -1234; ptrdiff_t ptrdiff_res = -1234;
TEST_CHECK(guf_saturating_add_ptrdiff_t(PTRDIFF_MAX, 1, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_saturating_add_ptrdiff_t(PTRDIFF_MAX, 1, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(ptrdiff_res == PTRDIFF_MAX); TEST_CHECK(ptrdiff_res == PTRDIFF_MAX);
TEST_CHECK(guf_saturating_add_ptrdiff_t(PTRDIFF_MIN, -1, &ptrdiff_res) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_saturating_add_ptrdiff_t(PTRDIFF_MIN, -1, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(ptrdiff_res == PTRDIFF_MIN); TEST_CHECK(ptrdiff_res == PTRDIFF_MIN);
TEST_CHECK(guf_saturating_mul_ptrdiff_t(PTRDIFF_MAX, 2, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_saturating_mul_ptrdiff_t(PTRDIFF_MAX, 2, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(ptrdiff_res == PTRDIFF_MAX); TEST_CHECK(ptrdiff_res == PTRDIFF_MAX);
TEST_CHECK(guf_saturating_mul_ptrdiff_t(PTRDIFF_MIN, 2, &ptrdiff_res) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_saturating_mul_ptrdiff_t(PTRDIFF_MIN, 2, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(ptrdiff_res == PTRDIFF_MIN); TEST_CHECK(ptrdiff_res == PTRDIFF_MIN);
} }
@ -220,12 +220,12 @@ void CkdIntTest::test_ckd_uint()
const int32_t add_res = a + b; const int32_t add_res = a + b;
const guf_math_ckd_result ckd_add = guf_ckd_add_u8((uint8_t)a, (uint8_t)b); const guf_math_ckd_result ckd_add = guf_ckd_add_u8((uint8_t)a, (uint8_t)b);
if (add_res > UINT8_MAX) { if (add_res > UINT8_MAX) {
TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW_POS);
uint8_t saturated; uint8_t saturated;
TEST_CHECK(guf_saturating_add_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_saturating_add_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(saturated == UINT8_MAX); TEST_CHECK(saturated == UINT8_MAX);
uint8_t wrapped; uint8_t wrapped;
TEST_CHECK(guf_wrapping_add_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_add_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(static_cast<int32_t>(wrapped) == 0 + (add_res % (UINT8_MAX + 1))); TEST_CHECK(static_cast<int32_t>(wrapped) == 0 + (add_res % (UINT8_MAX + 1)));
} }
else { else {
@ -241,12 +241,12 @@ void CkdIntTest::test_ckd_uint()
const int32_t sub_res = a - b; const int32_t sub_res = a - b;
const guf_math_ckd_result ckd_sub = guf_ckd_sub_u8((uint8_t)a, (uint8_t)b); const guf_math_ckd_result ckd_sub = guf_ckd_sub_u8((uint8_t)a, (uint8_t)b);
if (sub_res < 0) { if (sub_res < 0) {
TEST_CHECK(ckd_sub == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW_NEG);
uint8_t saturated; uint8_t saturated;
TEST_CHECK(guf_saturating_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_saturating_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(saturated == 0); TEST_CHECK(saturated == 0);
uint8_t wrapped; uint8_t wrapped;
TEST_CHECK(guf_wrapping_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW); TEST_CHECK(guf_wrapping_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_NEG);
TEST_CHECK(wrapped == static_cast<uint8_t>(static_cast<uint8_t>(a) - static_cast<uint8_t>(b))); TEST_CHECK(wrapped == static_cast<uint8_t>(static_cast<uint8_t>(a) - static_cast<uint8_t>(b)));
} else { } else {
TEST_CHECK(ckd_sub == GUF_MATH_CKD_SUCCESS); TEST_CHECK(ckd_sub == GUF_MATH_CKD_SUCCESS);
@ -261,12 +261,12 @@ void CkdIntTest::test_ckd_uint()
const int32_t mul_res = a * b; const int32_t mul_res = a * b;
const guf_math_ckd_result ckd_mul = guf_ckd_mul_u8((uint8_t)a, (uint8_t)b); const guf_math_ckd_result ckd_mul = guf_ckd_mul_u8((uint8_t)a, (uint8_t)b);
if (mul_res > UINT8_MAX) { if (mul_res > UINT8_MAX) {
TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW_POS);
uint8_t saturated; uint8_t saturated;
TEST_CHECK(guf_saturating_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_saturating_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(saturated == UINT8_MAX); TEST_CHECK(saturated == UINT8_MAX);
uint8_t wrapped; uint8_t wrapped;
TEST_CHECK(guf_wrapping_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW); TEST_CHECK(guf_wrapping_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW_POS);
TEST_CHECK(wrapped == static_cast<uint8_t>(static_cast<uint8_t>(a) * static_cast<uint8_t>(b))); TEST_CHECK(wrapped == static_cast<uint8_t>(static_cast<uint8_t>(a) * static_cast<uint8_t>(b)));
} else { } else {
TEST_CHECK(ckd_mul == GUF_MATH_CKD_SUCCESS); TEST_CHECK(ckd_mul == GUF_MATH_CKD_SUCCESS);

View File

@ -32,7 +32,7 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b)
{{ {{
if (b > 0 && a > {int_max} - b) {{ if (b > 0 && a > {int_max} - b) {{
return GUF_MATH_CKD_OVERFLOW; return GUF_MATH_CKD_OVERFLOW_POS;
}} else {{ }} else {{
return GUF_MATH_CKD_SUCCESS; return GUF_MATH_CKD_SUCCESS;
}} }}
@ -40,7 +40,7 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b)
{{ {{
if (b > a) {{ if (b > a) {{
return GUF_MATH_CKD_UNDERFLOW; return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{ }} else {{
return GUF_MATH_CKD_SUCCESS; return GUF_MATH_CKD_SUCCESS;
}} }}
@ -48,7 +48,7 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b)
{{ {{
const {type} c = 1u * a * b; const {type} c = 1u * a * b;
return a != 0 && ((1u * c / a) != b) ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; return a != 0 && ((1u * c / a) != b) ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
}} }}
""") """)
@ -62,9 +62,9 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_{type_abbr}({type} a, {type} b)
{{ {{
if (b > 0 && a > {int_max} - b) {{ if (b > 0 && a > {int_max} - b) {{
return GUF_MATH_CKD_OVERFLOW; return GUF_MATH_CKD_OVERFLOW_POS;
}} else if (b < 0 && a < {int_min} - b) {{ }} else if (b < 0 && a < {int_min} - b) {{
return GUF_MATH_CKD_UNDERFLOW; return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{ }} else {{
return GUF_MATH_CKD_SUCCESS; return GUF_MATH_CKD_SUCCESS;
}} }}
@ -72,9 +72,9 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_{type_abbr}({type} a, {type} b)
{{ {{
if (b < 0 && a > {int_max} + b) {{ if (b < 0 && a > {int_max} + b) {{
return GUF_MATH_CKD_OVERFLOW; return GUF_MATH_CKD_OVERFLOW_POS;
}} else if (b > 0 && a < {int_min} + b) {{ }} else if (b > 0 && a < {int_min} + b) {{
return GUF_MATH_CKD_UNDERFLOW; return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{ }} else {{
return GUF_MATH_CKD_SUCCESS; return GUF_MATH_CKD_SUCCESS;
}} }}
@ -83,19 +83,19 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
{{ {{
if (b > 0) {{ if (b > 0) {{
if (a > {int_max} / b) {{ if (a > {int_max} / b) {{
return GUF_MATH_CKD_OVERFLOW; return GUF_MATH_CKD_OVERFLOW_POS;
}} else if (a < {int_min} / b) {{ }} else if (a < {int_min} / b) {{
return GUF_MATH_CKD_UNDERFLOW; return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{ }} else {{
return GUF_MATH_CKD_SUCCESS; return GUF_MATH_CKD_SUCCESS;
}} }}
}} else if (b < 0) {{ }} else if (b < 0) {{
if ({int_min} != -{int_max} && b == -1) {{ // Prevent potential ({int_min} / b) overflow for b == -1 if ({int_min} != -{int_max} && b == -1) {{ // Prevent potential ({int_min} / b) overflow for b == -1
return a == {int_min} ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; return a == {int_min} ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
}} else if (a < {int_max} / b) {{ }} else if (a < {int_max} / b) {{
return GUF_MATH_CKD_OVERFLOW; return GUF_MATH_CKD_OVERFLOW_POS;
}} else if (a > {int_min} / b) {{ }} else if (a > {int_min} / b) {{
return GUF_MATH_CKD_UNDERFLOW; return GUF_MATH_CKD_OVERFLOW_NEG;
}} else {{ }} else {{
return GUF_MATH_CKD_SUCCESS; return GUF_MATH_CKD_SUCCESS;
}} }}
@ -125,10 +125,10 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
case GUF_MATH_CKD_SUCCESS: case GUF_MATH_CKD_SUCCESS:
*result = a + b; *result = a + b;
break; break;
case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max}; *result = {int_max};
break; break;
case GUF_MATH_CKD_UNDERFLOW: case GUF_MATH_CKD_OVERFLOW_NEG:
*result = {int_min}; *result = {int_min};
break; break;
default: default:
@ -145,10 +145,10 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
case GUF_MATH_CKD_SUCCESS: case GUF_MATH_CKD_SUCCESS:
*result = a - b; *result = a - b;
break; break;
case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max}; *result = {int_max};
break; break;
case GUF_MATH_CKD_UNDERFLOW: case GUF_MATH_CKD_OVERFLOW_NEG:
*result = {int_min}; *result = {int_min};
break; break;
default: default:
@ -165,10 +165,10 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
case GUF_MATH_CKD_SUCCESS: case GUF_MATH_CKD_SUCCESS:
*result = a * b; *result = a * b;
break; break;
case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max}; *result = {int_max};
break; break;
case GUF_MATH_CKD_UNDERFLOW: case GUF_MATH_CKD_OVERFLOW_NEG:
*result = {int_min}; *result = {int_min};
break; break;
default: default:
@ -186,10 +186,10 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
case GUF_MATH_CKD_SUCCESS: case GUF_MATH_CKD_SUCCESS:
*result = a + b; *result = a + b;
break; break;
case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_OVERFLOW_POS:
*result = (a + {int_min}) + (b + {int_min}); *result = (a + {int_min}) + (b + {int_min});
break; break;
case GUF_MATH_CKD_UNDERFLOW: case GUF_MATH_CKD_OVERFLOW_NEG:
*result = (a - {int_min}) + (b - {int_min}); *result = (a - {int_min}) + (b - {int_min});
break; break;
default: default:
@ -206,11 +206,11 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
case GUF_MATH_CKD_SUCCESS: case GUF_MATH_CKD_SUCCESS:
*result = a - b; *result = a - b;
break; break;
case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_OVERFLOW_POS:
GUF_ASSERT(b < 0); GUF_ASSERT(b < 0);
*result = (a + {int_min}) - (b - {int_min}); // TODO: not sure *result = (a + {int_min}) - (b - {int_min}); // TODO: not sure
break; break;
case GUF_MATH_CKD_UNDERFLOW: case GUF_MATH_CKD_OVERFLOW_NEG:
GUF_ASSERT(b > 0); GUF_ASSERT(b > 0);
*result = (a - {int_min}) - (b + {int_min}); // TODO: not sure *result = (a - {int_min}) - (b + {int_min}); // TODO: not sure
break; break;
@ -228,8 +228,8 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
case GUF_MATH_CKD_SUCCESS: case GUF_MATH_CKD_SUCCESS:
*result = a * b; *result = a * b;
break; break;
case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_OVERFLOW_POS:
case GUF_MATH_CKD_UNDERFLOW: {{ case GUF_MATH_CKD_OVERFLOW_NEG: {{
{uint_type} res = 1u * ({uint_type})a * ({uint_type})b; {uint_type} res = 1u * ({uint_type})a * ({uint_type})b;
if (res > {int_max}) {{ // This is the fix for implementation defined conversion from unsigned to signed. if (res > {int_max}) {{ // This is the fix for implementation defined conversion from unsigned to signed.
const {uint_type} mod = (1u * ({uint_type}){int_max} + 1u); const {uint_type} mod = (1u * ({uint_type}){int_max} + 1u);
@ -263,13 +263,13 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_{type_abbr}({type} a, {type} b, {type} *result)
{{ {{
const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b); const guf_math_ckd_result check = guf_ckd_add_{type_abbr}(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
if (result) {{ if (result) {{
switch (check) {{ switch (check) {{
case GUF_MATH_CKD_SUCCESS: case GUF_MATH_CKD_SUCCESS:
*result = a + b; *result = a + b;
break; break;
case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max}; *result = {int_max};
break; break;
default: default:
@ -281,13 +281,13 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_{type_abbr}({type} a, {type} b, {type} *result)
{{ {{
const guf_math_ckd_result check = guf_ckd_sub_{type_abbr}(a, b); const guf_math_ckd_result check = guf_ckd_sub_{type_abbr}(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_UNDERFLOW); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_NEG);
if (result) {{ if (result) {{
switch (check) {{ switch (check) {{
case GUF_MATH_CKD_SUCCESS: case GUF_MATH_CKD_SUCCESS:
*result = a - b; *result = a - b;
break; break;
case GUF_MATH_CKD_UNDERFLOW: case GUF_MATH_CKD_OVERFLOW_NEG:
*result = 0; *result = 0;
break; break;
default: default:
@ -299,13 +299,13 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> Tuple[str, s
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result)
{{ {{
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b); const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
if (result) {{ if (result) {{
switch (check) {{ switch (check) {{
case GUF_MATH_CKD_SUCCESS: case GUF_MATH_CKD_SUCCESS:
*result = a * b; *result = a * b;
break; break;
case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_OVERFLOW_POS:
*result = {int_max}; *result = {int_max};
break; break;
default: default:
@ -404,7 +404,7 @@ if __name__ == "__main__":
#define GUF_MATH_CKDINT_H #define GUF_MATH_CKDINT_H
#include "guf_common.h" #include "guf_common.h"
typedef enum guf_math_ckd_result {GUF_MATH_CKD_SUCCESS = 0, GUF_MATH_CKD_OVERFLOW, GUF_MATH_CKD_UNDERFLOW} guf_math_ckd_result; typedef enum guf_math_ckd_result {GUF_MATH_CKD_SUCCESS = 0, GUF_MATH_CKD_OVERFLOW_POS, GUF_MATH_CKD_OVERFLOW_NEG} guf_math_ckd_result;
""")) """))
@ -416,9 +416,9 @@ if __name__ == "__main__":
print("#if defined(GUF_MATH_CKDINT_IMPL) || defined(GUF_MATH_CKDINT_IMPL_STATIC)") print("#if defined(GUF_MATH_CKDINT_IMPL) || defined(GUF_MATH_CKDINT_IMPL_STATIC)")
print('#include "guf_assert.h"') print('#include "guf_assert.h"')
print(code_impl) print(code_impl)
print("#endif\n") print("#endif /* End impl */\n")
print("#endif") print("#endif /* End header-guard */\n")
print("#undef GUF_MATH_CKDINT_KWRDS") print("#undef GUF_MATH_CKDINT_KWRDS")
print("#undef GUF_MATH_CKDINT_IMPL") print("#undef GUF_MATH_CKDINT_IMPL")