authorgravatar for 94326797+riverbl@users.noreply.github.comriverbl <94326797+riverbl@users.noreply.github.com> 2021-12-26 00:04:48+00:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-01-29 18:12:28+02:00
log54634991a2b9767d20725b20a2c273b6db60a825
treee28b228599f2d1e58a7100b60c182fb3adb2fe6a
parentaa29f4a8037ae74fb2d97793312ef8c5262d025a

stage1: fix issue with bigint_add that caused incorrect results when adding a large and a small comptime_int of differing sign

stage1: fix issue with to_twos_complement that caused a compile error when performing wrapping addition on two signed ints, both of which have the minimum possible value

1 files changed, 22 insertions(+), 21 deletions(-)

src/stage1/bigint.cpp+22-21
......@@ -60,6 +60,9 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count)
6060 bigint_init_unsigned(dest, 0);
6161 return;
6262 }
63
64 BigInt pos_op = {0};
65
6366 if (op->is_negative) {
6467 BigInt negated = {0};
6568 bigint_negate(&negated, op);
......@@ -70,13 +73,14 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count)
7073 BigInt one = {0};
7174 bigint_init_unsigned(&one, 1);
7275
73 bigint_add(dest, &inverted, &one);
74 return;
76 bigint_add(&pos_op, &inverted, &one);
77 } else {
78 bigint_init_bigint(&pos_op, op);
7579 }
7680
7781 dest->is_negative = false;
78 const uint64_t *op_digits = bigint_ptr(op);
79 if (op->digit_count == 1) {
82 const uint64_t *op_digits = bigint_ptr(&pos_op);
83 if (pos_op.digit_count == 1) {
8084 dest->data.digit = op_digits[0];
8185 if (bit_count < 64) {
8286 dest->data.digit &= (1ULL << bit_count) - 1;
......@@ -98,11 +102,11 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count)
98102 }
99103 dest->data.digits = heap::c_allocator.allocate_nonzero<uint64_t>(dest->digit_count);
100104 for (size_t i = 0; i < digits_to_copy; i += 1) {
101 uint64_t digit = (i < op->digit_count) ? op_digits[i] : 0;
105 uint64_t digit = (i < pos_op.digit_count) ? op_digits[i] : 0;
102106 dest->data.digits[i] = digit;
103107 }
104108 if (leftover_bits != 0) {
105 uint64_t digit = (digits_to_copy < op->digit_count) ? op_digits[digits_to_copy] : 0;
109 uint64_t digit = (digits_to_copy < pos_op.digit_count) ? op_digits[digits_to_copy] : 0;
106110 dest->data.digits[digits_to_copy] = digit & ((1ULL << leftover_bits) - 1);
107111 }
108112 bigint_normalize(dest);
......@@ -469,18 +473,18 @@ void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) {
469473}
470474
471475/// clamps op within bit_count/signedness boundaries
472/// signed bounds are [-2^(bit_count-1)..2^(bit_count-1)-1]
473/// unsigned bounds are [0..2^bit_count-1]
476/// signed bounds are [-2^(bit_count-1)..2^(bit_count-1)-1]
477/// unsigned bounds are [0..2^bit_count-1]
474478void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed) {
475 // compute the number of bits required to store the value, and use that
479 // compute the number of bits required to store the value, and use that
476480 // to decide whether to clamp the result
477481 bool is_negative = dest->is_negative;
478 // to workaround the fact this bits_needed calculation would yield 65 or more for
479 // all negative numbers, set is_negative to false. this is a cheap way to find
480 // bits_needed(abs(dest)).
482 // 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 find
484 // bits_needed(abs(dest)).
481485 dest->is_negative = false;
482486 // because we've set is_negative to false, we have to account for the extra bit here
483 // by adding 1 additional bit_needed when (is_negative && !is_signed).
487 // by adding 1 additional bit_needed when (is_negative && !is_signed).
484488 size_t full_bits = dest->digit_count * 64;
485489 size_t leading_zero_count = bigint_clz(dest, full_bits);
486490 size_t bits_needed = full_bits - leading_zero_count + (is_negative && !is_signed);
......@@ -491,7 +495,7 @@ void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed)
491495 bigint_init_unsigned(&one, 1);
492496 BigInt bit_count_big;
493497 bigint_init_unsigned(&bit_count_big, bit_count);
494
498
495499 if(is_signed) {
496500 if(is_negative) {
497501 BigInt bound;
......@@ -639,25 +643,22 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {
639643 size_t i = 1;
640644
641645 for (;;) {
642 bool found_digit = false;
643646 uint64_t x = bigger_op_digits[i];
644647 uint64_t prev_overflow = overflow;
645648 overflow = 0;
646649
647650 if (i < smaller_op->digit_count) {
648 found_digit = true;
649651 uint64_t digit = smaller_op_digits[i];
650652 overflow += sub_u64_overflow(x, digit, &x);
651653 }
652 if (sub_u64_overflow(x, prev_overflow, &x)) {
653 found_digit = true;
654 overflow += 1;
655 }
654
655 overflow += sub_u64_overflow(x, prev_overflow, &x);
656656 dest->data.digits[i] = x;
657657 i += 1;
658658
659 if (!found_digit || i >= bigger_op->digit_count)
659 if (i >= bigger_op->digit_count) {
660660 break;
661 }
661662 }
662663 assert(overflow == 0);
663664 dest->digit_count = i;