Optimise append
calls
Add the transforms (append) -> nil (append X) -> X (append '(X) Y) -> (cons 'X Y) (append (list X) Y) -> (cons X Y) (append (list X...) nil) -> (list X...) and the argument transforms: (list X...) (list Y...) -> (list X... Y...) nil -> ;nothing CONST1 CONST2 -> CONST1++CONST2 (list CONSTANTS...) -> '(CONSTANTS...) (the last three for non-tail arguments only) * lisp/emacs-lisp/byte-opt.el: New.
This commit is contained in:
parent
d1ac1b2108
commit
7feb5b2da7
1 changed files with 78 additions and 0 deletions
|
@ -1295,6 +1295,84 @@ See Info node `(elisp) Integer Basics'."
|
|||
;; (list) -> nil
|
||||
(and (cdr form) form))
|
||||
|
||||
(put 'append 'byte-optimizer #'byte-optimize-append)
|
||||
(defun byte-optimize-append (form)
|
||||
;; There is (probably) too much code relying on `append' to return a
|
||||
;; new list for us to do full constant-folding; these transformations
|
||||
;; preserve the allocation semantics.
|
||||
(and (cdr form) ; (append) -> nil
|
||||
(named-let loop ((args (cdr form)) (newargs nil))
|
||||
(let ((arg (car args))
|
||||
(prev (car newargs)))
|
||||
(cond
|
||||
;; Flatten nested `append' forms.
|
||||
((and (consp arg) (eq (car arg) 'append))
|
||||
(loop (append (cdr arg) (cdr args)) newargs))
|
||||
|
||||
;; Merge consecutive `list' forms.
|
||||
((and (consp arg) (eq (car arg) 'list)
|
||||
newargs (consp prev) (eq (car prev) 'list))
|
||||
(loop (cons (cons (car prev) (append (cdr prev) (cdr arg)))
|
||||
(cdr args))
|
||||
(cdr newargs)))
|
||||
|
||||
;; non-terminal arg
|
||||
((cdr args)
|
||||
(cond
|
||||
((macroexp-const-p arg)
|
||||
;; constant arg
|
||||
(let ((val (eval arg)))
|
||||
(cond
|
||||
;; Elide empty arguments (nil, empty string, etc).
|
||||
((zerop (length val))
|
||||
(loop (cdr args) newargs))
|
||||
;; Merge consecutive constants.
|
||||
((and newargs (macroexp-const-p prev))
|
||||
(loop (cdr args)
|
||||
(cons
|
||||
(list 'quote
|
||||
(append (eval prev) val nil))
|
||||
(cdr newargs))))
|
||||
(t (loop (cdr args) (cons arg newargs))))))
|
||||
|
||||
;; (list CONSTANTS...) -> '(CONSTANTS...)
|
||||
((and (consp arg) (eq (car arg) 'list)
|
||||
(not (memq nil (mapcar #'macroexp-const-p (cdr arg)))))
|
||||
(loop (cons (list 'quote (eval arg)) (cdr args)) newargs))
|
||||
|
||||
(t (loop (cdr args) (cons arg newargs)))))
|
||||
|
||||
;; At this point, `arg' is the last (tail) argument.
|
||||
|
||||
;; (append X) -> X
|
||||
((null newargs) arg)
|
||||
|
||||
;; (append (list Xs...) nil) -> (list Xs...)
|
||||
((and (null arg)
|
||||
newargs (null (cdr newargs))
|
||||
(consp prev) (eq (car prev) 'list))
|
||||
prev)
|
||||
|
||||
;; (append '(X) Y) -> (cons 'X Y)
|
||||
;; (append (list X) Y) -> (cons X Y)
|
||||
((and newargs (null (cdr newargs))
|
||||
(consp prev)
|
||||
(cond ((eq (car prev) 'quote)
|
||||
(and (consp (cadr prev))
|
||||
(= (length (cadr prev)) 1)))
|
||||
((eq (car prev) 'list)
|
||||
(= (length (cdr prev)) 1))))
|
||||
(list 'cons (if (eq (car prev) 'quote)
|
||||
(macroexp-quote (caadr prev))
|
||||
(cadr prev))
|
||||
arg))
|
||||
|
||||
(t
|
||||
(let ((new-form (cons 'append (nreverse (cons arg newargs)))))
|
||||
(if (equal new-form form)
|
||||
form
|
||||
new-form))))))))
|
||||
|
||||
;; Fixme: delete-char -> delete-region (byte-coded)
|
||||
|
||||
(put 'set 'byte-optimizer #'byte-optimize-set)
|
||||
|
|
Loading…
Add table
Reference in a new issue