llvm-6502/lib/Target/Hexagon/HexagonFrameLowering.cpp
Eli Bendersky 700ed80d3d Move the eliminateCallFramePseudoInstr method from TargetRegisterInfo
to TargetFrameLowering, where it belongs. Incidentally, this allows us
to delete some duplicated (and slightly different!) code in TRI.

There are potentially other layering problems that can be cleaned up
as a result, or in a similar manner.

The refactoring was OK'd by Anton Korobeynikov on llvmdev.

Note: this touches the target interfaces, so out-of-tree targets may
be affected.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@175788 91177308-0d34-0410-b5e6-96231b3b80d8
2013-02-21 20:05:00 +00:00

349 lines
12 KiB
C++

//===-- HexagonFrameLowering.cpp - Define frame lowering ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//
//===----------------------------------------------------------------------===//
#include "HexagonFrameLowering.h"
#include "Hexagon.h"
#include "HexagonInstrInfo.h"
#include "HexagonMachineFunctionInfo.h"
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetMachine.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MachineLocation.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
using namespace llvm;
static cl::opt<bool> DisableDeallocRet(
"disable-hexagon-dealloc-ret",
cl::Hidden,
cl::desc("Disable Dealloc Return for Hexagon target"));
/// determineFrameLayout - Determine the size of the frame and maximum call
/// frame size.
void HexagonFrameLowering::determineFrameLayout(MachineFunction &MF) const {
MachineFrameInfo *MFI = MF.getFrameInfo();
// Get the number of bytes to allocate from the FrameInfo.
unsigned FrameSize = MFI->getStackSize();
// Get the alignments provided by the target.
unsigned TargetAlign = MF.getTarget().getFrameLowering()->getStackAlignment();
// Get the maximum call frame size of all the calls.
unsigned maxCallFrameSize = MFI->getMaxCallFrameSize();
// If we have dynamic alloca then maxCallFrameSize needs to be aligned so
// that allocations will be aligned.
if (MFI->hasVarSizedObjects())
maxCallFrameSize = RoundUpToAlignment(maxCallFrameSize, TargetAlign);
// Update maximum call frame size.
MFI->setMaxCallFrameSize(maxCallFrameSize);
// Include call frame size in total.
FrameSize += maxCallFrameSize;
// Make sure the frame is aligned.
FrameSize = RoundUpToAlignment(FrameSize, TargetAlign);
// Update frame info.
MFI->setStackSize(FrameSize);
}
void HexagonFrameLowering::emitPrologue(MachineFunction &MF) const {
MachineBasicBlock &MBB = MF.front();
MachineFrameInfo *MFI = MF.getFrameInfo();
MachineModuleInfo &MMI = MF.getMMI();
MachineBasicBlock::iterator MBBI = MBB.begin();
const HexagonRegisterInfo *QRI =
static_cast<const HexagonRegisterInfo *>(MF.getTarget().getRegisterInfo());
DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
determineFrameLayout(MF);
// Check if frame moves are needed for EH.
bool needsFrameMoves = MMI.hasDebugInfo() ||
!MF.getFunction()->needsUnwindTableEntry();
// Get the number of bytes to allocate from the FrameInfo.
int NumBytes = (int) MFI->getStackSize();
// LLVM expects allocframe not to be the first instruction in the
// basic block.
MachineBasicBlock::iterator InsertPt = MBB.begin();
//
// ALLOCA adjust regs. Iterate over ADJDYNALLOC nodes and change the offset.
//
HexagonMachineFunctionInfo *FuncInfo =
MF.getInfo<HexagonMachineFunctionInfo>();
const std::vector<MachineInstr*>& AdjustRegs =
FuncInfo->getAllocaAdjustInsts();
for (std::vector<MachineInstr*>::const_iterator i = AdjustRegs.begin(),
e = AdjustRegs.end();
i != e; ++i) {
MachineInstr* MI = *i;
assert((MI->getOpcode() == Hexagon::ADJDYNALLOC) &&
"Expected adjust alloca node");
MachineOperand& MO = MI->getOperand(2);
assert(MO.isImm() && "Expected immediate");
MO.setImm(MFI->getMaxCallFrameSize());
}
std::vector<MachineMove> &Moves = MMI.getFrameMoves();
if (needsFrameMoves) {
// Advance CFA. DW_CFA_def_cfa
unsigned FPReg = QRI->getFrameRegister();
unsigned RAReg = QRI->getRARegister();
MachineLocation Dst(MachineLocation::VirtualFP);
MachineLocation Src(FPReg, -8);
Moves.push_back(MachineMove(0, Dst, Src));
// R31 = (R31 - #4)
MachineLocation LRDst(RAReg, -4);
MachineLocation LRSrc(RAReg);
Moves.push_back(MachineMove(0, LRDst, LRSrc));
// R30 = (R30 - #8)
MachineLocation SPDst(FPReg, -8);
MachineLocation SPSrc(FPReg);
Moves.push_back(MachineMove(0, SPDst, SPSrc));
}
//
// Only insert ALLOCFRAME if we need to.
//
if (hasFP(MF)) {
// Check for overflow.
// Hexagon_TODO: Ugh! hardcoding. Is there an API that can be used?
const int ALLOCFRAME_MAX = 16384;
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
if (NumBytes >= ALLOCFRAME_MAX) {
// Emit allocframe(#0).
BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::ALLOCFRAME)).addImm(0);
// Subtract offset from frame pointer.
BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::CONST32_Int_Real),
HEXAGON_RESERVED_REG_1).addImm(NumBytes);
BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::SUB_rr),
QRI->getStackRegister()).
addReg(QRI->getStackRegister()).
addReg(HEXAGON_RESERVED_REG_1);
} else {
BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::ALLOCFRAME)).addImm(NumBytes);
}
}
}
// Returns true if MBB has a machine instructions that indicates a tail call
// in the block.
bool HexagonFrameLowering::hasTailCall(MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
unsigned RetOpcode = MBBI->getOpcode();
return RetOpcode == Hexagon::TCRETURNtg || RetOpcode == Hexagon::TCRETURNtext;
}
void HexagonFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = prior(MBB.end());
DebugLoc dl = MBBI->getDebugLoc();
//
// Only insert deallocframe if we need to.
//
if (hasFP(MF)) {
MachineBasicBlock::iterator MBBI = prior(MBB.end());
MachineBasicBlock::iterator MBBI_end = MBB.end();
//
// For Hexagon, we don't need the frame size.
//
MachineFrameInfo *MFI = MF.getFrameInfo();
int NumBytes = (int) MFI->getStackSize();
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
// Replace 'jumpr r31' instruction with dealloc_return for V4 and higher
// versions.
if (STI.hasV4TOps() && MBBI->getOpcode() == Hexagon::JMPR
&& !DisableDeallocRet) {
// Remove jumpr node.
MBB.erase(MBBI);
// Add dealloc_return.
BuildMI(MBB, MBBI_end, dl, TII.get(Hexagon::DEALLOC_RET_V4))
.addImm(NumBytes);
} else { // Add deallocframe for V2 and V3.
BuildMI(MBB, MBBI, dl, TII.get(Hexagon::DEALLOCFRAME)).addImm(NumBytes);
}
}
}
bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
const HexagonMachineFunctionInfo *FuncInfo =
MF.getInfo<HexagonMachineFunctionInfo>();
return (MFI->hasCalls() || (MFI->getStackSize() > 0) ||
FuncInfo->hasClobberLR() );
}
static inline
unsigned uniqueSuperReg(unsigned Reg, const TargetRegisterInfo *TRI) {
MCSuperRegIterator SRI(Reg, TRI);
assert(SRI.isValid() && "Expected a superreg");
unsigned SuperReg = *SRI;
++SRI;
assert(!SRI.isValid() && "Expected exactly one superreg");
return SuperReg;
}
bool
HexagonFrameLowering::spillCalleeSavedRegisters(
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const {
MachineFunction *MF = MBB.getParent();
const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo();
if (CSI.empty()) {
return false;
}
// We can only schedule double loads if we spill contiguous callee-saved regs
// For instance, we cannot scheduled double-word loads if we spill r24,
// r26, and r27.
// Hexagon_TODO: We can try to double-word align odd registers for -O2 and
// above.
bool ContiguousRegs = true;
for (unsigned i = 0; i < CSI.size(); ++i) {
unsigned Reg = CSI[i].getReg();
//
// Check if we can use a double-word store.
//
unsigned SuperReg = uniqueSuperReg(Reg, TRI);
bool CanUseDblStore = false;
const TargetRegisterClass* SuperRegClass = 0;
if (ContiguousRegs && (i < CSI.size()-1)) {
unsigned SuperRegNext = uniqueSuperReg(CSI[i+1].getReg(), TRI);
SuperRegClass = TRI->getMinimalPhysRegClass(SuperReg);
CanUseDblStore = (SuperRegNext == SuperReg);
}
if (CanUseDblStore) {
TII.storeRegToStackSlot(MBB, MI, SuperReg, true,
CSI[i+1].getFrameIdx(), SuperRegClass, TRI);
MBB.addLiveIn(SuperReg);
++i;
} else {
// Cannot use a double-word store.
ContiguousRegs = false;
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.storeRegToStackSlot(MBB, MI, Reg, true, CSI[i].getFrameIdx(), RC,
TRI);
MBB.addLiveIn(Reg);
}
}
return true;
}
bool HexagonFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const {
MachineFunction *MF = MBB.getParent();
const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo();
if (CSI.empty()) {
return false;
}
// We can only schedule double loads if we spill contiguous callee-saved regs
// For instance, we cannot scheduled double-word loads if we spill r24,
// r26, and r27.
// Hexagon_TODO: We can try to double-word align odd registers for -O2 and
// above.
bool ContiguousRegs = true;
for (unsigned i = 0; i < CSI.size(); ++i) {
unsigned Reg = CSI[i].getReg();
//
// Check if we can use a double-word load.
//
unsigned SuperReg = uniqueSuperReg(Reg, TRI);
const TargetRegisterClass* SuperRegClass = 0;
bool CanUseDblLoad = false;
if (ContiguousRegs && (i < CSI.size()-1)) {
unsigned SuperRegNext = uniqueSuperReg(CSI[i+1].getReg(), TRI);
SuperRegClass = TRI->getMinimalPhysRegClass(SuperReg);
CanUseDblLoad = (SuperRegNext == SuperReg);
}
if (CanUseDblLoad) {
TII.loadRegFromStackSlot(MBB, MI, SuperReg, CSI[i+1].getFrameIdx(),
SuperRegClass, TRI);
MBB.addLiveIn(SuperReg);
++i;
} else {
// Cannot use a double-word load.
ContiguousRegs = false;
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.loadRegFromStackSlot(MBB, MI, Reg, CSI[i].getFrameIdx(), RC, TRI);
MBB.addLiveIn(Reg);
}
}
return true;
}
void HexagonFrameLowering::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
MachineInstr &MI = *I;
if (MI.getOpcode() == Hexagon::ADJCALLSTACKDOWN) {
// Hexagon_TODO: add code
} else if (MI.getOpcode() == Hexagon::ADJCALLSTACKUP) {
// Hexagon_TODO: add code
} else {
llvm_unreachable("Cannot handle this call frame pseudo instruction");
}
MBB.erase(I);
}
int HexagonFrameLowering::getFrameIndexOffset(const MachineFunction &MF,
int FI) const {
return MF.getFrameInfo()->getObjectOffset(FI);
}