Mercurial > hg > xemacs-beta
comparison lisp/byte-optimize.el @ 398:74fd4e045ea6 r21-2-29
Import from CVS: tag r21-2-29
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:13:30 +0200 |
parents | 8626e4521993 |
children | a86b2b5e0111 |
comparison
equal
deleted
inserted
replaced
397:f4aeb21a5bad | 398:74fd4e045ea6 |
---|---|
1 ;;; byte-optimize.el --- the optimization passes of the emacs-lisp byte compiler. | 1 ;;; byte-optimize.el --- the optimization passes of the emacs-lisp byte compiler. |
2 | 2 |
3 ;;; Copyright (c) 1991, 1994 Free Software Foundation, Inc. | 3 ;;; Copyright (c) 1991, 1994 Free Software Foundation, Inc. |
4 | 4 |
5 ;; Author: Jamie Zawinski <jwz@netscape.com> | 5 ;; Author: Jamie Zawinski <jwz@jwz.org> |
6 ;; Hallvard Furuseth <hbf@ulrik.uio.no> | 6 ;; Hallvard Furuseth <hbf@ulrik.uio.no> |
7 ;; Keywords: internal | 7 ;; Keywords: internal |
8 | 8 |
9 ;; This file is part of XEmacs. | 9 ;; This file is part of XEmacs. |
10 | 10 |
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | 17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
19 ;; General Public License for more details. | 19 ;; General Public License for more details. |
20 | 20 |
21 ;; You should have received a copy of the GNU General Public License | 21 ;; You should have received a copy of the GNU General Public License |
22 ;; along with XEmacs; see the file COPYING. If not, write to the | 22 ;; along with XEmacs; see the file COPYING. If not, write to the |
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
24 ;; Boston, MA 02111-1307, USA. | 24 ;; Boston, MA 02111-1307, USA. |
25 | 25 |
26 ;;; Synched up with: FSF 19.30. | 26 ;;; Synched up with: FSF 19.30. |
27 | 27 |
30 ;; ======================================================================== | 30 ;; ======================================================================== |
31 ;; "No matter how hard you try, you can't make a racehorse out of a pig. | 31 ;; "No matter how hard you try, you can't make a racehorse out of a pig. |
32 ;; You can, however, make a faster pig." | 32 ;; You can, however, make a faster pig." |
33 ;; | 33 ;; |
34 ;; Or, to put it another way, the emacs byte compiler is a VW Bug. This code | 34 ;; Or, to put it another way, the emacs byte compiler is a VW Bug. This code |
35 ;; makes it be a VW Bug with fuel injection and a turbocharger... You're | 35 ;; makes it be a VW Bug with fuel injection and a turbocharger... You're |
36 ;; still not going to make it go faster than 70 mph, but it might be easier | 36 ;; still not going to make it go faster than 70 mph, but it might be easier |
37 ;; to get it there. | 37 ;; to get it there. |
38 ;; | 38 ;; |
39 | 39 |
40 ;; TO DO: | 40 ;; TO DO: |
62 ;; others? | 62 ;; others? |
63 ;; | 63 ;; |
64 ;; Simple defsubsts often produce forms like | 64 ;; Simple defsubsts often produce forms like |
65 ;; (let ((v1 (f1)) (v2 (f2)) ...) | 65 ;; (let ((v1 (f1)) (v2 (f2)) ...) |
66 ;; (FN v1 v2 ...)) | 66 ;; (FN v1 v2 ...)) |
67 ;; It would be nice if we could optimize this to | 67 ;; It would be nice if we could optimize this to |
68 ;; (FN (f1) (f2) ...) | 68 ;; (FN (f1) (f2) ...) |
69 ;; but we can't unless FN is dynamically-safe (it might be dynamically | 69 ;; but we can't unless FN is dynamically-safe (it might be dynamically |
70 ;; referring to the bindings that the lambda arglist established.) | 70 ;; referring to the bindings that the lambda arglist established.) |
71 ;; One of the uncountable lossages introduced by dynamic scope... | 71 ;; One of the uncountable lossages introduced by dynamic scope... |
72 ;; | 72 ;; |
73 ;; Maybe there should be a control-structure that says "turn on | 73 ;; Maybe there should be a control-structure that says "turn on |
74 ;; fast-and-loose type-assumptive optimizations here." Then when | 74 ;; fast-and-loose type-assumptive optimizations here." Then when |
75 ;; we see a form like (car foo) we can from then on assume that | 75 ;; we see a form like (car foo) we can from then on assume that |
76 ;; the variable foo is of type cons, and optimize based on that. | 76 ;; the variable foo is of type cons, and optimize based on that. |
77 ;; But, this won't win much because of (you guessed it) dynamic | 77 ;; But, this won't win much because of (you guessed it) dynamic |
78 ;; scope. Anything down the stack could change the value. | 78 ;; scope. Anything down the stack could change the value. |
79 ;; (Another reason it doesn't work is that it is perfectly valid | 79 ;; (Another reason it doesn't work is that it is perfectly valid |
80 ;; to call car with a null argument.) A better approach might | 80 ;; to call car with a null argument.) A better approach might |
81 ;; be to allow type-specification of the form | 81 ;; be to allow type-specification of the form |
82 ;; (put 'foo 'arg-types '(float (list integer) dynamic)) | 82 ;; (put 'foo 'arg-types '(float (list integer) dynamic)) |
107 ;; (funcall fn (car list)) | 107 ;; (funcall fn (car list)) |
108 ;; (tail-map fn (cdr list))))) | 108 ;; (tail-map fn (cdr list))))) |
109 ;; | 109 ;; |
110 ;; However, if there was even a single let-binding around the COND, | 110 ;; However, if there was even a single let-binding around the COND, |
111 ;; it could not be byte-compiled, because there would be an "unbind" | 111 ;; it could not be byte-compiled, because there would be an "unbind" |
112 ;; byte-op between the final "call" and "return." Adding a | 112 ;; byte-op between the final "call" and "return." Adding a |
113 ;; Bunbind_all byteop would fix this. | 113 ;; Bunbind_all byteop would fix this. |
114 ;; | 114 ;; |
115 ;; (defun foo (x y z) ... (foo a b c)) | 115 ;; (defun foo (x y z) ... (foo a b c)) |
116 ;; ... (const foo) (varref a) (varref b) (varref c) (call 3) END: (return) | 116 ;; ... (const foo) (varref a) (varref b) (varref c) (call 3) END: (return) |
117 ;; ... (varref a) (varbind x) (varref b) (varbind y) (varref c) (varbind z) (goto 0) END: (unbind-all) (return) | 117 ;; ... (varref a) (varbind x) (varref b) (varbind y) (varref c) (varbind z) (goto 0) END: (unbind-all) (return) |
129 ;; overflow. I don't believe there is any way around this without lexical | 129 ;; overflow. I don't believe there is any way around this without lexical |
130 ;; scope. | 130 ;; scope. |
131 ;; | 131 ;; |
132 ;; Wouldn't it be nice if Emacs Lisp had lexical scope. | 132 ;; Wouldn't it be nice if Emacs Lisp had lexical scope. |
133 ;; | 133 ;; |
134 ;; Idea: the form (lexical-scope) in a file means that the file may be | 134 ;; Idea: the form (lexical-scope) in a file means that the file may be |
135 ;; compiled lexically. This proclamation is file-local. Then, within | 135 ;; compiled lexically. This proclamation is file-local. Then, within |
136 ;; that file, "let" would establish lexical bindings, and "let-dynamic" | 136 ;; that file, "let" would establish lexical bindings, and "let-dynamic" |
137 ;; would do things the old way. (Or we could use CL "declare" forms.) | 137 ;; would do things the old way. (Or we could use CL "declare" forms.) |
138 ;; We'd have to notice defvars and defconsts, since those variables should | 138 ;; We'd have to notice defvars and defconsts, since those variables should |
139 ;; always be dynamic, and attempting to do a lexical binding of them | 139 ;; always be dynamic, and attempting to do a lexical binding of them |
140 ;; should simply do a dynamic binding instead. | 140 ;; should simply do a dynamic binding instead. |
141 ;; But! We need to know about variables that were not necessarily defvarred | 141 ;; But! We need to know about variables that were not necessarily defvarred |
142 ;; in the file being compiled (doing a boundp check isn't good enough.) | 142 ;; in the file being compiled (doing a boundp check isn't good enough.) |
143 ;; Fdefvar() would have to be modified to add something to the plist. | 143 ;; Fdefvar() would have to be modified to add something to the plist. |
144 ;; | 144 ;; |
145 ;; A major disadvantage of this scheme is that the interpreter and compiler | 145 ;; A major disadvantage of this scheme is that the interpreter and compiler |
146 ;; would have different semantics for files compiled with (dynamic-scope). | 146 ;; would have different semantics for files compiled with (dynamic-scope). |
147 ;; Since this would be a file-local optimization, there would be no way to | 147 ;; Since this would be a file-local optimization, there would be no way to |
148 ;; modify the interpreter to obey this (unless the loader was hacked | 148 ;; modify the interpreter to obey this (unless the loader was hacked |
149 ;; in some grody way, but that's a really bad idea.) | 149 ;; in some grody way, but that's a really bad idea.) |
150 ;; | 150 ;; |
151 ;; HA! RMS removed the following paragraph from his version of | 151 ;; HA! RMS removed the following paragraph from his version of |
152 ;; byte-optimize.el. | 152 ;; byte-optimize.el. |
153 ;; | 153 ;; |
154 ;; Really the Right Thing is to make lexical scope the default across | 154 ;; Really the Right Thing is to make lexical scope the default across |
155 ;; the board, in the interpreter and compiler, and just FIX all of | 155 ;; the board, in the interpreter and compiler, and just FIX all of |
156 ;; the code that relies on dynamic scope of non-defvarred variables. | 156 ;; the code that relies on dynamic scope of non-defvarred variables. |
157 | 157 |
158 ;; Other things to consider: | 158 ;; Other things to consider: |
159 | 159 |
160 ;; Associative math should recognize subcalls to identical function: | 160 ;; Associative math should recognize subcalls to identical function: |
164 ;;(disassemble #'(lambda (x) (cons (+ x 1) (- x 1)))) | 164 ;;(disassemble #'(lambda (x) (cons (+ x 1) (- x 1)))) |
165 ;; An awful lot of functions always return a non-nil value. If they're | 165 ;; An awful lot of functions always return a non-nil value. If they're |
166 ;; error free also they may act as true-constants. | 166 ;; error free also they may act as true-constants. |
167 | 167 |
168 ;;(disassemble #'(lambda (x) (and (point) (foo)))) | 168 ;;(disassemble #'(lambda (x) (and (point) (foo)))) |
169 ;; When | 169 ;; When |
170 ;; - all but one arguments to a function are constant | 170 ;; - all but one arguments to a function are constant |
171 ;; - the non-constant argument is an if-expression (cond-expression?) | 171 ;; - the non-constant argument is an if-expression (cond-expression?) |
172 ;; then the outer function can be distributed. If the guarding | 172 ;; then the outer function can be distributed. If the guarding |
173 ;; condition is side-effect-free [assignment-free] then the other | 173 ;; condition is side-effect-free [assignment-free] then the other |
174 ;; arguments may be any expressions. Since, however, the code size | 174 ;; arguments may be any expressions. Since, however, the code size |
293 (cdr form))) | 293 (cdr form))) |
294 (if (not (eq (car fn) 'lambda)) (error "%s is not a lambda" name)) | 294 (if (not (eq (car fn) 'lambda)) (error "%s is not a lambda" name)) |
295 (cons fn (cdr form))))))) | 295 (cons fn (cdr form))))))) |
296 | 296 |
297 ;;; ((lambda ...) ...) | 297 ;;; ((lambda ...) ...) |
298 ;;; | 298 ;;; |
299 (defun byte-compile-unfold-lambda (form &optional name) | 299 (defun byte-compile-unfold-lambda (form &optional name) |
300 (or name (setq name "anonymous lambda")) | 300 (or name (setq name "anonymous lambda")) |
301 (let ((lambda (car form)) | 301 (let ((lambda (car form)) |
302 (values (cdr form))) | 302 (values (cdr form))) |
303 (if (compiled-function-p lambda) | 303 (if (compiled-function-p lambda) |
348 (progn | 348 (progn |
349 (or (eq values 'too-few) | 349 (or (eq values 'too-few) |
350 (byte-compile-warn | 350 (byte-compile-warn |
351 "attempt to open-code %s with too many arguments" name)) | 351 "attempt to open-code %s with too many arguments" name)) |
352 form) | 352 form) |
353 (let ((newform | 353 (let ((newform |
354 (if bindings | 354 (if bindings |
355 (cons 'let (cons (nreverse bindings) body)) | 355 (cons 'let (cons (nreverse bindings) body)) |
356 (cons 'progn body)))) | 356 (cons 'progn body)))) |
357 (byte-compile-log " %s\t==>\t%s" form newform) | 357 (byte-compile-log " %s\t==>\t%s" form newform) |
358 newform))))) | 358 newform))))) |
433 ((eq fn 'prog2) | 433 ((eq fn 'prog2) |
434 (cons 'prog2 | 434 (cons 'prog2 |
435 (cons (byte-optimize-form (nth 1 form) t) | 435 (cons (byte-optimize-form (nth 1 form) t) |
436 (cons (byte-optimize-form (nth 2 form) for-effect) | 436 (cons (byte-optimize-form (nth 2 form) for-effect) |
437 (byte-optimize-body (cdr (cdr (cdr form))) t))))) | 437 (byte-optimize-body (cdr (cdr (cdr form))) t))))) |
438 | 438 |
439 ((memq fn '(save-excursion save-restriction save-current-buffer)) | 439 ((memq fn '(save-excursion save-restriction save-current-buffer)) |
440 ;; those subrs which have an implicit progn; it's not quite good | 440 ;; those subrs which have an implicit progn; it's not quite good |
441 ;; enough to treat these like normal function calls. | 441 ;; enough to treat these like normal function calls. |
442 ;; This can turn (save-excursion ...) into (save-excursion) which | 442 ;; This can turn (save-excursion ...) into (save-excursion) which |
443 ;; will be optimized away in the lap-optimize pass. | 443 ;; will be optimized away in the lap-optimize pass. |
444 (cons fn (byte-optimize-body (cdr form) for-effect))) | 444 (cons fn (byte-optimize-body (cdr form) for-effect))) |
445 | 445 |
446 ((eq fn 'with-output-to-temp-buffer) | 446 ((eq fn 'with-output-to-temp-buffer) |
447 ;; this is just like the above, except for the first argument. | 447 ;; this is just like the above, except for the first argument. |
448 (cons fn | 448 (cons fn |
449 (cons | 449 (cons |
450 (byte-optimize-form (nth 1 form) nil) | 450 (byte-optimize-form (nth 1 form) nil) |
451 (byte-optimize-body (cdr (cdr form)) for-effect)))) | 451 (byte-optimize-body (cdr (cdr form)) for-effect)))) |
452 | 452 |
453 ((eq fn 'if) | 453 ((eq fn 'if) |
454 (cons fn | 454 (cons fn |
455 (cons (byte-optimize-form (nth 1 form) nil) | 455 (cons (byte-optimize-form (nth 1 form) nil) |
456 (cons | 456 (cons |
457 (byte-optimize-form (nth 2 form) for-effect) | 457 (byte-optimize-form (nth 2 form) for-effect) |
458 (byte-optimize-body (nthcdr 3 form) for-effect))))) | 458 (byte-optimize-body (nthcdr 3 form) for-effect))))) |
459 | 459 |
460 ((memq fn '(and or)) ; remember, and/or are control structures. | 460 ((memq fn '(and or)) ; remember, and/or are control structures. |
461 ;; take forms off the back until we can't any more. | 461 ;; take forms off the back until we can't any more. |
462 ;; In the future it could conceivably be a problem that the | 462 ;; In the future it could conceivably be a problem that the |
463 ;; subexpressions of these forms are optimized in the reverse | 463 ;; subexpressions of these forms are optimized in the reverse |
464 ;; order, but it's ok for now. | 464 ;; order, but it's ok for now. |
478 | 478 |
479 ((eq fn 'interactive) | 479 ((eq fn 'interactive) |
480 (byte-compile-warn "misplaced interactive spec: %s" | 480 (byte-compile-warn "misplaced interactive spec: %s" |
481 (prin1-to-string form)) | 481 (prin1-to-string form)) |
482 nil) | 482 nil) |
483 | 483 |
484 ((memq fn '(defun defmacro function | 484 ((memq fn '(defun defmacro function |
485 condition-case save-window-excursion)) | 485 condition-case save-window-excursion)) |
486 ;; These forms are compiled as constants or by breaking out | 486 ;; These forms are compiled as constants or by breaking out |
487 ;; all the subexpressions and compiling them separately. | 487 ;; all the subexpressions and compiling them separately. |
488 form) | 488 form) |
494 ;; unwind-protect itself. (The protected part is always for effect, | 494 ;; unwind-protect itself. (The protected part is always for effect, |
495 ;; but that isn't handled properly yet.) | 495 ;; but that isn't handled properly yet.) |
496 (cons fn | 496 (cons fn |
497 (cons (byte-optimize-form (nth 1 form) for-effect) | 497 (cons (byte-optimize-form (nth 1 form) for-effect) |
498 (cdr (cdr form))))) | 498 (cdr (cdr form))))) |
499 | 499 |
500 ((eq fn 'catch) | 500 ((eq fn 'catch) |
501 ;; the body of a catch is compiled (and thus optimized) as a | 501 ;; the body of a catch is compiled (and thus optimized) as a |
502 ;; top-level form, so don't do it here. The tag is never | 502 ;; top-level form, so don't do it here. The tag is never |
503 ;; for-effect. The body should have the same for-effect status | 503 ;; for-effect. The body should have the same for-effect status |
504 ;; as the catch form itself, but that isn't handled properly yet. | 504 ;; as the catch form itself, but that isn't handled properly yet. |
512 ;; by the time that is reached. | 512 ;; by the time that is reached. |
513 ((not (eq form | 513 ((not (eq form |
514 (setq form (macroexpand form | 514 (setq form (macroexpand form |
515 byte-compile-macro-environment)))) | 515 byte-compile-macro-environment)))) |
516 (byte-optimize-form form for-effect)) | 516 (byte-optimize-form form for-effect)) |
517 | 517 |
518 ((not (symbolp fn)) | 518 ((not (symbolp fn)) |
519 (or (eq 'mocklisp (car-safe fn)) ; ha! | 519 (or (eq 'mocklisp (car-safe fn)) ; ha! |
520 (byte-compile-warn "%s is a malformed function" | 520 (byte-compile-warn "%s is a malformed function" |
521 (prin1-to-string fn))) | 521 (prin1-to-string fn))) |
522 form) | 522 form) |
530 nil))) | 530 nil))) |
531 (byte-compile-log " %s called for effect; deleted" fn) | 531 (byte-compile-log " %s called for effect; deleted" fn) |
532 ;; appending a nil here might not be necessary, but it can't hurt. | 532 ;; appending a nil here might not be necessary, but it can't hurt. |
533 (byte-optimize-form | 533 (byte-optimize-form |
534 (cons 'progn (append (cdr form) '(nil))) t)) | 534 (cons 'progn (append (cdr form) '(nil))) t)) |
535 | 535 |
536 (t | 536 (t |
537 ;; Otherwise, no args can be considered to be for-effect, | 537 ;; Otherwise, no args can be considered to be for-effect, |
538 ;; even if the called function is for-effect, because we | 538 ;; even if the called function is for-effect, because we |
539 ;; don't know anything about that function. | 539 ;; don't know anything about that function. |
540 (cons fn (mapcar 'byte-optimize-form (cdr form))))))) | 540 (cons fn (mapcar 'byte-optimize-form (cdr form))))))) |
600 ((not (symbolp ,form))) | 600 ((not (symbolp ,form))) |
601 ((eq ,form t)) | 601 ((eq ,form t)) |
602 ((keywordp ,form)))) | 602 ((keywordp ,form)))) |
603 | 603 |
604 ;; If the function is being called with constant numeric args, | 604 ;; If the function is being called with constant numeric args, |
605 ;; evaluate as much as possible at compile-time. This optimizer | 605 ;; evaluate as much as possible at compile-time. This optimizer |
606 ;; assumes that the function is associative, like + or *. | 606 ;; assumes that the function is associative, like + or *. |
607 (defun byte-optimize-associative-math (form) | 607 (defun byte-optimize-associative-math (form) |
608 (let ((args nil) | 608 (let ((args nil) |
609 (constants nil) | 609 (constants nil) |
610 (rest (cdr form))) | 610 (rest (cdr form))) |
697 | 697 |
698 (defun byte-optimize-plus (form) | 698 (defun byte-optimize-plus (form) |
699 (setq form (byte-optimize-delay-constants-math form 1 '+)) | 699 (setq form (byte-optimize-delay-constants-math form 1 '+)) |
700 (if (memq 0 form) (setq form (delq 0 (copy-sequence form)))) | 700 (if (memq 0 form) (setq form (delq 0 (copy-sequence form)))) |
701 ;;(setq form (byte-optimize-associative-two-args-math form)) | 701 ;;(setq form (byte-optimize-associative-two-args-math form)) |
702 (cond ((null (cdr form)) | 702 (case (length (cdr form)) |
703 (condition-case () | 703 ((0) |
704 (eval form) | 704 (condition-case () |
705 (error form))) | 705 (eval form) |
706 | 706 (error form))) |
707 ;; `add1' and `sub1' are a marginally fewer instructions | 707 |
708 ;; than `plus' and `minus', so use them when possible. | 708 ;; `add1' and `sub1' are a marginally fewer instructions |
709 ((and (null (nthcdr 3 form)) | 709 ;; than `plus' and `minus', so use them when possible. |
710 (eq (nth 2 form) 1)) | 710 ((2) |
711 (list '1+ (nth 1 form))) ; (+ x 1) --> (1+ x) | 711 (cond |
712 ((and (null (nthcdr 3 form)) | 712 ((eq (nth 1 form) 1) `(1+ ,(nth 2 form))) ; (+ 1 x) --> (1+ x) |
713 (eq (nth 1 form) 1)) | 713 ((eq (nth 2 form) 1) `(1+ ,(nth 1 form))) ; (+ x 1) --> (1+ x) |
714 (list '1+ (nth 2 form))) ; (+ 1 x) --> (1+ x) | 714 ((eq (nth 1 form) -1) `(1- ,(nth 2 form))) ; (+ -1 x) --> (1- x) |
715 ((and (null (nthcdr 3 form)) | 715 ((eq (nth 2 form) -1) `(1- ,(nth 1 form))) ; (+ x -1) --> (1- x) |
716 (eq (nth 2 form) -1)) | 716 (t form))) |
717 (list '1- (nth 1 form))) ; (+ x -1) --> (1- x) | 717 |
718 ((and (null (nthcdr 3 form)) | 718 ;; It is not safe to delete the function entirely |
719 (eq (nth 1 form) -1)) | 719 ;; (actually, it would be safe if we know the sole arg |
720 (list '1- (nth 2 form))) ; (+ -1 x) --> (1- x) | 720 ;; is not a marker). |
721 | 721 ;; ((null (cdr (cdr form))) (nth 1 form)) |
722 ;;; It is not safe to delete the function entirely | 722 (t form))) |
723 ;;; (actually, it would be safe if we know the sole arg | |
724 ;;; is not a marker). | |
725 ;; ((null (cdr (cdr form))) (nth 1 form)) | |
726 (t form))) | |
727 | 723 |
728 (defun byte-optimize-minus (form) | 724 (defun byte-optimize-minus (form) |
729 ;; Put constants at the end, except the last constant. | 725 ;; Put constants at the end, except the last constant. |
730 (setq form (byte-optimize-delay-constants-math form 2 '+)) | 726 (setq form (byte-optimize-delay-constants-math form 2 '+)) |
731 ;; Now only first and last element can be a number. | 727 ;; Now only first and last element can be a number. |
782 (prog1 (setq form (delq 2 (copy-sequence form))) | 778 (prog1 (setq form (delq 2 (copy-sequence form))) |
783 (while (not (symbolp (car (setq form (cdr form)))))) | 779 (while (not (symbolp (car (setq form (cdr form)))))) |
784 (setcar form (list '+ (car form) (car form))))) | 780 (setcar form (list '+ (car form) (car form))))) |
785 (form)))))) | 781 (form)))))) |
786 | 782 |
787 (defsubst byte-compile-butlast (form) | |
788 (nreverse (cdr (reverse form)))) | |
789 | |
790 (defun byte-optimize-divide (form) | 783 (defun byte-optimize-divide (form) |
791 (setq form (byte-optimize-delay-constants-math form 2 '*)) | 784 (setq form (byte-optimize-delay-constants-math form 2 '*)) |
792 (let ((last (car (reverse (cdr (cdr form)))))) | 785 (let ((last (car (reverse (cdr (cdr form)))))) |
793 (if (numberp last) | 786 (if (numberp last) |
794 (cond ((= (length form) 3) | 787 (cond ((= (length form) 3) |
797 (condition-case nil | 790 (condition-case nil |
798 (/ (nth 1 form) last) | 791 (/ (nth 1 form) last) |
799 (error nil))) | 792 (error nil))) |
800 (setq form (list 'progn (/ (nth 1 form) last))))) | 793 (setq form (list 'progn (/ (nth 1 form) last))))) |
801 ((= last 1) | 794 ((= last 1) |
802 (setq form (byte-compile-butlast form))) | 795 (setq form (butlast form))) |
803 ((numberp (nth 1 form)) | 796 ((numberp (nth 1 form)) |
804 (setq form (cons (car form) | 797 (setq form (cons (car form) |
805 (cons (/ (nth 1 form) last) | 798 (cons (/ (nth 1 form) last) |
806 (byte-compile-butlast (cdr (cdr form))))) | 799 (butlast (cdr (cdr form))))) |
807 last nil)))) | 800 last nil)))) |
808 (cond | 801 (cond |
809 ;;; ((null (cdr (cdr form))) | 802 ;;; ((null (cdr (cdr form))) |
810 ;;; (nth 1 form)) | 803 ;;; (nth 1 form)) |
811 ((eq (nth 1 form) 0) | 804 ((eq (nth 1 form) 0) |
812 (append '(progn) (cdr (cdr form)) '(0))) | 805 (append '(progn) (cdr (cdr form)) '(0))) |
813 ((eq last -1) | 806 ((eq last -1) |
814 (list '- (if (nthcdr 3 form) | 807 (list '- (if (nthcdr 3 form) |
815 (byte-compile-butlast form) | 808 (butlast form) |
816 (nth 1 form)))) | 809 (nth 1 form)))) |
817 (form)))) | 810 (form)))) |
818 | 811 |
819 (defun byte-optimize-logmumble (form) | 812 (defun byte-optimize-logmumble (form) |
820 (setq form (byte-optimize-delay-constants-math form 1 (car form))) | 813 (setq form (byte-optimize-delay-constants-math form 1 (car form))) |
888 (put 'listp 'byte-optimizer 'byte-optimize-predicate) | 881 (put 'listp 'byte-optimizer 'byte-optimize-predicate) |
889 (put 'symbolp 'byte-optimizer 'byte-optimize-predicate) | 882 (put 'symbolp 'byte-optimizer 'byte-optimize-predicate) |
890 (put 'stringp 'byte-optimizer 'byte-optimize-predicate) | 883 (put 'stringp 'byte-optimizer 'byte-optimize-predicate) |
891 (put 'string< 'byte-optimizer 'byte-optimize-predicate) | 884 (put 'string< 'byte-optimizer 'byte-optimize-predicate) |
892 (put 'string-lessp 'byte-optimizer 'byte-optimize-predicate) | 885 (put 'string-lessp 'byte-optimizer 'byte-optimize-predicate) |
886 (put 'length 'byte-optimizer 'byte-optimize-predicate) | |
893 | 887 |
894 (put 'logand 'byte-optimizer 'byte-optimize-logmumble) | 888 (put 'logand 'byte-optimizer 'byte-optimize-logmumble) |
895 (put 'logior 'byte-optimizer 'byte-optimize-logmumble) | 889 (put 'logior 'byte-optimizer 'byte-optimize-logmumble) |
896 (put 'logxor 'byte-optimizer 'byte-optimize-logmumble) | 890 (put 'logxor 'byte-optimizer 'byte-optimize-logmumble) |
897 (put 'lognot 'byte-optimizer 'byte-optimize-predicate) | 891 (put 'lognot 'byte-optimizer 'byte-optimize-predicate) |
900 (put 'cdr 'byte-optimizer 'byte-optimize-predicate) | 894 (put 'cdr 'byte-optimizer 'byte-optimize-predicate) |
901 (put 'car-safe 'byte-optimizer 'byte-optimize-predicate) | 895 (put 'car-safe 'byte-optimizer 'byte-optimize-predicate) |
902 (put 'cdr-safe 'byte-optimizer 'byte-optimize-predicate) | 896 (put 'cdr-safe 'byte-optimizer 'byte-optimize-predicate) |
903 | 897 |
904 | 898 |
905 ;; I'm not convinced that this is necessary. Doesn't the optimizer loop | 899 ;; I'm not convinced that this is necessary. Doesn't the optimizer loop |
906 ;; take care of this? - Jamie | 900 ;; take care of this? - Jamie |
907 ;; I think this may some times be necessary to reduce eg. (quote 5) to 5, | 901 ;; I think this may some times be necessary to reduce eg. (quote 5) to 5, |
908 ;; so arithmetic optimizers recognize the numeric constant. - Hallvard | 902 ;; so arithmetic optimizers recognize the numeric constant. - Hallvard |
909 (put 'quote 'byte-optimizer 'byte-optimize-quote) | 903 (put 'quote 'byte-optimizer 'byte-optimize-quote) |
910 (defun byte-optimize-quote (form) | 904 (defun byte-optimize-quote (form) |
1031 (put 'or 'byte-optimizer 'byte-optimize-or) | 1025 (put 'or 'byte-optimizer 'byte-optimize-or) |
1032 (put 'cond 'byte-optimizer 'byte-optimize-cond) | 1026 (put 'cond 'byte-optimizer 'byte-optimize-cond) |
1033 (put 'if 'byte-optimizer 'byte-optimize-if) | 1027 (put 'if 'byte-optimizer 'byte-optimize-if) |
1034 (put 'while 'byte-optimizer 'byte-optimize-while) | 1028 (put 'while 'byte-optimizer 'byte-optimize-while) |
1035 | 1029 |
1030 ;; Remove any reason for avoiding `char-before'. | |
1031 (defun byte-optimize-char-before (form) | |
1032 `(char-after (1- ,(or (nth 1 form) '(point))) ,@(cdr (cdr form)))) | |
1033 | |
1034 (put 'char-before 'byte-optimizer 'byte-optimize-char-before) | |
1035 | |
1036 ;; byte-compile-negation-optimizer lives in bytecomp.el | 1036 ;; byte-compile-negation-optimizer lives in bytecomp.el |
1037 ;(put '/= 'byte-optimizer 'byte-compile-negation-optimizer) | 1037 ;(put '/= 'byte-optimizer 'byte-compile-negation-optimizer) |
1038 (put 'atom 'byte-optimizer 'byte-compile-negation-optimizer) | 1038 (put 'atom 'byte-optimizer 'byte-compile-negation-optimizer) |
1039 (put 'nlistp 'byte-optimizer 'byte-compile-negation-optimizer) | 1039 (put 'nlistp 'byte-optimizer 'byte-compile-negation-optimizer) |
1040 | 1040 |
1101 (setq form (nth 2 form)) | 1101 (setq form (nth 2 form)) |
1102 (while (>= (setq count (1- count)) 0) | 1102 (while (>= (setq count (1- count)) 0) |
1103 (setq form (list 'cdr form))) | 1103 (setq form (list 'cdr form))) |
1104 form))) | 1104 form))) |
1105 | 1105 |
1106 ;;; enumerating those functions which need not be called if the returned | 1106 ;;; enumerating those functions which need not be called if the returned |
1107 ;;; value is not used. That is, something like | 1107 ;;; value is not used. That is, something like |
1108 ;;; (progn (list (something-with-side-effects) (yow)) | 1108 ;;; (progn (list (something-with-side-effects) (yow)) |
1109 ;;; (foo)) | 1109 ;;; (foo)) |
1110 ;;; may safely be turned into | 1110 ;;; may safely be turned into |
1111 ;;; (progn (progn (something-with-side-effects) (yow)) | 1111 ;;; (progn (progn (something-with-side-effects) (yow)) |
1139 ;; | 1139 ;; |
1140 int-to-string | 1140 int-to-string |
1141 length log log10 logand logb logior lognot logxor lsh | 1141 length log log10 logand logb logior lognot logxor lsh |
1142 marker-buffer max member memq min mod | 1142 marker-buffer max member memq min mod |
1143 next-window nth nthcdr number-to-string | 1143 next-window nth nthcdr number-to-string |
1144 parse-colon-path previous-window | 1144 parse-colon-path plist-get previous-window |
1145 radians-to-degrees rassq regexp-quote reverse round | 1145 radians-to-degrees rassq regexp-quote reverse round |
1146 sin sqrt string< string= string-equal string-lessp string-to-char | 1146 sin sqrt string< string= string-equal string-lessp string-to-char |
1147 string-to-int string-to-number substring symbol-plist | 1147 string-to-int string-to-number substring symbol-plist |
1148 tan upcase user-variable-p vconcat | 1148 tan upcase user-variable-p vconcat |
1149 ;; XEmacs change: window-edges -> window-pixel-edges | 1149 ;; XEmacs change: window-edges -> window-pixel-edges |
1153 ;; functions defined by cl | 1153 ;; functions defined by cl |
1154 oddp evenp plusp minusp | 1154 oddp evenp plusp minusp |
1155 abs expt signum last butlast ldiff | 1155 abs expt signum last butlast ldiff |
1156 pairlis gcd lcm | 1156 pairlis gcd lcm |
1157 isqrt floor* ceiling* truncate* round* mod* rem* subseq | 1157 isqrt floor* ceiling* truncate* round* mod* rem* subseq |
1158 list-length get* getf | 1158 list-length getf |
1159 )) | 1159 )) |
1160 (side-effect-and-error-free-fns | 1160 (side-effect-and-error-free-fns |
1161 '(arrayp atom | 1161 '(arrayp atom |
1162 bobp bolp buffer-end buffer-list buffer-size buffer-string bufferp | 1162 bobp bolp buffer-end buffer-list buffer-size buffer-string bufferp |
1163 car-safe case-table-p cdr-safe char-or-string-p char-table-p | 1163 car-safe case-table-p cdr-safe char-or-string-p char-table-p |
1379 byte-point-min byte-following-char byte-preceding-char | 1379 byte-point-min byte-following-char byte-preceding-char |
1380 byte-current-column byte-eolp byte-eobp byte-bolp byte-bobp | 1380 byte-current-column byte-eolp byte-eobp byte-bolp byte-bobp |
1381 byte-current-buffer byte-interactive-p)) | 1381 byte-current-buffer byte-interactive-p)) |
1382 | 1382 |
1383 (defconst byte-compile-side-effect-free-ops | 1383 (defconst byte-compile-side-effect-free-ops |
1384 (nconc | 1384 (nconc |
1385 '(byte-varref byte-nth byte-memq byte-car byte-cdr byte-length byte-aref | 1385 '(byte-varref byte-nth byte-memq byte-car byte-cdr byte-length byte-aref |
1386 byte-symbol-value byte-get byte-concat2 byte-concat3 byte-sub1 byte-add1 | 1386 byte-symbol-value byte-get byte-concat2 byte-concat3 byte-sub1 byte-add1 |
1387 byte-eqlsign byte-gtr byte-lss byte-leq byte-geq byte-diff byte-negate | 1387 byte-eqlsign byte-gtr byte-lss byte-leq byte-geq byte-diff byte-negate |
1388 byte-plus byte-max byte-min byte-mult byte-char-after byte-char-syntax | 1388 byte-plus byte-max byte-min byte-mult byte-char-after byte-char-syntax |
1389 byte-buffer-substring byte-string= byte-string< byte-nthcdr byte-elt | 1389 byte-buffer-substring byte-string= byte-string< byte-nthcdr byte-elt |
1411 ;;; varref flag | 1411 ;;; varref flag |
1412 ;;; dup | 1412 ;;; dup |
1413 ;;; varbind pop-up-windows | 1413 ;;; varbind pop-up-windows |
1414 ;;; not | 1414 ;;; not |
1415 ;;; | 1415 ;;; |
1416 ;;; we break the program, because it will appear that pop-up-windows and | 1416 ;;; we break the program, because it will appear that pop-up-windows and |
1417 ;;; old-pop-ups are not EQ when really they are. So we have to know what | 1417 ;;; old-pop-ups are not EQ when really they are. So we have to know what |
1418 ;;; the BOOL variables are, and not perform this optimization on them. | 1418 ;;; the BOOL variables are, and not perform this optimization on them. |
1419 ;;; | 1419 ;;; |
1420 | 1420 |
1421 ;;; This used to hold a large list of boolean variables, which had to | 1421 ;;; This used to hold a large list of boolean variables, which had to |
1591 ;; | 1591 ;; |
1592 ;; goto-X-if-nil goto-Y X: --> goto-Y-if-non-nil X: | 1592 ;; goto-X-if-nil goto-Y X: --> goto-Y-if-non-nil X: |
1593 ;; goto-X-if-non-nil goto-Y X: --> goto-Y-if-nil X: | 1593 ;; goto-X-if-non-nil goto-Y X: --> goto-Y-if-nil X: |
1594 ;; | 1594 ;; |
1595 ;; it is wrong to do the same thing for the -else-pop variants. | 1595 ;; it is wrong to do the same thing for the -else-pop variants. |
1596 ;; | 1596 ;; |
1597 ((and (or (eq 'byte-goto-if-nil (car lap0)) | 1597 ((and (or (eq 'byte-goto-if-nil (car lap0)) |
1598 (eq 'byte-goto-if-not-nil (car lap0))) ; gotoX | 1598 (eq 'byte-goto-if-not-nil (car lap0))) ; gotoX |
1599 (eq 'byte-goto (car lap1)) ; gotoY | 1599 (eq 'byte-goto (car lap1)) ; gotoY |
1600 (eq (cdr lap0) lap2)) ; TAG X | 1600 (eq (cdr lap0) lap2)) ; TAG X |
1601 (let ((inverse (if (eq 'byte-goto-if-nil (car lap0)) | 1601 (let ((inverse (if (eq 'byte-goto-if-nil (car lap0)) |
1694 (not (eq 'TAG (car (car tmp))))) | 1694 (not (eq 'TAG (car (car tmp))))) |
1695 (if opt-p (setq deleted (cons (car tmp) deleted) | 1695 (if opt-p (setq deleted (cons (car tmp) deleted) |
1696 str (concat str " %s") | 1696 str (concat str " %s") |
1697 i (1+ i)))) | 1697 i (1+ i)))) |
1698 (if opt-p | 1698 (if opt-p |
1699 (let ((tagstr | 1699 (let ((tagstr |
1700 (if (eq 'TAG (car (car tmp))) | 1700 (if (eq 'TAG (car (car tmp))) |
1701 (format "%d:" (car (cdr (car tmp)))) | 1701 (format "%d:" (car (cdr (car tmp)))) |
1702 (or (car tmp) "")))) | 1702 (or (car tmp) "")))) |
1703 (if (< i 6) | 1703 (if (< i 6) |
1704 (apply 'byte-compile-log-lap-1 | 1704 (apply 'byte-compile-log-lap-1 |
1876 (byte-goto-if-nil-else-pop . | 1876 (byte-goto-if-nil-else-pop . |
1877 byte-goto-if-not-nil-else-pop) | 1877 byte-goto-if-not-nil-else-pop) |
1878 (byte-goto-if-not-nil-else-pop . | 1878 (byte-goto-if-not-nil-else-pop . |
1879 byte-goto-if-nil-else-pop)))) | 1879 byte-goto-if-nil-else-pop)))) |
1880 newtag) | 1880 newtag) |
1881 | 1881 |
1882 (nth 1 newtag) | 1882 (nth 1 newtag) |
1883 ) | 1883 ) |
1884 (setcdr tmp (cons (setcdr lap0 newtag) (cdr tmp))) | 1884 (setcdr tmp (cons (setcdr lap0 newtag) (cdr tmp))) |
1885 (if (eq (car (car tmp)) 'byte-goto-if-nil-else-pop) | 1885 (if (eq (car (car tmp)) 'byte-goto-if-nil-else-pop) |
1886 ;; We can handle this case but not the -if-not-nil case, | 1886 ;; We can handle this case but not the -if-not-nil case, |