diff options
| author | Mattias EngdegÄrd | 2023-01-18 18:36:29 +0100 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2023-02-02 14:46:53 +0100 |
| commit | bfd338aad9d1e6bf898fc19d23e1a5ca4e696316 (patch) | |
| tree | 47d30f360c777d747574e48b888ec417a912576a | |
| parent | f6955482c2933706229044c04d88b807b63a7095 (diff) | |
| download | emacs-bfd338aad9d1e6bf898fc19d23e1a5ca4e696316.tar.gz emacs-bfd338aad9d1e6bf898fc19d23e1a5ca4e696316.zip | |
LAP peephole optimisation improvements
- Since discardN-preserve-tos(1) and stack-set(1) have the same
effect, treat them as equivalent in all transformations.
- Move the rule
discardN-preserve-tos(X) discardN-preserve-tos(Y)
--> discardN-preserve-tos(X+Y)
from the final pass to the main iteration since it may enable
further optimisations.
- Don't apply the rule
goto(X) ... X: DISCARD --> DISCARD goto(Y) ... X: DISCARD Y:
when DISCARD could be merged or deleted instead, which is even better.
- Add the rule
OP const return -> <deleted> const return
where OP is effect-free.
- Generalise the push-pop annihilation rule to
PUSH(K) discard(N) -> discard(N-K), N>K
PUSH(K) discard(N) -> <deleted>, N=K
to any N, not just N=1.
- Add the rule
OP goto(X) Y: OP X: -> <deleted> Y: OP X:
for any operation OP.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Make the changes described above.
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 128 |
1 files changed, 90 insertions, 38 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 9eb48f5fe0b..861cf95b1ff 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -2042,31 +2042,29 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." | |||
| 2042 | ;; optimized but sequences like "dup varset TAG1: discard" are not. | 2042 | ;; optimized but sequences like "dup varset TAG1: discard" are not. |
| 2043 | ;; You may be tempted to change this; resist that temptation. | 2043 | ;; You may be tempted to change this; resist that temptation. |
| 2044 | (cond | 2044 | (cond |
| 2045 | ;; <side-effect-free> pop --> <deleted> | 2045 | ;; |
| 2046 | ;; ...including: | 2046 | ;; PUSH(K) discard(N) --> <deleted> discard(N-K), N>K |
| 2047 | ;; const-X pop --> <deleted> | 2047 | ;; PUSH(K) discard(N) --> <deleted>, N=K |
| 2048 | ;; varref-X pop --> <deleted> | 2048 | ;; where PUSH(K) is a side-effect-free op such as const, varref, dup |
| 2049 | ;; dup pop --> <deleted> | 2049 | ;; |
| 2050 | ;; | 2050 | ((and (memq (car lap1) '(byte-discard byte-discardN)) |
| 2051 | ((and (eq 'byte-discard (car lap1)) | ||
| 2052 | (memq (car lap0) side-effect-free)) | 2051 | (memq (car lap0) side-effect-free)) |
| 2053 | (setq keep-going t) | 2052 | (setq keep-going t) |
| 2054 | (setq tmp (aref byte-stack+-info (symbol-value (car lap0)))) | 2053 | (let* ((pushes (aref byte-stack+-info (symbol-value (car lap0)))) |
| 2055 | (setq rest (cdr rest)) | 2054 | (pops (if (eq (car lap1) 'byte-discardN) (cdr lap1) 1)) |
| 2056 | (cond ((eql tmp 1) | 2055 | (net-pops (- pops pushes))) |
| 2057 | (byte-compile-log-lap | 2056 | (cond ((= net-pops 0) |
| 2058 | " %s discard\t-->\t<deleted>" lap0) | 2057 | (byte-compile-log-lap " %s %s\t-->\t<deleted>" lap0 lap1) |
| 2059 | (setq lap (delq lap0 (delq lap1 lap)))) | 2058 | (setcdr rest (cddr rest)) |
| 2060 | ((eql tmp 0) | 2059 | (setq lap (delq lap0 lap))) |
| 2061 | (byte-compile-log-lap | 2060 | ((> net-pops 0) |
| 2062 | " %s discard\t-->\t<deleted> discard" lap0) | 2061 | (byte-compile-log-lap |
| 2063 | (setq lap (delq lap0 lap))) | 2062 | " %s %s\t-->\t<deleted> discard(%d)" lap0 lap1 net-pops) |
| 2064 | ((eql tmp -1) | 2063 | (setcar rest (if (eql net-pops 1) |
| 2065 | (byte-compile-log-lap | 2064 | (cons 'byte-discard nil) |
| 2066 | " %s discard\t-->\tdiscard discard" lap0) | 2065 | (cons 'byte-discardN net-pops))) |
| 2067 | (setcar lap0 'byte-discard) | 2066 | (setcdr rest (cddr rest))) |
| 2068 | (setcdr lap0 0)) | 2067 | (t (error "Optimizer error: too much on the stack"))))) |
| 2069 | (t (error "Optimizer error: too much on the stack")))) | ||
| 2070 | ;; | 2068 | ;; |
| 2071 | ;; goto*-X X: --> X: | 2069 | ;; goto*-X X: --> X: |
| 2072 | ;; | 2070 | ;; |
| @@ -2353,6 +2351,40 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." | |||
| 2353 | (setcar lap0 'byte-return)) | 2351 | (setcar lap0 'byte-return)) |
| 2354 | (setcdr lap0 (cdr tmp)) | 2352 | (setcdr lap0 (cdr tmp)) |
| 2355 | (setq keep-going t)))) | 2353 | (setq keep-going t)))) |
| 2354 | |||
| 2355 | ;; | ||
| 2356 | ;; OP goto(X) Y: OP X: -> Y: OP X: | ||
| 2357 | ;; | ||
| 2358 | ((and (eq (car lap1) 'byte-goto) | ||
| 2359 | (eq (car lap2) 'TAG) | ||
| 2360 | (let ((lap3 (nth 3 rest))) | ||
| 2361 | (and (eq (car lap0) (car lap3)) | ||
| 2362 | (eq (cdr lap0) (cdr lap3)) | ||
| 2363 | (eq (cdr lap1) (nth 4 rest))))) | ||
| 2364 | (byte-compile-log-lap " %s %s %s %s %s\t-->\t%s %s %s" | ||
| 2365 | lap0 lap1 lap2 | ||
| 2366 | (nth 3 rest) (nth 4 rest) | ||
| 2367 | lap2 (nth 3 rest) (nth 4 rest)) | ||
| 2368 | (setcdr rest (cddr rest)) | ||
| 2369 | (setq lap (delq lap0 lap)) | ||
| 2370 | (setq keep-going t)) | ||
| 2371 | |||
| 2372 | ;; | ||
| 2373 | ;; OP const return --> const return | ||
| 2374 | ;; where OP is side-effect-free (or mere stack manipulation). | ||
| 2375 | ;; | ||
| 2376 | ((and (eq (car lap1) 'byte-constant) | ||
| 2377 | (eq (car (nth 2 rest)) 'byte-return) | ||
| 2378 | (or (memq (car lap0) '( byte-discard byte-discardN | ||
| 2379 | byte-discardN-preserve-tos | ||
| 2380 | byte-stack-set)) | ||
| 2381 | (memq (car lap0) side-effect-free))) | ||
| 2382 | (setq keep-going t) | ||
| 2383 | (setq add-depth 1) ; in case we get rid of too much stack reduction | ||
| 2384 | (setq lap (delq lap0 lap)) | ||
| 2385 | (byte-compile-log-lap " %s %s %s\t-->\t%s %s" | ||
| 2386 | lap0 lap1 (nth 2 rest) lap1 (nth 2 rest))) | ||
| 2387 | |||
| 2356 | ;; | 2388 | ;; |
| 2357 | ;; goto-*-else-pop X ... X: goto-if-* --> whatever | 2389 | ;; goto-*-else-pop X ... X: goto-if-* --> whatever |
| 2358 | ;; goto-*-else-pop X ... X: discard --> whatever | 2390 | ;; goto-*-else-pop X ... X: discard --> whatever |
| @@ -2491,6 +2523,24 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." | |||
| 2491 | ) | 2523 | ) |
| 2492 | (setq keep-going t)) | 2524 | (setq keep-going t)) |
| 2493 | 2525 | ||
| 2526 | ;; | ||
| 2527 | ;; discardN-preserve-tos(X) discardN-preserve-tos(Y) | ||
| 2528 | ;; --> discardN-preserve-tos(X+Y) | ||
| 2529 | ;; where stack-set(1) is accepted as discardN-preserve-tos(1) | ||
| 2530 | ;; | ||
| 2531 | ((and (or (eq (car lap0) 'byte-discardN-preserve-tos) | ||
| 2532 | (and (eq (car lap0) 'byte-stack-set) (eql (cdr lap0) 1))) | ||
| 2533 | (or (eq (car lap1) 'byte-discardN-preserve-tos) | ||
| 2534 | (and (eq (car lap1) 'byte-stack-set) (eql (cdr lap1) 1)))) | ||
| 2535 | (setq keep-going t) | ||
| 2536 | (let ((new-op (cons 'byte-discardN-preserve-tos | ||
| 2537 | ;; This happens to work even when either | ||
| 2538 | ;; op is stack-set(1). | ||
| 2539 | (+ (cdr lap0) (cdr lap1))))) | ||
| 2540 | (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 new-op) | ||
| 2541 | (setcar rest new-op) | ||
| 2542 | (setcdr rest (cddr rest)))) | ||
| 2543 | |||
| 2494 | ;; | 2544 | ;; |
| 2495 | ;; stack-set-M [discard/discardN ...] --> discardN-preserve-tos | 2545 | ;; stack-set-M [discard/discardN ...] --> discardN-preserve-tos |
| 2496 | ;; stack-set-M [discard/discardN ...] --> discardN | 2546 | ;; stack-set-M [discard/discardN ...] --> discardN |
| @@ -2529,7 +2579,7 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." | |||
| 2529 | ;; | 2579 | ;; |
| 2530 | ;; discardN-preserve-tos return --> return | 2580 | ;; discardN-preserve-tos return --> return |
| 2531 | ;; dup return --> return | 2581 | ;; dup return --> return |
| 2532 | ;; stack-set-N return --> return ; where N is TOS-1 | 2582 | ;; stack-set(1) return --> return |
| 2533 | ;; | 2583 | ;; |
| 2534 | ((and (eq (car lap1) 'byte-return) | 2584 | ((and (eq (car lap1) 'byte-return) |
| 2535 | (or (memq (car lap0) '(byte-discardN-preserve-tos byte-dup)) | 2585 | (or (memq (car lap0) '(byte-discardN-preserve-tos byte-dup)) |
| @@ -2546,8 +2596,15 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." | |||
| 2546 | ;; | 2596 | ;; |
| 2547 | ((and (eq (car lap0) 'byte-goto) | 2597 | ((and (eq (car lap0) 'byte-goto) |
| 2548 | (setq tmp (cdr (memq (cdr lap0) lap))) | 2598 | (setq tmp (cdr (memq (cdr lap0) lap))) |
| 2549 | (memq (caar tmp) '(byte-discard byte-discardN | 2599 | (or (memq (caar tmp) '(byte-discard byte-discardN)) |
| 2550 | byte-discardN-preserve-tos))) | 2600 | ;; Make sure we don't hoist a discardN-preserve-tos |
| 2601 | ;; that really should be merged or deleted instead. | ||
| 2602 | (and (eq (caar tmp) 'byte-discardN-preserve-tos) | ||
| 2603 | (let ((next (cadr tmp))) | ||
| 2604 | (not (or (memq (car next) '(byte-discardN-preserve-tos | ||
| 2605 | byte-return)) | ||
| 2606 | (and (eq (car next) 'byte-stack-set) | ||
| 2607 | (eql (cdr next) 1)))))))) | ||
| 2551 | (byte-compile-log-lap | 2608 | (byte-compile-log-lap |
| 2552 | " goto-X .. X: \t-->\t%s goto-X.. X: %s Y:" | 2609 | " goto-X .. X: \t-->\t%s goto-X.. X: %s Y:" |
| 2553 | (car tmp) (car tmp)) | 2610 | (car tmp) (car tmp)) |
| @@ -2562,11 +2619,16 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." | |||
| 2562 | 2619 | ||
| 2563 | ;; | 2620 | ;; |
| 2564 | ;; const discardN-preserve-tos ==> discardN const | 2621 | ;; const discardN-preserve-tos ==> discardN const |
| 2622 | ;; const stack-set(1) ==> discard const | ||
| 2565 | ;; | 2623 | ;; |
| 2566 | ((and (eq (car lap0) 'byte-constant) | 2624 | ((and (eq (car lap0) 'byte-constant) |
| 2567 | (eq (car lap1) 'byte-discardN-preserve-tos)) | 2625 | (or (eq (car lap1) 'byte-discardN-preserve-tos) |
| 2626 | (and (eq (car lap1) 'byte-stack-set) | ||
| 2627 | (eql (cdr lap1) 1)))) | ||
| 2568 | (setq keep-going t) | 2628 | (setq keep-going t) |
| 2569 | (let ((newdiscard (cons 'byte-discardN (cdr lap1)))) | 2629 | (let ((newdiscard (if (eql (cdr lap1) 1) |
| 2630 | (cons 'byte-discard nil) | ||
| 2631 | (cons 'byte-discardN (cdr lap1))))) | ||
| 2570 | (byte-compile-log-lap | 2632 | (byte-compile-log-lap |
| 2571 | " %s %s\t-->\t%s %s" lap0 lap1 newdiscard lap0) | 2633 | " %s %s\t-->\t%s %s" lap0 lap1 newdiscard lap0) |
| 2572 | (setf (car rest) newdiscard) | 2634 | (setf (car rest) newdiscard) |
| @@ -2651,16 +2713,6 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." | |||
| 2651 | (setcdr lap1 (+ (if (eq (car lap0) 'byte-discard) 1 (cdr lap0)) | 2713 | (setcdr lap1 (+ (if (eq (car lap0) 'byte-discard) 1 (cdr lap0)) |
| 2652 | (if (eq (car lap1) 'byte-discard) 1 (cdr lap1)))) | 2714 | (if (eq (car lap1) 'byte-discard) 1 (cdr lap1)))) |
| 2653 | (setcar lap1 'byte-discardN)) | 2715 | (setcar lap1 'byte-discardN)) |
| 2654 | |||
| 2655 | ;; | ||
| 2656 | ;; discardN-preserve-tos-X discardN-preserve-tos-Y --> | ||
| 2657 | ;; discardN-preserve-tos-(X+Y) | ||
| 2658 | ;; | ||
| 2659 | ((and (eq (car lap0) 'byte-discardN-preserve-tos) | ||
| 2660 | (eq (car lap1) 'byte-discardN-preserve-tos)) | ||
| 2661 | (setq lap (delq lap0 lap)) | ||
| 2662 | (setcdr lap1 (+ (cdr lap0) (cdr lap1))) | ||
| 2663 | (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 (car rest))) | ||
| 2664 | ) | 2716 | ) |
| 2665 | (setq rest (cdr rest))) | 2717 | (setq rest (cdr rest))) |
| 2666 | (setq byte-compile-maxdepth (+ byte-compile-maxdepth add-depth))) | 2718 | (setq byte-compile-maxdepth (+ byte-compile-maxdepth add-depth))) |