123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 |
- //==- RegAllocGreedy.h ------- greedy register allocator ----------*-C++-*-==//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- // This file defines the RAGreedy function pass for register allocation in
- // optimized builds.
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CODEGEN_REGALLOCGREEDY_H_
- #define LLVM_CODEGEN_REGALLOCGREEDY_H_
- #include "AllocationOrder.h"
- #include "InterferenceCache.h"
- #include "LiveDebugVariables.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/MapVector.h"
- #include "llvm/ADT/SetVector.h"
- #include "llvm/ADT/SmallPtrSet.h"
- #include "llvm/ADT/SmallSet.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/Analysis/AliasAnalysis.h"
- #include "llvm/CodeGen/CalcSpillWeights.h"
- #include "llvm/CodeGen/EdgeBundles.h"
- #include "llvm/CodeGen/LiveInterval.h"
- #include "llvm/CodeGen/LiveIntervalUnion.h"
- #include "llvm/CodeGen/LiveIntervals.h"
- #include "llvm/CodeGen/LiveRangeEdit.h"
- #include "llvm/CodeGen/LiveRegMatrix.h"
- #include "llvm/CodeGen/LiveStacks.h"
- #include "llvm/CodeGen/MachineBasicBlock.h"
- #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
- #include "llvm/CodeGen/MachineDominators.h"
- #include "llvm/CodeGen/MachineFrameInfo.h"
- #include "llvm/CodeGen/MachineFunction.h"
- #include "llvm/CodeGen/MachineFunctionPass.h"
- #include "llvm/CodeGen/MachineLoopInfo.h"
- #include "llvm/CodeGen/MachineRegisterInfo.h"
- #include "llvm/CodeGen/RegisterClassInfo.h"
- #include "llvm/CodeGen/SlotIndexes.h"
- #include "llvm/CodeGen/Spiller.h"
- #include "llvm/CodeGen/TargetInstrInfo.h"
- #include "llvm/CodeGen/TargetRegisterInfo.h"
- #include "llvm/CodeGen/TargetSubtargetInfo.h"
- #include "llvm/CodeGen/VirtRegMap.h"
- #include "llvm/IR/DebugInfoMetadata.h"
- #include "llvm/IR/Function.h"
- #include "llvm/IR/LLVMContext.h"
- #include "llvm/MC/MCRegisterInfo.h"
- #include "llvm/Pass.h"
- #include "llvm/Support/BranchProbability.h"
- #include "llvm/Target/TargetMachine.h"
- #include <algorithm>
- #include <cassert>
- #include <cstdint>
- #include <memory>
- #include <queue>
- #include <tuple>
- #include <utility>
- namespace llvm {
- class LLVM_LIBRARY_VISIBILITY RAGreedy : public MachineFunctionPass,
- public RegAllocBase,
- private LiveRangeEdit::Delegate {
- // Interface to eviction advisers
- public:
- /// Track allocation stage and eviction loop prevention during allocation.
- class ExtraRegInfo final {
- // RegInfo - Keep additional information about each live range.
- struct RegInfo {
- LiveRangeStage Stage = RS_New;
- // Cascade - Eviction loop prevention. See
- // canEvictInterferenceBasedOnCost().
- 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);
- }
- /// Return the current stage of the register, if present, otherwise
- /// initialize it and return that.
- 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(); }
- // end (interface to eviction advisers)
- private:
- // Convenient shortcuts.
- using PQueue = std::priority_queue<std::pair<unsigned, unsigned>>;
- using SmallLISet = SmallPtrSet<LiveInterval *, 4>;
- // context
- MachineFunction *MF;
- // Shortcuts to some useful interface.
- const TargetInstrInfo *TII;
- const TargetRegisterInfo *TRI;
- RegisterClassInfo RCI;
- // analyses
- SlotIndexes *Indexes;
- MachineBlockFrequencyInfo *MBFI;
- MachineDominatorTree *DomTree;
- MachineLoopInfo *Loops;
- MachineOptimizationRemarkEmitter *ORE;
- EdgeBundles *Bundles;
- SpillPlacement *SpillPlacer;
- LiveDebugVariables *DebugVars;
- AliasAnalysis *AA;
- // state
- std::unique_ptr<Spiller> SpillerInstance;
- PQueue Queue;
- std::unique_ptr<VirtRegAuxInfo> VRAI;
- Optional<ExtraRegInfo> ExtraInfo;
- std::unique_ptr<RegAllocEvictionAdvisor> EvictAdvisor;
- // Enum CutOffStage to keep a track whether the register allocation failed
- // because of the cutoffs encountered in last chance recoloring.
- // Note: This is used as bitmask. New value should be next power of 2.
- enum CutOffStage {
- // No cutoffs encountered
- CO_None = 0,
- // lcr-max-depth cutoff encountered
- CO_Depth = 1,
- // lcr-max-interf cutoff encountered
- CO_Interf = 2
- };
- uint8_t CutOffInfo;
- #ifndef NDEBUG
- static const char *const StageName[];
- #endif
- /// EvictionTrack - Keeps track of past evictions in order to optimize region
- /// split decision.
- class EvictionTrack {
- public:
- using EvictorInfo =
- std::pair<Register /* evictor */, MCRegister /* physreg */>;
- using EvicteeInfo = llvm::DenseMap<Register /* evictee */, EvictorInfo>;
- private:
- /// Each Vreg that has been evicted in the last stage of selectOrSplit will
- /// be mapped to the evictor Vreg and the PhysReg it was evicted from.
- EvicteeInfo Evictees;
- public:
- /// Clear all eviction information.
- void clear() { Evictees.clear(); }
- /// Clear eviction information for the given evictee Vreg.
- /// E.g. when Vreg get's a new allocation, the old eviction info is no
- /// longer relevant.
- /// \param Evictee The evictee Vreg for whom we want to clear collected
- /// eviction info.
- void clearEvicteeInfo(Register Evictee) { Evictees.erase(Evictee); }
- /// Track new eviction.
- /// The Evictor vreg has evicted the Evictee vreg from Physreg.
- /// \param PhysReg The physical register Evictee was evicted from.
- /// \param Evictor The evictor Vreg that evicted Evictee.
- /// \param Evictee The evictee Vreg.
- void addEviction(MCRegister PhysReg, Register Evictor, Register Evictee) {
- Evictees[Evictee].first = Evictor;
- Evictees[Evictee].second = PhysReg;
- }
- /// Return the Evictor Vreg which evicted Evictee Vreg from PhysReg.
- /// \param Evictee The evictee vreg.
- /// \return The Evictor vreg which evicted Evictee vreg from PhysReg. 0 if
- /// nobody has evicted Evictee from PhysReg.
- EvictorInfo getEvictor(Register Evictee) {
- if (Evictees.count(Evictee)) {
- return Evictees[Evictee];
- }
- return EvictorInfo(0, 0);
- }
- };
- // Keeps track of past evictions in order to optimize region split decision.
- EvictionTrack LastEvicted;
- // splitting state.
- std::unique_ptr<SplitAnalysis> SA;
- std::unique_ptr<SplitEditor> SE;
- /// Cached per-block interference maps
- InterferenceCache IntfCache;
- /// All basic blocks where the current register has uses.
- SmallVector<SpillPlacement::BlockConstraint, 8> SplitConstraints;
- /// Global live range splitting candidate info.
- struct GlobalSplitCandidate {
- // Register intended for assignment, or 0.
- MCRegister PhysReg;
- // SplitKit interval index for this candidate.
- unsigned IntvIdx;
- // Interference for PhysReg.
- InterferenceCache::Cursor Intf;
- // Bundles where this candidate should be live.
- BitVector LiveBundles;
- SmallVector<unsigned, 8> ActiveBlocks;
- void reset(InterferenceCache &Cache, MCRegister Reg) {
- PhysReg = Reg;
- IntvIdx = 0;
- Intf.setPhysReg(Cache, Reg);
- LiveBundles.clear();
- ActiveBlocks.clear();
- }
- // Set B[I] = C for every live bundle where B[I] was NoCand.
- 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;
- }
- };
- /// Candidate info for each PhysReg in AllocationOrder.
- /// This vector never shrinks, but grows to the size of the largest register
- /// class.
- SmallVector<GlobalSplitCandidate, 32> GlobalCand;
- enum : unsigned { NoCand = ~0u };
- /// Candidate map. Each edge bundle is assigned to a GlobalCand entry, or to
- /// NoCand which indicates the stack interval.
- SmallVector<unsigned, 32> BundleCand;
- /// Callee-save register cost, calculated once per machine function.
- BlockFrequency CSRCost;
- /// Enable or not the consideration of the cost of local intervals created
- /// by a split candidate when choosing the best split candidate.
- bool EnableAdvancedRASplitCost;
- /// Set of broken hints that may be reconciled later because of eviction.
- SmallSetVector<LiveInterval *, 8> SetOfBrokenHints;
- /// The register cost values. This list will be recreated for each Machine
- /// Function
- ArrayRef<uint8_t> RegCosts;
- public:
- RAGreedy(const RegClassFilterFunc F = allocateAllRegClasses);
- /// Return the pass name.
- StringRef getPassName() const override { return "Greedy Register Allocator"; }
- /// RAGreedy analysis usage.
- void getAnalysisUsage(AnalysisUsage &AU) const override;
- void releaseMemory() override;
- Spiller &spiller() override { return *SpillerInstance; }
- void enqueueImpl(LiveInterval *LI) override;
- LiveInterval *dequeue() override;
- MCRegister selectOrSplit(LiveInterval &,
- SmallVectorImpl<Register> &) override;
- void aboutToRemoveInterval(LiveInterval &) override;
- /// Perform register allocation.
- 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(LiveInterval &, SmallVectorImpl<Register> &,
- SmallVirtRegSet &, unsigned = 0);
- bool LRE_CanEraseVirtReg(Register) override;
- void LRE_WillShrinkVirtReg(Register) override;
- void LRE_DidCloneVirtReg(Register, Register) override;
- void enqueue(PQueue &CurQueue, LiveInterval *LI);
- LiveInterval *dequeue(PQueue &CurQueue);
- BlockFrequency calcSpillCost();
- bool addSplitConstraints(InterferenceCache::Cursor, BlockFrequency &);
- bool addThroughConstraints(InterferenceCache::Cursor, ArrayRef<unsigned>);
- bool growRegion(GlobalSplitCandidate &Cand);
- bool splitCanCauseEvictionChain(Register Evictee, GlobalSplitCandidate &Cand,
- unsigned BBNumber,
- const AllocationOrder &Order);
- bool splitCanCauseLocalSpill(unsigned VirtRegToSplit,
- GlobalSplitCandidate &Cand, unsigned BBNumber,
- const AllocationOrder &Order);
- BlockFrequency calcGlobalSplitCost(GlobalSplitCandidate &,
- const AllocationOrder &Order,
- bool *CanCauseEvictionChain);
- bool calcCompactRegion(GlobalSplitCandidate &);
- void splitAroundRegion(LiveRangeEdit &, ArrayRef<unsigned>);
- void calcGapWeights(MCRegister, SmallVectorImpl<float> &);
- bool canEvictInterferenceInRange(const LiveInterval &VirtReg,
- MCRegister PhysReg, SlotIndex Start,
- SlotIndex End, EvictionCost &MaxCost) const;
- MCRegister getCheapestEvicteeWeight(const AllocationOrder &Order,
- const LiveInterval &VirtReg,
- SlotIndex Start, SlotIndex End,
- float *BestEvictWeight) const;
- void evictInterference(LiveInterval &, MCRegister,
- SmallVectorImpl<Register> &);
- bool mayRecolorAllInterferences(MCRegister PhysReg, LiveInterval &VirtReg,
- SmallLISet &RecoloringCandidates,
- const SmallVirtRegSet &FixedRegisters);
- MCRegister tryAssign(LiveInterval &, AllocationOrder &,
- SmallVectorImpl<Register> &, const SmallVirtRegSet &);
- MCRegister tryEvict(LiveInterval &, AllocationOrder &,
- SmallVectorImpl<Register> &, uint8_t,
- const SmallVirtRegSet &);
- MCRegister tryRegionSplit(LiveInterval &, AllocationOrder &,
- SmallVectorImpl<Register> &);
- /// Calculate cost of region splitting.
- unsigned calculateRegionSplitCost(LiveInterval &VirtReg,
- AllocationOrder &Order,
- BlockFrequency &BestCost,
- unsigned &NumCands, bool IgnoreCSR,
- bool *CanCauseEvictionChain = nullptr);
- /// Perform region splitting.
- unsigned doRegionSplit(LiveInterval &VirtReg, unsigned BestCand,
- bool HasCompact, SmallVectorImpl<Register> &NewVRegs);
- /// Check other options before using a callee-saved register for the first
- /// time.
- MCRegister tryAssignCSRFirstTime(LiveInterval &VirtReg,
- AllocationOrder &Order, MCRegister PhysReg,
- uint8_t &CostPerUseLimit,
- SmallVectorImpl<Register> &NewVRegs);
- void initializeCSRCost();
- unsigned tryBlockSplit(LiveInterval &, AllocationOrder &,
- SmallVectorImpl<Register> &);
- unsigned tryInstructionSplit(LiveInterval &, AllocationOrder &,
- SmallVectorImpl<Register> &);
- unsigned tryLocalSplit(LiveInterval &, AllocationOrder &,
- SmallVectorImpl<Register> &);
- unsigned trySplit(LiveInterval &, AllocationOrder &,
- SmallVectorImpl<Register> &, const SmallVirtRegSet &);
- unsigned tryLastChanceRecoloring(LiveInterval &, AllocationOrder &,
- SmallVectorImpl<Register> &,
- SmallVirtRegSet &, unsigned);
- bool tryRecoloringCandidates(PQueue &, SmallVectorImpl<Register> &,
- SmallVirtRegSet &, unsigned);
- void tryHintRecoloring(LiveInterval &);
- void tryHintsRecoloring();
- /// Model the information carried by one end of a copy.
- struct HintInfo {
- /// The frequency of the copy.
- BlockFrequency Freq;
- /// The virtual register or physical register.
- Register Reg;
- /// Its currently assigned register.
- /// In case of a physical register Reg == PhysReg.
- 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 &);
- /// Greedy RA statistic to remark.
- 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);
- };
- /// Compute statistic for a basic block.
- RAGreedyStats computeStats(MachineBasicBlock &MBB);
- /// Compute and report statistic through a remark.
- RAGreedyStats reportStats(MachineLoop *L);
- /// Report the statistic for each loop.
- void reportStats();
- };
- } // namespace llvm
- #endif // #ifndef LLVM_CODEGEN_REGALLOCGREEDY_H_
|