1349cc55cSDimitry Andric //===- RegAllocEvictionAdvisor.h - Interference resolution ------*- C++ -*-===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric 9349cc55cSDimitry Andric #ifndef LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H 10349cc55cSDimitry Andric #define LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H 11349cc55cSDimitry Andric 1281ad6265SDimitry Andric #include "llvm/ADT/ArrayRef.h" 13349cc55cSDimitry Andric #include "llvm/ADT/SmallSet.h" 1481ad6265SDimitry Andric #include "llvm/ADT/StringRef.h" 15349cc55cSDimitry Andric #include "llvm/CodeGen/Register.h" 160eae32dcSDimitry Andric #include "llvm/Config/llvm-config.h" 1781ad6265SDimitry Andric #include "llvm/MC/MCRegister.h" 18349cc55cSDimitry Andric #include "llvm/Pass.h" 19349cc55cSDimitry Andric 20349cc55cSDimitry Andric namespace llvm { 2181ad6265SDimitry Andric class AllocationOrder; 2281ad6265SDimitry Andric class LiveInterval; 2381ad6265SDimitry Andric class LiveIntervals; 2481ad6265SDimitry Andric class LiveRegMatrix; 2581ad6265SDimitry Andric class MachineFunction; 2681ad6265SDimitry Andric class MachineRegisterInfo; 2781ad6265SDimitry Andric class RegisterClassInfo; 2881ad6265SDimitry Andric class TargetRegisterInfo; 2981ad6265SDimitry Andric class VirtRegMap; 30349cc55cSDimitry Andric 31349cc55cSDimitry Andric using SmallVirtRegSet = SmallSet<Register, 16>; 32349cc55cSDimitry Andric 33349cc55cSDimitry Andric // Live ranges pass through a number of stages as we try to allocate them. 34349cc55cSDimitry Andric // Some of the stages may also create new live ranges: 35349cc55cSDimitry Andric // 36349cc55cSDimitry Andric // - Region splitting. 37349cc55cSDimitry Andric // - Per-block splitting. 38349cc55cSDimitry Andric // - Local splitting. 39349cc55cSDimitry Andric // - Spilling. 40349cc55cSDimitry Andric // 41349cc55cSDimitry Andric // Ranges produced by one of the stages skip the previous stages when they are 42349cc55cSDimitry Andric // dequeued. This improves performance because we can skip interference checks 43349cc55cSDimitry Andric // that are unlikely to give any results. It also guarantees that the live 44349cc55cSDimitry Andric // range splitting algorithm terminates, something that is otherwise hard to 45349cc55cSDimitry Andric // ensure. 46349cc55cSDimitry Andric enum LiveRangeStage { 47349cc55cSDimitry Andric /// Newly created live range that has never been queued. 48349cc55cSDimitry Andric RS_New, 49349cc55cSDimitry Andric 50349cc55cSDimitry Andric /// Only attempt assignment and eviction. Then requeue as RS_Split. 51349cc55cSDimitry Andric RS_Assign, 52349cc55cSDimitry Andric 53349cc55cSDimitry Andric /// Attempt live range splitting if assignment is impossible. 54349cc55cSDimitry Andric RS_Split, 55349cc55cSDimitry Andric 56349cc55cSDimitry Andric /// Attempt more aggressive live range splitting that is guaranteed to make 57349cc55cSDimitry Andric /// progress. This is used for split products that may not be making 58349cc55cSDimitry Andric /// progress. 59349cc55cSDimitry Andric RS_Split2, 60349cc55cSDimitry Andric 61349cc55cSDimitry Andric /// Live range will be spilled. No more splitting will be attempted. 62349cc55cSDimitry Andric RS_Spill, 63349cc55cSDimitry Andric 64349cc55cSDimitry Andric /// Live range is in memory. Because of other evictions, it might get moved 65349cc55cSDimitry Andric /// in a register in the end. 66349cc55cSDimitry Andric RS_Memory, 67349cc55cSDimitry Andric 68349cc55cSDimitry Andric /// There is nothing more we can do to this live range. Abort compilation 69349cc55cSDimitry Andric /// if it can't be assigned. 70349cc55cSDimitry Andric RS_Done 71349cc55cSDimitry Andric }; 72349cc55cSDimitry Andric 73349cc55cSDimitry Andric /// Cost of evicting interference - used by default advisor, and the eviction 74349cc55cSDimitry Andric /// chain heuristic in RegAllocGreedy. 75349cc55cSDimitry Andric // FIXME: this can be probably made an implementation detail of the default 76349cc55cSDimitry Andric // advisor, if the eviction chain logic can be refactored. 77349cc55cSDimitry Andric struct EvictionCost { 78349cc55cSDimitry Andric unsigned BrokenHints = 0; ///< Total number of broken hints. 79349cc55cSDimitry Andric float MaxWeight = 0; ///< Maximum spill weight evicted. 80349cc55cSDimitry Andric 81349cc55cSDimitry Andric EvictionCost() = default; 82349cc55cSDimitry Andric isMaxEvictionCost83349cc55cSDimitry Andric bool isMax() const { return BrokenHints == ~0u; } 84349cc55cSDimitry Andric setMaxEvictionCost85349cc55cSDimitry Andric void setMax() { BrokenHints = ~0u; } 86349cc55cSDimitry Andric setBrokenHintsEvictionCost87349cc55cSDimitry Andric void setBrokenHints(unsigned NHints) { BrokenHints = NHints; } 88349cc55cSDimitry Andric 89349cc55cSDimitry Andric bool operator<(const EvictionCost &O) const { 90349cc55cSDimitry Andric return std::tie(BrokenHints, MaxWeight) < 91349cc55cSDimitry Andric std::tie(O.BrokenHints, O.MaxWeight); 92349cc55cSDimitry Andric } 93349cc55cSDimitry Andric }; 940eae32dcSDimitry Andric 950eae32dcSDimitry Andric /// Interface to the eviction advisor, which is responsible for making a 960eae32dcSDimitry Andric /// decision as to which live ranges should be evicted (if any). 9704eeddc0SDimitry Andric class RAGreedy; 980eae32dcSDimitry Andric class RegAllocEvictionAdvisor { 990eae32dcSDimitry Andric public: 1000eae32dcSDimitry Andric RegAllocEvictionAdvisor(const RegAllocEvictionAdvisor &) = delete; 1010eae32dcSDimitry Andric RegAllocEvictionAdvisor(RegAllocEvictionAdvisor &&) = delete; 1020eae32dcSDimitry Andric virtual ~RegAllocEvictionAdvisor() = default; 1030eae32dcSDimitry Andric 1040eae32dcSDimitry Andric /// Find a physical register that can be freed by evicting the FixedRegisters, 1050eae32dcSDimitry Andric /// or return NoRegister. The eviction decision is assumed to be correct (i.e. 1060eae32dcSDimitry Andric /// no fixed live ranges are evicted) and profitable. 10781ad6265SDimitry Andric virtual MCRegister tryFindEvictionCandidate( 10881ad6265SDimitry Andric const LiveInterval &VirtReg, const AllocationOrder &Order, 10981ad6265SDimitry Andric uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) const = 0; 1100eae32dcSDimitry Andric 1110eae32dcSDimitry Andric /// Find out if we can evict the live ranges occupying the given PhysReg, 1120eae32dcSDimitry Andric /// which is a hint (preferred register) for VirtReg. 1130eae32dcSDimitry Andric virtual bool 11481ad6265SDimitry Andric canEvictHintInterference(const LiveInterval &VirtReg, MCRegister PhysReg, 1150eae32dcSDimitry Andric const SmallVirtRegSet &FixedRegisters) const = 0; 1160eae32dcSDimitry Andric 1170eae32dcSDimitry Andric /// Returns true if the given \p PhysReg is a callee saved register and has 1180eae32dcSDimitry Andric /// not been used for allocation yet. 1190eae32dcSDimitry Andric bool isUnusedCalleeSavedReg(MCRegister PhysReg) const; 1200eae32dcSDimitry Andric 1210eae32dcSDimitry Andric protected: 12281ad6265SDimitry Andric RegAllocEvictionAdvisor(const MachineFunction &MF, const RAGreedy &RA); 1230eae32dcSDimitry Andric 124*06c3fb27SDimitry Andric bool canReassign(const LiveInterval &VirtReg, MCRegister FromReg) const; 1250eae32dcSDimitry Andric 12604eeddc0SDimitry Andric // Get the upper limit of elements in the given Order we need to analize. 12704eeddc0SDimitry Andric // TODO: is this heuristic, we could consider learning it. 128bdd1243dSDimitry Andric std::optional<unsigned> getOrderLimit(const LiveInterval &VirtReg, 12904eeddc0SDimitry Andric const AllocationOrder &Order, 13004eeddc0SDimitry Andric unsigned CostPerUseLimit) const; 13104eeddc0SDimitry Andric 13204eeddc0SDimitry Andric // Determine if it's worth trying to allocate this reg, given the 13304eeddc0SDimitry Andric // CostPerUseLimit 13404eeddc0SDimitry Andric // TODO: this is a heuristic component we could consider learning, too. 13504eeddc0SDimitry Andric bool canAllocatePhysReg(unsigned CostPerUseLimit, MCRegister PhysReg) const; 13604eeddc0SDimitry Andric 1370eae32dcSDimitry Andric const MachineFunction &MF; 13804eeddc0SDimitry Andric const RAGreedy &RA; 1390eae32dcSDimitry Andric LiveRegMatrix *const Matrix; 1400eae32dcSDimitry Andric LiveIntervals *const LIS; 1410eae32dcSDimitry Andric VirtRegMap *const VRM; 1420eae32dcSDimitry Andric MachineRegisterInfo *const MRI; 1430eae32dcSDimitry Andric const TargetRegisterInfo *const TRI; 1440eae32dcSDimitry Andric const RegisterClassInfo &RegClassInfo; 1450eae32dcSDimitry Andric const ArrayRef<uint8_t> RegCosts; 1460eae32dcSDimitry Andric 1470eae32dcSDimitry Andric /// Run or not the local reassignment heuristic. This information is 1480eae32dcSDimitry Andric /// obtained from the TargetSubtargetInfo. 1490eae32dcSDimitry Andric const bool EnableLocalReassign; 1500eae32dcSDimitry Andric }; 1510eae32dcSDimitry Andric 1520eae32dcSDimitry Andric /// ImmutableAnalysis abstraction for fetching the Eviction Advisor. We model it 1530eae32dcSDimitry Andric /// as an analysis to decouple the user from the implementation insofar as 1540eae32dcSDimitry Andric /// dependencies on other analyses goes. The motivation for it being an 1550eae32dcSDimitry Andric /// immutable pass is twofold: 1560eae32dcSDimitry Andric /// - in the ML implementation case, the evaluator is stateless but (especially 1570eae32dcSDimitry Andric /// in the development mode) expensive to set up. With an immutable pass, we set 1580eae32dcSDimitry Andric /// it up once. 1590eae32dcSDimitry Andric /// - in the 'development' mode ML case, we want to capture the training log 1600eae32dcSDimitry Andric /// during allocation (this is a log of features encountered and decisions 1610eae32dcSDimitry Andric /// made), and then measure a score, potentially a few steps after allocation 1620eae32dcSDimitry Andric /// completes. So we need the properties of an immutable pass to keep the logger 1630eae32dcSDimitry Andric /// state around until we can make that measurement. 1640eae32dcSDimitry Andric /// 1650eae32dcSDimitry Andric /// Because we need to offer additional services in 'development' mode, the 1660eae32dcSDimitry Andric /// implementations of this analysis need to implement RTTI support. 1670eae32dcSDimitry Andric class RegAllocEvictionAdvisorAnalysis : public ImmutablePass { 1680eae32dcSDimitry Andric public: 1690eae32dcSDimitry Andric enum class AdvisorMode : int { Default, Release, Development }; 1700eae32dcSDimitry Andric RegAllocEvictionAdvisorAnalysis(AdvisorMode Mode)1710eae32dcSDimitry Andric RegAllocEvictionAdvisorAnalysis(AdvisorMode Mode) 1720eae32dcSDimitry Andric : ImmutablePass(ID), Mode(Mode){}; 1730eae32dcSDimitry Andric static char ID; 1740eae32dcSDimitry Andric 1750eae32dcSDimitry Andric /// Get an advisor for the given context (i.e. machine function, etc) 1760eae32dcSDimitry Andric virtual std::unique_ptr<RegAllocEvictionAdvisor> 17781ad6265SDimitry Andric getAdvisor(const MachineFunction &MF, const RAGreedy &RA) = 0; getAdvisorMode()1780eae32dcSDimitry Andric AdvisorMode getAdvisorMode() const { return Mode; } logRewardIfNeeded(const MachineFunction & MF,llvm::function_ref<float ()> GetReward)179bdd1243dSDimitry Andric virtual void logRewardIfNeeded(const MachineFunction &MF, 180bdd1243dSDimitry Andric llvm::function_ref<float()> GetReward){}; 1810eae32dcSDimitry Andric 18204eeddc0SDimitry Andric protected: 1830eae32dcSDimitry Andric // This analysis preserves everything, and subclasses may have additional 1840eae32dcSDimitry Andric // requirements. getAnalysisUsage(AnalysisUsage & AU)1850eae32dcSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 1860eae32dcSDimitry Andric AU.setPreservesAll(); 1870eae32dcSDimitry Andric } 1880eae32dcSDimitry Andric 18904eeddc0SDimitry Andric private: 1900eae32dcSDimitry Andric StringRef getPassName() const override; 1910eae32dcSDimitry Andric const AdvisorMode Mode; 1920eae32dcSDimitry Andric }; 1930eae32dcSDimitry Andric 1940eae32dcSDimitry Andric /// Specialization for the API used by the analysis infrastructure to create 1950eae32dcSDimitry Andric /// an instance of the eviction advisor. 1960eae32dcSDimitry Andric template <> Pass *callDefaultCtor<RegAllocEvictionAdvisorAnalysis>(); 1970eae32dcSDimitry Andric 1980eae32dcSDimitry Andric RegAllocEvictionAdvisorAnalysis *createReleaseModeAdvisor(); 1990eae32dcSDimitry Andric 2000eae32dcSDimitry Andric RegAllocEvictionAdvisorAnalysis *createDevelopmentModeAdvisor(); 2010eae32dcSDimitry Andric 2020eae32dcSDimitry Andric // TODO: move to RegAllocEvictionAdvisor.cpp when we move implementation 2030eae32dcSDimitry Andric // out of RegAllocGreedy.cpp 2040eae32dcSDimitry Andric class DefaultEvictionAdvisor : public RegAllocEvictionAdvisor { 2050eae32dcSDimitry Andric public: DefaultEvictionAdvisor(const MachineFunction & MF,const RAGreedy & RA)20681ad6265SDimitry Andric DefaultEvictionAdvisor(const MachineFunction &MF, const RAGreedy &RA) 20704eeddc0SDimitry Andric : RegAllocEvictionAdvisor(MF, RA) {} 2080eae32dcSDimitry Andric 2090eae32dcSDimitry Andric private: 21081ad6265SDimitry Andric MCRegister tryFindEvictionCandidate(const LiveInterval &, 21181ad6265SDimitry Andric const AllocationOrder &, uint8_t, 2120eae32dcSDimitry Andric const SmallVirtRegSet &) const override; 21381ad6265SDimitry Andric bool canEvictHintInterference(const LiveInterval &, MCRegister, 2140eae32dcSDimitry Andric const SmallVirtRegSet &) const override; 21581ad6265SDimitry Andric bool canEvictInterferenceBasedOnCost(const LiveInterval &, MCRegister, bool, 2160eae32dcSDimitry Andric EvictionCost &, 2170eae32dcSDimitry Andric const SmallVirtRegSet &) const; 21881ad6265SDimitry Andric bool shouldEvict(const LiveInterval &A, bool, const LiveInterval &B, 21981ad6265SDimitry Andric bool) const; 2200eae32dcSDimitry Andric }; 221349cc55cSDimitry Andric } // namespace llvm 222349cc55cSDimitry Andric 223349cc55cSDimitry Andric #endif // LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H 224