aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2019-05-22 12:36:03 +0200
committerMattias EngdegÄrd2019-06-19 11:20:59 +0200
commit14a81524c27ab54850e0fda736e4ee0c92e447b5 (patch)
tree07dae25c695381ab4dc7c5fe70543276b90ace82
parentb8c74742c0238fe15b1cdc9a7f6ee021d038368f (diff)
downloademacs-14a81524c27ab54850e0fda736e4ee0c92e447b5.tar.gz
emacs-14a81524c27ab54850e0fda736e4ee0c92e447b5.zip
Compile cond with heterogeneous tests into switch (bug#36139)
Allow any mixture of `eq', `eql' and `equal', `memq', `memql' and `member' in a switch-like `cond' to be compiled into a single switch. * lisp/emacs-lisp/bytecomp.el (byte-compile--common-test): New. (byte-compile-cond-jump-table-info): Use most specific common test. * test/lisp/emacs-lisp/bytecomp-tests.el (byte-opt-testsuite-arith-data): Add test cases for multi-value clause cond forms.
-rw-r--r--lisp/emacs-lisp/bytecomp.el29
-rw-r--r--test/lisp/emacs-lisp/bytecomp-tests.el25
2 files changed, 41 insertions, 13 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index ab04c1bf439..3a23543f6a7 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -4132,6 +4132,12 @@ that suppresses all warnings during execution of BODY."
4132 4132
4133(defconst byte-compile--default-val (cons nil nil) "A unique object.") 4133(defconst byte-compile--default-val (cons nil nil) "A unique object.")
4134 4134
4135(defun byte-compile--common-test (test-1 test-2)
4136 "Most specific common test of `eq', `eql' and `equal'"
4137 (cond ((or (eq test-1 'equal) (eq test-2 'equal)) 'equal)
4138 ((or (eq test-1 'eql) (eq test-2 'eql)) 'eql)
4139 (t 'eq)))
4140
4135(defun byte-compile-cond-jump-table-info (clauses) 4141(defun byte-compile-cond-jump-table-info (clauses)
4136 "If CLAUSES is a `cond' form where: 4142 "If CLAUSES is a `cond' form where:
4137The condition for each clause is of the form (TEST VAR VALUE). 4143The condition for each clause is of the form (TEST VAR VALUE).
@@ -4143,7 +4149,8 @@ Return a list of the form ((TEST . VAR) ((VALUES BODY) ...))"
4143 (let ((cases '()) 4149 (let ((cases '())
4144 (ok t) 4150 (ok t)
4145 (all-keys nil) 4151 (all-keys nil)
4146 prev-var prev-test) 4152 (prev-test 'eq)
4153 prev-var)
4147 (and (catch 'break 4154 (and (catch 'break
4148 (dolist (clause (cdr clauses) ok) 4155 (dolist (clause (cdr clauses) ok)
4149 (let* ((condition (car clause)) 4156 (let* ((condition (car clause))
@@ -4152,15 +4159,13 @@ Return a list of the form ((TEST . VAR) ((VALUES BODY) ...))"
4152 (byte-compile-cond-vars (cadr condition) (cl-caddr condition)))) 4159 (byte-compile-cond-vars (cadr condition) (cl-caddr condition))))
4153 (obj1 (car-safe vars)) 4160 (obj1 (car-safe vars))
4154 (obj2 (cdr-safe vars)) 4161 (obj2 (cdr-safe vars))
4155 (body (cdr-safe clause)) 4162 (body (cdr-safe clause)))
4156 equality)
4157 (unless prev-var 4163 (unless prev-var
4158 (setq prev-var obj1)) 4164 (setq prev-var obj1))
4159 (cond 4165 (cond
4160 ((and obj1 (memq test '(eq eql equal)) 4166 ((and obj1 (memq test '(eq eql equal))
4161 (eq obj1 prev-var) 4167 (eq obj1 prev-var))
4162 (or (not prev-test) (eq test prev-test))) 4168 (setq prev-test (byte-compile--common-test prev-test test))
4163 (setq prev-test test)
4164 ;; Discard values already tested for. 4169 ;; Discard values already tested for.
4165 (unless (member obj2 all-keys) 4170 (unless (member obj2 all-keys)
4166 (push obj2 all-keys) 4171 (push obj2 all-keys)
@@ -4171,12 +4176,12 @@ Return a list of the form ((TEST . VAR) ((VALUES BODY) ...))"
4171 (listp obj2) 4176 (listp obj2)
4172 ;; Require a non-empty body, since the member function 4177 ;; Require a non-empty body, since the member function
4173 ;; value depends on the switch argument. 4178 ;; value depends on the switch argument.
4174 body 4179 body)
4175 (setq equality (cdr (assq test '((memq . eq) 4180 (setq prev-test
4176 (memql . eql) 4181 (byte-compile--common-test
4177 (member . equal))))) 4182 prev-test (cdr (assq test '((memq . eq)
4178 (or (not prev-test) (eq equality prev-test))) 4183 (memql . eql)
4179 (setq prev-test equality) 4184 (member . equal))))))
4180 (let ((vals nil)) 4185 (let ((vals nil))
4181 ;; Discard values already tested for. 4186 ;; Discard values already tested for.
4182 (dolist (elem obj2) 4187 (dolist (elem obj2)
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el
index 0c151e39169..0f18a34578d 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -311,7 +311,30 @@
311 (let ((x "a")) (cond ((equal x "a") 'correct) 311 (let ((x "a")) (cond ((equal x "a") 'correct)
312 ((equal x "b") 'incorrect) 312 ((equal x "b") 'incorrect)
313 ((equal x "a") 'incorrect) 313 ((equal x "a") 'incorrect)
314 ((equal x "c") 'incorrect)))) 314 ((equal x "c") 'incorrect)))
315 ;; Multi-value clauses
316 (mapcar (lambda (x) (cond ((eq x 'a) 11)
317 ((memq x '(b a c d)) 22)
318 ((eq x 'c) 33)
319 ((eq x 'e) 44)
320 ((memq x '(d f g)) 55)
321 (t 99)))
322 '(a b c d e f g h))
323 (mapcar (lambda (x) (cond ((eql x 1) 11)
324 ((memq x '(a b c)) 22)
325 ((memql x '(2 1 4 1e-3)) 33)
326 ((eq x 'd) 44)
327 ((eql x #x10000000000000000))))
328 '(1 2 4 1e-3 a b c d 1.0 #x10000000000000000))
329 (mapcar (lambda (x) (cond ((eq x 'a) 11)
330 ((memq x '(b d)) 22)
331 ((equal x '(a . b)) 33)
332 ((member x '(b c 1.5 2.5 "X" (d))) 44)
333 ((eql x 3.14) 55)
334 ((memql x '(9 0.5 1.5 q)) 66)
335 (t 99)))
336 '(a b c d (d) (a . b) "X" 0.5 1.5 3.14 9 9.0))
337 )
315 "List of expression for test. 338 "List of expression for test.
316Each element will be executed by interpreter and with 339Each element will be executed by interpreter and with
317bytecompiled code, and their results compared.") 340bytecompiled code, and their results compared.")