#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>
using namespace llvm;
static const unsigned FramePtr = XCore::R10;
static const int MaxImmU16 = (1<<16) - 1;
static inline bool isImmU6(unsigned val) {
return val < (1 << 6);
}
static inline bool isImmU16(unsigned val) {
return val < (1 << 16);
}
namespace {
struct StackSlotInfo {
int FI;
int Offset;
unsigned Reg;
StackSlotInfo(int f, int o, int r) : FI(f), Offset(o), Reg(r){};
};
}
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);
}
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);
}
}
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;
}
}
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);
}
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.getObjectAlign(FrameIndex));
return MMO;
}
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(const XCoreSubtarget &sti)
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 0) {
}
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>();
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);
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) {
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);
}
}
SmallVector<StackSlotInfo,2> SpillList;
GetSpillList(SpillList, MFI, XFI, saveLR, FP);
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);
}
}
IfNeededExtSP(MBB, MBBI, dl, TII, FrameSize, Adjusted, FrameSize,
emitFrameMoves);
assert(Adjusted==FrameSize && "IfNeededExtSP has not completed adjustment");
if (FP) {
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) {
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()) {
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();
int RemainingAdj = MFI.getStackSize();
assert(RemainingAdj%4 == 0 && "Misaligned frame size");
RemainingAdj /= 4;
if (RetOpcode == XCore::EH_RETURN) {
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);
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); return;
}
bool restoreLR = XFI->hasLRSpillSlot();
bool UseRETSP = restoreLR && RemainingAdj
&& (MFI.getObjectOffset(XFI->getLRSpillSlot()) == 0);
if (UseRETSP)
restoreLR = false;
bool FP = hasFP(MF);
if (FP) BuildMI(MBB, MBBI, dl, TII.get(XCore::SETSP_1r)).addReg(FramePtr);
SmallVector<StackSlotInfo,2> SpillList;
GetSpillList(SpillList, MFI, XFI, restoreLR, FP);
RestoreSpillList(MBB, MBBI, dl, TII, RemainingAdj, SpillList);
if (RemainingAdj) {
IfNeededLDAWSP(MBB, MBBI, dl, TII, 0, RemainingAdj);
if (UseRETSP) {
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)); MBB.erase(MBBI); } else {
int Opcode = isImmU6(RemainingAdj) ? XCore::LDAWSP_ru6 :
XCore::LDAWSP_lru6;
BuildMI(MBB, MBBI, dl, TII.get(Opcode), XCore::SP).addImm(RemainingAdj);
}
} }
bool XCoreFrameLowering::spillCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
ArrayRef<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 (const CalleeSavedInfo &I : CSI) {
Register Reg = I.getReg();
assert(Reg != XCore::LR && !(Reg == XCore::R10 && hasFP(*MF)) &&
"LR & FP are always handled in emitPrologue");
MBB.addLiveIn(Reg);
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.storeRegToStackSlot(MBB, MI, Reg, true, I.getFrameIdx(), RC, TRI);
if (emitFrameMoves) {
auto Store = MI;
--Store;
XFI->getSpillLabels().push_back(std::make_pair(Store, I));
}
}
return true;
}
bool XCoreFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
MutableArrayRef<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 (const CalleeSavedInfo &CSR : CSI) {
Register 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!");
if (AtStart)
MI = MBB.begin();
else {
MI = BeforeI;
++MI;
}
}
return true;
}
MachineBasicBlock::iterator XCoreFrameLowering::eliminateCallFramePseudoInstr(
MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
const XCoreInstrInfo &TII = *MF.getSubtarget<XCoreSubtarget>().getInstrInfo();
if (!hasReservedCallFrame(MF)) {
MachineInstr &Old = *I;
uint64_t Amount = Old.getOperand(0).getImm();
if (Amount != 0) {
Amount = alignTo(Amount, getStackAlign());
assert(Amount%4 == 0);
Amount /= 4;
bool isU6 = isImmU6(Amount);
if (!isU6 && !isImmU16(Amount)) {
#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);
}
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))
LRUsed = true;
if (MF.callsUnwindInit() || MF.callsEHReturn()) {
XFI->createEHSpillSlot(MF);
LRUsed = true;
}
if (LRUsed) {
SavedRegs.reset(XCore::LR);
XFI->createLRSpillSlot(MF);
}
if (hasFP(MF))
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>();
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));
}