1*d415bd75Srobert //===- RegAllocEvictionAdvisor.h - Interference resolution ------*- C++ -*-===// 2*d415bd75Srobert // 3*d415bd75Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*d415bd75Srobert // See https://llvm.org/LICENSE.txt for license information. 5*d415bd75Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*d415bd75Srobert // 7*d415bd75Srobert //===----------------------------------------------------------------------===// 8*d415bd75Srobert 9*d415bd75Srobert #ifndef LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H 10*d415bd75Srobert #define LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H 11*d415bd75Srobert 12*d415bd75Srobert #include "llvm/ADT/ArrayRef.h" 13*d415bd75Srobert #include "llvm/ADT/SmallSet.h" 14*d415bd75Srobert #include "llvm/ADT/StringRef.h" 15*d415bd75Srobert #include "llvm/CodeGen/Register.h" 16*d415bd75Srobert #include "llvm/Config/llvm-config.h" 17*d415bd75Srobert #include "llvm/MC/MCRegister.h" 18*d415bd75Srobert #include "llvm/Pass.h" 19*d415bd75Srobert 20*d415bd75Srobert namespace llvm { 21*d415bd75Srobert class AllocationOrder; 22*d415bd75Srobert class LiveInterval; 23*d415bd75Srobert class LiveIntervals; 24*d415bd75Srobert class LiveRegMatrix; 25*d415bd75Srobert class MachineFunction; 26*d415bd75Srobert class MachineRegisterInfo; 27*d415bd75Srobert class RegisterClassInfo; 28*d415bd75Srobert class TargetRegisterInfo; 29*d415bd75Srobert class VirtRegMap; 30*d415bd75Srobert 31*d415bd75Srobert using SmallVirtRegSet = SmallSet<Register, 16>; 32*d415bd75Srobert 33*d415bd75Srobert // Live ranges pass through a number of stages as we try to allocate them. 34*d415bd75Srobert // Some of the stages may also create new live ranges: 35*d415bd75Srobert // 36*d415bd75Srobert // - Region splitting. 37*d415bd75Srobert // - Per-block splitting. 38*d415bd75Srobert // - Local splitting. 39*d415bd75Srobert // - Spilling. 40*d415bd75Srobert // 41*d415bd75Srobert // Ranges produced by one of the stages skip the previous stages when they are 42*d415bd75Srobert // dequeued. This improves performance because we can skip interference checks 43*d415bd75Srobert // that are unlikely to give any results. It also guarantees that the live 44*d415bd75Srobert // range splitting algorithm terminates, something that is otherwise hard to 45*d415bd75Srobert // ensure. 46*d415bd75Srobert enum LiveRangeStage { 47*d415bd75Srobert /// Newly created live range that has never been queued. 48*d415bd75Srobert RS_New, 49*d415bd75Srobert 50*d415bd75Srobert /// Only attempt assignment and eviction. Then requeue as RS_Split. 51*d415bd75Srobert RS_Assign, 52*d415bd75Srobert 53*d415bd75Srobert /// Attempt live range splitting if assignment is impossible. 54*d415bd75Srobert RS_Split, 55*d415bd75Srobert 56*d415bd75Srobert /// Attempt more aggressive live range splitting that is guaranteed to make 57*d415bd75Srobert /// progress. This is used for split products that may not be making 58*d415bd75Srobert /// progress. 59*d415bd75Srobert RS_Split2, 60*d415bd75Srobert 61*d415bd75Srobert /// Live range will be spilled. No more splitting will be attempted. 62*d415bd75Srobert RS_Spill, 63*d415bd75Srobert 64*d415bd75Srobert /// Live range is in memory. Because of other evictions, it might get moved 65*d415bd75Srobert /// in a register in the end. 66*d415bd75Srobert RS_Memory, 67*d415bd75Srobert 68*d415bd75Srobert /// There is nothing more we can do to this live range. Abort compilation 69*d415bd75Srobert /// if it can't be assigned. 70*d415bd75Srobert RS_Done 71*d415bd75Srobert }; 72*d415bd75Srobert 73*d415bd75Srobert /// Cost of evicting interference - used by default advisor, and the eviction 74*d415bd75Srobert /// chain heuristic in RegAllocGreedy. 75*d415bd75Srobert // FIXME: this can be probably made an implementation detail of the default 76*d415bd75Srobert // advisor, if the eviction chain logic can be refactored. 77*d415bd75Srobert struct EvictionCost { 78*d415bd75Srobert unsigned BrokenHints = 0; ///< Total number of broken hints. 79*d415bd75Srobert float MaxWeight = 0; ///< Maximum spill weight evicted. 80*d415bd75Srobert 81*d415bd75Srobert EvictionCost() = default; 82*d415bd75Srobert isMaxEvictionCost83*d415bd75Srobert bool isMax() const { return BrokenHints == ~0u; } 84*d415bd75Srobert setMaxEvictionCost85*d415bd75Srobert void setMax() { BrokenHints = ~0u; } 86*d415bd75Srobert setBrokenHintsEvictionCost87*d415bd75Srobert void setBrokenHints(unsigned NHints) { BrokenHints = NHints; } 88*d415bd75Srobert 89*d415bd75Srobert bool operator<(const EvictionCost &O) const { 90*d415bd75Srobert return std::tie(BrokenHints, MaxWeight) < 91*d415bd75Srobert std::tie(O.BrokenHints, O.MaxWeight); 92*d415bd75Srobert } 93*d415bd75Srobert }; 94*d415bd75Srobert 95*d415bd75Srobert /// Interface to the eviction advisor, which is responsible for making a 96*d415bd75Srobert /// decision as to which live ranges should be evicted (if any). 97*d415bd75Srobert class RAGreedy; 98*d415bd75Srobert class RegAllocEvictionAdvisor { 99*d415bd75Srobert public: 100*d415bd75Srobert RegAllocEvictionAdvisor(const RegAllocEvictionAdvisor &) = delete; 101*d415bd75Srobert RegAllocEvictionAdvisor(RegAllocEvictionAdvisor &&) = delete; 102*d415bd75Srobert virtual ~RegAllocEvictionAdvisor() = default; 103*d415bd75Srobert 104*d415bd75Srobert /// Find a physical register that can be freed by evicting the FixedRegisters, 105*d415bd75Srobert /// or return NoRegister. The eviction decision is assumed to be correct (i.e. 106*d415bd75Srobert /// no fixed live ranges are evicted) and profitable. 107*d415bd75Srobert virtual MCRegister tryFindEvictionCandidate( 108*d415bd75Srobert const LiveInterval &VirtReg, const AllocationOrder &Order, 109*d415bd75Srobert uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) const = 0; 110*d415bd75Srobert 111*d415bd75Srobert /// Find out if we can evict the live ranges occupying the given PhysReg, 112*d415bd75Srobert /// which is a hint (preferred register) for VirtReg. 113*d415bd75Srobert virtual bool 114*d415bd75Srobert canEvictHintInterference(const LiveInterval &VirtReg, MCRegister PhysReg, 115*d415bd75Srobert const SmallVirtRegSet &FixedRegisters) const = 0; 116*d415bd75Srobert 117*d415bd75Srobert /// Returns true if the given \p PhysReg is a callee saved register and has 118*d415bd75Srobert /// not been used for allocation yet. 119*d415bd75Srobert bool isUnusedCalleeSavedReg(MCRegister PhysReg) const; 120*d415bd75Srobert 121*d415bd75Srobert protected: 122*d415bd75Srobert RegAllocEvictionAdvisor(const MachineFunction &MF, const RAGreedy &RA); 123*d415bd75Srobert 124*d415bd75Srobert Register canReassign(const LiveInterval &VirtReg, Register PrevReg) const; 125*d415bd75Srobert 126*d415bd75Srobert // Get the upper limit of elements in the given Order we need to analize. 127*d415bd75Srobert // TODO: is this heuristic, we could consider learning it. 128*d415bd75Srobert std::optional<unsigned> getOrderLimit(const LiveInterval &VirtReg, 129*d415bd75Srobert const AllocationOrder &Order, 130*d415bd75Srobert unsigned CostPerUseLimit) const; 131*d415bd75Srobert 132*d415bd75Srobert // Determine if it's worth trying to allocate this reg, given the 133*d415bd75Srobert // CostPerUseLimit 134*d415bd75Srobert // TODO: this is a heuristic component we could consider learning, too. 135*d415bd75Srobert bool canAllocatePhysReg(unsigned CostPerUseLimit, MCRegister PhysReg) const; 136*d415bd75Srobert 137*d415bd75Srobert const MachineFunction &MF; 138*d415bd75Srobert const RAGreedy &RA; 139*d415bd75Srobert LiveRegMatrix *const Matrix; 140*d415bd75Srobert LiveIntervals *const LIS; 141*d415bd75Srobert VirtRegMap *const VRM; 142*d415bd75Srobert MachineRegisterInfo *const MRI; 143*d415bd75Srobert const TargetRegisterInfo *const TRI; 144*d415bd75Srobert const RegisterClassInfo &RegClassInfo; 145*d415bd75Srobert const ArrayRef<uint8_t> RegCosts; 146*d415bd75Srobert 147*d415bd75Srobert /// Run or not the local reassignment heuristic. This information is 148*d415bd75Srobert /// obtained from the TargetSubtargetInfo. 149*d415bd75Srobert const bool EnableLocalReassign; 150*d415bd75Srobert }; 151*d415bd75Srobert 152*d415bd75Srobert /// ImmutableAnalysis abstraction for fetching the Eviction Advisor. We model it 153*d415bd75Srobert /// as an analysis to decouple the user from the implementation insofar as 154*d415bd75Srobert /// dependencies on other analyses goes. The motivation for it being an 155*d415bd75Srobert /// immutable pass is twofold: 156*d415bd75Srobert /// - in the ML implementation case, the evaluator is stateless but (especially 157*d415bd75Srobert /// in the development mode) expensive to set up. With an immutable pass, we set 158*d415bd75Srobert /// it up once. 159*d415bd75Srobert /// - in the 'development' mode ML case, we want to capture the training log 160*d415bd75Srobert /// during allocation (this is a log of features encountered and decisions 161*d415bd75Srobert /// made), and then measure a score, potentially a few steps after allocation 162*d415bd75Srobert /// completes. So we need the properties of an immutable pass to keep the logger 163*d415bd75Srobert /// state around until we can make that measurement. 164*d415bd75Srobert /// 165*d415bd75Srobert /// Because we need to offer additional services in 'development' mode, the 166*d415bd75Srobert /// implementations of this analysis need to implement RTTI support. 167*d415bd75Srobert class RegAllocEvictionAdvisorAnalysis : public ImmutablePass { 168*d415bd75Srobert public: 169*d415bd75Srobert enum class AdvisorMode : int { Default, Release, Development }; 170*d415bd75Srobert RegAllocEvictionAdvisorAnalysis(AdvisorMode Mode)171*d415bd75Srobert RegAllocEvictionAdvisorAnalysis(AdvisorMode Mode) 172*d415bd75Srobert : ImmutablePass(ID), Mode(Mode){}; 173*d415bd75Srobert static char ID; 174*d415bd75Srobert 175*d415bd75Srobert /// Get an advisor for the given context (i.e. machine function, etc) 176*d415bd75Srobert virtual std::unique_ptr<RegAllocEvictionAdvisor> 177*d415bd75Srobert getAdvisor(const MachineFunction &MF, const RAGreedy &RA) = 0; getAdvisorMode()178*d415bd75Srobert AdvisorMode getAdvisorMode() const { return Mode; } logRewardIfNeeded(const MachineFunction & MF,llvm::function_ref<float ()> GetReward)179*d415bd75Srobert virtual void logRewardIfNeeded(const MachineFunction &MF, 180*d415bd75Srobert llvm::function_ref<float()> GetReward){}; 181*d415bd75Srobert 182*d415bd75Srobert protected: 183*d415bd75Srobert // This analysis preserves everything, and subclasses may have additional 184*d415bd75Srobert // requirements. getAnalysisUsage(AnalysisUsage & AU)185*d415bd75Srobert void getAnalysisUsage(AnalysisUsage &AU) const override { 186*d415bd75Srobert AU.setPreservesAll(); 187*d415bd75Srobert } 188*d415bd75Srobert 189*d415bd75Srobert private: 190*d415bd75Srobert StringRef getPassName() const override; 191*d415bd75Srobert const AdvisorMode Mode; 192*d415bd75Srobert }; 193*d415bd75Srobert 194*d415bd75Srobert /// Specialization for the API used by the analysis infrastructure to create 195*d415bd75Srobert /// an instance of the eviction advisor. 196*d415bd75Srobert template <> Pass *callDefaultCtor<RegAllocEvictionAdvisorAnalysis>(); 197*d415bd75Srobert 198*d415bd75Srobert RegAllocEvictionAdvisorAnalysis *createReleaseModeAdvisor(); 199*d415bd75Srobert 200*d415bd75Srobert RegAllocEvictionAdvisorAnalysis *createDevelopmentModeAdvisor(); 201*d415bd75Srobert 202*d415bd75Srobert // TODO: move to RegAllocEvictionAdvisor.cpp when we move implementation 203*d415bd75Srobert // out of RegAllocGreedy.cpp 204*d415bd75Srobert class DefaultEvictionAdvisor : public RegAllocEvictionAdvisor { 205*d415bd75Srobert public: DefaultEvictionAdvisor(const MachineFunction & MF,const RAGreedy & RA)206*d415bd75Srobert DefaultEvictionAdvisor(const MachineFunction &MF, const RAGreedy &RA) 207*d415bd75Srobert : RegAllocEvictionAdvisor(MF, RA) {} 208*d415bd75Srobert 209*d415bd75Srobert private: 210*d415bd75Srobert MCRegister tryFindEvictionCandidate(const LiveInterval &, 211*d415bd75Srobert const AllocationOrder &, uint8_t, 212*d415bd75Srobert const SmallVirtRegSet &) const override; 213*d415bd75Srobert bool canEvictHintInterference(const LiveInterval &, MCRegister, 214*d415bd75Srobert const SmallVirtRegSet &) const override; 215*d415bd75Srobert bool canEvictInterferenceBasedOnCost(const LiveInterval &, MCRegister, bool, 216*d415bd75Srobert EvictionCost &, 217*d415bd75Srobert const SmallVirtRegSet &) const; 218*d415bd75Srobert bool shouldEvict(const LiveInterval &A, bool, const LiveInterval &B, 219*d415bd75Srobert bool) const; 220*d415bd75Srobert }; 221*d415bd75Srobert } // namespace llvm 222*d415bd75Srobert 223*d415bd75Srobert #endif // LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H 224