diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
| commit | 344a3780b2e33f6ca763666c380202b18aab72a3 (patch) | |
| tree | f0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/Target/ARM/ARMFrameLowering.cpp | |
| parent | b60736ec1405bb0a8dd40989f67ef4c93da068ab (diff) | |
vendor/llvm-project/llvmorg-13-init-16847-g88e66fa60ae5vendor/llvm-project/llvmorg-12.0.1-rc2-0-ge7dac564cd0evendor/llvm-project/llvmorg-12.0.1-0-gfed41342a82f
Diffstat (limited to 'llvm/lib/Target/ARM/ARMFrameLowering.cpp')
| -rw-r--r-- | llvm/lib/Target/ARM/ARMFrameLowering.cpp | 226 |
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); } |
