aboutsummaryrefslogtreecommitdiff
path: root/src/bigint.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-08-16 19:07:35 -0400
committerAndrew Kelley <superjoe30@gmail.com>2017-08-16 19:07:35 -0400
commit6a98bf3dba6f3ed5b40fe7899899e2a792028be4 (patch)
tree9c4e4eb61e70ad0853119c12882c108631b7ad4b /src/bigint.cpp
parentcf46cd5f2b0f87430185c5d89056321d16f42d58 (diff)
downloadzig-6a98bf3dba6f3ed5b40fe7899899e2a792028be4.tar.gz
zig-6a98bf3dba6f3ed5b40fe7899899e2a792028be4.zip
compiler_rt implementations for __fixuns* functions
* add u128 and i128 integer types * add f128 floating point type * implement big integer multiplication (See #405)
Diffstat (limited to 'src/bigint.cpp')
-rw-r--r--src/bigint.cpp84
1 files changed, 70 insertions, 14 deletions
diff --git a/src/bigint.cpp b/src/bigint.cpp
index db55d25fc9..5679d2041a 100644
--- a/src/bigint.cpp
+++ b/src/bigint.cpp
@@ -373,7 +373,6 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {
bigint_normalize(dest);
return;
}
- // TODO this code path is untested
size_t i = 1;
uint64_t first_digit = dest->data.digit;
dest->data.digits = allocate_nonzero<uint64_t>(max(op1->digit_count, op2->digit_count) + 1);
@@ -397,17 +396,14 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {
}
dest->data.digits[i] = x;
- x += 1;
+ i += 1;
if (!found_digit) {
- break;
+ dest->digit_count = i;
+ bigint_normalize(dest);
+ return;
}
}
- if (overflow > 0) {
- dest->data.digits[i] = overflow;
- }
- bigint_normalize(dest);
- return;
}
const BigInt *op_pos;
const BigInt *op_neg;
@@ -500,12 +496,49 @@ static void mul_overflow(uint64_t x, uint64_t y, uint64_t *result, uint64_t *car
*carry = 0;
return;
}
- zig_panic("TODO bigint_mul with big numbers");
- //unsigned __int128 big_x = x;
- //unsigned __int128 big_y = y;
- //unsigned __int128 big_result = big_x * big_y;
- //*carry = big_result >> 64;
+ unsigned __int128 big_x = x;
+ unsigned __int128 big_y = y;
+ unsigned __int128 big_result = big_x * big_y;
+ *carry = big_result >> 64;
+}
+
+static void mul_scalar(BigInt *dest, const BigInt *op, uint64_t scalar) {
+ bigint_init_unsigned(dest, 0);
+
+ BigInt bi_64;
+ bigint_init_unsigned(&bi_64, 64);
+
+ const uint64_t *op_digits = bigint_ptr(op);
+ size_t i = op->digit_count - 1;
+
+ for (;;) {
+ BigInt shifted;
+ bigint_shl(&shifted, dest, &bi_64);
+
+ uint64_t result_scalar;
+ uint64_t carry_scalar;
+ mul_overflow(scalar, op_digits[i], &result_scalar, &carry_scalar);
+
+ BigInt result;
+ bigint_init_unsigned(&result, result_scalar);
+
+ BigInt carry;
+ bigint_init_unsigned(&carry, carry_scalar);
+
+ BigInt carry_shifted;
+ bigint_shl(&carry_shifted, &carry, &bi_64);
+
+ BigInt tmp;
+ bigint_add(&tmp, &shifted, &carry_shifted);
+
+ bigint_add(dest, &tmp, &result);
+
+ if (i == 0) {
+ break;
+ }
+ i -= 1;
+ }
}
void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2) {
@@ -523,7 +556,30 @@ void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2) {
bigint_normalize(dest);
return;
}
- zig_panic("TODO bigint_mul with big numbers");
+
+ bigint_init_unsigned(dest, 0);
+
+ BigInt bi_64;
+ bigint_init_unsigned(&bi_64, 64);
+
+ size_t i = op2->digit_count - 1;
+ for (;;) {
+ BigInt shifted;
+ bigint_shl(&shifted, dest, &bi_64);
+
+ BigInt scalar_result;
+ mul_scalar(&scalar_result, op1, op2_digits[i]);
+
+ bigint_add(dest, &scalar_result, &shifted);
+
+ if (i == 0) {
+ break;
+ }
+ i -= 1;
+ }
+
+ dest->is_negative = (op1->is_negative != op2->is_negative);
+ bigint_normalize(dest);
}
void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) {