]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix bignum creation when EMACS_INT is wider than long
authorTom Tromey <tom@tromey.com>
Thu, 19 Jul 2018 21:58:10 +0000 (15:58 -0600)
committerTom Tromey <tom@tromey.com>
Thu, 19 Jul 2018 22:08:41 +0000 (16:08 -0600)
* 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.

src/alloc.c
src/data.c
src/emacs-module.c
src/floatfns.c
src/lisp.h

index b775948fd96656472c11a3944bc2b1b1a3c403df..1dc1bbb031ae885a646fb998d394438cfe4e3128 100644 (file)
@@ -3824,6 +3824,36 @@ make_number (mpz_t value)
   return obj;
 }
 
+void
+mpz_set_intmax_slow (mpz_t result, intmax_t v)
+{
+  /* If long is larger then a faster path is taken.  */
+  eassert (sizeof (intmax_t) > sizeof (long));
+
+  bool negate = false;
+  if (v < 0)
+    {
+      v = -v;
+      negate = true;
+    }
+  mpz_set_uintmax_slow (result, (uintmax_t) v);
+  if (negate)
+    mpz_neg (result, result);
+}
+
+void
+mpz_set_uintmax_slow (mpz_t result, uintmax_t v)
+{
+  /* If long is larger then a faster path is taken.  */
+  eassert (sizeof (uintmax_t) > sizeof (unsigned long));
+  /* This restriction could be lifted if needed.  */
+  eassert (sizeof (uintmax_t) <= 2 * sizeof (unsigned long));
+
+  mpz_set_ui (result, v >> (CHAR_BIT * sizeof (unsigned long)));
+  mpz_mul_2exp (result, result, CHAR_BIT * sizeof (unsigned long));
+  mpz_add_ui (result, result, v & -1ul);
+}
+
 \f
 /* Return a newly created vector or string with specified arguments as
    elements.  If all the arguments are characters that can fit
index 862381229d7b975222ebf9b73d1dd21f5692c536..0deebdca1ae2f627e2986b8d8f54606e3066c1f8 100644 (file)
@@ -2882,7 +2882,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
              if (BIGNUMP (val))
                mpz_set (accum, XBIGNUM (val)->value);
              else
-               mpz_set_si (accum, XINT (val));
+               mpz_set_intmax (accum, XINT (val));
              if (nargs == 1)
                mpz_neg (accum, accum);
            }
@@ -2905,7 +2905,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
              if (BIGNUMP (val))
                mpz_set (accum, XBIGNUM (val)->value);
              else
-               mpz_set_si (accum, XINT (val));
+               mpz_set_intmax (accum, XINT (val));
            }
          else
            {
@@ -2933,7 +2933,8 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
          else
            {
              mpz_t tem;
-             mpz_init_set_ui (tem, XUINT (val));
+             mpz_init (tem);
+             mpz_set_uintmax (tem, XUINT (val));
              mpz_and (accum, accum, tem);
              mpz_clear (tem);
            }
@@ -2944,7 +2945,8 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
          else
            {
              mpz_t tem;
-             mpz_init_set_ui (tem, XUINT (val));
+             mpz_init (tem);
+             mpz_set_uintmax (tem, XUINT (val));
              mpz_ior (accum, accum, tem);
              mpz_clear (tem);
            }
@@ -2955,7 +2957,8 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
          else
            {
              mpz_t tem;
-             mpz_init_set_ui (tem, XUINT (val));
+             mpz_init (tem);
+             mpz_set_uintmax (tem, XUINT (val));
              mpz_xor (accum, accum, tem);
              mpz_clear (tem);
            }
@@ -3092,7 +3095,8 @@ Both must be integers or markers.  */)
        xmp = &XBIGNUM (x)->value;
       else
        {
-         mpz_init_set_si (xm, XINT (x));
+         mpz_init (xm);
+         mpz_set_intmax (xm, XINT (x));
          xmp = &xm;
        }
 
@@ -3100,7 +3104,8 @@ Both must be integers or markers.  */)
        ymp = &XBIGNUM (y)->value;
       else
        {
-         mpz_init_set_si (ym, XINT (y));
+         mpz_init (ym);
+         mpz_set_intmax (ym, XINT (y));
          ymp = &ym;
        }
 
@@ -3163,7 +3168,8 @@ Both X and Y must be numbers or markers.  */)
        xmp = &XBIGNUM (x)->value;
       else
        {
-         mpz_init_set_si (xm, XINT (x));
+         mpz_init (xm);
+         mpz_set_intmax (xm, XINT (x));
          xmp = &xm;
        }
 
