1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 04:02:41 +01:00
llvm-mirror/lib/Target/XCore/XCoreFrameLowering.cpp
Chandler Carruth ae65e281f3 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

591 lines
24 KiB
C++

//===-- 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 <algorithm> // 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::createDefCfaOffset(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<StackSlotInfo> &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<StackSlotInfo> &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.getObjectAlignment(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<StackSlotInfo> &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, 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<XCoreSubtarget>().getInstrInfo();
XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();
// Debug location must be unknown since the first debug location is used
// to determine the end of the prologue.
DebugLoc dl;
if (MFI.getMaxAlignment() > getStackAlignment())
report_fatal_error("emitPrologue unsupported alignment: "
+ Twine(MFI.getMaxAlignment()));
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<StackSlotInfo,2> 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<StackSlotInfo, 2> 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<XCoreSubtarget>().getInstrInfo();
XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();
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<StackSlotInfo, 2> SpillList;
GetEHSpillList(SpillList, MFI, XFI, PersonalityFn,
MF.getSubtarget().getTargetLowering());
RestoreSpillList(MBB, MBBI, dl, TII, RemainingAdj, SpillList);
// Return to the landing pad.
unsigned EhStackReg = MBBI->getOperand(0).getReg();
unsigned 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<StackSlotInfo,2> 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,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const {
if (CSI.empty())
return true;
MachineFunction *MF = MBB.getParent();
const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
XCoreFunctionInfo *XFI = MF->getInfo<XCoreFunctionInfo>();
bool emitFrameMoves = XCoreRegisterInfo::needsFrameMoves(*MF);
DebugLoc DL;
if (MI != MBB.end() && !MI->isDebugInstr())
DL = MI->getDebugLoc();
for (std::vector<CalleeSavedInfo>::const_iterator 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,
std::vector<CalleeSavedInfo> &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 (std::vector<CalleeSavedInfo>::const_iterator 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 emitEpilogue");
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.loadRegFromStackSlot(MBB, MI, Reg, it->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<XCoreSubtarget>().getInstrInfo();
if (!hasReservedCallFrame(MF)) {
// Turn the adjcallstackdown instruction into 'extsp <amt>' and the
// adjcallstackup instruction into 'ldaw sp, sp[<amt>]'
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.
unsigned Align = getStackAlignment();
Amount = (Amount+Align-1)/Align*Align;
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<XCoreFunctionInfo>();
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<XCoreFunctionInfo>();
// 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);
unsigned Align = TRI.getSpillAlignment(RC);
if (XFI->isLargeFrame(MF) || hasFP(MF))
RS->addScavengingFrameIndex(MFI.CreateStackObject(Size, Align, false));
if (XFI->isLargeFrame(MF) && !hasFP(MF))
RS->addScavengingFrameIndex(MFI.CreateStackObject(Size, Align, false));
}