Skip to main content

Module frame

Module frame 

Source
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 upward

Every 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.

Structs§

Frame
What a function’s stack looks like while it runs.
Layout
Everything about a function’s frame that does not come out of its allocation.
Local
A piece of memory the function needs for its own use, which is what an alloca becomes.