emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master bfd338aad9d 2/2: LAP peephole optimisation improvements


From: Mattias Engdegård
Subject: master bfd338aad9d 2/2: LAP peephole optimisation improvements
Date: Thu, 2 Feb 2023 08:47:37 -0500 (EST)

branch: master
commit bfd338aad9d1e6bf898fc19d23e1a5ca4e696316
Author: Mattias Engdegård <mattiase@acm.org>
Commit: Mattias Engdegård <mattiase@acm.org>

    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.
---
 lisp/emacs-lisp/byte-opt.el | 128 +++++++++++++++++++++++++++++++-------------
 1 file 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."
        ;; optimized but sequences like "dup varset TAG1: discard" are not.
        ;; You may be tempted to change this; resist that temptation.
        (cond
-        ;; <side-effect-free> pop -->  <deleted>
-        ;;  ...including:
-        ;; const-X pop   -->  <deleted>
-        ;; varref-X pop  -->  <deleted>
-        ;; dup pop       -->  <deleted>
-        ;;
-        ((and (eq 'byte-discard (car lap1))
+         ;;
+         ;; PUSH(K) discard(N) -->  <deleted> discard(N-K), N>K
+         ;; PUSH(K) discard(N) -->  <deleted>,              N=K
+         ;;  where PUSH(K) is a side-effect-free op such as const, varref, dup
+         ;;
+         ((and (memq (car lap1) '(byte-discard byte-discardN))
               (memq (car lap0) side-effect-free))
          (setq keep-going t)
-         (setq tmp (aref byte-stack+-info (symbol-value (car lap0))))
-         (setq rest (cdr rest))
-         (cond ((eql tmp 1)
-                (byte-compile-log-lap
-                 "  %s discard\t-->\t<deleted>" lap0)
-                (setq lap (delq lap0 (delq lap1 lap))))
-               ((eql tmp 0)
-                (byte-compile-log-lap
-                 "  %s discard\t-->\t<deleted> discard" lap0)
-                (setq lap (delq lap0 lap)))
-               ((eql tmp -1)
-                (byte-compile-log-lap
-                 "  %s discard\t-->\tdiscard discard" lap0)
-                (setcar lap0 'byte-discard)
-                (setcdr lap0 0))
-               (t (error "Optimizer error: too much on the stack"))))
+          (let* ((pushes (aref byte-stack+-info (symbol-value (car lap0))))
+                 (pops (if (eq (car lap1) 'byte-discardN) (cdr lap1) 1))
+                 (net-pops (- pops pushes)))
+            (cond ((= net-pops 0)
+                   (byte-compile-log-lap "  %s %s\t-->\t<deleted>" lap0 lap1)
+                   (setcdr rest (cddr rest))
+                   (setq lap (delq lap0 lap)))
+                  ((> net-pops 0)
+                   (byte-compile-log-lap
+                    "  %s %s\t-->\t<deleted> discard(%d)" lap0 lap1 net-pops)
+                   (setcar rest (if (eql net-pops 1)
+                                    (cons 'byte-discard nil)
+                                  (cons 'byte-discardN net-pops)))
+                   (setcdr rest (cddr rest)))
+                  (t (error "Optimizer error: too much on the stack")))))
         ;;
         ;; goto*-X X:  -->  X:
         ;;
@@ -2353,6 +2351,40 @@ If FOR-EFFECT is non-nil, the return value is assumed to 
be of no importance."
                     (setcar lap0 'byte-return))
                 (setcdr lap0 (cdr tmp))
                 (setq keep-going t))))
+
+         ;;
+         ;; OP goto(X) Y: OP X: -> Y: OP X:
+         ;;
+         ((and (eq (car lap1) 'byte-goto)
+               (eq (car lap2) 'TAG)
+               (let ((lap3 (nth 3 rest)))
+                 (and (eq (car lap0) (car lap3))
+                      (eq (cdr lap0) (cdr lap3))
+                      (eq (cdr lap1) (nth 4 rest)))))
+          (byte-compile-log-lap "  %s %s %s %s %s\t-->\t%s %s %s"
+                                lap0 lap1 lap2
+                                (nth 3 rest)  (nth 4 rest)
+                                lap2 (nth 3 rest) (nth 4 rest))
+          (setcdr rest (cddr rest))
+          (setq lap (delq lap0 lap))
+          (setq keep-going t))
+
+         ;;
+         ;; OP const return  -->  const return
+         ;;  where OP is side-effect-free (or mere stack manipulation).
+         ;;
+         ((and (eq (car lap1) 'byte-constant)
+               (eq (car (nth 2 rest)) 'byte-return)
+               (or (memq (car lap0) '( byte-discard byte-discardN
+                                       byte-discardN-preserve-tos
+                                       byte-stack-set))
+                   (memq (car lap0) side-effect-free)))
+          (setq keep-going t)
+          (setq add-depth 1)  ; in case we get rid of too much stack reduction
+          (setq lap (delq lap0 lap))
+          (byte-compile-log-lap "  %s %s %s\t-->\t%s %s"
+                                lap0 lap1 (nth 2 rest) lap1 (nth 2 rest)))
+
         ;;
         ;; goto-*-else-pop X ... X: goto-if-* --> whatever
         ;; 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."
            )
          (setq keep-going t))
 
+         ;;
+         ;; discardN-preserve-tos(X) discardN-preserve-tos(Y)
+         ;; --> discardN-preserve-tos(X+Y)
+         ;;  where stack-set(1) is accepted as discardN-preserve-tos(1)
+         ;;
+         ((and (or (eq (car lap0) 'byte-discardN-preserve-tos)
+                   (and (eq (car lap0) 'byte-stack-set) (eql (cdr lap0) 1)))
+               (or (eq (car lap1) 'byte-discardN-preserve-tos)
+                   (and (eq (car lap1) 'byte-stack-set) (eql (cdr lap1) 1))))
+          (setq keep-going t)
+          (let ((new-op (cons 'byte-discardN-preserve-tos
+                              ;; This happens to work even when either
+                              ;; op is stack-set(1).
+                              (+ (cdr lap0) (cdr lap1)))))
+            (byte-compile-log-lap "  %s %s\t-->\t%s" lap0 lap1 new-op)
+            (setcar rest new-op)
+            (setcdr rest (cddr rest))))
+
         ;;
         ;; stack-set-M [discard/discardN ...]  -->  discardN-preserve-tos
         ;; 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."
         ;;
         ;; discardN-preserve-tos return  -->  return
         ;; dup return  -->  return
-        ;; stack-set-N return  -->  return     ; where N is TOS-1
+        ;; stack-set(1) return  -->  return
         ;;
         ((and (eq (car lap1) 'byte-return)
               (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."
         ;;
         ((and (eq (car lap0) 'byte-goto)
               (setq tmp (cdr (memq (cdr lap0) lap)))
-              (memq (caar tmp) '(byte-discard byte-discardN
-                                 byte-discardN-preserve-tos)))
+               (or (memq (caar tmp) '(byte-discard byte-discardN))
+                   ;; Make sure we don't hoist a discardN-preserve-tos
+                   ;; that really should be merged or deleted instead.
+                   (and (eq (caar tmp) 'byte-discardN-preserve-tos)
+                        (let ((next (cadr tmp)))
+                          (not (or (memq (car next) 
'(byte-discardN-preserve-tos
+                                                      byte-return))
+                                   (and (eq (car next) 'byte-stack-set)
+                                        (eql (cdr next) 1))))))))
          (byte-compile-log-lap
           "  goto-X .. X: \t-->\t%s goto-X.. X: %s Y:"
           (car tmp) (car tmp))
@@ -2562,11 +2619,16 @@ If FOR-EFFECT is non-nil, the return value is assumed 
to be of no importance."
 
         ;;
         ;; const discardN-preserve-tos ==> discardN const
+         ;; const stack-set(1)          ==> discard const
         ;;
         ((and (eq (car lap0) 'byte-constant)
-              (eq (car lap1) 'byte-discardN-preserve-tos))
+              (or (eq (car lap1) 'byte-discardN-preserve-tos)
+                   (and (eq (car lap1) 'byte-stack-set)
+                        (eql (cdr lap1) 1))))
          (setq keep-going t)
-         (let ((newdiscard (cons 'byte-discardN (cdr lap1))))
+          (let ((newdiscard (if (eql (cdr lap1) 1)
+                                (cons 'byte-discard nil)
+                              (cons 'byte-discardN (cdr lap1)))))
            (byte-compile-log-lap
             "  %s %s\t-->\t%s %s" lap0 lap1 newdiscard lap0)
            (setf (car rest) newdiscard)
@@ -2651,16 +2713,6 @@ If FOR-EFFECT is non-nil, the return value is assumed to 
be of no importance."
             (setcdr lap1 (+ (if (eq (car lap0) 'byte-discard) 1 (cdr lap0))
                             (if (eq (car lap1) 'byte-discard) 1 (cdr lap1))))
             (setcar lap1 'byte-discardN))
-
-           ;;
-           ;; discardN-preserve-tos-X discardN-preserve-tos-Y  -->
-           ;; discardN-preserve-tos-(X+Y)
-           ;;
-           ((and (eq (car lap0) 'byte-discardN-preserve-tos)
-                 (eq (car lap1) 'byte-discardN-preserve-tos))
-            (setq lap (delq lap0 lap))
-            (setcdr lap1 (+ (cdr lap0) (cdr lap1)))
-            (byte-compile-log-lap "  %s %s\t-->\t%s" lap0 lap1 (car rest)))
             )
       (setq rest (cdr rest)))
     (setq byte-compile-maxdepth (+ byte-compile-maxdepth add-depth)))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]