Expand description
The frame: what a function’s stack looks like while it runs.
Design: spec/10-backend.md section 10.7.
This is worked out after register allocation and not before, because the largest area in most frames is the spill slots and nothing knows how many of those there are until the allocator has finished running out of registers. It is worked out from the rewritten function rather than from the assignment alone, because the rewrite is what decides which scratch registers a reload uses, and a scratch register a call preserves is one the prologue has to save.
§What is in one
Section 10.7 lists the areas and this is the order they are in, from the stack pointer upward, which is the order of increasing address on every machine here.
incoming stack arguments the caller wrote these and they are above everything
return address the call instruction pushed it, on a machine that does
saved frame pointer when the function keeps one
saved general purpose regs pushed, one word each
saved vector registers stored rather than pushed, since no machine here pushes one
locals what an alloca becomes, widest alignment first
spill slots one for every value the allocator ran out of registers for
outgoing argument area at the bottom, because a call reads its stack arguments from
the stack pointer upwardEvery offset reported here is from the stack pointer as it stands in the body of the function, which is after the prologue and before the epilogue. That is the one base register always available. A frame pointer is a second way to reach the same bytes and the prologue is what knows the distance between the two, so nothing here reports an offset from it.
§Where the alignment comes from
A call has to leave the stack pointer on a multiple of the convention’s alignment, so a
function’s own frame is what puts it back: the call that reached this function pushed a return
address and left the stack pointer one word off, and the prologue’s pushes either fix that or
make it worse depending on how many there are. The size the prologue subtracts is therefore not
the size of the areas. It is whatever brings the stack pointer back to a multiple of the
alignment given the pushes in front of it, which is the arithmetic in Frame::of.
§The red zone
A leaf function may use the bytes below the stack pointer without moving it, which is what
red_zone on a convention says and what makes a small leaf function’s prologue and epilogue
empty. Then the offsets are negative, which is why they are signed, and the areas are in the
same order as ever, below the line rather than above it. Anything that calls, or is too big for
the zone, or wants more alignment than the stack pointer has for free, moves the stack pointer.
§Realignment
A local wanting more alignment than a call leaves the stack pointer with cannot be placed by
arithmetic, because nothing in the frame knows what the caller’s stack pointer was a multiple
of. The prologue has to force it, and forcing it destroys the only record of where the caller’s
stack was, so a realigned frame needs a frame pointer and the distance from the body’s stack
pointer to the incoming arguments stops being a constant. Frame::realign is where that is
reported and it is why Frame::incoming can answer that it does not know.