Skip to main content

Module kept

Module kept 

Source
Expand description

Where each local the program kept in a value ended up, and over which instructions.

Design: spec/11-asm-objects-debug.md section 11.4.

Selection says which declaration each virtual register holds a value of, and the allocator says where each virtual register went. Putting the two together is all this is, and the only thing that makes it more than a join is the stretch: a frame slot belongs to its local for as long as the frame exists, and a register is handed to the next value the moment this one is done with, so where a register holds a local is a question about part of a function rather than about the whole of it. The allocator’s own liveness is the answer, read rather than worked out again for the reason crate::slots gives for reading it: two answers about one function are free to disagree, and the one the machine runs is the allocator’s.

A stretch runs from the instruction after the one that wrote the value to the last instruction that reads it, both ends included, and it stops at the end of the block either way. The front is one instruction along because a register does not hold a value until the instruction writing it has run, and the back is where it is because nothing reads the value afterwards, so whatever the allocator puts in the register next cannot be seen by anybody asking. A value nothing reads at all gets no stretch, which is the same sentence read the other way: the two ends cross.

The block is where it stops because the pass that lays the blocks out runs after the allocator and can put them in any order it likes. Inside a block nothing has moved, so a run of instructions there is a run of addresses to come, and a value live from one block into the next gets a stretch in each of them rather than one stretch that would cover whatever the layout happened to put in between.

§What is left out

A function whose instructions moved about inside a block after it was allocated gets nothing. The liveness is counted along the order the allocator laid the function out in, and a scheduler makes that order no longer the order the block is in, so a stretch worked out from it would name two instructions that are no longer either side of the value. The check is the walk below, which notices the moment a surviving instruction is out of order.

That is -O2 and above, where the scheduler runs, and -O0 is what M8 is about. Carrying the liveness across a schedule is what would lift it, and the register allocator of M4 will want the same thing, since one that splits a live range has to say where the pieces went too.

A value the allocator spilled is in the frame over its stretch rather than in a register, which is as much an answer as the other and is written the same way. A value it spilled in a function whose alignment the prologue had to force has no answer, because the distance from the call frame address is not a constant there, which is what crate::frame says about a local in the same function.

Functions§

before
Every instruction of a function, in the order they are in, which is what the allocator’s liveness is counted along while that is still the order.
of
Which declaration is where, over which instructions, or nothing at all for a function the answer cannot be given about. See the module documentation for which those are.