diff options
| author | Paul Eggert | 2018-08-18 19:40:24 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-08-18 19:41:33 -0700 |
| commit | 6eade1efde873d0b048d8f2841646924cb2ceb16 (patch) | |
| tree | 6d4e3304cf8acedb9b3d841d6de35a3c868ec029 /src/alloc.c | |
| parent | 1d2df2fd03f35ca8d8dfc8b999d8bba3c7c13157 (diff) | |
| download | emacs-6eade1efde873d0b048d8f2841646924cb2ceb16.tar.gz emacs-6eade1efde873d0b048d8f2841646924cb2ceb16.zip | |
Improve --with-wide-int mpz_t→fixnum conversion
These tuneups and minor simplifications should affect only
platforms with EMACS_INT wider than ‘long’.
* src/alloc.c (make_number): If the number fits in long but
not in fixnum, do not attempt to convert to fixnum again.
Tighten the compile-time check for whether the second attempt
is worth trying, from sizeof (long) < sizeof (EMACS_INT) to
LONG_WIDTH < FIXNUM_BITS. Do not bother computing the sign of
the value to tighten the bounds for whether to try the second
attempt, as it’s not worth the effort. Do not call mpz_size,
which is unnecessary since the number of bits is already known
and the loop can iterate over a shift count instead. Avoid
unnecessary casts. Use + instead of | where either will do,
as + is typically better for optimization.
Improve mpz_t to fixnum when --with-wide-int
* src/alloc.c (make_number): Avoid undefined behavior
when shifting an EMACS_UINT by more than EMACS_UINT_WIDTH bits.
Check for integer overflow when shifting.
Diffstat (limited to 'src/alloc.c')
| -rw-r--r-- | src/alloc.c | 19 |
1 files changed, 7 insertions, 12 deletions
diff --git a/src/alloc.c b/src/alloc.c index 0cd3f0c0c3b..60850f73d51 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3752,25 +3752,20 @@ make_number (mpz_t value) | |||
| 3752 | if (!FIXNUM_OVERFLOW_P (l)) | 3752 | if (!FIXNUM_OVERFLOW_P (l)) |
| 3753 | return make_fixnum (l); | 3753 | return make_fixnum (l); |
| 3754 | } | 3754 | } |
| 3755 | 3755 | else if (LONG_WIDTH < FIXNUM_BITS) | |
| 3756 | /* Check if fixnum can be larger than long. */ | ||
| 3757 | if (sizeof (EMACS_INT) > sizeof (long)) | ||
| 3758 | { | 3756 | { |
| 3759 | size_t bits = mpz_sizeinbase (value, 2); | 3757 | size_t bits = mpz_sizeinbase (value, 2); |
| 3760 | int sign = mpz_sgn (value); | ||
| 3761 | 3758 | ||
| 3762 | if (bits < FIXNUM_BITS + (sign < 0)) | 3759 | if (bits <= FIXNUM_BITS) |
| 3763 | { | 3760 | { |
| 3764 | EMACS_INT v = 0; | 3761 | EMACS_INT v = 0; |
| 3765 | size_t limbs = mpz_size (value); | 3762 | int i = 0; |
| 3766 | mp_size_t i; | 3763 | for (int shift = 0; shift < bits; shift += mp_bits_per_limb) |
| 3767 | |||
| 3768 | for (i = 0; i < limbs; i++) | ||
| 3769 | { | 3764 | { |
| 3770 | mp_limb_t limb = mpz_getlimbn (value, i); | 3765 | EMACS_INT limb = mpz_getlimbn (value, i++); |
| 3771 | v |= (EMACS_INT) ((EMACS_UINT) limb << (i * mp_bits_per_limb)); | 3766 | v += limb << shift; |
| 3772 | } | 3767 | } |
| 3773 | if (sign < 0) | 3768 | if (mpz_sgn (value) < 0) |
| 3774 | v = -v; | 3769 | v = -v; |
| 3775 | 3770 | ||
| 3776 | if (!FIXNUM_OVERFLOW_P (v)) | 3771 | if (!FIXNUM_OVERFLOW_P (v)) |