HowTo: Manage stack frame allocation
From LLVM
Default Stack Layout
Is this correct? ...
LLVM default stack layout (for downward stack growth):
see PEI::calculateFrameObjectOffsets in PrologEpilogInserter.cpp
stack grows down
high address -------------------------------
| |
| Incoming Parameters |
| Passed to Callee | ^Caller Allocated
SP** in Caller -> ------------------------------- ----------------
| | Callee Allocated
| Callee Save |
| Registers |
-------------------------------
| |
| Local Workspace |
-------------------------------
| (fixed size) |
| alloca |
-------------------------------
| |\
| Outgoing Parameters | > MaxCallFrameSize
SP** -> -------------------------------/ (if hasReservedCallFrame)
low address
** SP is managed by target dependent code.
Allocas whose size can be determined at compile time will be allocated space on the stack when the stack frame size is calculated. For variable sized allocas the target specific code will have to resize the stack, adjusting the frame pointer and stack pointer as needed, and adjust the locations for the outgoing parameters to the top of the stack.
Reserved Call Frames
Reserved call frames are allocated in the function prologue for all calls the function makes. This avoids the add/sub of the stack pointer at each call site.
The TargetRegisterInfo class defines the virtual function hasReservedCallFrame:
// hasReservedCallFrame - Under normal circumstances, when a frame pointer is // not required, we reserve argument space for call sites in the function // immediately on entry to the current function. This eliminates the need for // add/sub sp brackets around call sites. Returns true if the call frame is // included as part of the stack frame.
The size of the reserved call frame is available in MachineFrameInfo::getMaxCallFrameSize(). The size of the call frames are calculated using the calling convention information generated from the XXXCallingConventions.td file.
/// getMaxCallFrameSize - Return the maximum size of a call frame that must be /// allocated for an outgoing function call. This is only available if /// CallFrameSetup/Destroy pseudo instructions are used by the target, and /// then only during or after prolog/epilog code insertion.
Code in PrologEpilogInseter.cpp PEI::calculateFrameObjectOffsets() will allocate space on the stack for reserved call frames if hasReservedCallFrame is true.
Stack Frame Allocation
LLVM uses the MachineFrameInfo class to represent the stack frame for a function.
This class stores an abstract representation of a target-nonspecific function frame. The representation assigns a unique 'frame index' to each 'object' in the frame.
From include/llvm/CodeGen/MachineFrameInfo.h:
/// The MachineFrameInfo class represents an abstract stack frame until /// prolog/epilog code is inserted. This class is key to allowing stack frame /// representation optimizations, such as frame pointer elimination. It also /// allows more mundane (but still important) optimizations, such as reordering /// of abstract objects on the stack frame. /// /// To support this, the class assigns unique integer identifiers to stack /// objects requested clients. These identifiers are negative integers for /// fixed stack objects (such as arguments passed on the stack) or nonnegative /// for objects that may be reordered. Instructions which refer to stack /// objects use a special MO_FrameIndex operand to represent these frame /// indexes. /// /// Because this class keeps track of all references to the stack frame, it /// knows when a variable sized object is allocated on the stack. This is the /// sole condition which prevents frame pointer elimination, which is an /// important optimization on register-poor architectures. Because original /// variable sized alloca's in the source program are the only source of /// variable sized stack objects, it is safe to decide whether there will be /// any variable sized objects before all stack objects are known (for /// example, register allocator spill code never needs variable sized /// objects). /// /// When prolog/epilog code emission is performed, the final stack frame is /// built and the machine instructions are modified to refer to the actual /// stack offsets of the object, eliminating all MO_FrameIndex operands from /// the program.
[edit] Example Code
The following example illustrates an implementation of the processFunctionBeforeCalleeSavedScan method for the XXX processor.
This example creates a spill slots at a fixed location for the link register (return address) and the frame pointer. The link register spill slot is at the top of the frame followed by the frame pointer slot. It is a downward growing stack. Note that MFI->CreateFixedObject(size, 0) would create a spill slot in the previous frame.
void XXXRegisterInfo:: processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS) const { MachineFrameInfo *MFI = MF.getFrameInfo(); bool LRUsed = MF.getRegInfo().isPhysRegUsed(XXX::R31); const TargetRegisterClass *RC = XXX::GPRCRegisterClass; XXXFunctionInfo *MonFI = MF.getInfo<XXXFunctionInfo>(); if (LRUsed) { int FrameIdx; // Put the Link Register at the top of the frame. FrameIdx = MFI->CreateFixedObject(RC->getSize(), -4); // Save the frame index so we can use it in other lowerings. MonFI->setLRSpillSlot(FrameIdx); } if (hasFP(MF)) { // The Frame Pointer is placed after the link register or at the top of frame. MonFI->setFPSpillSlot(MFI->CreateFixedObject(RC->getSize(),(LRUsed)?-8:-4)); } }

