xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/RegAllocEvictionAdvisor.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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