diff options
| author | Mattias EngdegÄrd | 2022-07-15 18:55:30 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2022-07-16 12:18:48 +0200 |
| commit | 7feb5b2da7f369a8ab1fea81975989aa30cbb397 (patch) | |
| tree | 34b442060ba624c6080eb8a5f2fa4c1616fb9c61 | |
| parent | d1ac1b2108e0934b11631c39307b208a2c0fdf1a (diff) | |
| download | emacs-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.el | 78 |
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) |