summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tom@tromey.com>2018-07-19 15:58:10 -0600
committerTom Tromey <tom@tromey.com>2018-07-19 16:08:41 -0600
commit76715f8921dca740880cd22c644a6328cd810846 (patch)
treed85940e4c452575c453ab3ea6a7d0ec25b20f2ab
parent678881e428073b39a906c1ffd01e1b76e271cb5d (diff)
downloademacs-feature/bignum.tar.gz
Fix bignum creation when EMACS_INT is wider than longfeature/bignum
* 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.
-rw-r--r--src/alloc.c30
-rw-r--r--src/data.c36
-rw-r--r--src/emacs-module.c3
-rw-r--r--src/floatfns.c3
-rw-r--r--src/lisp.h26
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)
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);
+}
+
/* Return a newly created vector or string with specified arguments as
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)
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);
}
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)
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);
}
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,
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);
}
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, ...);
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. */