diff options
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/emacs-lisp/byte-opt.el | 175 |
1 files changed, 124 insertions, 51 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 004f58cc12f..3bc4c438d6a 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el | |||
| @@ -678,59 +678,134 @@ | |||
| 678 | (apply (car form) constants)) | 678 | (apply (car form) constants)) |
| 679 | form))) | 679 | form))) |
| 680 | 680 | ||
| 681 | ;; Portable Emacs integers fall in this range. | ||
| 682 | (defconst byte-opt--portable-max #x1fffffff) | ||
| 683 | (defconst byte-opt--portable-min (- -1 byte-opt--portable-max)) | ||
| 684 | |||
| 685 | ;; True if N is a number that works the same on all Emacs platforms. | ||
| 686 | ;; Portable Emacs fixnums are exactly representable as floats on all | ||
| 687 | ;; Emacs platforms, and (except for -0.0) any floating-point number | ||
| 688 | ;; that equals one of these integers must be the same on all | ||
| 689 | ;; platforms. Although other floating-point numbers such as 0.5 are | ||
| 690 | ;; also portable, it can be tricky to characterize them portably so | ||
| 691 | ;; they are not optimized. | ||
| 692 | (defun byte-opt--portable-numberp (n) | ||
| 693 | (and (numberp n) | ||
| 694 | (<= byte-opt--portable-min n byte-opt--portable-max) | ||
| 695 | (= n (floor n)) | ||
| 696 | (not (and (floatp n) (zerop n) | ||
| 697 | (condition-case () (< (/ n) 0) (error)))))) | ||
| 698 | |||
| 699 | ;; Use OP to reduce any leading prefix of portable numbers in the list | ||
| 700 | ;; (cons ACCUM ARGS) down to a single portable number, and return the | ||
| 701 | ;; resulting list A of arguments. The idea is that applying OP to A | ||
| 702 | ;; is equivalent to (but likely more efficient than) applying OP to | ||
| 703 | ;; (cons ACCUM ARGS), on any Emacs platform. Do not make any special | ||
| 704 | ;; provision for (- X) or (/ X); for example, it is the caller’s | ||
| 705 | ;; responsibility that (- 1 0) should not be "optimized" to (- 1). | ||
| 706 | (defun byte-opt--arith-reduce (op accum args) | ||
| 707 | (when (byte-opt--portable-numberp accum) | ||
| 708 | (let (accum1) | ||
| 709 | (while (and (byte-opt--portable-numberp (car args)) | ||
| 710 | (byte-opt--portable-numberp | ||
| 711 | (setq accum1 (condition-case () | ||
| 712 | (funcall op accum (car args)) | ||
| 713 | (error)))) | ||
| 714 | (= accum1 (funcall op (float accum) (car args)))) | ||
| 715 | (setq accum accum1) | ||
| 716 | (setq args (cdr args))))) | ||
| 717 | (cons accum args)) | ||
| 718 | |||
| 681 | (defun byte-optimize-plus (form) | 719 | (defun byte-optimize-plus (form) |
| 682 | (if (memq 0 form) (setq form (delq 0 (copy-sequence form)))) | 720 | (let ((args (remq 0 (byte-opt--arith-reduce #'+ 0 (cdr form))))) |
| 683 | ;; For (+ constants...), byte-optimize-predicate does the work. | ||
| 684 | (when (memq nil (mapcar 'numberp (cdr form))) | ||
| 685 | (cond | 721 | (cond |
| 722 | ;; (+) -> 0 | ||
| 723 | ((null args) 0) | ||
| 724 | ;; (+ n) -> n, where n is a number | ||
| 725 | ((and (null (cdr args)) (numberp (car args))) (car args)) | ||
| 686 | ;; (+ x 1) --> (1+ x) and (+ x -1) --> (1- x). | 726 | ;; (+ x 1) --> (1+ x) and (+ x -1) --> (1- x). |
| 687 | ((and (= (length form) 3) | 727 | ((and (null (cddr args)) (or (memq 1 args) (memq -1 args))) |
| 688 | (or (memq (nth 1 form) '(1 -1)) | 728 | (let* ((arg1 (car args)) (arg2 (cadr args)) |
| 689 | (memq (nth 2 form) '(1 -1)))) | 729 | (integer-is-first (memq arg1 '(1 -1))) |
| 690 | (let (integer other) | 730 | (integer (if integer-is-first arg1 arg2)) |
| 691 | (if (memq (nth 1 form) '(1 -1)) | 731 | (other (if integer-is-first arg2 arg1))) |
| 692 | (setq integer (nth 1 form) other (nth 2 form)) | 732 | (list (if (eq integer 1) '1+ '1-) other))) |
| 693 | (setq integer (nth 2 form) other (nth 1 form))) | 733 | ;; not further optimized |
| 694 | (setq form | 734 | ((equal args (cdr form)) form) |
| 695 | (list (if (eq integer 1) '1+ '1-) other)))))) | 735 | (t (cons '+ args))))) |
| 696 | (byte-optimize-predicate form)) | ||
| 697 | 736 | ||
| 698 | (defun byte-optimize-minus (form) | 737 | (defun byte-optimize-minus (form) |
| 699 | ;; Remove zeros. | 738 | (let ((args (cdr form))) |
| 700 | (when (and (nthcdr 3 form) | 739 | (if (and (cdr args) |
| 701 | (memq 0 (cddr form))) | 740 | (null (cdr (setq args (byte-opt--arith-reduce |
| 702 | (setq form (nconc (list (car form) (cadr form)) | 741 | #'- (car args) (cdr args))))) |
| 703 | (delq 0 (copy-sequence (cddr form))))) | 742 | (numberp (car args))) |
| 704 | ;; After the above, we must turn (- x) back into (- x 0). | 743 | ;; The entire argument list reduced to a constant; return it. |
| 705 | (or (cddr form) | 744 | (car args) |
| 706 | (setq form (nconc form (list 0))))) | 745 | ;; Remove non-leading zeros, except for (- x 0). |
| 707 | ;; For (- constants...), byte-optimize-predicate does the work. | 746 | (when (memq 0 (cdr args)) |
| 708 | (when (memq nil (mapcar 'numberp (cdr form))) | 747 | (setq args (cons (car args) (or (remq 0 (cdr args)) (list 0))))) |
| 709 | (cond | 748 | (cond |
| 710 | ;; (- x 1) --> (1- x) | 749 | ;; (- x 1) --> (1- x) |
| 711 | ((equal (nthcdr 2 form) '(1)) | 750 | ((equal (cdr args) '(1)) |
| 712 | (setq form (list '1- (nth 1 form)))) | 751 | (list '1- (car args))) |
| 713 | ;; (- x -1) --> (1+ x) | 752 | ;; (- x -1) --> (1+ x) |
| 714 | ((equal (nthcdr 2 form) '(-1)) | 753 | ((equal (cdr args) '(-1)) |
| 715 | (setq form (list '1+ (nth 1 form)))))) | 754 | (list '1+ (car args))) |
| 716 | (byte-optimize-predicate form)) | 755 | ;; (- n) -> -n, where n and -n are portable numbers. |
| 756 | ;; This must be done separately since byte-opt--arith-reduce | ||
| 757 | ;; is not applied to (- n). | ||
| 758 | ((and (null (cdr args)) | ||
| 759 | (byte-opt--portable-numberp (car args)) | ||
| 760 | (byte-opt--portable-numberp (- (car args)))) | ||
| 761 | (- (car args))) | ||
| 762 | ;; not further optimized | ||
| 763 | ((equal args (cdr form)) form) | ||
| 764 | (t (cons '- args)))))) | ||
| 765 | |||
| 766 | (defun byte-optimize-1+ (form) | ||
| 767 | (let ((args (cdr form))) | ||
| 768 | (when (null (cdr args)) | ||
| 769 | (let ((n (car args))) | ||
| 770 | (when (and (byte-opt--portable-numberp n) | ||
| 771 | (byte-opt--portable-numberp (1+ n))) | ||
| 772 | (setq form (1+ n)))))) | ||
| 773 | form) | ||
| 774 | |||
| 775 | (defun byte-optimize-1- (form) | ||
| 776 | (let ((args (cdr form))) | ||
| 777 | (when (null (cdr args)) | ||
| 778 | (let ((n (car args))) | ||
| 779 | (when (and (byte-opt--portable-numberp n) | ||
| 780 | (byte-opt--portable-numberp (1- n))) | ||
| 781 | (setq form (1- n)))))) | ||
| 782 | form) | ||
| 717 | 783 | ||
| 718 | (defun byte-optimize-multiply (form) | 784 | (defun byte-optimize-multiply (form) |
| 719 | (if (memq 1 form) (setq form (delq 1 (copy-sequence form)))) | 785 | (let* ((args (remq 1 (byte-opt--arith-reduce #'* 1 (cdr form))))) |
| 720 | ;; For (* integers..), byte-optimize-predicate does the work. | 786 | (cond |
| 721 | (byte-optimize-predicate form)) | 787 | ;; (*) -> 1 |
| 788 | ((null args) 1) | ||
| 789 | ;; (* n) -> n, where n is a number | ||
| 790 | ((and (null (cdr args)) (numberp (car args))) (car args)) | ||
| 791 | ;; not further optimized | ||
| 792 | ((equal args (cdr form)) form) | ||
| 793 | (t (cons '* args))))) | ||
| 722 | 794 | ||
| 723 | (defun byte-optimize-divide (form) | 795 | (defun byte-optimize-divide (form) |
| 724 | ;; Remove 1s. | 796 | (let ((args (cdr form))) |
| 725 | (when (and (nthcdr 3 form) | 797 | (if (and (cdr args) |
| 726 | (memq 1 (cddr form))) | 798 | (null (cdr (setq args (byte-opt--arith-reduce |
| 727 | (setq form (nconc (list (car form) (cadr form)) | 799 | #'/ (car args) (cdr args))))) |
| 728 | (delq 1 (copy-sequence (cddr form))))) | 800 | (numberp (car args))) |
| 729 | ;; After the above, we must turn (/ x) back into (/ x 1). | 801 | ;; The entire argument list reduced to a constant; return it. |
| 730 | (or (cddr form) | 802 | (car args) |
| 731 | (setq form (nconc form (list 1))))) | 803 | ;; Remove non-leading 1s, except for (/ x 1). |
| 732 | (byte-optimize-predicate form)) | 804 | (when (memq 1 (cdr args)) |
| 733 | 805 | (setq args (cons (car args) (or (remq 1 (cdr args)) (list 1))))) | |
| 806 | (if (equal args (cdr form)) | ||
| 807 | form | ||
| 808 | (cons '/ args))))) | ||
| 734 | 809 | ||
| 735 | (defun byte-optimize-binary-predicate (form) | 810 | (defun byte-optimize-binary-predicate (form) |
| 736 | (cond | 811 | (cond |
| @@ -800,8 +875,8 @@ | |||
| 800 | (put '> 'byte-optimizer 'byte-optimize-predicate) | 875 | (put '> 'byte-optimizer 'byte-optimize-predicate) |
| 801 | (put '<= 'byte-optimizer 'byte-optimize-predicate) | 876 | (put '<= 'byte-optimizer 'byte-optimize-predicate) |
| 802 | (put '>= 'byte-optimizer 'byte-optimize-predicate) | 877 | (put '>= 'byte-optimizer 'byte-optimize-predicate) |
| 803 | (put '1+ 'byte-optimizer 'byte-optimize-predicate) | 878 | (put '1+ 'byte-optimizer 'byte-optimize-1+) |
| 804 | (put '1- 'byte-optimizer 'byte-optimize-predicate) | 879 | (put '1- 'byte-optimizer 'byte-optimize-1-) |
| 805 | (put 'not 'byte-optimizer 'byte-optimize-predicate) | 880 | (put 'not 'byte-optimizer 'byte-optimize-predicate) |
| 806 | (put 'null 'byte-optimizer 'byte-optimize-predicate) | 881 | (put 'null 'byte-optimizer 'byte-optimize-predicate) |
| 807 | (put 'consp 'byte-optimizer 'byte-optimize-predicate) | 882 | (put 'consp 'byte-optimizer 'byte-optimize-predicate) |
| @@ -854,8 +929,7 @@ | |||
| 854 | ;; Throw away nil's, and simplify if less than 2 args. | 929 | ;; Throw away nil's, and simplify if less than 2 args. |
| 855 | ;; If there is a literal non-nil constant in the args to `or', throw away all | 930 | ;; If there is a literal non-nil constant in the args to `or', throw away all |
| 856 | ;; following forms. | 931 | ;; following forms. |
| 857 | (if (memq nil form) | 932 | (setq form (remq nil form)) |
| 858 | (setq form (delq nil (copy-sequence form)))) | ||
| 859 | (let ((rest form)) | 933 | (let ((rest form)) |
| 860 | (while (cdr (setq rest (cdr rest))) | 934 | (while (cdr (setq rest (cdr rest))) |
| 861 | (if (byte-compile-trueconstp (car rest)) | 935 | (if (byte-compile-trueconstp (car rest)) |
| @@ -872,9 +946,8 @@ | |||
| 872 | (let (rest) | 946 | (let (rest) |
| 873 | ;; This must be first, to reduce (cond (t ...) (nil)) to (progn t ...) | 947 | ;; This must be first, to reduce (cond (t ...) (nil)) to (progn t ...) |
| 874 | (while (setq rest (assq nil (cdr form))) | 948 | (while (setq rest (assq nil (cdr form))) |
| 875 | (setq form (delq rest (copy-sequence form)))) | 949 | (setq form (remq rest form))) |
| 876 | (if (memq nil (cdr form)) | 950 | (setq form (remq nil form)) |
| 877 | (setq form (delq nil (copy-sequence form)))) | ||
| 878 | (setq rest form) | 951 | (setq rest form) |
| 879 | (while (setq rest (cdr rest)) | 952 | (while (setq rest (cdr rest)) |
| 880 | (cond ((byte-compile-trueconstp (car-safe (car rest))) | 953 | (cond ((byte-compile-trueconstp (car-safe (car rest))) |