diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/data.c | 60 |
1 files changed, 24 insertions, 36 deletions
diff --git a/src/data.c b/src/data.c index 5a355d9787c..a39978ab1dc 100644 --- a/src/data.c +++ b/src/data.c @@ -3365,30 +3365,44 @@ representation. */) : count_one_bits_ll (v)); } -static Lisp_Object -ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) +DEFUN ("ash", Fash, Sash, 2, 2, 0, + doc: /* Return VALUE with its bits shifted left by COUNT. +If COUNT is negative, shifting is actually to the right. +In this case, the sign bit is duplicated. */) + (Lisp_Object value, Lisp_Object count) { - /* This code assumes that signed right shifts are arithmetic. */ - verify ((EMACS_INT) -1 >> 1 == -1); - Lisp_Object val; + /* The negative of the minimum value of COUNT that fits into a fixnum, + such that mpz_fdiv_q_exp supports -COUNT. */ + EMACS_INT minus_count_min = min (-MOST_NEGATIVE_FIXNUM, + TYPE_MAXIMUM (mp_bitcnt_t)); CHECK_INTEGER (value); - CHECK_FIXNUM (count); + CHECK_RANGED_INTEGER (count, - minus_count_min, TYPE_MAXIMUM (mp_bitcnt_t)); if (BIGNUMP (value)) { + if (XFIXNUM (count) == 0) + return value; mpz_t result; mpz_init (result); - if (XFIXNUM (count) >= 0) + if (XFIXNUM (count) > 0) mpz_mul_2exp (result, XBIGNUM (value)->value, XFIXNUM (count)); - else if (lsh) - mpz_tdiv_q_2exp (result, XBIGNUM (value)->value, - XFIXNUM (count)); else mpz_fdiv_q_2exp (result, XBIGNUM (value)->value, - XFIXNUM (count)); val = make_number (result); mpz_clear (result); } + else if (XFIXNUM (count) <= 0) + { + /* This code assumes that signed right shifts are arithmetic. */ + verify ((EMACS_INT) -1 >> 1 == -1); + + EMACS_INT shift = -XFIXNUM (count); + EMACS_INT result = (shift < EMACS_INT_WIDTH ? XFIXNUM (value) >> shift + : XFIXNUM (value) < 0 ? -1 : 0); + val = make_fixnum (result); + } else { /* Just do the work as bignums to make the code simpler. */ @@ -3400,14 +3414,7 @@ ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) if (XFIXNUM (count) >= 0) mpz_mul_2exp (result, result, XFIXNUM (count)); - else if (lsh) - { - if (mpz_sgn (result) > 0) - mpz_fdiv_q_2exp (result, result, - XFIXNUM (count)); - else - mpz_fdiv_q_2exp (result, result, - XFIXNUM (count)); - } - else /* ash */ + else mpz_fdiv_q_2exp (result, result, - XFIXNUM (count)); val = make_number (result); @@ -3417,24 +3424,6 @@ ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) return val; } -DEFUN ("ash", Fash, Sash, 2, 2, 0, - doc: /* Return VALUE with its bits shifted left by COUNT. -If COUNT is negative, shifting is actually to the right. -In this case, the sign bit is duplicated. */) - (register Lisp_Object value, Lisp_Object count) -{ - return ash_lsh_impl (value, count, false); -} - -DEFUN ("lsh", Flsh, Slsh, 2, 2, 0, - doc: /* Return VALUE with its bits shifted left by COUNT. -If COUNT is negative, shifting is actually to the right. -In this case, zeros are shifted in on the left. */) - (register Lisp_Object value, Lisp_Object count) -{ - return ash_lsh_impl (value, count, true); -} - DEFUN ("1+", Fadd1, Sadd1, 1, 1, 0, doc: /* Return NUMBER plus one. NUMBER may be a number or a marker. Markers are converted to integers. */) @@ -4235,7 +4224,6 @@ syms_of_data (void) defsubr (&Slogior); defsubr (&Slogxor); defsubr (&Slogcount); - defsubr (&Slsh); defsubr (&Sash); defsubr (&Sadd1); defsubr (&Ssub1); |