* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns)
(side-effect-and-error-free-fns)
(byte-compile-side-effect-and-error-free-ops)
(byte-compile-side-effect-free-ops):
Demote `equal` and `equal-including-properties` from error-free to
merely side-effect-free since they may in fact signal error on
circularity.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-equal, byte-optimize-eq):
Optimise (eq X X) -> t where X is a variable; idem for eql and equal.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
Add test case.
* lisp/emacs-lisp/byte-opt.el (byte-after-unwind-ops):
Cease sinking `eq` past `unwind`, because that optimised away the
let-binding in
(let ((symbols-with-pos-enabled nil))
(eq x y))
and `eq` is currently sensitive to `symbols-with-pos-enabled`.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp--eq-symbols-with-pos-enabled): New test.
* lisp/emacs-lisp/byte-opt.el (byte-opt--nary-comparison):
Fix a typo causing miscompilation of code such as (OP X),
where OP is <, >, <=, >= or =.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp-tests--test-cases): Add test case.
Reported by Richard Copley.
While at it, rework the code so as not to rely on an
intermediate rewriting of (funcall (lambda ..) ...)
to ((lambda ..) ...) since that forms is deprecated.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-funcall): Unfold lambdas
instead of turning them into the deprecated ((lambda ..) ..).
(byte-optimize-form-code-walker): Don't unfold ((lambda ..) ..) any more.
(byte-compile-inline-expand): Revert to non-optimized call if the unfolding
can't be optimized.
* lisp/emacs-lisp/bytecomp.el (byte-compile-form): Don't unfold
((lambda ..) ..) any more.
* lisp/emacs-lisp/cl-macs.el (cl--slet): Remove workaround.
* lisp/emacs-lisp/disass.el (disassemble): Make sure the code is
compiled with its own `lexical-binding` value.
* lisp/emacs-lisp/macroexp.el (macroexp--unfold-lambda): Make it work
both for ((lambda ..) ..) and for (funcall #'(lambda ..) ..).
Be careful not to move dynbound vars from `lambda` to `let`.
(macroexp--expand-all): Unfold (funcall #'(lambda ..) ..) instead of
turning it into ((lambda ..) ..). Don't unfold ((lambda ..) ..) any more.
Previously (+ X 0) was reduced to (+ X) which became (* X 1) in
codegen, but this is wrong for X = -0.0 and also slightly slower.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-plus): Don't reduce an
addition to (+ X) by eliminating zeros; retain one 0 argument.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
Add test case.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Optimise closed-over values in closure creation like any other, which
can lead to stack variables being eliminated.
* lisp/emacs-lisp/byte-opt.el (byte-optimize--substitutable-p):
Allow quoted lists and conses, and vector literals, to be substituted
from lexical variables. This can eliminate variable bindings and
create new constant folding opportunities.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
((closure ...) ...) is a malformed function call; treat it as such.
Better malformed function warning location.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-funcall): Don't convert
(funcall '(lambda ...) ...) -> ((lambda ...) ...)
because that would inline what is essentially an `eval` of a
function using dynamic binding rules into lexbound code.
Since the last cdr of a non-terminal argument to `nconc` is
overwritten no matter its value:
(nconc (cons 1 2) nil) => (1)
a terminating nil arg cannot just be eliminated unconditionally.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-nconc):
Only eliminate a terminal nil arg to `nconc` if preceded by
a nonempty proper list. Right now we only bother to prove this
for `(list ...)`, so that
(nconc (list 1 2 3) nil) -> (list 1 2 3)
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp-tests--test-cases): Add test cases.
Add the transforms:
(nconc) -> nil
(nconc X) -> X
and for arguments to `nconc`:
nil -> <elided>
(list X...) (list Y...) -> (list X... Y...)
(list X) Y -> (cons X Y)
* lisp/emacs-lisp/byte-opt.el (byte-optimize-nconc): New.
(byte-optimize-append): Fix minor flaws and generalise.
Move the warning about unused return values from calls to
side-effect-free functions from the source-level optimiser to the code
generator, where it can be unified with the special-purpose warning
about unused values from `mapcar`. This change also cures spurious
duplicate warnings about the same code, makes the warnings amenable to
suppression through `with-suppressed-warnings`, and now warns about
some unused values that weren't caught before.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Move warning away from here.
* lisp/emacs-lisp/byte-run.el (with-suppressed-warnings):
* lisp/emacs-lisp/bytecomp.el (byte-compile-warnings):
Doc string updates.
(byte-compile-form): Put the new warnings here.
(byte-compile-normal-call): Move mapcar warning away from here.
* lisp/emacs-lisp/bytecomp.el (byte-compile-ignore):
Compile args to `ignore` for value to avoid unused-value warnings, and
then discard the generated values immediately thereafter. Mostly this
does not affect the generated code but in rare cases it might result
in slightly worse code.
* test/lisp/emacs-lisp/bytecomp-tests.el
(bytecomp-test--with-suppressed-warnings): Adapt test.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Accept (stack-set 1) as equivalent to (discardN-preserve-tos 1) in a
rule previously overlooked. This is usually beneficial in code size
and almost always shortens dynamic paths.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
Use the current for-effect mode when optimising the body form,
instead of always optimising it for value.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
Add `format-message` and `substring-no-properties`.
* lisp/subr.el (number-sequence, copy-tree, looking-at-p)
(string-match-p, string-trim-right, string-lines):
Declare side-effect-free.
(syntax-class, version-list-<, version-list-=, version-list-<=)
(version-list-not-zero): Declare pure and side-effect-free.
(ensure-list): Declare side-effect-free and error-free.
(string-equal-ignore-case): Remove `pure` declaration.
We may want it to be pure but right now it's not.
This way we don't need to set these properties on aliases at all;
it was always easy to forget doing so.
* lisp/emacs-lisp/byte-opt.el (byte-opt--fget): New function.
(byte-optimize-form-code-walker, byte-optimize-form): Use it.
(side-effect-free-fns, side-effect-and-error-free-fns, pure-fns):
Remove aliases from lists, leaving only built-in functions.
Some Lisp functions still had their `side-effect-free` and `pure`
properties declared in byte-opt.el; do it at their definition instead.
The lists in byte-opt.el now only contain functions implemented in C
and function aliases.
* lisp/emacs-lisp/byte-opt.el (side-effect-free-fns)
(side-effect-and-error-free-fns, pure-fns):
Remove functions whose properties are now declared elsewhere
and some obsolete entries.
* lisp/custom.el (custom-variable-p):
* lisp/emacs-lisp/lisp.el (buffer-end):
* lisp/emacs-lisp/regexp-opt.el (regexp-opt):
* lisp/env.el (getenv):
* lisp/simple.el (count-lines, mark, string-empty-p, lax-plist-get):
* lisp/subr.el (ignore, always, zerop, fixnump, bignump, lsh, last)
(eventp, mouse-movement-p, log10, memory-limit, string-greaterp)
(interactive-p):
* lisp/window.el (get-lru-window, get-largest-window, (window-edges)
(window-body-edges, window-pixel-edges, window-body-pixel-edges)
(window-absolute-pixel-edges, window-absolute-body-pixel-edges)
(one-window-p):
Declare functions `side-effect-free` and/or `pure` as appropriate.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Fix a flaw in the
dup (varset|varbind|stack-set) discard -> (varset|varbind|stack-set)
rule: don't match stack-set(1) which is dealt with elsewhere, and
generalise to discard(N).
Hoisting stack reduction ops allows them to coalesce and/or cancel out
pushing ops, and for useful operations to sink and combine, such as
not + goto-if-[not-]nil.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Add the rule
UNARY discardN-preserve-tos --> discardN-preserve-tos UNARY
where UNARY pops and pushes one value.
Generalise the rule
const discardN-preserve-tos --> discardN const
to any 0-ary op, not just const: varref, point, etc.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Make the improvements:
- Add the rule
stack-ref(X) discardN-preserve-tos(Y)
--> discard(Y) stack-ref(X-Y), X≥Y
discard(X) discardN-preserve-tos(Y-X-1), X<Y
with the usual equivalences:
stack-set(1) = discardN-preserve-tos(1)
stack-ref(0) = dup
discard(0) = discardN-preserve-tos(0) = no-op
This rule hoists stack reduction to where it is more likely to be
exploited further, may reduce the op size through smaller
immediates, and sometimes removes either or both operations
outright.
The rule is inhibited by an immediately following `return` op
because other rules will produce better code in that case.
- Add the rule
(discardN-preserve-tos|dup) OP return --> OP return
where OP is a unary operation such as `not` or `car`.
- Generalise a previous rule to
NOEFFECT PRODUCER return --> PRODUCER return
where PRODUCER is now any op that pushes a value without looking at
the stack: const, varref, point etc.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-concat):
Flatten nested forms; concat is associative. This reduces the number
of calls and may coalesce adjacent constant strings.
* lisp/emacs-lisp/byte-opt.el (byte-optimize-constant-args): Simplify.
(byte-optimize--constant-symbol-p): Speed up.
(byteopt--eval-const): New.
(byte-optimize-member, byte-optimize-concat, byte-optimize-append):
Use byteopt--eval-const instead of eval which is much slower.
* lisp/emacs-lisp/byte-opt.el (byte-after-unbind-ops):
Add discardN and discardN-preserve-tos, both of which
commute with unbind. This enables subsequent optimisations.
* 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))