diff options
author | Mattias EngdegÄrd <mattiase@acm.org> | 2021-07-29 15:35:55 +0200 |
---|---|---|
committer | Mattias EngdegÄrd <mattiase@acm.org> | 2021-07-30 09:54:30 +0200 |
commit | 52a55e11deb7822c67a8d7e6f2544b8f41d25a4e (patch) | |
tree | 0054a11e914e09d5dc775a6c07585c73c1cf0e35 /lisp/emacs-lisp | |
parent | ab9c06449df4c4c58d586573003de419199cc1be (diff) | |
download | emacs-52a55e11deb7822c67a8d7e6f2544b8f41d25a4e.tar.gz emacs-52a55e11deb7822c67a8d7e6f2544b8f41d25a4e.tar.bz2 emacs-52a55e11deb7822c67a8d7e6f2544b8f41d25a4e.zip |
Optimise let and let* whose body is constant or the last variable
Simplify (let ((X1 E1) ... (Xn En)) Xn)
=> (progn E1 ... En)
and (let* ((X1 E1) ... (Xn En)) Xn)
=> (let* ((X1 E1) ... (Xn-1 En-1)) En)
and similarly the case where the body is a constant, extending a
previous optimisation that only applied to the constant nil.
This reduces the number of bound variables, shortens the code, and
enables further optimisations.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-letX): Rewrite using
`pcase` and add the aforementioned transformations.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
Add test cases.
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 37 |
1 files changed, 25 insertions, 12 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index c9dfa69aeb2..d444d7006eb 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -1250,18 +1250,31 @@ See Info node `(elisp) Integer Basics'." (put 'let 'byte-optimizer #'byte-optimize-letX) (put 'let* 'byte-optimizer #'byte-optimize-letX) (defun byte-optimize-letX (form) - (cond ((null (nth 1 form)) - ;; No bindings - (cons 'progn (cdr (cdr form)))) - ((or (nth 2 form) (nthcdr 3 form)) - form) - ;; The body is nil - ((eq (car form) 'let) - (append '(progn) (mapcar 'car-safe (mapcar 'cdr-safe (nth 1 form))) - '(nil))) - (t - (let ((binds (reverse (nth 1 form)))) - (list 'let* (reverse (cdr binds)) (nth 1 (car binds)) nil))))) + (pcase form + ;; No bindings. + (`(,_ () . ,body) + `(progn . ,body)) + + ;; Body is empty or just contains a constant. + (`(,head ,bindings . ,(or '() `(,(and const (pred macroexp-const-p))))) + (if (eq head 'let) + `(progn ,@(mapcar (lambda (binding) + (and (consp binding) (cadr binding))) + bindings) + ,const) + `(let* ,(butlast bindings) ,(cadar (last bindings)) ,const))) + + ;; Body is last variable. + (`(,head ,bindings ,(and var (pred symbolp) (pred (not keywordp)) + (pred (not booleanp)) + (guard (eq var (caar (last bindings)))))) + (if (eq head 'let) + `(progn ,@(mapcar (lambda (binding) + (and (consp binding) (cadr binding))) + bindings)) + `(let* ,(butlast bindings) ,(cadar (last bindings))))) + + (_ form))) (put 'nth 'byte-optimizer #'byte-optimize-nth) |