From c6cd919a1852e4737fb99aa952eaca8c4d0a51df Mon Sep 17 00:00:00 2001 From: Jan Philipp Hafer Date: Tue, 15 Feb 2022 01:43:59 +0100 Subject: [PATCH] stage1: fix comptime saturation subtraction - also simplifies code - adding a few more tests closes #10870 --- src/stage1/bigint.cpp | 28 ++++++++++++------------- test/behavior/saturating_arithmetic.zig | 21 ++++++++++++++++++- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/stage1/bigint.cpp b/src/stage1/bigint.cpp index eab0f037cf..02f7c19367 100644 --- a/src/stage1/bigint.cpp +++ b/src/stage1/bigint.cpp @@ -476,9 +476,15 @@ void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) { /// signed bounds are [-2^(bit_count-1)..2^(bit_count-1)-1] /// unsigned bounds are [0..2^bit_count-1] void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed) { + bool is_negative = dest->is_negative; + // unsigned and dest->is_negative => clamp to 0 + if (is_negative && !is_signed) { + bigint_deinit(dest); + bigint_init_unsigned(dest, 0); + return; + } // compute the number of bits required to store the value, and use that // to decide whether to clamp the result - bool is_negative = dest->is_negative; // to workaround the fact this bits_needed calculation would yield 65 or more for // all negative numbers, set is_negative to false. this is a cheap way to find // bits_needed(abs(dest)). @@ -512,19 +518,13 @@ void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed) *dest = bound_sub_one; } } else { - if(is_negative) { - bigint_deinit(dest); - bigint_init_unsigned(dest, 0); - return; // skips setting is_negative which would be invalid - } else { - BigInt bound; - bigint_shl(&bound, &one, &bit_count_big); - BigInt bound_sub_one; - bigint_sub(&bound_sub_one, &bound, &one); - bigint_deinit(&bound); - bigint_deinit(dest); - *dest = bound_sub_one; - } + BigInt bound; + bigint_shl(&bound, &one, &bit_count_big); + BigInt bound_sub_one; + bigint_sub(&bound_sub_one, &bound, &one); + bigint_deinit(&bound); + bigint_deinit(dest); + *dest = bound_sub_one; } } dest->is_negative = is_negative; diff --git a/test/behavior/saturating_arithmetic.zig b/test/behavior/saturating_arithmetic.zig index 94e1f1ae81..c596c50a15 100644 --- a/test/behavior/saturating_arithmetic.zig +++ b/test/behavior/saturating_arithmetic.zig @@ -8,12 +8,17 @@ test "saturating add" { const S = struct { fn doTheTest() !void { try testSatAdd(i8, -3, 10, 7); + try testSatAdd(i8, 3, -10, -7); try testSatAdd(i8, -128, -128, -128); try testSatAdd(i2, 1, 1, 1); + try testSatAdd(i2, 1, -1, 0); + try testSatAdd(i2, -1, -1, -2); try testSatAdd(i64, maxInt(i64), 1, maxInt(i64)); try testSatAdd(i128, maxInt(i128), -maxInt(i128), 0); try testSatAdd(i128, minInt(i128), maxInt(i128), -1); try testSatAdd(i8, 127, 127, 127); + try testSatAdd(u2, 0, 0, 0); + try testSatAdd(u2, 0, 1, 1); try testSatAdd(u8, 3, 10, 13); try testSatAdd(u8, 255, 255, 255); try testSatAdd(u2, 3, 2, 3); @@ -34,7 +39,11 @@ test "saturating add" { comptime try S.doTheTest(); comptime try S.testSatAdd(comptime_int, 0, 0, 0); + comptime try S.testSatAdd(comptime_int, -1, 1, 0); comptime try S.testSatAdd(comptime_int, 3, 2, 5); + comptime try S.testSatAdd(comptime_int, -3, -2, -5); + comptime try S.testSatAdd(comptime_int, 3, -2, 1); + comptime try S.testSatAdd(comptime_int, -3, 2, -1); comptime try S.testSatAdd(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 1119305249183743626545271163355074748512); comptime try S.testSatAdd(comptime_int, 7, -593423721213448152027139550640105366508, -593423721213448152027139550640105366501); } @@ -43,14 +52,20 @@ test "saturating subtraction" { const S = struct { fn doTheTest() !void { try testSatSub(i8, -3, 10, -13); + try testSatSub(i8, -3, -10, 7); try testSatSub(i8, -128, -128, 0); try testSatSub(i8, -1, 127, -128); + try testSatSub(i2, 1, 1, 0); + try testSatSub(i2, 1, -1, 1); + try testSatSub(i2, -2, -2, 0); try testSatSub(i64, minInt(i64), 1, minInt(i64)); try testSatSub(i128, maxInt(i128), -1, maxInt(i128)); try testSatSub(i128, minInt(i128), -maxInt(i128), -1); + try testSatSub(u2, 0, 0, 0); + try testSatSub(u2, 0, 1, 0); + try testSatSub(u5, 0, 31, 0); try testSatSub(u8, 10, 3, 7); try testSatSub(u8, 0, 255, 0); - try testSatSub(u5, 0, 31, 0); try testSatSub(u128, 0, maxInt(u128), 0); } @@ -67,7 +82,11 @@ test "saturating subtraction" { comptime try S.doTheTest(); comptime try S.testSatSub(comptime_int, 0, 0, 0); + comptime try S.testSatSub(comptime_int, 1, 1, 0); comptime try S.testSatSub(comptime_int, 3, 2, 1); + comptime try S.testSatSub(comptime_int, -3, -2, -1); + comptime try S.testSatSub(comptime_int, 3, -2, 5); + comptime try S.testSatSub(comptime_int, -3, 2, -5); comptime try S.testSatSub(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 182846383813587550256162760261375991602); comptime try S.testSatSub(comptime_int, 7, -593423721213448152027139550640105366508, 593423721213448152027139550640105366515); }