diff options
| author | Paul Eggert | 2018-09-03 18:37:40 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-09-03 18:50:34 -0700 |
| commit | fe042e9d15da7863b5beb4c2cc326a62d2c7fccb (patch) | |
| tree | 84fac8f99c678667e01d69d5e2ef17f4c8e8e275 /src/floatfns.c | |
| parent | 40f8ade7c81ab6f99537691ae00d2d42069bdb20 (diff) | |
| download | emacs-fe042e9d15da7863b5beb4c2cc326a62d2c7fccb.tar.gz emacs-fe042e9d15da7863b5beb4c2cc326a62d2c7fccb.zip | |
Speed up (+ 2 2) by a factor of 10
Improve arithmetic performance by avoiding bignums until needed.
Also, simplify bignum memory management, fixing some unlikely leaks.
This patch improved the performance of (+ 2 2) by a factor of ten
on a simple microbenchmark computing (+ x 2), byte-compiled,
with x a local variable initialized to 2 via means the byte
compiler could not predict: performance improved from 135 to 13 ns.
The platform was Fedora 28 x86-64, AMD Phenom II X4 910e.
Performance also improved 0.6% on ‘make compile-always’.
* src/bignum.c (init_bignum_once): New function.
* src/emacs.c (main): Use it.
* src/bignum.c (mpz): New global var.
(make_integer_mpz): Rename from make_integer. All uses changed.
* src/bignum.c (double_to_bignum, make_bignum_bits)
(make_bignum, make_bigint, make_biguint, make_integer_mpz):
* src/data.c (bignum_arith_driver, Frem, Flogcount, Fash)
(expt_integer, Fadd1, Fsub1, Flognot):
* src/floatfns.c (Fabs, rounding_driver, rounddiv_q):
* src/fns.c (Fnthcdr):
Use mpz rather than mpz_initting and mpz_clearing private
temporaries.
* src/bignum.h (bignum_integer): New function.
* src/data.c (Frem, Fmod, Fash, expt_integer):
* src/floatfns.c (rounding_driver):
Use it to simplify code.
* src/data.c (FIXNUMS_FIT_IN_LONG, free_mpz_value):
Remove. All uses removed.
(floating_point_op): New function.
(floatop_arith_driver): New function, with much of the guts
of the old float_arith_driver.
(float_arith_driver): Use it.
(floatop_arith_driver, arith_driver):
Simplify by assuming NARGS is at least 2.
All callers changed.
(float_arith_driver):
New arg, containing the partly converted value of the next arg.
Reorder args for consistency. All uses changed.
(bignum_arith_driver): New function.
(arith_driver): Use it. Do fixnum-only integer calculations
in intmax_t instead of mpz_t, when they fit.
Break out mpz_t calculations into bignum_arith_driver.
(Fquo): Use floatop_arith_driver instead of float_arith_driver,
since the op is known to be valid.
(Flogcount, Fash): Simplify by coalescing bignum and fixnum code.
(Fadd1, Fsub1): Simplify by using make_int.
Diffstat (limited to 'src/floatfns.c')
| -rw-r--r-- | src/floatfns.c | 44 |
1 files changed, 13 insertions, 31 deletions
diff --git a/src/floatfns.c b/src/floatfns.c index 77e20d5640b..2f33b8652b2 100644 --- a/src/floatfns.c +++ b/src/floatfns.c | |||
| @@ -270,11 +270,8 @@ DEFUN ("abs", Fabs, Sabs, 1, 1, 0, | |||
| 270 | { | 270 | { |
| 271 | if (mpz_sgn (XBIGNUM (arg)->value) < 0) | 271 | if (mpz_sgn (XBIGNUM (arg)->value) < 0) |
| 272 | { | 272 | { |
| 273 | mpz_t val; | 273 | mpz_neg (mpz[0], XBIGNUM (arg)->value); |
| 274 | mpz_init (val); | 274 | arg = make_integer_mpz (); |
| 275 | mpz_neg (val, XBIGNUM (arg)->value); | ||
| 276 | arg = make_integer (val); | ||
| 277 | mpz_clear (val); | ||
| 278 | } | 275 | } |
| 279 | } | 276 | } |
| 280 | 277 | ||
| @@ -360,20 +357,10 @@ rounding_driver (Lisp_Object arg, Lisp_Object divisor, | |||
| 360 | { | 357 | { |
| 361 | if (EQ (divisor, make_fixnum (0))) | 358 | if (EQ (divisor, make_fixnum (0))) |
| 362 | xsignal0 (Qarith_error); | 359 | xsignal0 (Qarith_error); |
| 363 | mpz_t d, q; | 360 | int_divide (mpz[0], |
| 364 | mpz_init (d); | 361 | *bignum_integer (&mpz[0], arg), |
| 365 | mpz_init (q); | 362 | *bignum_integer (&mpz[1], divisor)); |
| 366 | int_divide (q, | 363 | return make_integer_mpz (); |
| 367 | (FIXNUMP (arg) | ||
| 368 | ? (mpz_set_intmax (q, XFIXNUM (arg)), q) | ||
| 369 | : XBIGNUM (arg)->value), | ||
| 370 | (FIXNUMP (divisor) | ||
| 371 | ? (mpz_set_intmax (d, XFIXNUM (divisor)), d) | ||
| 372 | : XBIGNUM (divisor)->value)); | ||
| 373 | Lisp_Object result = make_integer (q); | ||
| 374 | mpz_clear (d); | ||
| 375 | mpz_clear (q); | ||
| 376 | return result; | ||
| 377 | } | 364 | } |
| 378 | 365 | ||
| 379 | double f1 = FLOATP (arg) ? XFLOAT_DATA (arg) : XFIXNUM (arg); | 366 | double f1 = FLOATP (arg) ? XFLOAT_DATA (arg) : XFIXNUM (arg); |
| @@ -417,20 +404,15 @@ rounddiv_q (mpz_t q, mpz_t const n, mpz_t const d) | |||
| 417 | if (abs_r1 < abs_r + (q & 1)) | 404 | if (abs_r1 < abs_r + (q & 1)) |
| 418 | q += neg_d == neg_r ? 1 : -1; */ | 405 | q += neg_d == neg_r ? 1 : -1; */ |
| 419 | 406 | ||
| 420 | mpz_t r, abs_r1; | 407 | mpz_t *r = &mpz[2], *abs_r = r, *abs_r1 = &mpz[3]; |
| 421 | mpz_init (r); | 408 | mpz_tdiv_qr (q, *r, n, d); |
| 422 | mpz_init (abs_r1); | ||
| 423 | mpz_tdiv_qr (q, r, n, d); | ||
| 424 | bool neg_d = mpz_sgn (d) < 0; | 409 | bool neg_d = mpz_sgn (d) < 0; |
| 425 | bool neg_r = mpz_sgn (r) < 0; | 410 | bool neg_r = mpz_sgn (*r) < 0; |
| 426 | mpz_t *abs_r = &r; | 411 | mpz_abs (*abs_r, *r); |
| 427 | mpz_abs (*abs_r, r); | 412 | mpz_abs (*abs_r1, d); |
| 428 | mpz_abs (abs_r1, d); | 413 | mpz_sub (*abs_r1, *abs_r1, *abs_r); |
| 429 | mpz_sub (abs_r1, abs_r1, *abs_r); | 414 | if (mpz_cmp (*abs_r1, *abs_r) < (mpz_odd_p (q) != 0)) |
| 430 | if (mpz_cmp (abs_r1, *abs_r) < (mpz_odd_p (q) != 0)) | ||
| 431 | (neg_d == neg_r ? mpz_add_ui : mpz_sub_ui) (q, q, 1); | 415 | (neg_d == neg_r ? mpz_add_ui : mpz_sub_ui) (q, q, 1); |
| 432 | mpz_clear (r); | ||
| 433 | mpz_clear (abs_r1); | ||
| 434 | } | 416 | } |
| 435 | 417 | ||
| 436 | /* The code uses emacs_rint, so that it works to undefine HAVE_RINT | 418 | /* The code uses emacs_rint, so that it works to undefine HAVE_RINT |