123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- //===- RegAllocEvictionAdvisor.h - Interference resolution ------*- 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
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H
- #define LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/SmallSet.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/CodeGen/Register.h"
- #include "llvm/Config/llvm-config.h"
- #include "llvm/MC/MCRegister.h"
- #include "llvm/Pass.h"
- namespace llvm {
- class AllocationOrder;
- class LiveInterval;
- class LiveIntervals;
- class LiveRegMatrix;
- class MachineFunction;
- class MachineRegisterInfo;
- class RegisterClassInfo;
- class TargetRegisterInfo;
- class VirtRegMap;
- using SmallVirtRegSet = SmallSet<Register, 16>;
- // Live ranges pass through a number of stages as we try to allocate them.
- // Some of the stages may also create new live ranges:
- //
- // - Region splitting.
- // - Per-block splitting.
- // - Local splitting.
- // - Spilling.
- //
- // Ranges produced by one of the stages skip the previous stages when they are
- // dequeued. This improves performance because we can skip interference checks
- // that are unlikely to give any results. It also guarantees that the live
- // range splitting algorithm terminates, something that is otherwise hard to
- // ensure.
- enum LiveRangeStage {
- /// Newly created live range that has never been queued.
- RS_New,
- /// Only attempt assignment and eviction. Then requeue as RS_Split.
- RS_Assign,
- /// Attempt live range splitting if assignment is impossible.
- RS_Split,
- /// Attempt more aggressive live range splitting that is guaranteed to make
- /// progress. This is used for split products that may not be making
- /// progress.
- RS_Split2,
- /// Live range will be spilled. No more splitting will be attempted.
- RS_Spill,
- /// Live range is in memory. Because of other evictions, it might get moved
- /// in a register in the end.
- RS_Memory,
- /// There is nothing more we can do to this live range. Abort compilation
- /// if it can't be assigned.
- RS_Done
- };
- /// Cost of evicting interference - used by default advisor, and the eviction
- /// chain heuristic in RegAllocGreedy.
- // FIXME: this can be probably made an implementation detail of the default
- // advisor, if the eviction chain logic can be refactored.
- struct EvictionCost {
- unsigned BrokenHints = 0; ///< Total number of broken hints.
- float MaxWeight = 0; ///< Maximum spill weight evicted.
- EvictionCost() = default;
- bool isMax() const { return BrokenHints == ~0u; }
- void setMax() { BrokenHints = ~0u; }
- void setBrokenHints(unsigned NHints) { BrokenHints = NHints; }
- bool operator<(const EvictionCost &O) const {
- return std::tie(BrokenHints, MaxWeight) <
- std::tie(O.BrokenHints, O.MaxWeight);
- }
- };
- /// Interface to the eviction advisor, which is responsible for making a
- /// decision as to which live ranges should be evicted (if any).
- class RAGreedy;
- class RegAllocEvictionAdvisor {
- public:
- RegAllocEvictionAdvisor(const RegAllocEvictionAdvisor &) = delete;
- RegAllocEvictionAdvisor(RegAllocEvictionAdvisor &&) = delete;
- virtual ~RegAllocEvictionAdvisor() = default;
- /// Find a physical register that can be freed by evicting the FixedRegisters,
- /// or return NoRegister. The eviction decision is assumed to be correct (i.e.
- /// no fixed live ranges are evicted) and profitable.
- virtual MCRegister tryFindEvictionCandidate(
- const LiveInterval &VirtReg, const AllocationOrder &Order,
- uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) const = 0;
- /// Find out if we can evict the live ranges occupying the given PhysReg,
- /// which is a hint (preferred register) for VirtReg.
- virtual bool
- canEvictHintInterference(const LiveInterval &VirtReg, MCRegister PhysReg,
- const SmallVirtRegSet &FixedRegisters) const = 0;
- /// Returns true if the given \p PhysReg is a callee saved register and has
- /// not been used for allocation yet.
- bool isUnusedCalleeSavedReg(MCRegister PhysReg) const;
- protected:
- RegAllocEvictionAdvisor(const MachineFunction &MF, const RAGreedy &RA);
- Register canReassign(const LiveInterval &VirtReg, Register PrevReg) const;
- // Get the upper limit of elements in the given Order we need to analize.
- // TODO: is this heuristic, we could consider learning it.
- std::optional<unsigned> getOrderLimit(const LiveInterval &VirtReg,
- const AllocationOrder &Order,
- unsigned CostPerUseLimit) const;
- // Determine if it's worth trying to allocate this reg, given the
- // CostPerUseLimit
- // TODO: this is a heuristic component we could consider learning, too.
- bool canAllocatePhysReg(unsigned CostPerUseLimit, MCRegister PhysReg) const;
- const MachineFunction &MF;
- const RAGreedy &RA;
- LiveRegMatrix *const Matrix;
- LiveIntervals *const LIS;
- VirtRegMap *const VRM;
- MachineRegisterInfo *const MRI;
- const TargetRegisterInfo *const TRI;
- const RegisterClassInfo &RegClassInfo;
- const ArrayRef<uint8_t> RegCosts;
- /// Run or not the local reassignment heuristic. This information is
- /// obtained from the TargetSubtargetInfo.
- const bool EnableLocalReassign;
- };
- /// ImmutableAnalysis abstraction for fetching the Eviction Advisor. We model it
- /// as an analysis to decouple the user from the implementation insofar as
- /// dependencies on other analyses goes. The motivation for it being an
- /// immutable pass is twofold:
- /// - in the ML implementation case, the evaluator is stateless but (especially
- /// in the development mode) expensive to set up. With an immutable pass, we set
- /// it up once.
- /// - in the 'development' mode ML case, we want to capture the training log
- /// during allocation (this is a log of features encountered and decisions
- /// made), and then measure a score, potentially a few steps after allocation
- /// completes. So we need the properties of an immutable pass to keep the logger
- /// state around until we can make that measurement.
- ///
- /// Because we need to offer additional services in 'development' mode, the
- /// implementations of this analysis need to implement RTTI support.
- class RegAllocEvictionAdvisorAnalysis : public ImmutablePass {
- public:
- enum class AdvisorMode : int { Default, Release, Development };
- RegAllocEvictionAdvisorAnalysis(AdvisorMode Mode)
- : ImmutablePass(ID), Mode(Mode){};
- static char ID;
- /// Get an advisor for the given context (i.e. machine function, etc)
- virtual std::unique_ptr<RegAllocEvictionAdvisor>
- getAdvisor(const MachineFunction &MF, const RAGreedy &RA) = 0;
- AdvisorMode getAdvisorMode() const { return Mode; }
- virtual void logRewardIfNeeded(const MachineFunction &MF,
- llvm::function_ref<float()> GetReward){};
- protected:
- // This analysis preserves everything, and subclasses may have additional
- // requirements.
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesAll();
- }
- private:
- StringRef getPassName() const override;
- const AdvisorMode Mode;
- };
- /// Specialization for the API used by the analysis infrastructure to create
- /// an instance of the eviction advisor.
- template <> Pass *callDefaultCtor<RegAllocEvictionAdvisorAnalysis>();
- RegAllocEvictionAdvisorAnalysis *createReleaseModeAdvisor();
- RegAllocEvictionAdvisorAnalysis *createDevelopmentModeAdvisor();
- // TODO: move to RegAllocEvictionAdvisor.cpp when we move implementation
- // out of RegAllocGreedy.cpp
- class DefaultEvictionAdvisor : public RegAllocEvictionAdvisor {
- public:
- DefaultEvictionAdvisor(const MachineFunction &MF, const RAGreedy &RA)
- : RegAllocEvictionAdvisor(MF, RA) {}
- private:
- MCRegister tryFindEvictionCandidate(const LiveInterval &,
- const AllocationOrder &, uint8_t,
- const SmallVirtRegSet &) const override;
- bool canEvictHintInterference(const LiveInterval &, MCRegister,
- const SmallVirtRegSet &) const override;
- bool canEvictInterferenceBasedOnCost(const LiveInterval &, MCRegister, bool,
- EvictionCost &,
- const SmallVirtRegSet &) const;
- bool shouldEvict(const LiveInterval &A, bool, const LiveInterval &B,
- bool) const;
- };
- } // namespace llvm
- #endif // LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H
|