43#define DEBUG_TYPE "arm-frame-lowering"
57 if (CFSize >= ((1 << 8) - 1) * 4 / 2)
68 unsigned ScratchReg,
unsigned MIFlags) {
71 if (std::abs(NumBytes) > 508 * 3) {
76 if (ScratchReg == ARM::NoRegister)
80 if (ST.genExecuteOnly()) {
81 unsigned XOInstr = ST.useMovt() ? ARM::t2MOVi32imm : ARM::tMOVi32imm;
125 unsigned Amount =
TII.getFrameSize(Old);
134 if (
Opc == ARM::ADJCALLSTACKDOWN ||
Opc == ARM::tADJCALLSTACKDOWN) {
137 assert(
Opc == ARM::ADJCALLSTACKUP ||
Opc == ARM::tADJCALLSTACKUP);
157 assert(NumBytes >= ArgRegsSaveSize &&
158 "ArgRegsSaveSize is included in NumBytes");
161 "Must use R7 spilt for Thumb1");
168 Register BasePtr = RegInfo->getBaseRegister();
172 NumBytes = (NumBytes + 3) & ~3;
177 unsigned FRSize = 0, GPRCS1Size = 0, GPRCS2Size = 0, DPRCSSize = 0;
178 int FramePtrSpillFI = 0;
181 if (ArgRegsSaveSize) {
184 CFAOffset += ArgRegsSaveSize;
189 if (NumBytes - ArgRegsSaveSize != 0) {
191 -(NumBytes - ArgRegsSaveSize),
193 CFAOffset += NumBytes - ArgRegsSaveSize;
199 bool HasFrameRecordArea =
hasFP(MF) && ARM::hGPRRegClass.contains(
FramePtr);
203 int FI =
I.getFrameIdx();
205 FramePtrSpillFI = FI;
208 if (HasFrameRecordArea) {
219 if (HasFrameRecordArea) {
236 if (HasFrameRecordArea) {
241 std::advance(
MBBI, 2);
279 MBBI->getOperand(0).getReg() == ARM::LR &&
286 unsigned DPRCSOffset = NumBytes - ArgRegsSaveSize -
287 (FRSize + GPRCS1Size + GPRCS2Size + DPRCSSize);
288 unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize;
289 unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size;
290 bool HasFP =
hasFP(MF);
294 if (HasFrameRecordArea)
299 NumBytes = DPRCSOffset;
301 int FramePtrOffsetInBlock = 0;
302 unsigned adjustedGPRCS1Size = GPRCS1Size;
303 if (GPRCS1Size > 0 && GPRCS2Size == 0 &&
305 FramePtrOffsetInBlock = NumBytes;
306 adjustedGPRCS1Size += NumBytes;
309 CFAOffset += adjustedGPRCS1Size;
314 HasFrameRecordArea ? std::next(FRPush) : std::next(GPRCS1Push);
315 if (HasFrameRecordArea) {
323 FramePtrOffsetInBlock +=
327 .
addImm(FramePtrOffsetInBlock / 4)
333 if (FramePtrOffsetInBlock)
344 if (GPRCS1Size > 0) {
346 if (adjustedGPRCS1Size)
349 switch (
I.getReg()) {
373 if (GPRCS2Size > 0) {
375 for (
auto &
I : CSI) {
376 switch (
I.getReg()) {
397 unsigned ScratchRegister = ARM::NoRegister;
398 for (
auto &
I : CSI) {
401 ScratchRegister = Reg;
408 CFAOffset += NumBytes;
421 if (RegInfo->hasStackRealignment(MF)) {
456 if (RegInfo->hasBasePointer(MF))
485 assert((
unsigned)NumBytes >= ArgRegsSaveSize &&
486 "ArgRegsSaveSize is included in NumBytes");
490 if (NumBytes - ArgRegsSaveSize != 0)
492 NumBytes - ArgRegsSaveSize, ARM::NoRegister,
512 unsigned ScratchRegister = ARM::NoRegister;
513 bool HasFP =
hasFP(MF);
517 ScratchRegister = Reg;
528 assert(ScratchRegister != ARM::NoRegister &&
529 "No scratch register to restore SP from FP!");
554 if (needPopSpecialFixUp(MF)) {
555 bool Done = emitPopSpecialFixUp(
MBB,
true);
557 assert(
Done &&
"Emission of the special fixup failed!?");
566 return emitPopSpecialFixUp(*TmpMBB,
false);
569bool Thumb1FrameLowering::needPopSpecialFixUp(
const MachineFunction &MF)
const {
577 if (CSI.getReg() == ARM::LR)
588 for (
auto Reg : GPRsNoLRSP.
set_bits()) {
591 if (PopFriendly.
test(Reg)) {
620 bool CanRestoreDirectly =
STI.hasV5TOps() && !ArgRegsSaveSize;
621 if (CanRestoreDirectly) {
623 CanRestoreDirectly = (
MBBI->getOpcode() == ARM::tBX_RET ||
624 MBBI->getOpcode() == ARM::tPOP_RET);
626 auto MBBI_prev =
MBBI;
628 assert(MBBI_prev->getOpcode() == ARM::tPOP);
630 if ((*
MBB.
succ_begin())->begin()->getOpcode() == ARM::tBX_RET)
633 CanRestoreDirectly =
false;
637 if (CanRestoreDirectly) {
638 if (!DoIt ||
MBBI->getOpcode() == ARM::tPOP_RET)
645 for (
auto MO:
MBBI->operands())
646 if (MO.isReg() && (MO.isImplicit() || MO.isDef()))
658 UsedRegs.addLiveOuts(
MBB);
664 for (
unsigned i = 0; CSRegs[i]; ++i)
665 UsedRegs.addReg(CSRegs[i]);
669 dl =
MBBI->getDebugLoc();
670 auto InstUpToMBBI =
MBB.
end();
671 while (InstUpToMBBI !=
MBBI)
674 UsedRegs.stepBackward(*--InstUpToMBBI);
680 unsigned TemporaryReg = 0;
682 TRI.getAllocatableSet(MF,
TRI.getRegClass(ARM::tGPRRegClassID));
684 assert(PopFriendly.
any() &&
"No allocatable pop-friendly register?!");
688 TRI.getAllocatableSet(MF,
TRI.getRegClass(ARM::hGPRRegClassID));
689 GPRsNoLRSP |= PopFriendly;
690 GPRsNoLRSP.
reset(ARM::LR);
691 GPRsNoLRSP.
reset(ARM::SP);
692 GPRsNoLRSP.
reset(ARM::PC);
699 bool UseLDRSP =
false;
701 auto PrevMBBI =
MBBI;
703 if (PrevMBBI->getOpcode() == ARM::tPOP) {
704 UsedRegs.stepBackward(*PrevMBBI);
714 if (!DoIt && !PopReg && !TemporaryReg)
717 assert((PopReg || TemporaryReg) &&
"Cannot get LR");
720 assert(PopReg &&
"Do not know how to get LR");
738 ArgRegsSaveSize + 4, ARM::NoRegister,
744 assert(!PopReg &&
"Unnecessary MOV is about to be inserted");
761 for (
auto MO:
MBBI->operands())
762 if (MO.isReg() && (MO.isImplicit() || MO.isDef()) &&
763 MO.getReg() != ARM::PC) {
765 if (!MO.isImplicit())
778 assert(PopReg &&
"Do not know how to get LR");
808 ARM::R0, ARM::R1, ARM::R2, ARM::R3, ARM::R4,
809 ARM::R5, ARM::R6, ARM::R7, ARM::LR};
812 std::set<Register> &LowRegs,
813 std::set<Register> &HighRegs) {
815 if (ARM::tGPRRegClass.
contains(Reg) || Reg == ARM::LR) {
817 }
else if (ARM::hGPRRegClass.
contains(Reg) && Reg != ARM::LR) {
818 HighRegs.insert(Reg);
825template <
typename It>
827 const std::set<Register> &RegSet) {
828 return std::find_if(OrderedStartIt, OrderedEndIt,
829 [&](
Register Reg) {
return RegSet.count(Reg); });
835 const std::set<Register> &RegsToSave,
836 const std::set<Register> &CopyRegs,
837 bool &UsedLRAsTemp) {
842 std::set<Register> LowRegs, HighRegs;
846 if (!LowRegs.empty()) {
850 if (LowRegs.count(Reg)) {
851 bool isKill = !
MRI.isLiveIn(Reg);
852 if (isKill && !
MRI.isReserved(Reg))
890 if (HighRegs.count(*HiRegToSave)) {
891 bool isKill = !
MRI.isLiveIn(*HiRegToSave);
892 if (isKill && !
MRI.isReserved(*HiRegToSave))
894 if (*CopyRegIt == ARM::LR)
928 const std::set<Register> &RegsToRestore,
929 const std::set<Register> &AvailableCopyRegs,
930 bool IsVarArg,
bool HasV5Ops) {
931 if (RegsToRestore.empty())
938 std::set<Register> LowRegs, HighRegs;
952 std::set<Register> CopyRegs = AvailableCopyRegs;
954 if (!HighRegs.empty() && CopyRegs.empty()) {
957 LowScratchReg = ARM::R0;
963 CopyRegs.insert(LowScratchReg);
967 assert(!CopyRegs.empty());
1000 if (LowScratchReg.
isValid()) {
1009 if (!LowRegs.empty()) {
1014 bool NeedsPop =
false;
1016 if (!LowRegs.count(Reg))
1019 if (Reg == ARM::LR) {
1021 MI->getOpcode() == ARM::TCRETURNri ||
1022 MI->getOpcode() == ARM::TCRETURNrinotr12)
1043 (*MIB).setDesc(
TII.get(ARM::tPOP_RET));
1074 bool NeedsFrameRecordPush =
hasFP(MF) && ARM::hGPRRegClass.contains(
FPReg);
1076 bool UsedLRAsTemp =
false;
1078 std::set<Register> FrameRecord;
1079 std::set<Register> SpilledGPRs;
1082 if (NeedsFrameRecordPush && (Reg ==
FPReg.asMCReg() || Reg == ARM::LR))
1083 FrameRecord.insert(Reg);
1085 SpilledGPRs.insert(Reg);
1096 std::set<Register> FrameRecordCopyRegs;
1097 for (
unsigned ArgReg : {ARM::R0, ARM::R1, ARM::R2, ARM::R3})
1099 FrameRecordCopyRegs.insert(ArgReg);
1100 if (FrameRecordCopyRegs.empty())
1101 FrameRecordCopyRegs.insert(ARM::LR);
1108 std::set<Register> CopyRegs;
1110 if ((ARM::tGPRRegClass.
contains(Reg) || Reg == ARM::LR) &&
1112 CopyRegs.insert(Reg);
1113 for (
unsigned ArgReg : {ARM::R0, ARM::R1, ARM::R2, ARM::R3})
1115 CopyRegs.insert(ArgReg);
1124 if (LRLiveIn && UsedLRAsTemp) {
1128 unsigned NumRegsPushed = FrameRecord.size() + SpilledGPRs.size();
1130 dbgs() <<
"LR is live-in but clobbered in prologue, restoring via "
1131 << RegInfo->getName(*CopyRegIt) <<
"\n");
1135 .
addImm(NumRegsPushed - 1)
1164 bool NeedsFrameRecordPop =
hasFP(MF) && ARM::hGPRRegClass.contains(
FPReg);
1166 std::set<Register> FrameRecord;
1167 std::set<Register> SpilledGPRs;
1170 if (NeedsFrameRecordPop && (Reg ==
FPReg.asMCReg() || Reg == ARM::LR))
1171 FrameRecord.insert(Reg);
1173 SpilledGPRs.insert(Reg);
1176 I.setRestored(
false);
1182 std::set<Register> CopyRegs;
1183 std::set<Register> UnusedReturnRegs;
1186 CopyRegs.insert(Reg);
1188 if (Terminator !=
MBB.
end() && Terminator->getOpcode() == ARM::tBX_RET) {
1189 UnusedReturnRegs.insert(ARM::R0);
1190 UnusedReturnRegs.insert(ARM::R1);
1191 UnusedReturnRegs.insert(ARM::R2);
1192 UnusedReturnRegs.insert(ARM::R3);
1193 for (
auto Op : Terminator->implicit_operands()) {
1195 UnusedReturnRegs.erase(
Op.getReg());
1198 CopyRegs.insert(UnusedReturnRegs.begin(), UnusedReturnRegs.end());
1206 assert((!SpilledGPRs.count(ARM::LR) || FrameRecord.empty()) &&
1207 "Can't insert pop after return sequence");
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
This file implements the BitVector class.
const HexagonInstrInfo * TII
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
Register const TargetRegisterInfo * TRI
static constexpr MCPhysReg FPReg
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
This file defines the SmallVector class.
static void emitCallSPUpdate(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const TargetInstrInfo &TII, const DebugLoc &dl, const ThumbRegisterInfo &MRI, int NumBytes, unsigned MIFlags=MachineInstr::NoFlags)
static void pushRegsToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const TargetInstrInfo &TII, const std::set< Register > &RegsToSave, const std::set< Register > &CopyRegs, bool &UsedLRAsTemp)
static const SmallVector< Register > OrderedCopyRegs
static const SmallVector< Register > OrderedLowRegs
static void splitLowAndHighRegs(const std::set< Register > &Regs, std::set< Register > &LowRegs, std::set< Register > &HighRegs)
It getNextOrderedReg(It OrderedStartIt, It OrderedEndIt, const std::set< Register > &RegSet)
static void emitPrologueEpilogueSPUpdate(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const TargetInstrInfo &TII, const DebugLoc &dl, const ThumbRegisterInfo &MRI, int NumBytes, unsigned ScratchReg, unsigned MIFlags)
static const SmallVector< Register > OrderedHighRegs
static void popRegsFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MI, const TargetInstrInfo &TII, const std::set< Register > &RegsToRestore, const std::set< Register > &AvailableCopyRegs, bool IsVarArg, bool HasV5Ops)
static void findTemporariesForLR(const BitVector &GPRsNoLRSP, const BitVector &PopFriendly, const LiveRegUnits &UsedRegs, unsigned &PopReg, unsigned &TmpReg, MachineRegisterInfo &MRI)
static const unsigned FramePtr
Register getFrameRegister(const MachineFunction &MF) const override
ARMFunctionInfo - This class is derived from MachineFunctionInfo and contains private ARM-specific in...
bool hasStackFrame() const
unsigned getGPRCalleeSavedArea1Size() const
unsigned getDPRCalleeSavedArea1Size() const
void setDPRCalleeSavedArea1Offset(unsigned o)
void setGPRCalleeSavedArea2Size(unsigned s)
void setFramePtrSpillOffset(unsigned o)
unsigned getGPRCalleeSavedArea2Size() const
void setGPRCalleeSavedArea1Size(unsigned s)
bool isCmseNSEntryFunction() const
unsigned getFramePtrSpillOffset() const
bool shouldRestoreSPFromFP() const
void setFrameRecordSavedAreaSize(unsigned s)
unsigned getArgRegsSaveSize() const
void setGPRCalleeSavedArea2Offset(unsigned o)
unsigned getFrameRecordSavedAreaSize() const
void setGPRCalleeSavedArea1Offset(unsigned o)
void setDPRCalleeSavedArea1Size(unsigned s)
void setShouldRestoreSPFromFP(bool s)
const ARMBaseInstrInfo * getInstrInfo() const override
const ARMBaseRegisterInfo * getRegisterInfo() const override
enum PushPopSplitVariation getPushPopSplitVariation(const MachineFunction &MF) const
@ SplitR7
R7 and LR must be adjacent, because R7 is the frame pointer, and must point to a frame record consist...
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
bool empty() const
empty - Check if the array is empty.
bool test(unsigned Idx) const
int find_first() const
find_first - Returns the index of the first set bit, -1 if none of the bits are set.
bool any() const
any - Returns true if any bit is set.
iterator_range< const_set_bits_iterator > set_bits() const
Helper class for creating CFI instructions and inserting them into MIR.
void buildDefCFAOffset(int64_t Offset, MCSymbol *Label=nullptr) const
void buildDefCFARegister(MCRegister Reg) const
void buildOffset(MCRegister Reg, int64_t Offset) const
void buildDefCFA(MCRegister Reg, int64_t Offset) const
void setInsertPoint(MachineBasicBlock::iterator IP)
The CalleeSavedInfo class tracks the information need to locate where a callee saved register is in t...
This class represents an Operation in the Expression.
A set of register units used to track register liveness.
bool available(MCRegister Reg) const
Returns true if no part of physical register Reg is live.
Wrapper class representing physical registers. Should be passed by value.
LLVM_ABI instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
succ_iterator succ_begin()
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
unsigned succ_size() const
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.
bool hasVarSizedObjects() const
This method may be called any time after instruction selection is complete to determine if the stack ...
uint64_t getStackSize() const
Return the number of bytes that must be allocated to hold all of the fixed size frame objects.
Align getMaxAlign() const
Return the alignment in bytes that this function must be aligned to, which is greater than the defaul...
uint64_t getMaxCallFrameSize() const
Return the maximum size of a call frame that must be allocated for an outgoing function call.
int64_t getOffsetAdjustment() const
Return the correction for frame offsets.
const std::vector< CalleeSavedInfo > & getCalleeSavedInfo() const
Returns a reference to call saved info vector for the current function.
int64_t getObjectOffset(int ObjectIdx) const
Return the assigned stack offset of the specified object from the incoming stack pointer.
void setStackSize(uint64_t Size)
Set the size of the stack.
void setOffsetAdjustment(int64_t Adj)
Set the correction for frame offsets.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
void deleteMachineInstr(MachineInstr *MI)
DeleteMachineInstr - Delete the given MachineInstr.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const MachineFunctionProperties & getProperties() const
Get the function properties.
const MachineInstrBuilder & setMIFlag(MachineInstr::MIFlag Flag) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & copyImplicitOps(const MachineInstr &OtherMI) const
Copy all the implicit operands from OtherMI onto this one.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool isLiveIn(Register Reg) const
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool hasFP(const MachineFunction &MF) const
hasFP - Return true if the specified function should have a dedicated frame pointer register.
Align getStackAlign() const
getStackAlignment - This method returns the number of bytes to which the stack pointer must be aligne...
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const override
This method is called during prolog/epilog code insertion to eliminate call frame setup and destroy p...
Thumb1FrameLowering(const ARMSubtarget &sti)
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override
emitProlog/emitEpilog - These methods insert prolog and epilog code into the function.
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override
bool canUseAsEpilogue(const MachineBasicBlock &MBB) const override
Check whether or not the given MBB can be used as a epilogue for the target.
bool hasReservedCallFrame(const MachineFunction &MF) const override
hasReservedCallFrame - Under normal circumstances, when a frame pointer is not required,...
bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, MutableArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override
restoreCalleeSavedRegisters - Issues instruction(s) to restore all callee saved registers and returns...
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, ArrayRef< CalleeSavedInfo > CSI, const TargetRegisterInfo *TRI) const override
spillCalleeSavedRegisters - Issues instruction(s) to spill all callee saved registers and returns tru...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Define
Register definition.
@ Kill
The last use of a register.
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
static bool isARMLowRegister(MCRegister Reg)
isARMLowRegister - Returns true if the register is a low register (r0-r7).
static std::array< MachineOperand, 2 > predOps(ARMCC::CondCodes Pred, unsigned PredReg=0)
Get the operands corresponding to the given Pred value.
bool tryFoldSPUpdateIntoPushPop(const ARMSubtarget &Subtarget, MachineFunction &MF, MachineInstr *MI, unsigned NumBytes)
Tries to add registers to the reglist of a given base-updating push/pop instruction to adjust the sta...
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
unsigned getDefRegState(bool B)
unsigned getKillRegState(bool B)
void emitThumbRegPlusImmediate(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, const DebugLoc &dl, Register DestReg, Register BaseReg, int NumBytes, const TargetInstrInfo &TII, const ARMBaseRegisterInfo &MRI, unsigned MIFlags=0)
emitThumbRegPlusImmediate - Emits a series of instructions to materialize a destreg = basereg + immed...
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
unsigned Log2(Align A)
Returns the log2 of the alignment.