10eae32dcSDimitry Andric //===- RegAllocEvictionAdvisor.cpp - eviction advisor ---------------------===//
20eae32dcSDimitry Andric //
30eae32dcSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40eae32dcSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50eae32dcSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60eae32dcSDimitry Andric //
70eae32dcSDimitry Andric //===----------------------------------------------------------------------===//
80eae32dcSDimitry Andric //
90eae32dcSDimitry Andric // Implementation of the default eviction advisor and of the Analysis pass.
100eae32dcSDimitry Andric //
110eae32dcSDimitry Andric //===----------------------------------------------------------------------===//
120eae32dcSDimitry Andric
130eae32dcSDimitry Andric #include "RegAllocEvictionAdvisor.h"
1481ad6265SDimitry Andric #include "AllocationOrder.h"
1504eeddc0SDimitry Andric #include "RegAllocGreedy.h"
1681ad6265SDimitry Andric #include "llvm/CodeGen/LiveRegMatrix.h"
170eae32dcSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
180eae32dcSDimitry Andric #include "llvm/CodeGen/RegisterClassInfo.h"
190eae32dcSDimitry Andric #include "llvm/CodeGen/VirtRegMap.h"
20*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h"
210eae32dcSDimitry Andric #include "llvm/InitializePasses.h"
220eae32dcSDimitry Andric #include "llvm/Pass.h"
230eae32dcSDimitry Andric #include "llvm/Support/CommandLine.h"
240eae32dcSDimitry Andric #include "llvm/Support/ErrorHandling.h"
250eae32dcSDimitry Andric #include "llvm/Target/TargetMachine.h"
260eae32dcSDimitry Andric
270eae32dcSDimitry Andric using namespace llvm;
280eae32dcSDimitry Andric
290eae32dcSDimitry Andric static cl::opt<RegAllocEvictionAdvisorAnalysis::AdvisorMode> Mode(
3081ad6265SDimitry Andric "regalloc-enable-advisor", cl::Hidden,
310eae32dcSDimitry Andric cl::init(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Default),
320eae32dcSDimitry Andric cl::desc("Enable regalloc advisor mode"),
330eae32dcSDimitry Andric cl::values(
340eae32dcSDimitry Andric clEnumValN(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Default,
350eae32dcSDimitry Andric "default", "Default"),
360eae32dcSDimitry Andric clEnumValN(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Release,
370eae32dcSDimitry Andric "release", "precompiled"),
380eae32dcSDimitry Andric clEnumValN(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Development,
390eae32dcSDimitry Andric "development", "for training")));
400eae32dcSDimitry Andric
410eae32dcSDimitry Andric static cl::opt<bool> EnableLocalReassignment(
420eae32dcSDimitry Andric "enable-local-reassign", cl::Hidden,
430eae32dcSDimitry Andric cl::desc("Local reassignment can yield better allocation decisions, but "
440eae32dcSDimitry Andric "may be compile time intensive"),
450eae32dcSDimitry Andric cl::init(false));
460eae32dcSDimitry Andric
4706c3fb27SDimitry Andric namespace llvm {
4881ad6265SDimitry Andric cl::opt<unsigned> EvictInterferenceCutoff(
4981ad6265SDimitry Andric "regalloc-eviction-max-interference-cutoff", cl::Hidden,
5081ad6265SDimitry Andric cl::desc("Number of interferences after which we declare "
5181ad6265SDimitry Andric "an interference unevictable and bail out. This "
5281ad6265SDimitry Andric "is a compilation cost-saving consideration. To "
5381ad6265SDimitry Andric "disable, pass a very large number."),
5481ad6265SDimitry Andric cl::init(10));
5506c3fb27SDimitry Andric }
5681ad6265SDimitry Andric
570eae32dcSDimitry Andric #define DEBUG_TYPE "regalloc"
5804eeddc0SDimitry Andric #ifdef LLVM_HAVE_TF_AOT_REGALLOCEVICTMODEL
5904eeddc0SDimitry Andric #define LLVM_HAVE_TF_AOT
6004eeddc0SDimitry Andric #endif
610eae32dcSDimitry Andric
620eae32dcSDimitry Andric char RegAllocEvictionAdvisorAnalysis::ID = 0;
630eae32dcSDimitry Andric INITIALIZE_PASS(RegAllocEvictionAdvisorAnalysis, "regalloc-evict",
640eae32dcSDimitry Andric "Regalloc eviction policy", false, true)
650eae32dcSDimitry Andric
660eae32dcSDimitry Andric namespace {
670eae32dcSDimitry Andric class DefaultEvictionAdvisorAnalysis final
680eae32dcSDimitry Andric : public RegAllocEvictionAdvisorAnalysis {
690eae32dcSDimitry Andric public:
DefaultEvictionAdvisorAnalysis(bool NotAsRequested)700eae32dcSDimitry Andric DefaultEvictionAdvisorAnalysis(bool NotAsRequested)
710eae32dcSDimitry Andric : RegAllocEvictionAdvisorAnalysis(AdvisorMode::Default),
720eae32dcSDimitry Andric NotAsRequested(NotAsRequested) {}
730eae32dcSDimitry Andric
740eae32dcSDimitry Andric // support for isa<> and dyn_cast.
classof(const RegAllocEvictionAdvisorAnalysis * R)750eae32dcSDimitry Andric static bool classof(const RegAllocEvictionAdvisorAnalysis *R) {
760eae32dcSDimitry Andric return R->getAdvisorMode() == AdvisorMode::Default;
770eae32dcSDimitry Andric }
780eae32dcSDimitry Andric
790eae32dcSDimitry Andric private:
800eae32dcSDimitry Andric std::unique_ptr<RegAllocEvictionAdvisor>
getAdvisor(const MachineFunction & MF,const RAGreedy & RA)8181ad6265SDimitry Andric getAdvisor(const MachineFunction &MF, const RAGreedy &RA) override {
8204eeddc0SDimitry Andric return std::make_unique<DefaultEvictionAdvisor>(MF, RA);
830eae32dcSDimitry Andric }
doInitialization(Module & M)840eae32dcSDimitry Andric bool doInitialization(Module &M) override {
850eae32dcSDimitry Andric if (NotAsRequested)
860eae32dcSDimitry Andric M.getContext().emitError("Requested regalloc eviction advisor analysis "
875f757f3fSDimitry Andric "could not be created. Using default");
880eae32dcSDimitry Andric return RegAllocEvictionAdvisorAnalysis::doInitialization(M);
890eae32dcSDimitry Andric }
900eae32dcSDimitry Andric const bool NotAsRequested;
910eae32dcSDimitry Andric };
920eae32dcSDimitry Andric } // namespace
930eae32dcSDimitry Andric
callDefaultCtor()940eae32dcSDimitry Andric template <> Pass *llvm::callDefaultCtor<RegAllocEvictionAdvisorAnalysis>() {
950eae32dcSDimitry Andric Pass *Ret = nullptr;
960eae32dcSDimitry Andric switch (Mode) {
970eae32dcSDimitry Andric case RegAllocEvictionAdvisorAnalysis::AdvisorMode::Default:
980eae32dcSDimitry Andric Ret = new DefaultEvictionAdvisorAnalysis(/*NotAsRequested*/ false);
990eae32dcSDimitry Andric break;
1000eae32dcSDimitry Andric case RegAllocEvictionAdvisorAnalysis::AdvisorMode::Development:
101bdd1243dSDimitry Andric #if defined(LLVM_HAVE_TFLITE)
10204eeddc0SDimitry Andric Ret = createDevelopmentModeAdvisor();
10304eeddc0SDimitry Andric #endif
1040eae32dcSDimitry Andric break;
1050eae32dcSDimitry Andric case RegAllocEvictionAdvisorAnalysis::AdvisorMode::Release:
10604eeddc0SDimitry Andric Ret = createReleaseModeAdvisor();
1070eae32dcSDimitry Andric break;
1080eae32dcSDimitry Andric }
1090eae32dcSDimitry Andric if (Ret)
1100eae32dcSDimitry Andric return Ret;
1110eae32dcSDimitry Andric return new DefaultEvictionAdvisorAnalysis(/*NotAsRequested*/ true);
1120eae32dcSDimitry Andric }
1130eae32dcSDimitry Andric
getPassName() const1140eae32dcSDimitry Andric StringRef RegAllocEvictionAdvisorAnalysis::getPassName() const {
1150eae32dcSDimitry Andric switch (getAdvisorMode()) {
1160eae32dcSDimitry Andric case AdvisorMode::Default:
1170eae32dcSDimitry Andric return "Default Regalloc Eviction Advisor";
1180eae32dcSDimitry Andric case AdvisorMode::Release:
1190eae32dcSDimitry Andric return "Release mode Regalloc Eviction Advisor";
1200eae32dcSDimitry Andric case AdvisorMode::Development:
1210eae32dcSDimitry Andric return "Development mode Regalloc Eviction Advisor";
1220eae32dcSDimitry Andric }
1230eae32dcSDimitry Andric llvm_unreachable("Unknown advisor kind");
1240eae32dcSDimitry Andric }
1250eae32dcSDimitry Andric
RegAllocEvictionAdvisor(const MachineFunction & MF,const RAGreedy & RA)12681ad6265SDimitry Andric RegAllocEvictionAdvisor::RegAllocEvictionAdvisor(const MachineFunction &MF,
12704eeddc0SDimitry Andric const RAGreedy &RA)
12804eeddc0SDimitry Andric : MF(MF), RA(RA), Matrix(RA.getInterferenceMatrix()),
12904eeddc0SDimitry Andric LIS(RA.getLiveIntervals()), VRM(RA.getVirtRegMap()),
13004eeddc0SDimitry Andric MRI(&VRM->getRegInfo()), TRI(MF.getSubtarget().getRegisterInfo()),
13104eeddc0SDimitry Andric RegClassInfo(RA.getRegClassInfo()), RegCosts(TRI->getRegisterCosts(MF)),
1320eae32dcSDimitry Andric EnableLocalReassign(EnableLocalReassignment ||
1330eae32dcSDimitry Andric MF.getSubtarget().enableRALocalReassignment(
1340eae32dcSDimitry Andric MF.getTarget().getOptLevel())) {}
1351fd87a68SDimitry Andric
1361fd87a68SDimitry Andric /// shouldEvict - determine if A should evict the assigned live range B. The
1371fd87a68SDimitry Andric /// eviction policy defined by this function together with the allocation order
1381fd87a68SDimitry Andric /// defined by enqueue() decides which registers ultimately end up being split
1391fd87a68SDimitry Andric /// and spilled.
1401fd87a68SDimitry Andric ///
1411fd87a68SDimitry Andric /// Cascade numbers are used to prevent infinite loops if this function is a
1421fd87a68SDimitry Andric /// cyclic relation.
1431fd87a68SDimitry Andric ///
1441fd87a68SDimitry Andric /// @param A The live range to be assigned.
1451fd87a68SDimitry Andric /// @param IsHint True when A is about to be assigned to its preferred
1461fd87a68SDimitry Andric /// register.
1471fd87a68SDimitry Andric /// @param B The live range to be evicted.
1481fd87a68SDimitry Andric /// @param BreaksHint True when B is already assigned to its preferred register.
shouldEvict(const LiveInterval & A,bool IsHint,const LiveInterval & B,bool BreaksHint) const14981ad6265SDimitry Andric bool DefaultEvictionAdvisor::shouldEvict(const LiveInterval &A, bool IsHint,
15081ad6265SDimitry Andric const LiveInterval &B,
1511fd87a68SDimitry Andric bool BreaksHint) const {
1521fd87a68SDimitry Andric bool CanSplit = RA.getExtraInfo().getStage(B) < RS_Spill;
1531fd87a68SDimitry Andric
1541fd87a68SDimitry Andric // Be fairly aggressive about following hints as long as the evictee can be
1551fd87a68SDimitry Andric // split.
1561fd87a68SDimitry Andric if (CanSplit && IsHint && !BreaksHint)
1571fd87a68SDimitry Andric return true;
1581fd87a68SDimitry Andric
1591fd87a68SDimitry Andric if (A.weight() > B.weight()) {
1601fd87a68SDimitry Andric LLVM_DEBUG(dbgs() << "should evict: " << B << " w= " << B.weight() << '\n');
1611fd87a68SDimitry Andric return true;
1621fd87a68SDimitry Andric }
1631fd87a68SDimitry Andric return false;
1641fd87a68SDimitry Andric }
1651fd87a68SDimitry Andric
1661fd87a68SDimitry Andric /// canEvictHintInterference - return true if the interference for VirtReg
1671fd87a68SDimitry Andric /// on the PhysReg, which is VirtReg's hint, can be evicted in favor of VirtReg.
canEvictHintInterference(const LiveInterval & VirtReg,MCRegister PhysReg,const SmallVirtRegSet & FixedRegisters) const1681fd87a68SDimitry Andric bool DefaultEvictionAdvisor::canEvictHintInterference(
16981ad6265SDimitry Andric const LiveInterval &VirtReg, MCRegister PhysReg,
1701fd87a68SDimitry Andric const SmallVirtRegSet &FixedRegisters) const {
1711fd87a68SDimitry Andric EvictionCost MaxCost;
1721fd87a68SDimitry Andric MaxCost.setBrokenHints(1);
1731fd87a68SDimitry Andric return canEvictInterferenceBasedOnCost(VirtReg, PhysReg, true, MaxCost,
1741fd87a68SDimitry Andric FixedRegisters);
1751fd87a68SDimitry Andric }
1761fd87a68SDimitry Andric
1771fd87a68SDimitry Andric /// canEvictInterferenceBasedOnCost - Return true if all interferences between
1781fd87a68SDimitry Andric /// VirtReg and PhysReg can be evicted.
1791fd87a68SDimitry Andric ///
1801fd87a68SDimitry Andric /// @param VirtReg Live range that is about to be assigned.
1811fd87a68SDimitry Andric /// @param PhysReg Desired register for assignment.
1821fd87a68SDimitry Andric /// @param IsHint True when PhysReg is VirtReg's preferred register.
1831fd87a68SDimitry Andric /// @param MaxCost Only look for cheaper candidates and update with new cost
1841fd87a68SDimitry Andric /// when returning true.
1851fd87a68SDimitry Andric /// @returns True when interference can be evicted cheaper than MaxCost.
canEvictInterferenceBasedOnCost(const LiveInterval & VirtReg,MCRegister PhysReg,bool IsHint,EvictionCost & MaxCost,const SmallVirtRegSet & FixedRegisters) const1861fd87a68SDimitry Andric bool DefaultEvictionAdvisor::canEvictInterferenceBasedOnCost(
18781ad6265SDimitry Andric const LiveInterval &VirtReg, MCRegister PhysReg, bool IsHint,
1881fd87a68SDimitry Andric EvictionCost &MaxCost, const SmallVirtRegSet &FixedRegisters) const {
1891fd87a68SDimitry Andric // It is only possible to evict virtual register interference.
1901fd87a68SDimitry Andric if (Matrix->checkInterference(VirtReg, PhysReg) > LiveRegMatrix::IK_VirtReg)
1911fd87a68SDimitry Andric return false;
1921fd87a68SDimitry Andric
1931fd87a68SDimitry Andric bool IsLocal = VirtReg.empty() || LIS->intervalIsInOneMBB(VirtReg);
1941fd87a68SDimitry Andric
1951fd87a68SDimitry Andric // Find VirtReg's cascade number. This will be unassigned if VirtReg was never
1961fd87a68SDimitry Andric // involved in an eviction before. If a cascade number was assigned, deny
1971fd87a68SDimitry Andric // evicting anything with the same or a newer cascade number. This prevents
1981fd87a68SDimitry Andric // infinite eviction loops.
1991fd87a68SDimitry Andric //
2001fd87a68SDimitry Andric // This works out so a register without a cascade number is allowed to evict
2011fd87a68SDimitry Andric // anything, and it can be evicted by anything.
2021fd87a68SDimitry Andric unsigned Cascade = RA.getExtraInfo().getCascadeOrCurrentNext(VirtReg.reg());
2031fd87a68SDimitry Andric
2041fd87a68SDimitry Andric EvictionCost Cost;
20506c3fb27SDimitry Andric for (MCRegUnit Unit : TRI->regunits(PhysReg)) {
20606c3fb27SDimitry Andric LiveIntervalUnion::Query &Q = Matrix->query(VirtReg, Unit);
2071fd87a68SDimitry Andric // If there is 10 or more interferences, chances are one is heavier.
20881ad6265SDimitry Andric const auto &Interferences = Q.interferingVRegs(EvictInterferenceCutoff);
20981ad6265SDimitry Andric if (Interferences.size() >= EvictInterferenceCutoff)
2101fd87a68SDimitry Andric return false;
2111fd87a68SDimitry Andric
2121fd87a68SDimitry Andric // Check if any interfering live range is heavier than MaxWeight.
21381ad6265SDimitry Andric for (const LiveInterval *Intf : reverse(Interferences)) {
214bdd1243dSDimitry Andric assert(Intf->reg().isVirtual() &&
2151fd87a68SDimitry Andric "Only expecting virtual register interference from query");
2161fd87a68SDimitry Andric
2171fd87a68SDimitry Andric // Do not allow eviction of a virtual register if we are in the middle
2181fd87a68SDimitry Andric // of last-chance recoloring and this virtual register is one that we
2191fd87a68SDimitry Andric // have scavenged a physical register for.
2201fd87a68SDimitry Andric if (FixedRegisters.count(Intf->reg()))
2211fd87a68SDimitry Andric return false;
2221fd87a68SDimitry Andric
2231fd87a68SDimitry Andric // Never evict spill products. They cannot split or spill.
2241fd87a68SDimitry Andric if (RA.getExtraInfo().getStage(*Intf) == RS_Done)
2251fd87a68SDimitry Andric return false;
2261fd87a68SDimitry Andric // Once a live range becomes small enough, it is urgent that we find a
2271fd87a68SDimitry Andric // register for it. This is indicated by an infinite spill weight. These
2281fd87a68SDimitry Andric // urgent live ranges get to evict almost anything.
2291fd87a68SDimitry Andric //
2301fd87a68SDimitry Andric // Also allow urgent evictions of unspillable ranges from a strictly
2311fd87a68SDimitry Andric // larger allocation order.
2321fd87a68SDimitry Andric bool Urgent =
2331fd87a68SDimitry Andric !VirtReg.isSpillable() &&
2341fd87a68SDimitry Andric (Intf->isSpillable() ||
2351fd87a68SDimitry Andric RegClassInfo.getNumAllocatableRegs(MRI->getRegClass(VirtReg.reg())) <
2361fd87a68SDimitry Andric RegClassInfo.getNumAllocatableRegs(
2371fd87a68SDimitry Andric MRI->getRegClass(Intf->reg())));
2381fd87a68SDimitry Andric // Only evict older cascades or live ranges without a cascade.
2391fd87a68SDimitry Andric unsigned IntfCascade = RA.getExtraInfo().getCascade(Intf->reg());
24081ad6265SDimitry Andric if (Cascade == IntfCascade)
24181ad6265SDimitry Andric return false;
24281ad6265SDimitry Andric
24381ad6265SDimitry Andric if (Cascade < IntfCascade) {
2441fd87a68SDimitry Andric if (!Urgent)
2451fd87a68SDimitry Andric return false;
2461fd87a68SDimitry Andric // We permit breaking cascades for urgent evictions. It should be the
2471fd87a68SDimitry Andric // last resort, though, so make it really expensive.
2481fd87a68SDimitry Andric Cost.BrokenHints += 10;
2491fd87a68SDimitry Andric }
2501fd87a68SDimitry Andric // Would this break a satisfied hint?
2511fd87a68SDimitry Andric bool BreaksHint = VRM->hasPreferredPhys(Intf->reg());
2521fd87a68SDimitry Andric // Update eviction cost.
2531fd87a68SDimitry Andric Cost.BrokenHints += BreaksHint;
2541fd87a68SDimitry Andric Cost.MaxWeight = std::max(Cost.MaxWeight, Intf->weight());
2551fd87a68SDimitry Andric // Abort if this would be too expensive.
2561fd87a68SDimitry Andric if (!(Cost < MaxCost))
2571fd87a68SDimitry Andric return false;
2581fd87a68SDimitry Andric if (Urgent)
2591fd87a68SDimitry Andric continue;
2601fd87a68SDimitry Andric // Apply the eviction policy for non-urgent evictions.
2611fd87a68SDimitry Andric if (!shouldEvict(VirtReg, IsHint, *Intf, BreaksHint))
2621fd87a68SDimitry Andric return false;
2631fd87a68SDimitry Andric // If !MaxCost.isMax(), then we're just looking for a cheap register.
2641fd87a68SDimitry Andric // Evicting another local live range in this case could lead to suboptimal
2651fd87a68SDimitry Andric // coloring.
2661fd87a68SDimitry Andric if (!MaxCost.isMax() && IsLocal && LIS->intervalIsInOneMBB(*Intf) &&
2671fd87a68SDimitry Andric (!EnableLocalReassign || !canReassign(*Intf, PhysReg))) {
2681fd87a68SDimitry Andric return false;
2691fd87a68SDimitry Andric }
2701fd87a68SDimitry Andric }
2711fd87a68SDimitry Andric }
2721fd87a68SDimitry Andric MaxCost = Cost;
2731fd87a68SDimitry Andric return true;
2741fd87a68SDimitry Andric }
2751fd87a68SDimitry Andric
tryFindEvictionCandidate(const LiveInterval & VirtReg,const AllocationOrder & Order,uint8_t CostPerUseLimit,const SmallVirtRegSet & FixedRegisters) const2761fd87a68SDimitry Andric MCRegister DefaultEvictionAdvisor::tryFindEvictionCandidate(
27781ad6265SDimitry Andric const LiveInterval &VirtReg, const AllocationOrder &Order,
2781fd87a68SDimitry Andric uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) const {
2791fd87a68SDimitry Andric // Keep track of the cheapest interference seen so far.
2801fd87a68SDimitry Andric EvictionCost BestCost;
2811fd87a68SDimitry Andric BestCost.setMax();
2821fd87a68SDimitry Andric MCRegister BestPhys;
2831fd87a68SDimitry Andric auto MaybeOrderLimit = getOrderLimit(VirtReg, Order, CostPerUseLimit);
2841fd87a68SDimitry Andric if (!MaybeOrderLimit)
2851fd87a68SDimitry Andric return MCRegister::NoRegister;
2861fd87a68SDimitry Andric unsigned OrderLimit = *MaybeOrderLimit;
2871fd87a68SDimitry Andric
2881fd87a68SDimitry Andric // When we are just looking for a reduced cost per use, don't break any
2891fd87a68SDimitry Andric // hints, and only evict smaller spill weights.
2901fd87a68SDimitry Andric if (CostPerUseLimit < uint8_t(~0u)) {
2911fd87a68SDimitry Andric BestCost.BrokenHints = 0;
2921fd87a68SDimitry Andric BestCost.MaxWeight = VirtReg.weight();
2931fd87a68SDimitry Andric }
2941fd87a68SDimitry Andric
2951fd87a68SDimitry Andric for (auto I = Order.begin(), E = Order.getOrderLimitEnd(OrderLimit); I != E;
2961fd87a68SDimitry Andric ++I) {
2971fd87a68SDimitry Andric MCRegister PhysReg = *I;
2981fd87a68SDimitry Andric assert(PhysReg);
2991fd87a68SDimitry Andric if (!canAllocatePhysReg(CostPerUseLimit, PhysReg) ||
3001fd87a68SDimitry Andric !canEvictInterferenceBasedOnCost(VirtReg, PhysReg, false, BestCost,
3011fd87a68SDimitry Andric FixedRegisters))
3021fd87a68SDimitry Andric continue;
3031fd87a68SDimitry Andric
3041fd87a68SDimitry Andric // Best so far.
3051fd87a68SDimitry Andric BestPhys = PhysReg;
3061fd87a68SDimitry Andric
3071fd87a68SDimitry Andric // Stop if the hint can be used.
3081fd87a68SDimitry Andric if (I.isHint())
3091fd87a68SDimitry Andric break;
3101fd87a68SDimitry Andric }
3111fd87a68SDimitry Andric return BestPhys;
3121fd87a68SDimitry Andric }
313