llvm-project/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp

333 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 "Hexagon.h"
#include "HexagonInstrInfo.h"
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetMachine.h"
#include "HexagonMachineFunctionInfo.h"
#include "HexagonFrameLowering.h"
#include "llvm/Function.h"
#include "llvm/Type.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/MC/MachineLocation.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/CommandLine.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() );
}
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.
//
const unsigned* SuperReg = TRI->getSuperRegisters(Reg);
// Assume that there is exactly one superreg.
assert(SuperReg[0] && !SuperReg[1] && "Expected exactly one superreg");
bool CanUseDblStore = false;
const TargetRegisterClass* SuperRegClass = 0;
if (ContiguousRegs && (i < CSI.size()-1)) {
const unsigned* SuperRegNext = TRI->getSuperRegisters(CSI[i+1].getReg());
assert(SuperRegNext[0] && !SuperRegNext[1] &&
"Expected exactly one superreg");
SuperRegClass = TRI->getMinimalPhysRegClass(SuperReg[0]);
CanUseDblStore = (SuperRegNext[0] == SuperReg[0]);
}
if (CanUseDblStore) {
TII.storeRegToStackSlot(MBB, MI, SuperReg[0], true,
CSI[i+1].getFrameIdx(), SuperRegClass, TRI);
MBB.addLiveIn(SuperReg[0]);
++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.
//
const unsigned* SuperReg = TRI->getSuperRegisters(Reg);
const TargetRegisterClass* SuperRegClass = 0;
// Assume that there is exactly one superreg.
assert(SuperReg[0] && !SuperReg[1] && "Expected exactly one superreg");
bool CanUseDblLoad = false;
if (ContiguousRegs && (i < CSI.size()-1)) {
const unsigned* SuperRegNext = TRI->getSuperRegisters(CSI[i+1].getReg());
assert(SuperRegNext[0] && !SuperRegNext[1] &&
"Expected exactly one superreg");
SuperRegClass = TRI->getMinimalPhysRegClass(SuperReg[0]);
CanUseDblLoad = (SuperRegNext[0] == SuperReg[0]);
}
if (CanUseDblLoad) {
TII.loadRegFromStackSlot(MBB, MI, SuperReg[0], CSI[i+1].getFrameIdx(),
SuperRegClass, TRI);
MBB.addLiveIn(SuperReg[0]);
++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;
}
int HexagonFrameLowering::getFrameIndexOffset(const MachineFunction &MF,
int FI) const {
return MF.getFrameInfo()->getObjectOffset(FI);
}