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.
This commit is contained in:
parent
ab9c06449d
commit
52a55e11de
2 changed files with 43 additions and 12 deletions
|
@ -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)
|
||||
|
|
|
@ -509,6 +509,24 @@
|
|||
((member x '("b" "c")) 2)
|
||||
((not x) 3)))
|
||||
'("a" "b" "c" "d" nil))
|
||||
|
||||
;; `let' and `let*' optimisations with body being constant or variable
|
||||
(let* (a
|
||||
(b (progn (setq a (cons 1 a)) 2))
|
||||
(c (1+ b))
|
||||
(d (list a c)))
|
||||
d)
|
||||
(let ((a nil))
|
||||
(let ((b (progn (setq a (cons 1 a)) 2))
|
||||
(c (progn (setq a (cons 3 a))))
|
||||
(d (list a)))
|
||||
d))
|
||||
(let* ((_a 1)
|
||||
(_b 2))
|
||||
'z)
|
||||
(let ((_a 1)
|
||||
(_b 2))
|
||||
'z)
|
||||
)
|
||||
"List of expressions for cross-testing interpreted and compiled code.")
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue