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.el263
1 files changed, 219 insertions, 44 deletions
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 0b4043b1f2a..4a073a8e2e9 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -187,8 +187,8 @@
(eval-when-compile (require 'cl))
(defun byte-compile-log-lap-1 (format &rest args)
- (if (aref byte-code-vector 0)
- (error "The old version of the disassembler is loaded. Reload new-bytecomp as well"))
+;; (if (aref byte-code-vector 0)
+;; (error "The old version of the disassembler is loaded. Reload new-bytecomp as well"))
(byte-compile-log-1
(apply 'format format
(let (c a)
@@ -282,7 +282,8 @@
(byte-code ,string ,(aref fn 2) ,(aref fn 3)))
(cdr form)))
(if (eq (car-safe fn) 'lambda)
- (cons fn (cdr form))
+ (macroexpand-all (cons fn (cdr form))
+ byte-compile-macro-environment)
;; Give up on inlining.
form))))))
@@ -1335,14 +1336,15 @@
((>= op byte-constant)
(prog1 (- op byte-constant) ;offset in opcode
(setq op byte-constant)))
- ((and (>= op byte-constant2)
- (<= op byte-goto-if-not-nil-else-pop))
+ ((or (and (>= op byte-constant2)
+ (<= op byte-goto-if-not-nil-else-pop))
+ (= op byte-stack-set2))
(setq ptr (1+ ptr)) ;offset in next 2 bytes
(+ (aref bytes ptr)
(progn (setq ptr (1+ ptr))
(lsh (aref bytes ptr) 8))))
((and (>= op byte-listN)
- (<= op byte-insertN))
+ (<= op byte-discardN))
(setq ptr (1+ ptr)) ;offset in next byte
(aref bytes ptr))))
@@ -1403,7 +1405,16 @@
(if (= ptr (1- length))
(setq op nil)
(setq offset (or endtag (setq endtag (byte-compile-make-tag)))
- op 'byte-goto))))
+ op 'byte-goto)))
+ ((eq op 'byte-stack-set2)
+ (setq op 'byte-stack-set))
+ ((and (eq op 'byte-discardN) (>= offset #x80))
+ ;; The top bit of the operand for byte-discardN is a flag,
+ ;; saying whether the top-of-stack is preserved. In
+ ;; lapcode, we represent this by using a different opcode
+ ;; (with the flag removed from the operand).
+ (setq op 'byte-discardN-preserve-tos)
+ (setq offset (- offset #x80))))
;; lap = ( [ (pc . (op . arg)) ]* )
(setq lap (cons (cons optr (cons op (or offset 0)))
lap))
@@ -1459,7 +1470,7 @@
byte-cdr-safe byte-cons byte-list1 byte-list2 byte-point byte-point-max
byte-point-min byte-following-char byte-preceding-char
byte-current-column byte-eolp byte-eobp byte-bolp byte-bobp
- byte-current-buffer byte-interactive-p))
+ byte-current-buffer byte-interactive-p byte-stack-ref))
(defconst byte-compile-side-effect-free-ops
(nconc
@@ -1468,7 +1479,7 @@
byte-eqlsign byte-gtr byte-lss byte-leq byte-geq byte-diff byte-negate
byte-plus byte-max byte-min byte-mult byte-char-after byte-char-syntax
byte-buffer-substring byte-string= byte-string< byte-nthcdr byte-elt
- byte-member byte-assq byte-quo byte-rem)
+ byte-member byte-assq byte-quo byte-rem byte-vec-ref)
byte-compile-side-effect-and-error-free-ops))
;; This crock is because of the way DEFVAR_BOOL variables work.
@@ -1501,12 +1512,50 @@
;; The variable `byte-boolean-vars' is now primitive and updated
;; automatically by DEFVAR_BOOL.
+(defmacro byte-opt-update-stack-params (stack-adjust stack-depth lap0 rest lap)
+ "...macro used by byte-optimize-lapcode..."
+ `(progn
+ (byte-compile-log-lap "Before %s [depth = %s]" ,lap0 ,stack-depth)
+ (cond ((eq (car ,lap0) 'TAG)
+ ;; A tag can encode the expected stack depth.
+ (when (cddr ,lap0)
+ ;; First, check to see if our notion of the current stack
+ ;; depth agrees with this tag. We don't check at the
+ ;; beginning of the function, because the presence of
+ ;; lexical arguments means the first tag will have a
+ ;; non-zero offset.
+ (when (and (not (eq ,rest ,lap)) ; not at first insn
+ ,stack-depth ; not just after a goto
+ (not (= (cddr ,lap0) ,stack-depth)))
+ (error "Compiler error: optimizer is confused about %s:
+ %s != %s at lapcode %s" ',stack-depth (cddr ,lap0) ,stack-depth ,lap0))
+ ;; Now set out current depth from this tag
+ (setq ,stack-depth (cddr ,lap0)))
+ (setq ,stack-adjust 0))
+ ((memq (car ,lap0) '(byte-goto byte-return))
+ ;; These insns leave us in an unknown state
+ (setq ,stack-adjust nil))
+ ((car ,lap0)
+ ;; Not a no-op, set ,stack-adjust for lap0. ,stack-adjust will
+ ;; be added to ,stack-depth at the end of the loop, so any code
+ ;; that modifies the instruction sequence must adjust this too.
+ (setq ,stack-adjust
+ (byte-compile-stack-adjustment (car ,lap0) (cdr ,lap0)))))
+ (byte-compile-log-lap "Before %s [depth => %s, adj = %s]" ,lap0 ,stack-depth ,stack-adjust)
+ ))
+
(defun byte-optimize-lapcode (lap &optional for-effect)
"Simple peephole optimizer. LAP is both modified and returned.
If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(let (lap0
lap1
lap2
+ stack-adjust
+ stack-depth
+ (initial-stack-depth
+ (if (and lap (eq (car (car lap)) 'TAG))
+ (cdr (cdr (car lap)))
+ 0))
(keep-going 'first-time)
(add-depth 0)
rest tmp tmp2 tmp3
@@ -1517,12 +1566,15 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(or (eq keep-going 'first-time)
(byte-compile-log-lap " ---- next pass"))
(setq rest lap
+ stack-depth initial-stack-depth
keep-going nil)
(while rest
(setq lap0 (car rest)
lap1 (nth 1 rest)
lap2 (nth 2 rest))
+ (byte-opt-update-stack-params stack-adjust stack-depth lap0 rest lap)
+
;; You may notice that sequences like "dup varset discard" are
;; optimized but sequences like "dup varset TAG1: discard" are not.
;; You may be tempted to change this; resist that temptation.
@@ -1536,22 +1588,22 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
((and (eq 'byte-discard (car lap1))
(memq (car lap0) side-effect-free))
(setq keep-going t)
- (setq tmp (aref byte-stack+-info (symbol-value (car lap0))))
(setq rest (cdr rest))
- (cond ((= tmp 1)
+ (cond ((= stack-adjust 1)
(byte-compile-log-lap
" %s discard\t-->\t<deleted>" lap0)
(setq lap (delq lap0 (delq lap1 lap))))
- ((= tmp 0)
+ ((= stack-adjust 0)
(byte-compile-log-lap
" %s discard\t-->\t<deleted> discard" lap0)
(setq lap (delq lap0 lap)))
- ((= tmp -1)
+ ((= stack-adjust -1)
(byte-compile-log-lap
" %s discard\t-->\tdiscard discard" lap0)
(setcar lap0 'byte-discard)
(setcdr lap0 0))
- ((error "Optimizer error: too much on the stack"))))
+ ((error "Optimizer error: too much on the stack")))
+ (setq stack-adjust (1- stack-adjust)))
;;
;; goto*-X X: --> X:
;;
@@ -1576,10 +1628,14 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
;; const/dup varbind-X varref-X --> const/dup varbind-X const/dup
;; The latter two can enable other optimizations.
;;
- ((and (eq 'byte-varref (car lap2))
- (eq (cdr lap1) (cdr lap2))
- (memq (car lap1) '(byte-varset byte-varbind)))
- (if (and (setq tmp (memq (car (cdr lap2)) byte-boolean-vars))
+ ((or (and (eq 'byte-varref (car lap2))
+ (eq (cdr lap1) (cdr lap2))
+ (memq (car lap1) '(byte-varset byte-varbind)))
+ (and (eq (car lap2) 'byte-stack-ref)
+ (eq (car lap1) 'byte-stack-set)
+ (eq (cdr lap1) (cdr lap2))))
+ (if (and (eq 'byte-varref (car lap2))
+ (setq tmp (memq (car (cdr lap2)) byte-boolean-vars))
(not (eq (car lap0) 'byte-constant)))
nil
(setq keep-going t)
@@ -1611,10 +1667,11 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
;;
((and (eq 'byte-dup (car lap0))
(eq 'byte-discard (car lap2))
- (memq (car lap1) '(byte-varset byte-varbind)))
+ (memq (car lap1) '(byte-varset byte-varbind byte-stack-set byte-vec-set)))
(byte-compile-log-lap " dup %s discard\t-->\t%s" lap1 lap1)
(setq keep-going t
- rest (cdr rest))
+ rest (cdr rest)
+ stack-adjust -1)
(setq lap (delq lap0 (delq lap2 lap))))
;;
;; not goto-X-if-nil --> goto-X-if-non-nil
@@ -1636,7 +1693,8 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
'byte-goto-if-not-nil
'byte-goto-if-nil))
(setq lap (delq lap0 lap))
- (setq keep-going t))
+ (setq keep-going t
+ stack-adjust 0))
;;
;; goto-X-if-nil goto-Y X: --> goto-Y-if-non-nil X:
;; goto-X-if-non-nil goto-Y X: --> goto-Y-if-nil X:
@@ -1652,7 +1710,8 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(byte-compile-log-lap " %s %s %s:\t-->\t%s %s:"
lap0 lap1 lap2
(cons inverse (cdr lap1)) lap2)
- (setq lap (delq lap0 lap))
+ (setq lap (delq lap0 lap)
+ stack-adjust 0)
(setcar lap1 inverse)
(setq keep-going t)))
;;
@@ -1669,15 +1728,14 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(setq rest (cdr rest)
lap (delq lap0 (delq lap1 lap))))
(t
- (if (memq (car lap1) byte-goto-always-pop-ops)
- (progn
- (byte-compile-log-lap " %s %s\t-->\t%s"
- lap0 lap1 (cons 'byte-goto (cdr lap1)))
- (setq lap (delq lap0 lap)))
- (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1
- (cons 'byte-goto (cdr lap1))))
+ (byte-compile-log-lap " %s %s\t-->\t%s"
+ lap0 lap1
+ (cons 'byte-goto (cdr lap1)))
+ (when (memq (car lap1) byte-goto-always-pop-ops)
+ (setq lap (delq lap0 lap)))
(setcar lap1 'byte-goto)))
- (setq keep-going t))
+ (setq keep-going t
+ stack-adjust 0))
;;
;; varref-X varref-X --> varref-X dup
;; varref-X [dup ...] varref-X --> varref-X [dup ...] dup
@@ -1685,14 +1743,14 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
;; because that would inhibit some goto optimizations; we
;; optimize the const-X case after all other optimizations.
;;
- ((and (eq 'byte-varref (car lap0))
+ ((and (memq (car lap0) '(byte-varref byte-stack-ref))
(progn
- (setq tmp (cdr rest))
+ (setq tmp (cdr rest) tmp2 0)
(while (eq (car (car tmp)) 'byte-dup)
- (setq tmp (cdr tmp)))
+ (setq tmp (cdr tmp) tmp2 (1+ tmp2)))
t)
- (eq (cdr lap0) (cdr (car tmp)))
- (eq 'byte-varref (car (car tmp))))
+ (eq (car lap0) (car (car tmp)))
+ (eq (cdr lap0) (cdr (car tmp))))
(if (memq byte-optimize-log '(t byte))
(let ((str ""))
(setq tmp2 (cdr rest))
@@ -1704,7 +1762,8 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(setq keep-going t)
(setcar (car tmp) 'byte-dup)
(setcdr (car tmp) 0)
- (setq rest tmp))
+ (setq rest tmp
+ stack-adjust (+ 2 tmp2)))
;;
;; TAG1: TAG2: --> TAG1: <deleted>
;; (and other references to TAG2 are replaced with TAG1)
@@ -1771,7 +1830,8 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(byte-compile-log-lap " %s %s\t-->\t%s %s" lap0 lap1 lap1 lap0)
(setcar rest lap1)
(setcar (cdr rest) lap0)
- (setq keep-going t))
+ (setq keep-going t
+ stack-adjust 0))
;;
;; varbind-X unbind-N --> discard unbind-(N-1)
;; save-excursion unbind-N --> unbind-(N-1)
@@ -1797,6 +1857,14 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
""))
(setq keep-going t))
;;
+ ;; stack-ref-N --> dup ; where N is TOS
+ ;;
+ ((and (eq (car lap0) 'byte-stack-ref)
+ (= (cdr lap0) (1- stack-depth)))
+ (setcar lap0 'byte-dup)
+ (setcdr lap0 nil)
+ (setq keep-going t))
+ ;;
;; goto*-X ... X: goto-Y --> goto*-Y
;; goto-X ... X: return --> return
;;
@@ -1873,20 +1941,22 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(cdr tmp))))
(setcdr lap1 (car (cdr tmp)))
(setq lap (delq lap0 lap))))
- (setq keep-going t))
+ (setq keep-going t
+ stack-adjust 0))
;;
;; X: varref-Y ... varset-Y goto-X -->
;; X: varref-Y Z: ... dup varset-Y goto-Z
;; (varset-X goto-BACK, BACK: varref-X --> copy the varref down.)
;; (This is so usual for while loops that it is worth handling).
;;
- ((and (eq (car lap1) 'byte-varset)
+ ((and (memq (car lap1) '(byte-varset byte-stack-set))
(eq (car lap2) 'byte-goto)
(not (memq (cdr lap2) rest)) ;Backwards jump
(eq (car (car (setq tmp (cdr (memq (cdr lap2) lap)))))
- 'byte-varref)
+ (if (eq (car lap1) 'byte-varset) 'byte-varref 'byte-stack-ref))
(eq (cdr (car tmp)) (cdr lap1))
- (not (memq (car (cdr lap1)) byte-boolean-vars)))
+ (not (and (eq (car lap1) 'byte-varref)
+ (memq (car (cdr lap1)) byte-boolean-vars))))
;;(byte-compile-log-lap " Pulled %s to end of loop" (car tmp))
(let ((newtag (byte-compile-make-tag)))
(byte-compile-log-lap
@@ -1943,10 +2013,15 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
byte-goto-if-not-nil
byte-goto byte-goto))))
)
- (setq keep-going t))
+ (setq keep-going t
+ stack-adjust (and (not (eq (car lap0) 'byte-goto)) -1)))
)
+
+ (setq stack-depth
+ (and stack-depth stack-adjust (+ stack-depth stack-adjust)))
(setq rest (cdr rest)))
)
+
;; Cleanup stage:
;; Rebuild byte-compile-constants / byte-compile-variables.
;; Simple optimizations that would inhibit other optimizations if they
@@ -1954,10 +2029,13 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
;; need to do more than once.
(setq byte-compile-constants nil
byte-compile-variables nil)
- (setq rest lap)
+ (setq rest lap
+ stack-depth initial-stack-depth)
+ (byte-compile-log-lap " ---- final pass")
(while rest
(setq lap0 (car rest)
lap1 (nth 1 rest))
+ (byte-opt-update-stack-params stack-adjust stack-depth lap0 rest lap)
(if (memq (car lap0) byte-constref-ops)
(if (or (eq (car lap0) 'byte-constant)
(eq (car lap0) 'byte-constant2))
@@ -2004,11 +2082,108 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1
(cons 'byte-unbind
(+ (cdr lap0) (cdr lap1))))
- (setq keep-going t)
(setq lap (delq lap0 lap))
(setcdr lap1 (+ (cdr lap1) (cdr lap0))))
+
+ ;;
+ ;; stack-set-M [discard/discardN ...] --> discardN-preserve-tos
+ ;; stack-set-M [discard/discardN ...] --> discardN
+ ;;
+ ((and (eq (car lap0) 'byte-stack-set)
+ (memq (car lap1) '(byte-discard byte-discardN))
+ (progn
+ ;; See if enough discard operations follow to expose or
+ ;; destroy the value stored by the stack-set.
+ (setq tmp (cdr rest))
+ (setq tmp2 (- stack-depth 2 (cdr lap0)))
+ (setq tmp3 0)
+ (while (memq (car (car tmp)) '(byte-discard byte-discardN))
+ (if (eq (car (car tmp)) 'byte-discard)
+ (setq tmp3 (1+ tmp3))
+ (setq tmp3 (+ tmp3 (cdr (car tmp)))))
+ (setq tmp (cdr tmp)))
+ (>= tmp3 tmp2)))
+ ;; Do the optimization
+ (setq lap (delq lap0 lap))
+ (cond ((= tmp2 tmp3)
+ ;; The value stored is the new TOS, so pop one more value
+ ;; (to get rid of the old value) using the TOS-preserving
+ ;; discard operator.
+ (setcar lap1 'byte-discardN-preserve-tos)
+ (setcdr lap1 (1+ tmp3)))
+ (t
+ ;; Otherwise, the value stored is lost, so just use a
+ ;; normal discard.
+ (setcar lap1 'byte-discardN)
+ (setcdr lap1 tmp3)))
+ (setcdr (cdr rest) tmp)
+ (setq stack-adjust 0)
+ (byte-compile-log-lap " %s [discard/discardN]...\t-->\t%s"
+ lap0 lap1))
+
+ ;;
+ ;; discard/discardN/discardN-preserve-tos-X discard/discardN-Y -->
+ ;; discardN-(X+Y)
+ ;;
+ ((and (memq (car lap0)
+ '(byte-discard
+ byte-discardN
+ byte-discardN-preserve-tos))
+ (memq (car lap1) '(byte-discard byte-discardN)))
+ (setq lap (delq lap0 lap))
+ (byte-compile-log-lap
+ " %s %s\t-->\t(discardN %s)"
+ lap0 lap1
+ (+ (if (eq (car lap0) 'byte-discard) 1 (cdr lap0))
+ (if (eq (car lap1) 'byte-discard) 1 (cdr lap1))))
+ (setcdr lap1 (+ (if (eq (car lap0) 'byte-discard) 1 (cdr lap0))
+ (if (eq (car lap1) 'byte-discard) 1 (cdr lap1))))
+ (setcar lap1 'byte-discardN)
+ (setq stack-adjust 0))
+
+ ;;
+ ;; discardN-preserve-tos-X discardN-preserve-tos-Y -->
+ ;; discardN-preserve-tos-(X+Y)
+ ;;
+ ((and (eq (car lap0) 'byte-discardN-preserve-tos)
+ (eq (car lap1) 'byte-discardN-preserve-tos))
+ (setq lap (delq lap0 lap))
+ (setcdr lap1 (+ (cdr lap0) (cdr lap1)))
+ (setq stack-adjust 0)
+ (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 (car rest)))
+
+ ;;
+ ;; discardN-preserve-tos return --> return
+ ;; dup return --> return
+ ;; stack-set-N return --> return ; where N is TOS-1
+ ;;
+ ((and (eq (car lap1) 'byte-return)
+ (or (memq (car lap0) '(byte-discardN-preserve-tos byte-dup))
+ (and (eq (car lap0) 'byte-stack-set)
+ (= (cdr lap0) (- stack-depth 2)))))
+ ;; the byte-code interpreter will pop the stack for us, so
+ ;; we can just leave stuff on it
+ (setq lap (delq lap0 lap))
+ (setq stack-adjust 0)
+ (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 lap1))
+
+ ;;
+ ;; dup stack-set-N return --> return ; where N is TOS
+ ;;
+ ((and (eq (car lap0) 'byte-dup)
+ (eq (car lap1) 'byte-stack-set)
+ (eq (car (car (cdr (cdr rest)))) 'byte-return)
+ (= (cdr lap1) (1- stack-depth)))
+ (setq lap (delq lap0 (delq lap1 lap)))
+ (setq rest (cdr rest))
+ (setq stack-adjust 0)
+ (byte-compile-log-lap " dup %s return\t-->\treturn" lap1))
)
+
+ (setq stack-depth
+ (and stack-depth stack-adjust (+ stack-depth stack-adjust)))
(setq rest (cdr rest)))
+
(setq byte-compile-maxdepth (+ byte-compile-maxdepth add-depth)))
lap)