mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-26 23:29:22 +00:00
When registers must be live throughout the scheduling region, increase the limit for the register class. Once we exceed the original limit, they will be spilled, and there's no point further reducing pressure. This isn't a perfect heuristics but avoids a situation where the scheduler could become trapped by trying to achieve the impossible. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187436 91177308-0d34-0410-b5e6-96231b3b80d8
847 lines
30 KiB
C++
847 lines
30 KiB
C++
//===-- RegisterPressure.cpp - Dynamic Register Pressure ------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the RegisterPressure class which can be used to track
|
|
// MachineInstr level register pressure.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/CodeGen/RegisterPressure.h"
|
|
#include "llvm/CodeGen/LiveInterval.h"
|
|
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/RegisterClassInfo.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
using namespace llvm;
|
|
|
|
/// Increase pressure for each pressure set provided by TargetRegisterInfo.
|
|
static void increaseSetPressure(std::vector<unsigned> &CurrSetPressure,
|
|
std::vector<unsigned> &MaxSetPressure,
|
|
const int *PSet, unsigned Weight) {
|
|
for (; *PSet != -1; ++PSet) {
|
|
CurrSetPressure[*PSet] += Weight;
|
|
if (&CurrSetPressure != &MaxSetPressure
|
|
&& CurrSetPressure[*PSet] > MaxSetPressure[*PSet]) {
|
|
MaxSetPressure[*PSet] = CurrSetPressure[*PSet];
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Decrease pressure for each pressure set provided by TargetRegisterInfo.
|
|
static void decreaseSetPressure(std::vector<unsigned> &CurrSetPressure,
|
|
const int *PSet, unsigned Weight) {
|
|
for (; *PSet != -1; ++PSet) {
|
|
assert(CurrSetPressure[*PSet] >= Weight && "register pressure underflow");
|
|
CurrSetPressure[*PSet] -= Weight;
|
|
}
|
|
}
|
|
|
|
/// Directly increase pressure only within this RegisterPressure result.
|
|
void RegisterPressure::increase(unsigned Reg, const TargetRegisterInfo *TRI,
|
|
const MachineRegisterInfo *MRI) {
|
|
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
|
|
const TargetRegisterClass *RC = MRI->getRegClass(Reg);
|
|
increaseSetPressure(MaxSetPressure, MaxSetPressure,
|
|
TRI->getRegClassPressureSets(RC),
|
|
TRI->getRegClassWeight(RC).RegWeight);
|
|
}
|
|
else {
|
|
increaseSetPressure(MaxSetPressure, MaxSetPressure,
|
|
TRI->getRegUnitPressureSets(Reg),
|
|
TRI->getRegUnitWeight(Reg));
|
|
}
|
|
}
|
|
|
|
/// Directly decrease pressure only within this RegisterPressure result.
|
|
void RegisterPressure::decrease(unsigned Reg, const TargetRegisterInfo *TRI,
|
|
const MachineRegisterInfo *MRI) {
|
|
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
|
|
const TargetRegisterClass *RC = MRI->getRegClass(Reg);
|
|
decreaseSetPressure(MaxSetPressure, TRI->getRegClassPressureSets(RC),
|
|
TRI->getRegClassWeight(RC).RegWeight);
|
|
}
|
|
else {
|
|
decreaseSetPressure(MaxSetPressure, TRI->getRegUnitPressureSets(Reg),
|
|
TRI->getRegUnitWeight(Reg));
|
|
}
|
|
}
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
void llvm::dumpRegSetPressure(ArrayRef<unsigned> SetPressure,
|
|
const TargetRegisterInfo *TRI) {
|
|
bool Empty = true;
|
|
for (unsigned i = 0, e = SetPressure.size(); i < e; ++i) {
|
|
if (SetPressure[i] != 0) {
|
|
dbgs() << TRI->getRegPressureSetName(i) << "=" << SetPressure[i] << '\n';
|
|
Empty = false;
|
|
}
|
|
}
|
|
if (Empty)
|
|
dbgs() << "\n";
|
|
}
|
|
|
|
void RegisterPressure::dump(const TargetRegisterInfo *TRI) const {
|
|
dbgs() << "Max Pressure: ";
|
|
dumpRegSetPressure(MaxSetPressure, TRI);
|
|
dbgs() << "Live In: ";
|
|
for (unsigned i = 0, e = LiveInRegs.size(); i < e; ++i)
|
|
dbgs() << PrintReg(LiveInRegs[i], TRI) << " ";
|
|
dbgs() << '\n';
|
|
dbgs() << "Live Out: ";
|
|
for (unsigned i = 0, e = LiveOutRegs.size(); i < e; ++i)
|
|
dbgs() << PrintReg(LiveOutRegs[i], TRI) << " ";
|
|
dbgs() << '\n';
|
|
}
|
|
|
|
void RegPressureTracker::dump() const {
|
|
if (!isTopClosed() || !isBottomClosed()) {
|
|
dbgs() << "Curr Pressure: ";
|
|
dumpRegSetPressure(CurrSetPressure, TRI);
|
|
}
|
|
P.dump(TRI);
|
|
}
|
|
#endif
|
|
|
|
/// Increase the current pressure as impacted by these registers and bump
|
|
/// the high water mark if needed.
|
|
void RegPressureTracker::increaseRegPressure(ArrayRef<unsigned> Regs) {
|
|
for (unsigned I = 0, E = Regs.size(); I != E; ++I) {
|
|
if (TargetRegisterInfo::isVirtualRegister(Regs[I])) {
|
|
const TargetRegisterClass *RC = MRI->getRegClass(Regs[I]);
|
|
increaseSetPressure(CurrSetPressure, P.MaxSetPressure,
|
|
TRI->getRegClassPressureSets(RC),
|
|
TRI->getRegClassWeight(RC).RegWeight);
|
|
}
|
|
else {
|
|
increaseSetPressure(CurrSetPressure, P.MaxSetPressure,
|
|
TRI->getRegUnitPressureSets(Regs[I]),
|
|
TRI->getRegUnitWeight(Regs[I]));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Simply decrease the current pressure as impacted by these registers.
|
|
void RegPressureTracker::decreaseRegPressure(ArrayRef<unsigned> Regs) {
|
|
for (unsigned I = 0, E = Regs.size(); I != E; ++I) {
|
|
if (TargetRegisterInfo::isVirtualRegister(Regs[I])) {
|
|
const TargetRegisterClass *RC = MRI->getRegClass(Regs[I]);
|
|
decreaseSetPressure(CurrSetPressure,
|
|
TRI->getRegClassPressureSets(RC),
|
|
TRI->getRegClassWeight(RC).RegWeight);
|
|
}
|
|
else {
|
|
decreaseSetPressure(CurrSetPressure, TRI->getRegUnitPressureSets(Regs[I]),
|
|
TRI->getRegUnitWeight(Regs[I]));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Clear the result so it can be used for another round of pressure tracking.
|
|
void IntervalPressure::reset() {
|
|
TopIdx = BottomIdx = SlotIndex();
|
|
MaxSetPressure.clear();
|
|
LiveInRegs.clear();
|
|
LiveOutRegs.clear();
|
|
}
|
|
|
|
/// Clear the result so it can be used for another round of pressure tracking.
|
|
void RegionPressure::reset() {
|
|
TopPos = BottomPos = MachineBasicBlock::const_iterator();
|
|
MaxSetPressure.clear();
|
|
LiveInRegs.clear();
|
|
LiveOutRegs.clear();
|
|
}
|
|
|
|
/// If the current top is not less than or equal to the next index, open it.
|
|
/// We happen to need the SlotIndex for the next top for pressure update.
|
|
void IntervalPressure::openTop(SlotIndex NextTop) {
|
|
if (TopIdx <= NextTop)
|
|
return;
|
|
TopIdx = SlotIndex();
|
|
LiveInRegs.clear();
|
|
}
|
|
|
|
/// If the current top is the previous instruction (before receding), open it.
|
|
void RegionPressure::openTop(MachineBasicBlock::const_iterator PrevTop) {
|
|
if (TopPos != PrevTop)
|
|
return;
|
|
TopPos = MachineBasicBlock::const_iterator();
|
|
LiveInRegs.clear();
|
|
}
|
|
|
|
/// If the current bottom is not greater than the previous index, open it.
|
|
void IntervalPressure::openBottom(SlotIndex PrevBottom) {
|
|
if (BottomIdx > PrevBottom)
|
|
return;
|
|
BottomIdx = SlotIndex();
|
|
LiveInRegs.clear();
|
|
}
|
|
|
|
/// If the current bottom is the previous instr (before advancing), open it.
|
|
void RegionPressure::openBottom(MachineBasicBlock::const_iterator PrevBottom) {
|
|
if (BottomPos != PrevBottom)
|
|
return;
|
|
BottomPos = MachineBasicBlock::const_iterator();
|
|
LiveInRegs.clear();
|
|
}
|
|
|
|
const LiveInterval *RegPressureTracker::getInterval(unsigned Reg) const {
|
|
if (TargetRegisterInfo::isVirtualRegister(Reg))
|
|
return &LIS->getInterval(Reg);
|
|
return LIS->getCachedRegUnit(Reg);
|
|
}
|
|
|
|
/// Setup the RegPressureTracker.
|
|
///
|
|
/// TODO: Add support for pressure without LiveIntervals.
|
|
void RegPressureTracker::init(const MachineFunction *mf,
|
|
const RegisterClassInfo *rci,
|
|
const LiveIntervals *lis,
|
|
const MachineBasicBlock *mbb,
|
|
MachineBasicBlock::const_iterator pos,
|
|
bool ShouldTrackUntiedDefs)
|
|
{
|
|
MF = mf;
|
|
TRI = MF->getTarget().getRegisterInfo();
|
|
RCI = rci;
|
|
MRI = &MF->getRegInfo();
|
|
MBB = mbb;
|
|
TrackUntiedDefs = ShouldTrackUntiedDefs;
|
|
|
|
if (RequireIntervals) {
|
|
assert(lis && "IntervalPressure requires LiveIntervals");
|
|
LIS = lis;
|
|
}
|
|
|
|
CurrPos = pos;
|
|
CurrSetPressure.assign(TRI->getNumRegPressureSets(), 0);
|
|
LiveThruPressure.clear();
|
|
|
|
if (RequireIntervals)
|
|
static_cast<IntervalPressure&>(P).reset();
|
|
else
|
|
static_cast<RegionPressure&>(P).reset();
|
|
P.MaxSetPressure = CurrSetPressure;
|
|
|
|
LiveRegs.PhysRegs.clear();
|
|
LiveRegs.PhysRegs.setUniverse(TRI->getNumRegs());
|
|
LiveRegs.VirtRegs.clear();
|
|
LiveRegs.VirtRegs.setUniverse(MRI->getNumVirtRegs());
|
|
UntiedDefs.clear();
|
|
if (TrackUntiedDefs)
|
|
UntiedDefs.setUniverse(MRI->getNumVirtRegs());
|
|
}
|
|
|
|
/// Does this pressure result have a valid top position and live ins.
|
|
bool RegPressureTracker::isTopClosed() const {
|
|
if (RequireIntervals)
|
|
return static_cast<IntervalPressure&>(P).TopIdx.isValid();
|
|
return (static_cast<RegionPressure&>(P).TopPos ==
|
|
MachineBasicBlock::const_iterator());
|
|
}
|
|
|
|
/// Does this pressure result have a valid bottom position and live outs.
|
|
bool RegPressureTracker::isBottomClosed() const {
|
|
if (RequireIntervals)
|
|
return static_cast<IntervalPressure&>(P).BottomIdx.isValid();
|
|
return (static_cast<RegionPressure&>(P).BottomPos ==
|
|
MachineBasicBlock::const_iterator());
|
|
}
|
|
|
|
|
|
SlotIndex RegPressureTracker::getCurrSlot() const {
|
|
MachineBasicBlock::const_iterator IdxPos = CurrPos;
|
|
while (IdxPos != MBB->end() && IdxPos->isDebugValue())
|
|
++IdxPos;
|
|
if (IdxPos == MBB->end())
|
|
return LIS->getMBBEndIdx(MBB);
|
|
return LIS->getInstructionIndex(IdxPos).getRegSlot();
|
|
}
|
|
|
|
/// Set the boundary for the top of the region and summarize live ins.
|
|
void RegPressureTracker::closeTop() {
|
|
if (RequireIntervals)
|
|
static_cast<IntervalPressure&>(P).TopIdx = getCurrSlot();
|
|
else
|
|
static_cast<RegionPressure&>(P).TopPos = CurrPos;
|
|
|
|
assert(P.LiveInRegs.empty() && "inconsistent max pressure result");
|
|
P.LiveInRegs.reserve(LiveRegs.PhysRegs.size() + LiveRegs.VirtRegs.size());
|
|
P.LiveInRegs.append(LiveRegs.PhysRegs.begin(), LiveRegs.PhysRegs.end());
|
|
for (SparseSet<unsigned>::const_iterator I =
|
|
LiveRegs.VirtRegs.begin(), E = LiveRegs.VirtRegs.end(); I != E; ++I)
|
|
P.LiveInRegs.push_back(*I);
|
|
std::sort(P.LiveInRegs.begin(), P.LiveInRegs.end());
|
|
P.LiveInRegs.erase(std::unique(P.LiveInRegs.begin(), P.LiveInRegs.end()),
|
|
P.LiveInRegs.end());
|
|
}
|
|
|
|
/// Set the boundary for the bottom of the region and summarize live outs.
|
|
void RegPressureTracker::closeBottom() {
|
|
if (RequireIntervals)
|
|
static_cast<IntervalPressure&>(P).BottomIdx = getCurrSlot();
|
|
else
|
|
static_cast<RegionPressure&>(P).BottomPos = CurrPos;
|
|
|
|
assert(P.LiveOutRegs.empty() && "inconsistent max pressure result");
|
|
P.LiveOutRegs.reserve(LiveRegs.PhysRegs.size() + LiveRegs.VirtRegs.size());
|
|
P.LiveOutRegs.append(LiveRegs.PhysRegs.begin(), LiveRegs.PhysRegs.end());
|
|
for (SparseSet<unsigned>::const_iterator I =
|
|
LiveRegs.VirtRegs.begin(), E = LiveRegs.VirtRegs.end(); I != E; ++I)
|
|
P.LiveOutRegs.push_back(*I);
|
|
std::sort(P.LiveOutRegs.begin(), P.LiveOutRegs.end());
|
|
P.LiveOutRegs.erase(std::unique(P.LiveOutRegs.begin(), P.LiveOutRegs.end()),
|
|
P.LiveOutRegs.end());
|
|
}
|
|
|
|
/// Finalize the region boundaries and record live ins and live outs.
|
|
void RegPressureTracker::closeRegion() {
|
|
if (!isTopClosed() && !isBottomClosed()) {
|
|
assert(LiveRegs.PhysRegs.empty() && LiveRegs.VirtRegs.empty() &&
|
|
"no region boundary");
|
|
return;
|
|
}
|
|
if (!isBottomClosed())
|
|
closeBottom();
|
|
else if (!isTopClosed())
|
|
closeTop();
|
|
// If both top and bottom are closed, do nothing.
|
|
}
|
|
|
|
/// The register tracker is unaware of global liveness so ignores normal
|
|
/// live-thru ranges. However, two-address or coalesced chains can also lead
|
|
/// to live ranges with no holes. Count these to inform heuristics that we
|
|
/// can never drop below this pressure.
|
|
void RegPressureTracker::initLiveThru(const RegPressureTracker &RPTracker) {
|
|
LiveThruPressure.assign(TRI->getNumRegPressureSets(), 0);
|
|
assert(isBottomClosed() && "need bottom-up tracking to intialize.");
|
|
for (unsigned i = 0, e = P.LiveOutRegs.size(); i < e; ++i) {
|
|
unsigned Reg = P.LiveOutRegs[i];
|
|
if (TargetRegisterInfo::isVirtualRegister(Reg)
|
|
&& !RPTracker.hasUntiedDef(Reg)) {
|
|
const TargetRegisterClass *RC = MRI->getRegClass(Reg);
|
|
increaseSetPressure(LiveThruPressure, LiveThruPressure,
|
|
TRI->getRegClassPressureSets(RC),
|
|
TRI->getRegClassWeight(RC).RegWeight);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// \brief Convenient wrapper for checking membership in RegisterOperands.
|
|
static bool containsReg(ArrayRef<unsigned> Regs, unsigned Reg) {
|
|
return std::find(Regs.begin(), Regs.end(), Reg) != Regs.end();
|
|
}
|
|
|
|
/// Collect this instruction's unique uses and defs into SmallVectors for
|
|
/// processing defs and uses in order.
|
|
class RegisterOperands {
|
|
const TargetRegisterInfo *TRI;
|
|
const MachineRegisterInfo *MRI;
|
|
|
|
public:
|
|
SmallVector<unsigned, 8> Uses;
|
|
SmallVector<unsigned, 8> Defs;
|
|
SmallVector<unsigned, 8> DeadDefs;
|
|
|
|
RegisterOperands(const TargetRegisterInfo *tri,
|
|
const MachineRegisterInfo *mri): TRI(tri), MRI(mri) {}
|
|
|
|
/// Push this operand's register onto the correct vector.
|
|
void collect(const MachineOperand &MO) {
|
|
if (!MO.isReg() || !MO.getReg())
|
|
return;
|
|
if (MO.readsReg())
|
|
pushRegUnits(MO.getReg(), Uses);
|
|
if (MO.isDef()) {
|
|
if (MO.isDead())
|
|
pushRegUnits(MO.getReg(), DeadDefs);
|
|
else
|
|
pushRegUnits(MO.getReg(), Defs);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
void pushRegUnits(unsigned Reg, SmallVectorImpl<unsigned> &Regs) {
|
|
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
|
|
if (containsReg(Regs, Reg))
|
|
return;
|
|
Regs.push_back(Reg);
|
|
}
|
|
else if (MRI->isAllocatable(Reg)) {
|
|
for (MCRegUnitIterator Units(Reg, TRI); Units.isValid(); ++Units) {
|
|
if (containsReg(Regs, *Units))
|
|
continue;
|
|
Regs.push_back(*Units);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/// Collect physical and virtual register operands.
|
|
static void collectOperands(const MachineInstr *MI,
|
|
RegisterOperands &RegOpers) {
|
|
for (ConstMIBundleOperands OperI(MI); OperI.isValid(); ++OperI)
|
|
RegOpers.collect(*OperI);
|
|
|
|
// Remove redundant physreg dead defs.
|
|
SmallVectorImpl<unsigned>::iterator I =
|
|
std::remove_if(RegOpers.DeadDefs.begin(), RegOpers.DeadDefs.end(),
|
|
std::bind1st(std::ptr_fun(containsReg), RegOpers.Defs));
|
|
RegOpers.DeadDefs.erase(I, RegOpers.DeadDefs.end());
|
|
}
|
|
|
|
/// Force liveness of registers.
|
|
void RegPressureTracker::addLiveRegs(ArrayRef<unsigned> Regs) {
|
|
for (unsigned i = 0, e = Regs.size(); i != e; ++i) {
|
|
if (LiveRegs.insert(Regs[i]))
|
|
increaseRegPressure(Regs[i]);
|
|
}
|
|
}
|
|
|
|
/// Add Reg to the live in set and increase max pressure.
|
|
void RegPressureTracker::discoverLiveIn(unsigned Reg) {
|
|
assert(!LiveRegs.contains(Reg) && "avoid bumping max pressure twice");
|
|
if (containsReg(P.LiveInRegs, Reg))
|
|
return;
|
|
|
|
// At live in discovery, unconditionally increase the high water mark.
|
|
P.LiveInRegs.push_back(Reg);
|
|
P.increase(Reg, TRI, MRI);
|
|
}
|
|
|
|
/// Add Reg to the live out set and increase max pressure.
|
|
void RegPressureTracker::discoverLiveOut(unsigned Reg) {
|
|
assert(!LiveRegs.contains(Reg) && "avoid bumping max pressure twice");
|
|
if (containsReg(P.LiveOutRegs, Reg))
|
|
return;
|
|
|
|
// At live out discovery, unconditionally increase the high water mark.
|
|
P.LiveOutRegs.push_back(Reg);
|
|
P.increase(Reg, TRI, MRI);
|
|
}
|
|
|
|
/// Recede across the previous instruction.
|
|
bool RegPressureTracker::recede() {
|
|
// Check for the top of the analyzable region.
|
|
if (CurrPos == MBB->begin()) {
|
|
closeRegion();
|
|
return false;
|
|
}
|
|
if (!isBottomClosed())
|
|
closeBottom();
|
|
|
|
// Open the top of the region using block iterators.
|
|
if (!RequireIntervals && isTopClosed())
|
|
static_cast<RegionPressure&>(P).openTop(CurrPos);
|
|
|
|
// Find the previous instruction.
|
|
do
|
|
--CurrPos;
|
|
while (CurrPos != MBB->begin() && CurrPos->isDebugValue());
|
|
|
|
if (CurrPos->isDebugValue()) {
|
|
closeRegion();
|
|
return false;
|
|
}
|
|
SlotIndex SlotIdx;
|
|
if (RequireIntervals)
|
|
SlotIdx = LIS->getInstructionIndex(CurrPos).getRegSlot();
|
|
|
|
// Open the top of the region using slot indexes.
|
|
if (RequireIntervals && isTopClosed())
|
|
static_cast<IntervalPressure&>(P).openTop(SlotIdx);
|
|
|
|
RegisterOperands RegOpers(TRI, MRI);
|
|
collectOperands(CurrPos, RegOpers);
|
|
|
|
// Boost pressure for all dead defs together.
|
|
increaseRegPressure(RegOpers.DeadDefs);
|
|
decreaseRegPressure(RegOpers.DeadDefs);
|
|
|
|
// Kill liveness at live defs.
|
|
// TODO: consider earlyclobbers?
|
|
for (unsigned i = 0, e = RegOpers.Defs.size(); i < e; ++i) {
|
|
unsigned Reg = RegOpers.Defs[i];
|
|
if (LiveRegs.erase(Reg))
|
|
decreaseRegPressure(Reg);
|
|
else
|
|
discoverLiveOut(Reg);
|
|
}
|
|
|
|
// Generate liveness for uses.
|
|
for (unsigned i = 0, e = RegOpers.Uses.size(); i < e; ++i) {
|
|
unsigned Reg = RegOpers.Uses[i];
|
|
if (!LiveRegs.contains(Reg)) {
|
|
// Adjust liveouts if LiveIntervals are available.
|
|
if (RequireIntervals) {
|
|
const LiveInterval *LI = getInterval(Reg);
|
|
if (LI && !LI->killedAt(SlotIdx))
|
|
discoverLiveOut(Reg);
|
|
}
|
|
increaseRegPressure(Reg);
|
|
LiveRegs.insert(Reg);
|
|
}
|
|
}
|
|
if (TrackUntiedDefs) {
|
|
for (unsigned i = 0, e = RegOpers.Defs.size(); i < e; ++i) {
|
|
unsigned Reg = RegOpers.Defs[i];
|
|
if (TargetRegisterInfo::isVirtualRegister(Reg) && !LiveRegs.contains(Reg))
|
|
UntiedDefs.insert(Reg);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// Advance across the current instruction.
|
|
bool RegPressureTracker::advance() {
|
|
assert(!TrackUntiedDefs && "unsupported mode");
|
|
|
|
// Check for the bottom of the analyzable region.
|
|
if (CurrPos == MBB->end()) {
|
|
closeRegion();
|
|
return false;
|
|
}
|
|
if (!isTopClosed())
|
|
closeTop();
|
|
|
|
SlotIndex SlotIdx;
|
|
if (RequireIntervals)
|
|
SlotIdx = getCurrSlot();
|
|
|
|
// Open the bottom of the region using slot indexes.
|
|
if (isBottomClosed()) {
|
|
if (RequireIntervals)
|
|
static_cast<IntervalPressure&>(P).openBottom(SlotIdx);
|
|
else
|
|
static_cast<RegionPressure&>(P).openBottom(CurrPos);
|
|
}
|
|
|
|
RegisterOperands RegOpers(TRI, MRI);
|
|
collectOperands(CurrPos, RegOpers);
|
|
|
|
for (unsigned i = 0, e = RegOpers.Uses.size(); i < e; ++i) {
|
|
unsigned Reg = RegOpers.Uses[i];
|
|
// Discover live-ins.
|
|
bool isLive = LiveRegs.contains(Reg);
|
|
if (!isLive)
|
|
discoverLiveIn(Reg);
|
|
// Kill liveness at last uses.
|
|
bool lastUse = false;
|
|
if (RequireIntervals) {
|
|
const LiveInterval *LI = getInterval(Reg);
|
|
lastUse = LI && LI->killedAt(SlotIdx);
|
|
}
|
|
else {
|
|
// Allocatable physregs are always single-use before register rewriting.
|
|
lastUse = !TargetRegisterInfo::isVirtualRegister(Reg);
|
|
}
|
|
if (lastUse && isLive) {
|
|
LiveRegs.erase(Reg);
|
|
decreaseRegPressure(Reg);
|
|
}
|
|
else if (!lastUse && !isLive)
|
|
increaseRegPressure(Reg);
|
|
}
|
|
|
|
// Generate liveness for defs.
|
|
for (unsigned i = 0, e = RegOpers.Defs.size(); i < e; ++i) {
|
|
unsigned Reg = RegOpers.Defs[i];
|
|
if (LiveRegs.insert(Reg))
|
|
increaseRegPressure(Reg);
|
|
}
|
|
|
|
// Boost pressure for all dead defs together.
|
|
increaseRegPressure(RegOpers.DeadDefs);
|
|
decreaseRegPressure(RegOpers.DeadDefs);
|
|
|
|
// Find the next instruction.
|
|
do
|
|
++CurrPos;
|
|
while (CurrPos != MBB->end() && CurrPos->isDebugValue());
|
|
return true;
|
|
}
|
|
|
|
/// Find the max change in excess pressure across all sets.
|
|
static void computeExcessPressureDelta(ArrayRef<unsigned> OldPressureVec,
|
|
ArrayRef<unsigned> NewPressureVec,
|
|
RegPressureDelta &Delta,
|
|
const RegisterClassInfo *RCI,
|
|
ArrayRef<unsigned> LiveThruPressureVec) {
|
|
int ExcessUnits = 0;
|
|
unsigned PSetID = ~0U;
|
|
for (unsigned i = 0, e = OldPressureVec.size(); i < e; ++i) {
|
|
unsigned POld = OldPressureVec[i];
|
|
unsigned PNew = NewPressureVec[i];
|
|
int PDiff = (int)PNew - (int)POld;
|
|
if (!PDiff) // No change in this set in the common case.
|
|
continue;
|
|
// Only consider change beyond the limit.
|
|
unsigned Limit = RCI->getRegPressureSetLimit(i);
|
|
if (!LiveThruPressureVec.empty())
|
|
Limit += LiveThruPressureVec[i];
|
|
|
|
if (Limit > POld) {
|
|
if (Limit > PNew)
|
|
PDiff = 0; // Under the limit
|
|
else
|
|
PDiff = PNew - Limit; // Just exceeded limit.
|
|
}
|
|
else if (Limit > PNew)
|
|
PDiff = Limit - POld; // Just obeyed limit.
|
|
|
|
if (PDiff) {
|
|
ExcessUnits = PDiff;
|
|
PSetID = i;
|
|
break;
|
|
}
|
|
}
|
|
Delta.Excess.PSetID = PSetID;
|
|
Delta.Excess.UnitIncrease = ExcessUnits;
|
|
}
|
|
|
|
/// Find the max change in max pressure that either surpasses a critical PSet
|
|
/// limit or exceeds the current MaxPressureLimit.
|
|
///
|
|
/// FIXME: comparing each element of the old and new MaxPressure vectors here is
|
|
/// silly. It's done now to demonstrate the concept but will go away with a
|
|
/// RegPressureTracker API change to work with pressure differences.
|
|
static void computeMaxPressureDelta(ArrayRef<unsigned> OldMaxPressureVec,
|
|
ArrayRef<unsigned> NewMaxPressureVec,
|
|
ArrayRef<PressureElement> CriticalPSets,
|
|
ArrayRef<unsigned> MaxPressureLimit,
|
|
RegPressureDelta &Delta) {
|
|
Delta.CriticalMax = PressureElement();
|
|
Delta.CurrentMax = PressureElement();
|
|
|
|
unsigned CritIdx = 0, CritEnd = CriticalPSets.size();
|
|
for (unsigned i = 0, e = OldMaxPressureVec.size(); i < e; ++i) {
|
|
unsigned POld = OldMaxPressureVec[i];
|
|
unsigned PNew = NewMaxPressureVec[i];
|
|
if (PNew == POld) // No change in this set in the common case.
|
|
continue;
|
|
|
|
if (!Delta.CriticalMax.isValid()) {
|
|
while (CritIdx != CritEnd && CriticalPSets[CritIdx].PSetID < i)
|
|
++CritIdx;
|
|
|
|
if (CritIdx != CritEnd && CriticalPSets[CritIdx].PSetID == i) {
|
|
int PDiff = (int)PNew - (int)CriticalPSets[CritIdx].UnitIncrease;
|
|
if (PDiff > 0) {
|
|
Delta.CriticalMax.PSetID = i;
|
|
Delta.CriticalMax.UnitIncrease = PDiff;
|
|
}
|
|
}
|
|
}
|
|
// Find the first increase above MaxPressureLimit.
|
|
// (Ignores negative MDiff).
|
|
if (!Delta.CurrentMax.isValid()) {
|
|
int MDiff = (int)PNew - (int)MaxPressureLimit[i];
|
|
if (MDiff > 0) {
|
|
Delta.CurrentMax.PSetID = i;
|
|
Delta.CurrentMax.UnitIncrease = MDiff;
|
|
if (CritIdx == CritEnd || Delta.CriticalMax.isValid())
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Record the upward impact of a single instruction on current register
|
|
/// pressure. Unlike the advance/recede pressure tracking interface, this does
|
|
/// not discover live in/outs.
|
|
///
|
|
/// This is intended for speculative queries. It leaves pressure inconsistent
|
|
/// with the current position, so must be restored by the caller.
|
|
void RegPressureTracker::bumpUpwardPressure(const MachineInstr *MI) {
|
|
assert(!MI->isDebugValue() && "Expect a nondebug instruction.");
|
|
|
|
// Account for register pressure similar to RegPressureTracker::recede().
|
|
RegisterOperands RegOpers(TRI, MRI);
|
|
collectOperands(MI, RegOpers);
|
|
|
|
// Boost max pressure for all dead defs together.
|
|
// Since CurrSetPressure and MaxSetPressure
|
|
increaseRegPressure(RegOpers.DeadDefs);
|
|
decreaseRegPressure(RegOpers.DeadDefs);
|
|
|
|
// Kill liveness at live defs.
|
|
for (unsigned i = 0, e = RegOpers.Defs.size(); i < e; ++i) {
|
|
unsigned Reg = RegOpers.Defs[i];
|
|
if (!containsReg(RegOpers.Uses, Reg))
|
|
decreaseRegPressure(Reg);
|
|
}
|
|
// Generate liveness for uses.
|
|
for (unsigned i = 0, e = RegOpers.Uses.size(); i < e; ++i) {
|
|
unsigned Reg = RegOpers.Uses[i];
|
|
if (!LiveRegs.contains(Reg))
|
|
increaseRegPressure(Reg);
|
|
}
|
|
}
|
|
|
|
/// Consider the pressure increase caused by traversing this instruction
|
|
/// bottom-up. Find the pressure set with the most change beyond its pressure
|
|
/// limit based on the tracker's current pressure, and return the change in
|
|
/// number of register units of that pressure set introduced by this
|
|
/// instruction.
|
|
///
|
|
/// This assumes that the current LiveOut set is sufficient.
|
|
///
|
|
/// FIXME: This is expensive for an on-the-fly query. We need to cache the
|
|
/// result per-SUnit with enough information to adjust for the current
|
|
/// scheduling position. But this works as a proof of concept.
|
|
void RegPressureTracker::
|
|
getMaxUpwardPressureDelta(const MachineInstr *MI, RegPressureDelta &Delta,
|
|
ArrayRef<PressureElement> CriticalPSets,
|
|
ArrayRef<unsigned> MaxPressureLimit) {
|
|
// Snapshot Pressure.
|
|
// FIXME: The snapshot heap space should persist. But I'm planning to
|
|
// summarize the pressure effect so we don't need to snapshot at all.
|
|
std::vector<unsigned> SavedPressure = CurrSetPressure;
|
|
std::vector<unsigned> SavedMaxPressure = P.MaxSetPressure;
|
|
|
|
bumpUpwardPressure(MI);
|
|
|
|
computeExcessPressureDelta(SavedPressure, CurrSetPressure, Delta, RCI,
|
|
LiveThruPressure);
|
|
computeMaxPressureDelta(SavedMaxPressure, P.MaxSetPressure, CriticalPSets,
|
|
MaxPressureLimit, Delta);
|
|
assert(Delta.CriticalMax.UnitIncrease >= 0 &&
|
|
Delta.CurrentMax.UnitIncrease >= 0 && "cannot decrease max pressure");
|
|
|
|
// Restore the tracker's state.
|
|
P.MaxSetPressure.swap(SavedMaxPressure);
|
|
CurrSetPressure.swap(SavedPressure);
|
|
}
|
|
|
|
/// Helper to find a vreg use between two indices [PriorUseIdx, NextUseIdx).
|
|
static bool findUseBetween(unsigned Reg,
|
|
SlotIndex PriorUseIdx, SlotIndex NextUseIdx,
|
|
const MachineRegisterInfo *MRI,
|
|
const LiveIntervals *LIS) {
|
|
for (MachineRegisterInfo::use_nodbg_iterator
|
|
UI = MRI->use_nodbg_begin(Reg), UE = MRI->use_nodbg_end();
|
|
UI != UE; UI.skipInstruction()) {
|
|
const MachineInstr* MI = &*UI;
|
|
if (MI->isDebugValue())
|
|
continue;
|
|
SlotIndex InstSlot = LIS->getInstructionIndex(MI).getRegSlot();
|
|
if (InstSlot >= PriorUseIdx && InstSlot < NextUseIdx)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Record the downward impact of a single instruction on current register
|
|
/// pressure. Unlike the advance/recede pressure tracking interface, this does
|
|
/// not discover live in/outs.
|
|
///
|
|
/// This is intended for speculative queries. It leaves pressure inconsistent
|
|
/// with the current position, so must be restored by the caller.
|
|
void RegPressureTracker::bumpDownwardPressure(const MachineInstr *MI) {
|
|
assert(!MI->isDebugValue() && "Expect a nondebug instruction.");
|
|
|
|
// Account for register pressure similar to RegPressureTracker::recede().
|
|
RegisterOperands RegOpers(TRI, MRI);
|
|
collectOperands(MI, RegOpers);
|
|
|
|
// Kill liveness at last uses. Assume allocatable physregs are single-use
|
|
// rather than checking LiveIntervals.
|
|
SlotIndex SlotIdx;
|
|
if (RequireIntervals)
|
|
SlotIdx = LIS->getInstructionIndex(MI).getRegSlot();
|
|
|
|
for (unsigned i = 0, e = RegOpers.Uses.size(); i < e; ++i) {
|
|
unsigned Reg = RegOpers.Uses[i];
|
|
if (RequireIntervals) {
|
|
// FIXME: allow the caller to pass in the list of vreg uses that remain
|
|
// to be bottom-scheduled to avoid searching uses at each query.
|
|
SlotIndex CurrIdx = getCurrSlot();
|
|
const LiveInterval *LI = getInterval(Reg);
|
|
if (LI && LI->killedAt(SlotIdx)
|
|
&& !findUseBetween(Reg, CurrIdx, SlotIdx, MRI, LIS)) {
|
|
decreaseRegPressure(Reg);
|
|
}
|
|
}
|
|
else if (!TargetRegisterInfo::isVirtualRegister(Reg)) {
|
|
// Allocatable physregs are always single-use before register rewriting.
|
|
decreaseRegPressure(Reg);
|
|
}
|
|
}
|
|
|
|
// Generate liveness for defs.
|
|
increaseRegPressure(RegOpers.Defs);
|
|
|
|
// Boost pressure for all dead defs together.
|
|
increaseRegPressure(RegOpers.DeadDefs);
|
|
decreaseRegPressure(RegOpers.DeadDefs);
|
|
}
|
|
|
|
/// Consider the pressure increase caused by traversing this instruction
|
|
/// top-down. Find the register class with the most change in its pressure limit
|
|
/// based on the tracker's current pressure, and return the number of excess
|
|
/// register units of that pressure set introduced by this instruction.
|
|
///
|
|
/// This assumes that the current LiveIn set is sufficient.
|
|
void RegPressureTracker::
|
|
getMaxDownwardPressureDelta(const MachineInstr *MI, RegPressureDelta &Delta,
|
|
ArrayRef<PressureElement> CriticalPSets,
|
|
ArrayRef<unsigned> MaxPressureLimit) {
|
|
// Snapshot Pressure.
|
|
std::vector<unsigned> SavedPressure = CurrSetPressure;
|
|
std::vector<unsigned> SavedMaxPressure = P.MaxSetPressure;
|
|
|
|
bumpDownwardPressure(MI);
|
|
|
|
computeExcessPressureDelta(SavedPressure, CurrSetPressure, Delta, RCI,
|
|
LiveThruPressure);
|
|
computeMaxPressureDelta(SavedMaxPressure, P.MaxSetPressure, CriticalPSets,
|
|
MaxPressureLimit, Delta);
|
|
assert(Delta.CriticalMax.UnitIncrease >= 0 &&
|
|
Delta.CurrentMax.UnitIncrease >= 0 && "cannot decrease max pressure");
|
|
|
|
// Restore the tracker's state.
|
|
P.MaxSetPressure.swap(SavedMaxPressure);
|
|
CurrSetPressure.swap(SavedPressure);
|
|
}
|
|
|
|
/// Get the pressure of each PSet after traversing this instruction bottom-up.
|
|
void RegPressureTracker::
|
|
getUpwardPressure(const MachineInstr *MI,
|
|
std::vector<unsigned> &PressureResult,
|
|
std::vector<unsigned> &MaxPressureResult) {
|
|
// Snapshot pressure.
|
|
PressureResult = CurrSetPressure;
|
|
MaxPressureResult = P.MaxSetPressure;
|
|
|
|
bumpUpwardPressure(MI);
|
|
|
|
// Current pressure becomes the result. Restore current pressure.
|
|
P.MaxSetPressure.swap(MaxPressureResult);
|
|
CurrSetPressure.swap(PressureResult);
|
|
}
|
|
|
|
/// Get the pressure of each PSet after traversing this instruction top-down.
|
|
void RegPressureTracker::
|
|
getDownwardPressure(const MachineInstr *MI,
|
|
std::vector<unsigned> &PressureResult,
|
|
std::vector<unsigned> &MaxPressureResult) {
|
|
// Snapshot pressure.
|
|
PressureResult = CurrSetPressure;
|
|
MaxPressureResult = P.MaxSetPressure;
|
|
|
|
bumpDownwardPressure(MI);
|
|
|
|
// Current pressure becomes the result. Restore current pressure.
|
|
P.MaxSetPressure.swap(MaxPressureResult);
|
|
CurrSetPressure.swap(PressureResult);
|
|
}
|