xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/RegAllocEvictionAdvisor.cpp (revision 1fd87a682ad7442327078e1eeb63edc4258f9815)
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"
1404eeddc0SDimitry Andric #include "RegAllocGreedy.h"
150eae32dcSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
160eae32dcSDimitry Andric #include "llvm/CodeGen/RegisterClassInfo.h"
170eae32dcSDimitry Andric #include "llvm/CodeGen/VirtRegMap.h"
180eae32dcSDimitry Andric #include "llvm/InitializePasses.h"
190eae32dcSDimitry Andric #include "llvm/Pass.h"
200eae32dcSDimitry Andric #include "llvm/PassRegistry.h"
210eae32dcSDimitry Andric #include "llvm/Support/CommandLine.h"
220eae32dcSDimitry Andric #include "llvm/Support/ErrorHandling.h"
230eae32dcSDimitry Andric #include "llvm/Target/TargetMachine.h"
240eae32dcSDimitry Andric 
250eae32dcSDimitry Andric using namespace llvm;
260eae32dcSDimitry Andric 
270eae32dcSDimitry Andric static cl::opt<RegAllocEvictionAdvisorAnalysis::AdvisorMode> Mode(
28*1fd87a68SDimitry Andric     "regalloc-enable-advisor", cl::Hidden, cl::ZeroOrMore,
290eae32dcSDimitry Andric     cl::init(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Default),
300eae32dcSDimitry Andric     cl::desc("Enable regalloc advisor mode"),
310eae32dcSDimitry Andric     cl::values(
320eae32dcSDimitry Andric         clEnumValN(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Default,
330eae32dcSDimitry Andric                    "default", "Default"),
340eae32dcSDimitry Andric         clEnumValN(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Release,
350eae32dcSDimitry Andric                    "release", "precompiled"),
360eae32dcSDimitry Andric         clEnumValN(RegAllocEvictionAdvisorAnalysis::AdvisorMode::Development,
370eae32dcSDimitry Andric                    "development", "for training")));
380eae32dcSDimitry Andric 
390eae32dcSDimitry Andric static cl::opt<bool> EnableLocalReassignment(
400eae32dcSDimitry Andric     "enable-local-reassign", cl::Hidden,
410eae32dcSDimitry Andric     cl::desc("Local reassignment can yield better allocation decisions, but "
420eae32dcSDimitry Andric              "may be compile time intensive"),
430eae32dcSDimitry Andric     cl::init(false));
440eae32dcSDimitry Andric 
450eae32dcSDimitry Andric #define DEBUG_TYPE "regalloc"
4604eeddc0SDimitry Andric #ifdef LLVM_HAVE_TF_AOT_REGALLOCEVICTMODEL
4704eeddc0SDimitry Andric #define LLVM_HAVE_TF_AOT
4804eeddc0SDimitry Andric #endif
490eae32dcSDimitry Andric 
500eae32dcSDimitry Andric char RegAllocEvictionAdvisorAnalysis::ID = 0;
510eae32dcSDimitry Andric INITIALIZE_PASS(RegAllocEvictionAdvisorAnalysis, "regalloc-evict",
520eae32dcSDimitry Andric                 "Regalloc eviction policy", false, true)
530eae32dcSDimitry Andric 
540eae32dcSDimitry Andric namespace {
550eae32dcSDimitry Andric class DefaultEvictionAdvisorAnalysis final
560eae32dcSDimitry Andric     : public RegAllocEvictionAdvisorAnalysis {
570eae32dcSDimitry Andric public:
580eae32dcSDimitry Andric   DefaultEvictionAdvisorAnalysis(bool NotAsRequested)
590eae32dcSDimitry Andric       : RegAllocEvictionAdvisorAnalysis(AdvisorMode::Default),
600eae32dcSDimitry Andric         NotAsRequested(NotAsRequested) {}
610eae32dcSDimitry Andric 
620eae32dcSDimitry Andric   // support for isa<> and dyn_cast.
630eae32dcSDimitry Andric   static bool classof(const RegAllocEvictionAdvisorAnalysis *R) {
640eae32dcSDimitry Andric     return R->getAdvisorMode() == AdvisorMode::Default;
650eae32dcSDimitry Andric   }
660eae32dcSDimitry Andric 
670eae32dcSDimitry Andric private:
680eae32dcSDimitry Andric   std::unique_ptr<RegAllocEvictionAdvisor>
69*1fd87a68SDimitry Andric   getAdvisor(MachineFunction &MF, const RAGreedy &RA) override {
7004eeddc0SDimitry Andric     return std::make_unique<DefaultEvictionAdvisor>(MF, RA);
710eae32dcSDimitry Andric   }
720eae32dcSDimitry Andric   bool doInitialization(Module &M) override {
730eae32dcSDimitry Andric     if (NotAsRequested)
740eae32dcSDimitry Andric       M.getContext().emitError("Requested regalloc eviction advisor analysis "
750eae32dcSDimitry Andric                                "could be created. Using default");
760eae32dcSDimitry Andric     return RegAllocEvictionAdvisorAnalysis::doInitialization(M);
770eae32dcSDimitry Andric   }
780eae32dcSDimitry Andric   const bool NotAsRequested;
790eae32dcSDimitry Andric };
800eae32dcSDimitry Andric } // namespace
810eae32dcSDimitry Andric 
820eae32dcSDimitry Andric template <> Pass *llvm::callDefaultCtor<RegAllocEvictionAdvisorAnalysis>() {
830eae32dcSDimitry Andric   Pass *Ret = nullptr;
840eae32dcSDimitry Andric   switch (Mode) {
850eae32dcSDimitry Andric   case RegAllocEvictionAdvisorAnalysis::AdvisorMode::Default:
860eae32dcSDimitry Andric     Ret = new DefaultEvictionAdvisorAnalysis(/*NotAsRequested*/ false);
870eae32dcSDimitry Andric     break;
880eae32dcSDimitry Andric   case RegAllocEvictionAdvisorAnalysis::AdvisorMode::Development:
8904eeddc0SDimitry Andric #if defined(LLVM_HAVE_TF_API)
9004eeddc0SDimitry Andric     Ret = createDevelopmentModeAdvisor();
9104eeddc0SDimitry Andric #endif
920eae32dcSDimitry Andric     break;
930eae32dcSDimitry Andric   case RegAllocEvictionAdvisorAnalysis::AdvisorMode::Release:
9404eeddc0SDimitry Andric #if defined(LLVM_HAVE_TF_AOT)
9504eeddc0SDimitry Andric     Ret = createReleaseModeAdvisor();
9604eeddc0SDimitry Andric #endif
970eae32dcSDimitry Andric     break;
980eae32dcSDimitry Andric   }
990eae32dcSDimitry Andric   if (Ret)
1000eae32dcSDimitry Andric     return Ret;
1010eae32dcSDimitry Andric   return new DefaultEvictionAdvisorAnalysis(/*NotAsRequested*/ true);
1020eae32dcSDimitry Andric }
1030eae32dcSDimitry Andric 
1040eae32dcSDimitry Andric StringRef RegAllocEvictionAdvisorAnalysis::getPassName() const {
1050eae32dcSDimitry Andric   switch (getAdvisorMode()) {
1060eae32dcSDimitry Andric   case AdvisorMode::Default:
1070eae32dcSDimitry Andric     return "Default Regalloc Eviction Advisor";
1080eae32dcSDimitry Andric   case AdvisorMode::Release:
1090eae32dcSDimitry Andric     return "Release mode Regalloc Eviction Advisor";
1100eae32dcSDimitry Andric   case AdvisorMode::Development:
1110eae32dcSDimitry Andric     return "Development mode Regalloc Eviction Advisor";
1120eae32dcSDimitry Andric   }
1130eae32dcSDimitry Andric   llvm_unreachable("Unknown advisor kind");
1140eae32dcSDimitry Andric }
1150eae32dcSDimitry Andric 
116*1fd87a68SDimitry Andric RegAllocEvictionAdvisor::RegAllocEvictionAdvisor(MachineFunction &MF,
11704eeddc0SDimitry Andric                                                  const RAGreedy &RA)
11804eeddc0SDimitry Andric     : MF(MF), RA(RA), Matrix(RA.getInterferenceMatrix()),
11904eeddc0SDimitry Andric       LIS(RA.getLiveIntervals()), VRM(RA.getVirtRegMap()),
12004eeddc0SDimitry Andric       MRI(&VRM->getRegInfo()), TRI(MF.getSubtarget().getRegisterInfo()),
12104eeddc0SDimitry Andric       RegClassInfo(RA.getRegClassInfo()), RegCosts(TRI->getRegisterCosts(MF)),
1220eae32dcSDimitry Andric       EnableLocalReassign(EnableLocalReassignment ||
1230eae32dcSDimitry Andric                           MF.getSubtarget().enableRALocalReassignment(
1240eae32dcSDimitry Andric                               MF.getTarget().getOptLevel())) {}
125*1fd87a68SDimitry Andric 
126*1fd87a68SDimitry Andric /// shouldEvict - determine if A should evict the assigned live range B. The
127*1fd87a68SDimitry Andric /// eviction policy defined by this function together with the allocation order
128*1fd87a68SDimitry Andric /// defined by enqueue() decides which registers ultimately end up being split
129*1fd87a68SDimitry Andric /// and spilled.
130*1fd87a68SDimitry Andric ///
131*1fd87a68SDimitry Andric /// Cascade numbers are used to prevent infinite loops if this function is a
132*1fd87a68SDimitry Andric /// cyclic relation.
133*1fd87a68SDimitry Andric ///
134*1fd87a68SDimitry Andric /// @param A          The live range to be assigned.
135*1fd87a68SDimitry Andric /// @param IsHint     True when A is about to be assigned to its preferred
136*1fd87a68SDimitry Andric ///                   register.
137*1fd87a68SDimitry Andric /// @param B          The live range to be evicted.
138*1fd87a68SDimitry Andric /// @param BreaksHint True when B is already assigned to its preferred register.
139*1fd87a68SDimitry Andric bool DefaultEvictionAdvisor::shouldEvict(LiveInterval &A, bool IsHint,
140*1fd87a68SDimitry Andric                                          LiveInterval &B,
141*1fd87a68SDimitry Andric                                          bool BreaksHint) const {
142*1fd87a68SDimitry Andric   bool CanSplit = RA.getExtraInfo().getStage(B) < RS_Spill;
143*1fd87a68SDimitry Andric 
144*1fd87a68SDimitry Andric   // Be fairly aggressive about following hints as long as the evictee can be
145*1fd87a68SDimitry Andric   // split.
146*1fd87a68SDimitry Andric   if (CanSplit && IsHint && !BreaksHint)
147*1fd87a68SDimitry Andric     return true;
148*1fd87a68SDimitry Andric 
149*1fd87a68SDimitry Andric   if (A.weight() > B.weight()) {
150*1fd87a68SDimitry Andric     LLVM_DEBUG(dbgs() << "should evict: " << B << " w= " << B.weight() << '\n');
151*1fd87a68SDimitry Andric     return true;
152*1fd87a68SDimitry Andric   }
153*1fd87a68SDimitry Andric   return false;
154*1fd87a68SDimitry Andric }
155*1fd87a68SDimitry Andric 
156*1fd87a68SDimitry Andric /// canEvictHintInterference - return true if the interference for VirtReg
157*1fd87a68SDimitry Andric /// on the PhysReg, which is VirtReg's hint, can be evicted in favor of VirtReg.
158*1fd87a68SDimitry Andric bool DefaultEvictionAdvisor::canEvictHintInterference(
159*1fd87a68SDimitry Andric     LiveInterval &VirtReg, MCRegister PhysReg,
160*1fd87a68SDimitry Andric     const SmallVirtRegSet &FixedRegisters) const {
161*1fd87a68SDimitry Andric   EvictionCost MaxCost;
162*1fd87a68SDimitry Andric   MaxCost.setBrokenHints(1);
163*1fd87a68SDimitry Andric   return canEvictInterferenceBasedOnCost(VirtReg, PhysReg, true, MaxCost,
164*1fd87a68SDimitry Andric                                          FixedRegisters);
165*1fd87a68SDimitry Andric }
166*1fd87a68SDimitry Andric 
167*1fd87a68SDimitry Andric /// canEvictInterferenceBasedOnCost - Return true if all interferences between
168*1fd87a68SDimitry Andric /// VirtReg and PhysReg can be evicted.
169*1fd87a68SDimitry Andric ///
170*1fd87a68SDimitry Andric /// @param VirtReg Live range that is about to be assigned.
171*1fd87a68SDimitry Andric /// @param PhysReg Desired register for assignment.
172*1fd87a68SDimitry Andric /// @param IsHint  True when PhysReg is VirtReg's preferred register.
173*1fd87a68SDimitry Andric /// @param MaxCost Only look for cheaper candidates and update with new cost
174*1fd87a68SDimitry Andric ///                when returning true.
175*1fd87a68SDimitry Andric /// @returns True when interference can be evicted cheaper than MaxCost.
176*1fd87a68SDimitry Andric bool DefaultEvictionAdvisor::canEvictInterferenceBasedOnCost(
177*1fd87a68SDimitry Andric     LiveInterval &VirtReg, MCRegister PhysReg, bool IsHint,
178*1fd87a68SDimitry Andric     EvictionCost &MaxCost, const SmallVirtRegSet &FixedRegisters) const {
179*1fd87a68SDimitry Andric   // It is only possible to evict virtual register interference.
180*1fd87a68SDimitry Andric   if (Matrix->checkInterference(VirtReg, PhysReg) > LiveRegMatrix::IK_VirtReg)
181*1fd87a68SDimitry Andric     return false;
182*1fd87a68SDimitry Andric 
183*1fd87a68SDimitry Andric   bool IsLocal = VirtReg.empty() || LIS->intervalIsInOneMBB(VirtReg);
184*1fd87a68SDimitry Andric 
185*1fd87a68SDimitry Andric   // Find VirtReg's cascade number. This will be unassigned if VirtReg was never
186*1fd87a68SDimitry Andric   // involved in an eviction before. If a cascade number was assigned, deny
187*1fd87a68SDimitry Andric   // evicting anything with the same or a newer cascade number. This prevents
188*1fd87a68SDimitry Andric   // infinite eviction loops.
189*1fd87a68SDimitry Andric   //
190*1fd87a68SDimitry Andric   // This works out so a register without a cascade number is allowed to evict
191*1fd87a68SDimitry Andric   // anything, and it can be evicted by anything.
192*1fd87a68SDimitry Andric   unsigned Cascade = RA.getExtraInfo().getCascadeOrCurrentNext(VirtReg.reg());
193*1fd87a68SDimitry Andric 
194*1fd87a68SDimitry Andric   EvictionCost Cost;
195*1fd87a68SDimitry Andric   for (MCRegUnitIterator Units(PhysReg, TRI); Units.isValid(); ++Units) {
196*1fd87a68SDimitry Andric     LiveIntervalUnion::Query &Q = Matrix->query(VirtReg, *Units);
197*1fd87a68SDimitry Andric     // If there is 10 or more interferences, chances are one is heavier.
198*1fd87a68SDimitry Andric     const auto &Interferences = Q.interferingVRegs(10);
199*1fd87a68SDimitry Andric     if (Interferences.size() >= 10)
200*1fd87a68SDimitry Andric       return false;
201*1fd87a68SDimitry Andric 
202*1fd87a68SDimitry Andric     // Check if any interfering live range is heavier than MaxWeight.
203*1fd87a68SDimitry Andric     for (LiveInterval *Intf : reverse(Interferences)) {
204*1fd87a68SDimitry Andric       assert(Register::isVirtualRegister(Intf->reg()) &&
205*1fd87a68SDimitry Andric              "Only expecting virtual register interference from query");
206*1fd87a68SDimitry Andric 
207*1fd87a68SDimitry Andric       // Do not allow eviction of a virtual register if we are in the middle
208*1fd87a68SDimitry Andric       // of last-chance recoloring and this virtual register is one that we
209*1fd87a68SDimitry Andric       // have scavenged a physical register for.
210*1fd87a68SDimitry Andric       if (FixedRegisters.count(Intf->reg()))
211*1fd87a68SDimitry Andric         return false;
212*1fd87a68SDimitry Andric 
213*1fd87a68SDimitry Andric       // Never evict spill products. They cannot split or spill.
214*1fd87a68SDimitry Andric       if (RA.getExtraInfo().getStage(*Intf) == RS_Done)
215*1fd87a68SDimitry Andric         return false;
216*1fd87a68SDimitry Andric       // Once a live range becomes small enough, it is urgent that we find a
217*1fd87a68SDimitry Andric       // register for it. This is indicated by an infinite spill weight. These
218*1fd87a68SDimitry Andric       // urgent live ranges get to evict almost anything.
219*1fd87a68SDimitry Andric       //
220*1fd87a68SDimitry Andric       // Also allow urgent evictions of unspillable ranges from a strictly
221*1fd87a68SDimitry Andric       // larger allocation order.
222*1fd87a68SDimitry Andric       bool Urgent =
223*1fd87a68SDimitry Andric           !VirtReg.isSpillable() &&
224*1fd87a68SDimitry Andric           (Intf->isSpillable() ||
225*1fd87a68SDimitry Andric            RegClassInfo.getNumAllocatableRegs(MRI->getRegClass(VirtReg.reg())) <
226*1fd87a68SDimitry Andric                RegClassInfo.getNumAllocatableRegs(
227*1fd87a68SDimitry Andric                    MRI->getRegClass(Intf->reg())));
228*1fd87a68SDimitry Andric       // Only evict older cascades or live ranges without a cascade.
229*1fd87a68SDimitry Andric       unsigned IntfCascade = RA.getExtraInfo().getCascade(Intf->reg());
230*1fd87a68SDimitry Andric       if (Cascade <= IntfCascade) {
231*1fd87a68SDimitry Andric         if (!Urgent)
232*1fd87a68SDimitry Andric           return false;
233*1fd87a68SDimitry Andric         // We permit breaking cascades for urgent evictions. It should be the
234*1fd87a68SDimitry Andric         // last resort, though, so make it really expensive.
235*1fd87a68SDimitry Andric         Cost.BrokenHints += 10;
236*1fd87a68SDimitry Andric       }
237*1fd87a68SDimitry Andric       // Would this break a satisfied hint?
238*1fd87a68SDimitry Andric       bool BreaksHint = VRM->hasPreferredPhys(Intf->reg());
239*1fd87a68SDimitry Andric       // Update eviction cost.
240*1fd87a68SDimitry Andric       Cost.BrokenHints += BreaksHint;
241*1fd87a68SDimitry Andric       Cost.MaxWeight = std::max(Cost.MaxWeight, Intf->weight());
242*1fd87a68SDimitry Andric       // Abort if this would be too expensive.
243*1fd87a68SDimitry Andric       if (!(Cost < MaxCost))
244*1fd87a68SDimitry Andric         return false;
245*1fd87a68SDimitry Andric       if (Urgent)
246*1fd87a68SDimitry Andric         continue;
247*1fd87a68SDimitry Andric       // Apply the eviction policy for non-urgent evictions.
248*1fd87a68SDimitry Andric       if (!shouldEvict(VirtReg, IsHint, *Intf, BreaksHint))
249*1fd87a68SDimitry Andric         return false;
250*1fd87a68SDimitry Andric       // If !MaxCost.isMax(), then we're just looking for a cheap register.
251*1fd87a68SDimitry Andric       // Evicting another local live range in this case could lead to suboptimal
252*1fd87a68SDimitry Andric       // coloring.
253*1fd87a68SDimitry Andric       if (!MaxCost.isMax() && IsLocal && LIS->intervalIsInOneMBB(*Intf) &&
254*1fd87a68SDimitry Andric           (!EnableLocalReassign || !canReassign(*Intf, PhysReg))) {
255*1fd87a68SDimitry Andric         return false;
256*1fd87a68SDimitry Andric       }
257*1fd87a68SDimitry Andric     }
258*1fd87a68SDimitry Andric   }
259*1fd87a68SDimitry Andric   MaxCost = Cost;
260*1fd87a68SDimitry Andric   return true;
261*1fd87a68SDimitry Andric }
262*1fd87a68SDimitry Andric 
263*1fd87a68SDimitry Andric MCRegister DefaultEvictionAdvisor::tryFindEvictionCandidate(
264*1fd87a68SDimitry Andric     LiveInterval &VirtReg, const AllocationOrder &Order,
265*1fd87a68SDimitry Andric     uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) const {
266*1fd87a68SDimitry Andric   // Keep track of the cheapest interference seen so far.
267*1fd87a68SDimitry Andric   EvictionCost BestCost;
268*1fd87a68SDimitry Andric   BestCost.setMax();
269*1fd87a68SDimitry Andric   MCRegister BestPhys;
270*1fd87a68SDimitry Andric   auto MaybeOrderLimit = getOrderLimit(VirtReg, Order, CostPerUseLimit);
271*1fd87a68SDimitry Andric   if (!MaybeOrderLimit)
272*1fd87a68SDimitry Andric     return MCRegister::NoRegister;
273*1fd87a68SDimitry Andric   unsigned OrderLimit = *MaybeOrderLimit;
274*1fd87a68SDimitry Andric 
275*1fd87a68SDimitry Andric   // When we are just looking for a reduced cost per use, don't break any
276*1fd87a68SDimitry Andric   // hints, and only evict smaller spill weights.
277*1fd87a68SDimitry Andric   if (CostPerUseLimit < uint8_t(~0u)) {
278*1fd87a68SDimitry Andric     BestCost.BrokenHints = 0;
279*1fd87a68SDimitry Andric     BestCost.MaxWeight = VirtReg.weight();
280*1fd87a68SDimitry Andric   }
281*1fd87a68SDimitry Andric 
282*1fd87a68SDimitry Andric   for (auto I = Order.begin(), E = Order.getOrderLimitEnd(OrderLimit); I != E;
283*1fd87a68SDimitry Andric        ++I) {
284*1fd87a68SDimitry Andric     MCRegister PhysReg = *I;
285*1fd87a68SDimitry Andric     assert(PhysReg);
286*1fd87a68SDimitry Andric     if (!canAllocatePhysReg(CostPerUseLimit, PhysReg) ||
287*1fd87a68SDimitry Andric         !canEvictInterferenceBasedOnCost(VirtReg, PhysReg, false, BestCost,
288*1fd87a68SDimitry Andric                                          FixedRegisters))
289*1fd87a68SDimitry Andric       continue;
290*1fd87a68SDimitry Andric 
291*1fd87a68SDimitry Andric     // Best so far.
292*1fd87a68SDimitry Andric     BestPhys = PhysReg;
293*1fd87a68SDimitry Andric 
294*1fd87a68SDimitry Andric     // Stop if the hint can be used.
295*1fd87a68SDimitry Andric     if (I.isHint())
296*1fd87a68SDimitry Andric       break;
297*1fd87a68SDimitry Andric   }
298*1fd87a68SDimitry Andric   return BestPhys;
299*1fd87a68SDimitry Andric }
300