451 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			451 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
| //==- 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 "InterferenceCache.h"
 | |
| #include "RegAllocBase.h"
 | |
| #include "RegAllocEvictionAdvisor.h"
 | |
| #include "RegAllocPriorityAdvisor.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 {
 | |
|   // 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)
 | |
| 
 | |
|   // Interface to priority advisers
 | |
|   bool getRegClassPriorityTrumpsGlobalness() const {
 | |
|     return RegClassPriorityTrumpsGlobalness;
 | |
|   }
 | |
|   bool getReverseLocalAssignment() const { return ReverseLocalAssignment; }
 | |
|   // FIXME: this is unnecessary once priority advisers are created by an
 | |
|   // analysis pass, which can fetch the SlotIndexes analysis itself.
 | |
|   SlotIndexes *getIndexes() const { return Indexes; }
 | |
|   // end (interface to priority advisers)
 | |
| 
 | |
| private:
 | |
|   // Convenient shortcuts.
 | |
|   using PQueue = std::priority_queue<std::pair<unsigned, unsigned>>;
 | |
|   using SmallLISet = SmallSetVector<const LiveInterval *, 4>;
 | |
| 
 | |
|   // We need to track all tentative recolorings so we can roll back any
 | |
|   // successful and unsuccessful recoloring attempts.
 | |
|   using RecoloringStack =
 | |
|       SmallVector<std::pair<const LiveInterval *, MCRegister>, 8>;
 | |
| 
 | |
|   // context
 | |
|   MachineFunction *MF;
 | |
| 
 | |
|   // Shortcuts to some useful interface.
 | |
|   const TargetInstrInfo *TII;
 | |
| 
 | |
|   // analyses
 | |
|   SlotIndexes *Indexes;
 | |
|   MachineBlockFrequencyInfo *MBFI;
 | |
|   MachineDominatorTree *DomTree;
 | |
|   MachineLoopInfo *Loops;
 | |
|   MachineOptimizationRemarkEmitter *ORE;
 | |
|   EdgeBundles *Bundles;
 | |
|   SpillPlacement *SpillPlacer;
 | |
|   LiveDebugVariables *DebugVars;
 | |
| 
 | |
|   // state
 | |
|   std::unique_ptr<Spiller> SpillerInstance;
 | |
|   PQueue Queue;
 | |
|   std::unique_ptr<VirtRegAuxInfo> VRAI;
 | |
|   Optional<ExtraRegInfo> ExtraInfo;
 | |
|   std::unique_ptr<RegAllocEvictionAdvisor> EvictAdvisor;
 | |
| 
 | |
|   std::unique_ptr<RegAllocPriorityAdvisor> PriorityAdvisor;
 | |
| 
 | |
|   // 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
 | |
| 
 | |
|   // 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;
 | |
| 
 | |
|   /// Set of broken hints that may be reconciled later because of eviction.
 | |
|   SmallSetVector<const LiveInterval *, 8> SetOfBrokenHints;
 | |
| 
 | |
|   /// The register cost values. This list will be recreated for each Machine
 | |
|   /// Function
 | |
|   ArrayRef<uint8_t> RegCosts;
 | |
| 
 | |
|   /// Flags for the live range priority calculation, determined once per
 | |
|   /// machine function.
 | |
|   bool RegClassPriorityTrumpsGlobalness;
 | |
| 
 | |
|   bool ReverseLocalAssignment;
 | |
| 
 | |
| 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(const LiveInterval *LI) override;
 | |
|   const LiveInterval *dequeue() override;
 | |
|   MCRegister selectOrSplit(const LiveInterval &,
 | |
|                            SmallVectorImpl<Register> &) override;
 | |
|   void aboutToRemoveInterval(const 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(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> &);
 | |
|   /// Calculate cost of region splitting.
 | |
|   unsigned calculateRegionSplitCost(const LiveInterval &VirtReg,
 | |
|                                     AllocationOrder &Order,
 | |
|                                     BlockFrequency &BestCost,
 | |
|                                     unsigned &NumCands, bool IgnoreCSR);
 | |
|   /// Perform region splitting.
 | |
|   unsigned doRegionSplit(const LiveInterval &VirtReg, unsigned BestCand,
 | |
|                          bool HasCompact, SmallVectorImpl<Register> &NewVRegs);
 | |
|   /// Check other options before using a callee-saved register for the first
 | |
|   /// time.
 | |
|   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();
 | |
| 
 | |
|   /// 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_
 |