summaryrefslogtreecommitdiff
path: root/llvm/lib/Target/ARM/ARMFrameLowering.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
commit344a3780b2e33f6ca763666c380202b18aab72a3 (patch)
treef0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/Target/ARM/ARMFrameLowering.cpp
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
Diffstat (limited to 'llvm/lib/Target/ARM/ARMFrameLowering.cpp')
-rw-r--r--llvm/lib/Target/ARM/ARMFrameLowering.cpp226
1 files changed, 187 insertions, 39 deletions
diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
index 9eeb7f20dc8d..025e43444f9c 100644
--- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
@@ -9,6 +9,102 @@
// This file contains the ARM implementation of TargetFrameLowering class.
//
//===----------------------------------------------------------------------===//
+//
+// This file contains the ARM implementation of TargetFrameLowering class.
+//
+// On ARM, stack frames are structured as follows:
+//
+// The stack grows downward.
+//
+// All of the individual frame areas on the frame below are optional, i.e. it's
+// possible to create a function so that the particular area isn't present
+// in the frame.
+//
+// At function entry, the "frame" looks as follows:
+//
+// | | Higher address
+// |-----------------------------------|
+// | |
+// | arguments passed on the stack |
+// | |
+// |-----------------------------------| <- sp
+// | | Lower address
+//
+//
+// After the prologue has run, the frame has the following general structure.
+// Technically the last frame area (VLAs) doesn't get created until in the
+// main function body, after the prologue is run. However, it's depicted here
+// for completeness.
+//
+// | | Higher address
+// |-----------------------------------|
+// | |
+// | arguments passed on the stack |
+// | |
+// |-----------------------------------| <- (sp at function entry)
+// | |
+// | varargs from registers |
+// | |
+// |-----------------------------------|
+// | |
+// | prev_fp, prev_lr |
+// | (a.k.a. "frame record") |
+// | |
+// |- - - - - - - - - - - - - - - - - -| <- fp (r7 or r11)
+// | |
+// | callee-saved gpr registers |
+// | |
+// |-----------------------------------|
+// | |
+// | callee-saved fp/simd regs |
+// | |
+// |-----------------------------------|
+// |.empty.space.to.make.part.below....|
+// |.aligned.in.case.it.needs.more.than| (size of this area is unknown at
+// |.the.standard.8-byte.alignment.....| compile time; if present)
+// |-----------------------------------|
+// | |
+// | local variables of fixed size |
+// | including spill slots |
+// |-----------------------------------| <- base pointer (not defined by ABI,
+// |.variable-sized.local.variables....| LLVM chooses r6)
+// |.(VLAs)............................| (size of this area is unknown at
+// |...................................| compile time)
+// |-----------------------------------| <- sp
+// | | Lower address
+//
+//
+// To access the data in a frame, at-compile time, a constant offset must be
+// computable from one of the pointers (fp, bp, sp) to access it. The size
+// of the areas with a dotted background cannot be computed at compile-time
+// if they are present, making it required to have all three of fp, bp and
+// sp to be set up to be able to access all contents in the frame areas,
+// assuming all of the frame areas are non-empty.
+//
+// For most functions, some of the frame areas are empty. For those functions,
+// it may not be necessary to set up fp or bp:
+// * A base pointer is definitely needed when there are both VLAs and local
+// variables with more-than-default alignment requirements.
+// * A frame pointer is definitely needed when there are local variables with
+// more-than-default alignment requirements.
+//
+// In some cases when a base pointer is not strictly needed, it is generated
+// anyway when offsets from the frame pointer to access local variables become
+// so large that the offset can't be encoded in the immediate fields of loads
+// or stores.
+//
+// The frame pointer might be chosen to be r7 or r11, depending on the target
+// architecture and operating system. See ARMSubtarget::getFramePointerReg for
+// details.
+//
+// Outgoing function arguments must be at the bottom of the stack frame when
+// calling another function. If we do not have variable-sized stack objects, we
+// can allocate a "reserved call frame" area at the bottom of the local
+// variable area, large enough for all outgoing calls. If we do have VLAs, then
+// the stack pointer must be decremented and incremented around each call to
+// make space for the arguments below the VLAs.
+//
+//===----------------------------------------------------------------------===//
#include "ARMFrameLowering.h"
#include "ARMBaseInstrInfo.h"
@@ -110,8 +206,7 @@ bool ARMFrameLowering::hasFP(const MachineFunction &MF) const {
return true;
// Frame pointer required for use within this function.
- return (RegInfo->needsStackRealignment(MF) ||
- MFI.hasVarSizedObjects() ||
+ return (RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
MFI.isFrameAddressTaken());
}
@@ -142,6 +237,41 @@ ARMFrameLowering::canSimplifyCallFramePseudos(const MachineFunction &MF) const {
return hasReservedCallFrame(MF) || MF.getFrameInfo().hasVarSizedObjects();
}
+// Returns how much of the incoming argument stack area we should clean up in an
+// epilogue. For the C calling convention this will be 0, for guaranteed tail
+// call conventions it can be positive (a normal return or a tail call to a
+// function that uses less stack space for arguments) or negative (for a tail
+// call to a function that needs more stack space than us for arguments).
+static int getArgumentStackToRestore(MachineFunction &MF,
+ MachineBasicBlock &MBB) {
+ MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
+ bool IsTailCallReturn = false;
+ if (MBB.end() != MBBI) {
+ unsigned RetOpcode = MBBI->getOpcode();
+ IsTailCallReturn = RetOpcode == ARM::TCRETURNdi ||
+ RetOpcode == ARM::TCRETURNri;
+ }
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+
+ int ArgumentPopSize = 0;
+ if (IsTailCallReturn) {
+ MachineOperand &StackAdjust = MBBI->getOperand(1);
+
+ // For a tail-call in a callee-pops-arguments environment, some or all of
+ // the stack may actually be in use for the call's arguments, this is
+ // calculated during LowerCall and consumed here...
+ ArgumentPopSize = StackAdjust.getImm();
+ } else {
+ // ... otherwise the amount to pop is *all* of the argument space,
+ // conveniently stored in the MachineFunctionInfo by
+ // LowerFormalArguments. This will, of course, be zero for the C calling
+ // convention.
+ ArgumentPopSize = AFI->getArgumentStackToRestore();
+ }
+
+ return ArgumentPopSize;
+}
+
static void emitRegPlusImmediate(
bool isARM, MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI,
const DebugLoc &dl, const ARMBaseInstrInfo &TII, unsigned DestReg,
@@ -711,7 +841,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
// sure if we also have VLAs, we have a base pointer for frame access.
// If aligned NEON registers were spilled, the stack has already been
// realigned.
- if (!AFI->getNumAlignedDPRCS2Regs() && RegInfo->needsStackRealignment(MF)) {
+ if (!AFI->getNumAlignedDPRCS2Regs() && RegInfo->hasStackRealignment(MF)) {
Align MaxAlign = MFI.getMaxAlign();
assert(!AFI->isThumb1OnlyFunction());
if (!AFI->isThumbFunction()) {
@@ -773,7 +903,13 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
"This emitEpilogue does not support Thumb1!");
bool isARM = !AFI->isThumbFunction();
- unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize();
+ // Amount of stack space we reserved next to incoming args for either
+ // varargs registers or stack arguments in tail calls made by this function.
+ unsigned ReservedArgStack = AFI->getArgRegsSaveSize();
+
+ // How much of the stack used by incoming arguments this function is expected
+ // to restore in this particular epilogue.
+ int IncomingArgStackToRestore = getArgumentStackToRestore(MF, MBB);
int NumBytes = (int)MFI.getStackSize();
Register FramePtr = RegInfo->getFrameRegister(MF);
@@ -787,8 +923,8 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
if (!AFI->hasStackFrame()) {
- if (NumBytes - ArgRegsSaveSize != 0)
- emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes - ArgRegsSaveSize,
+ if (NumBytes - ReservedArgStack != 0)
+ emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes - ReservedArgStack,
MachineInstr::FrameDestroy);
} else {
// Unwind MBBI to point to first LDR / VLDRD.
@@ -802,7 +938,7 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
}
// Move SP to start of FP callee save spill area.
- NumBytes -= (ArgRegsSaveSize +
+ NumBytes -= (ReservedArgStack +
AFI->getFPCXTSaveAreaSize() +
AFI->getGPRCalleeSavedArea1Size() +
AFI->getGPRCalleeSavedArea2Size() +
@@ -874,9 +1010,13 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
if (AFI->getFPCXTSaveAreaSize()) MBBI++;
}
- if (ArgRegsSaveSize)
- emitSPUpdate(isARM, MBB, MBBI, dl, TII, ArgRegsSaveSize,
+ if (ReservedArgStack || IncomingArgStackToRestore) {
+ assert((int)ReservedArgStack + IncomingArgStackToRestore >= 0 &&
+ "attempting to restore negative stack amount");
+ emitSPUpdate(isARM, MBB, MBBI, dl, TII,
+ ReservedArgStack + IncomingArgStackToRestore,
MachineInstr::FrameDestroy);
+ }
}
/// getFrameIndexReference - Provide a base+offset reference to an FI slot for
@@ -909,7 +1049,7 @@ int ARMFrameLowering::ResolveFrameIndexReference(const MachineFunction &MF,
// When dynamically realigning the stack, use the frame pointer for
// parameters, and the stack/base pointer for locals.
- if (RegInfo->needsStackRealignment(MF)) {
+ if (RegInfo->hasStackRealignment(MF)) {
assert(hasFP(MF) && "dynamic stack realignment without a FP!");
if (isFixed) {
FrameReg = RegInfo->getFrameRegister(MF);
@@ -1089,19 +1229,16 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
// The aligned reloads from area DPRCS2 are not inserted here.
if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs)
continue;
-
if (Reg == ARM::LR && !isTailCall && !isVarArg && !isInterrupt &&
- !isCmseEntry && !isTrap && STI.hasV5TOps()) {
- if (MBB.succ_empty()) {
- Reg = ARM::PC;
- // Fold the return instruction into the LDM.
- DeleteRet = true;
- LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET;
- // We 'restore' LR into PC so it is not live out of the return block:
- // Clear Restored bit.
- Info.setRestored(false);
- } else
- LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_UPD : ARM::LDMIA_UPD;
+ !isCmseEntry && !isTrap && AFI->getArgumentStackToRestore() == 0 &&
+ STI.hasV5TOps() && MBB.succ_empty()) {
+ Reg = ARM::PC;
+ // Fold the return instruction into the LDM.
+ DeleteRet = true;
+ LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET;
+ // We 'restore' LR into PC so it is not live out of the return block:
+ // Clear Restored bit.
+ Info.setRestored(false);
}
// If NoGap is true, pop consecutive registers and then leave the rest
@@ -1687,7 +1824,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
// instruction.
// FIXME: It will be better just to find spare register here.
if (AFI->isThumb2Function() &&
- (MFI.hasVarSizedObjects() || RegInfo->needsStackRealignment(MF)))
+ (MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(MF)))
SavedRegs.set(ARM::R4);
// If a stack probe will be emitted, spill R4 and LR, since they are
@@ -1712,7 +1849,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
// changes it, it'll be a spill, which implies we've used all the registers
// and so R4 is already used, so not marking it here will be OK.
// FIXME: It will be better just to find spare register here.
- if (MFI.hasVarSizedObjects() || RegInfo->needsStackRealignment(MF) ||
+ if (MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(MF) ||
MFI.estimateStackSize(MF) > 508)
SavedRegs.set(ARM::R4);
}
@@ -2193,31 +2330,37 @@ MachineBasicBlock::iterator ARMFrameLowering::eliminateCallFramePseudoInstr(
MachineBasicBlock::iterator I) const {
const ARMBaseInstrInfo &TII =
*static_cast<const ARMBaseInstrInfo *>(MF.getSubtarget().getInstrInfo());
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ bool isARM = !AFI->isThumbFunction();
+ DebugLoc dl = I->getDebugLoc();
+ unsigned Opc = I->getOpcode();
+ bool IsDestroy = Opc == TII.getCallFrameDestroyOpcode();
+ unsigned CalleePopAmount = IsDestroy ? I->getOperand(1).getImm() : 0;
+
+ assert(!AFI->isThumb1OnlyFunction() &&
+ "This eliminateCallFramePseudoInstr does not support Thumb1!");
+
+ int PIdx = I->findFirstPredOperandIdx();
+ ARMCC::CondCodes Pred = (PIdx == -1)
+ ? ARMCC::AL
+ : (ARMCC::CondCodes)I->getOperand(PIdx).getImm();
+ unsigned PredReg = TII.getFramePred(*I);
+
if (!hasReservedCallFrame(MF)) {
+ // Bail early if the callee is expected to do the adjustment.
+ if (IsDestroy && CalleePopAmount != -1U)
+ return MBB.erase(I);
+
// If we have alloca, convert as follows:
// ADJCALLSTACKDOWN -> sub, sp, sp, amount
// ADJCALLSTACKUP -> add, sp, sp, amount
- MachineInstr &Old = *I;
- DebugLoc dl = Old.getDebugLoc();
- unsigned Amount = TII.getFrameSize(Old);
+ unsigned Amount = TII.getFrameSize(*I);
if (Amount != 0) {
// We need to keep the stack aligned properly. To do this, we round the
// amount of space needed for the outgoing arguments up to the next
// alignment boundary.
Amount = alignSPAdjust(Amount);
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- assert(!AFI->isThumb1OnlyFunction() &&
- "This eliminateCallFramePseudoInstr does not support Thumb1!");
- bool isARM = !AFI->isThumbFunction();
-
- // Replace the pseudo instruction with a new instruction...
- unsigned Opc = Old.getOpcode();
- int PIdx = Old.findFirstPredOperandIdx();
- ARMCC::CondCodes Pred =
- (PIdx == -1) ? ARMCC::AL
- : (ARMCC::CondCodes)Old.getOperand(PIdx).getImm();
- unsigned PredReg = TII.getFramePred(Old);
if (Opc == ARM::ADJCALLSTACKDOWN || Opc == ARM::tADJCALLSTACKDOWN) {
emitSPUpdate(isARM, MBB, I, dl, TII, -Amount, MachineInstr::NoFlags,
Pred, PredReg);
@@ -2227,6 +2370,11 @@ MachineBasicBlock::iterator ARMFrameLowering::eliminateCallFramePseudoInstr(
Pred, PredReg);
}
}
+ } else if (CalleePopAmount != -1U) {
+ // If the calling convention demands that the callee pops arguments from the
+ // stack, we want to add it back if we have a reserved call frame.
+ emitSPUpdate(isARM, MBB, I, dl, TII, -CalleePopAmount,
+ MachineInstr::NoFlags, Pred, PredReg);
}
return MBB.erase(I);
}