aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'lisp')
-rw-r--r--lisp/emacs-lisp/byte-opt.el175
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)))