* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Remove code forcing forward motion after applying certain
transformations; these were only there to keep output identical across
refactorings.
This is a refactoring step: there is no change in how the optimiser
works.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Instead of re-using local variables through mutation, bind them at
point of use. This ensures that there is no value leakage by mistake
and actually reduces the static size of the bytecode of this function
somewhat.
The lousy variable names (tmp, tmp2 etc) are retained but
can at least now be changed into something more descriptive.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Instead of using the O(n) `delq' to remove single instructions, use
the O(1) `setcdr'. To do this, anchor the instruction list in a cons
cell and use the predecessor cell in iteration.
- Since discardN-preserve-tos(1) and stack-set(1) have the same
effect, treat them as equivalent in all transformations.
- Move the rule
discardN-preserve-tos(X) discardN-preserve-tos(Y)
--> discardN-preserve-tos(X+Y)
from the final pass to the main iteration since it may enable
further optimisations.
- Don't apply the rule
goto(X) ... X: DISCARD --> DISCARD goto(Y) ... X: DISCARD Y:
when DISCARD could be merged or deleted instead, which is even better.
- Add the rule
OP const return -> <deleted> const return
where OP is effect-free.
- Generalise the push-pop annihilation rule to
PUSH(K) discard(N) -> discard(N-K), N>K
PUSH(K) discard(N) -> <deleted>, N=K
to any N, not just N=1.
- Add the rule
OP goto(X) Y: OP X: -> <deleted> Y: OP X:
for any operation OP.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Make the changes described above.
Make `byte-compile-log-lap` more robust and produce nicer output.
This is of interest for Elisp compiler maintainers only.
* lisp/emacs-lisp/byte-opt.el (bytecomp--log-lap-arg): New.
(byte-compile-log-lap-1): Extract argument conversion and rewrite
in a more modern way, fixing bugs. In particular, tags are now
displayed as "X:" where X is the tag number, and that tag number
is shown as argument to goto-like ops.
(byte-optimize-lapcode): Clean up and simplify logging, producing
useful information when `byte-optimize-log` is `byte` as intended.
Transform n-ary comparisons to a chain of binary comparisons in the
Lisp optimiser instead of in codegen, to allow for subsequent
optimisations. This generalises the transform, so that
(< 1 X 10) -> (let ((x X)) (and (< 1 x) (< x 10)))
where (< 1 x) is then flipped to (> x 1) in codegen since it's
slightly more efficient to have the constant argument last. Arguments
that are neither constants nor variables are given temporary bindings.
This results in about 2× speedup for 3-ary comparisons of fixnums with
nontrivial arguments, and also improves the code slightly for binary
comparisons with a constant first argument.
* lisp/emacs-lisp/byte-opt.el (byte-opt--nary-comparison): New,
set as the `byte-optimizer` property for =, <, <=, >, and >=.
* lisp/emacs-lisp/bytecomp.el (byte-compile-and-folded):
Rename to...
(byte-compile-cmp): ...and rewrite.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Allow removal of unreachable basic blocks in the LAP peephole
optimiser even when switch ops are present. The origins of
this apparently unnecessary condition are unclear.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-apply): Transform
(apply F ... (cons X Y)) -> (apply F ... X Y)
This pattern is seen both in hand-written code and in backquote
expansions.
cae528457c ; Add 2023 to copyright years.
b394359261 Improve documentation of 'isearch-open-overlay-temporary'
ab3210e709 Document 'use-package' in the 2 main manuals
# Conflicts:
# etc/refcards/ru-refcard.tex
# lib/explicit_bzero.c
# m4/explicit_bzero.m4
(condition-case x A (:success B)) should not compile A for-effect even
if the entire form is in for-effect context.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Don't optimise the condition-case body form for effect (potentially
discarding its value) if there is a success handler and a variable.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
Add test cases.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-if):
Remove explicit clauses purposing to simplify
(if X nil t) -> (not X)
(if X t nil) -> (not (not X))
but never did so because of a coding mistake (eq instead of equal),
found by a recently added warning. They weren't actually needed
thanks to the optimiser's fixpoint iteration: we eventually get the
same results through
(if X nil t) -> (if (not X) t nil) -> (if (not X) t) -> (not X)
(if X t nil) -> (if X t) -> (not (not X))
* lisp/emacs-lisp/byte-opt.el (byte-optimize-if):
Remove explicit clauses purposing to simplify
(if X nil t) -> (not X)
(if X t nil) -> (not (not X))
but never did so because of a coding mistake (eq instead of equal),
found by a recently added warning. They weren't actually needed
thanks to the optimiser's fixpoint iteration: we eventually get the
same results through
(if X nil t) -> (if (not X) t nil) -> (if (not X) t) -> (not X)
(if X t nil) -> (if X t) -> (not (not X))
* lisp/emacs-lisp/byte-opt.el (byte-optimize-if):
Remove explicit clauses purposing to simplify
(if X nil t) -> (not X)
(if X t nil) -> (not (not X))
but never did so because of a coding mistake (eq instead of equal),
found by a recently added warning. They weren't actually needed
thanks to the optimiser's fixpoint iteration: we eventually get the
same results through
(if X nil t) -> (if (not X) t nil) -> (if (not X) t) -> (not X)
(if X t nil) -> (if X t) -> (not (not X))
* lisp/emacs-lisp/byte-opt.el (byte-opt--bool-value-form):
`set` is boolean identity in its second argument.
(byte-compile-trueconstp): `set-marker` is always true.
Only perform the rewrite
(set 'VAR X) -> (setq VAR X)
for dynamic variables, as `set` isn't supposed to affect
lexical vars (and never does so when interpreted).
* lisp/emacs-lisp/byte-opt.el (byte-optimize-set):
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--xx): New.
(bytecomp-tests--test-cases): Add test cases.
* test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el:
Remove obsolete test.
For a switch op to be generated, comparisons must be made using `eq`,
`eql` or `equal`, not `=`.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
* lisp/files.el (file-modes-char-to-who, file-modes-char-to-right):
* lisp/international/titdic-cnv.el (tit-process-header):
* lisp/language/ethio-util.el (ethio-input-special-character)
(ethio-fidel-to-tex-buffer):
* lisp/language/lao.el (consonant):
Use `eq` or `eql` instead of `=`.
In these cases either `eq` or `eql` would do and the choice does not
affect the resulting code. We compare numbers with `eql` and
characters with `eq` as a matter of style.
* lisp/emacs-lisp/byte-opt.el (byte-opt--bool-value-form):
Recognise boolean identity in aset, put, function-put and puthash.
* lisp/emacs-lisp/byte-opt.el (byte-compile-trueconstp):
Mark more functins as non-nil-returning, including the new
pos-bol and pos-eol.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
Mark pos-bol and pos-eol as side-effect-free.
This change was partially generated and mechanically cross-validated
with function type information from comp-known-type-specifiers in
comp.el.
* lisp/emacs-lisp/byte-opt.el (byte-compile-trueconstp):
Extend list of functions and fix a typo (logxor).
* lisp/emacs-lisp/byte-opt.el (byte-optimize-and, byte-optimize-or):
Rewrite. Avoid branching on arguments statically known to be true or
false, and hoist code out to an unconditional prefix when possible.
Recognise some more special cases:
(if X nil t) -> (not X)
(if X t) -> (not (not X))
(if X t nil) -> (not (not X))
(if VAR VAR X...) -> (or VAR (progn X...))
* lisp/emacs-lisp/byte-opt.el (byte-opt-negate): New.
(byte-optimize-if): Add transformations above and refactor.
(byte-optimize-while): Better static nil-detection.
* lisp/emacs-lisp/byte-opt.el (byte-opt--bool-value-form): New.
(byte-compile-trueconstp, byte-compile-nilconstp): Determine a static
nil or non-nil result in more cases. These functions have grown and
are no longer defsubst.
Extend the set of eligible opcodes for certain peephole
transformations, which then provide further optimisation
opportunities.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Optimise empty save-current-buffer in the same way as we already
do for save-excursion and save-restriction. This is safe
because (save-current-buffer) is a no-op.
(byte-compile-side-effect-and-error-free-ops): Add list3, list4 and
listN. These were all apparent oversights as list1 and list2 were
already included.
(byte-after-unbind-ops): Add stack-ref, stack-set, discard, list3,
list4 and listN. Stack manipulation is safe because unbind cannot
read or modify stack entries.
This variable and related functions have been obsolete since 23.1.
The last things to depend on this (fast-lock.el and lazy-lock.el) were
recently removed.
* src/dispextern.h (struct it): Delete field
'redisplay_end_trigger_charpos'.
* src/window.c (Fwindow_redisplay_end_trigger)
(Fset_window_redisplay_end_trigger): Delete defuns and corresponding
defsubrs for functions obsolete since 23.1.
* src/window.h (wset_redisplay_end_trigger): Delete function.
(GCALIGNED_STRUCT): Delete 'redisplay_end_trigger'.
* src/xdisp.c (run_redisplay_end_trigger_hook): Delete function.
(syms_of_xdisp) <redisplay_end_trigger_functions>: Delete
variable obsolete since 23.1.
(init_iterator, next_element_from_buffer): Don't run or set above
deleted hook variable.
* lisp/subr.el: Delete obsoletion definitions for above deleted
defuns and variable.
* doc/lispref/hooks.texi (Standard Hooks):
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
* lisp/loadhist.el (unload-feature-special-hooks): Don't mention
above deleted variable.
* admin/coccinelle/window.cocci: Adjust for above changes.
This optimisation is already done in the code generator but performing
it at this earlier stage is a useful normalising step that uncovers
more opportunities.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-list): New.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Turn functions into nil when compiled for-effect since they have no
side-effects on their own. This may enable further improvements such
as the elimination of variable bindings.
`unwind-protect` forms can be treated as plain function call at this
point. In particular, their unwind function argument should be
not optimised for effect since it's a function.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker)
(byte-optimize-let-form, byte-optimize-letX):
* lisp/emacs-lisp/bytecomp.el (byte-compile-unwind-protect):
Simplify source optimisation and codegen code that can now rely on
normalised let/let* and unwind-protect forms.
Early normalisation of setq during macroexpand-all allows later
stages, cconv, byte-opt and codegen, to be simplified and duplicated
checks to be eliminated.
* lisp/emacs-lisp/macroexp.el (macroexp--expand-all):
Normalise all setq forms to a sequence of (setq VAR EXPR).
Emit warnings if necessary.
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv-analyze-form):
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
* lisp/emacs-lisp/bytecomp.el (byte-compile-setq):
Simplify.
* test/lisp/emacs-lisp/bytecomp-tests.el: Adapt and add tests.
* test/lisp/emacs-lisp/bytecomp-resources/warn-variable-setq-nonvariable.el;
* test/lisp/emacs-lisp/bytecomp-resources/warn-variable-setq-odd.el:
New files.