#ifndef LLVM_CODEGEN_REGALLOCGREEDY_H_
#define LLVM_CODEGEN_REGALLOCGREEDY_H_
#include "InterferenceCache.h"
#include "RegAllocBase.h"
#include "RegAllocEvictionAdvisor.h"
#include "SpillPlacement.h"
#include "SplitKit.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/CalcSpillWeights.h"
#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/LiveRangeEdit.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/RegisterClassInfo.h"
#include "llvm/CodeGen/Spiller.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include <algorithm>
#include <cstdint>
#include <memory>
#include <queue>
#include <utility>
namespace llvm {
class AllocationOrder;
class AnalysisUsage;
class EdgeBundles;
class LiveDebugVariables;
class LiveIntervals;
class LiveRegMatrix;
class MachineBasicBlock;
class MachineBlockFrequencyInfo;
class MachineDominatorTree;
class MachineLoop;
class MachineLoopInfo;
class MachineOptimizationRemarkEmitter;
class MachineOptimizationRemarkMissed;
class SlotIndexes;
class TargetInstrInfo;
class VirtRegMap;
class LLVM_LIBRARY_VISIBILITY RAGreedy : public MachineFunctionPass,
public RegAllocBase,
private LiveRangeEdit::Delegate {
public:
class ExtraRegInfo final {
struct RegInfo {
LiveRangeStage Stage = RS_New;
unsigned Cascade = 0;
RegInfo() = default;
};
IndexedMap<RegInfo, VirtReg2IndexFunctor> Info;
unsigned NextCascade = 1;
public:
ExtraRegInfo() = default;
ExtraRegInfo(const ExtraRegInfo &) = delete;
LiveRangeStage getStage(Register Reg) const { return Info[Reg].Stage; }
LiveRangeStage getStage(const LiveInterval &VirtReg) const {
return getStage(VirtReg.reg());
}
void setStage(Register Reg, LiveRangeStage Stage) {
Info.grow(Reg.id());
Info[Reg].Stage = Stage;
}
void setStage(const LiveInterval &VirtReg, LiveRangeStage Stage) {
setStage(VirtReg.reg(), Stage);
}
LiveRangeStage getOrInitStage(Register Reg) {
Info.grow(Reg.id());
return getStage(Reg);
}
unsigned getCascade(Register Reg) const { return Info[Reg].Cascade; }
void setCascade(Register Reg, unsigned Cascade) {
Info.grow(Reg.id());
Info[Reg].Cascade = Cascade;
}
unsigned getOrAssignNewCascade(Register Reg) {
unsigned Cascade = getCascade(Reg);
if (!Cascade) {
Cascade = NextCascade++;
setCascade(Reg, Cascade);
}
return Cascade;
}
unsigned getCascadeOrCurrentNext(Register Reg) const {
unsigned Cascade = getCascade(Reg);
if (!Cascade)
Cascade = NextCascade;
return Cascade;
}
template <typename Iterator>
void setStage(Iterator Begin, Iterator End, LiveRangeStage NewStage) {
for (; Begin != End; ++Begin) {
Register Reg = *Begin;
Info.grow(Reg.id());
if (Info[Reg].Stage == RS_New)
Info[Reg].Stage = NewStage;
}
}
void LRE_DidCloneVirtReg(Register New, Register Old);
};
LiveRegMatrix *getInterferenceMatrix() const { return Matrix; }
LiveIntervals *getLiveIntervals() const { return LIS; }
VirtRegMap *getVirtRegMap() const { return VRM; }
const RegisterClassInfo &getRegClassInfo() const { return RegClassInfo; }
const ExtraRegInfo &getExtraInfo() const { return *ExtraInfo; }
size_t getQueueSize() const { return Queue.size(); }
private:
using PQueue = std::priority_queue<std::pair<unsigned, unsigned>>;
using SmallLISet = SmallPtrSet<const LiveInterval *, 4>;
using RecoloringStack =
SmallVector<std::pair<const LiveInterval *, MCRegister>, 8>;
MachineFunction *MF;
const TargetInstrInfo *TII;
SlotIndexes *Indexes;
MachineBlockFrequencyInfo *MBFI;
MachineDominatorTree *DomTree;
MachineLoopInfo *Loops;
MachineOptimizationRemarkEmitter *ORE;
EdgeBundles *Bundles;
SpillPlacement *SpillPlacer;
LiveDebugVariables *DebugVars;
std::unique_ptr<Spiller> SpillerInstance;
PQueue Queue;
std::unique_ptr<VirtRegAuxInfo> VRAI;
Optional<ExtraRegInfo> ExtraInfo;
std::unique_ptr<RegAllocEvictionAdvisor> EvictAdvisor;
enum CutOffStage {
CO_None = 0,
CO_Depth = 1,
CO_Interf = 2
};
uint8_t CutOffInfo;
#ifndef NDEBUG
static const char *const StageName[];
#endif
std::unique_ptr<SplitAnalysis> SA;
std::unique_ptr<SplitEditor> SE;
InterferenceCache IntfCache;
SmallVector<SpillPlacement::BlockConstraint, 8> SplitConstraints;
struct GlobalSplitCandidate {
MCRegister PhysReg;
unsigned IntvIdx;
InterferenceCache::Cursor Intf;
BitVector LiveBundles;
SmallVector<unsigned, 8> ActiveBlocks;
void reset(InterferenceCache &Cache, MCRegister Reg) {
PhysReg = Reg;
IntvIdx = 0;
Intf.setPhysReg(Cache, Reg);
LiveBundles.clear();
ActiveBlocks.clear();
}
unsigned getBundles(SmallVectorImpl<unsigned> &B, unsigned C) {
unsigned Count = 0;
for (unsigned I : LiveBundles.set_bits())
if (B[I] == NoCand) {
B[I] = C;
Count++;
}
return Count;
}
};
SmallVector<GlobalSplitCandidate, 32> GlobalCand;
enum : unsigned { NoCand = ~0u };
SmallVector<unsigned, 32> BundleCand;
BlockFrequency CSRCost;
SmallSetVector<const LiveInterval *, 8> SetOfBrokenHints;
ArrayRef<uint8_t> RegCosts;
bool RegClassPriorityTrumpsGlobalness;
bool ReverseLocalAssignment;
public:
RAGreedy(const RegClassFilterFunc F = allocateAllRegClasses);
StringRef getPassName() const override { return "Greedy Register Allocator"; }
void getAnalysisUsage(AnalysisUsage &AU) const override;
void releaseMemory() override;
Spiller &spiller() override { return *SpillerInstance; }
void enqueueImpl(const LiveInterval *LI) override;
const LiveInterval *dequeue() override;
MCRegister selectOrSplit(const LiveInterval &,
SmallVectorImpl<Register> &) override;
void aboutToRemoveInterval(const LiveInterval &) override;
bool runOnMachineFunction(MachineFunction &mf) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::NoPHIs);
}
MachineFunctionProperties getClearedProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::IsSSA);
}
static char ID;
private:
MCRegister selectOrSplitImpl(const LiveInterval &,
SmallVectorImpl<Register> &, SmallVirtRegSet &,
RecoloringStack &, unsigned = 0);
bool LRE_CanEraseVirtReg(Register) override;
void LRE_WillShrinkVirtReg(Register) override;
void LRE_DidCloneVirtReg(Register, Register) override;
void enqueue(PQueue &CurQueue, const LiveInterval *LI);
const LiveInterval *dequeue(PQueue &CurQueue);
bool hasVirtRegAlloc();
BlockFrequency calcSpillCost();
bool addSplitConstraints(InterferenceCache::Cursor, BlockFrequency &);
bool addThroughConstraints(InterferenceCache::Cursor, ArrayRef<unsigned>);
bool growRegion(GlobalSplitCandidate &Cand);
BlockFrequency calcGlobalSplitCost(GlobalSplitCandidate &,
const AllocationOrder &Order);
bool calcCompactRegion(GlobalSplitCandidate &);
void splitAroundRegion(LiveRangeEdit &, ArrayRef<unsigned>);
void calcGapWeights(MCRegister, SmallVectorImpl<float> &);
void evictInterference(const LiveInterval &, MCRegister,
SmallVectorImpl<Register> &);
bool mayRecolorAllInterferences(MCRegister PhysReg,
const LiveInterval &VirtReg,
SmallLISet &RecoloringCandidates,
const SmallVirtRegSet &FixedRegisters);
MCRegister tryAssign(const LiveInterval &, AllocationOrder &,
SmallVectorImpl<Register> &, const SmallVirtRegSet &);
MCRegister tryEvict(const LiveInterval &, AllocationOrder &,
SmallVectorImpl<Register> &, uint8_t,
const SmallVirtRegSet &);
MCRegister tryRegionSplit(const LiveInterval &, AllocationOrder &,
SmallVectorImpl<Register> &);
unsigned calculateRegionSplitCost(const LiveInterval &VirtReg,
AllocationOrder &Order,
BlockFrequency &BestCost,
unsigned &NumCands, bool IgnoreCSR);
unsigned doRegionSplit(const LiveInterval &VirtReg, unsigned BestCand,
bool HasCompact, SmallVectorImpl<Register> &NewVRegs);
MCRegister tryAssignCSRFirstTime(const LiveInterval &VirtReg,
AllocationOrder &Order, MCRegister PhysReg,
uint8_t &CostPerUseLimit,
SmallVectorImpl<Register> &NewVRegs);
void initializeCSRCost();
unsigned tryBlockSplit(const LiveInterval &, AllocationOrder &,
SmallVectorImpl<Register> &);
unsigned tryInstructionSplit(const LiveInterval &, AllocationOrder &,
SmallVectorImpl<Register> &);
unsigned tryLocalSplit(const LiveInterval &, AllocationOrder &,
SmallVectorImpl<Register> &);
unsigned trySplit(const LiveInterval &, AllocationOrder &,
SmallVectorImpl<Register> &, const SmallVirtRegSet &);
unsigned tryLastChanceRecoloring(const LiveInterval &, AllocationOrder &,
SmallVectorImpl<Register> &,
SmallVirtRegSet &, RecoloringStack &,
unsigned);
bool tryRecoloringCandidates(PQueue &, SmallVectorImpl<Register> &,
SmallVirtRegSet &, RecoloringStack &, unsigned);
void tryHintRecoloring(const LiveInterval &);
void tryHintsRecoloring();
struct HintInfo {
BlockFrequency Freq;
Register Reg;
MCRegister PhysReg;
HintInfo(BlockFrequency Freq, Register Reg, MCRegister PhysReg)
: Freq(Freq), Reg(Reg), PhysReg(PhysReg) {}
};
using HintsInfo = SmallVector<HintInfo, 4>;
BlockFrequency getBrokenHintFreq(const HintsInfo &, MCRegister);
void collectHintInfo(Register, HintsInfo &);
struct RAGreedyStats {
unsigned Reloads = 0;
unsigned FoldedReloads = 0;
unsigned ZeroCostFoldedReloads = 0;
unsigned Spills = 0;
unsigned FoldedSpills = 0;
unsigned Copies = 0;
float ReloadsCost = 0.0f;
float FoldedReloadsCost = 0.0f;
float SpillsCost = 0.0f;
float FoldedSpillsCost = 0.0f;
float CopiesCost = 0.0f;
bool isEmpty() {
return !(Reloads || FoldedReloads || Spills || FoldedSpills ||
ZeroCostFoldedReloads || Copies);
}
void add(RAGreedyStats other) {
Reloads += other.Reloads;
FoldedReloads += other.FoldedReloads;
ZeroCostFoldedReloads += other.ZeroCostFoldedReloads;
Spills += other.Spills;
FoldedSpills += other.FoldedSpills;
Copies += other.Copies;
ReloadsCost += other.ReloadsCost;
FoldedReloadsCost += other.FoldedReloadsCost;
SpillsCost += other.SpillsCost;
FoldedSpillsCost += other.FoldedSpillsCost;
CopiesCost += other.CopiesCost;
}
void report(MachineOptimizationRemarkMissed &R);
};
RAGreedyStats computeStats(MachineBasicBlock &MBB);
RAGreedyStats reportStats(MachineLoop *L);
void reportStats();
};
} #endif