aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/ARM/Thumb1FrameLowering.cpp')
-rw-r--r--llvm/lib/Target/ARM/Thumb1FrameLowering.cpp95
1 files changed, 76 insertions, 19 deletions
diff --git a/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp b/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
index cb9ded7dee57..faa0352507fb 100644
--- a/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
+++ b/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp
@@ -39,11 +39,12 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MathExtras.h"
#include <cassert>
#include <iterator>
#include <vector>
+#define DEBUG_TYPE "arm-frame-lowering"
+
using namespace llvm;
Thumb1FrameLowering::Thumb1FrameLowering(const ARMSubtarget &sti)
@@ -160,6 +161,8 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
assert(NumBytes >= ArgRegsSaveSize &&
"ArgRegsSaveSize is included in NumBytes");
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
+ assert(STI.getPushPopSplitVariation(MF) == ARMSubtarget::SplitR7 &&
+ "Must use R7 spilt for Thumb1");
// Debug location must be unknown since the first debug location is used
// to determine the end of the prologue.
@@ -221,11 +224,8 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
case ARM::R8:
case ARM::R9:
case ARM::R10:
- if (STI.splitFramePushPop(MF)) {
- GPRCS2Size += 4;
- break;
- }
- [[fallthrough]];
+ GPRCS2Size += 4;
+ break;
case ARM::LR:
if (HasFrameRecordArea) {
FRSize += 4;
@@ -279,6 +279,20 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
}
}
+ // Skip past this code sequence, which is emitted to restore the LR if it is
+ // live-in and clobbered by the frame record setup code:
+ // ldr rX, [sp, #Y]
+ // mov lr, rX
+ if (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tLDRspi &&
+ MBBI->getFlag(MachineInstr::FrameSetup)) {
+ ++MBBI;
+ if (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tMOVr &&
+ MBBI->getOperand(0).getReg() == ARM::LR &&
+ MBBI->getFlag(MachineInstr::FrameSetup)) {
+ ++MBBI;
+ }
+ }
+
// Determine starting offsets of spill areas.
unsigned DPRCSOffset = NumBytes - ArgRegsSaveSize -
(FRSize + GPRCS1Size + GPRCS2Size + DPRCSSize);
@@ -292,7 +306,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
AFI->setFrameRecordSavedAreaSize(FRSize);
AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset);
AFI->setGPRCalleeSavedArea2Offset(GPRCS2Offset);
- AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset);
+ AFI->setDPRCalleeSavedArea1Offset(DPRCSOffset);
NumBytes = DPRCSOffset;
int FramePtrOffsetInBlock = 0;
@@ -365,9 +379,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
case ARM::R10:
case ARM::R11:
case ARM::R12:
- if (STI.splitFramePushPop(MF))
- break;
- [[fallthrough]];
+ break;
case ARM::R0:
case ARM::R1:
case ARM::R2:
@@ -444,7 +456,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
AFI->setGPRCalleeSavedArea1Size(GPRCS1Size);
AFI->setGPRCalleeSavedArea2Size(GPRCS2Size);
- AFI->setDPRCalleeSavedAreaSize(DPRCSSize);
+ AFI->setDPRCalleeSavedArea1Size(DPRCSSize);
if (RegInfo->hasStackRealignment(MF)) {
const unsigned NrBitsToZero = Log2(MFI.getMaxAlign());
@@ -530,11 +542,10 @@ void Thumb1FrameLowering::emitEpilogue(MachineFunction &MF,
}
// Move SP to start of FP callee save spill area.
- NumBytes -= (AFI->getFrameRecordSavedAreaSize() +
- AFI->getGPRCalleeSavedArea1Size() +
- AFI->getGPRCalleeSavedArea2Size() +
- AFI->getDPRCalleeSavedAreaSize() +
- ArgRegsSaveSize);
+ NumBytes -=
+ (AFI->getFrameRecordSavedAreaSize() +
+ AFI->getGPRCalleeSavedArea1Size() + AFI->getGPRCalleeSavedArea2Size() +
+ AFI->getDPRCalleeSavedArea1Size() + ArgRegsSaveSize);
// We are likely to need a scratch register and we know all callee-save
// registers are free at this point in the epilogue, so pick one.
@@ -862,7 +873,8 @@ static void pushRegsToStack(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const TargetInstrInfo &TII,
const std::set<Register> &RegsToSave,
- const std::set<Register> &CopyRegs) {
+ const std::set<Register> &CopyRegs,
+ bool &UsedLRAsTemp) {
MachineFunction &MF = *MBB.getParent();
const MachineRegisterInfo &MRI = MF.getRegInfo();
DebugLoc DL;
@@ -919,6 +931,8 @@ static void pushRegsToStack(MachineBasicBlock &MBB,
bool isKill = !MRI.isLiveIn(*HiRegToSave);
if (isKill && !MRI.isReserved(*HiRegToSave))
MBB.addLiveIn(*HiRegToSave);
+ if (*CopyRegIt == ARM::LR)
+ UsedLRAsTemp = true;
// Emit a MOV from the high reg to the low reg.
BuildMI(MBB, MI, DL, TII.get(ARM::tMOVr))
@@ -1098,6 +1112,8 @@ bool Thumb1FrameLowering::spillCalleeSavedRegisters(
// In case FP is a high reg, we need a separate push sequence to generate
// a correct Frame Record
bool NeedsFrameRecordPush = hasFP(MF) && ARM::hGPRRegClass.contains(FPReg);
+ bool LRLiveIn = MF.getRegInfo().isLiveIn(ARM::LR);
+ bool UsedLRAsTemp = false;
std::set<Register> FrameRecord;
std::set<Register> SpilledGPRs;
@@ -1109,7 +1125,22 @@ bool Thumb1FrameLowering::spillCalleeSavedRegisters(
SpilledGPRs.insert(Reg);
}
- pushRegsToStack(MBB, MI, TII, FrameRecord, {ARM::LR});
+ // Determine intermediate registers which can be used for pushing the frame
+ // record:
+ // - Unused argument registers
+ // - LR: This is possible because the first PUSH will save it on the stack,
+ // so it is free to be used as a temporary for the second. However, it
+ // is possible for LR to be live-in to the function, in which case we
+ // will need to restore it later in the prologue, so we only use this
+ // if there are no free argument registers.
+ std::set<Register> FrameRecordCopyRegs;
+ for (unsigned ArgReg : {ARM::R0, ARM::R1, ARM::R2, ARM::R3})
+ if (!MF.getRegInfo().isLiveIn(ArgReg))
+ FrameRecordCopyRegs.insert(ArgReg);
+ if (FrameRecordCopyRegs.empty())
+ FrameRecordCopyRegs.insert(ARM::LR);
+
+ pushRegsToStack(MBB, MI, TII, FrameRecord, FrameRecordCopyRegs, UsedLRAsTemp);
// Determine intermediate registers which can be used for pushing high regs:
// - Spilled low regs
@@ -1123,7 +1154,33 @@ bool Thumb1FrameLowering::spillCalleeSavedRegisters(
if (!MF.getRegInfo().isLiveIn(ArgReg))
CopyRegs.insert(ArgReg);
- pushRegsToStack(MBB, MI, TII, SpilledGPRs, CopyRegs);
+ pushRegsToStack(MBB, MI, TII, SpilledGPRs, CopyRegs, UsedLRAsTemp);
+
+ // If the push sequence used LR as a temporary, and LR is live-in (for
+ // example because it is used by the llvm.returnaddress intrinsic), then we
+ // need to reload it from the stack. Thumb1 does not have a load instruction
+ // which can use LR, so we need to load into a temporary low register and
+ // copy to LR.
+ if (LRLiveIn && UsedLRAsTemp) {
+ auto CopyRegIt = getNextOrderedReg(OrderedCopyRegs.rbegin(),
+ OrderedCopyRegs.rend(), CopyRegs);
+ assert(CopyRegIt != OrderedCopyRegs.rend());
+ unsigned NumRegsPushed = FrameRecord.size() + SpilledGPRs.size();
+ LLVM_DEBUG(
+ dbgs() << "LR is live-in but clobbered in prologue, restoring via "
+ << RegInfo->getName(*CopyRegIt) << "\n");
+
+ BuildMI(MBB, MI, DebugLoc(), TII.get(ARM::tLDRspi), *CopyRegIt)
+ .addReg(ARM::SP)
+ .addImm(NumRegsPushed - 1)
+ .add(predOps(ARMCC::AL))
+ .setMIFlags(MachineInstr::FrameSetup);
+
+ BuildMI(MBB, MI, DebugLoc(), TII.get(ARM::tMOVr), ARM::LR)
+ .addReg(*CopyRegIt)
+ .add(predOps(ARMCC::AL))
+ .setMIFlags(MachineInstr::FrameSetup);
+ }
return true;
}