aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2019-05-21 11:56:14 +0200
committerMattias EngdegÄrd2019-06-19 11:20:58 +0200
commit36ab408207d7adf94fd1396922e0df38d746a948 (patch)
tree8c0a40db0b370296b32f8681c6aae377072e3ff6
parent2419fa3937f07f8e2e4a79f77fe367a9979cb578 (diff)
downloademacs-36ab408207d7adf94fd1396922e0df38d746a948.tar.gz
emacs-36ab408207d7adf94fd1396922e0df38d746a948.zip
Compile list member functions in cond to switch (bug#36139)
* lisp/emacs-lisp/bytecomp.el (byte-compile-cond-jump-table-info): Expand `memq', `memql' and `member' to their corresponding equality tests. (byte-compile-cond-jump-table): Cases now have multiple values. * lisp/emacs-lisp/byte-opt.el (byte-decompile-bytecode-1) (byte-optimize-lapcode): Don't assume switch hash tables to be injective.
-rw-r--r--lisp/emacs-lisp/byte-opt.el21
-rw-r--r--lisp/emacs-lisp/bytecomp.el81
2 files changed, 65 insertions, 37 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 44cca6136c0..b0aa407c8b4 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -1376,11 +1376,15 @@
1376 do (setq last-constant (copy-hash-table e)) 1376 do (setq last-constant (copy-hash-table e))
1377 and return nil) 1377 and return nil)
1378 ;; Replace all addresses with TAGs. 1378 ;; Replace all addresses with TAGs.
1379 (maphash #'(lambda (value tag) 1379 (maphash #'(lambda (value offset)
1380 (let (newtag) 1380 (let ((match (assq offset tags)))
1381 (setq newtag (byte-compile-make-tag)) 1381 (puthash value
1382 (push (cons tag newtag) tags) 1382 (if match
1383 (puthash value newtag last-constant))) 1383 (cdr match)
1384 (let ((tag (byte-compile-make-tag)))
1385 (push (cons offset tag) tags)
1386 tag))
1387 last-constant)))
1384 last-constant) 1388 last-constant)
1385 ;; Replace the hash table referenced in the lapcode with our 1389 ;; Replace the hash table referenced in the lapcode with our
1386 ;; modified one. 1390 ;; modified one.
@@ -1722,13 +1726,10 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
1722 keep-going t) 1726 keep-going t)
1723 ;; replace references to tag in jump tables, if any 1727 ;; replace references to tag in jump tables, if any
1724 (dolist (table byte-compile-jump-tables) 1728 (dolist (table byte-compile-jump-tables)
1725 (catch 'break
1726 (maphash #'(lambda (value tag) 1729 (maphash #'(lambda (value tag)
1727 (when (equal tag lap0) 1730 (when (equal tag lap0)
1728 ;; each tag occurs only once in the jump table 1731 (puthash value lap1 table)))
1729 (puthash value lap1 table) 1732 table)))
1730 (throw 'break nil)))
1731 table))))
1732 ;; 1733 ;;
1733 ;; unused-TAG: --> <deleted> 1734 ;; unused-TAG: --> <deleted>
1734 ;; 1735 ;;
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 9e3e603c043..ab04c1bf439 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -4139,9 +4139,10 @@ VAR is a variable.
4139TEST and VAR are the same throughout all conditions. 4139TEST and VAR are the same throughout all conditions.
4140VALUE satisfies `macroexp-const-p'. 4140VALUE satisfies `macroexp-const-p'.
4141 4141
4142Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))" 4142Return a list of the form ((TEST . VAR) ((VALUES BODY) ...))"
4143 (let ((cases '()) 4143 (let ((cases '())
4144 (ok t) 4144 (ok t)
4145 (all-keys nil)
4145 prev-var prev-test) 4146 prev-var prev-test)
4146 (and (catch 'break 4147 (and (catch 'break
4147 (dolist (clause (cdr clauses) ok) 4148 (dolist (clause (cdr clauses) ok)
@@ -4151,23 +4152,46 @@ Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))"
4151 (byte-compile-cond-vars (cadr condition) (cl-caddr condition)))) 4152 (byte-compile-cond-vars (cadr condition) (cl-caddr condition))))
4152 (obj1 (car-safe vars)) 4153 (obj1 (car-safe vars))
4153 (obj2 (cdr-safe vars)) 4154 (obj2 (cdr-safe vars))
4154 (body (cdr-safe clause))) 4155 (body (cdr-safe clause))
4156 equality)
4155 (unless prev-var 4157 (unless prev-var
4156 (setq prev-var obj1)) 4158 (setq prev-var obj1))
4157 (unless prev-test 4159 (cond
4158 (setq prev-test test)) 4160 ((and obj1 (memq test '(eq eql equal))
4159 (if (and obj1 (memq test '(eq eql equal)) 4161 (eq obj1 prev-var)
4160 (eq test prev-test) 4162 (or (not prev-test) (eq test prev-test)))
4161 (eq obj1 prev-var)) 4163 (setq prev-test test)
4162 ;; discard duplicate clauses 4164 ;; Discard values already tested for.
4163 (unless (assoc obj2 cases test) 4165 (unless (member obj2 all-keys)
4164 (push (list obj2 body) cases)) 4166 (push obj2 all-keys)
4165 (if (and (macroexp-const-p condition) condition) 4167 (push (list (list obj2) body) cases)))
4166 (progn (push (list byte-compile--default-val 4168
4167 (or body `(,condition))) 4169 ((and obj1 (memq test '(memq memql member))
4168 cases) 4170 (eq obj1 prev-var)
4169 (throw 'break t)) 4171 (listp obj2)
4170 (setq ok nil) 4172 ;; Require a non-empty body, since the member function
4173 ;; value depends on the switch argument.
4174 body
4175 (setq equality (cdr (assq test '((memq . eq)
4176 (memql . eql)
4177 (member . equal)))))
4178 (or (not prev-test) (eq equality prev-test)))
4179 (setq prev-test equality)
4180 (let ((vals nil))
4181 ;; Discard values already tested for.
4182 (dolist (elem obj2)
4183 (unless (funcall test elem all-keys)
4184 (push elem vals)))
4185 (when vals
4186 (setq all-keys (append vals all-keys))
4187 (push (list vals body) cases))))
4188
4189 ((and (macroexp-const-p condition) condition)
4190 (push (list byte-compile--default-val
4191 (or body `(,condition)))
4192 cases)
4193 (throw 'break t))
4194 (t (setq ok nil)
4171 (throw 'break nil)))))) 4195 (throw 'break nil))))))
4172 (list (cons prev-test prev-var) (nreverse cases))))) 4196 (list (cons prev-test prev-var) (nreverse cases)))))
4173 4197
@@ -4176,18 +4200,20 @@ Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))"
4176 (test (caar table-info)) 4200 (test (caar table-info))
4177 (var (cdar table-info)) 4201 (var (cdar table-info))
4178 (cases (cadr table-info)) 4202 (cases (cadr table-info))
4179 jump-table test-obj body tag donetag default-tag default-case) 4203 jump-table test-objects body tag donetag default-tag default-case)
4180 (when (and cases (not (= (length cases) 1))) 4204 (when (and cases (not (= (length cases) 1)))
4181 ;; TODO: Once :linear-search is implemented for `make-hash-table' 4205 ;; TODO: Once :linear-search is implemented for `make-hash-table'
4182 ;; set it to `t' for cond forms with a small number of cases. 4206 ;; set it to `t' for cond forms with a small number of cases.
4183 (setq jump-table (make-hash-table 4207 (let ((nvalues (apply #'+ (mapcar (lambda (case) (length (car case)))
4184 :test test 4208 cases))))
4185 :purecopy t 4209 (setq jump-table (make-hash-table
4186 :size (if (assq byte-compile--default-val cases) 4210 :test test
4187 (1- (length cases)) 4211 :purecopy t
4188 (length cases))) 4212 :size (if (assq byte-compile--default-val cases)
4189 default-tag (byte-compile-make-tag) 4213 (1- nvalues)
4190 donetag (byte-compile-make-tag)) 4214 nvalues))))
4215 (setq default-tag (byte-compile-make-tag))
4216 (setq donetag (byte-compile-make-tag))
4191 ;; The structure of byte-switch code: 4217 ;; The structure of byte-switch code:
4192 ;; 4218 ;;
4193 ;; varref var 4219 ;; varref var
@@ -4224,10 +4250,11 @@ Return a list of the form ((TEST . VAR) ((VALUE BODY) ...))"
4224 4250
4225 (dolist (case cases) 4251 (dolist (case cases)
4226 (setq tag (byte-compile-make-tag) 4252 (setq tag (byte-compile-make-tag)
4227 test-obj (nth 0 case) 4253 test-objects (nth 0 case)
4228 body (nth 1 case)) 4254 body (nth 1 case))
4229 (byte-compile-out-tag tag) 4255 (byte-compile-out-tag tag)
4230 (puthash test-obj tag jump-table) 4256 (dolist (value test-objects)
4257 (puthash value tag jump-table))
4231 4258
4232 (let ((byte-compile-depth byte-compile-depth) 4259 (let ((byte-compile-depth byte-compile-depth)
4233 (init-depth byte-compile-depth)) 4260 (init-depth byte-compile-depth))