* module/language/tree-il.scm (pre-order): Re-implement in terms of
pre-post-order, and rename from pre-order!.
* module/language/tree-il/primitives.scm (expand-primitives): Adapt to
pre-order change, and rename from expand-primitives!.
* module/language/tree-il/optimize.scm (optimize): Adapt to
expand-primitives! change, and rename from optimize!.
* module/language/tree-il/compile-glil.scm:
* module/system/repl/common.scm:
* test-suite/tests/cse.test:
* test-suite/tests/peval.test:
* test-suite/tests/tree-il.test: Adapt to expand-primitives and optimize
changes.
* module/language/tree-il.scm (pre-post-order): New helper, like
pre-order! and post-order! but not destructive.
(post-order): Implement in terms of pre-post-order, and rename from
post-order!.
* module/ice-9/compile-psyntax.scm (squeeze-tree-il):
* module/language/tree-il/canonicalize.scm (canonicalize):
* module/language/tree-il/fix-letrec.scm (fix-letrec):
* module/language/tree-il/primitives.scm (resolve-primitives): Use
post-order, and rename from the destructive
variants (squeeze-tree-il!, canonicalize!, etc). Adapt callers.
* test-suite/tests/tree-il.test (strip-source): Adapt to post-order.
* test-suite/tests/cse.test:
* test-suite/tests/peval.test:
* module/language/tree-il/optimize.scm: Adapt callers.
* module/language/tree-il/peval.scm: Move to its own file. Remove the
bits about <prompt> thunk-application bodies, as they are not
optimizations, simply expectations of the compiler. `canonicalize'
handles that now.
* module/language/tree-il/optimize.scm: Use peval from its module.
Don't call `inline!', as that's useless now.
* module/language/tree-il/canonicalize.scm: New file, implementing a
pass that `compile-tree-il' runs on the result from the optimizer.
The compiler currently expects a <let> form to have bindings, for
example, and this pass turns a <let> without bindings into its body.
* module/language/tree-il/inline.scm: Deprecate, as `peval' does
everything this function ever did.
* module/language/tree-il/compile-glil.scm: Canonicalize after
optimizing. This should allow us to skip the optimizer entirely, if
we want.
* module/Makefile.am: Update and reorder a little bit.
* module/language/tree-il/optimize.scm (peval): If it's a lambda in the
operator position, inline without a nested counter, as it's not
possible to increase code size.
* module/language/tree-il/optimize.scm (peval): Factor prune-bindings
out of `let' and company. Have it process unreferenced bindings in
effect context instead of always residualizing non-constant
expressions.
* module/language/tree-il/optimize.scm (types-check?): New helper, to
determine if a primcall will apply without throwing an exception.
(peval): constant-expression? returns #f for expressions that don't
types-check?. Effect-free primitives that type-check are void.
* module/language/tree-il/optimize.scm (alpha-rename, peval): Add
<dynset> cases. Allow any kind of <application>. Remove the `catch'
wrapper as now peval handles all kinds of expressions.
* module/language/tree-il/optimize.scm (peval): Fix a duplicate
traversal for constructors in effect or test context. Add support for
eliding make-prompt-tag.
* test-suite/tests/tree-il.test ("partial evaluation"): Update the test
for make-prompt-tag elision.
* module/language/tree-il/optimize.scm (alpha-rename, peval): Handle
<prompt> and <abort>. Attempt to remove the prompt if the tag is
otherwise unreferenced.
* module/language/tree-il/primitives.scm (*primitive-constructors*): Add
make-prompt-tag as a constructor.
* test-suite/tests/tree-il.test ("partial evaluation"): Add a test that
an prompt whose tag is unreferenced is removed.
* module/language/tree-il/optimize.scm (peval): Fix treatment of `cons'
to not process the value twice, leading to n^2 work. This prevented
primitives.scm from compiling in a reasonable amount of time, because
it contained a `(foo ... ,@bar) form that resulted in a long sequence
of nested conses, and no effort counter was in place as it was not
within an inlining attempt.
* module/language/tree-il/optimize.scm (transfer!, make-nested-counter):
(make-recursive-counter, peval): Limit the algorithm's time to be
strictly O(N) by transferring effort and size counters of recursive
inlining attempts from containing counters.
* test-suite/tests/tree-il.test ("partial evaluation"): Update
expectations for the ((lambda (x) (x x)) (lambda (x) (x x))) case, as
the new accounting policy will cause the entire inlining attempt to
abort.
* module/language/tree-il/optimize.scm (peval): Fix calculation of how
many init expressions to drop when inlining lambdas.
* test-suite/tests/tree-il.test ("partial evaluation"): Add tests.
* module/language/tree-il/optimize.scm (peval): The old approach of
optimistically producing constants and then de-constifying them at
their uses was not only cumbersome but incorrect: it both failed to
preserve identity in some cases and failed to retain immutable
constant values. Instead, now we only produce constants if they
really are constant and immutable. The constant folder has to have a
few more algebraic cases to be as effective as it was, to destructure
(car (cons _ _)) appropriately. On the plus side, now constructors
and deconstructors can handle impure cases more generally.
* test-suite/tests/tree-il.test ("partial evaluation"): Add constructor
and destructuring tests. Adapt other tests to new expectations.
* module/language/tree-il/optimize.scm (peval): Add missing
maybe-unconst calls. Things are getting ugly. They will get better
in the next commit though.
* module/language/tree-il/optimize.scm (code-contains-calls?): Remove
this helper, we will deal with recursion when it happens, not after
the fact.
(peval): Add keyword args for various size and effort limits. Instead
of keeping a call stack, keep a chain of <counter> records, each with
an abort continuation. If ever an inlining attempt is taking too
long, measured in terms of number of trips through the main loop, the
counter will abort. Add new contexts, `operator' and `operand'. They
have different default size limits. In the future we should actually
use the size counter, instead of these heuristics.
The <lexical-ref> case is smarter now, and tries to avoid propagating
too much data. Perhaps it should be dumber though, and use a
counter. That would require changes to the environment structure.
Inline <lambda> applications to <let>, so that we allow residual
lexical references to have bindings. Add a `for-operand' helper, and
use it for the RHS of `let' expressions. A `let' is an inlined
`lambda'.
`Let' and company no longer elide bindings if the result is a
constant, as the arguments could have effects. Peval will still do as
much as it can, though.
* test-suite/tests/tree-il.test ("partial evaluation"): Update the tests
for the new expectations. They are uniformly awesomer, with the
exception of two cases in which pure but not constant data is not
propagated.
* module/language/tree-il/optimize.scm (peval): Rename `var-table' to
`store', as we're going to put some more things in it. Rename
`record-lexical-bindings' to `record-source-expression', which also
takes the original, pre-renaming expression. Keep a mapping from new
expressions to original expressions, available using the
`source-expression' helper.
* module/language/tree-il/optimize.scm (<counter>, abort-counter)
(record-effort!, record-size!, find-counter, make-top-counter)
(make-nested-counter, make-recursive-counter): New helpers, as yet
unused, but which will implement fixed effort bounds on the inlining
algorithm.
* module/language/tree-il/optimize.scm (peval): Rename `record-lexicals'
to `record-lexical-bindings'. Record residualized lexical
references. Record lexical references in maybe-unlambda.
Unfortunately this has the disadvantage that the speculative mapping
of lambda expressions to lexical references records that reference,
even if we are not going to residualize it. After processing a `let',
prune pure unreferenced bindings. (We can do better than this in the
future: we can simply process them for effect.)
* test-suite/tests/tree-il.test (pass-if-peval): More debugging.
("partial evaluation"): Update to reflect the fact that the `y'
binding won't be emitted.
* module/language/tree-il/optimize.scm (alpha-rename, peval): Add
support for lexical-set, while avoiding copy propagation and pruning
of assigned variables.
* module/language/tree-il/optimize.scm (<var>, build-var-table, peval):
Before going into peval, build a table indicating refcounts and a set?
flag for all lexicals. Add to the table when introducing new bindings
(via alpha-renaming).
* module/language/tree-il/optimize.scm (peval): Rename
`pure-expression?' to `constant-expression?', in the sense of GCC's
`pure' and `const'. A <toplevel-ref> is not constant, because it can
be mutated. A <dynref> isn't constant either, for the same reason.
* test-suite/tests/tree-il.test ("partial evaluation"): Add a test, and
update existing tests that assumed that toplevel-ref would propagate.
* module/language/tree-il/optimize.scm (peval): Add a "test" context,
which folds statically decidable values to <const>. Fold pure
expressions to <void> in "effect" contexts. Adapt the <conditional>
and <sequence> tests to simply look for <const> or <void> expressions,
respectively.
* module/language/tree-il/optimize.scm (alpha-rename): Rename the
init
expressions of a <lambda-case>.
(peval): Coalesce the <let-values> clauses.
Fix pure-expression? matching of <lambda> clauses.
Loop over and maybe-unconst the inits of a <lambda-case>.
* module/language/tree-il/optimize.scm (peval): Rename `src' to
`lv-src', and `src2' to `src'; pass `make-let-values' the right source
locations. Reindent `let*'.
* module/language/tree-il/optimize.scm (peval): Fix comment regarding
alpha-renaming: it's not simply the allocator that needs unique names;
rather, all transformations depend on it.
* module/language/tree-il/optimize.scm (fresh-gensyms): New helper.
(alpha-rename): Name the new gensyms using the old names as templates,
not the old gensyms. This prevents accidental collisions between
gensyms, if #{x 1}# becomes #{x 12}# instead of #{x 2}#.
* module/language/tree-il/optimize.scm (peval): Add support for
let-values. Try to inline the consumer into the body of the producer,
if there is only one return point, and we can figure out how many
values are being returned, and that number is compatible with the
consumer.
* module/language/tree-il/optimize.scm (peval): Add support for fix,
dynwind, dynlet, dynref, module-set, and toplevel-set. (Mutating a
variable directly is similar to calling a function that does so behind
our backs, so this presents no additional problem.)
* module/language/tree-il/optimize.scm (code-contains-calls?): New
procedure.
(peval): Use it and abort inlining if the residual code of a procedure
application contains recursive calls. Suggested by Wingo, Waddell,
and Dybvig. Fixes <http://debbugs.gnu.org/9542>.
* test-suite/tests/tree-il.test ("partial evaluation"): Update 2 tests
that relied on the previous behavior. Add 1 another test.
* module/language/tree-il/optimize.scm (peval)[maybe-unlambda]: New
procedures.
Use it to de-duplicate named lambdas. This fixes the scoping bug
described at <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html>.
* test-suite/tests/tree-il.test ("partial evaluation"): Add tests to
reproduce the bug.