//===-- XCoreFrameLowering.cpp - Frame info for XCore Target --------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains XCore frame information that doesn't fit anywhere else // cleanly... // //===----------------------------------------------------------------------===// #include "XCoreFrameLowering.h" #include "XCore.h" #include "XCoreInstrInfo.h" #include "XCoreMachineFunctionInfo.h" #include "XCoreSubtarget.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetOptions.h" #include // std::sort using namespace llvm; static const unsigned FramePtr = XCore::R10; static const int MaxImmU16 = (1<<16) - 1; // helper functions. FIXME: Eliminate. static inline bool isImmU6(unsigned val) { return val < (1 << 6); } static inline bool isImmU16(unsigned val) { return val < (1 << 16); } // Helper structure with compare function for handling stack slots. namespace { struct StackSlotInfo { int FI; int Offset; unsigned Reg; StackSlotInfo(int f, int o, int r) : FI(f), Offset(o), Reg(r){}; }; } // end anonymous namespace static bool CompareSSIOffset(const StackSlotInfo& a, const StackSlotInfo& b) { return a.Offset < b.Offset; } static void EmitDefCfaRegister(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &dl, const TargetInstrInfo &TII, MachineFunction &MF, unsigned DRegNum) { unsigned CFIIndex = MF.addFrameInst( MCCFIInstruction::createDefCfaRegister(nullptr, DRegNum)); BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); } static void EmitDefCfaOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &dl, const TargetInstrInfo &TII, int Offset) { MachineFunction &MF = *MBB.getParent(); unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, Offset)); BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); } static void EmitCfiOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &dl, const TargetInstrInfo &TII, unsigned DRegNum, int Offset) { MachineFunction &MF = *MBB.getParent(); unsigned CFIIndex = MF.addFrameInst( MCCFIInstruction::createOffset(nullptr, DRegNum, Offset)); BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); } /// The SP register is moved in steps of 'MaxImmU16' towards the bottom of the /// frame. During these steps, it may be necessary to spill registers. /// IfNeededExtSP emits the necessary EXTSP instructions to move the SP only /// as far as to make 'OffsetFromBottom' reachable using an STWSP_lru6. /// \param OffsetFromTop the spill offset from the top of the frame. /// \param [in,out] Adjusted the current SP offset from the top of the frame. static void IfNeededExtSP(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &dl, const TargetInstrInfo &TII, int OffsetFromTop, int &Adjusted, int FrameSize, bool emitFrameMoves) { while (OffsetFromTop > Adjusted) { assert(Adjusted < FrameSize && "OffsetFromTop is beyond FrameSize"); int remaining = FrameSize - Adjusted; int OpImm = (remaining > MaxImmU16) ? MaxImmU16 : remaining; int Opcode = isImmU6(OpImm) ? XCore::EXTSP_u6 : XCore::EXTSP_lu6; BuildMI(MBB, MBBI, dl, TII.get(Opcode)).addImm(OpImm); Adjusted += OpImm; if (emitFrameMoves) EmitDefCfaOffset(MBB, MBBI, dl, TII, Adjusted*4); } } /// The SP register is moved in steps of 'MaxImmU16' towards the top of the /// frame. During these steps, it may be necessary to re-load registers. /// IfNeededLDAWSP emits the necessary LDAWSP instructions to move the SP only /// as far as to make 'OffsetFromTop' reachable using an LDAWSP_lru6. /// \param OffsetFromTop the spill offset from the top of the frame. /// \param [in,out] RemainingAdj the current SP offset from the top of the /// frame. static void IfNeededLDAWSP(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &dl, const TargetInstrInfo &TII, int OffsetFromTop, int &RemainingAdj) { while (OffsetFromTop < RemainingAdj - MaxImmU16) { assert(RemainingAdj && "OffsetFromTop is beyond FrameSize"); int OpImm = (RemainingAdj > MaxImmU16) ? MaxImmU16 : RemainingAdj; int Opcode = isImmU6(OpImm) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; BuildMI(MBB, MBBI, dl, TII.get(Opcode), XCore::SP).addImm(OpImm); RemainingAdj -= OpImm; } } /// Creates an ordered list of registers that are spilled /// during the emitPrologue/emitEpilogue. /// Registers are ordered according to their frame offset. /// As offsets are negative, the largest offsets will be first. static void GetSpillList(SmallVectorImpl &SpillList, MachineFrameInfo &MFI, XCoreFunctionInfo *XFI, bool fetchLR, bool fetchFP) { if (fetchLR) { int Offset = MFI.getObjectOffset(XFI->getLRSpillSlot()); SpillList.push_back(StackSlotInfo(XFI->getLRSpillSlot(), Offset, XCore::LR)); } if (fetchFP) { int Offset = MFI.getObjectOffset(XFI->getFPSpillSlot()); SpillList.push_back(StackSlotInfo(XFI->getFPSpillSlot(), Offset, FramePtr)); } llvm::sort(SpillList, CompareSSIOffset); } /// Creates an ordered list of EH info register 'spills'. /// These slots are only used by the unwinder and calls to llvm.eh.return(). /// Registers are ordered according to their frame offset. /// As offsets are negative, the largest offsets will be first. static void GetEHSpillList(SmallVectorImpl &SpillList, MachineFrameInfo &MFI, XCoreFunctionInfo *XFI, const Constant *PersonalityFn, const TargetLowering *TL) { assert(XFI->hasEHSpillSlot() && "There are no EH register spill slots"); const int *EHSlot = XFI->getEHSpillSlot(); SpillList.push_back( StackSlotInfo(EHSlot[0], MFI.getObjectOffset(EHSlot[0]), TL->getExceptionPointerRegister(PersonalityFn))); SpillList.push_back( StackSlotInfo(EHSlot[0], MFI.getObjectOffset(EHSlot[1]), TL->getExceptionSelectorRegister(PersonalityFn))); llvm::sort(SpillList, CompareSSIOffset); } static MachineMemOperand *getFrameIndexMMO(MachineBasicBlock &MBB, int FrameIndex, MachineMemOperand::Flags flags) { MachineFunction *MF = MBB.getParent(); const MachineFrameInfo &MFI = MF->getFrameInfo(); MachineMemOperand *MMO = MF->getMachineMemOperand( MachinePointerInfo::getFixedStack(*MF, FrameIndex), flags, MFI.getObjectSize(FrameIndex), MFI.getObjectAlign(FrameIndex)); return MMO; } /// Restore clobbered registers with their spill slot value. /// The SP will be adjusted at the same time, thus the SpillList must be ordered /// with the largest (negative) offsets first. static void RestoreSpillList(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &dl, const TargetInstrInfo &TII, int &RemainingAdj, SmallVectorImpl &SpillList) { for (unsigned i = 0, e = SpillList.size(); i != e; ++i) { assert(SpillList[i].Offset % 4 == 0 && "Misaligned stack offset"); assert(SpillList[i].Offset <= 0 && "Unexpected positive stack offset"); int OffsetFromTop = - SpillList[i].Offset/4; IfNeededLDAWSP(MBB, MBBI, dl, TII, OffsetFromTop, RemainingAdj); int Offset = RemainingAdj - OffsetFromTop; int Opcode = isImmU6(Offset) ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6; BuildMI(MBB, MBBI, dl, TII.get(Opcode), SpillList[i].Reg) .addImm(Offset) .addMemOperand(getFrameIndexMMO(MBB, SpillList[i].FI, MachineMemOperand::MOLoad)); } } //===----------------------------------------------------------------------===// // XCoreFrameLowering: //===----------------------------------------------------------------------===// XCoreFrameLowering::XCoreFrameLowering(const XCoreSubtarget &sti) : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0) { // Do nothing } bool XCoreFrameLowering::hasFP(const MachineFunction &MF) const { return MF.getTarget().Options.DisableFramePointerElim(MF) || MF.getFrameInfo().hasVarSizedObjects(); } void XCoreFrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); MachineBasicBlock::iterator MBBI = MBB.begin(); MachineFrameInfo &MFI = MF.getFrameInfo(); MachineModuleInfo *MMI = &MF.getMMI(); const MCRegisterInfo *MRI = MMI->getContext().getRegisterInfo(); const XCoreInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); XCoreFunctionInfo *XFI = MF.getInfo(); // Debug location must be unknown since the first debug location is used // to determine the end of the prologue. DebugLoc dl; if (MFI.getMaxAlign() > getStackAlign()) report_fatal_error("emitPrologue unsupported alignment: " + Twine(MFI.getMaxAlign().value())); const AttributeList &PAL = MF.getFunction().getAttributes(); if (PAL.hasAttrSomewhere(Attribute::Nest)) BuildMI(MBB, MBBI, dl, TII.get(XCore::LDWSP_ru6), XCore::R11).addImm(0); // FIX: Needs addMemOperand() but can't use getFixedStack() or getStack(). // Work out frame sizes. // We will adjust the SP in stages towards the final FrameSize. assert(MFI.getStackSize()%4 == 0 && "Misaligned frame size"); const int FrameSize = MFI.getStackSize() / 4; int Adjusted = 0; bool saveLR = XFI->hasLRSpillSlot(); bool UseENTSP = saveLR && FrameSize && (MFI.getObjectOffset(XFI->getLRSpillSlot()) == 0); if (UseENTSP) saveLR = false; bool FP = hasFP(MF); bool emitFrameMoves = XCoreRegisterInfo::needsFrameMoves(MF); if (UseENTSP) { // Allocate space on the stack at the same time as saving LR. Adjusted = (FrameSize > MaxImmU16) ? MaxImmU16 : FrameSize; int Opcode = isImmU6(Adjusted) ? XCore::ENTSP_u6 : XCore::ENTSP_lu6; MBB.addLiveIn(XCore::LR); MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(Opcode)); MIB.addImm(Adjusted); MIB->addRegisterKilled(XCore::LR, MF.getSubtarget().getRegisterInfo(), true); if (emitFrameMoves) { EmitDefCfaOffset(MBB, MBBI, dl, TII, Adjusted*4); unsigned DRegNum = MRI->getDwarfRegNum(XCore::LR, true); EmitCfiOffset(MBB, MBBI, dl, TII, DRegNum, 0); } } // If necessary, save LR and FP to the stack, as we EXTSP. SmallVector SpillList; GetSpillList(SpillList, MFI, XFI, saveLR, FP); // We want the nearest (negative) offsets first, so reverse list. std::reverse(SpillList.begin(), SpillList.end()); for (unsigned i = 0, e = SpillList.size(); i != e; ++i) { assert(SpillList[i].Offset % 4 == 0 && "Misaligned stack offset"); assert(SpillList[i].Offset <= 0 && "Unexpected positive stack offset"); int OffsetFromTop = - SpillList[i].Offset/4; IfNeededExtSP(MBB, MBBI, dl, TII, OffsetFromTop, Adjusted, FrameSize, emitFrameMoves); int Offset = Adjusted - OffsetFromTop; int Opcode = isImmU6(Offset) ? XCore::STWSP_ru6 : XCore::STWSP_lru6; MBB.addLiveIn(SpillList[i].Reg); BuildMI(MBB, MBBI, dl, TII.get(Opcode)) .addReg(SpillList[i].Reg, RegState::Kill) .addImm(Offset) .addMemOperand(getFrameIndexMMO(MBB, SpillList[i].FI, MachineMemOperand::MOStore)); if (emitFrameMoves) { unsigned DRegNum = MRI->getDwarfRegNum(SpillList[i].Reg, true); EmitCfiOffset(MBB, MBBI, dl, TII, DRegNum, SpillList[i].Offset); } } // Complete any remaining Stack adjustment. IfNeededExtSP(MBB, MBBI, dl, TII, FrameSize, Adjusted, FrameSize, emitFrameMoves); assert(Adjusted==FrameSize && "IfNeededExtSP has not completed adjustment"); if (FP) { // Set the FP from the SP. BuildMI(MBB, MBBI, dl, TII.get(XCore::LDAWSP_ru6), FramePtr).addImm(0); if (emitFrameMoves) EmitDefCfaRegister(MBB, MBBI, dl, TII, MF, MRI->getDwarfRegNum(FramePtr, true)); } if (emitFrameMoves) { // Frame moves for callee saved. for (const auto &SpillLabel : XFI->getSpillLabels()) { MachineBasicBlock::iterator Pos = SpillLabel.first; ++Pos; const CalleeSavedInfo &CSI = SpillLabel.second; int Offset = MFI.getObjectOffset(CSI.getFrameIdx()); unsigned DRegNum = MRI->getDwarfRegNum(CSI.getReg(), true); EmitCfiOffset(MBB, Pos, dl, TII, DRegNum, Offset); } if (XFI->hasEHSpillSlot()) { // The unwinder requires stack slot & CFI offsets for the exception info. // We do not save/spill these registers. const Function *Fn = &MF.getFunction(); const Constant *PersonalityFn = Fn->hasPersonalityFn() ? Fn->getPersonalityFn() : nullptr; SmallVector SpillList; GetEHSpillList(SpillList, MFI, XFI, PersonalityFn, MF.getSubtarget().getTargetLowering()); assert(SpillList.size()==2 && "Unexpected SpillList size"); EmitCfiOffset(MBB, MBBI, dl, TII, MRI->getDwarfRegNum(SpillList[0].Reg, true), SpillList[0].Offset); EmitCfiOffset(MBB, MBBI, dl, TII, MRI->getDwarfRegNum(SpillList[1].Reg, true), SpillList[1].Offset); } } } void XCoreFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { MachineFrameInfo &MFI = MF.getFrameInfo(); MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); const XCoreInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); XCoreFunctionInfo *XFI = MF.getInfo(); DebugLoc dl = MBBI->getDebugLoc(); unsigned RetOpcode = MBBI->getOpcode(); // Work out frame sizes. // We will adjust the SP in stages towards the final FrameSize. int RemainingAdj = MFI.getStackSize(); assert(RemainingAdj%4 == 0 && "Misaligned frame size"); RemainingAdj /= 4; if (RetOpcode == XCore::EH_RETURN) { // 'Restore' the exception info the unwinder has placed into the stack // slots. const Function *Fn = &MF.getFunction(); const Constant *PersonalityFn = Fn->hasPersonalityFn() ? Fn->getPersonalityFn() : nullptr; SmallVector SpillList; GetEHSpillList(SpillList, MFI, XFI, PersonalityFn, MF.getSubtarget().getTargetLowering()); RestoreSpillList(MBB, MBBI, dl, TII, RemainingAdj, SpillList); // Return to the landing pad. Register EhStackReg = MBBI->getOperand(0).getReg(); Register EhHandlerReg = MBBI->getOperand(1).getReg(); BuildMI(MBB, MBBI, dl, TII.get(XCore::SETSP_1r)).addReg(EhStackReg); BuildMI(MBB, MBBI, dl, TII.get(XCore::BAU_1r)).addReg(EhHandlerReg); MBB.erase(MBBI); // Erase the previous return instruction. return; } bool restoreLR = XFI->hasLRSpillSlot(); bool UseRETSP = restoreLR && RemainingAdj && (MFI.getObjectOffset(XFI->getLRSpillSlot()) == 0); if (UseRETSP) restoreLR = false; bool FP = hasFP(MF); if (FP) // Restore the stack pointer. BuildMI(MBB, MBBI, dl, TII.get(XCore::SETSP_1r)).addReg(FramePtr); // If necessary, restore LR and FP from the stack, as we EXTSP. SmallVector SpillList; GetSpillList(SpillList, MFI, XFI, restoreLR, FP); RestoreSpillList(MBB, MBBI, dl, TII, RemainingAdj, SpillList); if (RemainingAdj) { // Complete all but one of the remaining Stack adjustments. IfNeededLDAWSP(MBB, MBBI, dl, TII, 0, RemainingAdj); if (UseRETSP) { // Fold prologue into return instruction assert(RetOpcode == XCore::RETSP_u6 || RetOpcode == XCore::RETSP_lu6); int Opcode = isImmU6(RemainingAdj) ? XCore::RETSP_u6 : XCore::RETSP_lu6; MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(Opcode)) .addImm(RemainingAdj); for (unsigned i = 3, e = MBBI->getNumOperands(); i < e; ++i) MIB->addOperand(MBBI->getOperand(i)); // copy any variadic operands MBB.erase(MBBI); // Erase the previous return instruction. } else { int Opcode = isImmU6(RemainingAdj) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; BuildMI(MBB, MBBI, dl, TII.get(Opcode), XCore::SP).addImm(RemainingAdj); // Don't erase the return instruction. } } // else Don't erase the return instruction. } bool XCoreFrameLowering::spillCalleeSavedRegisters( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, ArrayRef CSI, const TargetRegisterInfo *TRI) const { if (CSI.empty()) return true; MachineFunction *MF = MBB.getParent(); const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); XCoreFunctionInfo *XFI = MF->getInfo(); bool emitFrameMoves = XCoreRegisterInfo::needsFrameMoves(*MF); DebugLoc DL; if (MI != MBB.end() && !MI->isDebugInstr()) DL = MI->getDebugLoc(); for (auto it = CSI.begin(); it != CSI.end(); ++it) { unsigned Reg = it->getReg(); assert(Reg != XCore::LR && !(Reg == XCore::R10 && hasFP(*MF)) && "LR & FP are always handled in emitPrologue"); // Add the callee-saved register as live-in. It's killed at the spill. MBB.addLiveIn(Reg); const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); TII.storeRegToStackSlot(MBB, MI, Reg, true, it->getFrameIdx(), RC, TRI); if (emitFrameMoves) { auto Store = MI; --Store; XFI->getSpillLabels().push_back(std::make_pair(Store, *it)); } } return true; } bool XCoreFrameLowering::restoreCalleeSavedRegisters( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, MutableArrayRef CSI, const TargetRegisterInfo *TRI) const { MachineFunction *MF = MBB.getParent(); const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); bool AtStart = MI == MBB.begin(); MachineBasicBlock::iterator BeforeI = MI; if (!AtStart) --BeforeI; for (const CalleeSavedInfo &CSR : CSI) { unsigned Reg = CSR.getReg(); assert(Reg != XCore::LR && !(Reg == XCore::R10 && hasFP(*MF)) && "LR & FP are always handled in emitEpilogue"); const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); TII.loadRegFromStackSlot(MBB, MI, Reg, CSR.getFrameIdx(), RC, TRI); assert(MI != MBB.begin() && "loadRegFromStackSlot didn't insert any code!"); // Insert in reverse order. loadRegFromStackSlot can insert multiple // instructions. if (AtStart) MI = MBB.begin(); else { MI = BeforeI; ++MI; } } return true; } // This function eliminates ADJCALLSTACKDOWN, // ADJCALLSTACKUP pseudo instructions MachineBasicBlock::iterator XCoreFrameLowering::eliminateCallFramePseudoInstr( MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { const XCoreInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); if (!hasReservedCallFrame(MF)) { // Turn the adjcallstackdown instruction into 'extsp ' and the // adjcallstackup instruction into 'ldaw sp, sp[]' MachineInstr &Old = *I; uint64_t Amount = Old.getOperand(0).getImm(); if (Amount != 0) { // We need to keep the stack aligned properly. To do this, we round the // amount of space needed for the outgoing arguments up to the next // alignment boundary. Amount = alignTo(Amount, getStackAlign()); assert(Amount%4 == 0); Amount /= 4; bool isU6 = isImmU6(Amount); if (!isU6 && !isImmU16(Amount)) { // FIX could emit multiple instructions in this case. #ifndef NDEBUG errs() << "eliminateCallFramePseudoInstr size too big: " << Amount << "\n"; #endif llvm_unreachable(nullptr); } MachineInstr *New; if (Old.getOpcode() == XCore::ADJCALLSTACKDOWN) { int Opcode = isU6 ? XCore::EXTSP_u6 : XCore::EXTSP_lu6; New = BuildMI(MF, Old.getDebugLoc(), TII.get(Opcode)).addImm(Amount); } else { assert(Old.getOpcode() == XCore::ADJCALLSTACKUP); int Opcode = isU6 ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; New = BuildMI(MF, Old.getDebugLoc(), TII.get(Opcode), XCore::SP) .addImm(Amount); } // Replace the pseudo instruction with a new instruction... MBB.insert(I, New); } } return MBB.erase(I); } void XCoreFrameLowering::determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const { TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); XCoreFunctionInfo *XFI = MF.getInfo(); const MachineRegisterInfo &MRI = MF.getRegInfo(); bool LRUsed = MRI.isPhysRegModified(XCore::LR); if (!LRUsed && !MF.getFunction().isVarArg() && MF.getFrameInfo().estimateStackSize(MF)) // If we need to extend the stack it is more efficient to use entsp / retsp. // We force the LR to be saved so these instructions are used. LRUsed = true; if (MF.callsUnwindInit() || MF.callsEHReturn()) { // The unwinder expects to find spill slots for the exception info regs R0 // & R1. These are used during llvm.eh.return() to 'restore' the exception // info. N.B. we do not spill or restore R0, R1 during normal operation. XFI->createEHSpillSlot(MF); // As we will have a stack, we force the LR to be saved. LRUsed = true; } if (LRUsed) { // We will handle the LR in the prologue/epilogue // and allocate space on the stack ourselves. SavedRegs.reset(XCore::LR); XFI->createLRSpillSlot(MF); } if (hasFP(MF)) // A callee save register is used to hold the FP. // This needs saving / restoring in the epilogue / prologue. XFI->createFPSpillSlot(MF); } void XCoreFrameLowering:: processFunctionBeforeFrameFinalized(MachineFunction &MF, RegScavenger *RS) const { assert(RS && "requiresRegisterScavenging failed"); MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetRegisterClass &RC = XCore::GRRegsRegClass; const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); XCoreFunctionInfo *XFI = MF.getInfo(); // Reserve slots close to SP or frame pointer for Scavenging spills. // When using SP for small frames, we don't need any scratch registers. // When using SP for large frames, we may need 2 scratch registers. // When using FP, for large or small frames, we may need 1 scratch register. unsigned Size = TRI.getSpillSize(RC); Align Alignment = TRI.getSpillAlign(RC); if (XFI->isLargeFrame(MF) || hasFP(MF)) RS->addScavengingFrameIndex(MFI.CreateStackObject(Size, Alignment, false)); if (XFI->isLargeFrame(MF) && !hasFP(MF)) RS->addScavengingFrameIndex(MFI.CreateStackObject(Size, Alignment, false)); }