nim-works / phy

compiler and vm experiments
MIT License
3 stars 2 forks source link

add an IL with self-contained continuations #19

Closed zerbina closed 2 months ago

zerbina commented 2 months ago

Summary

Add an intermediate language extending L3 where values must be passed explicitly between local continuations.

Details

The IL is aimed at providing all information necessary for register allocation in an efficient to process format.

pass4 is responsible for allocating and assigning registers (which are just locals in L3) to Continuation locals and parameters, turning moves into either renames or copies, the former being preferred.

Language Changes

Other Changes


To-Do

zerbina commented 2 months ago

Two observations I made while implementing the pass/IL:

zerbina commented 2 months ago

Okay, so the register allocation works properly now. The main goal for the current algorithm was that it should be simple yet still produced reasonably good results, and I think I was able to achieve both.

I've also made a few changes to the IL:

When reading the tests, do keep in mind that they're contrived -- in a normal setting (i.e., when the IL code comes from source code), no code where locals are spawned and passed between continuations without ever being written to or read from would be produced.

zerbina commented 2 months ago

As can be seen in t02_different_types.test, due to the three different types, the locals all map to separate registers, even though they all use the same register type underneath (there's only a single integer type in the VM).

More broadly speaking, the different current and future target languages have different capabilities regarding integers:

My plan here is to introduce a lowering pass (happening before pass4) that changes the types of all integer locals into ones that are supported by the target language, together with injecting masking and sign extension operations where necessary for the correct behaviour.

For example:

var n = 0'u8
n = n + 1 

would become:

var n: int = 0
n = (n + 1) and 0xFF

which is equivalent to what pass0 already does.

Beyond allowing reusing the same registers for the various integer types, lowering integers and integer operations early also means that the bit masking is visible to optimization passes, allowing them to be optimized away, if unnecessary (such as is the case in the example above).