diff options
| author | Tom Tromey | 2018-07-19 15:58:10 -0600 |
|---|---|---|
| committer | Tom Tromey | 2018-07-19 16:08:41 -0600 |
| commit | 76715f8921dca740880cd22c644a6328cd810846 (patch) | |
| tree | d85940e4c452575c453ab3ea6a7d0ec25b20f2ab /src | |
| parent | 678881e428073b39a906c1ffd01e1b76e271cb5d (diff) | |
| download | emacs-76715f8921dca740880cd22c644a6328cd810846.tar.gz emacs-76715f8921dca740880cd22c644a6328cd810846.zip | |
Fix bignum creation when EMACS_INT is wider than long
* src/alloc.c (mpz_set_intmax_slow, mpz_set_uintmax_slow): New
functions.
* src/data.c (arith_driver, Frem, Fmod, ash_lsh_impl, Fadd1)
(Fsub1): Use mpz_set_intmax, mpz_set_uintmax.
* src/emacs-module.c (module_make_integer): Use mpz_set_intmax.
* src/floatfns.c (Fabs): Use mpz_set_intmax.
* src/lisp.h (mpz_set_intmax, mpz_set_uintmax): New inline
functions.
(mpz_set_uintmax_slow, mpz_set_intmax_slow): Declare.
Diffstat (limited to 'src')
| -rw-r--r-- | src/alloc.c | 30 | ||||
| -rw-r--r-- | src/data.c | 36 | ||||
| -rw-r--r-- | src/emacs-module.c | 3 | ||||
| -rw-r--r-- | src/floatfns.c | 3 | ||||
| -rw-r--r-- | src/lisp.h | 26 |
5 files changed, 83 insertions, 15 deletions
diff --git a/src/alloc.c b/src/alloc.c index b775948fd96..1dc1bbb031a 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3824,6 +3824,36 @@ make_number (mpz_t value) | |||
| 3824 | return obj; | 3824 | return obj; |
| 3825 | } | 3825 | } |
| 3826 | 3826 | ||
| 3827 | void | ||
| 3828 | mpz_set_intmax_slow (mpz_t result, intmax_t v) | ||
| 3829 | { | ||
| 3830 | /* If long is larger then a faster path is taken. */ | ||
| 3831 | eassert (sizeof (intmax_t) > sizeof (long)); | ||
| 3832 | |||
| 3833 | bool negate = false; | ||
| 3834 | if (v < 0) | ||
| 3835 | { | ||
| 3836 | v = -v; | ||
| 3837 | negate = true; | ||
| 3838 | } | ||
| 3839 | mpz_set_uintmax_slow (result, (uintmax_t) v); | ||
| 3840 | if (negate) | ||
| 3841 | mpz_neg (result, result); | ||
| 3842 | } | ||
| 3843 | |||
| 3844 | void | ||
| 3845 | mpz_set_uintmax_slow (mpz_t result, uintmax_t v) | ||
| 3846 | { | ||
| 3847 | /* If long is larger then a faster path is taken. */ | ||
| 3848 | eassert (sizeof (uintmax_t) > sizeof (unsigned long)); | ||
| 3849 | /* This restriction could be lifted if needed. */ | ||
| 3850 | eassert (sizeof (uintmax_t) <= 2 * sizeof (unsigned long)); | ||
| 3851 | |||
| 3852 | mpz_set_ui (result, v >> (CHAR_BIT * sizeof (unsigned long))); | ||
| 3853 | mpz_mul_2exp (result, result, CHAR_BIT * sizeof (unsigned long)); | ||
| 3854 | mpz_add_ui (result, result, v & -1ul); | ||
| 3855 | } | ||
| 3856 | |||
| 3827 | 3857 | ||
| 3828 | /* Return a newly created vector or string with specified arguments as | 3858 | /* Return a newly created vector or string with specified arguments as |
| 3829 | elements. If all the arguments are characters that can fit | 3859 | elements. If all the arguments are characters that can fit |
diff --git a/src/data.c b/src/data.c index 862381229d7..0deebdca1ae 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -2882,7 +2882,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args) | |||
| 2882 | if (BIGNUMP (val)) | 2882 | if (BIGNUMP (val)) |
| 2883 | mpz_set (accum, XBIGNUM (val)->value); | 2883 | mpz_set (accum, XBIGNUM (val)->value); |
| 2884 | else | 2884 | else |
| 2885 | mpz_set_si (accum, XINT (val)); | 2885 | mpz_set_intmax (accum, XINT (val)); |
| 2886 | if (nargs == 1) | 2886 | if (nargs == 1) |
| 2887 | mpz_neg (accum, accum); | 2887 | mpz_neg (accum, accum); |
| 2888 | } | 2888 | } |
| @@ -2905,7 +2905,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args) | |||
| 2905 | if (BIGNUMP (val)) | 2905 | if (BIGNUMP (val)) |
| 2906 | mpz_set (accum, XBIGNUM (val)->value); | 2906 | mpz_set (accum, XBIGNUM (val)->value); |
| 2907 | else | 2907 | else |
| 2908 | mpz_set_si (accum, XINT (val)); | 2908 | mpz_set_intmax (accum, XINT (val)); |
| 2909 | } | 2909 | } |
| 2910 | else | 2910 | else |
| 2911 | { | 2911 | { |
| @@ -2933,7 +2933,8 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args) | |||
| 2933 | else | 2933 | else |
| 2934 | { | 2934 | { |
| 2935 | mpz_t tem; | 2935 | mpz_t tem; |
| 2936 | mpz_init_set_ui (tem, XUINT (val)); | 2936 | mpz_init (tem); |
| 2937 | mpz_set_uintmax (tem, XUINT (val)); | ||
| 2937 | mpz_and (accum, accum, tem); | 2938 | mpz_and (accum, accum, tem); |
| 2938 | mpz_clear (tem); | 2939 | mpz_clear (tem); |
| 2939 | } | 2940 | } |
| @@ -2944,7 +2945,8 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args) | |||
| 2944 | else | 2945 | else |
| 2945 | { | 2946 | { |
| 2946 | mpz_t tem; | 2947 | mpz_t tem; |
| 2947 | mpz_init_set_ui (tem, XUINT (val)); | 2948 | mpz_init (tem); |
| 2949 | mpz_set_uintmax (tem, XUINT (val)); | ||
| 2948 | mpz_ior (accum, accum, tem); | 2950 | mpz_ior (accum, accum, tem); |
| 2949 | mpz_clear (tem); | 2951 | mpz_clear (tem); |
| 2950 | } | 2952 | } |
| @@ -2955,7 +2957,8 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args) | |||
| 2955 | else | 2957 | else |
| 2956 | { | 2958 | { |
| 2957 | mpz_t tem; | 2959 | mpz_t tem; |
| 2958 | mpz_init_set_ui (tem, XUINT (val)); | 2960 | mpz_init (tem); |
| 2961 | mpz_set_uintmax (tem, XUINT (val)); | ||
| 2959 | mpz_xor (accum, accum, tem); | 2962 | mpz_xor (accum, accum, tem); |
| 2960 | mpz_clear (tem); | 2963 | mpz_clear (tem); |
| 2961 | } | 2964 | } |
| @@ -3092,7 +3095,8 @@ Both must be integers or markers. */) | |||
| 3092 | xmp = &XBIGNUM (x)->value; | 3095 | xmp = &XBIGNUM (x)->value; |
| 3093 | else | 3096 | else |
| 3094 | { | 3097 | { |
| 3095 | mpz_init_set_si (xm, XINT (x)); | 3098 | mpz_init (xm); |
| 3099 | mpz_set_intmax (xm, XINT (x)); | ||
| 3096 | xmp = &xm; | 3100 | xmp = &xm; |
| 3097 | } | 3101 | } |
| 3098 | 3102 | ||
| @@ -3100,7 +3104,8 @@ Both must be integers or markers. */) | |||
| 3100 | ymp = &XBIGNUM (y)->value; | 3104 | ymp = &XBIGNUM (y)->value; |
| 3101 | else | 3105 | else |
| 3102 | { | 3106 | { |
| 3103 | mpz_init_set_si (ym, XINT (y)); | 3107 | mpz_init (ym); |
| 3108 | mpz_set_intmax (ym, XINT (y)); | ||
| 3104 | ymp = &ym; | 3109 | ymp = &ym; |
| 3105 | } | 3110 | } |
| 3106 | 3111 | ||
| @@ -3163,7 +3168,8 @@ Both X and Y must be numbers or markers. */) | |||
| 3163 | xmp = &XBIGNUM (x)->value; | 3168 | xmp = &XBIGNUM (x)->value; |
| 3164 | else | 3169 | else |
| 3165 | { | 3170 | { |
| 3166 | mpz_init_set_si (xm, XINT (x)); | 3171 | mpz_init (xm); |
| 3172 | mpz_set_intmax (xm, XINT (x)); | ||
| 3167 | xmp = &xm; | 3173 | xmp = &xm; |
| 3168 | } | 3174 | } |
| 3169 | 3175 | ||
| @@ -3171,7 +3177,8 @@ Both X and Y must be numbers or markers. */) | |||
| 3171 | ymp = &XBIGNUM (y)->value; | 3177 | ymp = &XBIGNUM (y)->value; |
| 3172 | else | 3178 | else |
| 3173 | { | 3179 | { |
| 3174 | mpz_init_set_si (ym, XINT (y)); | 3180 | mpz_init (ym); |
| 3181 | mpz_set_intmax (ym, XINT (y)); | ||
| 3175 | ymp = &ym; | 3182 | ymp = &ym; |
| 3176 | } | 3183 | } |
| 3177 | 3184 | ||
| @@ -3317,10 +3324,11 @@ ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) | |||
| 3317 | /* Just do the work as bignums to make the code simpler. */ | 3324 | /* Just do the work as bignums to make the code simpler. */ |
| 3318 | mpz_t result; | 3325 | mpz_t result; |
| 3319 | eassume (FIXNUMP (value)); | 3326 | eassume (FIXNUMP (value)); |
| 3327 | mpz_init (result); | ||
| 3320 | if (lsh) | 3328 | if (lsh) |
| 3321 | mpz_init_set_ui (result, XUINT (value)); | 3329 | mpz_set_uintmax (result, XUINT (value)); |
| 3322 | else | 3330 | else |
| 3323 | mpz_init_set_si (result, XINT (value)); | 3331 | mpz_set_intmax (result, XINT (value)); |
| 3324 | if (XINT (count) >= 0) | 3332 | if (XINT (count) >= 0) |
| 3325 | mpz_mul_2exp (result, result, XINT (count)); | 3333 | mpz_mul_2exp (result, result, XINT (count)); |
| 3326 | else | 3334 | else |
| @@ -3376,7 +3384,8 @@ Markers are converted to integers. */) | |||
| 3376 | else | 3384 | else |
| 3377 | { | 3385 | { |
| 3378 | mpz_t num; | 3386 | mpz_t num; |
| 3379 | mpz_init_set_si (num, XINT (number) + 1); | 3387 | mpz_init (num); |
| 3388 | mpz_set_intmax (num, XINT (number) + 1); | ||
| 3380 | number = make_number (num); | 3389 | number = make_number (num); |
| 3381 | mpz_clear (num); | 3390 | mpz_clear (num); |
| 3382 | } | 3391 | } |
| @@ -3410,7 +3419,8 @@ Markers are converted to integers. */) | |||
| 3410 | else | 3419 | else |
| 3411 | { | 3420 | { |
| 3412 | mpz_t num; | 3421 | mpz_t num; |
| 3413 | mpz_init_set_si (num, XINT (number) - 1); | 3422 | mpz_init (num); |
| 3423 | mpz_set_intmax (num, XINT (number) - 1); | ||
| 3414 | number = make_number (num); | 3424 | number = make_number (num); |
| 3415 | mpz_clear (num); | 3425 | mpz_clear (num); |
| 3416 | } | 3426 | } |
diff --git a/src/emacs-module.c b/src/emacs-module.c index 7709eeca94a..39150f6f67b 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c | |||
| @@ -536,7 +536,8 @@ module_make_integer (emacs_env *env, intmax_t n) | |||
| 536 | if (FIXNUM_OVERFLOW_P (n)) | 536 | if (FIXNUM_OVERFLOW_P (n)) |
| 537 | { | 537 | { |
| 538 | mpz_t val; | 538 | mpz_t val; |
| 539 | mpz_init_set_si (val, n); | 539 | mpz_init (val); |
| 540 | mpz_set_intmax (val, n); | ||
| 540 | obj = make_number (val); | 541 | obj = make_number (val); |
| 541 | mpz_clear (val); | 542 | mpz_clear (val); |
| 542 | } | 543 | } |
diff --git a/src/floatfns.c b/src/floatfns.c index 9a5f0a3ad2f..563c65f827a 100644 --- a/src/floatfns.c +++ b/src/floatfns.c | |||
| @@ -288,7 +288,8 @@ DEFUN ("abs", Fabs, Sabs, 1, 1, 0, | |||
| 288 | else if (FIXNUMP (arg) && XINT (arg) == MOST_NEGATIVE_FIXNUM) | 288 | else if (FIXNUMP (arg) && XINT (arg) == MOST_NEGATIVE_FIXNUM) |
| 289 | { | 289 | { |
| 290 | mpz_t val; | 290 | mpz_t val; |
| 291 | mpz_init_set_si (val, - MOST_NEGATIVE_FIXNUM); | 291 | mpz_init (val); |
| 292 | mpz_set_intmax (val, - MOST_NEGATIVE_FIXNUM); | ||
| 292 | arg = make_number (val); | 293 | arg = make_number (val); |
| 293 | mpz_clear (val); | 294 | mpz_clear (val); |
| 294 | } | 295 | } |
diff --git a/src/lisp.h b/src/lisp.h index e046429c1b1..4208634fa95 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3655,6 +3655,32 @@ extern Lisp_Object listn (enum constype, ptrdiff_t, Lisp_Object, ...); | |||
| 3655 | 3655 | ||
| 3656 | extern Lisp_Object make_bignum_str (const char *num, int base); | 3656 | extern Lisp_Object make_bignum_str (const char *num, int base); |
| 3657 | extern Lisp_Object make_number (mpz_t value); | 3657 | extern Lisp_Object make_number (mpz_t value); |
| 3658 | extern void mpz_set_intmax_slow (mpz_t result, intmax_t v); | ||
| 3659 | extern void mpz_set_uintmax_slow (mpz_t result, uintmax_t v); | ||
| 3660 | |||
| 3661 | INLINE void | ||
| 3662 | mpz_set_intmax (mpz_t result, intmax_t v) | ||
| 3663 | { | ||
| 3664 | /* mpz_set_si works in terms of long, but Emacs may use a wider | ||
| 3665 | integer type, and so sometimes will have to construct the mpz_t | ||
| 3666 | by hand. */ | ||
| 3667 | if (sizeof (intmax_t) > sizeof (long) && (long) v != v) | ||
| 3668 | mpz_set_intmax_slow (result, v); | ||
| 3669 | else | ||
| 3670 | mpz_set_si (result, v); | ||
| 3671 | } | ||
| 3672 | |||
| 3673 | INLINE void | ||
| 3674 | mpz_set_uintmax (mpz_t result, uintmax_t v) | ||
| 3675 | { | ||
| 3676 | /* mpz_set_ui works in terms of unsigned long, but Emacs may use a | ||
| 3677 | wider integer type, and so sometimes will have to construct the | ||
| 3678 | mpz_t by hand. */ | ||
| 3679 | if (sizeof (uintmax_t) > sizeof (unsigned long) && (unsigned long) v != v) | ||
| 3680 | mpz_set_uintmax_slow (result, v); | ||
| 3681 | else | ||
| 3682 | mpz_set_ui (result, v); | ||
| 3683 | } | ||
| 3658 | 3684 | ||
| 3659 | /* Build a frequently used 2/3/4-integer lists. */ | 3685 | /* Build a frequently used 2/3/4-integer lists. */ |
| 3660 | 3686 | ||