@@ -3171,7 +3177,8 @@ Both X and Y must be numbers or markers.  */)
        ymp = &XBIGNUM (y)->value;
       else
        {
-         mpz_init_set_si (ym, XINT (y));
+         mpz_init (ym);
+         mpz_set_intmax (ym, XINT (y));
          ymp = &ym;
        }
 
@@ -3317,10 +3324,11 @@ ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh)
       /* Just do the work as bignums to make the code simpler.  */
       mpz_t result;
       eassume (FIXNUMP (value));
+      mpz_init (result);
       if (lsh)
-       mpz_init_set_ui (result, XUINT (value));
+       mpz_set_uintmax (result, XUINT (value));
       else
-       mpz_init_set_si (result, XINT (value));
+       mpz_set_intmax (result, XINT (value));
       if (XINT (count) >= 0)
        mpz_mul_2exp (result, result, XINT (count));
       else
@@ -3376,7 +3384,8 @@ Markers are converted to integers.  */)
       else
        {
          mpz_t num;
-         mpz_init_set_si (num, XINT (number) + 1);
+         mpz_init (num);
+         mpz_set_intmax (num, XINT (number) + 1);
          number = make_number (num);
          mpz_clear (num);
        }
@@ -3410,7 +3419,8 @@ Markers are converted to integers.  */)
       else
        {
          mpz_t num;
-         mpz_init_set_si (num, XINT (number) - 1);
+         mpz_init (num);
+         mpz_set_intmax (num, XINT (number) - 1);
          number = make_number (num);
          mpz_clear (num);
        }
index 7709eeca94a72eab95d6eeb35d406da6fef3d702..39150f6f67b8b84c5e6ddd24c47ba86d3dca257a 100644 (file)
@@ -536,7 +536,8 @@ module_make_integer (emacs_env *env, intmax_t n)
   if (FIXNUM_OVERFLOW_P (n))
     {
       mpz_t val;
-      mpz_init_set_si (val, n);
+      mpz_init (val);
+      mpz_set_intmax (val, n);
       obj = make_number (val);
       mpz_clear (val);
     }
index 9a5f0a3ad2f66eb2a33e2955fa9e26ea5a57a8f1..563c65f827a51e724048bb4b36ecfadd9e9c8a1e 100644 (file)
@@ -288,7 +288,8 @@ DEFUN ("abs", Fabs, Sabs, 1, 1, 0,
   else if (FIXNUMP (arg) && XINT (arg) == MOST_NEGATIVE_FIXNUM)
     {
       mpz_t val;
-      mpz_init_set_si (val, - MOST_NEGATIVE_FIXNUM);
+      mpz_init (val);
+      mpz_set_intmax (val, - MOST_NEGATIVE_FIXNUM);
       arg = make_number (val);
       mpz_clear (val);
     }
index e046429c1b1809a3d2eb2781d88117a26d136fd1..4208634fa95e519e95ee31ac1e8dce20727557d1 100644 (file)
@@ -3655,6 +3655,32 @@ extern Lisp_Object listn (enum constype, ptrdiff_t, Lisp_Object, ...);
 
 extern Lisp_Object make_bignum_str (const char *num, int base);
 extern Lisp_Object make_number (mpz_t value);
+extern void mpz_set_intmax_slow (mpz_t result, intmax_t v);
+extern void mpz_set_uintmax_slow (mpz_t result, uintmax_t v);
+
+INLINE void
+mpz_set_intmax (mpz_t result, intmax_t v)
+{
+  /* mpz_set_si works in terms of long, but Emacs may use a wider
+     integer type, and so sometimes will have to construct the mpz_t
+     by hand.  */
+  if (sizeof (intmax_t) > sizeof (long) && (long) v != v)
+    mpz_set_intmax_slow (result, v);
+  else
+    mpz_set_si (result, v);
+}
+
+INLINE void
+mpz_set_uintmax (mpz_t result, uintmax_t v)
+{
+  /* mpz_set_ui works in terms of unsigned long, but Emacs may use a
+     wider integer type, and so sometimes will have to construct the
+     mpz_t by hand.  */
+  if (sizeof (uintmax_t) > sizeof (unsigned long) && (unsigned long) v != v)
+    mpz_set_uintmax_slow (result, v);
+  else
+    mpz_set_ui (result, v);
+}
 
 /* Build a frequently used 2/3/4-integer lists.  */