aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2022-07-15 18:55:30 +0200
committerMattias EngdegÄrd2022-07-16 12:18:48 +0200
commit7feb5b2da7f369a8ab1fea81975989aa30cbb397 (patch)
tree34b442060ba624c6080eb8a5f2fa4c1616fb9c61
parentd1ac1b2108e0934b11631c39307b208a2c0fdf1a (diff)
downloademacs-7feb5b2da7f369a8ab1fea81975989aa30cbb397.tar.gz
emacs-7feb5b2da7f369a8ab1fea81975989aa30cbb397.zip
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.
-rw-r--r--lisp/emacs-lisp/byte-opt.el78
1 files changed, 78 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 480b652342b..ce73a5e91f4 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -1295,6 +1295,84 @@ See Info node `(elisp) Integer Basics'."
1295 ;; (list) -> nil 1295 ;; (list) -> nil
1296 (and (cdr form) form)) 1296 (and (cdr form) form))
1297 1297
1298(put 'append 'byte-optimizer #'byte-optimize-append)
1299(defun byte-optimize-append (form)
1300 ;; There is (probably) too much code relying on `append' to return a
1301 ;; new list for us to do full constant-folding; these transformations
1302 ;; preserve the allocation semantics.
1303 (and (cdr form) ; (append) -> nil
1304 (named-let loop ((args (cdr form)) (newargs nil))
1305 (let ((arg (car args))
1306 (prev (car newargs)))
1307 (cond
1308 ;; Flatten nested `append' forms.
1309 ((and (consp arg) (eq (car arg) 'append))
1310 (loop (append (cdr arg) (cdr args)) newargs))
1311
1312 ;; Merge consecutive `list' forms.
1313 ((and (consp arg) (eq (car arg) 'list)
1314 newargs (consp prev) (eq (car prev) 'list))
1315 (loop (cons (cons (car prev) (append (cdr prev) (cdr arg)))
1316 (cdr args))
1317 (cdr newargs)))
1318
1319 ;; non-terminal arg
1320 ((cdr args)
1321 (cond
1322 ((macroexp-const-p arg)
1323 ;; constant arg
1324 (let ((val (eval arg)))
1325 (cond
1326 ;; Elide empty arguments (nil, empty string, etc).
1327 ((zerop (length val))
1328 (loop (cdr args) newargs))
1329 ;; Merge consecutive constants.
1330 ((and newargs (macroexp-const-p prev))
1331 (loop (cdr args)
1332 (cons
1333 (list 'quote
1334 (append (eval prev) val nil))
1335 (cdr newargs))))
1336 (t (loop (cdr args) (cons arg newargs))))))
1337
1338 ;; (list CONSTANTS...) -> '(CONSTANTS...)
1339 ((and (consp arg) (eq (car arg) 'list)
1340 (not (memq nil (mapcar #'macroexp-const-p (cdr arg)))))
1341 (loop (cons (list 'quote (eval arg)) (cdr args)) newargs))
1342
1343 (t (loop (cdr args) (cons arg newargs)))))
1344
1345 ;; At this point, `arg' is the last (tail) argument.
1346
1347 ;; (append X) -> X
1348 ((null newargs) arg)
1349
1350 ;; (append (list Xs...) nil) -> (list Xs...)
1351 ((and (null arg)
1352 newargs (null (cdr newargs))
1353 (consp prev) (eq (car prev) 'list))
1354 prev)
1355
1356 ;; (append '(X) Y) -> (cons 'X Y)
1357 ;; (append (list X) Y) -> (cons X Y)
1358 ((and newargs (null (cdr newargs))
1359 (consp prev)
1360 (cond ((eq (car prev) 'quote)
1361 (and (consp (cadr prev))
1362 (= (length (cadr prev)) 1)))
1363 ((eq (car prev) 'list)
1364 (= (length (cdr prev)) 1))))
1365 (list 'cons (if (eq (car prev) 'quote)
1366 (macroexp-quote (caadr prev))
1367 (cadr prev))
1368 arg))
1369
1370 (t
1371 (let ((new-form (cons 'append (nreverse (cons arg newargs)))))
1372 (if (equal new-form form)
1373 form
1374 new-form))))))))
1375
1298;; Fixme: delete-char -> delete-region (byte-coded) 1376;; Fixme: delete-char -> delete-region (byte-coded)
1299 1377
1300(put 'set 'byte-optimizer #'byte-optimize-set) 1378(put 'set 'byte-optimizer #'byte-optimize-set)