diff options
Diffstat (limited to 'src/data.c')
| -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. */) | |||
| 3365 | : count_one_bits_ll (v)); | 3365 | : count_one_bits_ll (v)); |
| 3366 | } | 3366 | } |
| 3367 | 3367 | ||
| 3368 | static Lisp_Object | 3368 | DEFUN ("ash", Fash, Sash, 2, 2, 0, |
| 3369 | ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) | 3369 | doc: /* Return VALUE with its bits shifted left by COUNT. |
| 3370 | If COUNT is negative, shifting is actually to the right. | ||
| 3371 | In this case, the sign bit is duplicated. */) | ||
| 3372 | (Lisp_Object value, Lisp_Object count) | ||
| 3370 | { | 3373 | { |
| 3371 | /* This code assumes that signed right shifts are arithmetic. */ | ||
| 3372 | verify ((EMACS_INT) -1 >> 1 == -1); | ||
| 3373 | |||
| 3374 | Lisp_Object val; | 3374 | Lisp_Object val; |
| 3375 | 3375 | ||
| 3376 | /* The negative of the minimum value of COUNT that fits into a fixnum, | ||
| 3377 | such that mpz_fdiv_q_exp supports -COUNT. */ | ||
| 3378 | EMACS_INT minus_count_min = min (-MOST_NEGATIVE_FIXNUM, | ||
| 3379 | TYPE_MAXIMUM (mp_bitcnt_t)); | ||
| 3376 | CHECK_INTEGER (value); | 3380 | CHECK_INTEGER (value); |
| 3377 | CHECK_FIXNUM (count); | 3381 | CHECK_RANGED_INTEGER (count, - minus_count_min, TYPE_MAXIMUM (mp_bitcnt_t)); |
| 3378 | 3382 | ||
| 3379 | if (BIGNUMP (value)) | 3383 | if (BIGNUMP (value)) |
| 3380 | { | 3384 | { |
| 3385 | if (XFIXNUM (count) == 0) | ||
| 3386 | return value; | ||
| 3381 | mpz_t result; | 3387 | mpz_t result; |
| 3382 | mpz_init (result); | 3388 | mpz_init (result); |
| 3383 | if (XFIXNUM (count) >= 0) | 3389 | if (XFIXNUM (count) > 0) |
| 3384 | mpz_mul_2exp (result, XBIGNUM (value)->value, XFIXNUM (count)); | 3390 | mpz_mul_2exp (result, XBIGNUM (value)->value, XFIXNUM (count)); |
| 3385 | else if (lsh) | ||
| 3386 | mpz_tdiv_q_2exp (result, XBIGNUM (value)->value, - XFIXNUM (count)); | ||
| 3387 | else | 3391 | else |
| 3388 | mpz_fdiv_q_2exp (result, XBIGNUM (value)->value, - XFIXNUM (count)); | 3392 | mpz_fdiv_q_2exp (result, XBIGNUM (value)->value, - XFIXNUM (count)); |
| 3389 | val = make_number (result); | 3393 | val = make_number (result); |
| 3390 | mpz_clear (result); | 3394 | mpz_clear (result); |
| 3391 | } | 3395 | } |
| 3396 | else if (XFIXNUM (count) <= 0) | ||
| 3397 | { | ||
| 3398 | /* This code assumes that signed right shifts are arithmetic. */ | ||
| 3399 | verify ((EMACS_INT) -1 >> 1 == -1); | ||
| 3400 | |||
| 3401 | EMACS_INT shift = -XFIXNUM (count); | ||
| 3402 | EMACS_INT result = (shift < EMACS_INT_WIDTH ? XFIXNUM (value) >> shift | ||
| 3403 | : XFIXNUM (value) < 0 ? -1 : 0); | ||
| 3404 | val = make_fixnum (result); | ||
| 3405 | } | ||
| 3392 | else | 3406 | else |
| 3393 | { | 3407 | { |
| 3394 | /* Just do the work as bignums to make the code simpler. */ | 3408 | /* 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) | |||
| 3400 | 3414 | ||
| 3401 | if (XFIXNUM (count) >= 0) | 3415 | if (XFIXNUM (count) >= 0) |
| 3402 | mpz_mul_2exp (result, result, XFIXNUM (count)); | 3416 | mpz_mul_2exp (result, result, XFIXNUM (count)); |
| 3403 | else if (lsh) | 3417 | else |
| 3404 | { | ||
| 3405 | if (mpz_sgn (result) > 0) | ||
| 3406 | mpz_fdiv_q_2exp (result, result, - XFIXNUM (count)); | ||
| 3407 | else | ||
| 3408 | mpz_fdiv_q_2exp (result, result, - XFIXNUM (count)); | ||
| 3409 | } | ||
| 3410 | else /* ash */ | ||
| 3411 | mpz_fdiv_q_2exp (result, result, - XFIXNUM (count)); | 3418 | mpz_fdiv_q_2exp (result, result, - XFIXNUM (count)); |
| 3412 | 3419 | ||
| 3413 | val = make_number (result); | 3420 | val = make_number (result); |
| @@ -3417,24 +3424,6 @@ ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) | |||
| 3417 | return val; | 3424 | return val; |
| 3418 | } | 3425 | } |
| 3419 | 3426 | ||
| 3420 | DEFUN ("ash", Fash, Sash, 2, 2, 0, | ||
| 3421 | doc: /* Return VALUE with its bits shifted left by COUNT. | ||
| 3422 | If COUNT is negative, shifting is actually to the right. | ||
| 3423 | In this case, the sign bit is duplicated. */) | ||
| 3424 | (register Lisp_Object value, Lisp_Object count) | ||
| 3425 | { | ||
| 3426 | return ash_lsh_impl (value, count, false); | ||
| 3427 | } | ||
| 3428 | |||
| 3429 | DEFUN ("lsh", Flsh, Slsh, 2, 2, 0, | ||
| 3430 | doc: /* Return VALUE with its bits shifted left by COUNT. | ||
| 3431 | If COUNT is negative, shifting is actually to the right. | ||
| 3432 | In this case, zeros are shifted in on the left. */) | ||
| 3433 | (register Lisp_Object value, Lisp_Object count) | ||
| 3434 | { | ||
| 3435 | return ash_lsh_impl (value, count, true); | ||
| 3436 | } | ||
| 3437 | |||
| 3438 | DEFUN ("1+", Fadd1, Sadd1, 1, 1, 0, | 3427 | DEFUN ("1+", Fadd1, Sadd1, 1, 1, 0, |
| 3439 | doc: /* Return NUMBER plus one. NUMBER may be a number or a marker. | 3428 | doc: /* Return NUMBER plus one. NUMBER may be a number or a marker. |
| 3440 | Markers are converted to integers. */) | 3429 | Markers are converted to integers. */) |
| @@ -4235,7 +4224,6 @@ syms_of_data (void) | |||
| 4235 | defsubr (&Slogior); | 4224 | defsubr (&Slogior); |
| 4236 | defsubr (&Slogxor); | 4225 | defsubr (&Slogxor); |
| 4237 | defsubr (&Slogcount); | 4226 | defsubr (&Slogcount); |
| 4238 | defsubr (&Slsh); | ||
| 4239 | defsubr (&Sash); | 4227 | defsubr (&Sash); |
| 4240 | defsubr (&Sadd1); | 4228 | defsubr (&Sadd1); |
| 4241 | defsubr (&Ssub1); | 4229 | defsubr (&Ssub1); |