diff options
| author | Mattias EngdegÄrd | 2022-08-12 20:12:25 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2022-08-16 20:44:50 +0200 |
| commit | e618b6faee5b81d17501fdb2e6b121062f95c021 (patch) | |
| tree | 7b9c47a1a008da199e7e361287ecbb021c8c32d8 | |
| parent | 869db699ee276349b5de17b54daa4e75433075b9 (diff) | |
| download | emacs-e618b6faee5b81d17501fdb2e6b121062f95c021.tar.gz emacs-e618b6faee5b81d17501fdb2e6b121062f95c021.zip | |
Improved `if` and `while` optimisation
Recognise some more special cases:
(if X nil t) -> (not X)
(if X t) -> (not (not X))
(if X t nil) -> (not (not X))
(if VAR VAR X...) -> (or VAR (progn X...))
* lisp/emacs-lisp/byte-opt.el (byte-opt-negate): New.
(byte-optimize-if): Add transformations above and refactor.
(byte-optimize-while): Better static nil-detection.
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 91 |
1 files changed, 53 insertions, 38 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 062f5bf0a22..579e2f61ae1 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -1190,49 +1190,64 @@ See Info node `(elisp) Integer Basics'." | |||
| 1190 | (and clauses form))) | 1190 | (and clauses form))) |
| 1191 | form)) | 1191 | form)) |
| 1192 | 1192 | ||
| 1193 | (defsubst byte-opt--negate (form) | ||
| 1194 | "Negate FORM, avoiding double negation if already negated." | ||
| 1195 | (if (and (consp form) (memq (car form) '(not null))) | ||
| 1196 | (cadr form) | ||
| 1197 | `(not ,form))) | ||
| 1198 | |||
| 1193 | (defun byte-optimize-if (form) | 1199 | (defun byte-optimize-if (form) |
| 1194 | ;; (if (progn <insts> <test>) <rest>) ==> (progn <insts> (if <test> <rest>)) | 1200 | (let ((condition (nth 1 form)) |
| 1195 | ;; (if <true-constant> <then> <else...>) ==> <then> | 1201 | (then (nth 2 form)) |
| 1196 | ;; (if <false-constant> <then> <else...>) ==> (progn <else...>) | 1202 | (else (nthcdr 3 form))) |
| 1197 | ;; (if <test> nil <else...>) ==> (if (not <test>) (progn <else...>)) | 1203 | (cond |
| 1198 | ;; (if <test> <then> nil) ==> (if <test> <then>) | 1204 | ;; (if (progn ... X) ...) -> (progn ... (if X ...)) |
| 1199 | (let ((clause (nth 1 form))) | 1205 | ((eq (car-safe condition) 'progn) |
| 1200 | (cond ((and (eq (car-safe clause) 'progn) | 1206 | (nconc (butlast condition) |
| 1201 | (proper-list-p clause)) | 1207 | (list |
| 1202 | (if (null (cddr clause)) | 1208 | (byte-optimize-if |
| 1203 | ;; A trivial `progn'. | 1209 | `(,(car form) ,(car (last condition)) ,@(nthcdr 2 form)))))) |
| 1204 | (byte-optimize-if `(,(car form) ,(cadr clause) ,@(nthcdr 2 form))) | 1210 | ;; (if TRUE THEN ...) -> (progn TRUE THEN) |
| 1205 | (nconc (butlast clause) | 1211 | ((byte-compile-trueconstp condition) |
| 1206 | (list | 1212 | `(progn ,condition ,then)) |
| 1207 | (byte-optimize-if | 1213 | ;; (if FALSE THEN ELSE...) -> (progn FALSE ELSE...) |
| 1208 | `(,(car form) ,(car (last clause)) ,@(nthcdr 2 form))))))) | 1214 | ((byte-compile-nilconstp condition) |
| 1209 | ((byte-compile-trueconstp clause) | 1215 | (if else |
| 1210 | `(progn ,clause ,(nth 2 form))) | 1216 | `(progn ,condition ,@else) |
| 1211 | ((byte-compile-nilconstp clause) | 1217 | condition)) |
| 1212 | `(progn ,clause ,@(nthcdr 3 form))) | 1218 | ;; (if X nil t) -> (not X) |
| 1213 | ((nth 2 form) | 1219 | ((and (eq then nil) (eq else '(t))) |
| 1214 | (if (equal '(nil) (nthcdr 3 form)) | 1220 | `(not ,condition)) |
| 1215 | (list (car form) clause (nth 2 form)) | 1221 | ;; (if X t [nil]) -> (not (not X)) |
| 1216 | form)) | 1222 | ((and (eq then t) (or (null else) (eq else '(nil)))) |
| 1217 | ((or (nth 3 form) (nthcdr 4 form)) | 1223 | `(not ,(byte-opt--negate condition))) |
| 1218 | (list (car form) | 1224 | ;; (if VAR VAR X...) -> (or VAR (progn X...)) |
| 1219 | ;; Don't make a double negative; | 1225 | ((and (symbolp condition) (eq condition then)) |
| 1220 | ;; instead, take away the one that is there. | 1226 | `(or ,then ,(if (cdr else) |
| 1221 | (if (and (consp clause) (memq (car clause) '(not null)) | 1227 | `(progn . ,else) |
| 1222 | (= (length clause) 2)) ; (not xxxx) or (not (xxxx)) | 1228 | (car else)))) |
| 1223 | (nth 1 clause) | 1229 | ;; (if X THEN nil) -> (if X THEN) |
| 1224 | (list 'not clause)) | 1230 | (then |
| 1225 | (if (nthcdr 4 form) | 1231 | (if (equal else '(nil)) |
| 1226 | (cons 'progn (nthcdr 3 form)) | 1232 | (list (car form) condition then) |
| 1227 | (nth 3 form)))) | 1233 | form)) |
| 1228 | (t | 1234 | ;; (if X nil ELSE...) -> (if (not X) (progn ELSE...)) |
| 1229 | (list 'progn clause nil))))) | 1235 | ((or (car else) (cdr else)) |
| 1236 | (list (car form) (byte-opt--negate condition) | ||
| 1237 | (if (cdr else) | ||
| 1238 | `(progn . ,else) | ||
| 1239 | (car else)))) | ||
| 1240 | ;; (if X nil nil) -> (progn X nil) | ||
| 1241 | (t | ||
| 1242 | (list 'progn condition nil))))) | ||
| 1230 | 1243 | ||
| 1231 | (defun byte-optimize-while (form) | 1244 | (defun byte-optimize-while (form) |
| 1232 | (when (< (length form) 2) | 1245 | (when (< (length form) 2) |
| 1233 | (byte-compile-warn-x form "too few arguments for `while'")) | 1246 | (byte-compile-warn-x form "too few arguments for `while'")) |
| 1234 | (if (nth 1 form) | 1247 | (let ((condition (nth 1 form))) |
| 1235 | form)) | 1248 | (if (byte-compile-nilconstp condition) |
| 1249 | condition | ||
| 1250 | form))) | ||
| 1236 | 1251 | ||
| 1237 | (put 'and 'byte-optimizer #'byte-optimize-and) | 1252 | (put 'and 'byte-optimizer #'byte-optimize-and) |
| 1238 | (put 'or 'byte-optimizer #'byte-optimize-or) | 1253 | (put 'or 'byte-optimizer #'byte-optimize-or) |