Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add a higher-level IL to use as a target for source2il #21

Merged
merged 25 commits into from
Sep 5, 2024

Conversation

zerbina
Copy link
Collaborator

@zerbina zerbina commented Aug 30, 2024

Summary

Add the L10 intermediate language, which is the first IL not
structured around basic blocks (i.e., continuations). The pass10
pass lowers it into the L4 language.

Details

Motivation

Directly translating the source language into a language with explicit
basic blocks is hard. L10 is intended to bridge the gap between the
source language and L4.

Language

The name L10 is chosen so that there's still space for more ILs. It
does away with the basic-block centered structure, instead providing
higher- level control-flow constructs such as if, case, and
loop.

A try/except like facility is currently missing, meaning that
exception handling (where Raise is used) cannot be expressed.

Some way to delimit lifetimes of locals is also missing. Locals are
currently treated as being alive for the whole duration, which can lead
to locals that have their address taken being kept alive longer than
necessary.

Apart from the new control-flow constructs, L10 stays close to L4,
so that the lowering can focus on the splitting the procedure into
basic blocks.


To-Do

  • improve the tests (mainly the documentation)
  • make the t01_loop test work
  • look into improving "pinned local" handling
  • write a proper commit message

Notes For Reviewers

  • a try/except like facility can be added later on with ease
  • for a scoping / lifetime delimiting facility, I think it makes sense to wait until the source language requirements become clearer

`spec` is updated too.
It covers everything relevant to the lowering pass (unless I missed
something). The output uses a shorter formatting that doesn't match
what `pretty` produces -- a separate change for supporting S-expr
normalization in the tester will be necessary.
It's fully functional (according to the test suite), though not very
optimized, both in terms of output it produces and how it does so.
It's a run-of-the-mill test runner. Given the repetition, common parts
of the test runners should move into a separate module at one point.
The necessary runner support for disabling execution is still missing,
and the test would only result in an infinite loop.
@zerbina zerbina added the enhancement New feature or request label Aug 30, 2024
The result stays the same, but how one gets there changes.

There are no "implicit parameter", only "implicit arguments". Attaching
the implicitness to the callee (i.e., target block) rather than the
caller (i.e., block exit) precludes some future optimizations, such as
merging basic blocks, in addition to just being wrong conceptually.
Only loops are iterated twice now, greatly reducing the time the pass
takes when there are no loops. Further optimizations are possible, such
as not following the back edge when there are no changes, but are not
implemented yet.

The documentation is also improved a bit.
A single-block `Loop` resulted in the forward propagation pass getting
stuck.
The test runner now supports the `--compileOnly` argument, which
disables validation and execution of the produced VM bytecode.
Pinned locals are now only passed through to blocks/continuations that
perform an indirect memory access.
Procedure parameters must unconditionally be registered with the first
basic block.
Some of the pinned local tests trigger an illegal access error at run-
time, which is fine.
The new name more accurately describes which locals the set contains.
Some `.expected` files were not marked as storing S-expressions.
@zerbina zerbina marked this pull request as ready for review September 3, 2024 23:16
(Continuation (Params) (Locals)
(Continue 1 (List)))
(Continuation (Params) (Locals)
(Drop (IntVal 100))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for what is undoubtedly a silly question, but I checked out what opcDrop does and I can't figure out why we want a <value> operand for the op code, it seems unused. Is the idea that in the future it'll be possible to specify the number of items, or the address (?), we want to drop?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opcDrop pops and discard the last operand from the operand stack, it's purpose is to remove operand from the stack without having to assign them to a dummy local. The Drop operation has the same role as discard, that is, it evaluates the operand but discards the result.

(Drop (IntVal 100)) just means "discard the integer value 100". I've used it as form of "marker", since it's a simple, short, and side-effect-free statement. The idea is to us them to make sure that statements are placed correctly in the continuations after splitting up the statement list(s).

Copy link
Contributor

@saem saem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One very minor suggestion, but g2g.

tests/pass10/t03_ssa_join_2.test Outdated Show resolved Hide resolved
Co-authored-by: Saem Ghani <[email protected]>
@zerbina zerbina merged commit 47e1dda into nim-works:main Sep 5, 2024
5 checks passed
@zerbina zerbina deleted the implement-il-10 branch September 5, 2024 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants