summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp/byte-opt.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/emacs-lisp/byte-opt.el')
-rw-r--r--lisp/emacs-lisp/byte-opt.el72
1 files changed, 56 insertions, 16 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 937300cf0c0..4d39e28fc8e 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -410,7 +410,10 @@ for speeding up processing.")
(`(condition-case ,var ,exp . ,clauses)
`(,fn ,var ;Not evaluated.
- ,(byte-optimize-form exp for-effect)
+ ,(byte-optimize-form exp
+ (if (assq :success clauses)
+ (null var)
+ for-effect))
,@(mapcar (lambda (clause)
(let ((byte-optimize--lexvars
(and lexical-binding
@@ -755,7 +758,8 @@ for speeding up processing.")
((eq head 'list) (cdr form))
((memq head
;; FIXME: Replace this list with a function property?
- '( length safe-length cons lambda
+ '( lambda internal-make-closure
+ length safe-length cons
string unibyte-string make-string concat
format format-message
substring substring-no-properties string-replace
@@ -971,6 +975,43 @@ for speeding up processing.")
(t ;; Moving the constant to the end can enable some lapcode optimizations.
(list (car form) (nth 2 form) (nth 1 form)))))
+(defun byte-opt--nary-comparison (form)
+ "Optimise n-ary comparisons such as `=', `<' etc."
+ (let ((nargs (length (cdr form))))
+ (cond
+ ((= nargs 1)
+ `(progn (cadr form) t))
+ ((>= nargs 3)
+ ;; At least 3 arguments: transform to N-1 binary comparisons,
+ ;; since those have their own byte-ops which are particularly
+ ;; fast for fixnums.
+ (let* ((op (car form))
+ (bindings nil)
+ (rev-args nil))
+ (if (memq nil (mapcar #'macroexp-copyable-p (cddr form)))
+ ;; At least one arg beyond the first is non-constant non-variable:
+ ;; create temporaries for all args to guard against side-effects.
+ ;; The optimiser will eliminate trivial bindings later.
+ (let ((i 1))
+ (dolist (arg (cdr form))
+ (let ((var (make-symbol (format "arg%d" i))))
+ (push var rev-args)
+ (push (list var arg) bindings)
+ (setq i (1+ i)))))
+ ;; All args beyond the first are copyable: no temporary variables
+ ;; required.
+ (setq rev-args (reverse (cdr form))))
+ (let ((prev (car rev-args))
+ (exprs nil))
+ (dolist (arg (cdr rev-args))
+ (push (list op arg prev) exprs)
+ (setq prev arg))
+ (let ((and-expr (cons 'and exprs)))
+ (if bindings
+ (list 'let (nreverse bindings) and-expr)
+ and-expr)))))
+ (t form))))
+
(defun byte-optimize-constant-args (form)
(let ((ok t)
(rest (cdr form)))
@@ -1126,13 +1167,18 @@ See Info node `(elisp) Integer Basics'."
(put 'max 'byte-optimizer #'byte-optimize-min-max)
(put 'min 'byte-optimizer #'byte-optimize-min-max)
-(put '= 'byte-optimizer #'byte-optimize-binary-predicate)
(put 'eq 'byte-optimizer #'byte-optimize-eq)
(put 'eql 'byte-optimizer #'byte-optimize-equal)
(put 'equal 'byte-optimizer #'byte-optimize-equal)
(put 'string= 'byte-optimizer #'byte-optimize-binary-predicate)
(put 'string-equal 'byte-optimizer #'byte-optimize-binary-predicate)
+(put '= 'byte-optimizer #'byte-opt--nary-comparison)
+(put '< 'byte-optimizer #'byte-opt--nary-comparison)
+(put '<= 'byte-optimizer #'byte-opt--nary-comparison)
+(put '> 'byte-optimizer #'byte-opt--nary-comparison)
+(put '>= 'byte-optimizer #'byte-opt--nary-comparison)
+
(put 'string-greaterp 'byte-optimizer #'byte-optimize-string-greaterp)
(put 'string> 'byte-optimizer #'byte-optimize-string-greaterp)
@@ -1297,11 +1343,8 @@ See Info node `(elisp) Integer Basics'."
(if else
`(progn ,condition ,@else)
condition))
- ;; (if X nil t) -> (not X)
- ((and (eq then nil) (eq else '(t)))
- `(not ,condition))
- ;; (if X t [nil]) -> (not (not X))
- ((and (eq then t) (or (null else) (eq else '(nil))))
+ ;; (if X t) -> (not (not X))
+ ((and (eq then t) (null else))
`(not ,(byte-opt--negate condition)))
;; (if VAR VAR X...) -> (or VAR (progn X...))
((and (symbolp condition) (eq condition then))
@@ -1379,6 +1422,9 @@ See Info node `(elisp) Integer Basics'."
;; (apply F ... (list X Y ...)) -> (funcall F ... X Y ...)
((eq (car-safe last) 'list)
`(funcall ,fn ,@(butlast (cddr form)) ,@(cdr last)))
+ ;; (apply F ... (cons X Y)) -> (apply F ... X Y)
+ ((eq (car-safe last) 'cons)
+ (append (butlast form) (cdr last)))
(t form)))
form)))
@@ -2223,18 +2269,12 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
;;
;; goto ... --> goto <delete until TAG or end>
;; return ... --> return <delete until TAG or end>
- ;; (unless a jump-table is being used, where deleting may affect
- ;; other valid case bodies)
;;
((and (memq (car lap0) '(byte-goto byte-return))
- (not (memq (car lap1) '(TAG nil)))
- ;; FIXME: Instead of deferring simply when jump-tables are
- ;; being used, keep a list of tags used for switch tags and
- ;; use them instead (see `byte-compile-inline-lapcode').
- (not byte-compile-jump-tables))
+ (not (memq (car lap1) '(TAG nil))))
(setq tmp rest)
(let ((i 0)
- (opt-p (memq byte-optimize-log '(t lap)))
+ (opt-p (memq byte-optimize-log '(t byte)))
str deleted)
(while (and (setq tmp (cdr tmp))
(not (eq 'TAG (car (car tmp)))))