mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-27 13:30:05 +00:00
4f28c1c714
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@123399 91177308-0d34-0410-b5e6-96231b3b80d8
277 lines
11 KiB
C++
277 lines
11 KiB
C++
//===-- SPUTargetMachine.cpp - Define TargetMachine for Cell SPU ----------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Top-level implementation for the Cell SPU target.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SPU.h"
|
|
#include "SPUFrameLowering.h"
|
|
#include "SPURegisterNames.h"
|
|
#include "SPUInstrBuilder.h"
|
|
#include "SPUInstrInfo.h"
|
|
#include "llvm/Function.h"
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/RegisterScavenging.h"
|
|
#include "llvm/Target/TargetData.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
using namespace llvm;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SPUFrameLowering:
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
SPUFrameLowering::SPUFrameLowering(const SPUSubtarget &sti)
|
|
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown, 16, 0),
|
|
Subtarget(sti) {
|
|
LR[0].first = SPU::R0;
|
|
LR[0].second = 16;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// hasFP - Return true if the specified function actually has a dedicated frame
|
|
// pointer register. This is true if the function needs a frame pointer and has
|
|
// a non-zero stack size.
|
|
bool SPUFrameLowering::hasFP(const MachineFunction &MF) const {
|
|
const MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
|
|
return MFI->getStackSize() &&
|
|
(DisableFramePointerElim(MF) || MFI->hasVarSizedObjects());
|
|
}
|
|
|
|
|
|
/// determineFrameLayout - Determine the size of the frame and maximum call
|
|
/// frame size.
|
|
void SPUFrameLowering::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, and the maximum alignment
|
|
// (if any) of the fixed frame objects.
|
|
unsigned TargetAlign = getStackAlignment();
|
|
unsigned Align = std::max(TargetAlign, MFI->getMaxAlignment());
|
|
assert(isPowerOf2_32(Align) && "Alignment is not power of 2");
|
|
unsigned AlignMask = Align - 1;
|
|
|
|
// 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 = (maxCallFrameSize + AlignMask) & ~AlignMask;
|
|
|
|
// Update maximum call frame size.
|
|
MFI->setMaxCallFrameSize(maxCallFrameSize);
|
|
|
|
// Include call frame size in total.
|
|
FrameSize += maxCallFrameSize;
|
|
|
|
// Make sure the frame is aligned.
|
|
FrameSize = (FrameSize + AlignMask) & ~AlignMask;
|
|
|
|
// Update frame info.
|
|
MFI->setStackSize(FrameSize);
|
|
}
|
|
|
|
void SPUFrameLowering::emitPrologue(MachineFunction &MF) const {
|
|
MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB
|
|
MachineBasicBlock::iterator MBBI = MBB.begin();
|
|
MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
const SPUInstrInfo &TII =
|
|
*static_cast<const SPUInstrInfo*>(MF.getTarget().getInstrInfo());
|
|
MachineModuleInfo &MMI = MF.getMMI();
|
|
DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
|
|
|
|
// Prepare for debug frame info.
|
|
bool hasDebugInfo = MMI.hasDebugInfo();
|
|
MCSymbol *FrameLabel = 0;
|
|
|
|
// Move MBBI back to the beginning of the function.
|
|
MBBI = MBB.begin();
|
|
|
|
// Work out frame sizes.
|
|
determineFrameLayout(MF);
|
|
int FrameSize = MFI->getStackSize();
|
|
|
|
assert((FrameSize & 0xf) == 0
|
|
&& "SPURegisterInfo::emitPrologue: FrameSize not aligned");
|
|
|
|
// the "empty" frame size is 16 - just the register scavenger spill slot
|
|
if (FrameSize > 16 || MFI->adjustsStack()) {
|
|
FrameSize = -(FrameSize + SPUFrameLowering::minStackSize());
|
|
if (hasDebugInfo) {
|
|
// Mark effective beginning of when frame pointer becomes valid.
|
|
FrameLabel = MMI.getContext().CreateTempSymbol();
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::PROLOG_LABEL)).addSym(FrameLabel);
|
|
}
|
|
|
|
// Adjust stack pointer, spilling $lr -> 16($sp) and $sp -> -FrameSize($sp)
|
|
// for the ABI
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::STQDr32), SPU::R0).addImm(16)
|
|
.addReg(SPU::R1);
|
|
if (isInt<10>(FrameSize)) {
|
|
// Spill $sp to adjusted $sp
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::STQDr32), SPU::R1).addImm(FrameSize)
|
|
.addReg(SPU::R1);
|
|
// Adjust $sp by required amout
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::AIr32), SPU::R1).addReg(SPU::R1)
|
|
.addImm(FrameSize);
|
|
} else if (isInt<16>(FrameSize)) {
|
|
// Frame size can be loaded into ILr32n, so temporarily spill $r2 and use
|
|
// $r2 to adjust $sp:
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::STQDr128), SPU::R2)
|
|
.addImm(-16)
|
|
.addReg(SPU::R1);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::ILr32), SPU::R2)
|
|
.addImm(FrameSize);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::STQXr32), SPU::R1)
|
|
.addReg(SPU::R2)
|
|
.addReg(SPU::R1);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::Ar32), SPU::R1)
|
|
.addReg(SPU::R1)
|
|
.addReg(SPU::R2);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::SFIr32), SPU::R2)
|
|
.addReg(SPU::R2)
|
|
.addImm(16);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::LQXr128), SPU::R2)
|
|
.addReg(SPU::R2)
|
|
.addReg(SPU::R1);
|
|
} else {
|
|
report_fatal_error("Unhandled frame size: " + Twine(FrameSize));
|
|
}
|
|
|
|
if (hasDebugInfo) {
|
|
std::vector<MachineMove> &Moves = MMI.getFrameMoves();
|
|
|
|
// Show update of SP.
|
|
MachineLocation SPDst(MachineLocation::VirtualFP);
|
|
MachineLocation SPSrc(MachineLocation::VirtualFP, -FrameSize);
|
|
Moves.push_back(MachineMove(FrameLabel, SPDst, SPSrc));
|
|
|
|
// Add callee saved registers to move list.
|
|
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
|
|
for (unsigned I = 0, E = CSI.size(); I != E; ++I) {
|
|
int Offset = MFI->getObjectOffset(CSI[I].getFrameIdx());
|
|
unsigned Reg = CSI[I].getReg();
|
|
if (Reg == SPU::R0) continue;
|
|
MachineLocation CSDst(MachineLocation::VirtualFP, Offset);
|
|
MachineLocation CSSrc(Reg);
|
|
Moves.push_back(MachineMove(FrameLabel, CSDst, CSSrc));
|
|
}
|
|
|
|
// Mark effective beginning of when frame pointer is ready.
|
|
MCSymbol *ReadyLabel = MMI.getContext().CreateTempSymbol();
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::PROLOG_LABEL)).addSym(ReadyLabel);
|
|
|
|
MachineLocation FPDst(SPU::R1);
|
|
MachineLocation FPSrc(MachineLocation::VirtualFP);
|
|
Moves.push_back(MachineMove(ReadyLabel, FPDst, FPSrc));
|
|
}
|
|
} else {
|
|
// This is a leaf function -- insert a branch hint iff there are
|
|
// sufficient number instructions in the basic block. Note that
|
|
// this is just a best guess based on the basic block's size.
|
|
if (MBB.size() >= (unsigned) SPUFrameLowering::branchHintPenalty()) {
|
|
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
|
|
dl = MBBI->getDebugLoc();
|
|
|
|
// Insert terminator label
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::PROLOG_LABEL))
|
|
.addSym(MMI.getContext().CreateTempSymbol());
|
|
}
|
|
}
|
|
}
|
|
|
|
void SPUFrameLowering::emitEpilogue(MachineFunction &MF,
|
|
MachineBasicBlock &MBB) const {
|
|
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
|
|
const SPUInstrInfo &TII =
|
|
*static_cast<const SPUInstrInfo*>(MF.getTarget().getInstrInfo());
|
|
const MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
int FrameSize = MFI->getStackSize();
|
|
int LinkSlotOffset = SPUFrameLowering::stackSlotSize();
|
|
DebugLoc dl = MBBI->getDebugLoc();
|
|
|
|
assert(MBBI->getOpcode() == SPU::RET &&
|
|
"Can only insert epilog into returning blocks");
|
|
assert((FrameSize & 0xf) == 0 && "FrameSize not aligned");
|
|
|
|
// the "empty" frame size is 16 - just the register scavenger spill slot
|
|
if (FrameSize > 16 || MFI->adjustsStack()) {
|
|
FrameSize = FrameSize + SPUFrameLowering::minStackSize();
|
|
if (isInt<10>(FrameSize + LinkSlotOffset)) {
|
|
// Reload $lr, adjust $sp by required amount
|
|
// Note: We do this to slightly improve dual issue -- not by much, but it
|
|
// is an opportunity for dual issue.
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::LQDr128), SPU::R0)
|
|
.addImm(FrameSize + LinkSlotOffset)
|
|
.addReg(SPU::R1);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::AIr32), SPU::R1)
|
|
.addReg(SPU::R1)
|
|
.addImm(FrameSize);
|
|
} else if (FrameSize <= (1 << 16) - 1 && FrameSize >= -(1 << 16)) {
|
|
// Frame size can be loaded into ILr32n, so temporarily spill $r2 and use
|
|
// $r2 to adjust $sp:
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::STQDr128), SPU::R2)
|
|
.addImm(16)
|
|
.addReg(SPU::R1);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::ILr32), SPU::R2)
|
|
.addImm(FrameSize);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::Ar32), SPU::R1)
|
|
.addReg(SPU::R1)
|
|
.addReg(SPU::R2);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::LQDr128), SPU::R0)
|
|
.addImm(16)
|
|
.addReg(SPU::R1);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::SFIr32), SPU::R2).
|
|
addReg(SPU::R2)
|
|
.addImm(16);
|
|
BuildMI(MBB, MBBI, dl, TII.get(SPU::LQXr128), SPU::R2)
|
|
.addReg(SPU::R2)
|
|
.addReg(SPU::R1);
|
|
} else {
|
|
report_fatal_error("Unhandled frame size: " + Twine(FrameSize));
|
|
}
|
|
}
|
|
}
|
|
|
|
void SPUFrameLowering::getInitialFrameState(std::vector<MachineMove> &Moves)
|
|
const {
|
|
// Initial state of the frame pointer is R1.
|
|
MachineLocation Dst(MachineLocation::VirtualFP);
|
|
MachineLocation Src(SPU::R1, 0);
|
|
Moves.push_back(MachineMove(0, Dst, Src));
|
|
}
|
|
|
|
void SPUFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
|
RegScavenger *RS) const{
|
|
// Mark LR and SP unused, since the prolog spills them to stack and
|
|
// we don't want anyone else to spill them for us.
|
|
//
|
|
// Also, unless R2 is really used someday, don't spill it automatically.
|
|
MF.getRegInfo().setPhysRegUnused(SPU::R0);
|
|
MF.getRegInfo().setPhysRegUnused(SPU::R1);
|
|
MF.getRegInfo().setPhysRegUnused(SPU::R2);
|
|
|
|
MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
const TargetRegisterClass *RC = &SPU::R32CRegClass;
|
|
RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
|
|
RC->getAlignment(),
|
|
false));
|
|
}
|