aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2018-08-27 21:27:50 -0700
committerPaul Eggert2018-08-27 21:45:22 -0700
commit9abaf5f3581ecb76f30e8a6e7ee0e9633c133d1c (patch)
treec39260a6e26845b0a1307be98b38581468925c58 /src
parentbf1b147b55e1328efca6e40181e79dd9a369895d (diff)
downloademacs-9abaf5f3581ecb76f30e8a6e7ee0e9633c133d1c.tar.gz
emacs-9abaf5f3581ecb76f30e8a6e7ee0e9633c133d1c.zip
Modularize bignums better
* src/bignum.c, src/bignum.h: New files. Only modules that need to know how bignums are implemented should include bignum.h. Currently these are alloc.c, bignum.c (of course), data.c, emacs.c, emacs-module.c, floatfns.c, fns.c, print.c. * src/Makefile.in (base_obj): Add bignum.o. * src/alloc.c (make_bignum_str): Move to bignum.c. (make_number): Remove; replaced by bignum.c’s make_integer. All callers changed. * src/conf_post.h (ARG_NONNULL): New macro. * src/json.c (json_to_lisp): Use it. * src/data.c (Fnatnump): Move NATNUMP’s implementation here from lisp.h. * src/data.c (Fnumber_to_string): * src/editfns.c (styled_format): Move conversion of string to bignum to bignum_to_string, and call it here. * src/emacs-module.c (module_make_integer): * src/floatfns.c (Fabs): Simplify by using make_int. * src/emacs.c: Include bignum.h, to expand its inline fns. * src/floatfns.c (Ffloat): Simplify by using XFLOATINT. (rounding_driver): Simplify by using double_to_bignum. (rounddiv_q): Clarify use of temporaries. * src/lisp.h: Move decls that need to know bignum internals to bignum.h. Do not include gmp.h or mini-gmp.h; that is now bignum.h’s job. (GMP_NUM_BITS, struct Lisp_Bignum, XBIGNUM, mpz_set_intmax): Move to bignum.h. (make_int): New function. (NATNUMP): Remove; all callers changed to use Fnatnump. (XFLOATINT): If arg is a bignum, use bignum_to_double, so that bignum internals are not exposed here. * src/print.c (print_vectorlike): Use SAFE_ALLOCA to avoid the need for a record_unwind_protect_ptr.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in2
-rw-r--r--src/alloc.c78
-rw-r--r--src/bignum.c161
-rw-r--r--src/bignum.h70
-rw-r--r--src/conf_post.h1
-rw-r--r--src/data.c38
-rw-r--r--src/editfns.c4
-rw-r--r--src/emacs-module.c16
-rw-r--r--src/emacs.c1
-rw-r--r--src/floatfns.c50
-rw-r--r--src/fns.c1
-rw-r--r--src/json.c2
-rw-r--r--src/lisp.h72
-rw-r--r--src/print.c9
14 files changed, 299 insertions, 206 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 52ce7605f7b..7d9c2361a9b 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -392,7 +392,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
392 charset.o coding.o category.o ccl.o character.o chartab.o bidi.o \ 392 charset.o coding.o category.o ccl.o character.o chartab.o bidi.o \
393 $(CM_OBJ) term.o terminal.o xfaces.o $(XOBJ) $(GTK_OBJ) $(DBUS_OBJ) \ 393 $(CM_OBJ) term.o terminal.o xfaces.o $(XOBJ) $(GTK_OBJ) $(DBUS_OBJ) \
394 emacs.o keyboard.o macros.o keymap.o sysdep.o \ 394 emacs.o keyboard.o macros.o keymap.o sysdep.o \
395 buffer.o filelock.o insdel.o marker.o \ 395 bignum.o buffer.o filelock.o insdel.o marker.o \
396 minibuf.o fileio.o dired.o \ 396 minibuf.o fileio.o dired.o \
397 cmds.o casetab.o casefiddle.o indent.o search.o regex-emacs.o undo.o \ 397 cmds.o casetab.o casefiddle.o indent.o search.o regex-emacs.o undo.o \
398 alloc.o data.o doc.o editfns.o callint.o \ 398 alloc.o data.o doc.o editfns.o callint.o \
diff --git a/src/alloc.c b/src/alloc.c
index c9788ab4c6b..350b668ec61 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -31,6 +31,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
31#endif 31#endif
32 32
33#include "lisp.h" 33#include "lisp.h"
34#include "bignum.h"
34#include "dispextern.h" 35#include "dispextern.h"
35#include "intervals.h" 36#include "intervals.h"
36#include "ptr-bounds.h" 37#include "ptr-bounds.h"
@@ -3728,83 +3729,6 @@ build_marker (struct buffer *buf, ptrdiff_t charpos, ptrdiff_t bytepos)
3728} 3729}
3729 3730
3730 3731
3731
3732Lisp_Object
3733make_bignum_str (const char *num, int base)
3734{
3735 struct Lisp_Bignum *b = ALLOCATE_PSEUDOVECTOR (struct Lisp_Bignum, value,
3736 PVEC_BIGNUM);
3737 mpz_init (b->value);
3738 int check = mpz_set_str (b->value, num, base);
3739 eassert (check == 0);
3740 return make_lisp_ptr (b, Lisp_Vectorlike);
3741}
3742
3743/* Given an mpz_t, make a number. This may return a bignum or a
3744 fixnum depending on VALUE. */
3745
3746Lisp_Object
3747make_number (mpz_t value)
3748{
3749 size_t bits = mpz_sizeinbase (value, 2);
3750
3751 if (bits <= FIXNUM_BITS)
3752 {
3753 EMACS_INT v = 0;
3754 int i = 0, shift = 0;
3755
3756 do
3757 {
3758 EMACS_INT limb = mpz_getlimbn (value, i++);
3759 v += limb << shift;
3760 shift += GMP_NUMB_BITS;
3761 }
3762 while (shift < bits);
3763
3764 if (mpz_sgn (value) < 0)
3765 v = -v;
3766
3767 if (!FIXNUM_OVERFLOW_P (v))
3768 return make_fixnum (v);
3769 }
3770
3771 /* The documentation says integer-width should be nonnegative, so
3772 a single comparison suffices even though 'bits' is unsigned. */
3773 if (integer_width < bits)
3774 range_error ();
3775
3776 struct Lisp_Bignum *b = ALLOCATE_PSEUDOVECTOR (struct Lisp_Bignum, value,
3777 PVEC_BIGNUM);
3778 /* We could mpz_init + mpz_swap here, to avoid a copy, but the
3779 resulting API seemed possibly confusing. */
3780 mpz_init_set (b->value, value);
3781
3782 return make_lisp_ptr (b, Lisp_Vectorlike);
3783}
3784
3785void
3786mpz_set_intmax_slow (mpz_t result, intmax_t v)
3787{
3788 /* If V fits in long, a faster path is taken. */
3789 eassert (! (LONG_MIN <= v && v <= LONG_MAX));
3790
3791 bool complement = v < 0;
3792 if (complement)
3793 v = -1 - v;
3794
3795 enum { nails = sizeof v * CHAR_BIT - INTMAX_WIDTH };
3796# ifndef HAVE_GMP
3797 /* mini-gmp requires NAILS to be zero, which is true for all
3798 likely Emacs platforms. Sanity-check this. */
3799 verify (nails == 0);
3800# endif
3801
3802 mpz_import (result, 1, -1, sizeof v, 0, nails, &v);
3803 if (complement)
3804 mpz_com (result, result);
3805}
3806
3807
3808/* Return a newly created vector or string with specified arguments as 3732/* Return a newly created vector or string with specified arguments as
3809 elements. If all the arguments are characters that can fit 3733 elements. If all the arguments are characters that can fit
3810 in a string of events, make a string; otherwise, make a vector. 3734 in a string of events, make a string; otherwise, make a vector.
diff --git a/src/bignum.c b/src/bignum.c
new file mode 100644
index 00000000000..18f94e7ed63
--- /dev/null
+++ b/src/bignum.c
@@ -0,0 +1,161 @@
1/* Big numbers for Emacs.
2
3Copyright 2018 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20#include <config.h>
21
22#include "bignum.h"
23
24#include "lisp.h"
25
26/* Return the value of the Lisp bignum N, as a double. */
27double
28bignum_to_double (Lisp_Object n)
29{
30 return mpz_get_d (XBIGNUM (n)->value);
31}
32
33/* Return D, converted to a bignum. Discard any fraction. */
34Lisp_Object
35double_to_bignum (double d)
36{
37 mpz_t z;
38 mpz_init_set_d (z, d);
39 Lisp_Object result = make_integer (z);
40 mpz_clear (z);
41 return result;
42}
43
44/* Return a Lisp integer equal to OP, which has BITS bits and which
45 must not be in fixnum range. */
46static Lisp_Object
47make_bignum_bits (mpz_t const op, size_t bits)
48{
49 /* The documentation says integer-width should be nonnegative, so
50 a single comparison suffices even though 'bits' is unsigned. */
51 if (integer_width < bits)
52 range_error ();
53
54 struct Lisp_Bignum *b = ALLOCATE_PSEUDOVECTOR (struct Lisp_Bignum, value,
55 PVEC_BIGNUM);
56 /* We could mpz_init + mpz_swap here, to avoid a copy, but the
57 resulting API seemed possibly confusing. */
58 mpz_init_set (b->value, op);
59
60 return make_lisp_ptr (b, Lisp_Vectorlike);
61}
62
63/* Return a Lisp integer equal to OP, which must not be in fixnum range. */
64static Lisp_Object
65make_bignum (mpz_t const op)
66{
67 return make_bignum_bits (op, mpz_sizeinbase (op, 2));
68}
69
70/* Return a Lisp integer equal to N, which must not be in fixnum range. */
71Lisp_Object
72make_bigint (intmax_t n)
73{
74 eassert (FIXNUM_OVERFLOW_P (n));
75 mpz_t z;
76 mpz_init (z);
77 mpz_set_intmax (z, n);
78 Lisp_Object result = make_bignum (z);
79 mpz_clear (z);
80 return result;
81}
82
83/* Return a Lisp integer with value taken from OP. */
84Lisp_Object
85make_integer (mpz_t const op)
86{
87 size_t bits = mpz_sizeinbase (op, 2);
88
89 if (bits <= FIXNUM_BITS)
90 {
91 EMACS_INT v = 0;
92 int i = 0, shift = 0;
93
94 do
95 {
96 EMACS_INT limb = mpz_getlimbn (op, i++);
97 v += limb << shift;
98 shift += GMP_NUMB_BITS;
99 }
100 while (shift < bits);
101
102 if (mpz_sgn (op) < 0)
103 v = -v;
104
105 if (!FIXNUM_OVERFLOW_P (v))
106 return make_fixnum (v);
107 }
108
109 return make_bignum_bits (op, bits);
110}
111
112void
113mpz_set_intmax_slow (mpz_t result, intmax_t v)
114{
115 bool complement = v < 0;
116 if (complement)
117 v = -1 - v;
118
119 enum { nails = sizeof v * CHAR_BIT - INTMAX_WIDTH };
120# ifndef HAVE_GMP
121 /* mini-gmp requires NAILS to be zero, which is true for all
122 likely Emacs platforms. Sanity-check this. */
123 verify (nails == 0);
124# endif
125
126 mpz_import (result, 1, -1, sizeof v, 0, nails, &v);
127 if (complement)
128 mpz_com (result, result);
129}
130
131/* Convert NUM to a base-BASE Lisp string. */
132
133Lisp_Object
134bignum_to_string (Lisp_Object num, int base)
135{
136 ptrdiff_t n = mpz_sizeinbase (XBIGNUM (num)->value, base) - 1;
137 USE_SAFE_ALLOCA;
138 char *str = SAFE_ALLOCA (n + 3);
139 mpz_get_str (str, base, XBIGNUM (num)->value);
140 while (str[n])
141 n++;
142 Lisp_Object result = make_unibyte_string (str, n);
143 SAFE_FREE ();
144 return result;
145}
146
147/* Create a bignum by scanning NUM, with digits in BASE.
148 NUM must consist of an optional '-', a nonempty sequence
149 of base-BASE digits, and a terminating null byte, and
150 the represented number must not be in fixnum range. */
151
152Lisp_Object
153make_bignum_str (char const *num, int base)
154{
155 struct Lisp_Bignum *b = ALLOCATE_PSEUDOVECTOR (struct Lisp_Bignum, value,
156 PVEC_BIGNUM);
157 mpz_init (b->value);
158 int check = mpz_set_str (b->value, num, base);
159 eassert (check == 0);
160 return make_lisp_ptr (b, Lisp_Vectorlike);
161}
diff --git a/src/bignum.h b/src/bignum.h
new file mode 100644
index 00000000000..a368333d77e
--- /dev/null
+++ b/src/bignum.h
@@ -0,0 +1,70 @@
1/* Big numbers for Emacs.
2
3Copyright 2018 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or (at
10your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19
20/* Include this header only if access to bignum internals is needed. */
21
22#ifndef BIGNUM_H
23#define BIGNUM_H
24
25#ifdef HAVE_GMP
26# include <gmp.h>
27#else
28# include "mini-gmp.h"
29#endif
30
31#include "lisp.h"
32
33/* Number of data bits in a limb. */
34#ifndef GMP_NUMB_BITS
35enum { GMP_NUMB_BITS = TYPE_WIDTH (mp_limb_t) };
36#endif
37
38struct Lisp_Bignum
39{
40 union vectorlike_header header;
41 mpz_t value;
42};
43
44extern Lisp_Object make_integer (mpz_t const) ARG_NONNULL ((1));
45extern void mpz_set_intmax_slow (mpz_t, intmax_t) ARG_NONNULL ((1));
46
47INLINE_HEADER_BEGIN
48
49INLINE struct Lisp_Bignum *
50XBIGNUM (Lisp_Object a)
51{
52 eassert (BIGNUMP (a));
53 return XUNTAG (a, Lisp_Vectorlike, struct Lisp_Bignum);
54}
55
56INLINE void ARG_NONNULL ((1))
57mpz_set_intmax (mpz_t result, intmax_t v)
58{
59 /* mpz_set_si works in terms of long, but Emacs may use a wider
60 integer type, and so sometimes will have to construct the mpz_t
61 by hand. */
62 if (LONG_MIN <= v && v <= LONG_MAX)
63 mpz_set_si (result, v);
64 else
65 mpz_set_intmax_slow (result, v);
66}
67
68INLINE_HEADER_END
69
70#endif /* BIGNUM_H */
diff --git a/src/conf_post.h b/src/conf_post.h
index f9838bc662a..683a96f9368 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -277,6 +277,7 @@ extern int emacs_setenv_TZ (char const *);
277#define ATTRIBUTE_FORMAT_PRINTF(string_index, first_to_check) \ 277#define ATTRIBUTE_FORMAT_PRINTF(string_index, first_to_check) \
278 ATTRIBUTE_FORMAT ((PRINTF_ARCHETYPE, string_index, first_to_check)) 278 ATTRIBUTE_FORMAT ((PRINTF_ARCHETYPE, string_index, first_to_check))
279 279
280#define ARG_NONNULL _GL_ARG_NONNULL
280#define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST 281#define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST
281#define ATTRIBUTE_UNUSED _GL_UNUSED 282#define ATTRIBUTE_UNUSED _GL_UNUSED
282 283
diff --git a/src/data.c b/src/data.c
index 170a74a6589..ece76a5bc6f 100644
--- a/src/data.c
+++ b/src/data.c
@@ -29,6 +29,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
29#include <intprops.h> 29#include <intprops.h>
30 30
31#include "lisp.h" 31#include "lisp.h"
32#include "bignum.h"
32#include "puresize.h" 33#include "puresize.h"
33#include "character.h" 34#include "character.h"
34#include "buffer.h" 35#include "buffer.h"
@@ -525,9 +526,9 @@ DEFUN ("natnump", Fnatnump, Snatnump, 1, 1, 0,
525 attributes: const) 526 attributes: const)
526 (Lisp_Object object) 527 (Lisp_Object object)
527{ 528{
528 if (NATNUMP (object)) 529 return ((FIXNUMP (object) ? 0 <= XFIXNUM (object)
529 return Qt; 530 : BIGNUMP (object) && 0 <= mpz_sgn (XBIGNUM (object)->value))
530 return Qnil; 531 ? Qt : Qnil);
531} 532}
532 533
533DEFUN ("numberp", Fnumberp, Snumberp, 1, 1, 0, 534DEFUN ("numberp", Fnumberp, Snumberp, 1, 1, 0,
@@ -2400,7 +2401,7 @@ emacs_mpz_size (mpz_t const op)
2400 the library code aborts when a number is too large. These wrappers 2401 the library code aborts when a number is too large. These wrappers
2401 avoid the problem for functions that can return numbers much larger 2402 avoid the problem for functions that can return numbers much larger
2402 than their arguments. For slowly-growing numbers, the integer 2403 than their arguments. For slowly-growing numbers, the integer
2403 width check in make_number should suffice. */ 2404 width checks in bignum.c should suffice. */
2404 2405
2405static void 2406static void
2406emacs_mpz_mul (mpz_t rop, mpz_t const op1, mpz_t const op2) 2407emacs_mpz_mul (mpz_t rop, mpz_t const op1, mpz_t const op2)
@@ -2770,12 +2771,7 @@ NUMBER may be an integer or a floating point number. */)
2770 int len; 2771 int len;
2771 2772
2772 if (BIGNUMP (number)) 2773 if (BIGNUMP (number))
2773 { 2774 return bignum_to_string (number, 10);
2774 ptrdiff_t count = SPECPDL_INDEX ();
2775 char *str = mpz_get_str (NULL, 10, XBIGNUM (number)->value);
2776 record_unwind_protect_ptr (xfree, str);
2777 return unbind_to (count, make_unibyte_string (str, strlen (str)));
2778 }
2779 2775
2780 CHECK_FIXNUM_OR_FLOAT (number); 2776 CHECK_FIXNUM_OR_FLOAT (number);
2781 2777
@@ -3011,7 +3007,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
3011 } 3007 }
3012 } 3008 }
3013 3009
3014 return unbind_to (count, make_number (accum)); 3010 return unbind_to (count, make_integer (accum));
3015} 3011}
3016 3012
3017static Lisp_Object 3013static Lisp_Object
@@ -3141,7 +3137,7 @@ Both must be integers or markers. */)
3141 3137
3142 mpz_init (result); 3138 mpz_init (result);
3143 mpz_tdiv_r (result, *xmp, *ymp); 3139 mpz_tdiv_r (result, *xmp, *ymp);
3144 val = make_number (result); 3140 val = make_integer (result);
3145 mpz_clear (result); 3141 mpz_clear (result);
3146 3142
3147 if (xmp == &xm) 3143 if (xmp == &xm)
@@ -3221,7 +3217,7 @@ Both X and Y must be numbers or markers. */)
3221 if (cmpy < 0 ? cmpr > 0 : cmpr < 0) 3217 if (cmpy < 0 ? cmpr > 0 : cmpr < 0)
3222 mpz_add (result, result, *ymp); 3218 mpz_add (result, result, *ymp);
3223 3219
3224 val = make_number (result); 3220 val = make_integer (result);
3225 mpz_clear (result); 3221 mpz_clear (result);
3226 3222
3227 if (xmp == &xm) 3223 if (xmp == &xm)
@@ -3351,7 +3347,7 @@ In this case, the sign bit is duplicated. */)
3351 emacs_mpz_mul_2exp (result, XBIGNUM (value)->value, XFIXNUM (count)); 3347 emacs_mpz_mul_2exp (result, XBIGNUM (value)->value, XFIXNUM (count));
3352 else 3348 else
3353 mpz_fdiv_q_2exp (result, XBIGNUM (value)->value, - XFIXNUM (count)); 3349 mpz_fdiv_q_2exp (result, XBIGNUM (value)->value, - XFIXNUM (count));
3354 val = make_number (result); 3350 val = make_integer (result);
3355 mpz_clear (result); 3351 mpz_clear (result);
3356 } 3352 }
3357 else if (XFIXNUM (count) <= 0) 3353 else if (XFIXNUM (count) <= 0)
@@ -3378,7 +3374,7 @@ In this case, the sign bit is duplicated. */)
3378 else 3374 else
3379 mpz_fdiv_q_2exp (result, result, - XFIXNUM (count)); 3375 mpz_fdiv_q_2exp (result, result, - XFIXNUM (count));
3380 3376
3381 val = make_number (result); 3377 val = make_integer (result);
3382 mpz_clear (result); 3378 mpz_clear (result);
3383 } 3379 }
3384 3380
@@ -3407,7 +3403,7 @@ expt_integer (Lisp_Object x, Lisp_Object y)
3407 ? (mpz_set_intmax (val, XFIXNUM (x)), val) 3403 ? (mpz_set_intmax (val, XFIXNUM (x)), val)
3408 : XBIGNUM (x)->value), 3404 : XBIGNUM (x)->value),
3409 exp); 3405 exp);
3410 Lisp_Object res = make_number (val); 3406 Lisp_Object res = make_integer (val);
3411 mpz_clear (val); 3407 mpz_clear (val);
3412 return res; 3408 return res;
3413} 3409}
@@ -3427,7 +3423,7 @@ Markers are converted to integers. */)
3427 mpz_t num; 3423 mpz_t num;
3428 mpz_init (num); 3424 mpz_init (num);
3429 mpz_add_ui (num, XBIGNUM (number)->value, 1); 3425 mpz_add_ui (num, XBIGNUM (number)->value, 1);
3430 number = make_number (num); 3426 number = make_integer (num);
3431 mpz_clear (num); 3427 mpz_clear (num);
3432 } 3428 }
3433 else 3429 else
@@ -3440,7 +3436,7 @@ Markers are converted to integers. */)
3440 mpz_t num; 3436 mpz_t num;
3441 mpz_init (num); 3437 mpz_init (num);
3442 mpz_set_intmax (num, XFIXNUM (number) + 1); 3438 mpz_set_intmax (num, XFIXNUM (number) + 1);
3443 number = make_number (num); 3439 number = make_integer (num);
3444 mpz_clear (num); 3440 mpz_clear (num);
3445 } 3441 }
3446 } 3442 }
@@ -3462,7 +3458,7 @@ Markers are converted to integers. */)
3462 mpz_t num; 3458 mpz_t num;
3463 mpz_init (num); 3459 mpz_init (num);
3464 mpz_sub_ui (num, XBIGNUM (number)->value, 1); 3460 mpz_sub_ui (num, XBIGNUM (number)->value, 1);
3465 number = make_number (num); 3461 number = make_integer (num);
3466 mpz_clear (num); 3462 mpz_clear (num);
3467 } 3463 }
3468 else 3464 else
@@ -3475,7 +3471,7 @@ Markers are converted to integers. */)
3475 mpz_t num; 3471 mpz_t num;
3476 mpz_init (num); 3472 mpz_init (num);
3477 mpz_set_intmax (num, XFIXNUM (number) - 1); 3473 mpz_set_intmax (num, XFIXNUM (number) - 1);
3478 number = make_number (num); 3474 number = make_integer (num);
3479 mpz_clear (num); 3475 mpz_clear (num);
3480 } 3476 }
3481 } 3477 }
@@ -3492,7 +3488,7 @@ DEFUN ("lognot", Flognot, Slognot, 1, 1, 0,
3492 mpz_t value; 3488 mpz_t value;
3493 mpz_init (value); 3489 mpz_init (value);
3494 mpz_com (value, XBIGNUM (number)->value); 3490 mpz_com (value, XBIGNUM (number)->value);
3495 number = make_number (value); 3491 number = make_integer (value);
3496 mpz_clear (value); 3492 mpz_clear (value);
3497 } 3493 }
3498 else 3494 else
diff --git a/src/editfns.c b/src/editfns.c
index d2281d7e81c..9ca6f373e04 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -4491,9 +4491,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message)
4491 else if (conversion == 'X') 4491 else if (conversion == 'X')
4492 base = -16; 4492 base = -16;
4493 4493
4494 char *str = mpz_get_str (NULL, base, XBIGNUM (arg)->value); 4494 arg = bignum_to_string (arg, base);
4495 arg = make_unibyte_string (str, strlen (str));
4496 xfree (str);
4497 conversion = 's'; 4495 conversion = 's';
4498 } 4496 }
4499 4497
diff --git a/src/emacs-module.c b/src/emacs-module.c
index f2844c40d0f..a1bed491b62 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -27,6 +27,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
27#include <stdio.h> 27#include <stdio.h>
28 28
29#include "lisp.h" 29#include "lisp.h"
30#include "bignum.h"
30#include "dynlib.h" 31#include "dynlib.h"
31#include "coding.h" 32#include "coding.h"
32#include "keyboard.h" 33#include "keyboard.h"
@@ -521,6 +522,8 @@ module_extract_integer (emacs_env *env, emacs_value n)
521 CHECK_INTEGER (l); 522 CHECK_INTEGER (l);
522 if (BIGNUMP (l)) 523 if (BIGNUMP (l))
523 { 524 {
525 /* FIXME: This can incorrectly signal overflow on platforms
526 where long is narrower than intmax_t. */
524 if (!mpz_fits_slong_p (XBIGNUM (l)->value)) 527 if (!mpz_fits_slong_p (XBIGNUM (l)->value))
525 xsignal1 (Qoverflow_error, l); 528 xsignal1 (Qoverflow_error, l);
526 return mpz_get_si (XBIGNUM (l)->value); 529 return mpz_get_si (XBIGNUM (l)->value);
@@ -531,19 +534,8 @@ module_extract_integer (emacs_env *env, emacs_value n)
531static emacs_value 534static emacs_value
532module_make_integer (emacs_env *env, intmax_t n) 535module_make_integer (emacs_env *env, intmax_t n)
533{ 536{
534 Lisp_Object obj;
535 MODULE_FUNCTION_BEGIN (module_nil); 537 MODULE_FUNCTION_BEGIN (module_nil);
536 if (FIXNUM_OVERFLOW_P (n)) 538 return lisp_to_value (env, make_int (n));
537 {
538 mpz_t val;
539 mpz_init (val);
540 mpz_set_intmax (val, n);
541 obj = make_number (val);
542 mpz_clear (val);
543 }
544 else
545 obj = make_fixnum (n);
546 return lisp_to_value (env, obj);
547} 539}
548 540
549static double 541static double
diff --git a/src/emacs.c b/src/emacs.c
index 7d07ec85029..07a1aff9b06 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -66,6 +66,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
66#include TERM_HEADER 66#include TERM_HEADER
67#endif /* HAVE_WINDOW_SYSTEM */ 67#endif /* HAVE_WINDOW_SYSTEM */
68 68
69#include "bignum.h"
69#include "intervals.h" 70#include "intervals.h"
70#include "character.h" 71#include "character.h"
71#include "buffer.h" 72#include "buffer.h"
diff --git a/src/floatfns.c b/src/floatfns.c
index e7884864eef..8008929be61 100644
--- a/src/floatfns.c
+++ b/src/floatfns.c
@@ -42,6 +42,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
42#include <config.h> 42#include <config.h>
43 43
44#include "lisp.h" 44#include "lisp.h"
45#include "bignum.h"
45 46
46#include <math.h> 47#include <math.h>
47 48
@@ -209,7 +210,7 @@ DEFUN ("expt", Fexpt, Sexpt, 2, 2, 0,
209 210
210 /* Common Lisp spec: don't promote if both are integers, and if the 211 /* Common Lisp spec: don't promote if both are integers, and if the
211 result is not fractional. */ 212 result is not fractional. */
212 if (INTEGERP (arg1) && NATNUMP (arg2)) 213 if (INTEGERP (arg1) && Fnatnump (arg2))
213 return expt_integer (arg1, arg2); 214 return expt_integer (arg1, arg2);
214 215
215 return make_float (pow (XFLOATINT (arg1), XFLOATINT (arg2))); 216 return make_float (pow (XFLOATINT (arg1), XFLOATINT (arg2)));
@@ -258,19 +259,7 @@ DEFUN ("abs", Fabs, Sabs, 1, 1, 0,
258 if (FIXNUMP (arg)) 259 if (FIXNUMP (arg))
259 { 260 {
260 if (XFIXNUM (arg) < 0) 261 if (XFIXNUM (arg) < 0)
261 { 262 arg = make_int (-XFIXNUM (arg));
262 EMACS_INT absarg = -XFIXNUM (arg);
263 if (absarg <= MOST_POSITIVE_FIXNUM)
264 arg = make_fixnum (absarg);
265 else
266 {
267 mpz_t val;
268 mpz_init (val);
269 mpz_set_intmax (val, absarg);
270 arg = make_number (val);
271 mpz_clear (val);
272 }
273 }
274 } 263 }
275 else if (FLOATP (arg)) 264 else if (FLOATP (arg))
276 { 265 {
@@ -284,7 +273,7 @@ DEFUN ("abs", Fabs, Sabs, 1, 1, 0,
284 mpz_t val; 273 mpz_t val;
285 mpz_init (val); 274 mpz_init (val);
286 mpz_neg (val, XBIGNUM (arg)->value); 275 mpz_neg (val, XBIGNUM (arg)->value);
287 arg = make_number (val); 276 arg = make_integer (val);
288 mpz_clear (val); 277 mpz_clear (val);
289 } 278 }
290 } 279 }
@@ -297,13 +286,8 @@ DEFUN ("float", Ffloat, Sfloat, 1, 1, 0,
297 (register Lisp_Object arg) 286 (register Lisp_Object arg)
298{ 287{
299 CHECK_NUMBER (arg); 288 CHECK_NUMBER (arg);
300 289 /* If ARG is a float, give 'em the same float back. */
301 if (BIGNUMP (arg)) 290 return FLOATP (arg) ? arg : make_float (XFLOATINT (arg));
302 return make_float (mpz_get_d (XBIGNUM (arg)->value));
303 if (FIXNUMP (arg))
304 return make_float ((double) XFIXNUM (arg));
305 else /* give 'em the same float back */
306 return arg;
307} 291}
308 292
309static int 293static int
@@ -386,7 +370,7 @@ rounding_driver (Lisp_Object arg, Lisp_Object divisor,
386 (FIXNUMP (divisor) 370 (FIXNUMP (divisor)
387 ? (mpz_set_intmax (d, XFIXNUM (divisor)), d) 371 ? (mpz_set_intmax (d, XFIXNUM (divisor)), d)
388 : XBIGNUM (divisor)->value)); 372 : XBIGNUM (divisor)->value));
389 Lisp_Object result = make_number (q); 373 Lisp_Object result = make_integer (q);
390 mpz_clear (d); 374 mpz_clear (d);
391 mpz_clear (q); 375 mpz_clear (q);
392 return result; 376 return result;
@@ -410,12 +394,7 @@ rounding_driver (Lisp_Object arg, Lisp_Object divisor,
410 if (! FIXNUM_OVERFLOW_P (ir)) 394 if (! FIXNUM_OVERFLOW_P (ir))
411 return make_fixnum (ir); 395 return make_fixnum (ir);
412 } 396 }
413 mpz_t drz; 397 return double_to_bignum (dr);
414 mpz_init (drz);
415 mpz_set_d (drz, dr);
416 Lisp_Object rounded = make_number (drz);
417 mpz_clear (drz);
418 return rounded;
419} 398}
420 399
421static void 400static void
@@ -433,9 +412,9 @@ rounddiv_q (mpz_t q, mpz_t const n, mpz_t const d)
433 r = n % d; 412 r = n % d;
434 neg_d = d < 0; 413 neg_d = d < 0;
435 neg_r = r < 0; 414 neg_r = r < 0;
436 r = eabs (r); 415 abs_r = eabs (r);
437 abs_r1 = eabs (d) - r; 416 abs_r1 = eabs (d) - abs_r;
438 if (abs_r1 < r + (q & 1)) 417 if (abs_r1 < abs_r + (q & 1))
439 q += neg_d == neg_r ? 1 : -1; */ 418 q += neg_d == neg_r ? 1 : -1; */
440 419
441 mpz_t r, abs_r1; 420 mpz_t r, abs_r1;
@@ -444,10 +423,11 @@ rounddiv_q (mpz_t q, mpz_t const n, mpz_t const d)
444 mpz_tdiv_qr (q, r, n, d); 423 mpz_tdiv_qr (q, r, n, d);
445 bool neg_d = mpz_sgn (d) < 0; 424 bool neg_d = mpz_sgn (d) < 0;
446 bool neg_r = mpz_sgn (r) < 0; 425 bool neg_r = mpz_sgn (r) < 0;
447 mpz_abs (r, r); 426 mpz_t *abs_r = &r;
427 mpz_abs (*abs_r, r);
448 mpz_abs (abs_r1, d); 428 mpz_abs (abs_r1, d);
449 mpz_sub (abs_r1, abs_r1, r); 429 mpz_sub (abs_r1, abs_r1, *abs_r);
450 if (mpz_cmp (abs_r1, r) < (mpz_odd_p (q) != 0)) 430 if (mpz_cmp (abs_r1, *abs_r) < (mpz_odd_p (q) != 0))
451 (neg_d == neg_r ? mpz_add_ui : mpz_sub_ui) (q, q, 1); 431 (neg_d == neg_r ? mpz_add_ui : mpz_sub_ui) (q, q, 1);
452 mpz_clear (r); 432 mpz_clear (r);
453 mpz_clear (abs_r1); 433 mpz_clear (abs_r1);
diff --git a/src/fns.c b/src/fns.c
index b368ffd58f2..3f7dfeddb6e 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -28,6 +28,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
28#include <errno.h> 28#include <errno.h>
29 29
30#include "lisp.h" 30#include "lisp.h"
31#include "bignum.h"
31#include "character.h" 32#include "character.h"
32#include "coding.h" 33#include "coding.h"
33#include "composite.h" 34#include "composite.h"
diff --git a/src/json.c b/src/json.c
index 4e46640a0c6..d525d1b7577 100644
--- a/src/json.c
+++ b/src/json.c
@@ -709,7 +709,7 @@ usage: (json-insert OBJECT &rest ARGS) */)
709 709
710/* Convert a JSON object to a Lisp object. */ 710/* Convert a JSON object to a Lisp object. */
711 711
712static _GL_ARG_NONNULL ((1)) Lisp_Object 712static Lisp_Object ARG_NONNULL ((1))
713json_to_lisp (json_t *json, struct json_configuration *conf) 713json_to_lisp (json_t *json, struct json_configuration *conf)
714{ 714{
715 switch (json_typeof (json)) 715 switch (json_typeof (json))
diff --git a/src/lisp.h b/src/lisp.h
index fb11a11fda3..555496bc271 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -31,12 +31,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
31#include <inttypes.h> 31#include <inttypes.h>
32#include <limits.h> 32#include <limits.h>
33 33
34#ifdef HAVE_GMP
35# include <gmp.h>
36#else
37# include "mini-gmp.h"
38#endif
39
40#include <intprops.h> 34#include <intprops.h>
41#include <verify.h> 35#include <verify.h>
42 36
@@ -589,6 +583,10 @@ enum CHECK_LISP_OBJECT_TYPE { CHECK_LISP_OBJECT_TYPE = false };
589INLINE void set_sub_char_table_contents (Lisp_Object, ptrdiff_t, 583INLINE void set_sub_char_table_contents (Lisp_Object, ptrdiff_t,
590 Lisp_Object); 584 Lisp_Object);
591 585
586/* Defined in bignum.c. */
587extern double bignum_to_double (Lisp_Object);
588extern Lisp_Object make_bigint (intmax_t);
589
592/* Defined in chartab.c. */ 590/* Defined in chartab.c. */
593extern Lisp_Object char_table_ref (Lisp_Object, int); 591extern Lisp_Object char_table_ref (Lisp_Object, int);
594extern void char_table_set (Lisp_Object, int, Lisp_Object); 592extern void char_table_set (Lisp_Object, int, Lisp_Object);
@@ -1013,14 +1011,6 @@ enum More_Lisp_Bits
1013#define MOST_POSITIVE_FIXNUM (EMACS_INT_MAX >> INTTYPEBITS) 1011#define MOST_POSITIVE_FIXNUM (EMACS_INT_MAX >> INTTYPEBITS)
1014#define MOST_NEGATIVE_FIXNUM (-1 - MOST_POSITIVE_FIXNUM) 1012#define MOST_NEGATIVE_FIXNUM (-1 - MOST_POSITIVE_FIXNUM)
1015 1013
1016
1017/* GMP-related limits. */
1018
1019/* Number of data bits in a limb. */
1020#ifndef GMP_NUMB_BITS
1021enum { GMP_NUMB_BITS = TYPE_WIDTH (mp_limb_t) };
1022#endif
1023
1024#if USE_LSB_TAG 1014#if USE_LSB_TAG
1025 1015
1026INLINE Lisp_Object 1016INLINE Lisp_Object
@@ -2460,31 +2450,25 @@ XUSER_PTR (Lisp_Object a)
2460} 2450}
2461#endif 2451#endif
2462 2452
2463struct Lisp_Bignum
2464{
2465 union vectorlike_header header;
2466 mpz_t value;
2467};
2468
2469INLINE bool 2453INLINE bool
2470BIGNUMP (Lisp_Object x) 2454BIGNUMP (Lisp_Object x)
2471{ 2455{
2472 return PSEUDOVECTORP (x, PVEC_BIGNUM); 2456 return PSEUDOVECTORP (x, PVEC_BIGNUM);
2473} 2457}
2474 2458
2475INLINE struct Lisp_Bignum *
2476XBIGNUM (Lisp_Object a)
2477{
2478 eassert (BIGNUMP (a));
2479 return XUNTAG (a, Lisp_Vectorlike, struct Lisp_Bignum);
2480}
2481
2482INLINE bool 2459INLINE bool
2483INTEGERP (Lisp_Object x) 2460INTEGERP (Lisp_Object x)
2484{ 2461{
2485 return FIXNUMP (x) || BIGNUMP (x); 2462 return FIXNUMP (x) || BIGNUMP (x);
2486} 2463}
2487 2464
2465/* Return a Lisp integer with value taken from n. */
2466INLINE Lisp_Object
2467make_int (intmax_t n)
2468{
2469 return FIXNUM_OVERFLOW_P (n) ? make_bigint (n) : make_fixnum (n);
2470}
2471
2488 2472
2489/* Forwarding pointer to an int variable. 2473/* Forwarding pointer to an int variable.
2490 This is allowed only in the value cell of a symbol, 2474 This is allowed only in the value cell of a symbol,
@@ -2698,13 +2682,6 @@ FIXNATP (Lisp_Object x)
2698 return FIXNUMP (x) && 0 <= XFIXNUM (x); 2682 return FIXNUMP (x) && 0 <= XFIXNUM (x);
2699} 2683}
2700INLINE bool 2684INLINE bool
2701NATNUMP (Lisp_Object x)
2702{
2703 if (BIGNUMP (x))
2704 return mpz_sgn (XBIGNUM (x)->value) >= 0;
2705 return FIXNUMP (x) && 0 <= XFIXNUM (x);
2706}
2707INLINE bool
2708NUMBERP (Lisp_Object x) 2685NUMBERP (Lisp_Object x)
2709{ 2686{
2710 return INTEGERP (x) || FLOATP (x); 2687 return INTEGERP (x) || FLOATP (x);
@@ -2848,9 +2825,9 @@ CHECK_FIXNAT (Lisp_Object x)
2848INLINE double 2825INLINE double
2849XFLOATINT (Lisp_Object n) 2826XFLOATINT (Lisp_Object n)
2850{ 2827{
2851 if (BIGNUMP (n)) 2828 return (FIXNUMP (n) ? XFIXNUM (n)
2852 return mpz_get_d (XBIGNUM (n)->value); 2829 : FLOATP (n) ? XFLOAT_DATA (n)
2853 return FLOATP (n) ? XFLOAT_DATA (n) : XFIXNUM (n); 2830 : bignum_to_double (n));
2854} 2831}
2855 2832
2856INLINE void 2833INLINE void
@@ -3310,6 +3287,11 @@ set_sub_char_table_contents (Lisp_Object table, ptrdiff_t idx, Lisp_Object val)
3310 XSUB_CHAR_TABLE (table)->contents[idx] = val; 3287 XSUB_CHAR_TABLE (table)->contents[idx] = val;
3311} 3288}
3312 3289
3290/* Defined in bignum.c. */
3291extern Lisp_Object bignum_to_string (Lisp_Object, int);
3292extern Lisp_Object make_bignum_str (char const *, int);
3293extern Lisp_Object double_to_bignum (double);
3294
3313/* Defined in data.c. */ 3295/* Defined in data.c. */
3314extern _Noreturn void wrong_choice (Lisp_Object, Lisp_Object); 3296extern _Noreturn void wrong_choice (Lisp_Object, Lisp_Object);
3315extern void notify_variable_watchers (Lisp_Object, Lisp_Object, 3297extern void notify_variable_watchers (Lisp_Object, Lisp_Object,
@@ -3582,22 +3564,6 @@ extern Lisp_Object list5 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object,
3582enum constype {CONSTYPE_HEAP, CONSTYPE_PURE}; 3564enum constype {CONSTYPE_HEAP, CONSTYPE_PURE};
3583extern Lisp_Object listn (enum constype, ptrdiff_t, Lisp_Object, ...); 3565extern Lisp_Object listn (enum constype, ptrdiff_t, Lisp_Object, ...);
3584 3566
3585extern Lisp_Object make_bignum_str (const char *num, int base);
3586extern Lisp_Object make_number (mpz_t value);
3587extern void mpz_set_intmax_slow (mpz_t result, intmax_t v);
3588
3589INLINE void
3590mpz_set_intmax (mpz_t result, intmax_t v)
3591{
3592 /* mpz_set_si works in terms of long, but Emacs may use a wider
3593 integer type, and so sometimes will have to construct the mpz_t
3594 by hand. */
3595 if (LONG_MIN <= v && v <= LONG_MAX)
3596 mpz_set_si (result, v);
3597 else
3598 mpz_set_intmax_slow (result, v);
3599}
3600
3601/* Build a frequently used 2/3/4-integer lists. */ 3567/* Build a frequently used 2/3/4-integer lists. */
3602 3568
3603INLINE Lisp_Object 3569INLINE Lisp_Object
diff --git a/src/print.c b/src/print.c
index 824f8d75779..49d9e38e7d3 100644
--- a/src/print.c
+++ b/src/print.c
@@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
23#include "sysstdio.h" 23#include "sysstdio.h"
24 24
25#include "lisp.h" 25#include "lisp.h"
26#include "bignum.h"
26#include "character.h" 27#include "character.h"
27#include "coding.h" 28#include "coding.h"
28#include "buffer.h" 29#include "buffer.h"
@@ -1369,10 +1370,12 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
1369 { 1370 {
1370 case PVEC_BIGNUM: 1371 case PVEC_BIGNUM:
1371 { 1372 {
1372 struct Lisp_Bignum *b = XBIGNUM (obj); 1373 USE_SAFE_ALLOCA;
1373 char *str = mpz_get_str (NULL, 10, b->value); 1374 char *str = SAFE_ALLOCA (mpz_sizeinbase (XBIGNUM (obj)->value, 10)
1374 record_unwind_protect_ptr (xfree, str); 1375 + 2);
1376 mpz_get_str (str, 10, XBIGNUM (obj)->value);
1375 print_c_string (str, printcharfun); 1377 print_c_string (str, printcharfun);
1378 SAFE_FREE ();
1376 } 1379 }
1377 break; 1380 break;
1378 1381