authorgravatar for jan.hafer@rwth-aachen.deJan Philipp Hafer <jan.hafer@rwth-aachen.de> 2022-02-15 01:43:59+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-15 10:40:53+02:00
logc6cd919a1852e4737fb99aa952eaca8c4d0a51df
treea836c6d1a7d73dd9c34485ada993dc5ad34eeaaa
parentbe98f30a2d647075564e02791813ddfb599f6cd7

stage1: fix comptime saturation subtraction

- also simplifies code - adding a few more tests closes #10870

2 files changed, 34 insertions(+), 15 deletions(-)

src/stage1/bigint.cpp+14-14
...@@ -476,9 +476,15 @@ void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) {...@@ -476,9 +476,15 @@ void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) {
476/// signed bounds are [-2^(bit_count-1)..2^(bit_count-1)-1]476/// signed bounds are [-2^(bit_count-1)..2^(bit_count-1)-1]
477/// unsigned bounds are [0..2^bit_count-1]477/// unsigned bounds are [0..2^bit_count-1]
478void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed) {478void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed) {
479 bool is_negative = dest->is_negative;
480 // unsigned and dest->is_negative => clamp to 0
481 if (is_negative && !is_signed) {
482 bigint_deinit(dest);
483 bigint_init_unsigned(dest, 0);
484 return;
485 }
479 // compute the number of bits required to store the value, and use that486 // compute the number of bits required to store the value, and use that
480 // to decide whether to clamp the result487 // to decide whether to clamp the result
481 bool is_negative = dest->is_negative;
482 // to workaround the fact this bits_needed calculation would yield 65 or more for488 // to workaround the fact this bits_needed calculation would yield 65 or more for
483 // all negative numbers, set is_negative to false. this is a cheap way to find489 // all negative numbers, set is_negative to false. this is a cheap way to find
484 // bits_needed(abs(dest)).490 // bits_needed(abs(dest)).
...@@ -512,19 +518,13 @@ void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed)...@@ -512,19 +518,13 @@ void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed)
512 *dest = bound_sub_one;518 *dest = bound_sub_one;
513 }519 }
514 } else {520 } else {
515 if(is_negative) {521 BigInt bound;
516 bigint_deinit(dest);522 bigint_shl(&bound, &one, &bit_count_big);
517 bigint_init_unsigned(dest, 0);523 BigInt bound_sub_one;
518 return; // skips setting is_negative which would be invalid524 bigint_sub(&bound_sub_one, &bound, &one);
519 } else {525 bigint_deinit(&bound);
520 BigInt bound;526 bigint_deinit(dest);
521 bigint_shl(&bound, &one, &bit_count_big);527 *dest = bound_sub_one;
522 BigInt bound_sub_one;
523 bigint_sub(&bound_sub_one, &bound, &one);
524 bigint_deinit(&bound);
525 bigint_deinit(dest);
526 *dest = bound_sub_one;
527 }
528 }528 }
529 }529 }
530 dest->is_negative = is_negative;530 dest->is_negative = is_negative;
test/behavior/saturating_arithmetic.zig+20-1
...@@ -8,12 +8,17 @@ test "saturating add" {...@@ -8,12 +8,17 @@ test "saturating add" {
8 const S = struct {8 const S = struct {
9 fn doTheTest() !void {9 fn doTheTest() !void {
10 try testSatAdd(i8, -3, 10, 7);10 try testSatAdd(i8, -3, 10, 7);
11 try testSatAdd(i8, 3, -10, -7);
11 try testSatAdd(i8, -128, -128, -128);12 try testSatAdd(i8, -128, -128, -128);
12 try testSatAdd(i2, 1, 1, 1);13 try testSatAdd(i2, 1, 1, 1);
14 try testSatAdd(i2, 1, -1, 0);
15 try testSatAdd(i2, -1, -1, -2);
13 try testSatAdd(i64, maxInt(i64), 1, maxInt(i64));16 try testSatAdd(i64, maxInt(i64), 1, maxInt(i64));
14 try testSatAdd(i128, maxInt(i128), -maxInt(i128), 0);17 try testSatAdd(i128, maxInt(i128), -maxInt(i128), 0);
15 try testSatAdd(i128, minInt(i128), maxInt(i128), -1);18 try testSatAdd(i128, minInt(i128), maxInt(i128), -1);
16 try testSatAdd(i8, 127, 127, 127);19 try testSatAdd(i8, 127, 127, 127);
20 try testSatAdd(u2, 0, 0, 0);
21 try testSatAdd(u2, 0, 1, 1);
17 try testSatAdd(u8, 3, 10, 13);22 try testSatAdd(u8, 3, 10, 13);
18 try testSatAdd(u8, 255, 255, 255);23 try testSatAdd(u8, 255, 255, 255);
19 try testSatAdd(u2, 3, 2, 3);24 try testSatAdd(u2, 3, 2, 3);
...@@ -34,7 +39,11 @@ test "saturating add" {...@@ -34,7 +39,11 @@ test "saturating add" {
34 comptime try S.doTheTest();39 comptime try S.doTheTest();
3540
36 comptime try S.testSatAdd(comptime_int, 0, 0, 0);41 comptime try S.testSatAdd(comptime_int, 0, 0, 0);
42 comptime try S.testSatAdd(comptime_int, -1, 1, 0);
37 comptime try S.testSatAdd(comptime_int, 3, 2, 5);43 comptime try S.testSatAdd(comptime_int, 3, 2, 5);
44 comptime try S.testSatAdd(comptime_int, -3, -2, -5);
45 comptime try S.testSatAdd(comptime_int, 3, -2, 1);
46 comptime try S.testSatAdd(comptime_int, -3, 2, -1);
38 comptime try S.testSatAdd(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 1119305249183743626545271163355074748512);47 comptime try S.testSatAdd(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 1119305249183743626545271163355074748512);
39 comptime try S.testSatAdd(comptime_int, 7, -593423721213448152027139550640105366508, -593423721213448152027139550640105366501);48 comptime try S.testSatAdd(comptime_int, 7, -593423721213448152027139550640105366508, -593423721213448152027139550640105366501);
40}49}
...@@ -43,14 +52,20 @@ test "saturating subtraction" {...@@ -43,14 +52,20 @@ test "saturating subtraction" {
43 const S = struct {52 const S = struct {
44 fn doTheTest() !void {53 fn doTheTest() !void {
45 try testSatSub(i8, -3, 10, -13);54 try testSatSub(i8, -3, 10, -13);
55 try testSatSub(i8, -3, -10, 7);
46 try testSatSub(i8, -128, -128, 0);56 try testSatSub(i8, -128, -128, 0);
47 try testSatSub(i8, -1, 127, -128);57 try testSatSub(i8, -1, 127, -128);
58 try testSatSub(i2, 1, 1, 0);
59 try testSatSub(i2, 1, -1, 1);
60 try testSatSub(i2, -2, -2, 0);
48 try testSatSub(i64, minInt(i64), 1, minInt(i64));61 try testSatSub(i64, minInt(i64), 1, minInt(i64));
49 try testSatSub(i128, maxInt(i128), -1, maxInt(i128));62 try testSatSub(i128, maxInt(i128), -1, maxInt(i128));
50 try testSatSub(i128, minInt(i128), -maxInt(i128), -1);63 try testSatSub(i128, minInt(i128), -maxInt(i128), -1);
64 try testSatSub(u2, 0, 0, 0);
65 try testSatSub(u2, 0, 1, 0);
66 try testSatSub(u5, 0, 31, 0);
51 try testSatSub(u8, 10, 3, 7);67 try testSatSub(u8, 10, 3, 7);
52 try testSatSub(u8, 0, 255, 0);68 try testSatSub(u8, 0, 255, 0);
53 try testSatSub(u5, 0, 31, 0);
54 try testSatSub(u128, 0, maxInt(u128), 0);69 try testSatSub(u128, 0, maxInt(u128), 0);
55 }70 }
5671
...@@ -67,7 +82,11 @@ test "saturating subtraction" {...@@ -67,7 +82,11 @@ test "saturating subtraction" {
67 comptime try S.doTheTest();82 comptime try S.doTheTest();
6883
69 comptime try S.testSatSub(comptime_int, 0, 0, 0);84 comptime try S.testSatSub(comptime_int, 0, 0, 0);
85 comptime try S.testSatSub(comptime_int, 1, 1, 0);
70 comptime try S.testSatSub(comptime_int, 3, 2, 1);86 comptime try S.testSatSub(comptime_int, 3, 2, 1);
87 comptime try S.testSatSub(comptime_int, -3, -2, -1);
88 comptime try S.testSatSub(comptime_int, 3, -2, 5);
89 comptime try S.testSatSub(comptime_int, -3, 2, -5);
71 comptime try S.testSatSub(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 182846383813587550256162760261375991602);90 comptime try S.testSatSub(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 182846383813587550256162760261375991602);
72 comptime try S.testSatSub(comptime_int, 7, -593423721213448152027139550640105366508, 593423721213448152027139550640105366515);91 comptime try S.testSatSub(comptime_int, 7, -593423721213448152027139550640105366508, 593423721213448152027139550640105366515);
73}92}