summaryrefslogtreecommitdiff
path: root/llvm/lib/Target/ARM/ARMFrameLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/ARM/ARMFrameLowering.cpp')
-rw-r--r--llvm/lib/Target/ARM/ARMFrameLowering.cpp503
1 files changed, 300 insertions, 203 deletions
diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
index 40354f995598..60062a2422e4 100644
--- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
@@ -173,6 +173,127 @@ static MachineBasicBlock::iterator
skipAlignedDPRCS2Spills(MachineBasicBlock::iterator MI,
unsigned NumAlignedDPRCS2Regs);
+enum class SpillArea {
+ GPRCS1,
+ GPRCS2,
+ DPRCS1,
+ DPRCS2,
+ FPCXT,
+};
+
+/// Get the spill area that Reg should be saved into in the prologue.
+SpillArea getSpillArea(Register Reg,
+ ARMSubtarget::PushPopSplitVariation Variation,
+ unsigned NumAlignedDPRCS2Regs,
+ const ARMBaseRegisterInfo *RegInfo) {
+ // NoSplit:
+ // push {r0-r12, lr} GPRCS1
+ // vpush {r8-d15} DPRCS1
+ //
+ // SplitR7:
+ // push {r0-r7, lr} GPRCS1
+ // push {r8-r12} GPRCS2
+ // vpush {r8-d15} DPRCS1
+ //
+ // SplitR11WindowsSEH:
+ // push {r0-r10, r12} GPRCS1
+ // vpush {r8-d15} DPRCS1
+ // push {r11, lr} GPRCS2
+
+ // If FPCXTNS is spilled (for CMSE secure entryfunctions), it is always at
+ // the top of the stack frame.
+ // The DPRCS2 region is used for ABIs which only guarantee 4-byte alignment
+ // of SP. If used, it will be below the other save areas, after the stack has
+ // been re-aligned.
+
+ switch (Reg) {
+ default:
+ dbgs() << "Don't know where to spill " << printReg(Reg, RegInfo) << "\n";
+ llvm_unreachable("Don't know where to spill this register");
+ break;
+
+ case ARM::FPCXTNS:
+ return SpillArea::FPCXT;
+
+ case ARM::R0:
+ case ARM::R1:
+ case ARM::R2:
+ case ARM::R3:
+ case ARM::R4:
+ case ARM::R5:
+ case ARM::R6:
+ case ARM::R7:
+ return SpillArea::GPRCS1;
+
+ case ARM::R8:
+ case ARM::R9:
+ case ARM::R10:
+ if (Variation == ARMSubtarget::SplitR7)
+ return SpillArea::GPRCS2;
+ else
+ return SpillArea::GPRCS1;
+
+ case ARM::R11:
+ if (Variation == ARMSubtarget::NoSplit)
+ return SpillArea::GPRCS1;
+ else
+ return SpillArea::GPRCS2;
+
+ case ARM::R12:
+ if (Variation == ARMSubtarget::SplitR7)
+ return SpillArea::GPRCS2;
+ else
+ return SpillArea::GPRCS1;
+
+ case ARM::LR:
+ if (Variation == ARMSubtarget::SplitR11WindowsSEH)
+ return SpillArea::GPRCS2;
+ else
+ return SpillArea::GPRCS1;
+
+ case ARM::D0:
+ case ARM::D1:
+ case ARM::D2:
+ case ARM::D3:
+ case ARM::D4:
+ case ARM::D5:
+ case ARM::D6:
+ case ARM::D7:
+ return SpillArea::DPRCS1;
+
+ case ARM::D8:
+ case ARM::D9:
+ case ARM::D10:
+ case ARM::D11:
+ case ARM::D12:
+ case ARM::D13:
+ case ARM::D14:
+ case ARM::D15:
+ if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs)
+ return SpillArea::DPRCS2;
+ else
+ return SpillArea::DPRCS1;
+
+ case ARM::D16:
+ case ARM::D17:
+ case ARM::D18:
+ case ARM::D19:
+ case ARM::D20:
+ case ARM::D21:
+ case ARM::D22:
+ case ARM::D23:
+ case ARM::D24:
+ case ARM::D25:
+ case ARM::D26:
+ case ARM::D27:
+ case ARM::D28:
+ case ARM::D29:
+ case ARM::D30:
+ case ARM::D31:
+ return SpillArea::DPRCS1;
+ }
+}
+
ARMFrameLowering::ARMFrameLowering(const ARMSubtarget &sti)
: TargetFrameLowering(StackGrowsDown, sti.getStackAlignment(), 0, Align(4)),
STI(sti) {}
@@ -600,6 +721,14 @@ struct StackAdjustingInsts {
MachineBasicBlock::iterator I;
unsigned SPAdjust;
bool BeforeFPSet;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ void dump() {
+ dbgs() << " " << (BeforeFPSet ? "before-fp " : " ")
+ << "sp-adjust=" << SPAdjust;
+ I->dump();
+ }
+#endif
};
SmallVector<InstInfo, 4> Insts;
@@ -634,6 +763,14 @@ struct StackAdjustingInsts {
.setMIFlags(MachineInstr::FrameSetup);
}
}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ void dump() {
+ dbgs() << "StackAdjustingInsts:\n";
+ for (auto &Info : Insts)
+ Info.dump();
+ }
+#endif
};
} // end anonymous namespace
@@ -713,6 +850,8 @@ static void emitAligningInstructions(MachineFunction &MF, ARMFunctionInfo *AFI,
/// this to produce a conservative estimate that we check in an assert() later.
static int getMaxFPOffset(const ARMSubtarget &STI, const ARMFunctionInfo &AFI,
const MachineFunction &MF) {
+ ARMSubtarget::PushPopSplitVariation PushPopSplit =
+ STI.getPushPopSplitVariation(MF);
// For Thumb1, push.w isn't available, so the first push will always push
// r7 and lr onto the stack first.
if (AFI.isThumb1OnlyFunction())
@@ -720,9 +859,8 @@ static int getMaxFPOffset(const ARMSubtarget &STI, const ARMFunctionInfo &AFI,
// This is a conservative estimation: Assume the frame pointer being r7 and
// pc("r15") up to r8 getting spilled before (= 8 registers).
int MaxRegBytes = 8 * 4;
- if (STI.splitFramePointerPush(MF)) {
- // Here, r11 can be stored below all of r4-r15 (3 registers more than
- // above), plus d8-d15.
+ if (PushPopSplit == ARMSubtarget::SplitR11WindowsSEH) {
+ // Here, r11 can be stored below all of r4-r15 plus d8-d15.
MaxRegBytes = 11 * 4 + 8 * 8;
}
int FPCXTSaveSize =
@@ -749,6 +887,10 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
int FPCXTSaveSize = 0;
bool NeedsWinCFI = needsWinCFI(MF);
+ ARMSubtarget::PushPopSplitVariation PushPopSplit =
+ STI.getPushPopSplitVariation(MF);
+
+ LLVM_DEBUG(dbgs() << "Emitting prologue for " << MF.getName() << "\n");
// Debug location must be unknown since the first debug location is used
// to determine the end of the prologue.
@@ -788,81 +930,32 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
return;
}
- // Determine spill area sizes.
- if (STI.splitFramePointerPush(MF)) {
- for (const CalleeSavedInfo &I : CSI) {
- Register Reg = I.getReg();
- int FI = I.getFrameIdx();
- switch (Reg) {
- case ARM::R11:
- case ARM::LR:
- if (Reg == FramePtr)
- FramePtrSpillFI = FI;
- GPRCS2Size += 4;
- break;
- case ARM::R0:
- case ARM::R1:
- case ARM::R2:
- case ARM::R3:
- case ARM::R4:
- case ARM::R5:
- case ARM::R6:
- case ARM::R7:
- case ARM::R8:
- case ARM::R9:
- case ARM::R10:
- case ARM::R12:
- GPRCS1Size += 4;
- break;
- case ARM::FPCXTNS:
- FPCXTSaveSize = 4;
- break;
- default:
- // This is a DPR. Exclude the aligned DPRCS2 spills.
- if (Reg == ARM::D8)
- D8SpillFI = FI;
- if (Reg < ARM::D8 || Reg >= ARM::D8 + AFI->getNumAlignedDPRCS2Regs())
- DPRCSSize += 8;
- }
- }
- } else {
- for (const CalleeSavedInfo &I : CSI) {
- Register Reg = I.getReg();
- int FI = I.getFrameIdx();
- switch (Reg) {
- case ARM::R8:
- case ARM::R9:
- case ARM::R10:
- case ARM::R11:
- case ARM::R12:
- if (STI.splitFramePushPop(MF)) {
- GPRCS2Size += 4;
- break;
- }
- [[fallthrough]];
- case ARM::R0:
- case ARM::R1:
- case ARM::R2:
- case ARM::R3:
- case ARM::R4:
- case ARM::R5:
- case ARM::R6:
- case ARM::R7:
- case ARM::LR:
- if (Reg == FramePtr)
- FramePtrSpillFI = FI;
- GPRCS1Size += 4;
- break;
- case ARM::FPCXTNS:
- FPCXTSaveSize = 4;
- break;
- default:
- // This is a DPR. Exclude the aligned DPRCS2 spills.
- if (Reg == ARM::D8)
- D8SpillFI = FI;
- if (Reg < ARM::D8 || Reg >= ARM::D8 + AFI->getNumAlignedDPRCS2Regs())
- DPRCSSize += 8;
- }
+ // Determine spill area sizes, and some important frame indices.
+ for (const CalleeSavedInfo &I : CSI) {
+ Register Reg = I.getReg();
+ int FI = I.getFrameIdx();
+
+ if (Reg == FramePtr)
+ FramePtrSpillFI = FI;
+ if (Reg == ARM::D8)
+ D8SpillFI = FI;
+
+ switch (getSpillArea(Reg, PushPopSplit, AFI->getNumAlignedDPRCS2Regs(),
+ RegInfo)) {
+ case SpillArea::FPCXT:
+ FPCXTSaveSize += 4;
+ break;
+ case SpillArea::GPRCS1:
+ GPRCS1Size += 4;
+ break;
+ case SpillArea::GPRCS2:
+ GPRCS2Size += 4;
+ break;
+ case SpillArea::DPRCS1:
+ DPRCSSize += 8;
+ break;
+ case SpillArea::DPRCS2:
+ break;
}
}
@@ -892,19 +985,22 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
DefCFAOffsetCandidates.addInst(LastPush, GPRCS1Size, true);
}
- // Determine starting offsets of spill areas.
+ // Determine starting offsets of spill areas. These offsets are all positive
+ // offsets from the bottom of the lowest-addressed callee-save area
+ // (excluding DPRCS2, which is th the re-aligned stack region) to the bottom
+ // of the spill area in question.
unsigned FPCXTOffset = NumBytes - ArgRegsSaveSize - FPCXTSaveSize;
unsigned GPRCS1Offset = FPCXTOffset - GPRCS1Size;
unsigned GPRCS2Offset = GPRCS1Offset - GPRCS2Size;
Align DPRAlign = DPRCSSize ? std::min(Align(8), Alignment) : Align(4);
unsigned DPRGapSize = GPRCS1Size + FPCXTSaveSize + ArgRegsSaveSize;
- if (!STI.splitFramePointerPush(MF)) {
+ if (PushPopSplit != ARMSubtarget::SplitR11WindowsSEH) {
DPRGapSize += GPRCS2Size;
}
DPRGapSize %= DPRAlign.value();
unsigned DPRCSOffset;
- if (STI.splitFramePointerPush(MF)) {
+ if (PushPopSplit == ARMSubtarget::SplitR11WindowsSEH) {
DPRCSOffset = GPRCS1Offset - DPRGapSize - DPRCSSize;
GPRCS2Offset = DPRCSOffset - GPRCS2Size;
} else {
@@ -912,10 +1008,19 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
}
int FramePtrOffsetInPush = 0;
if (HasFP) {
+ // Offset from the CFA to the saved frame pointer, will be negative.
int FPOffset = MFI.getObjectOffset(FramePtrSpillFI);
+ LLVM_DEBUG(dbgs() << "FramePtrSpillFI: " << FramePtrSpillFI
+ << ", FPOffset: " << FPOffset << "\n");
assert(getMaxFPOffset(STI, *AFI, MF) <= FPOffset &&
"Max FP estimation is wrong");
+ // Offset from the top of the GPRCS1 area to the saved frame pointer, will
+ // be negative.
FramePtrOffsetInPush = FPOffset + ArgRegsSaveSize + FPCXTSaveSize;
+ LLVM_DEBUG(dbgs() << "FramePtrOffsetInPush=" << FramePtrOffsetInPush
+ << ", FramePtrSpillOffset="
+ << (MFI.getObjectOffset(FramePtrSpillFI) + NumBytes)
+ << "\n");
AFI->setFramePtrSpillOffset(MFI.getObjectOffset(FramePtrSpillFI) +
NumBytes);
}
@@ -923,8 +1028,9 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
AFI->setGPRCalleeSavedArea2Offset(GPRCS2Offset);
AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset);
- // Move past area 2.
- if (GPRCS2Size > 0 && !STI.splitFramePointerPush(MF)) {
+ // Move GPRCS2, unless using SplitR11WindowsSEH, in which case it will be
+ // after DPRCS1.
+ if (GPRCS2Size > 0 && PushPopSplit != ARMSubtarget::SplitR11WindowsSEH) {
GPRCS2Push = LastPush = MBBI++;
DefCFAOffsetCandidates.addInst(LastPush, GPRCS2Size);
}
@@ -943,7 +1049,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
}
}
- // Move past area 3.
+ // Move past DPRCS1.
if (DPRCSSize > 0) {
// Since vpush register list cannot have gaps, there may be multiple vpush
// instructions in the prologue.
@@ -964,13 +1070,14 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
} else
NumBytes = DPRCSOffset;
- if (GPRCS2Size > 0 && STI.splitFramePointerPush(MF)) {
+ // Move GPRCS2, if using using SplitR11WindowsSEH.
+ if (GPRCS2Size > 0 && PushPopSplit == ARMSubtarget::SplitR11WindowsSEH) {
GPRCS2Push = LastPush = MBBI++;
DefCFAOffsetCandidates.addInst(LastPush, GPRCS2Size);
}
bool NeedsWinCFIStackAlloc = NeedsWinCFI;
- if (STI.splitFramePointerPush(MF) && HasFP)
+ if (PushPopSplit == ARMSubtarget::SplitR11WindowsSEH && HasFP)
NeedsWinCFIStackAlloc = false;
if (STI.isTargetWindows() && WindowsRequiresStackProbe(MF, NumBytes)) {
@@ -1075,7 +1182,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
AfterPush = std::next(GPRCS1Push);
unsigned PushSize = sizeOfSPAdjustment(*GPRCS1Push);
int FPOffset = PushSize + FramePtrOffsetInPush;
- if (STI.splitFramePointerPush(MF)) {
+ if (PushPopSplit == ARMSubtarget::SplitR11WindowsSEH) {
AfterPush = std::next(GPRCS2Push);
emitRegPlusImmediate(!AFI->isThumbFunction(), MBB, AfterPush, dl, TII,
FramePtr, ARM::SP, 0, MachineInstr::FrameSetup);
@@ -1107,7 +1214,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
// instructions below don't need to be replayed to unwind the stack.
if (NeedsWinCFI && MBBI != MBB.begin()) {
MachineBasicBlock::iterator End = MBBI;
- if (HasFP && STI.splitFramePointerPush(MF))
+ if (HasFP && PushPopSplit == ARMSubtarget::SplitR11WindowsSEH)
End = AfterPush;
insertSEHRange(MBB, {}, End, TII, MachineInstr::FrameSetup);
BuildMI(MBB, End, dl, TII.get(ARM::SEH_PrologEnd))
@@ -1118,80 +1225,35 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
// Now that the prologue's actual instructions are finalised, we can insert
// the necessary DWARF cf instructions to describe the situation. Start by
// recording where each register ended up:
- if (GPRCS1Size > 0 && !NeedsWinCFI) {
- MachineBasicBlock::iterator Pos = std::next(GPRCS1Push);
- int CFIIndex;
- for (const auto &Entry : CSI) {
+ if (!NeedsWinCFI) {
+ for (const auto &Entry : reverse(CSI)) {
Register Reg = Entry.getReg();
int FI = Entry.getFrameIdx();
- switch (Reg) {
- case ARM::R8:
- case ARM::R9:
- case ARM::R10:
- case ARM::R11:
- case ARM::R12:
- if (STI.splitFramePushPop(MF))
- break;
- [[fallthrough]];
- case ARM::R0:
- case ARM::R1:
- case ARM::R2:
- case ARM::R3:
- case ARM::R4:
- case ARM::R5:
- case ARM::R6:
- case ARM::R7:
- case ARM::LR:
- CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
- nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
- BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
- .addCFIIndex(CFIIndex)
- .setMIFlags(MachineInstr::FrameSetup);
+ MachineBasicBlock::iterator CFIPos;
+ switch (getSpillArea(Reg, PushPopSplit, AFI->getNumAlignedDPRCS2Regs(),
+ RegInfo)) {
+ case SpillArea::GPRCS1:
+ CFIPos = std::next(GPRCS1Push);
break;
- }
- }
- }
-
- if (GPRCS2Size > 0 && !NeedsWinCFI) {
- MachineBasicBlock::iterator Pos = std::next(GPRCS2Push);
- for (const auto &Entry : CSI) {
- Register Reg = Entry.getReg();
- int FI = Entry.getFrameIdx();
- switch (Reg) {
- case ARM::R8:
- case ARM::R9:
- case ARM::R10:
- case ARM::R11:
- case ARM::R12:
- if (STI.splitFramePushPop(MF)) {
- unsigned DwarfReg = MRI->getDwarfRegNum(
- Reg == ARM::R12 ? ARM::RA_AUTH_CODE : Reg, true);
- int64_t Offset = MFI.getObjectOffset(FI);
- unsigned CFIIndex = MF.addFrameInst(
- MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
- BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
- .addCFIIndex(CFIIndex)
- .setMIFlags(MachineInstr::FrameSetup);
- }
+ case SpillArea::GPRCS2:
+ CFIPos = std::next(GPRCS2Push);
+ break;
+ case SpillArea::DPRCS1:
+ CFIPos = std::next(LastPush);
+ break;
+ case SpillArea::FPCXT:
+ case SpillArea::DPRCS2:
+ // FPCXT and DPRCS2 are not represented in the DWARF info.
break;
}
- }
- }
- if (DPRCSSize > 0 && !NeedsWinCFI) {
- // Since vpush register list cannot have gaps, there may be multiple vpush
- // instructions in the prologue.
- MachineBasicBlock::iterator Pos = std::next(LastPush);
- for (const auto &Entry : CSI) {
- Register Reg = Entry.getReg();
- int FI = Entry.getFrameIdx();
- if ((Reg >= ARM::D0 && Reg <= ARM::D31) &&
- (Reg < ARM::D8 || Reg >= ARM::D8 + AFI->getNumAlignedDPRCS2Regs())) {
- unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
- int64_t Offset = MFI.getObjectOffset(FI);
- unsigned CFIIndex = MF.addFrameInst(
- MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
- BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
+ if (CFIPos.isValid()) {
+ int CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
+ nullptr,
+ MRI->getDwarfRegNum(Reg == ARM::R12 ? ARM::RA_AUTH_CODE : Reg,
+ true),
+ MFI.getObjectOffset(FI)));
+ BuildMI(MBB, CFIPos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
}
@@ -1202,8 +1264,10 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF,
// throughout the process. If we have a frame pointer, it takes over the job
// half-way through, so only the first few .cfi_def_cfa_offset instructions
// actually get emitted.
- if (!NeedsWinCFI)
+ if (!NeedsWinCFI) {
+ LLVM_DEBUG(DefCFAOffsetCandidates.dump());
DefCFAOffsetCandidates.emitDefCFAOffsets(MBB, dl, TII, HasFP);
+ }
if (STI.isTargetELF() && hasFP(MF))
MFI.setOffsetAdjustment(MFI.getOffsetAdjustment() -
@@ -1280,6 +1344,10 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
assert(!AFI->isThumb1OnlyFunction() &&
"This emitEpilogue does not support Thumb1!");
bool isARM = !AFI->isThumbFunction();
+ ARMSubtarget::PushPopSplitVariation PushPopSplit =
+ STI.getPushPopSplitVariation(MF);
+
+ LLVM_DEBUG(dbgs() << "Emitting epilogue for " << MF.getName() << "\n");
// Amount of stack space we reserved next to incoming args for either
// varargs registers or stack arguments in tail calls made by this function.
@@ -1383,7 +1451,8 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
MachineInstr::FrameDestroy);
// Increment past our save areas.
- if (AFI->getGPRCalleeSavedArea2Size() && STI.splitFramePointerPush(MF))
+ if (AFI->getGPRCalleeSavedArea2Size() &&
+ PushPopSplit == ARMSubtarget::SplitR11WindowsSEH)
MBBI++;
if (MBBI != MBB.end() && AFI->getDPRCalleeSavedAreaSize()) {
@@ -1400,7 +1469,8 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
MachineInstr::FrameDestroy);
}
- if (AFI->getGPRCalleeSavedArea2Size() && !STI.splitFramePointerPush(MF))
+ if (AFI->getGPRCalleeSavedArea2Size() &&
+ PushPopSplit != ARMSubtarget::SplitR11WindowsSEH)
MBBI++;
if (AFI->getGPRCalleeSavedArea1Size()) MBBI++;
@@ -1523,9 +1593,8 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
ArrayRef<CalleeSavedInfo> CSI,
unsigned StmOpc, unsigned StrOpc,
- bool NoGap, bool (*Func)(unsigned, bool),
- unsigned NumAlignedDPRCS2Regs,
- unsigned MIFlags) const {
+ bool NoGap,
+ function_ref<bool(unsigned)> Func) const {
MachineFunction &MF = *MBB.getParent();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
@@ -1540,10 +1609,7 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
unsigned LastReg = 0;
for (; i != 0; --i) {
Register Reg = CSI[i-1].getReg();
- if (!(Func)(Reg, STI.splitFramePushPop(MF))) continue;
-
- // D-registers in the aligned area DPRCS2 are NOT spilled here.
- if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs)
+ if (!Func(Reg))
continue;
const MachineRegisterInfo &MRI = MF.getRegInfo();
@@ -1574,7 +1640,7 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
if (Regs.size() > 1 || StrOpc== 0) {
MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(StmOpc), ARM::SP)
.addReg(ARM::SP)
- .setMIFlags(MIFlags)
+ .setMIFlags(MachineInstr::FrameSetup)
.add(predOps(ARMCC::AL));
for (unsigned i = 0, e = Regs.size(); i < e; ++i)
MIB.addReg(Regs[i].first, getKillRegState(Regs[i].second));
@@ -1582,7 +1648,7 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
BuildMI(MBB, MI, DL, TII.get(StrOpc), ARM::SP)
.addReg(Regs[0].first, getKillRegState(Regs[0].second))
.addReg(ARM::SP)
- .setMIFlags(MIFlags)
+ .setMIFlags(MachineInstr::FrameSetup)
.addImm(-4)
.add(predOps(ARMCC::AL));
}
@@ -1601,8 +1667,7 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
MutableArrayRef<CalleeSavedInfo> CSI,
unsigned LdmOpc, unsigned LdrOpc,
bool isVarArg, bool NoGap,
- bool (*Func)(unsigned, bool),
- unsigned NumAlignedDPRCS2Regs) const {
+ function_ref<bool(unsigned)> Func) const {
MachineFunction &MF = *MBB.getParent();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
@@ -1613,6 +1678,8 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
bool isInterrupt = false;
bool isTrap = false;
bool isCmseEntry = false;
+ ARMSubtarget::PushPopSplitVariation PushPopSplit =
+ STI.getPushPopSplitVariation(MF);
if (MBB.end() != MI) {
DL = MI->getDebugLoc();
unsigned RetOpcode = MI->getOpcode();
@@ -1635,15 +1702,13 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
for (; i != 0; --i) {
CalleeSavedInfo &Info = CSI[i-1];
Register Reg = Info.getReg();
- if (!(Func)(Reg, STI.splitFramePushPop(MF))) continue;
-
- // The aligned reloads from area DPRCS2 are not inserted here.
- if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs)
+ if (!Func(Reg))
continue;
+
if (Reg == ARM::LR && !isTailCall && !isVarArg && !isInterrupt &&
!isCmseEntry && !isTrap && AFI->getArgumentStackToRestore() == 0 &&
STI.hasV5TOps() && MBB.succ_empty() && !hasPAC &&
- !STI.splitFramePointerPush(MF)) {
+ PushPopSplit != ARMSubtarget::SplitR11WindowsSEH) {
Reg = ARM::PC;
// Fold the return instruction into the LDM.
DeleteRet = true;
@@ -1983,6 +2048,9 @@ bool ARMFrameLowering::spillCalleeSavedRegisters(
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ ARMSubtarget::PushPopSplitVariation PushPopSplit =
+ STI.getPushPopSplitVariation(MF);
+ const ARMBaseRegisterInfo *RegInfo = STI.getRegisterInfo();
unsigned PushOpc = AFI->isThumbFunction() ? ARM::t2STMDB_UPD : ARM::STMDB_UPD;
unsigned PushOneOpc = AFI->isThumbFunction() ?
@@ -2004,20 +2072,33 @@ bool ARMFrameLowering::spillCalleeSavedRegisters(
.addImm(-4)
.add(predOps(ARMCC::AL));
}
- if (STI.splitFramePointerPush(MF)) {
- emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false,
- &isSplitFPArea1Register, 0, MachineInstr::FrameSetup);
- emitPushInst(MBB, MI, CSI, FltOpc, 0, true, &isARMArea3Register,
- NumAlignedDPRCS2Regs, MachineInstr::FrameSetup);
- emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false,
- &isSplitFPArea2Register, 0, MachineInstr::FrameSetup);
+
+ auto CheckRegArea = [PushPopSplit, NumAlignedDPRCS2Regs,
+ RegInfo](unsigned Reg, SpillArea TestArea) {
+ return getSpillArea(Reg, PushPopSplit, NumAlignedDPRCS2Regs, RegInfo) ==
+ TestArea;
+ };
+ auto IsGPRCS1 = [&CheckRegArea](unsigned Reg) {
+ return CheckRegArea(Reg, SpillArea::GPRCS1);
+ };
+ auto IsGPRCS2 = [&CheckRegArea](unsigned Reg) {
+ return CheckRegArea(Reg, SpillArea::GPRCS2);
+ };
+ auto IsDPRCS1 = [&CheckRegArea](unsigned Reg) {
+ return CheckRegArea(Reg, SpillArea::DPRCS1);
+ };
+
+ // Windows SEH requires the floating-point registers to be pushed between the
+ // two blocks of GPRs in some situations. In all other cases, they are pushed
+ // below the GPRs.
+ if (PushPopSplit == ARMSubtarget::SplitR11WindowsSEH) {
+ emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, IsGPRCS1);
+ emitPushInst(MBB, MI, CSI, FltOpc, 0, true, IsDPRCS1);
+ emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, IsGPRCS2);
} else {
- emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea1Register,
- 0, MachineInstr::FrameSetup);
- emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea2Register,
- 0, MachineInstr::FrameSetup);
- emitPushInst(MBB, MI, CSI, FltOpc, 0, true, &isARMArea3Register,
- NumAlignedDPRCS2Regs, MachineInstr::FrameSetup);
+ emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, IsGPRCS1);
+ emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, IsGPRCS2);
+ emitPushInst(MBB, MI, CSI, FltOpc, 0, true, IsDPRCS1);
}
// The code above does not insert spill code for the aligned DPRCS2 registers.
@@ -2037,8 +2118,12 @@ bool ARMFrameLowering::restoreCalleeSavedRegisters(
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ const ARMBaseRegisterInfo *RegInfo = STI.getRegisterInfo();
+
bool isVarArg = AFI->getArgRegsSaveSize() > 0;
unsigned NumAlignedDPRCS2Regs = AFI->getNumAlignedDPRCS2Regs();
+ ARMSubtarget::PushPopSplitVariation PushPopSplit =
+ STI.getPushPopSplitVariation(MF);
// The emitPopInst calls below do not insert reloads for the aligned DPRCS2
// registers. Do that here instead.
@@ -2049,20 +2134,30 @@ bool ARMFrameLowering::restoreCalleeSavedRegisters(
unsigned LdrOpc =
AFI->isThumbFunction() ? ARM::t2LDR_POST : ARM::LDR_POST_IMM;
unsigned FltOpc = ARM::VLDMDIA_UPD;
- if (STI.splitFramePointerPush(MF)) {
- emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
- &isSplitFPArea2Register, 0);
- emitPopInst(MBB, MI, CSI, FltOpc, 0, isVarArg, true, &isARMArea3Register,
- NumAlignedDPRCS2Regs);
- emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
- &isSplitFPArea1Register, 0);
+
+ auto CheckRegArea = [PushPopSplit, NumAlignedDPRCS2Regs,
+ RegInfo](unsigned Reg, SpillArea TestArea) {
+ return getSpillArea(Reg, PushPopSplit, NumAlignedDPRCS2Regs, RegInfo) ==
+ TestArea;
+ };
+ auto IsGPRCS1 = [&CheckRegArea](unsigned Reg) {
+ return CheckRegArea(Reg, SpillArea::GPRCS1);
+ };
+ auto IsGPRCS2 = [&CheckRegArea](unsigned Reg) {
+ return CheckRegArea(Reg, SpillArea::GPRCS2);
+ };
+ auto IsDPRCS1 = [&CheckRegArea](unsigned Reg) {
+ return CheckRegArea(Reg, SpillArea::DPRCS1);
+ };
+
+ if (PushPopSplit == ARMSubtarget::SplitR11WindowsSEH) {
+ emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, IsGPRCS2);
+ emitPopInst(MBB, MI, CSI, FltOpc, 0, isVarArg, true, IsDPRCS1);
+ emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, IsGPRCS1);
} else {
- emitPopInst(MBB, MI, CSI, FltOpc, 0, isVarArg, true, &isARMArea3Register,
- NumAlignedDPRCS2Regs);
- emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
- &isARMArea2Register, 0);
- emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
- &isARMArea1Register, 0);
+ emitPopInst(MBB, MI, CSI, FltOpc, 0, isVarArg, true, IsDPRCS1);
+ emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, IsGPRCS2);
+ emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, IsGPRCS1);
}
return true;
@@ -2287,6 +2382,8 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
(void)TRI; // Silence unused warning in non-assert builds.
Register FramePtr = RegInfo->getFrameRegister(MF);
+ ARMSubtarget::PushPopSplitVariation PushPopSplit =
+ STI.getPushPopSplitVariation(MF);
// Spill R4 if Thumb2 function requires stack realignment - it will be used as
// scratch register. Also spill R4 if Thumb2 function has varsized objects,
@@ -2365,7 +2462,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
if (Spilled) {
NumGPRSpills++;
- if (!STI.splitFramePushPop(MF)) {
+ if (PushPopSplit != ARMSubtarget::SplitR7) {
if (Reg == ARM::LR)
LRSpilled = true;
CS1Spilled = true;
@@ -2387,7 +2484,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
break;
}
} else {
- if (!STI.splitFramePushPop(MF)) {
+ if (PushPopSplit != ARMSubtarget::SplitR7) {
UnspilledCS1GPRs.push_back(Reg);
continue;
}