* module/language/tree-il/compile-glil.scm (flatten-lambda-case): Clear
lexical stack slots at the end of a non-tail let, letrec, or fix.
Fixes http://debbugs.gnu.org/9900.
* test-suite/tests/gc.test ("gc"): Add test.
* module/language/tree-il.scm (<tree-il>): Add `pre' and `post' fields
to <dynwind>, so that we can inline the guard bodies in the normal
control-flow case. It also avoids duplicating code in compile-glil,
which probably hides more bugs in 2.0.
(parse-tree-il, unparse-tree-il, tree-il->scheme, tree-il-fold)
(make-tree-il-folder, post-order!, pre-order!): Update.
* module/language/tree-il/analyze.scm (analyze-lexicals): Update.
* module/language/tree-il/compile-glil.scm (flatten-lambda-case): Update
to use `pre' and `post' instead of compiling code twice.
* module/language/tree-il/debug.scm (verify-tree-il): Update.
* module/language/tree-il/peval.scm (peval): Update. Instead of doing
complicated things in <dynwind>, handle 'dynamic-wind primcalls.
* module/language/tree-il/primitives.scm (*primitive-expand-table*):
Remove 'dynamic-wind mess. Adapt '@dynamic-wind.
* test-suite/tests/tree-il.test ("partial evaluation"): Update tests.
* module/language/tree-il/peval.scm (peval): The <dynwind> compiler will
copy the winder and unwinder values, so make sure that they are
constant, and if not, create lexical bindings. Fixes
http://debbugs.gnu.org/9844.
* test-suite/tests/tree-il.test ("partial evaluation"): Add a couple
<dynwind> tests.
* module/language/tree-il/peval.scm (peval): Since constant-expression?
is used to determine whether to copy values, return #f if any lexical
is assigned.
* module/language/tree-il/primitives.scm (resolve-primitives!): Don't
resolve toplevels defined in the same compilation unit to primitives,
as it could be that the module doesn't have those bindings yet.
* libguile/_scm.h (SCM_OBJCODE_MAJOR_VERSION): Bump the major version,
indicating the first incompatibility between 2.0 and 2.2.
* libguile/vm-i-scheme.c (string-length, string-ref, vector-length): New
instructions.
* module/language/tree-il/compile-glil.scm (*primcall-ops*): Add
primcall ops for the new instructions.
* module/language/tree-il/primitives.scm
(*interesting-primitive-names*, *effect-free-primitives*): Recognize
vector-length as an effect-free primitive.
* module/language/tree-il/primitives.scm (*primitive-expand-table*):
Remove a hack to compensate for the lack of a good inliner, now that
we do have a good inliner.
* module/language/tree-il/peval.scm (peval): Accessor primitives applied
to constants are pure if the call type-checks. Also, fold constants
in accessor primcalls.
* test-suite/tests/tree-il.test ("partial evaluation"): Fix the "yo"
test.
* module/language/tree-il/analyze.scm (analyze-lexicals): When stepping
into a non-tail form, we know that labels allocation will be invalid,
so use an empty labels set. Fixes http://debbugs.gnu.org/9769.
* test-suite/tests/tree-il.test ("labels allocation"): Add a test.
* module/language/tree-il/peval.scm (peval): Factor constant folding out
to a helper. Use it in the accessor case in addition to the normal
effect-free-primitive case.
* test-suite/tests/tree-il.test: Add a test.
* module/language/tree-il/peval.scm (peval): Add special handlers for
memq and memv, as inline.scm used to have. This is important for
`case' clauses. It is very ugly, though.
* test-suite/tests/tree-il.test ("partial evaluation"): Add tests.
* module/language/tree-il/primitives.scm (*primitive-accessors*): New
set of primitives: those that access mutable memory, but are otherwise
pure. Include bytevector references here.
(accessor-primitive?): New public predicate.
* module/language/tree-il/peval.scm (peval): Refactor to distinguish
constructor-primitive? from accessor-primitive?.
This commit changes to use <operand> structures to hold the context
needed to visit lexical bindings lazily, in context, instead of eagerly
visiting them for value. This laziness enables inlining of mutually
recursive bindings.
* module/language/tree-il/peval.scm (<var>): Remove comment about copy
propagation having to run build-var-table; things don't work like that
any more.
(build-var-table): Build <var> entries for all variables, even
unreferenced variables.
(alpha-rename): Remove. We will rename bindings on-demand now.
(peval lookup-var): New helper, to fetch the <var> of a gensym.
(peval fresh-gensyms): Fold here, under peval, and in it, handle
updating the store to record a mapping between new names and <var>
entries from the source program.
(peval record-source-expression): Don't call build-var-table on the
new expression, as alpha-renaming happens on-demand now.
(peval prune-bindings): Rewrite to work with mutually-recursive
bindings, while optionally preserving binding order.
(peval extend-env): New helper.
(peval loop): OK, here goes... Remove the `operand' context, as now we
visit operands lazily. Add a `call' context, which does not
copy-propagate lambda expressions, used to residualize a call after
aborting an inlining attempt. Change the `env' to be a mapping of
gensym to <operand>. Instead of looking up the operand's binding then
alpha-renaming it, just rely on the fact that visiting the operand
will rename it if necessary.
If we residualize a lexical, do so with the fresh name from the
environment. If we visit an operand and it doesn't turn out to be
constant, we will never be able to copy it, and so cache that fact in
the operand. If we residualize a binding and we know what the value
should be, record that binding so that prune-bindings won't have to
visit it again. If the operand folds to a constant, cache that too,
to save effort when unrolling loops.
For let, letrec, fix, and lambda-case, instead of visiting the
bindings eagerly for value, simply record the source expressions and
environments in an <operand> and rely on copy-propagation to visit
them later in the right context. In the case of letrec and fix, this
allows mutually-recursive bindings to be inlined.
Refactor folding of "constructors" (which still need renaming) to
avoid visiting operands twice in some contexts.
For applications, if we have to abort, process the procedure in call
context, which allows some folding but avoids copying lambdas. If we
find a recursive procedure, mark intervening counters as recursive
too, to allow for mutual recursion at the top level.
For lambdas, if we are processing for value, record the source
expression so we can detect recursion. This was previously done in
the lexical-ref copy propagator.
* test-suite/tests/tree-il.test ("partial evaluation"): Remove unused
recursive lexicals in a couple of cases. Add a couple test cases for
pruning. Add a few recursive binding cases.
This was a pretty big merge involving a fair amount of porting,
especially to peval and its tests. I did not update psyntax-pp.scm,
that comes in the next commit.
Conflicts:
module/ice-9/boot-9.scm
module/ice-9/psyntax-pp.scm
module/language/ecmascript/compile-tree-il.scm
module/language/tree-il.scm
module/language/tree-il/analyze.scm
module/language/tree-il/inline.scm
test-suite/tests/tree-il.test
* 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.