Anyone know of any good writeups out there on the reverse linear scan register allocation (on SSA form IR).

I'm especially interested in discussion of register usage hints or constraints around things like calling conventions -- landing parameters in the right registers, but making the most of those registers outside of call boundaries, etc.

#PLdev #Questions

Implemented the RV32I pass-by-register calling convention in the simple SR32 code generator... as a compiler parameter.

Updated the emulator to support either calling convention (at runtime) for syscalls.

This all works, which is nice, but now I've just added a third dimension to the test grid, which is less nice.

#Projects #Compiler #PLdev

The desire to explore Subnautica 2 (now in early access) is warring with the desire to generate assembly from IR now that register allocation is happening.

#PLdev #Gaming #Argh

Rearranged the register assignments in my softrisc32 ISA to match that of RV32I because there's no point in maintaining a variant register map just because I find the RV32I map "untidy" (due to them arranging stuff to make sense when the top half are missing in RV32E).

This has the side-effect of making (textual) sr32 assembly even closer to rv32i assembly.

About to shift from passing parameters on the stack to passing parameters in registers.

#Projects #Compiler #PLdev

Starting to allocate some registers. I need more test cases with greater register pressure. Most of them fit within 4 working registers just fine.

I did update my live range graph in the IR dump to use dashed lines for spilled registers.

Here's one that spills at 4 and spills a bit more at 3.

#Projects #Compiler #PLdev

Housekeeping to allow the -out path (for final compilation) and the -xir path (for eXecutable IR useful for validation) to coexist in a single compiler invocation. Also some tidying up of argument wrangling, improving the XIR format so writing it is non-destructive (to allow generating pre/post optimization variants), tidying up output file argument handling in main, and separate flags for dumping ir0 (initial IR generated from the AST) and -ir1 (final IR).

#Projects #Compiler #PLdev

Next: Finish up register allocation and selection and final code generation from the IR. At which point it should be self-hosting through the full stage3 compiler. Guessing it'll wind up around 8000 lines of code total once that's done, but we shall see!

Not tiny, but not enormous either.

#Projects #Compiler #PLdev

Cleaning up the validated AST form involved having the AST be more consistent about types, in particular pointers (which are generally not explicit in the language syntax, except when indicating if a struct field that is an array or struct is inline or not).

This resulted in an explosion of Type objects (2438 total, 1978 of them pointer-to-x types) when building the compiler.

Adding a pointer-to cache field in Type dropped that to 580 total. ~76% savings.

#Projects #Compiler #PLdev

That took a few days to get sorted, and it's not entirely done until I fix up the stage3 compiler's IR generation to work with the revised AST that the validation phase now generates, but stage1 and stage2 pass all tests and the a bunch of weird quirks from the early days of the project have been sorted out.

Responsibility for validating types, handling lhs vs rhs differences, managing other bookkeeping now lives entirely in the validator.

https://github.com/swetland/spl/commit/0f2f73521ea9ef55e9a6b57ae204b763bdf519a3

#Projects #Compiler #PLdev

Needing to better formalize the rules for pointers (which only exist explicitly in structure or array type definitions to indicate if fields or elements are in-line or not) to make sure the implicit dereferencing (or not) happens correctly. Getting closer. Doing it post-parsing but pre-codegen is definitely feeling better than the original side-effect-of-codegen approach that got really messy.

Only a couple tests not passing with all these changes.

#Projects #Compiler #PLdev