xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARM/Thumb1FrameLowering.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===- Thumb1FrameLowering.cpp - Thumb1 Frame Information -----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains the Thumb1 implementation of TargetFrameLowering class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "Thumb1FrameLowering.h"
140b57cec5SDimitry Andric #include "ARMBaseInstrInfo.h"
150b57cec5SDimitry Andric #include "ARMBaseRegisterInfo.h"
160b57cec5SDimitry Andric #include "ARMMachineFunctionInfo.h"
170b57cec5SDimitry Andric #include "ARMSubtarget.h"
180b57cec5SDimitry Andric #include "Thumb1InstrInfo.h"
190b57cec5SDimitry Andric #include "ThumbRegisterInfo.h"
200b57cec5SDimitry Andric #include "Utils/ARMBaseInfo.h"
210b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
220b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
230b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
330b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
340b57cec5SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
350b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
360b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
370b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
380b57cec5SDimitry Andric #include "llvm/MC/MCDwarf.h"
390b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
400b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
410b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
420b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
430b57cec5SDimitry Andric #include <bitset>
440b57cec5SDimitry Andric #include <cassert>
450b57cec5SDimitry Andric #include <iterator>
460b57cec5SDimitry Andric #include <vector>
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric using namespace llvm;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric Thumb1FrameLowering::Thumb1FrameLowering(const ARMSubtarget &sti)
510b57cec5SDimitry Andric     : ARMFrameLowering(sti) {}
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric bool Thumb1FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const{
540b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
550b57cec5SDimitry Andric   unsigned CFSize = MFI.getMaxCallFrameSize();
560b57cec5SDimitry Andric   // It's not always a good idea to include the call frame as part of the
570b57cec5SDimitry Andric   // stack frame. ARM (especially Thumb) has small immediate offset to
580b57cec5SDimitry Andric   // address the stack frame. So a large call frame can cause poor codegen
590b57cec5SDimitry Andric   // and may even makes it impossible to scavenge a register.
600b57cec5SDimitry Andric   if (CFSize >= ((1 << 8) - 1) * 4 / 2) // Half of imm8 * 4
610b57cec5SDimitry Andric     return false;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   return !MFI.hasVarSizedObjects();
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric static void
670b57cec5SDimitry Andric emitPrologueEpilogueSPUpdate(MachineBasicBlock &MBB,
680b57cec5SDimitry Andric                              MachineBasicBlock::iterator &MBBI,
690b57cec5SDimitry Andric                              const TargetInstrInfo &TII, const DebugLoc &dl,
700b57cec5SDimitry Andric                              const ThumbRegisterInfo &MRI, int NumBytes,
710b57cec5SDimitry Andric                              unsigned ScratchReg, unsigned MIFlags) {
720b57cec5SDimitry Andric   // If it would take more than three instructions to adjust the stack pointer
730b57cec5SDimitry Andric   // using tADDspi/tSUBspi, load an immediate instead.
740b57cec5SDimitry Andric   if (std::abs(NumBytes) > 508 * 3) {
750b57cec5SDimitry Andric     // We use a different codepath here from the normal
760b57cec5SDimitry Andric     // emitThumbRegPlusImmediate so we don't have to deal with register
770b57cec5SDimitry Andric     // scavenging. (Scavenging could try to use the emergency spill slot
780b57cec5SDimitry Andric     // before we've actually finished setting up the stack.)
790b57cec5SDimitry Andric     if (ScratchReg == ARM::NoRegister)
800b57cec5SDimitry Andric       report_fatal_error("Failed to emit Thumb1 stack adjustment");
810b57cec5SDimitry Andric     MachineFunction &MF = *MBB.getParent();
820b57cec5SDimitry Andric     const ARMSubtarget &ST = MF.getSubtarget<ARMSubtarget>();
830b57cec5SDimitry Andric     if (ST.genExecuteOnly()) {
84*06c3fb27SDimitry Andric       unsigned XOInstr = ST.useMovt() ? ARM::t2MOVi32imm : ARM::tMOVi32imm;
85*06c3fb27SDimitry Andric       BuildMI(MBB, MBBI, dl, TII.get(XOInstr), ScratchReg)
860b57cec5SDimitry Andric           .addImm(NumBytes).setMIFlags(MIFlags);
870b57cec5SDimitry Andric     } else {
880b57cec5SDimitry Andric       MRI.emitLoadConstPool(MBB, MBBI, dl, ScratchReg, 0, NumBytes, ARMCC::AL,
890b57cec5SDimitry Andric                             0, MIFlags);
900b57cec5SDimitry Andric     }
910b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ARM::tADDhirr), ARM::SP)
925ffd83dbSDimitry Andric         .addReg(ARM::SP)
935ffd83dbSDimitry Andric         .addReg(ScratchReg, RegState::Kill)
945ffd83dbSDimitry Andric         .add(predOps(ARMCC::AL))
955ffd83dbSDimitry Andric         .setMIFlags(MIFlags);
960b57cec5SDimitry Andric     return;
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric   // FIXME: This is assuming the heuristics in emitThumbRegPlusImmediate
990b57cec5SDimitry Andric   // won't change.
1000b57cec5SDimitry Andric   emitThumbRegPlusImmediate(MBB, MBBI, dl, ARM::SP, ARM::SP, NumBytes, TII,
1010b57cec5SDimitry Andric                             MRI, MIFlags);
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric static void emitCallSPUpdate(MachineBasicBlock &MBB,
1060b57cec5SDimitry Andric                              MachineBasicBlock::iterator &MBBI,
1070b57cec5SDimitry Andric                              const TargetInstrInfo &TII, const DebugLoc &dl,
1080b57cec5SDimitry Andric                              const ThumbRegisterInfo &MRI, int NumBytes,
1090b57cec5SDimitry Andric                              unsigned MIFlags = MachineInstr::NoFlags) {
1100b57cec5SDimitry Andric   emitThumbRegPlusImmediate(MBB, MBBI, dl, ARM::SP, ARM::SP, NumBytes, TII,
1110b57cec5SDimitry Andric                             MRI, MIFlags);
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric MachineBasicBlock::iterator Thumb1FrameLowering::
1160b57cec5SDimitry Andric eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
1170b57cec5SDimitry Andric                               MachineBasicBlock::iterator I) const {
1180b57cec5SDimitry Andric   const Thumb1InstrInfo &TII =
1190b57cec5SDimitry Andric       *static_cast<const Thumb1InstrInfo *>(STI.getInstrInfo());
1200b57cec5SDimitry Andric   const ThumbRegisterInfo *RegInfo =
1210b57cec5SDimitry Andric       static_cast<const ThumbRegisterInfo *>(STI.getRegisterInfo());
1220b57cec5SDimitry Andric   if (!hasReservedCallFrame(MF)) {
1230b57cec5SDimitry Andric     // If we have alloca, convert as follows:
1240b57cec5SDimitry Andric     // ADJCALLSTACKDOWN -> sub, sp, sp, amount
1250b57cec5SDimitry Andric     // ADJCALLSTACKUP   -> add, sp, sp, amount
1260b57cec5SDimitry Andric     MachineInstr &Old = *I;
1270b57cec5SDimitry Andric     DebugLoc dl = Old.getDebugLoc();
1280b57cec5SDimitry Andric     unsigned Amount = TII.getFrameSize(Old);
1290b57cec5SDimitry Andric     if (Amount != 0) {
1300b57cec5SDimitry Andric       // We need to keep the stack aligned properly.  To do this, we round the
1310b57cec5SDimitry Andric       // amount of space needed for the outgoing arguments up to the next
1320b57cec5SDimitry Andric       // alignment boundary.
1335ffd83dbSDimitry Andric       Amount = alignTo(Amount, getStackAlign());
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric       // Replace the pseudo instruction with a new instruction...
1360b57cec5SDimitry Andric       unsigned Opc = Old.getOpcode();
1370b57cec5SDimitry Andric       if (Opc == ARM::ADJCALLSTACKDOWN || Opc == ARM::tADJCALLSTACKDOWN) {
1380b57cec5SDimitry Andric         emitCallSPUpdate(MBB, I, TII, dl, *RegInfo, -Amount);
1390b57cec5SDimitry Andric       } else {
1400b57cec5SDimitry Andric         assert(Opc == ARM::ADJCALLSTACKUP || Opc == ARM::tADJCALLSTACKUP);
1410b57cec5SDimitry Andric         emitCallSPUpdate(MBB, I, TII, dl, *RegInfo, Amount);
1420b57cec5SDimitry Andric       }
1430b57cec5SDimitry Andric     }
1440b57cec5SDimitry Andric   }
1450b57cec5SDimitry Andric   return MBB.erase(I);
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
1490b57cec5SDimitry Andric                                        MachineBasicBlock &MBB) const {
1500b57cec5SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.begin();
1510b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
1520b57cec5SDimitry Andric   ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
1530b57cec5SDimitry Andric   MachineModuleInfo &MMI = MF.getMMI();
1540b57cec5SDimitry Andric   const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
1550b57cec5SDimitry Andric   const ThumbRegisterInfo *RegInfo =
1560b57cec5SDimitry Andric       static_cast<const ThumbRegisterInfo *>(STI.getRegisterInfo());
1570b57cec5SDimitry Andric   const Thumb1InstrInfo &TII =
1580b57cec5SDimitry Andric       *static_cast<const Thumb1InstrInfo *>(STI.getInstrInfo());
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize();
1610b57cec5SDimitry Andric   unsigned NumBytes = MFI.getStackSize();
1620b57cec5SDimitry Andric   assert(NumBytes >= ArgRegsSaveSize &&
1630b57cec5SDimitry Andric          "ArgRegsSaveSize is included in NumBytes");
1640b57cec5SDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   // Debug location must be unknown since the first debug location is used
1670b57cec5SDimitry Andric   // to determine the end of the prologue.
1680b57cec5SDimitry Andric   DebugLoc dl;
1690b57cec5SDimitry Andric 
1708bcb0991SDimitry Andric   Register FramePtr = RegInfo->getFrameRegister(MF);
17104eeddc0SDimitry Andric   Register BasePtr = RegInfo->getBaseRegister();
1720b57cec5SDimitry Andric   int CFAOffset = 0;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   // Thumb add/sub sp, imm8 instructions implicitly multiply the offset by 4.
1750b57cec5SDimitry Andric   NumBytes = (NumBytes + 3) & ~3;
1760b57cec5SDimitry Andric   MFI.setStackSize(NumBytes);
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   // Determine the sizes of each callee-save spill areas and record which frame
1790b57cec5SDimitry Andric   // belongs to which callee-save spill areas.
18081ad6265SDimitry Andric   unsigned FRSize = 0, GPRCS1Size = 0, GPRCS2Size = 0, DPRCSSize = 0;
1810b57cec5SDimitry Andric   int FramePtrSpillFI = 0;
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   if (ArgRegsSaveSize) {
1840b57cec5SDimitry Andric     emitPrologueEpilogueSPUpdate(MBB, MBBI, TII, dl, *RegInfo, -ArgRegsSaveSize,
1850b57cec5SDimitry Andric                                  ARM::NoRegister, MachineInstr::FrameSetup);
1865ffd83dbSDimitry Andric     CFAOffset += ArgRegsSaveSize;
1875ffd83dbSDimitry Andric     unsigned CFIIndex =
1885ffd83dbSDimitry Andric         MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, CFAOffset));
1890b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
1900b57cec5SDimitry Andric         .addCFIIndex(CFIIndex)
1910b57cec5SDimitry Andric         .setMIFlags(MachineInstr::FrameSetup);
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   if (!AFI->hasStackFrame()) {
1950b57cec5SDimitry Andric     if (NumBytes - ArgRegsSaveSize != 0) {
1960b57cec5SDimitry Andric       emitPrologueEpilogueSPUpdate(MBB, MBBI, TII, dl, *RegInfo,
1970b57cec5SDimitry Andric                                    -(NumBytes - ArgRegsSaveSize),
1980b57cec5SDimitry Andric                                    ARM::NoRegister, MachineInstr::FrameSetup);
1995ffd83dbSDimitry Andric       CFAOffset += NumBytes - ArgRegsSaveSize;
2000b57cec5SDimitry Andric       unsigned CFIIndex = MF.addFrameInst(
2015ffd83dbSDimitry Andric           MCCFIInstruction::cfiDefCfaOffset(nullptr, CFAOffset));
2020b57cec5SDimitry Andric       BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
2030b57cec5SDimitry Andric           .addCFIIndex(CFIIndex)
2040b57cec5SDimitry Andric           .setMIFlags(MachineInstr::FrameSetup);
2050b57cec5SDimitry Andric     }
2060b57cec5SDimitry Andric     return;
2070b57cec5SDimitry Andric   }
2080b57cec5SDimitry Andric 
20981ad6265SDimitry Andric   bool HasFrameRecordArea = hasFP(MF) && ARM::hGPRRegClass.contains(FramePtr);
21081ad6265SDimitry Andric 
2114824e7fdSDimitry Andric   for (const CalleeSavedInfo &I : CSI) {
21204eeddc0SDimitry Andric     Register Reg = I.getReg();
2134824e7fdSDimitry Andric     int FI = I.getFrameIdx();
21481ad6265SDimitry Andric     if (Reg == FramePtr)
21581ad6265SDimitry Andric       FramePtrSpillFI = FI;
2160b57cec5SDimitry Andric     switch (Reg) {
21781ad6265SDimitry Andric     case ARM::R11:
21881ad6265SDimitry Andric       if (HasFrameRecordArea) {
21981ad6265SDimitry Andric         FRSize += 4;
22081ad6265SDimitry Andric         break;
22181ad6265SDimitry Andric       }
222bdd1243dSDimitry Andric       [[fallthrough]];
2230b57cec5SDimitry Andric     case ARM::R8:
2240b57cec5SDimitry Andric     case ARM::R9:
2250b57cec5SDimitry Andric     case ARM::R10:
2260b57cec5SDimitry Andric       if (STI.splitFramePushPop(MF)) {
2270b57cec5SDimitry Andric         GPRCS2Size += 4;
2280b57cec5SDimitry Andric         break;
2290b57cec5SDimitry Andric       }
230bdd1243dSDimitry Andric       [[fallthrough]];
23181ad6265SDimitry Andric     case ARM::LR:
23281ad6265SDimitry Andric       if (HasFrameRecordArea) {
23381ad6265SDimitry Andric         FRSize += 4;
23481ad6265SDimitry Andric         break;
23581ad6265SDimitry Andric       }
236bdd1243dSDimitry Andric       [[fallthrough]];
2370b57cec5SDimitry Andric     case ARM::R4:
2380b57cec5SDimitry Andric     case ARM::R5:
2390b57cec5SDimitry Andric     case ARM::R6:
2400b57cec5SDimitry Andric     case ARM::R7:
2410b57cec5SDimitry Andric       GPRCS1Size += 4;
2420b57cec5SDimitry Andric       break;
2430b57cec5SDimitry Andric     default:
2440b57cec5SDimitry Andric       DPRCSSize += 8;
2450b57cec5SDimitry Andric     }
2460b57cec5SDimitry Andric   }
2470b57cec5SDimitry Andric 
24881ad6265SDimitry Andric   MachineBasicBlock::iterator FRPush, GPRCS1Push, GPRCS2Push;
24981ad6265SDimitry Andric   if (HasFrameRecordArea) {
25081ad6265SDimitry Andric     // Skip Frame Record setup:
25181ad6265SDimitry Andric     //   push {lr}
25281ad6265SDimitry Andric     //   mov lr, r11
25381ad6265SDimitry Andric     //   push {lr}
25481ad6265SDimitry Andric     std::advance(MBBI, 2);
25581ad6265SDimitry Andric     FRPush = MBBI++;
25681ad6265SDimitry Andric   }
25781ad6265SDimitry Andric 
2580b57cec5SDimitry Andric   if (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tPUSH) {
25981ad6265SDimitry Andric     GPRCS1Push = MBBI;
2600b57cec5SDimitry Andric     ++MBBI;
2610b57cec5SDimitry Andric   }
2620b57cec5SDimitry Andric 
26381ad6265SDimitry Andric   // Find last push instruction for GPRCS2 - spilling of high registers
26481ad6265SDimitry Andric   // (r8-r11) could consist of multiple tPUSH and tMOVr instructions.
26581ad6265SDimitry Andric   while (true) {
26681ad6265SDimitry Andric     MachineBasicBlock::iterator OldMBBI = MBBI;
26781ad6265SDimitry Andric     // Skip a run of tMOVr instructions
26881ad6265SDimitry Andric     while (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tMOVr &&
26981ad6265SDimitry Andric            MBBI->getFlag(MachineInstr::FrameSetup))
27081ad6265SDimitry Andric       MBBI++;
27181ad6265SDimitry Andric     if (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tPUSH &&
27281ad6265SDimitry Andric         MBBI->getFlag(MachineInstr::FrameSetup)) {
27381ad6265SDimitry Andric       GPRCS2Push = MBBI;
27481ad6265SDimitry Andric       MBBI++;
27581ad6265SDimitry Andric     } else {
27681ad6265SDimitry Andric       // We have reached an instruction which is not a push, so the previous
27781ad6265SDimitry Andric       // run of tMOVr instructions (which may have been empty) was not part of
27881ad6265SDimitry Andric       // the prologue. Reset MBBI back to the last PUSH of the prologue.
27981ad6265SDimitry Andric       MBBI = OldMBBI;
28081ad6265SDimitry Andric       break;
28181ad6265SDimitry Andric     }
28281ad6265SDimitry Andric   }
28381ad6265SDimitry Andric 
2840b57cec5SDimitry Andric   // Determine starting offsets of spill areas.
28581ad6265SDimitry Andric   unsigned DPRCSOffset = NumBytes - ArgRegsSaveSize -
28681ad6265SDimitry Andric                          (FRSize + GPRCS1Size + GPRCS2Size + DPRCSSize);
2870b57cec5SDimitry Andric   unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize;
2880b57cec5SDimitry Andric   unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size;
2890b57cec5SDimitry Andric   bool HasFP = hasFP(MF);
2900b57cec5SDimitry Andric   if (HasFP)
2910b57cec5SDimitry Andric     AFI->setFramePtrSpillOffset(MFI.getObjectOffset(FramePtrSpillFI) +
2920b57cec5SDimitry Andric                                 NumBytes);
29381ad6265SDimitry Andric   if (HasFrameRecordArea)
29481ad6265SDimitry Andric     AFI->setFrameRecordSavedAreaSize(FRSize);
2950b57cec5SDimitry Andric   AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset);
2960b57cec5SDimitry Andric   AFI->setGPRCalleeSavedArea2Offset(GPRCS2Offset);
2970b57cec5SDimitry Andric   AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset);
2980b57cec5SDimitry Andric   NumBytes = DPRCSOffset;
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric   int FramePtrOffsetInBlock = 0;
3010b57cec5SDimitry Andric   unsigned adjustedGPRCS1Size = GPRCS1Size;
3020b57cec5SDimitry Andric   if (GPRCS1Size > 0 && GPRCS2Size == 0 &&
30381ad6265SDimitry Andric       tryFoldSPUpdateIntoPushPop(STI, MF, &*(GPRCS1Push), NumBytes)) {
3040b57cec5SDimitry Andric     FramePtrOffsetInBlock = NumBytes;
3050b57cec5SDimitry Andric     adjustedGPRCS1Size += NumBytes;
3060b57cec5SDimitry Andric     NumBytes = 0;
3070b57cec5SDimitry Andric   }
3085ffd83dbSDimitry Andric   CFAOffset += adjustedGPRCS1Size;
30981ad6265SDimitry Andric 
31081ad6265SDimitry Andric   // Adjust FP so it point to the stack slot that contains the previous FP.
31181ad6265SDimitry Andric   if (HasFP) {
31281ad6265SDimitry Andric     MachineBasicBlock::iterator AfterPush =
31381ad6265SDimitry Andric         HasFrameRecordArea ? std::next(FRPush) : std::next(GPRCS1Push);
31481ad6265SDimitry Andric     if (HasFrameRecordArea) {
31581ad6265SDimitry Andric       // We have just finished pushing the previous FP into the stack,
31681ad6265SDimitry Andric       // so simply capture the SP value as the new Frame Pointer.
31781ad6265SDimitry Andric       BuildMI(MBB, AfterPush, dl, TII.get(ARM::tMOVr), FramePtr)
31881ad6265SDimitry Andric           .addReg(ARM::SP)
31981ad6265SDimitry Andric           .setMIFlags(MachineInstr::FrameSetup)
32081ad6265SDimitry Andric           .add(predOps(ARMCC::AL));
32181ad6265SDimitry Andric     } else {
32281ad6265SDimitry Andric       FramePtrOffsetInBlock +=
32381ad6265SDimitry Andric           MFI.getObjectOffset(FramePtrSpillFI) + GPRCS1Size + ArgRegsSaveSize;
32481ad6265SDimitry Andric       BuildMI(MBB, AfterPush, dl, TII.get(ARM::tADDrSPi), FramePtr)
32581ad6265SDimitry Andric           .addReg(ARM::SP)
32681ad6265SDimitry Andric           .addImm(FramePtrOffsetInBlock / 4)
32781ad6265SDimitry Andric           .setMIFlags(MachineInstr::FrameSetup)
32881ad6265SDimitry Andric           .add(predOps(ARMCC::AL));
32981ad6265SDimitry Andric     }
33081ad6265SDimitry Andric 
33181ad6265SDimitry Andric     if(FramePtrOffsetInBlock) {
33281ad6265SDimitry Andric       unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
33381ad6265SDimitry Andric           nullptr, MRI->getDwarfRegNum(FramePtr, true), (CFAOffset - FramePtrOffsetInBlock)));
33481ad6265SDimitry Andric       BuildMI(MBB, AfterPush, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
33581ad6265SDimitry Andric           .addCFIIndex(CFIIndex)
33681ad6265SDimitry Andric           .setMIFlags(MachineInstr::FrameSetup);
33781ad6265SDimitry Andric     } else {
33881ad6265SDimitry Andric       unsigned CFIIndex =
33981ad6265SDimitry Andric           MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
34081ad6265SDimitry Andric               nullptr, MRI->getDwarfRegNum(FramePtr, true)));
34181ad6265SDimitry Andric       BuildMI(MBB, AfterPush, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
34281ad6265SDimitry Andric           .addCFIIndex(CFIIndex)
34381ad6265SDimitry Andric           .setMIFlags(MachineInstr::FrameSetup);
34481ad6265SDimitry Andric     }
34581ad6265SDimitry Andric     if (NumBytes > 508)
34681ad6265SDimitry Andric       // If offset is > 508 then sp cannot be adjusted in a single instruction,
34781ad6265SDimitry Andric       // try restoring from fp instead.
34881ad6265SDimitry Andric       AFI->setShouldRestoreSPFromFP(true);
34981ad6265SDimitry Andric   }
35081ad6265SDimitry Andric 
35181ad6265SDimitry Andric   // Emit call frame information for the callee-saved low registers.
35281ad6265SDimitry Andric   if (GPRCS1Size > 0) {
35381ad6265SDimitry Andric     MachineBasicBlock::iterator Pos = std::next(GPRCS1Push);
35481ad6265SDimitry Andric     if (adjustedGPRCS1Size) {
3555ffd83dbSDimitry Andric       unsigned CFIIndex =
3565ffd83dbSDimitry Andric           MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, CFAOffset));
35781ad6265SDimitry Andric       BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
3580b57cec5SDimitry Andric           .addCFIIndex(CFIIndex)
3590b57cec5SDimitry Andric           .setMIFlags(MachineInstr::FrameSetup);
3600b57cec5SDimitry Andric     }
3614824e7fdSDimitry Andric     for (const CalleeSavedInfo &I : CSI) {
36204eeddc0SDimitry Andric       Register Reg = I.getReg();
3634824e7fdSDimitry Andric       int FI = I.getFrameIdx();
3640b57cec5SDimitry Andric       switch (Reg) {
3650b57cec5SDimitry Andric       case ARM::R8:
3660b57cec5SDimitry Andric       case ARM::R9:
3670b57cec5SDimitry Andric       case ARM::R10:
3680b57cec5SDimitry Andric       case ARM::R11:
3690b57cec5SDimitry Andric       case ARM::R12:
3700b57cec5SDimitry Andric         if (STI.splitFramePushPop(MF))
3710b57cec5SDimitry Andric           break;
372bdd1243dSDimitry Andric         [[fallthrough]];
3730b57cec5SDimitry Andric       case ARM::R0:
3740b57cec5SDimitry Andric       case ARM::R1:
3750b57cec5SDimitry Andric       case ARM::R2:
3760b57cec5SDimitry Andric       case ARM::R3:
3770b57cec5SDimitry Andric       case ARM::R4:
3780b57cec5SDimitry Andric       case ARM::R5:
3790b57cec5SDimitry Andric       case ARM::R6:
3800b57cec5SDimitry Andric       case ARM::R7:
3810b57cec5SDimitry Andric       case ARM::LR:
3820b57cec5SDimitry Andric         unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
3830b57cec5SDimitry Andric             nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
38481ad6265SDimitry Andric         BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
3850b57cec5SDimitry Andric             .addCFIIndex(CFIIndex)
3860b57cec5SDimitry Andric             .setMIFlags(MachineInstr::FrameSetup);
3870b57cec5SDimitry Andric         break;
3880b57cec5SDimitry Andric       }
3890b57cec5SDimitry Andric     }
3900b57cec5SDimitry Andric   }
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   // Emit call frame information for the callee-saved high registers.
39381ad6265SDimitry Andric   if (GPRCS2Size > 0) {
39481ad6265SDimitry Andric     MachineBasicBlock::iterator Pos = std::next(GPRCS2Push);
3950b57cec5SDimitry Andric     for (auto &I : CSI) {
39604eeddc0SDimitry Andric       Register Reg = I.getReg();
3970b57cec5SDimitry Andric       int FI = I.getFrameIdx();
3980b57cec5SDimitry Andric       switch (Reg) {
3990b57cec5SDimitry Andric       case ARM::R8:
4000b57cec5SDimitry Andric       case ARM::R9:
4010b57cec5SDimitry Andric       case ARM::R10:
4020b57cec5SDimitry Andric       case ARM::R11:
4030b57cec5SDimitry Andric       case ARM::R12: {
4040b57cec5SDimitry Andric         unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
4050b57cec5SDimitry Andric             nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
40681ad6265SDimitry Andric         BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
4070b57cec5SDimitry Andric             .addCFIIndex(CFIIndex)
4080b57cec5SDimitry Andric             .setMIFlags(MachineInstr::FrameSetup);
4090b57cec5SDimitry Andric         break;
4100b57cec5SDimitry Andric       }
4110b57cec5SDimitry Andric       default:
4120b57cec5SDimitry Andric         break;
4130b57cec5SDimitry Andric       }
4140b57cec5SDimitry Andric     }
41581ad6265SDimitry Andric   }
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric   if (NumBytes) {
4180b57cec5SDimitry Andric     // Insert it after all the callee-save spills.
4190b57cec5SDimitry Andric     //
4200b57cec5SDimitry Andric     // For a large stack frame, we might need a scratch register to store
4210b57cec5SDimitry Andric     // the size of the frame.  We know all callee-save registers are free
4220b57cec5SDimitry Andric     // at this point in the prologue, so pick one.
4230b57cec5SDimitry Andric     unsigned ScratchRegister = ARM::NoRegister;
4240b57cec5SDimitry Andric     for (auto &I : CSI) {
42504eeddc0SDimitry Andric       Register Reg = I.getReg();
4260b57cec5SDimitry Andric       if (isARMLowRegister(Reg) && !(HasFP && Reg == FramePtr)) {
4270b57cec5SDimitry Andric         ScratchRegister = Reg;
4280b57cec5SDimitry Andric         break;
4290b57cec5SDimitry Andric       }
4300b57cec5SDimitry Andric     }
4310b57cec5SDimitry Andric     emitPrologueEpilogueSPUpdate(MBB, MBBI, TII, dl, *RegInfo, -NumBytes,
4320b57cec5SDimitry Andric                                  ScratchRegister, MachineInstr::FrameSetup);
4330b57cec5SDimitry Andric     if (!HasFP) {
4345ffd83dbSDimitry Andric       CFAOffset += NumBytes;
4350b57cec5SDimitry Andric       unsigned CFIIndex = MF.addFrameInst(
4365ffd83dbSDimitry Andric           MCCFIInstruction::cfiDefCfaOffset(nullptr, CFAOffset));
4370b57cec5SDimitry Andric       BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
4380b57cec5SDimitry Andric           .addCFIIndex(CFIIndex)
4390b57cec5SDimitry Andric           .setMIFlags(MachineInstr::FrameSetup);
4400b57cec5SDimitry Andric     }
4410b57cec5SDimitry Andric   }
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric   if (STI.isTargetELF() && HasFP)
4440b57cec5SDimitry Andric     MFI.setOffsetAdjustment(MFI.getOffsetAdjustment() -
4450b57cec5SDimitry Andric                             AFI->getFramePtrSpillOffset());
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric   AFI->setGPRCalleeSavedArea1Size(GPRCS1Size);
4480b57cec5SDimitry Andric   AFI->setGPRCalleeSavedArea2Size(GPRCS2Size);
4490b57cec5SDimitry Andric   AFI->setDPRCalleeSavedAreaSize(DPRCSSize);
4500b57cec5SDimitry Andric 
451fe6060f1SDimitry Andric   if (RegInfo->hasStackRealignment(MF)) {
4525ffd83dbSDimitry Andric     const unsigned NrBitsToZero = Log2(MFI.getMaxAlign());
4530b57cec5SDimitry Andric     // Emit the following sequence, using R4 as a temporary, since we cannot use
4540b57cec5SDimitry Andric     // SP as a source or destination register for the shifts:
4550b57cec5SDimitry Andric     // mov  r4, sp
4560b57cec5SDimitry Andric     // lsrs r4, r4, #NrBitsToZero
4570b57cec5SDimitry Andric     // lsls r4, r4, #NrBitsToZero
4580b57cec5SDimitry Andric     // mov  sp, r4
4590b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), ARM::R4)
4600b57cec5SDimitry Andric       .addReg(ARM::SP, RegState::Kill)
4610b57cec5SDimitry Andric       .add(predOps(ARMCC::AL));
4620b57cec5SDimitry Andric 
4630b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ARM::tLSRri), ARM::R4)
4640b57cec5SDimitry Andric       .addDef(ARM::CPSR)
4650b57cec5SDimitry Andric       .addReg(ARM::R4, RegState::Kill)
4660b57cec5SDimitry Andric       .addImm(NrBitsToZero)
4670b57cec5SDimitry Andric       .add(predOps(ARMCC::AL));
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ARM::tLSLri), ARM::R4)
4700b57cec5SDimitry Andric       .addDef(ARM::CPSR)
4710b57cec5SDimitry Andric       .addReg(ARM::R4, RegState::Kill)
4720b57cec5SDimitry Andric       .addImm(NrBitsToZero)
4730b57cec5SDimitry Andric       .add(predOps(ARMCC::AL));
4740b57cec5SDimitry Andric 
4750b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), ARM::SP)
4760b57cec5SDimitry Andric       .addReg(ARM::R4, RegState::Kill)
4770b57cec5SDimitry Andric       .add(predOps(ARMCC::AL));
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric     AFI->setShouldRestoreSPFromFP(true);
4800b57cec5SDimitry Andric   }
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric   // If we need a base pointer, set it up here. It's whatever the value
4830b57cec5SDimitry Andric   // of the stack pointer is at this point. Any variable size objects
4840b57cec5SDimitry Andric   // will be allocated after this, so we can still use the base pointer
4850b57cec5SDimitry Andric   // to reference locals.
4860b57cec5SDimitry Andric   if (RegInfo->hasBasePointer(MF))
4870b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), BasePtr)
4880b57cec5SDimitry Andric         .addReg(ARM::SP)
4890b57cec5SDimitry Andric         .add(predOps(ARMCC::AL));
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric   // If the frame has variable sized objects then the epilogue must restore
4920b57cec5SDimitry Andric   // the sp from fp. We can assume there's an FP here since hasFP already
4930b57cec5SDimitry Andric   // checks for hasVarSizedObjects.
4940b57cec5SDimitry Andric   if (MFI.hasVarSizedObjects())
4950b57cec5SDimitry Andric     AFI->setShouldRestoreSPFromFP(true);
4960b57cec5SDimitry Andric 
4970b57cec5SDimitry Andric   // In some cases, virtual registers have been introduced, e.g. by uses of
4980b57cec5SDimitry Andric   // emitThumbRegPlusImmInReg.
4990b57cec5SDimitry Andric   MF.getProperties().reset(MachineFunctionProperties::Property::NoVRegs);
5000b57cec5SDimitry Andric }
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric void Thumb1FrameLowering::emitEpilogue(MachineFunction &MF,
5030b57cec5SDimitry Andric                                    MachineBasicBlock &MBB) const {
5040b57cec5SDimitry Andric   MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
5050b57cec5SDimitry Andric   DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
5060b57cec5SDimitry Andric   MachineFrameInfo &MFI = MF.getFrameInfo();
5070b57cec5SDimitry Andric   ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
5080b57cec5SDimitry Andric   const ThumbRegisterInfo *RegInfo =
5090b57cec5SDimitry Andric       static_cast<const ThumbRegisterInfo *>(STI.getRegisterInfo());
5100b57cec5SDimitry Andric   const Thumb1InstrInfo &TII =
5110b57cec5SDimitry Andric       *static_cast<const Thumb1InstrInfo *>(STI.getInstrInfo());
5120b57cec5SDimitry Andric 
5130b57cec5SDimitry Andric   unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize();
5140b57cec5SDimitry Andric   int NumBytes = (int)MFI.getStackSize();
5150b57cec5SDimitry Andric   assert((unsigned)NumBytes >= ArgRegsSaveSize &&
5160b57cec5SDimitry Andric          "ArgRegsSaveSize is included in NumBytes");
5178bcb0991SDimitry Andric   Register FramePtr = RegInfo->getFrameRegister(MF);
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   if (!AFI->hasStackFrame()) {
5200b57cec5SDimitry Andric     if (NumBytes - ArgRegsSaveSize != 0)
5210b57cec5SDimitry Andric       emitPrologueEpilogueSPUpdate(MBB, MBBI, TII, dl, *RegInfo,
5220b57cec5SDimitry Andric                                    NumBytes - ArgRegsSaveSize, ARM::NoRegister,
52381ad6265SDimitry Andric                                    MachineInstr::FrameDestroy);
5240b57cec5SDimitry Andric   } else {
5250b57cec5SDimitry Andric     // Unwind MBBI to point to first LDR / VLDRD.
5260b57cec5SDimitry Andric     if (MBBI != MBB.begin()) {
5270b57cec5SDimitry Andric       do
5280b57cec5SDimitry Andric         --MBBI;
52981ad6265SDimitry Andric       while (MBBI != MBB.begin() && MBBI->getFlag(MachineInstr::FrameDestroy));
53081ad6265SDimitry Andric       if (!MBBI->getFlag(MachineInstr::FrameDestroy))
5310b57cec5SDimitry Andric         ++MBBI;
5320b57cec5SDimitry Andric     }
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric     // Move SP to start of FP callee save spill area.
53581ad6265SDimitry Andric     NumBytes -= (AFI->getFrameRecordSavedAreaSize() +
53681ad6265SDimitry Andric                  AFI->getGPRCalleeSavedArea1Size() +
5370b57cec5SDimitry Andric                  AFI->getGPRCalleeSavedArea2Size() +
5380b57cec5SDimitry Andric                  AFI->getDPRCalleeSavedAreaSize() +
5390b57cec5SDimitry Andric                  ArgRegsSaveSize);
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric     if (AFI->shouldRestoreSPFromFP()) {
5420b57cec5SDimitry Andric       NumBytes = AFI->getFramePtrSpillOffset() - NumBytes;
5430b57cec5SDimitry Andric       // Reset SP based on frame pointer only if the stack frame extends beyond
5440b57cec5SDimitry Andric       // frame pointer stack slot, the target is ELF and the function has FP, or
5450b57cec5SDimitry Andric       // the target uses var sized objects.
5460b57cec5SDimitry Andric       if (NumBytes) {
5470b57cec5SDimitry Andric         assert(!MFI.getPristineRegs(MF).test(ARM::R4) &&
5480b57cec5SDimitry Andric                "No scratch register to restore SP from FP!");
5490b57cec5SDimitry Andric         emitThumbRegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes,
55081ad6265SDimitry Andric                                   TII, *RegInfo, MachineInstr::FrameDestroy);
5510b57cec5SDimitry Andric         BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), ARM::SP)
5520b57cec5SDimitry Andric             .addReg(ARM::R4)
55381ad6265SDimitry Andric             .add(predOps(ARMCC::AL))
55481ad6265SDimitry Andric             .setMIFlag(MachineInstr::FrameDestroy);
5550b57cec5SDimitry Andric       } else
5560b57cec5SDimitry Andric         BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), ARM::SP)
5570b57cec5SDimitry Andric             .addReg(FramePtr)
55881ad6265SDimitry Andric             .add(predOps(ARMCC::AL))
55981ad6265SDimitry Andric             .setMIFlag(MachineInstr::FrameDestroy);
5600b57cec5SDimitry Andric     } else {
5610b57cec5SDimitry Andric       // For a large stack frame, we might need a scratch register to store
5620b57cec5SDimitry Andric       // the size of the frame.  We know all callee-save registers are free
5630b57cec5SDimitry Andric       // at this point in the epilogue, so pick one.
5640b57cec5SDimitry Andric       unsigned ScratchRegister = ARM::NoRegister;
5650b57cec5SDimitry Andric       bool HasFP = hasFP(MF);
5660b57cec5SDimitry Andric       for (auto &I : MFI.getCalleeSavedInfo()) {
56704eeddc0SDimitry Andric         Register Reg = I.getReg();
5680b57cec5SDimitry Andric         if (isARMLowRegister(Reg) && !(HasFP && Reg == FramePtr)) {
5690b57cec5SDimitry Andric           ScratchRegister = Reg;
5700b57cec5SDimitry Andric           break;
5710b57cec5SDimitry Andric         }
5720b57cec5SDimitry Andric       }
5730b57cec5SDimitry Andric       if (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tBX_RET &&
5740b57cec5SDimitry Andric           &MBB.front() != &*MBBI && std::prev(MBBI)->getOpcode() == ARM::tPOP) {
5750b57cec5SDimitry Andric         MachineBasicBlock::iterator PMBBI = std::prev(MBBI);
5760b57cec5SDimitry Andric         if (!tryFoldSPUpdateIntoPushPop(STI, MF, &*PMBBI, NumBytes))
5770b57cec5SDimitry Andric           emitPrologueEpilogueSPUpdate(MBB, PMBBI, TII, dl, *RegInfo, NumBytes,
57881ad6265SDimitry Andric                                        ScratchRegister, MachineInstr::FrameDestroy);
5790b57cec5SDimitry Andric       } else if (!tryFoldSPUpdateIntoPushPop(STI, MF, &*MBBI, NumBytes))
5800b57cec5SDimitry Andric         emitPrologueEpilogueSPUpdate(MBB, MBBI, TII, dl, *RegInfo, NumBytes,
58181ad6265SDimitry Andric                                      ScratchRegister, MachineInstr::FrameDestroy);
5820b57cec5SDimitry Andric     }
5830b57cec5SDimitry Andric   }
5840b57cec5SDimitry Andric 
5850b57cec5SDimitry Andric   if (needPopSpecialFixUp(MF)) {
5860b57cec5SDimitry Andric     bool Done = emitPopSpecialFixUp(MBB, /* DoIt */ true);
5870b57cec5SDimitry Andric     (void)Done;
5880b57cec5SDimitry Andric     assert(Done && "Emission of the special fixup failed!?");
5890b57cec5SDimitry Andric   }
5900b57cec5SDimitry Andric }
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric bool Thumb1FrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
5930b57cec5SDimitry Andric   if (!needPopSpecialFixUp(*MBB.getParent()))
5940b57cec5SDimitry Andric     return true;
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric   MachineBasicBlock *TmpMBB = const_cast<MachineBasicBlock *>(&MBB);
5970b57cec5SDimitry Andric   return emitPopSpecialFixUp(*TmpMBB, /* DoIt */ false);
5980b57cec5SDimitry Andric }
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric bool Thumb1FrameLowering::needPopSpecialFixUp(const MachineFunction &MF) const {
6010b57cec5SDimitry Andric   ARMFunctionInfo *AFI =
6020b57cec5SDimitry Andric       const_cast<MachineFunction *>(&MF)->getInfo<ARMFunctionInfo>();
6030b57cec5SDimitry Andric   if (AFI->getArgRegsSaveSize())
6040b57cec5SDimitry Andric     return true;
6050b57cec5SDimitry Andric 
6060b57cec5SDimitry Andric   // LR cannot be encoded with Thumb1, i.e., it requires a special fix-up.
6070b57cec5SDimitry Andric   for (const CalleeSavedInfo &CSI : MF.getFrameInfo().getCalleeSavedInfo())
6080b57cec5SDimitry Andric     if (CSI.getReg() == ARM::LR)
6090b57cec5SDimitry Andric       return true;
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric   return false;
6120b57cec5SDimitry Andric }
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric static void findTemporariesForLR(const BitVector &GPRsNoLRSP,
6150b57cec5SDimitry Andric                                  const BitVector &PopFriendly,
6160b57cec5SDimitry Andric                                  const LivePhysRegs &UsedRegs, unsigned &PopReg,
617349cc55cSDimitry Andric                                  unsigned &TmpReg, MachineRegisterInfo &MRI) {
6180b57cec5SDimitry Andric   PopReg = TmpReg = 0;
6190b57cec5SDimitry Andric   for (auto Reg : GPRsNoLRSP.set_bits()) {
620349cc55cSDimitry Andric     if (UsedRegs.available(MRI, Reg)) {
6210b57cec5SDimitry Andric       // Remember the first pop-friendly register and exit.
6220b57cec5SDimitry Andric       if (PopFriendly.test(Reg)) {
6230b57cec5SDimitry Andric         PopReg = Reg;
6240b57cec5SDimitry Andric         TmpReg = 0;
6250b57cec5SDimitry Andric         break;
6260b57cec5SDimitry Andric       }
6270b57cec5SDimitry Andric       // Otherwise, remember that the register will be available to
6280b57cec5SDimitry Andric       // save a pop-friendly register.
6290b57cec5SDimitry Andric       TmpReg = Reg;
6300b57cec5SDimitry Andric     }
6310b57cec5SDimitry Andric   }
6320b57cec5SDimitry Andric }
6330b57cec5SDimitry Andric 
6340b57cec5SDimitry Andric bool Thumb1FrameLowering::emitPopSpecialFixUp(MachineBasicBlock &MBB,
6350b57cec5SDimitry Andric                                               bool DoIt) const {
6360b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
6370b57cec5SDimitry Andric   ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
6380b57cec5SDimitry Andric   unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize();
6390b57cec5SDimitry Andric   const TargetInstrInfo &TII = *STI.getInstrInfo();
6400b57cec5SDimitry Andric   const ThumbRegisterInfo *RegInfo =
6410b57cec5SDimitry Andric       static_cast<const ThumbRegisterInfo *>(STI.getRegisterInfo());
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric   // If MBBI is a return instruction, or is a tPOP followed by a return
6440b57cec5SDimitry Andric   // instruction in the successor BB, we may be able to directly restore
6450b57cec5SDimitry Andric   // LR in the PC.
6460b57cec5SDimitry Andric   // This is only possible with v5T ops (v4T can't change the Thumb bit via
6470b57cec5SDimitry Andric   // a POP PC instruction), and only if we do not need to emit any SP update.
6480b57cec5SDimitry Andric   // Otherwise, we need a temporary register to pop the value
6490b57cec5SDimitry Andric   // and copy that value into LR.
6500b57cec5SDimitry Andric   auto MBBI = MBB.getFirstTerminator();
6510b57cec5SDimitry Andric   bool CanRestoreDirectly = STI.hasV5TOps() && !ArgRegsSaveSize;
6520b57cec5SDimitry Andric   if (CanRestoreDirectly) {
6530b57cec5SDimitry Andric     if (MBBI != MBB.end() && MBBI->getOpcode() != ARM::tB)
6540b57cec5SDimitry Andric       CanRestoreDirectly = (MBBI->getOpcode() == ARM::tBX_RET ||
6550b57cec5SDimitry Andric                             MBBI->getOpcode() == ARM::tPOP_RET);
6560b57cec5SDimitry Andric     else {
6570b57cec5SDimitry Andric       auto MBBI_prev = MBBI;
6580b57cec5SDimitry Andric       MBBI_prev--;
6590b57cec5SDimitry Andric       assert(MBBI_prev->getOpcode() == ARM::tPOP);
6600b57cec5SDimitry Andric       assert(MBB.succ_size() == 1);
6610b57cec5SDimitry Andric       if ((*MBB.succ_begin())->begin()->getOpcode() == ARM::tBX_RET)
6620b57cec5SDimitry Andric         MBBI = MBBI_prev; // Replace the final tPOP with a tPOP_RET.
6630b57cec5SDimitry Andric       else
6640b57cec5SDimitry Andric         CanRestoreDirectly = false;
6650b57cec5SDimitry Andric     }
6660b57cec5SDimitry Andric   }
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric   if (CanRestoreDirectly) {
6690b57cec5SDimitry Andric     if (!DoIt || MBBI->getOpcode() == ARM::tPOP_RET)
6700b57cec5SDimitry Andric       return true;
6710b57cec5SDimitry Andric     MachineInstrBuilder MIB =
6720b57cec5SDimitry Andric         BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII.get(ARM::tPOP_RET))
67381ad6265SDimitry Andric             .add(predOps(ARMCC::AL))
67481ad6265SDimitry Andric             .setMIFlag(MachineInstr::FrameDestroy);
6750b57cec5SDimitry Andric     // Copy implicit ops and popped registers, if any.
6760b57cec5SDimitry Andric     for (auto MO: MBBI->operands())
6770b57cec5SDimitry Andric       if (MO.isReg() && (MO.isImplicit() || MO.isDef()))
6780b57cec5SDimitry Andric         MIB.add(MO);
6790b57cec5SDimitry Andric     MIB.addReg(ARM::PC, RegState::Define);
6800b57cec5SDimitry Andric     // Erase the old instruction (tBX_RET or tPOP).
6810b57cec5SDimitry Andric     MBB.erase(MBBI);
6820b57cec5SDimitry Andric     return true;
6830b57cec5SDimitry Andric   }
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric   // Look for a temporary register to use.
6860b57cec5SDimitry Andric   // First, compute the liveness information.
6870b57cec5SDimitry Andric   const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
6880b57cec5SDimitry Andric   LivePhysRegs UsedRegs(TRI);
6890b57cec5SDimitry Andric   UsedRegs.addLiveOuts(MBB);
6900b57cec5SDimitry Andric   // The semantic of pristines changed recently and now,
6910b57cec5SDimitry Andric   // the callee-saved registers that are touched in the function
6920b57cec5SDimitry Andric   // are not part of the pristines set anymore.
6930b57cec5SDimitry Andric   // Add those callee-saved now.
6940b57cec5SDimitry Andric   const MCPhysReg *CSRegs = TRI.getCalleeSavedRegs(&MF);
6950b57cec5SDimitry Andric   for (unsigned i = 0; CSRegs[i]; ++i)
6960b57cec5SDimitry Andric     UsedRegs.addReg(CSRegs[i]);
6970b57cec5SDimitry Andric 
6980b57cec5SDimitry Andric   DebugLoc dl = DebugLoc();
6990b57cec5SDimitry Andric   if (MBBI != MBB.end()) {
7000b57cec5SDimitry Andric     dl = MBBI->getDebugLoc();
7010b57cec5SDimitry Andric     auto InstUpToMBBI = MBB.end();
7020b57cec5SDimitry Andric     while (InstUpToMBBI != MBBI)
7030b57cec5SDimitry Andric       // The pre-decrement is on purpose here.
7040b57cec5SDimitry Andric       // We want to have the liveness right before MBBI.
7050b57cec5SDimitry Andric       UsedRegs.stepBackward(*--InstUpToMBBI);
7060b57cec5SDimitry Andric   }
7070b57cec5SDimitry Andric 
7080b57cec5SDimitry Andric   // Look for a register that can be directly use in the POP.
7090b57cec5SDimitry Andric   unsigned PopReg = 0;
7100b57cec5SDimitry Andric   // And some temporary register, just in case.
7110b57cec5SDimitry Andric   unsigned TemporaryReg = 0;
7120b57cec5SDimitry Andric   BitVector PopFriendly =
7130b57cec5SDimitry Andric       TRI.getAllocatableSet(MF, TRI.getRegClass(ARM::tGPRRegClassID));
7140b57cec5SDimitry Andric   // R7 may be used as a frame pointer, hence marked as not generally
7150b57cec5SDimitry Andric   // allocatable, however there's no reason to not use it as a temporary for
7160b57cec5SDimitry Andric   // restoring LR.
717fe6060f1SDimitry Andric   if (STI.getFramePointerReg() == ARM::R7)
7180b57cec5SDimitry Andric     PopFriendly.set(ARM::R7);
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric   assert(PopFriendly.any() && "No allocatable pop-friendly register?!");
7210b57cec5SDimitry Andric   // Rebuild the GPRs from the high registers because they are removed
7220b57cec5SDimitry Andric   // form the GPR reg class for thumb1.
7230b57cec5SDimitry Andric   BitVector GPRsNoLRSP =
7240b57cec5SDimitry Andric       TRI.getAllocatableSet(MF, TRI.getRegClass(ARM::hGPRRegClassID));
7250b57cec5SDimitry Andric   GPRsNoLRSP |= PopFriendly;
7260b57cec5SDimitry Andric   GPRsNoLRSP.reset(ARM::LR);
7270b57cec5SDimitry Andric   GPRsNoLRSP.reset(ARM::SP);
7280b57cec5SDimitry Andric   GPRsNoLRSP.reset(ARM::PC);
729349cc55cSDimitry Andric   findTemporariesForLR(GPRsNoLRSP, PopFriendly, UsedRegs, PopReg, TemporaryReg,
730349cc55cSDimitry Andric                        MF.getRegInfo());
7310b57cec5SDimitry Andric 
7320b57cec5SDimitry Andric   // If we couldn't find a pop-friendly register, try restoring LR before
7330b57cec5SDimitry Andric   // popping the other callee-saved registers, so we could use one of them as a
7340b57cec5SDimitry Andric   // temporary.
7350b57cec5SDimitry Andric   bool UseLDRSP = false;
7360b57cec5SDimitry Andric   if (!PopReg && MBBI != MBB.begin()) {
7370b57cec5SDimitry Andric     auto PrevMBBI = MBBI;
7380b57cec5SDimitry Andric     PrevMBBI--;
7390b57cec5SDimitry Andric     if (PrevMBBI->getOpcode() == ARM::tPOP) {
7400b57cec5SDimitry Andric       UsedRegs.stepBackward(*PrevMBBI);
741349cc55cSDimitry Andric       findTemporariesForLR(GPRsNoLRSP, PopFriendly, UsedRegs, PopReg,
742349cc55cSDimitry Andric                            TemporaryReg, MF.getRegInfo());
7430b57cec5SDimitry Andric       if (PopReg) {
7440b57cec5SDimitry Andric         MBBI = PrevMBBI;
7450b57cec5SDimitry Andric         UseLDRSP = true;
7460b57cec5SDimitry Andric       }
7470b57cec5SDimitry Andric     }
7480b57cec5SDimitry Andric   }
7490b57cec5SDimitry Andric 
7500b57cec5SDimitry Andric   if (!DoIt && !PopReg && !TemporaryReg)
7510b57cec5SDimitry Andric     return false;
7520b57cec5SDimitry Andric 
7530b57cec5SDimitry Andric   assert((PopReg || TemporaryReg) && "Cannot get LR");
7540b57cec5SDimitry Andric 
7550b57cec5SDimitry Andric   if (UseLDRSP) {
7560b57cec5SDimitry Andric     assert(PopReg && "Do not know how to get LR");
7570b57cec5SDimitry Andric     // Load the LR via LDR tmp, [SP, #off]
7580b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ARM::tLDRspi))
7590b57cec5SDimitry Andric       .addReg(PopReg, RegState::Define)
7600b57cec5SDimitry Andric       .addReg(ARM::SP)
7610b57cec5SDimitry Andric       .addImm(MBBI->getNumExplicitOperands() - 2)
76281ad6265SDimitry Andric       .add(predOps(ARMCC::AL))
76381ad6265SDimitry Andric       .setMIFlag(MachineInstr::FrameDestroy);
7640b57cec5SDimitry Andric     // Move from the temporary register to the LR.
7650b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr))
7660b57cec5SDimitry Andric       .addReg(ARM::LR, RegState::Define)
7670b57cec5SDimitry Andric       .addReg(PopReg, RegState::Kill)
76881ad6265SDimitry Andric       .add(predOps(ARMCC::AL))
76981ad6265SDimitry Andric       .setMIFlag(MachineInstr::FrameDestroy);
7700b57cec5SDimitry Andric     // Advance past the pop instruction.
7710b57cec5SDimitry Andric     MBBI++;
7720b57cec5SDimitry Andric     // Increment the SP.
7730b57cec5SDimitry Andric     emitPrologueEpilogueSPUpdate(MBB, MBBI, TII, dl, *RegInfo,
7740b57cec5SDimitry Andric                                  ArgRegsSaveSize + 4, ARM::NoRegister,
77581ad6265SDimitry Andric                                  MachineInstr::FrameDestroy);
7760b57cec5SDimitry Andric     return true;
7770b57cec5SDimitry Andric   }
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric   if (TemporaryReg) {
7800b57cec5SDimitry Andric     assert(!PopReg && "Unnecessary MOV is about to be inserted");
7810b57cec5SDimitry Andric     PopReg = PopFriendly.find_first();
7820b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr))
7830b57cec5SDimitry Andric         .addReg(TemporaryReg, RegState::Define)
7840b57cec5SDimitry Andric         .addReg(PopReg, RegState::Kill)
78581ad6265SDimitry Andric         .add(predOps(ARMCC::AL))
78681ad6265SDimitry Andric         .setMIFlag(MachineInstr::FrameDestroy);
7870b57cec5SDimitry Andric   }
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric   if (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tPOP_RET) {
7900b57cec5SDimitry Andric     // We couldn't use the direct restoration above, so
7910b57cec5SDimitry Andric     // perform the opposite conversion: tPOP_RET to tPOP.
7920b57cec5SDimitry Andric     MachineInstrBuilder MIB =
7930b57cec5SDimitry Andric         BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII.get(ARM::tPOP))
79481ad6265SDimitry Andric             .add(predOps(ARMCC::AL))
79581ad6265SDimitry Andric             .setMIFlag(MachineInstr::FrameDestroy);
7960b57cec5SDimitry Andric     bool Popped = false;
7970b57cec5SDimitry Andric     for (auto MO: MBBI->operands())
7980b57cec5SDimitry Andric       if (MO.isReg() && (MO.isImplicit() || MO.isDef()) &&
7990b57cec5SDimitry Andric           MO.getReg() != ARM::PC) {
8000b57cec5SDimitry Andric         MIB.add(MO);
8010b57cec5SDimitry Andric         if (!MO.isImplicit())
8020b57cec5SDimitry Andric           Popped = true;
8030b57cec5SDimitry Andric       }
8040b57cec5SDimitry Andric     // Is there anything left to pop?
8050b57cec5SDimitry Andric     if (!Popped)
8060b57cec5SDimitry Andric       MBB.erase(MIB.getInstr());
8070b57cec5SDimitry Andric     // Erase the old instruction.
8080b57cec5SDimitry Andric     MBB.erase(MBBI);
8090b57cec5SDimitry Andric     MBBI = BuildMI(MBB, MBB.end(), dl, TII.get(ARM::tBX_RET))
81081ad6265SDimitry Andric                .add(predOps(ARMCC::AL))
81181ad6265SDimitry Andric                .setMIFlag(MachineInstr::FrameDestroy);
8120b57cec5SDimitry Andric   }
8130b57cec5SDimitry Andric 
8140b57cec5SDimitry Andric   assert(PopReg && "Do not know how to get LR");
8150b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII.get(ARM::tPOP))
8160b57cec5SDimitry Andric       .add(predOps(ARMCC::AL))
81781ad6265SDimitry Andric       .addReg(PopReg, RegState::Define)
81881ad6265SDimitry Andric       .setMIFlag(MachineInstr::FrameDestroy);
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric   emitPrologueEpilogueSPUpdate(MBB, MBBI, TII, dl, *RegInfo, ArgRegsSaveSize,
82181ad6265SDimitry Andric                                ARM::NoRegister, MachineInstr::FrameDestroy);
8220b57cec5SDimitry Andric 
8230b57cec5SDimitry Andric   BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr))
8240b57cec5SDimitry Andric       .addReg(ARM::LR, RegState::Define)
8250b57cec5SDimitry Andric       .addReg(PopReg, RegState::Kill)
82681ad6265SDimitry Andric       .add(predOps(ARMCC::AL))
82781ad6265SDimitry Andric       .setMIFlag(MachineInstr::FrameDestroy);
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric   if (TemporaryReg)
8300b57cec5SDimitry Andric     BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr))
8310b57cec5SDimitry Andric         .addReg(PopReg, RegState::Define)
8320b57cec5SDimitry Andric         .addReg(TemporaryReg, RegState::Kill)
83381ad6265SDimitry Andric         .add(predOps(ARMCC::AL))
83481ad6265SDimitry Andric         .setMIFlag(MachineInstr::FrameDestroy);
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric   return true;
8370b57cec5SDimitry Andric }
8380b57cec5SDimitry Andric 
83981ad6265SDimitry Andric static const SmallVector<Register> OrderedLowRegs = {ARM::R4, ARM::R5, ARM::R6,
84081ad6265SDimitry Andric                                                      ARM::R7, ARM::LR};
84181ad6265SDimitry Andric static const SmallVector<Register> OrderedHighRegs = {ARM::R8, ARM::R9,
84281ad6265SDimitry Andric                                                       ARM::R10, ARM::R11};
84381ad6265SDimitry Andric static const SmallVector<Register> OrderedCopyRegs = {
84481ad6265SDimitry Andric     ARM::R0, ARM::R1, ARM::R2, ARM::R3, ARM::R4,
84581ad6265SDimitry Andric     ARM::R5, ARM::R6, ARM::R7, ARM::LR};
8460b57cec5SDimitry Andric 
84781ad6265SDimitry Andric static void splitLowAndHighRegs(const std::set<Register> &Regs,
84881ad6265SDimitry Andric                                 std::set<Register> &LowRegs,
84981ad6265SDimitry Andric                                 std::set<Register> &HighRegs) {
85081ad6265SDimitry Andric   for (Register Reg : Regs) {
8510b57cec5SDimitry Andric     if (ARM::tGPRRegClass.contains(Reg) || Reg == ARM::LR) {
85281ad6265SDimitry Andric       LowRegs.insert(Reg);
8530b57cec5SDimitry Andric     } else if (ARM::hGPRRegClass.contains(Reg) && Reg != ARM::LR) {
85481ad6265SDimitry Andric       HighRegs.insert(Reg);
8550b57cec5SDimitry Andric     } else {
8560b57cec5SDimitry Andric       llvm_unreachable("callee-saved register of unexpected class");
8570b57cec5SDimitry Andric     }
85881ad6265SDimitry Andric   }
8590b57cec5SDimitry Andric }
8600b57cec5SDimitry Andric 
86181ad6265SDimitry Andric template <typename It>
86281ad6265SDimitry Andric It getNextOrderedReg(It OrderedStartIt, It OrderedEndIt,
86381ad6265SDimitry Andric                      const std::set<Register> &RegSet) {
86481ad6265SDimitry Andric   return std::find_if(OrderedStartIt, OrderedEndIt,
86581ad6265SDimitry Andric                       [&](Register Reg) { return RegSet.count(Reg); });
86681ad6265SDimitry Andric }
8670b57cec5SDimitry Andric 
86881ad6265SDimitry Andric static void pushRegsToStack(MachineBasicBlock &MBB,
86981ad6265SDimitry Andric                             MachineBasicBlock::iterator MI,
87081ad6265SDimitry Andric                             const TargetInstrInfo &TII,
87181ad6265SDimitry Andric                             const std::set<Register> &RegsToSave,
87281ad6265SDimitry Andric                             const std::set<Register> &CopyRegs) {
87381ad6265SDimitry Andric   MachineFunction &MF = *MBB.getParent();
8740b57cec5SDimitry Andric   const MachineRegisterInfo &MRI = MF.getRegInfo();
87581ad6265SDimitry Andric   DebugLoc DL;
87681ad6265SDimitry Andric 
87781ad6265SDimitry Andric   std::set<Register> LowRegs, HighRegs;
87881ad6265SDimitry Andric   splitLowAndHighRegs(RegsToSave, LowRegs, HighRegs);
87981ad6265SDimitry Andric 
88081ad6265SDimitry Andric   // Push low regs first
88181ad6265SDimitry Andric   if (!LowRegs.empty()) {
8820b57cec5SDimitry Andric     MachineInstrBuilder MIB =
8830b57cec5SDimitry Andric         BuildMI(MBB, MI, DL, TII.get(ARM::tPUSH)).add(predOps(ARMCC::AL));
88481ad6265SDimitry Andric     for (unsigned Reg : OrderedLowRegs) {
88581ad6265SDimitry Andric       if (LowRegs.count(Reg)) {
8860b57cec5SDimitry Andric         bool isKill = !MRI.isLiveIn(Reg);
8870b57cec5SDimitry Andric         if (isKill && !MRI.isReserved(Reg))
8880b57cec5SDimitry Andric           MBB.addLiveIn(Reg);
8890b57cec5SDimitry Andric 
8900b57cec5SDimitry Andric         MIB.addReg(Reg, getKillRegState(isKill));
8910b57cec5SDimitry Andric       }
8920b57cec5SDimitry Andric     }
8930b57cec5SDimitry Andric     MIB.setMIFlags(MachineInstr::FrameSetup);
8940b57cec5SDimitry Andric   }
8950b57cec5SDimitry Andric 
89681ad6265SDimitry Andric   // Now push the high registers
89781ad6265SDimitry Andric   // There are no store instructions that can access high registers directly,
89881ad6265SDimitry Andric   // so we have to move them to low registers, and push them.
89981ad6265SDimitry Andric   // This might take multiple pushes, as it is possible for there to
9000b57cec5SDimitry Andric   // be fewer low registers available than high registers which need saving.
9010b57cec5SDimitry Andric 
90281ad6265SDimitry Andric   // Find the first register to save.
90381ad6265SDimitry Andric   // Registers must be processed in reverse order so that in case we need to use
9040b57cec5SDimitry Andric   // multiple PUSH instructions, the order of the registers on the stack still
9050b57cec5SDimitry Andric   // matches the unwind info. They need to be swicthed back to ascending order
9060b57cec5SDimitry Andric   // before adding to the PUSH instruction.
90781ad6265SDimitry Andric   auto HiRegToSave = getNextOrderedReg(OrderedHighRegs.rbegin(),
90881ad6265SDimitry Andric                                        OrderedHighRegs.rend(),
90981ad6265SDimitry Andric                                        HighRegs);
9100b57cec5SDimitry Andric 
91181ad6265SDimitry Andric   while (HiRegToSave != OrderedHighRegs.rend()) {
9120b57cec5SDimitry Andric     // Find the first low register to use.
91381ad6265SDimitry Andric     auto CopyRegIt = getNextOrderedReg(OrderedCopyRegs.rbegin(),
91481ad6265SDimitry Andric                                        OrderedCopyRegs.rend(),
91581ad6265SDimitry Andric                                        CopyRegs);
9160b57cec5SDimitry Andric 
9170b57cec5SDimitry Andric     // Create the PUSH, but don't insert it yet (the MOVs need to come first).
9180b57cec5SDimitry Andric     MachineInstrBuilder PushMIB = BuildMI(MF, DL, TII.get(ARM::tPUSH))
9190b57cec5SDimitry Andric                                       .add(predOps(ARMCC::AL))
9200b57cec5SDimitry Andric                                       .setMIFlags(MachineInstr::FrameSetup);
9210b57cec5SDimitry Andric 
9220b57cec5SDimitry Andric     SmallVector<unsigned, 4> RegsToPush;
92381ad6265SDimitry Andric     while (HiRegToSave != OrderedHighRegs.rend() &&
92481ad6265SDimitry Andric            CopyRegIt != OrderedCopyRegs.rend()) {
92581ad6265SDimitry Andric       if (HighRegs.count(*HiRegToSave)) {
9260b57cec5SDimitry Andric         bool isKill = !MRI.isLiveIn(*HiRegToSave);
9270b57cec5SDimitry Andric         if (isKill && !MRI.isReserved(*HiRegToSave))
9280b57cec5SDimitry Andric           MBB.addLiveIn(*HiRegToSave);
9290b57cec5SDimitry Andric 
9300b57cec5SDimitry Andric         // Emit a MOV from the high reg to the low reg.
9310b57cec5SDimitry Andric         BuildMI(MBB, MI, DL, TII.get(ARM::tMOVr))
93281ad6265SDimitry Andric             .addReg(*CopyRegIt, RegState::Define)
9330b57cec5SDimitry Andric             .addReg(*HiRegToSave, getKillRegState(isKill))
9340b57cec5SDimitry Andric             .add(predOps(ARMCC::AL))
9350b57cec5SDimitry Andric             .setMIFlags(MachineInstr::FrameSetup);
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric         // Record the register that must be added to the PUSH.
93881ad6265SDimitry Andric         RegsToPush.push_back(*CopyRegIt);
9390b57cec5SDimitry Andric 
94081ad6265SDimitry Andric         CopyRegIt = getNextOrderedReg(std::next(CopyRegIt),
94181ad6265SDimitry Andric                                       OrderedCopyRegs.rend(),
94281ad6265SDimitry Andric                                       CopyRegs);
94381ad6265SDimitry Andric         HiRegToSave = getNextOrderedReg(std::next(HiRegToSave),
94481ad6265SDimitry Andric                                         OrderedHighRegs.rend(),
94581ad6265SDimitry Andric                                         HighRegs);
9460b57cec5SDimitry Andric       }
9470b57cec5SDimitry Andric     }
9480b57cec5SDimitry Andric 
9490b57cec5SDimitry Andric     // Add the low registers to the PUSH, in ascending order.
9500b57cec5SDimitry Andric     for (unsigned Reg : llvm::reverse(RegsToPush))
9510b57cec5SDimitry Andric       PushMIB.addReg(Reg, RegState::Kill);
9520b57cec5SDimitry Andric 
9530b57cec5SDimitry Andric     // Insert the PUSH instruction after the MOVs.
9540b57cec5SDimitry Andric     MBB.insert(MI, PushMIB);
9550b57cec5SDimitry Andric   }
9560b57cec5SDimitry Andric }
9570b57cec5SDimitry Andric 
95881ad6265SDimitry Andric static void popRegsFromStack(MachineBasicBlock &MBB,
95981ad6265SDimitry Andric                              MachineBasicBlock::iterator &MI,
96081ad6265SDimitry Andric                              const TargetInstrInfo &TII,
96181ad6265SDimitry Andric                              const std::set<Register> &RegsToRestore,
96281ad6265SDimitry Andric                              const std::set<Register> &AvailableCopyRegs,
96381ad6265SDimitry Andric                              bool IsVarArg, bool HasV5Ops) {
96481ad6265SDimitry Andric   if (RegsToRestore.empty())
96581ad6265SDimitry Andric     return;
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric   MachineFunction &MF = *MBB.getParent();
9680b57cec5SDimitry Andric   ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
9690b57cec5SDimitry Andric   DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
9700b57cec5SDimitry Andric 
97181ad6265SDimitry Andric   std::set<Register> LowRegs, HighRegs;
97281ad6265SDimitry Andric   splitLowAndHighRegs(RegsToRestore, LowRegs, HighRegs);
9730b57cec5SDimitry Andric 
97481ad6265SDimitry Andric   // Pop the high registers first
97581ad6265SDimitry Andric   // There are no store instructions that can access high registers directly,
97681ad6265SDimitry Andric   // so we have to pop into low registers and them move to  the high registers.
97781ad6265SDimitry Andric   // This might take multiple pops, as it is possible for there to
97881ad6265SDimitry Andric   // be fewer low registers available than high registers which need restoring.
9790b57cec5SDimitry Andric 
9800b57cec5SDimitry Andric   // Find the first register to restore.
98181ad6265SDimitry Andric   auto HiRegToRestore = getNextOrderedReg(OrderedHighRegs.begin(),
98281ad6265SDimitry Andric                                           OrderedHighRegs.end(),
98381ad6265SDimitry Andric                                           HighRegs);
9840b57cec5SDimitry Andric 
98581ad6265SDimitry Andric   std::set<Register> CopyRegs = AvailableCopyRegs;
98681ad6265SDimitry Andric   Register LowScratchReg;
98781ad6265SDimitry Andric   if (!HighRegs.empty() && CopyRegs.empty()) {
98881ad6265SDimitry Andric     // No copy regs are available to pop high regs. Let's make use of a return
98981ad6265SDimitry Andric     // register and the scratch register (IP/R12) to copy things around.
99081ad6265SDimitry Andric     LowScratchReg = ARM::R0;
99181ad6265SDimitry Andric     BuildMI(MBB, MI, DL, TII.get(ARM::tMOVr))
99281ad6265SDimitry Andric         .addReg(ARM::R12, RegState::Define)
99381ad6265SDimitry Andric         .addReg(LowScratchReg, RegState::Kill)
99481ad6265SDimitry Andric         .add(predOps(ARMCC::AL))
99581ad6265SDimitry Andric         .setMIFlag(MachineInstr::FrameDestroy);
99681ad6265SDimitry Andric     CopyRegs.insert(LowScratchReg);
99781ad6265SDimitry Andric   }
99881ad6265SDimitry Andric 
99981ad6265SDimitry Andric   while (HiRegToRestore != OrderedHighRegs.end()) {
100081ad6265SDimitry Andric     assert(!CopyRegs.empty());
10010b57cec5SDimitry Andric     // Find the first low register to use.
100281ad6265SDimitry Andric     auto CopyReg = getNextOrderedReg(OrderedCopyRegs.begin(),
100381ad6265SDimitry Andric                                      OrderedCopyRegs.end(),
100481ad6265SDimitry Andric                                      CopyRegs);
10050b57cec5SDimitry Andric 
10060b57cec5SDimitry Andric     // Create the POP instruction.
100781ad6265SDimitry Andric     MachineInstrBuilder PopMIB = BuildMI(MBB, MI, DL, TII.get(ARM::tPOP))
100881ad6265SDimitry Andric                                      .add(predOps(ARMCC::AL))
100981ad6265SDimitry Andric                                      .setMIFlag(MachineInstr::FrameDestroy);
10100b57cec5SDimitry Andric 
101181ad6265SDimitry Andric     while (HiRegToRestore != OrderedHighRegs.end() &&
101281ad6265SDimitry Andric            CopyReg != OrderedCopyRegs.end()) {
10130b57cec5SDimitry Andric       // Add the low register to the POP.
10140b57cec5SDimitry Andric       PopMIB.addReg(*CopyReg, RegState::Define);
10150b57cec5SDimitry Andric 
10160b57cec5SDimitry Andric       // Create the MOV from low to high register.
10170b57cec5SDimitry Andric       BuildMI(MBB, MI, DL, TII.get(ARM::tMOVr))
10180b57cec5SDimitry Andric           .addReg(*HiRegToRestore, RegState::Define)
10190b57cec5SDimitry Andric           .addReg(*CopyReg, RegState::Kill)
102081ad6265SDimitry Andric           .add(predOps(ARMCC::AL))
102181ad6265SDimitry Andric           .setMIFlag(MachineInstr::FrameDestroy);
10220b57cec5SDimitry Andric 
102381ad6265SDimitry Andric       CopyReg = getNextOrderedReg(std::next(CopyReg),
102481ad6265SDimitry Andric                                   OrderedCopyRegs.end(),
102581ad6265SDimitry Andric                                   CopyRegs);
102681ad6265SDimitry Andric       HiRegToRestore = getNextOrderedReg(std::next(HiRegToRestore),
102781ad6265SDimitry Andric                                          OrderedHighRegs.end(),
102881ad6265SDimitry Andric                                          HighRegs);
10290b57cec5SDimitry Andric     }
10300b57cec5SDimitry Andric   }
10310b57cec5SDimitry Andric 
103281ad6265SDimitry Andric   // Restore low register used as scratch if necessary
103381ad6265SDimitry Andric   if (LowScratchReg.isValid()) {
103481ad6265SDimitry Andric     BuildMI(MBB, MI, DL, TII.get(ARM::tMOVr))
103581ad6265SDimitry Andric         .addReg(LowScratchReg, RegState::Define)
103681ad6265SDimitry Andric         .addReg(ARM::R12, RegState::Kill)
103781ad6265SDimitry Andric         .add(predOps(ARMCC::AL))
103881ad6265SDimitry Andric         .setMIFlag(MachineInstr::FrameDestroy);
103981ad6265SDimitry Andric   }
104081ad6265SDimitry Andric 
104181ad6265SDimitry Andric   // Now pop the low registers
104281ad6265SDimitry Andric   if (!LowRegs.empty()) {
104381ad6265SDimitry Andric     MachineInstrBuilder MIB = BuildMI(MF, DL, TII.get(ARM::tPOP))
104481ad6265SDimitry Andric                                   .add(predOps(ARMCC::AL))
104581ad6265SDimitry Andric                                   .setMIFlag(MachineInstr::FrameDestroy);
10460b57cec5SDimitry Andric 
10470b57cec5SDimitry Andric     bool NeedsPop = false;
104881ad6265SDimitry Andric     for (Register Reg : OrderedLowRegs) {
104981ad6265SDimitry Andric       if (!LowRegs.count(Reg))
10500b57cec5SDimitry Andric         continue;
10510b57cec5SDimitry Andric 
10520b57cec5SDimitry Andric       if (Reg == ARM::LR) {
10530b57cec5SDimitry Andric         if (!MBB.succ_empty() ||
10540b57cec5SDimitry Andric             MI->getOpcode() == ARM::TCRETURNdi ||
10550b57cec5SDimitry Andric             MI->getOpcode() == ARM::TCRETURNri)
10560b57cec5SDimitry Andric           // LR may only be popped into PC, as part of return sequence.
10570b57cec5SDimitry Andric           // If this isn't the return sequence, we'll need emitPopSpecialFixUp
10580b57cec5SDimitry Andric           // to restore LR the hard way.
10590b57cec5SDimitry Andric           // FIXME: if we don't pass any stack arguments it would be actually
10600b57cec5SDimitry Andric           // advantageous *and* correct to do the conversion to an ordinary call
10610b57cec5SDimitry Andric           // instruction here.
10620b57cec5SDimitry Andric           continue;
10630b57cec5SDimitry Andric         // Special epilogue for vararg functions. See emitEpilogue
106481ad6265SDimitry Andric         if (IsVarArg)
10650b57cec5SDimitry Andric           continue;
10660b57cec5SDimitry Andric         // ARMv4T requires BX, see emitEpilogue
106781ad6265SDimitry Andric         if (!HasV5Ops)
10680b57cec5SDimitry Andric           continue;
10690b57cec5SDimitry Andric 
10705ffd83dbSDimitry Andric         // CMSE entry functions must return via BXNS, see emitEpilogue.
10715ffd83dbSDimitry Andric         if (AFI->isCmseNSEntryFunction())
10725ffd83dbSDimitry Andric           continue;
10735ffd83dbSDimitry Andric 
10740b57cec5SDimitry Andric         // Pop LR into PC.
10750b57cec5SDimitry Andric         Reg = ARM::PC;
10760b57cec5SDimitry Andric         (*MIB).setDesc(TII.get(ARM::tPOP_RET));
10770b57cec5SDimitry Andric         if (MI != MBB.end())
10780b57cec5SDimitry Andric           MIB.copyImplicitOps(*MI);
10790b57cec5SDimitry Andric         MI = MBB.erase(MI);
10800b57cec5SDimitry Andric       }
10810b57cec5SDimitry Andric       MIB.addReg(Reg, getDefRegState(true));
10820b57cec5SDimitry Andric       NeedsPop = true;
10830b57cec5SDimitry Andric     }
10840b57cec5SDimitry Andric 
10850b57cec5SDimitry Andric     // It's illegal to emit pop instruction without operands.
10860b57cec5SDimitry Andric     if (NeedsPop)
10870b57cec5SDimitry Andric       MBB.insert(MI, &*MIB);
10880b57cec5SDimitry Andric     else
10890eae32dcSDimitry Andric       MF.deleteMachineInstr(MIB);
109081ad6265SDimitry Andric   }
109181ad6265SDimitry Andric }
109281ad6265SDimitry Andric 
109381ad6265SDimitry Andric bool Thumb1FrameLowering::spillCalleeSavedRegisters(
109481ad6265SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
109581ad6265SDimitry Andric     ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
109681ad6265SDimitry Andric   if (CSI.empty())
109781ad6265SDimitry Andric     return false;
109881ad6265SDimitry Andric 
109981ad6265SDimitry Andric   const TargetInstrInfo &TII = *STI.getInstrInfo();
110081ad6265SDimitry Andric   MachineFunction &MF = *MBB.getParent();
110181ad6265SDimitry Andric   const ARMBaseRegisterInfo *RegInfo = static_cast<const ARMBaseRegisterInfo *>(
110281ad6265SDimitry Andric       MF.getSubtarget().getRegisterInfo());
110381ad6265SDimitry Andric   Register FPReg = RegInfo->getFrameRegister(MF);
110481ad6265SDimitry Andric 
110581ad6265SDimitry Andric   // In case FP is a high reg, we need a separate push sequence to generate
110681ad6265SDimitry Andric   // a correct Frame Record
110781ad6265SDimitry Andric   bool NeedsFrameRecordPush = hasFP(MF) && ARM::hGPRRegClass.contains(FPReg);
110881ad6265SDimitry Andric 
110981ad6265SDimitry Andric   std::set<Register> FrameRecord;
111081ad6265SDimitry Andric   std::set<Register> SpilledGPRs;
111181ad6265SDimitry Andric   for (const CalleeSavedInfo &I : CSI) {
111281ad6265SDimitry Andric     Register Reg = I.getReg();
111381ad6265SDimitry Andric     if (NeedsFrameRecordPush && (Reg == FPReg || Reg == ARM::LR))
111481ad6265SDimitry Andric       FrameRecord.insert(Reg);
111581ad6265SDimitry Andric     else
111681ad6265SDimitry Andric       SpilledGPRs.insert(Reg);
111781ad6265SDimitry Andric   }
111881ad6265SDimitry Andric 
111981ad6265SDimitry Andric   pushRegsToStack(MBB, MI, TII, FrameRecord, {ARM::LR});
112081ad6265SDimitry Andric 
112181ad6265SDimitry Andric   // Determine intermediate registers which can be used for pushing high regs:
112281ad6265SDimitry Andric   // - Spilled low regs
112381ad6265SDimitry Andric   // - Unused argument registers
112481ad6265SDimitry Andric   std::set<Register> CopyRegs;
112581ad6265SDimitry Andric   for (Register Reg : SpilledGPRs)
112681ad6265SDimitry Andric     if ((ARM::tGPRRegClass.contains(Reg) || Reg == ARM::LR) &&
112781ad6265SDimitry Andric         !MF.getRegInfo().isLiveIn(Reg) && !(hasFP(MF) && Reg == FPReg))
112881ad6265SDimitry Andric       CopyRegs.insert(Reg);
112981ad6265SDimitry Andric   for (unsigned ArgReg : {ARM::R0, ARM::R1, ARM::R2, ARM::R3})
113081ad6265SDimitry Andric     if (!MF.getRegInfo().isLiveIn(ArgReg))
113181ad6265SDimitry Andric       CopyRegs.insert(ArgReg);
113281ad6265SDimitry Andric 
113381ad6265SDimitry Andric   pushRegsToStack(MBB, MI, TII, SpilledGPRs, CopyRegs);
113481ad6265SDimitry Andric 
113581ad6265SDimitry Andric   return true;
113681ad6265SDimitry Andric }
113781ad6265SDimitry Andric 
113881ad6265SDimitry Andric bool Thumb1FrameLowering::restoreCalleeSavedRegisters(
113981ad6265SDimitry Andric     MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
114081ad6265SDimitry Andric     MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
114181ad6265SDimitry Andric   if (CSI.empty())
114281ad6265SDimitry Andric     return false;
114381ad6265SDimitry Andric 
114481ad6265SDimitry Andric   MachineFunction &MF = *MBB.getParent();
114581ad6265SDimitry Andric   ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
114681ad6265SDimitry Andric   const TargetInstrInfo &TII = *STI.getInstrInfo();
114781ad6265SDimitry Andric   const ARMBaseRegisterInfo *RegInfo = static_cast<const ARMBaseRegisterInfo *>(
114881ad6265SDimitry Andric       MF.getSubtarget().getRegisterInfo());
114981ad6265SDimitry Andric   bool IsVarArg = AFI->getArgRegsSaveSize() > 0;
115081ad6265SDimitry Andric   Register FPReg = RegInfo->getFrameRegister(MF);
115181ad6265SDimitry Andric 
115281ad6265SDimitry Andric   // In case FP is a high reg, we need a separate pop sequence to generate
115381ad6265SDimitry Andric   // a correct Frame Record
115481ad6265SDimitry Andric   bool NeedsFrameRecordPop = hasFP(MF) && ARM::hGPRRegClass.contains(FPReg);
115581ad6265SDimitry Andric 
115681ad6265SDimitry Andric   std::set<Register> FrameRecord;
115781ad6265SDimitry Andric   std::set<Register> SpilledGPRs;
115881ad6265SDimitry Andric   for (CalleeSavedInfo &I : CSI) {
115981ad6265SDimitry Andric     Register Reg = I.getReg();
116081ad6265SDimitry Andric     if (NeedsFrameRecordPop && (Reg == FPReg || Reg == ARM::LR))
116181ad6265SDimitry Andric       FrameRecord.insert(Reg);
116281ad6265SDimitry Andric     else
116381ad6265SDimitry Andric       SpilledGPRs.insert(Reg);
116481ad6265SDimitry Andric 
116581ad6265SDimitry Andric     if (Reg == ARM::LR)
116681ad6265SDimitry Andric       I.setRestored(false);
116781ad6265SDimitry Andric   }
116881ad6265SDimitry Andric 
116981ad6265SDimitry Andric   // Determine intermidiate registers which can be used for popping high regs:
117081ad6265SDimitry Andric   // - Spilled low regs
117181ad6265SDimitry Andric   // - Unused return registers
117281ad6265SDimitry Andric   std::set<Register> CopyRegs;
117381ad6265SDimitry Andric   std::set<Register> UnusedReturnRegs;
117481ad6265SDimitry Andric   for (Register Reg : SpilledGPRs)
117581ad6265SDimitry Andric     if ((ARM::tGPRRegClass.contains(Reg)) && !(hasFP(MF) && Reg == FPReg))
117681ad6265SDimitry Andric       CopyRegs.insert(Reg);
117781ad6265SDimitry Andric   auto Terminator = MBB.getFirstTerminator();
117881ad6265SDimitry Andric   if (Terminator != MBB.end() && Terminator->getOpcode() == ARM::tBX_RET) {
117981ad6265SDimitry Andric     UnusedReturnRegs.insert(ARM::R0);
118081ad6265SDimitry Andric     UnusedReturnRegs.insert(ARM::R1);
118181ad6265SDimitry Andric     UnusedReturnRegs.insert(ARM::R2);
118281ad6265SDimitry Andric     UnusedReturnRegs.insert(ARM::R3);
118381ad6265SDimitry Andric     for (auto Op : Terminator->implicit_operands()) {
118481ad6265SDimitry Andric       if (Op.isReg())
118581ad6265SDimitry Andric         UnusedReturnRegs.erase(Op.getReg());
118681ad6265SDimitry Andric     }
118781ad6265SDimitry Andric   }
118881ad6265SDimitry Andric   CopyRegs.insert(UnusedReturnRegs.begin(), UnusedReturnRegs.end());
118981ad6265SDimitry Andric 
119081ad6265SDimitry Andric   // First pop regular spilled regs.
119181ad6265SDimitry Andric   popRegsFromStack(MBB, MI, TII, SpilledGPRs, CopyRegs, IsVarArg,
119281ad6265SDimitry Andric                    STI.hasV5TOps());
119381ad6265SDimitry Andric 
119481ad6265SDimitry Andric   // LR may only be popped into pc, as part of a return sequence.
119581ad6265SDimitry Andric   // Check that no other pop instructions are inserted after that.
119681ad6265SDimitry Andric   assert((!SpilledGPRs.count(ARM::LR) || FrameRecord.empty()) &&
119781ad6265SDimitry Andric          "Can't insert pop after return sequence");
119881ad6265SDimitry Andric 
119981ad6265SDimitry Andric   // Now pop Frame Record regs.
120081ad6265SDimitry Andric   // Only unused return registers can be used as copy regs at this point.
120181ad6265SDimitry Andric   popRegsFromStack(MBB, MI, TII, FrameRecord, UnusedReturnRegs, IsVarArg,
120281ad6265SDimitry Andric                    STI.hasV5TOps());
12030b57cec5SDimitry Andric 
12040b57cec5SDimitry Andric   return true;
12050b57cec5SDimitry Andric }
1206