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)...@@ -60,6 +60,9 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count)
60 bigint_init_unsigned(dest, 0);60 bigint_init_unsigned(dest, 0);
61 return;61 return;
62 }62 }
63
64 BigInt pos_op = {0};
65
63 if (op->is_negative) {66 if (op->is_negative) {
64 BigInt negated = {0};67 BigInt negated = {0};
65 bigint_negate(&negated, op);68 bigint_negate(&negated, op);
...@@ -70,13 +73,14 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count)...@@ -70,13 +73,14 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count)
70 BigInt one = {0};73 BigInt one = {0};
71 bigint_init_unsigned(&one, 1);74 bigint_init_unsigned(&one, 1);
7275
73 bigint_add(dest, &inverted, &one);76 bigint_add(&pos_op, &inverted, &one);
74 return;77 } else {
78 bigint_init_bigint(&pos_op, op);
75 }79 }
7680
77 dest->is_negative = false;81 dest->is_negative = false;
78 const uint64_t *op_digits = bigint_ptr(op);82 const uint64_t *op_digits = bigint_ptr(&pos_op);
79 if (op->digit_count == 1) {83 if (pos_op.digit_count == 1) {
80 dest->data.digit = op_digits[0];84 dest->data.digit = op_digits[0];
81 if (bit_count < 64) {85 if (bit_count < 64) {
82 dest->data.digit &= (1ULL << bit_count) - 1;86 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)...@@ -98,11 +102,11 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count)
98 }102 }
99 dest->data.digits = heap::c_allocator.allocate_nonzero<uint64_t>(dest->digit_count);103 dest->data.digits = heap::c_allocator.allocate_nonzero<uint64_t>(dest->digit_count);
100 for (size_t i = 0; i < digits_to_copy; i += 1) {104 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;
102 dest->data.digits[i] = digit;106 dest->data.digits[i] = digit;
103 }107 }
104 if (leftover_bits != 0) {108 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;
106 dest->data.digits[digits_to_copy] = digit & ((1ULL << leftover_bits) - 1);110 dest->data.digits[digits_to_copy] = digit & ((1ULL << leftover_bits) - 1);
107 }111 }
108 bigint_normalize(dest);112 bigint_normalize(dest);
...@@ -469,18 +473,18 @@ void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) {...@@ -469,18 +473,18 @@ void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) {
469}473}
470474
471/// clamps op within bit_count/signedness boundaries475/// clamps op within bit_count/signedness boundaries
472/// 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]
473/// unsigned bounds are [0..2^bit_count-1] 477/// unsigned bounds are [0..2^bit_count-1]
474void 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) {
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
476 // to decide whether to clamp the result480 // to decide whether to clamp the result
477 bool is_negative = dest->is_negative;481 bool is_negative = dest->is_negative;
478 // to workaround the fact this bits_needed calculation would yield 65 or more for 482 // 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 483 // all negative numbers, set is_negative to false. this is a cheap way to find
480 // bits_needed(abs(dest)). 484 // bits_needed(abs(dest)).
481 dest->is_negative = false;485 dest->is_negative = false;
482 // because we've set is_negative to false, we have to account for the extra bit here486 // 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).
484 size_t full_bits = dest->digit_count * 64;488 size_t full_bits = dest->digit_count * 64;
485 size_t leading_zero_count = bigint_clz(dest, full_bits);489 size_t leading_zero_count = bigint_clz(dest, full_bits);
486 size_t bits_needed = full_bits - leading_zero_count + (is_negative && !is_signed);490 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)...@@ -491,7 +495,7 @@ void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed)
491 bigint_init_unsigned(&one, 1);495 bigint_init_unsigned(&one, 1);
492 BigInt bit_count_big;496 BigInt bit_count_big;
493 bigint_init_unsigned(&bit_count_big, bit_count);497 bigint_init_unsigned(&bit_count_big, bit_count);
494 498
495 if(is_signed) {499 if(is_signed) {
496 if(is_negative) {500 if(is_negative) {
497 BigInt bound;501 BigInt bound;
...@@ -639,25 +643,22 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -639,25 +643,22 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {
639 size_t i = 1;643 size_t i = 1;
640644
641 for (;;) {645 for (;;) {
642 bool found_digit = false;
643 uint64_t x = bigger_op_digits[i];646 uint64_t x = bigger_op_digits[i];
644 uint64_t prev_overflow = overflow;647 uint64_t prev_overflow = overflow;
645 overflow = 0;648 overflow = 0;
646649
647 if (i < smaller_op->digit_count) {650 if (i < smaller_op->digit_count) {
648 found_digit = true;
649 uint64_t digit = smaller_op_digits[i];651 uint64_t digit = smaller_op_digits[i];
650 overflow += sub_u64_overflow(x, digit, &x);652 overflow += sub_u64_overflow(x, digit, &x);
651 }653 }
652 if (sub_u64_overflow(x, prev_overflow, &x)) {654
653 found_digit = true;655 overflow += sub_u64_overflow(x, prev_overflow, &x);
654 overflow += 1;
655 }
656 dest->data.digits[i] = x;656 dest->data.digits[i] = x;
657 i += 1;657 i += 1;
658658
659 if (!found_digit || i >= bigger_op->digit_count)659 if (i >= bigger_op->digit_count) {
660 break;660 break;
661 }
661 }662 }
662 assert(overflow == 0);663 assert(overflow == 0);
663 dest->digit_count = i;664 dest->digit_count = i;