#include "ARCFrameLowering.h"
#include "ARCMachineFunctionInfo.h"
#include "ARCSubtarget.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "arc-frame-lowering"
using namespace llvm;
static cl::opt<bool>
UseSaveRestoreFunclet("arc-save-restore-funclet", cl::Hidden,
cl::desc("Use arc callee save/restore functions"),
cl::init(true));
static const char *store_funclet_name[] = {
"__st_r13_to_r15", "__st_r13_to_r16", "__st_r13_to_r17", "__st_r13_to_r18",
"__st_r13_to_r19", "__st_r13_to_r20", "__st_r13_to_r21", "__st_r13_to_r22",
"__st_r13_to_r23", "__st_r13_to_r24", "__st_r13_to_r25",
};
static const char *load_funclet_name[] = {
"__ld_r13_to_r15", "__ld_r13_to_r16", "__ld_r13_to_r17", "__ld_r13_to_r18",
"__ld_r13_to_r19", "__ld_r13_to_r20", "__ld_r13_to_r21", "__ld_r13_to_r22",
"__ld_r13_to_r23", "__ld_r13_to_r24", "__ld_r13_to_r25",
};
static void generateStackAdjustment(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const ARCInstrInfo &TII, DebugLoc dl,
int Amount, int StackPtr) {
unsigned AdjOp;
if (!Amount)
return;
bool Positive;
unsigned AbsAmount;
if (Amount < 0) {
AbsAmount = -Amount;
Positive = false;
} else {
AbsAmount = Amount;
Positive = true;
}
LLVM_DEBUG(dbgs() << "Internal: adjust stack by: " << Amount << ","
<< AbsAmount << "\n");
assert((AbsAmount % 4 == 0) && "Stack adjustments must be 4-byte aligned.");
if (isUInt<6>(AbsAmount))
AdjOp = Positive ? ARC::ADD_rru6 : ARC::SUB_rru6;
else if (isInt<12>(AbsAmount))
AdjOp = Positive ? ARC::ADD_rrs12 : ARC::SUB_rrs12;
else
AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr)
.addReg(StackPtr)
.addImm(AbsAmount);
}
static unsigned determineLastCalleeSave(ArrayRef<CalleeSavedInfo> CSI) {
unsigned Last = 0;
for (auto Reg : CSI) {
assert(Reg.getReg() >= ARC::R13 && Reg.getReg() <= ARC::R25 &&
"Unexpected callee saved reg.");
if (Reg.getReg() > Last)
Last = Reg.getReg();
}
return Last;
}
void ARCFrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
LLVM_DEBUG(dbgs() << "Determine Callee Saves: " << MF.getName() << "\n");
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
SavedRegs.set(ARC::BLINK);
}
void ARCFrameLowering::adjustStackToMatchRecords(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
bool Allocate) const {
MachineFunction &MF = *MBB.getParent();
int ScalarAlloc = MF.getFrameInfo().getStackSize();
if (Allocate) {
ScalarAlloc = -ScalarAlloc;
}
generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(),
ScalarAlloc, ARC::SP);
}
void ARCFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
LLVM_DEBUG(dbgs() << "Emit Prologue: " << MF.getName() << "\n");
auto *AFI = MF.getInfo<ARCFunctionInfo>();
MachineModuleInfo &MMI = MF.getMMI();
MCContext &Context = MMI.getContext();
const MCRegisterInfo *MRI = Context.getRegisterInfo();
const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
MachineBasicBlock::iterator MBBI = MBB.begin();
DebugLoc dl;
MachineFrameInfo &MFI = MF.getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
unsigned Last = determineLastCalleeSave(CSI);
unsigned StackSlotsUsedByFunclet = 0;
bool SavedBlink = false;
unsigned AlreadyAdjusted = 0;
if (MF.getFunction().isVarArg()) {
LLVM_DEBUG(dbgs() << "Varargs\n");
unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
unsigned Opc = ARC::SUB_rrlimm;
if (isUInt<6>(VarArgsBytes))
Opc = ARC::SUB_rru6;
else if (isInt<12>(VarArgsBytes))
Opc = ARC::SUB_rrs12;
BuildMI(MBB, MBBI, dl, TII->get(Opc), ARC::SP)
.addReg(ARC::SP)
.addImm(VarArgsBytes);
}
if (hasFP(MF)) {
LLVM_DEBUG(dbgs() << "Saving FP\n");
BuildMI(MBB, MBBI, dl, TII->get(ARC::ST_AW_rs9))
.addReg(ARC::SP, RegState::Define)
.addReg(ARC::FP)
.addReg(ARC::SP)
.addImm(-4);
AlreadyAdjusted += 4;
}
if (UseSaveRestoreFunclet && Last > ARC::R14) {
LLVM_DEBUG(dbgs() << "Creating store funclet.\n");
StackSlotsUsedByFunclet = Last - ARC::R12;
BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6))
.addReg(ARC::SP)
.addReg(ARC::SP)
.addImm(4 * StackSlotsUsedByFunclet);
BuildMI(MBB, MBBI, dl, TII->get(ARC::BL))
.addExternalSymbol(store_funclet_name[Last - ARC::R15])
.addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
AlreadyAdjusted += 4 * (StackSlotsUsedByFunclet + 1);
SavedBlink = true;
}
if (MFI.hasCalls() && !SavedBlink) {
LLVM_DEBUG(dbgs() << "Creating save blink.\n");
BuildMI(MBB, MBBI, dl, TII->get(ARC::PUSH_S_BLINK));
AlreadyAdjusted += 4;
}
if (AFI->MaxCallStackReq > 0)
MFI.setStackSize(MFI.getStackSize() + AFI->MaxCallStackReq);
LLVM_DEBUG(dbgs() << "Adjusting stack by: "
<< (MFI.getStackSize() - AlreadyAdjusted) << "\n");
generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl,
-(MFI.getStackSize() - AlreadyAdjusted), ARC::SP);
if (hasFP(MF)) {
LLVM_DEBUG(dbgs() << "Setting FP from SP.\n");
BuildMI(MBB, MBBI, dl,
TII->get(isUInt<6>(MFI.getStackSize()) ? ARC::ADD_rru6
: ARC::ADD_rrlimm),
ARC::FP)
.addReg(ARC::SP)
.addImm(MFI.getStackSize());
}
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize()));
BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
int CurOffset = -4;
if (hasFP(MF)) {
CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(ARC::FP, true), CurOffset));
BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
CurOffset -= 4;
}
if (MFI.hasCalls()) {
CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(ARC::BLINK, true), CurOffset));
BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
}
for (const auto &Entry : CSI) {
unsigned Reg = Entry.getReg();
int FI = Entry.getFrameIdx();
if ((hasFP(MF) && Reg == ARC::FP) || (MFI.hasCalls() && Reg == ARC::BLINK))
continue;
CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI)));
BuildMI(MBB, MBBI, dl, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlags(MachineInstr::FrameSetup);
}
}
void ARCFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
LLVM_DEBUG(dbgs() << "Emit Epilogue: " << MF.getName() << "\n");
auto *AFI = MF.getInfo<ARCFunctionInfo>();
const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
MachineFrameInfo &MFI = MF.getFrameInfo();
uint64_t StackSize = MF.getFrameInfo().getStackSize();
bool SavedBlink = false;
unsigned AmountAboveFunclet = 0;
if (hasFP(MF)) {
unsigned Opc = ARC::SUB_rrlimm;
if (isUInt<6>(StackSize))
Opc = ARC::SUB_rru6;
BuildMI(MBB, MBBI, DebugLoc(), TII->get(Opc), ARC::SP)
.addReg(ARC::FP)
.addImm(StackSize);
AmountAboveFunclet += 4;
}
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
unsigned Last = determineLastCalleeSave(CSI);
unsigned StackSlotsUsedByFunclet = 0;
if (UseSaveRestoreFunclet && Last > ARC::R14) {
StackSlotsUsedByFunclet = Last - ARC::R12;
AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1);
SavedBlink = true;
}
if (MFI.hasCalls() && !SavedBlink) {
AmountAboveFunclet += 4;
SavedBlink = true;
}
if (unsigned MoveAmount = StackSize - AmountAboveFunclet) {
unsigned Opc = ARC::ADD_rrlimm;
if (isUInt<6>(MoveAmount))
Opc = ARC::ADD_rru6;
else if (isInt<12>(MoveAmount))
Opc = ARC::ADD_rrs12;
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)
.addReg(ARC::SP)
.addImm(StackSize - AmountAboveFunclet);
}
if (StackSlotsUsedByFunclet) {
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::BL))
.addExternalSymbol(load_funclet_name[Last - ARC::R15])
.addReg(ARC::BLINK, RegState::Implicit | RegState::Kill);
unsigned Opc = ARC::ADD_rrlimm;
if (isUInt<6>(4 * StackSlotsUsedByFunclet))
Opc = ARC::ADD_rru6;
else if (isInt<12>(4 * StackSlotsUsedByFunclet))
Opc = ARC::ADD_rrs12;
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc), ARC::SP)
.addReg(ARC::SP)
.addImm(4 * (StackSlotsUsedByFunclet));
}
if (SavedBlink) {
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK));
}
if (hasFP(MF)) {
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9))
.addReg(ARC::FP, RegState::Define)
.addReg(ARC::SP, RegState::Define)
.addReg(ARC::SP)
.addImm(4);
}
if (MF.getFunction().isVarArg()) {
LLVM_DEBUG(dbgs() << "Varargs\n");
unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
unsigned Opc = ARC::ADD_rrlimm;
if (isUInt<6>(VarArgsBytes))
Opc = ARC::ADD_rru6;
else if (isInt<12>(VarArgsBytes))
Opc = ARC::ADD_rrs12;
BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(Opc))
.addReg(ARC::SP)
.addReg(ARC::SP)
.addImm(VarArgsBytes);
}
}
static std::vector<CalleeSavedInfo>::iterator
getSavedReg(std::vector<CalleeSavedInfo> &V, unsigned reg) {
for (auto I = V.begin(), E = V.end(); I != E; ++I) {
if (reg == I->getReg())
return I;
}
return V.end();
}
bool ARCFrameLowering::assignCalleeSavedSpillSlots(
MachineFunction &MF, const TargetRegisterInfo *TRI,
std::vector<CalleeSavedInfo> &CSI) const {
int CurOffset = -4;
unsigned Last = determineLastCalleeSave(CSI);
MachineFrameInfo &MFI = MF.getFrameInfo();
if (hasFP(MF)) {
int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at "
<< CurOffset << "\n");
(void)StackObj;
CurOffset -= 4;
}
if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) {
int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
LLVM_DEBUG(dbgs() << "Creating fixed object (" << StackObj
<< ") for BLINK at " << CurOffset << "\n");
(void)StackObj;
CurOffset -= 4;
}
for (unsigned Which = Last; Which > ARC::R12; Which--) {
auto RegI = getSavedReg(CSI, Which);
if (RegI == CSI.end() || RegI->getFrameIdx() == 0) {
int FI = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
if (RegI != CSI.end())
RegI->setFrameIdx(FI);
} else
MFI.setObjectOffset(RegI->getFrameIdx(), CurOffset);
CurOffset -= 4;
}
for (auto &I : CSI) {
if (I.getReg() > ARC::R12)
continue;
if (I.getFrameIdx() == 0) {
I.setFrameIdx(MFI.CreateFixedSpillStackObject(4, CurOffset, true));
LLVM_DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx()
<< ") for other register at " << CurOffset << "\n");
} else {
MFI.setObjectOffset(I.getFrameIdx(), CurOffset);
LLVM_DEBUG(dbgs() << "Updating fixed object (" << I.getFrameIdx()
<< ") for other register at " << CurOffset << "\n");
}
CurOffset -= 4;
}
return true;
}
bool ARCFrameLowering::spillCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
LLVM_DEBUG(dbgs() << "Spill callee saved registers: "
<< MBB.getParent()->getName() << "\n");
unsigned Last = determineLastCalleeSave(CSI);
if (UseSaveRestoreFunclet && Last > ARC::R14) {
return true;
}
return false;
}
bool ARCFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
LLVM_DEBUG(dbgs() << "Restore callee saved registers: "
<< MBB.getParent()->getName() << "\n");
unsigned Last = determineLastCalleeSave(CSI);
if (UseSaveRestoreFunclet && Last > ARC::R14) {
return true;
}
return false;
}
void ARCFrameLowering::processFunctionBeforeFrameFinalized(
MachineFunction &MF, RegScavenger *RS) const {
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
LLVM_DEBUG(dbgs() << "Process function before frame finalized: "
<< MF.getName() << "\n");
MachineFrameInfo &MFI = MF.getFrameInfo();
LLVM_DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n");
const TargetRegisterClass *RC = &ARC::GPR32RegClass;
if (MFI.hasStackObjects()) {
int RegScavFI = MFI.CreateStackObject(RegInfo->getSpillSize(*RC),
RegInfo->getSpillAlign(*RC), false);
RS->addScavengingFrameIndex(RegScavFI);
LLVM_DEBUG(dbgs() << "Created scavenging index RegScavFI=" << RegScavFI
<< "\n");
}
}
static void emitRegUpdate(MachineBasicBlock &MBB,
MachineBasicBlock::iterator &MBBI, DebugLoc dl,
unsigned Reg, int NumBytes, bool IsAdd,
const ARCInstrInfo *TII) {
unsigned Opc;
if (isUInt<6>(NumBytes))
Opc = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6;
else if (isInt<12>(NumBytes))
Opc = IsAdd ? ARC::ADD_rrs12 : ARC::SUB_rrs12;
else
Opc = IsAdd ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
BuildMI(MBB, MBBI, dl, TII->get(Opc), Reg)
.addReg(Reg, RegState::Kill)
.addImm(NumBytes);
}
MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr(
MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
LLVM_DEBUG(dbgs() << "EmitCallFramePseudo: " << MF.getName() << "\n");
const ARCInstrInfo *TII = MF.getSubtarget<ARCSubtarget>().getInstrInfo();
MachineInstr &Old = *I;
DebugLoc dl = Old.getDebugLoc();
unsigned Amt = Old.getOperand(0).getImm();
auto *AFI = MF.getInfo<ARCFunctionInfo>();
if (!hasFP(MF)) {
if (Amt > AFI->MaxCallStackReq && Old.getOpcode() == ARC::ADJCALLSTACKDOWN)
AFI->MaxCallStackReq = Amt;
} else {
if (Amt != 0) {
assert((Old.getOpcode() == ARC::ADJCALLSTACKDOWN ||
Old.getOpcode() == ARC::ADJCALLSTACKUP) &&
"Unknown Frame Pseudo.");
bool IsAdd = (Old.getOpcode() == ARC::ADJCALLSTACKUP);
emitRegUpdate(MBB, I, dl, ARC::SP, Amt, IsAdd, TII);
}
}
return MBB.erase(I);
}
bool ARCFrameLowering::hasFP(const MachineFunction &MF) const {
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) ||
MF.getFrameInfo().hasVarSizedObjects() ||
MF.getFrameInfo().isFrameAddressTaken() ||
RegInfo->hasStackRealignment(MF);
return HasFP;
}