aboutsummaryrefslogtreecommitdiffstats
path: root/src/data.c
diff options
context:
space:
mode:
authorPaul Eggert2019-11-13 12:10:31 -0800
committerPaul Eggert2019-11-13 13:10:09 -0800
commit02e637ecca3b1419d2a6c433eca72c5728c65051 (patch)
treef3a213c730c7893513a69b5f9e2e69a429f837da /src/data.c
parentff10e9517d98aa606e007d3aa4d5aef1c423ab77 (diff)
downloademacs-02e637ecca3b1419d2a6c433eca72c5728c65051.tar.gz
emacs-02e637ecca3b1419d2a6c433eca72c5728c65051.zip
Refactor bignum multiplication, exponentiation
This doesn’t alter behavior, and simplifies the next commit. * src/bignum.c (GMP_NLIMBS_MAX, NLIMBS_LIMIT, emacs_mpz_size) (emacs_mpz_mul, emacs_mpz_mul_2exp, emacs_mpz_pow_ui): Move here ... * src/data.c: ... from here.
Diffstat (limited to 'src/data.c')
-rw-r--r--src/data.c74
1 files changed, 0 insertions, 74 deletions
diff --git a/src/data.c b/src/data.c
index 649dc174f90..9efcd72f93e 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2352,80 +2352,6 @@ bool-vector. IDX starts at 0. */)
2352 return newelt; 2352 return newelt;
2353} 2353}
2354 2354
2355/* GMP tests for this value and aborts (!) if it is exceeded.
2356 This is as of GMP 6.1.2 (2016); perhaps future versions will differ. */
2357enum { GMP_NLIMBS_MAX = min (INT_MAX, ULONG_MAX / GMP_NUMB_BITS) };
2358
2359/* An upper bound on limb counts, needed to prevent libgmp and/or
2360 Emacs from aborting or otherwise misbehaving. This bound applies
2361 to estimates of mpz_t sizes before the mpz_t objects are created,
2362 as opposed to integer-width which operates on mpz_t values after
2363 creation and before conversion to Lisp bignums. */
2364enum
2365 {
2366 NLIMBS_LIMIT = min (min (/* libgmp needs to store limb counts. */
2367 GMP_NLIMBS_MAX,
2368
2369 /* Size calculations need to work. */
2370 min (PTRDIFF_MAX, SIZE_MAX) / sizeof (mp_limb_t)),
2371
2372 /* Emacs puts bit counts into fixnums. */
2373 MOST_POSITIVE_FIXNUM / GMP_NUMB_BITS)
2374 };
2375
2376/* Like mpz_size, but tell the compiler the result is a nonnegative int. */
2377
2378static int
2379emacs_mpz_size (mpz_t const op)
2380{
2381 mp_size_t size = mpz_size (op);
2382 eassume (0 <= size && size <= INT_MAX);
2383 return size;
2384}
2385
2386/* Wrappers to work around GMP limitations. As of GMP 6.1.2 (2016),
2387 the library code aborts when a number is too large. These wrappers
2388 avoid the problem for functions that can return numbers much larger
2389 than their arguments. For slowly-growing numbers, the integer
2390 width checks in bignum.c should suffice. */
2391
2392static void
2393emacs_mpz_mul (mpz_t rop, mpz_t const op1, mpz_t const op2)
2394{
2395 if (NLIMBS_LIMIT - emacs_mpz_size (op1) < emacs_mpz_size (op2))
2396 overflow_error ();
2397 mpz_mul (rop, op1, op2);
2398}
2399
2400static void
2401emacs_mpz_mul_2exp (mpz_t rop, mpz_t const op1, EMACS_INT op2)
2402{
2403 /* Fudge factor derived from GMP 6.1.2, to avoid an abort in
2404 mpz_mul_2exp (look for the '+ 1' in its source code). */
2405 enum { mul_2exp_extra_limbs = 1 };
2406 enum { lim = min (NLIMBS_LIMIT, GMP_NLIMBS_MAX - mul_2exp_extra_limbs) };
2407
2408 EMACS_INT op2limbs = op2 / GMP_NUMB_BITS;
2409 if (lim - emacs_mpz_size (op1) < op2limbs)
2410 overflow_error ();
2411 mpz_mul_2exp (rop, op1, op2);
2412}
2413
2414static void
2415emacs_mpz_pow_ui (mpz_t rop, mpz_t const base, unsigned long exp)
2416{
2417 /* This fudge factor is derived from GMP 6.1.2, to avoid an abort in
2418 mpz_n_pow_ui (look for the '5' in its source code). */
2419 enum { pow_ui_extra_limbs = 5 };
2420 enum { lim = min (NLIMBS_LIMIT, GMP_NLIMBS_MAX - pow_ui_extra_limbs) };
2421
2422 int nbase = emacs_mpz_size (base), n;
2423 if (INT_MULTIPLY_WRAPV (nbase, exp, &n) || lim < n)
2424 overflow_error ();
2425 mpz_pow_ui (rop, base, exp);
2426}
2427
2428
2429/* Arithmetic functions */ 2355/* Arithmetic functions */
2430 2356
2431Lisp_Object 2357Lisp_Object