aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/Target/ARC/ARCFrameLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Target/ARC/ARCFrameLowering.cpp')
-rw-r--r--contrib/llvm/lib/Target/ARC/ARCFrameLowering.cpp471
1 files changed, 471 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/ARC/ARCFrameLowering.cpp b/contrib/llvm/lib/Target/ARC/ARCFrameLowering.cpp
new file mode 100644
index 000000000000..195a781950be
--- /dev/null
+++ b/contrib/llvm/lib/Target/ARC/ARCFrameLowering.cpp
@@ -0,0 +1,471 @@
+//===- ARCFrameLowering.cpp - ARC Frame Information -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the ARC implementation of the TargetFrameLowering class.
+//
+//===----------------------------------------------------------------------===//
+
+#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;
+ }
+
+ 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
+ AdjOp = Positive ? ARC::ADD_rrlimm : ARC::SUB_rrlimm;
+
+ BuildMI(MBB, MBBI, dl, TII.get(AdjOp), StackPtr)
+ .addReg(StackPtr)
+ .addImm(AbsAmount);
+}
+
+static unsigned
+determineLastCalleeSave(const std::vector<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 {
+ 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) {
+ // Allocate by adjusting by the negative of what the record holder tracked
+ // it tracked a positive offset in a downward growing stack.
+ ScalarAlloc = -ScalarAlloc;
+ }
+
+ generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), DebugLoc(),
+ ScalarAlloc, ARC::SP);
+}
+
+/// Insert prolog code into the function.
+/// For ARC, this inserts a call to a function that puts required callee saved
+/// registers onto the stack, when enough callee saved registers are required.
+void ARCFrameLowering::emitPrologue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ 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();
+ // Debug location must be unknown since the first debug location is used
+ // to determine the end of the prologue.
+ 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()) {
+ // Add in the varargs area here first.
+ DEBUG(dbgs() << "Varargs\n");
+ unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
+ BuildMI(MBB, MBBI, dl, TII->get(ARC::SUB_rru6))
+ .addReg(ARC::SP)
+ .addReg(ARC::SP)
+ .addImm(VarArgsBytes);
+ }
+ if (hasFP(MF)) {
+ 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) {
+ DEBUG(dbgs() << "Creating store funclet.\n");
+ // BL to __save_r13_to_<TRI->getRegAsmName()>
+ 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 we haven't saved BLINK, but we need to...do that now.
+ if (MFI.hasCalls() && !SavedBlink) {
+ 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);
+ // We have already saved some of the stack...
+ DEBUG(dbgs() << "Adjusting stack by: "
+ << (MFI.getStackSize() - AlreadyAdjusted) << "\n");
+ generateStackAdjustment(MBB, MBBI, *ST.getInstrInfo(), dl,
+ -(MFI.getStackSize() - AlreadyAdjusted), ARC::SP);
+
+ if (hasFP(MF)) {
+ 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());
+ }
+
+ // Emit CFI records:
+ // .cfi_def_cfa_offset StackSize
+ // .cfi_offset fp, -StackSize
+ // .cfi_offset blink, -StackSize+4
+ unsigned CFIIndex = MF.addFrameInst(
+ MCCFIInstruction::createDefCfaOffset(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);
+ }
+ // CFI for the rest of the registers.
+ for (const auto &Entry : CSI) {
+ unsigned Reg = Entry.getReg();
+ int FI = Entry.getFrameIdx();
+ // Skip BLINK and FP.
+ 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);
+ }
+}
+
+/// Insert epilog code into the function.
+/// For ARC, this inserts a call to a function that restores callee saved
+/// registers onto the stack, when enough callee saved registers are required.
+void ARCFrameLowering::emitEpilogue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ 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 we have variable sized frame objects, then we have to move
+ // the stack pointer to a known spot (fp - StackSize).
+ // Then, replace the frame pointer by (new) [sp,StackSize-4].
+ // Then, move the stack pointer the rest of the way (sp = sp + StackSize).
+ if (hasFP(MF)) {
+ BuildMI(MBB, MBBI, DebugLoc(), TII->get(ARC::SUB_rru6), ARC::SP)
+ .addReg(ARC::FP)
+ .addImm(StackSize);
+ AmountAboveFunclet += 4;
+ }
+
+ // Now, move the stack pointer to the bottom of the save area for the funclet.
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
+ unsigned Last = determineLastCalleeSave(CSI);
+ unsigned StackSlotsUsedByFunclet = 0;
+ // Now, restore the callee save registers.
+ if (UseSaveRestoreFunclet && Last > ARC::R14) {
+ // BL to __ld_r13_to_<TRI->getRegAsmName()>
+ StackSlotsUsedByFunclet = Last - ARC::R12;
+ AmountAboveFunclet += 4 * (StackSlotsUsedByFunclet + 1);
+ SavedBlink = true;
+ }
+
+ if (MFI.hasCalls() && !SavedBlink) {
+ AmountAboveFunclet += 4;
+ SavedBlink = true;
+ }
+
+ // Move the stack pointer up to the point of the funclet.
+ if (StackSize - AmountAboveFunclet) {
+ BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6))
+ .addReg(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);
+ BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6))
+ .addReg(ARC::SP)
+ .addReg(ARC::SP)
+ .addImm(4 * (StackSlotsUsedByFunclet));
+ }
+ // Now, pop blink if necessary.
+ if (SavedBlink) {
+ BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::POP_S_BLINK));
+ }
+ // Now, pop fp if necessary.
+ if (hasFP(MF)) {
+ BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::LD_AB_rs9))
+ .addReg(ARC::SP, RegState::Define)
+ .addReg(ARC::FP, RegState::Define)
+ .addReg(ARC::SP)
+ .addImm(4);
+ }
+
+ // Relieve the varargs area if necessary.
+ if (MF.getFunction().isVarArg()) {
+ // Add in the varargs area here first.
+ DEBUG(dbgs() << "Varargs\n");
+ unsigned VarArgsBytes = MFI.getObjectSize(AFI->getVarArgsFrameIndex());
+ BuildMI(MBB, MBBI, MBB.findDebugLoc(MBBI), TII->get(ARC::ADD_rru6))
+ .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 {
+ // Use this opportunity to assign the spill slots for all of the potential
+ // callee save registers (blink, fp, r13->r25) that we care about the
+ // placement for. We can calculate all of that data here.
+ int CurOffset = -4;
+ unsigned Last = determineLastCalleeSave(CSI);
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ if (hasFP(MF)) {
+ // Create a fixed slot at for FP
+ int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
+ DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for FP at "
+ << CurOffset << "\n");
+ (void)StackObj;
+ CurOffset -= 4;
+ }
+ if (MFI.hasCalls() || (UseSaveRestoreFunclet && Last > ARC::R14)) {
+ // Create a fixed slot for BLINK.
+ int StackObj = MFI.CreateFixedSpillStackObject(4, CurOffset, true);
+ DEBUG(dbgs() << "Creating fixed object (" << StackObj << ") for BLINK at "
+ << CurOffset << "\n");
+ (void)StackObj;
+ CurOffset -= 4;
+ }
+
+ // Create slots for last down to r13.
+ for (unsigned Which = Last; Which > ARC::R12; Which--) {
+ auto RegI = getSavedReg(CSI, Which);
+ if (RegI == CSI.end() || RegI->getFrameIdx() == 0) {
+ // Always create the stack slot. If for some reason the register isn't in
+ // the save list, then don't worry about it.
+ 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));
+ DEBUG(dbgs() << "Creating fixed object (" << I.getFrameIdx()
+ << ") for other register at " << CurOffset << "\n");
+ } else {
+ MFI.setObjectOffset(I.getFrameIdx(), CurOffset);
+ 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,
+ const std::vector<CalleeSavedInfo> &CSI,
+ const TargetRegisterInfo *TRI) const {
+ DEBUG(dbgs() << "Spill callee saved registers: "
+ << MBB.getParent()->getName() << "\n");
+ // There are routines for saving at least 3 registers (r13 to r15, etc.)
+ unsigned Last = determineLastCalleeSave(CSI);
+ if (UseSaveRestoreFunclet && Last > ARC::R14) {
+ // Use setObjectOffset for these registers.
+ // Needs to be in or before processFunctionBeforeFrameFinalized.
+ // Or, do assignCalleeSaveSpillSlots?
+ // Will be handled in prolog.
+ return true;
+ }
+ return false;
+}
+
+bool ARCFrameLowering::restoreCalleeSavedRegisters(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
+ std::vector<CalleeSavedInfo> &CSI, const TargetRegisterInfo *TRI) const {
+ DEBUG(dbgs() << "Restore callee saved registers: "
+ << MBB.getParent()->getName() << "\n");
+ // There are routines for saving at least 3 registers (r13 to r15, etc.)
+ unsigned Last = determineLastCalleeSave(CSI);
+ if (UseSaveRestoreFunclet && Last > ARC::R14) {
+ // Will be handled in epilog.
+ return true;
+ }
+ return false;
+}
+
+// Adjust local variables that are 4-bytes or larger to 4-byte boundary
+void ARCFrameLowering::processFunctionBeforeFrameFinalized(
+ MachineFunction &MF, RegScavenger *RS) const {
+ const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
+ DEBUG(dbgs() << "Process function before frame finalized: "
+ << MF.getName() << "\n");
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ DEBUG(dbgs() << "Current stack size: " << MFI.getStackSize() << "\n");
+ const TargetRegisterClass *RC = &ARC::GPR32RegClass;
+ if (MFI.hasStackObjects()) {
+ int RegScavFI = MFI.CreateStackObject(
+ RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false);
+ RS->addScavengingFrameIndex(RegScavFI);
+ 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 = IsAdd ? ARC::ADD_rru6 : ARC::SUB_rru6;
+ 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 {
+ 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->needsStackRealignment(MF);
+ return HasFP;
+}