diff options
Diffstat (limited to 'contrib/llvm/lib/Target/ARC/ARCFrameLowering.cpp')
-rw-r--r-- | contrib/llvm/lib/Target/ARC/ARCFrameLowering.cpp | 471 |
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; +} |