LLVM 22.0.0git
MLRegAllocEvictAdvisor.cpp
Go to the documentation of this file.
1//===- MLRegAllocEvictAdvisor.cpp - ML eviction advisor -------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Implementation of the ML eviction advisor and reward injection pass
10//
11//===----------------------------------------------------------------------===//
12
13#include "AllocationOrder.h"
14#include "RegAllocGreedy.h"
19#if defined(LLVM_HAVE_TF_AOT_REGALLOCEVICTMODEL) || defined(LLVM_HAVE_TFLITE)
23#endif
32#include "llvm/CodeGen/Passes.h"
35#include "llvm/IR/Module.h"
37#include "llvm/Pass.h"
38#include "llvm/PassRegistry.h"
41
42#include <array>
43#include <bitset>
44#include <memory>
45#include <unordered_map>
46
47using namespace llvm;
48
49#define DEBUG_TYPE "ml-regalloc"
50
51// Generated header in release (AOT) mode
52#if defined(LLVM_HAVE_TF_AOT_REGALLOCEVICTMODEL)
53#include "RegAllocEvictModel.h"
54using CompiledModelType = RegAllocEvictModel;
55#else
57#endif
58
60 "regalloc-evict-interactive-channel-base", cl::Hidden,
62 "Base file path for the interactive mode. The incoming filename should "
63 "have the name <regalloc-evict-interactive-channel-base>.in, while the "
64 "outgoing name should be "
65 "<regalloc-evict-interactive-channel-base>.out"));
66
68 "mlregalloc-max-eviction-count", cl::Hidden,
69 cl::desc("The maximum number of times a live range can be "
70 "evicted before preventing it from being evicted"),
71 cl::init(100));
72
73// Options that only make sense in development mode
74#ifdef LLVM_HAVE_TFLITE
75#include "RegAllocScore.h"
77
78static cl::opt<std::string> TrainingLog(
79 "regalloc-training-log", cl::Hidden,
80 cl::desc("Training log for the register allocator eviction model"));
81
82static cl::opt<std::string> ModelUnderTraining(
83 "regalloc-model", cl::Hidden,
84 cl::desc("The model being trained for register allocation eviction"));
85
87 "regalloc-enable-development-features", cl::Hidden,
88 cl::desc("Whether or not to enable features under development for the ML "
89 "regalloc advisor"));
90
91#else
92static const bool EnableDevelopmentFeatures = false;
93#endif // #ifdef LLVM_HAVE_TFLITE
94
95/// The score injection pass.
96/// This pass calculates the score for a function and inserts it in the log, but
97/// this happens only in development mode. It's a no-op otherwise.
98namespace llvm {
100} // namespace llvm
101
102namespace {
103class RegAllocScoring : public MachineFunctionPass {
104public:
105 static char ID;
106
107 RegAllocScoring() : MachineFunctionPass(ID) {
109 }
110
111 ~RegAllocScoring() override = default;
112
113 StringRef getPassName() const override {
114 return "Register Allocation Pass Scoring";
115 }
116
117 /// RegAllocReward analysis usage.
118 void getAnalysisUsage(AnalysisUsage &AU) const override {
119 AU.setPreservesAll();
120 AU.addRequired<RegAllocEvictionAdvisorAnalysisLegacy>();
121 AU.addRequired<RegAllocPriorityAdvisorAnalysisLegacy>();
122 AU.addRequired<MachineBlockFrequencyInfoWrapperPass>();
124 }
125
126 /// Performs this pass
127 bool runOnMachineFunction(MachineFunction &) override;
128};
129} // namespace
130
131char RegAllocScoring::ID = 0;
133 return new RegAllocScoring();
134}
135
136INITIALIZE_PASS(RegAllocScoring, "regallocscoringpass",
137 "Register Allocation Scoring Pass", false, false)
138
139// ===================================
140// Common ML Advisor declarations
141// ===================================
142namespace {
143// The model can only accept a specified number of opcodes and will error it if
144// fed an opcode it hasn't seen before. This constant sets the current cutoff.
145static const int OpcodeValueCutoff = 17716;
146
147// Most features are as described above, so we'll reuse this vector in defining
148// them.
149static const std::vector<int64_t> PerLiveRangeShape{1, NumberOfInterferences};
150
151// --------------
152// Features table
153// --------------
154// For each interfering live range (incl. the candidate) we collect a number of
155// features. However, because the features are of different types (and because
156// of ML best practices), we organize the tensors per feature, not per
157// candidate. Each such tensor has a scalar value corresponding to the
158// interferring live range at that position, in the order in AllocationOrder.
159// The last position corresponds to the virt reg seeking allocation.
160// Exception to all that is the progression feature, which is just a scalar (see
161// its documentation for details).
162// Note on naming: the "_by_max" are normalized using the largest value of that
163// tensor, as observed in the current decision making stage (i.e. for the
164// current call to the advisor's tryFindEvictionCandidate)
165//
166// The feature list format: type, name, shape, documentation.
167// Note: we can really just use int64 and float, hence the modeling of some
168// bools as int64 values.
169#define RA_EVICT_FEATURES_LIST(M) \
170 M(int64_t, mask, PerLiveRangeShape, \
171 "boolean values, 0 for unavailable candidates (i.e. if a position is 0, " \
172 "it " \
173 "can't be evicted)") \
174 M(int64_t, is_free, PerLiveRangeShape, \
175 "boolean values, 1 if this phys reg is actually free (no interferences)") \
176 M(float, nr_urgent, PerLiveRangeShape, \
177 "number of 'urgent' intervals, normalized. Urgent are those that are OK " \
178 "to break cascades") \
179 M(float, nr_broken_hints, PerLiveRangeShape, \
180 "if this position were evicted, how many broken hints would there be") \
181 M(int64_t, is_hint, PerLiveRangeShape, \
182 "is this a preferred phys reg for the candidate") \
183 M(int64_t, is_local, PerLiveRangeShape, \
184 "is this live range local to a basic block") \
185 M(float, nr_rematerializable, PerLiveRangeShape, \
186 "nr rematerializable ranges") \
187 M(float, nr_defs_and_uses, PerLiveRangeShape, \
188 "bb freq - weighed nr defs and uses") \
189 M(float, weighed_reads_by_max, PerLiveRangeShape, \
190 "bb freq - weighed nr of reads, normalized") \
191 M(float, weighed_writes_by_max, PerLiveRangeShape, \
192 "bb feq - weighed nr of writes, normalized") \
193 M(float, weighed_read_writes_by_max, PerLiveRangeShape, \
194 "bb freq - weighed nr of uses that are both read and writes, normalized") \
195 M(float, weighed_indvars_by_max, PerLiveRangeShape, \
196 "bb freq - weighed nr of uses that are indvars, normalized") \
197 M(float, hint_weights_by_max, PerLiveRangeShape, \
198 "bb freq - weighed nr of uses that are hints, normalized") \
199 M(float, start_bb_freq_by_max, PerLiveRangeShape, \
200 "the freq in the start block, normalized") \
201 M(float, end_bb_freq_by_max, PerLiveRangeShape, \
202 "freq of end block, normalized") \
203 M(float, hottest_bb_freq_by_max, PerLiveRangeShape, \
204 "hottest BB freq, normalized") \
205 M(float, liverange_size, PerLiveRangeShape, \
206 "size (instr index diff) of the LR") \
207 M(float, use_def_density, PerLiveRangeShape, \
208 "the max weight, as computed by the manual heuristic") \
209 M(int64_t, max_stage, PerLiveRangeShape, \
210 "largest stage of an interval in this LR") \
211 M(int64_t, min_stage, PerLiveRangeShape, \
212 "lowest stage of an interval in this LR") \
213 M(float, progress, {1}, "ratio of current queue size to initial size")
214
215#ifdef LLVM_HAVE_TFLITE
216#define RA_EVICT_FIRST_DEVELOPMENT_FEATURE(M) \
217 M(int64_t, instructions, InstructionsShape, \
218 "Opcodes of the instructions covered by the eviction problem")
219
220#define RA_EVICT_REST_DEVELOPMENT_FEATURES(M) \
221 M(int64_t, instructions_mapping, InstructionsMappingShape, \
222 "A binary matrix mapping LRs to instruction opcodes") \
223 M(float, mbb_frequencies, MBBFrequencyShape, \
224 "A vector of machine basic block frequencies") \
225 M(int64_t, mbb_mapping, InstructionsShape, \
226 "A vector of indices mapping instructions to MBBs")
227#else
228#define RA_EVICT_FIRST_DEVELOPMENT_FEATURE(M)
229#define RA_EVICT_REST_DEVELOPMENT_FEATURES(M)
230#endif
231
232// The model learns to pick one of the mask == 1 interferences. This is the
233// name of the output tensor. The contract with the model is that the output
234// will be guaranteed to be to a mask == 1 position. Using a macro here to
235// avoid 'not used' warnings (and keep cond compilation to a minimum)
236#define DecisionName "index_to_evict"
237static const TensorSpec DecisionSpec =
239
240// Named features index.
241enum FeatureIDs {
242#define _FEATURE_IDX_SIMPLE(_, name, __, ___) name
243#define _FEATURE_IDX(A, B, C, D) _FEATURE_IDX_SIMPLE(A, B, C, D),
245#ifdef LLVM_HAVE_TFLITE
247#else
249#endif // #ifdef LLVM_HAVE_TFLITE
250 RA_EVICT_REST_DEVELOPMENT_FEATURES(_FEATURE_IDX) FeaturesWithDevelopmentCount
251#undef _FEATURE_IDX
252#undef _FEATURE_IDX_SIMPLE
253};
254
255// The ML advisor will typically have a sparse input to the evaluator, because
256// various phys regs won't be available. It's easier (maintenance-wise) to
257// bulk-reset the state of the evaluator each time we are about to use it
258// again.
259template <typename T> size_t getTotalSize(const std::vector<int64_t> &Shape) {
260 size_t Ret = sizeof(T);
261 for (const auto V : Shape)
262 Ret *= V;
263 return Ret;
264}
265
266void resetInputs(MLModelRunner &Runner) {
267#define _RESET(TYPE, NAME, SHAPE, __) \
268 std::memset(Runner.getTensorUntyped(FeatureIDs::NAME), 0, \
269 getTotalSize<TYPE>(SHAPE));
274#undef _RESET
275 }
276}
277
278// Per-live interval components that get aggregated into the feature values
279// that will be passed to the evaluator.
280struct LIFeatureComponents {
281 double R = 0;
282 double W = 0;
283 double RW = 0;
284 double IndVarUpdates = 0;
285 double HintWeights = 0.0;
286 int64_t NumDefsAndUses = 0;
287 float HottestBlockFreq = 0.0;
288 bool IsRemat = false;
289};
290
291using CandidateRegList =
292 std::array<std::pair<MCRegister, bool>, NumberOfInterferences>;
293using FeaturesListNormalizer =
295
296/// The ML evictor (commonalities between release and development mode)
297class MLEvictAdvisor : public RegAllocEvictionAdvisor {
298public:
299 MLEvictAdvisor(const MachineFunction &MF, const RAGreedy &RA,
300 MLModelRunner *Runner, const MachineBlockFrequencyInfo &MBFI,
301 const MachineLoopInfo &Loops);
302
303protected:
304 const RegAllocEvictionAdvisor &getDefaultAdvisor() const {
305 return static_cast<const RegAllocEvictionAdvisor &>(DefaultAdvisor);
306 }
307
308 // The assumption is that if the Runner could not be constructed, we emit-ed
309 // error, and we shouldn't be asking for it here.
310 const MLModelRunner &getRunner() const { return *Runner; }
311
312 /// This just calls Evaluate on the Runner, but in the development mode
313 /// case, if we're just capturing the log of the default advisor, it needs
314 /// to call the latter instead, so we need to pass all the necessary
315 /// parameters for it. In the development case, it will also log.
316 virtual int64_t
317 tryFindEvictionCandidatePosition(const LiveInterval &VirtReg,
318 const AllocationOrder &Order,
319 unsigned OrderLimit, uint8_t CostPerUseLimit,
320 const SmallVirtRegSet &FixedRegisters) const;
321
322 /// Load the features of the given VirtReg (allocated or not) at column Pos,
323 /// but if that can't be evicted, return false instead.
324 bool
325 loadInterferenceFeatures(const LiveInterval &VirtReg, MCRegister PhysReg,
326 bool IsHint, const SmallVirtRegSet &FixedRegisters,
327 llvm::SmallVectorImpl<float> &Largest, size_t Pos,
328 SmallVectorImpl<LRStartEndInfo> &LRPosInfo) const;
329
330private:
331 static float getInitialQueueSize(const MachineFunction &MF);
332
334 const LiveInterval &VirtReg, const AllocationOrder &Order,
335 uint8_t CostPerUseLimit,
336 const SmallVirtRegSet &FixedRegisters) const override;
337
338 void extractFeatures(const SmallVectorImpl<const LiveInterval *> &Intervals,
339 llvm::SmallVectorImpl<float> &Largest, size_t Pos,
340 int64_t IsHint, int64_t LocalIntfsCount, float NumUrgent,
341 SmallVectorImpl<LRStartEndInfo> &LRPosInfo) const;
342
343 // Point-in-time: we didn't learn this, so we always delegate to the
344 // default.
346 const LiveInterval &VirtReg, MCRegister PhysReg,
347 const SmallVirtRegSet &FixedRegisters) const override {
348 return getDefaultAdvisor().canEvictHintInterference(VirtReg, PhysReg,
349 FixedRegisters);
350 }
351
352 const LIFeatureComponents &
353 getLIFeatureComponents(const LiveInterval &LI) const;
354
355 // Hold on to a default advisor for:
356 // 1) the implementation of canEvictHintInterference, because we didn't
357 // learn that nuance yet; 2) for bootstrapping (logging) in the development
358 // mode case.
359 const DefaultEvictionAdvisor DefaultAdvisor;
360 MLModelRunner *const Runner;
361 const MachineBlockFrequencyInfo &MBFI;
362 const MachineLoopInfo &Loops;
363
364 // Indices of those features we don't want to normalize.
365 // This could be static and shared, but its initialization is non-trivial.
366 std::bitset<FeatureIDs::FeatureCount> DoNotNormalize;
367 const float InitialQSize;
368
369 using RegID = unsigned;
370 mutable DenseMap<RegID, LIFeatureComponents> CachedFeatures;
371
372 mutable std::unordered_map<unsigned, unsigned> VirtRegEvictionCounts;
373
374 void onEviction(Register RegBeingEvicted) const {
375 // If we cannot find the virtual register in the map, we just assume it has
376 // not been evicted before and thus has a value of zero (which is what the
377 // subscript operator returns by default).
378 ++VirtRegEvictionCounts[RegBeingEvicted.id()];
379 }
380
381 unsigned getEvictionCount(Register Reg) const {
382 auto EvictionCountIt = VirtRegEvictionCounts.find(Reg.id());
383 if (EvictionCountIt != VirtRegEvictionCounts.end())
384 return EvictionCountIt->second;
385 return 0;
386 }
387};
388
389#define _DECL_FEATURES(type, name, shape, _) \
390 TensorSpec::createSpec<type>(#name, shape),
391
392// ===================================
393// Release (AOT) - specifics
394// ===================================
395/// Common provider for legacy and new pass managers.
396class ReleaseModeEvictionAdvisorProvider final
398public:
399 ReleaseModeEvictionAdvisorProvider(LLVMContext &Ctx)
400 : RegAllocEvictionAdvisorProvider(AdvisorMode::Release, Ctx) {
405 } else {
407 }
408 }
409 // support for isa<> and dyn_cast.
410 static bool classof(const RegAllocEvictionAdvisorProvider *R) {
411 return R->getAdvisorMode() == AdvisorMode::Release;
412 }
413
414 std::unique_ptr<RegAllocEvictionAdvisor>
415 getAdvisor(const MachineFunction &MF, const RAGreedy &RA,
417 if (!Runner) {
418 if (InteractiveChannelBaseName.empty())
419 Runner = std::make_unique<ReleaseModeModelRunner<CompiledModelType>>(
420 MF.getFunction().getContext(), InputFeatures, DecisionName);
421 else
422 Runner = std::make_unique<InteractiveModelRunner>(
426 }
427 assert(MBFI && Loops &&
428 "Invalid provider state: must have analysis available");
429 return std::make_unique<MLEvictAdvisor>(MF, RA, Runner.get(), *MBFI,
430 *Loops);
431 }
432
433private:
434 std::vector<TensorSpec> InputFeatures;
435 std::unique_ptr<MLModelRunner> Runner;
436};
437
438class ReleaseModeEvictionAdvisorAnalysisLegacy final
440public:
441 ReleaseModeEvictionAdvisorAnalysisLegacy()
442 : RegAllocEvictionAdvisorAnalysisLegacy(AdvisorMode::Release) {}
443
444 void logRewardIfNeeded(const MachineFunction &MF,
445 llvm::function_ref<float()> GetReward) override {
446 // No-op in release mode
447 }
448
449 bool doInitialization(Module &M) override {
450 Provider =
451 std::make_unique<ReleaseModeEvictionAdvisorProvider>(M.getContext());
452 return false;
453 }
454
455 static bool classof(const RegAllocEvictionAdvisorAnalysisLegacy *R) {
456 return R->getAdvisorMode() == AdvisorMode::Release;
457 }
458
459 void getAnalysisUsage(AnalysisUsage &AU) const override {
463 }
464};
465
466// ===================================
467// Development mode-specifics
468// ===================================
469//
470// Features we log
471#ifdef LLVM_HAVE_TFLITE
472static const TensorSpec Reward = TensorSpec::createSpec<float>("reward", {1});
473
474// Features we bind on the model. The tensor names have a prefix, and we also
475// need to include some tensors that are expected to be present by the
476// training algo.
477// TODO: can we just get rid of these?
478#define _DECL_TRAIN_FEATURES(type, name, shape, _) \
479 TensorSpec::createSpec<type>(std::string("action_") + #name, shape),
480
481class DevelopmentModeEvictAdvisor : public MLEvictAdvisor {
482public:
483 DevelopmentModeEvictAdvisor(const MachineFunction &MF, const RAGreedy &RA,
484 MLModelRunner *Runner,
485 const MachineBlockFrequencyInfo &MBFI,
486 const MachineLoopInfo &Loops, Logger *Log)
487 : MLEvictAdvisor(MF, RA, Runner, MBFI, Loops), Log(Log) {}
488
489private:
490 int64_t tryFindEvictionCandidatePosition(
491 const LiveInterval &VirtReg, const AllocationOrder &Order,
492 unsigned OrderLimit, uint8_t CostPerUseLimit,
493 const SmallVirtRegSet &FixedRegisters) const override;
494
495 Logger *const Log;
496};
497
498class DevelopmentModeEvictionAdvisorProvider final
500public:
501 DevelopmentModeEvictionAdvisorProvider(LLVMContext &Ctx)
502 : RegAllocEvictionAdvisorProvider(AdvisorMode::Development, Ctx) {
507 TrainingInputFeatures = {
508 RA_EVICT_FEATURES_LIST(_DECL_TRAIN_FEATURES)
509 RA_EVICT_FIRST_DEVELOPMENT_FEATURE(_DECL_TRAIN_FEATURES)
510 RA_EVICT_REST_DEVELOPMENT_FEATURES(_DECL_TRAIN_FEATURES)
511 TensorSpec::createSpec<float>("action_discount", {1}),
512 TensorSpec::createSpec<int32_t>("action_step_type", {1}),
513 TensorSpec::createSpec<float>("action_reward", {1})};
514 } else {
516 TrainingInputFeatures = {
517 RA_EVICT_FEATURES_LIST(_DECL_TRAIN_FEATURES)
518 TensorSpec::createSpec<float>("action_discount", {1}),
519 TensorSpec::createSpec<int32_t>("action_step_type", {1}),
520 TensorSpec::createSpec<float>("action_reward", {1})};
521 }
522 if (ModelUnderTraining.empty() && TrainingLog.empty()) {
523 Ctx.emitError("Regalloc development mode should be requested with at "
524 "least logging enabled and/or a training model");
525 return;
526 }
527 if (ModelUnderTraining.empty())
528 Runner = std::make_unique<NoInferenceModelRunner>(Ctx, InputFeatures);
529 else
530 Runner = ModelUnderTrainingRunner::createAndEnsureValid(
531 Ctx, ModelUnderTraining, DecisionName, TrainingInputFeatures);
532 if (!Runner) {
533 Ctx.emitError("Regalloc: could not set up the model runner");
534 return;
535 }
536 if (TrainingLog.empty())
537 return;
538 std::error_code EC;
539 auto OS = std::make_unique<raw_fd_ostream>(TrainingLog, EC);
540 if (EC) {
541 Ctx.emitError(EC.message() + ":" + TrainingLog);
542 return;
543 }
544 std::vector<TensorSpec> LFS = InputFeatures;
545 if (auto *MUTR = dyn_cast<ModelUnderTrainingRunner>(Runner.get()))
546 append_range(LFS, MUTR->extraOutputsForLoggingSpecs());
547 // We always log the output; in particular, if we're not evaluating, we
548 // don't have an output spec json file. That's why we handle the
549 // 'normal' output separately.
550 LFS.push_back(DecisionSpec);
551
552 Log = std::make_unique<Logger>(std::move(OS), LFS, Reward,
553 /*IncludeReward*/ true);
554 return;
555 }
556
557 // support for isa<> and dyn_cast.
558 static bool classof(const RegAllocEvictionAdvisorProvider *R) {
559 return R->getAdvisorMode() == AdvisorMode::Development;
560 }
561
562 void logRewardIfNeeded(const MachineFunction &MF,
563 llvm::function_ref<float()> GetReward) override {
564 if (!Log || !Log->hasAnyObservationForContext(MF.getName()))
565 return;
566 // The function pass manager would run all the function passes for a
567 // function, so we assume the last context belongs to this function. If
568 // this invariant ever changes, we can implement at that time switching
569 // contexts. At this point, it'd be an error
570 if (Log->currentContext() != MF.getName()) {
572 "The training log context shouldn't have had changed.");
573 }
574 if (Log->hasObservationInProgress())
575 Log->logReward<float>(GetReward());
576 }
577
578 std::unique_ptr<RegAllocEvictionAdvisor>
579 getAdvisor(const MachineFunction &MF, const RAGreedy &RA,
581 if (!Runner)
582 return nullptr;
583 if (Log)
584 Log->switchContext(MF.getName());
585 assert(MBFI && Loops &&
586 "Invalid provider state: must have analysis available");
587 return std::make_unique<DevelopmentModeEvictAdvisor>(
588 MF, RA, Runner.get(), *MBFI, *Loops, Log.get());
589 }
590
591private:
592 std::vector<TensorSpec> InputFeatures;
593 std::vector<TensorSpec> TrainingInputFeatures;
594
595 std::unique_ptr<MLModelRunner> Runner;
596 std::unique_ptr<Logger> Log;
597};
598
599class DevelopmentModeEvictionAdvisorAnalysisLegacy final
601public:
602 DevelopmentModeEvictionAdvisorAnalysisLegacy()
603 : RegAllocEvictionAdvisorAnalysisLegacy(AdvisorMode::Development) {}
604
605 bool doInitialization(Module &M) override {
606 Provider = std::make_unique<DevelopmentModeEvictionAdvisorProvider>(
607 M.getContext());
608 return false;
609 }
610
611 void logRewardIfNeeded(const MachineFunction &MF,
612 llvm::function_ref<float()> GetReward) override {
613 Provider->logRewardIfNeeded(MF, GetReward);
614 }
615
616 // support for isa<> and dyn_cast.
617 static bool classof(const RegAllocEvictionAdvisorAnalysisLegacy *R) {
618 return R->getAdvisorMode() == AdvisorMode::Development;
619 }
620
621 void getAnalysisUsage(AnalysisUsage &AU) const override {
625 }
626};
627
628#endif // #ifdef LLVM_HAVE_TFLITE
629} // namespace
630
631float MLEvictAdvisor::getInitialQueueSize(const MachineFunction &MF) {
632 auto &MRI = MF.getRegInfo();
633 unsigned NumUsedRegs = 0;
634 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
636 if (!MRI.reg_nodbg_empty(Reg))
637 ++NumUsedRegs;
638 }
639 return static_cast<float>(NumUsedRegs);
640}
641
642MLEvictAdvisor::MLEvictAdvisor(const MachineFunction &MF, const RAGreedy &RA,
643 MLModelRunner *Runner,
644 const MachineBlockFrequencyInfo &MBFI,
645 const MachineLoopInfo &Loops)
646 : RegAllocEvictionAdvisor(MF, RA), DefaultAdvisor(MF, RA),
647 Runner(std::move(Runner)), MBFI(MBFI), Loops(Loops),
648 InitialQSize(MLEvictAdvisor::getInitialQueueSize(MF)) {
649 assert(this->Runner);
650 Runner->switchContext(MF.getName());
651 DoNotNormalize.set(FeatureIDs::mask);
652 DoNotNormalize.set(FeatureIDs::is_free);
653 DoNotNormalize.set(FeatureIDs::is_hint);
654 DoNotNormalize.set(FeatureIDs::is_local);
655 DoNotNormalize.set(FeatureIDs::min_stage);
656 DoNotNormalize.set(FeatureIDs::max_stage);
657 DoNotNormalize.set(FeatureIDs::progress);
658}
659
660int64_t MLEvictAdvisor::tryFindEvictionCandidatePosition(
661 const LiveInterval &, const AllocationOrder &, unsigned, uint8_t,
662 const SmallVirtRegSet &) const {
663 int64_t Ret = Runner->evaluate<int64_t>();
664 assert(Ret >= 0);
666 return Ret;
667}
668
669bool MLEvictAdvisor::loadInterferenceFeatures(
670 const LiveInterval &VirtReg, MCRegister PhysReg, bool IsHint,
671 const SmallVirtRegSet &FixedRegisters,
672 llvm::SmallVectorImpl<float> &Largest, size_t Pos,
673 llvm::SmallVectorImpl<LRStartEndInfo> &LRPosInfo) const {
674 // It is only possible to evict virtual register interference.
675 if (Matrix->checkInterference(VirtReg, PhysReg) > LiveRegMatrix::IK_VirtReg) {
676 // leave unavailable
677 return false;
678 }
679
680 const bool IsLocal = LIS->intervalIsInOneMBB(VirtReg);
681 int64_t LocalIntfs = 0;
682 float NumUrgent = 0.0f;
683
684 // The cascade tracking is the same as in the default advisor
685 unsigned Cascade = RA.getExtraInfo().getCascadeOrCurrentNext(VirtReg.reg());
686
688 for (MCRegUnit Unit : TRI->regunits(PhysReg)) {
689 LiveIntervalUnion::Query &Q = Matrix->query(VirtReg, Unit);
690 // Different from the default heuristic, we don't make any assumptions
691 // about what having more than 10 results in the query may mean.
692 const auto &IFIntervals = Q.interferingVRegs(EvictInterferenceCutoff);
693 if (IFIntervals.empty() && InterferingIntervals.empty())
694 continue;
695 if (IFIntervals.size() >= EvictInterferenceCutoff)
696 return false;
697 InterferingIntervals.append(IFIntervals.begin(), IFIntervals.end());
698 for (const LiveInterval *Intf : reverse(IFIntervals)) {
699 assert(Intf->reg().isVirtual() &&
700 "Only expecting virtual register interference from query");
701 // This is the same set of legality checks as in the default case: don't
702 // try to evict fixed regs or 'done' ones. Also don't break cascades,
703 // except in the urgent case, with the same nuances used in the default
704 // heuristic.
705 // We could try sharing this between the advisors, but it may end up
706 // more complex than it is right now.
707 if (FixedRegisters.count(Intf->reg()))
708 return false;
709 if (RA.getExtraInfo().getStage(*Intf) == RS_Done)
710 return false;
711 bool Urgent =
712 !VirtReg.isSpillable() &&
713 (Intf->isSpillable() ||
714 RegClassInfo.getNumAllocatableRegs(MRI->getRegClass(VirtReg.reg())) <
715 RegClassInfo.getNumAllocatableRegs(
716 MRI->getRegClass(Intf->reg())));
717
718 unsigned IntfCascade = RA.getExtraInfo().getCascade(Intf->reg());
719 // There is a potential that the model could be adversarial and
720 // continually evict live ranges over and over again, leading to a
721 // large amount of compile time being spent in regalloc. If we hit the
722 // threshold, prevent the range from being evicted. We still let the
723 // range through if it is urgent as we are required to produce an
724 // eviction if the candidate is not spillable.
725 if (getEvictionCount(Intf->reg()) > MaxEvictionCount && !Urgent)
726 return false;
727
728 // Only evict older cascades or live ranges without a cascade.
729 if (Cascade <= IntfCascade) {
730 if (!Urgent)
731 return false;
732 ++NumUrgent;
733 }
734
735 LocalIntfs += (IsLocal && LIS->intervalIsInOneMBB(*Intf) &&
736 (!EnableLocalReassign || !canReassign(*Intf, PhysReg)));
737 }
738 }
739 // OK, so if we made it this far, this LR is an eviction candidate, load its
740 // features.
741 extractFeatures(InterferingIntervals, Largest, Pos, IsHint, LocalIntfs,
742 NumUrgent, LRPosInfo);
743 return true;
744}
745
746MCRegister MLEvictAdvisor::tryFindEvictionCandidate(
747 const LiveInterval &VirtReg, const AllocationOrder &Order,
748 uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) const {
749 auto MaybeOrderLimit = getOrderLimit(VirtReg, Order, CostPerUseLimit);
750 if (!MaybeOrderLimit)
752 unsigned OrderLimit = *MaybeOrderLimit;
753
754 // The heuristic sets initial costs such as, if CostPerUseLimit is
755 // max<uint8_t>, then any of the costs of the legally-evictable intervals
756 // would be lower. When that happens, one of those will be selected.
757 // Therefore, we allow the candidate be selected, unless the candidate is
758 // unspillable, in which case it would be incorrect to not find a register
759 // for it.
760 const bool MustFindEviction =
761 (!VirtReg.isSpillable() && CostPerUseLimit == static_cast<uint8_t>(~0u));
762 // Number of available candidates - if 0, no need to continue.
763 size_t Available = 0;
764 // Make sure we don't have leftover partial state from an attempt where we
765 // had no available candidates and bailed out early.
766 resetInputs(*Runner);
767
768 // Track the index->register mapping because AllocationOrder doesn't do that
769 // and we'd have to scan it.
770 // Also track their mask, to write asserts/debug.
771 CandidateRegList Regs;
772 Regs.fill({0, false});
773
774 // Track the largest value of features seen during this eviction session. We
775 // only normalize (some of) the float features, but it's just simpler to
776 // dimension 'Largest' to all the features, especially since we have the
777 // 'DoNotNormalize' list.
778 FeaturesListNormalizer Largest(FeatureIDs::FeatureCount, 0.0);
779
780 // Same overal idea as in the default eviction policy - we visit the values
781 // of AllocationOrder one at a time. If it's not legally available, we mask
782 // off the corresponding feature column (==do nothing because we already
783 // reset all the features to 0) Use Pos to capture the column we load
784 // features at - in AllocationOrder order.
785 size_t Pos = 0;
787 for (auto I = Order.begin(), E = Order.getOrderLimitEnd(OrderLimit); I != E;
788 ++I, ++Pos) {
789 MCRegister PhysReg = *I;
790 assert(!Regs[Pos].second);
791 assert(PhysReg);
792 if (!canAllocatePhysReg(CostPerUseLimit, PhysReg)) {
793 continue;
794 }
795 if (loadInterferenceFeatures(VirtReg, PhysReg, I.isHint(), FixedRegisters,
796 Largest, Pos, LRPosInfo)) {
797 ++Available;
798 Regs[Pos] = std::make_pair(PhysReg, true);
799 }
800 }
801 if (Available == 0) {
802 // Nothing to decide, nothing to learn.
803 assert(!MustFindEviction);
805 }
806 const size_t ValidPosLimit = Pos;
807 // If we must find eviction, the candidate should be masked out of the
808 // decision making process.
809 Regs[CandidateVirtRegPos].second = !MustFindEviction;
810 if (!MustFindEviction)
811 extractFeatures(SmallVector<const LiveInterval *, 1>(1, &VirtReg), Largest,
812 CandidateVirtRegPos, /*IsHint*/ 0,
813 /*LocalIntfsCount*/ 0,
814 /*NumUrgent*/ 0.0, LRPosInfo);
815 assert(InitialQSize > 0.0 && "We couldn't have gotten here if we had "
816 "nothing to allocate initially.");
817#ifdef LLVM_HAVE_TFLITE
820 LRPosInfo, Runner,
821 [this](SlotIndex InputIndex) -> int {
822 auto *CurrentMachineInstruction =
823 LIS->getInstructionFromIndex(InputIndex);
824 if (!CurrentMachineInstruction) {
825 return -1;
826 }
827 return CurrentMachineInstruction->getOpcode();
828 },
829 [this](SlotIndex InputIndex) -> float {
830 auto *CurrentMachineInstruction =
831 LIS->getInstructionFromIndex(InputIndex);
833 CurrentMachineInstruction->getParent());
834 },
835 [this](SlotIndex InputIndex) -> MachineBasicBlock * {
836 auto *CurrentMachineInstruction =
837 LIS->getInstructionFromIndex(InputIndex);
838 return CurrentMachineInstruction->getParent();
839 },
840 FeatureIDs::instructions, FeatureIDs::instructions_mapping,
841 FeatureIDs::mbb_frequencies, FeatureIDs::mbb_mapping,
842 LIS->getSlotIndexes()->getLastIndex());
843 }
844#endif // #ifdef LLVM_HAVE_TFLITE
845 // Normalize the features.
846 for (auto &V : Largest)
847 V = V ? V : 1.0;
849 ++FeatureIndex) {
850 if (DoNotNormalize.test(FeatureIndex))
851 continue;
852 for (size_t Pos = 0; Pos < NumberOfInterferences; ++Pos) {
853 Runner->getTensor<float>(FeatureIndex)[Pos] /= Largest[FeatureIndex];
854 }
855 }
856 *Runner->getTensor<float>(FeatureIDs::progress) =
857 static_cast<float>(RA.getQueueSize()) / InitialQSize;
858
859 // Get a decision.
860 size_t CandidatePos = tryFindEvictionCandidatePosition(
861 VirtReg, Order, OrderLimit, CostPerUseLimit, FixedRegisters);
862 // The contract with the ML side is that CandidatePos is mask == 1 (i.e.
863 // Regs[CandidatePos].second)
864 assert(Regs[CandidatePos].second);
865 if (CandidatePos == CandidateVirtRegPos) {
866 onEviction(VirtReg.reg());
867 assert(!MustFindEviction);
869 }
870 assert(CandidatePos < ValidPosLimit);
871 (void)ValidPosLimit;
872
873 // Update information about how many times the virtual registers being
874 // evicted have been evicted so that we can prevent the model from evicting
875 // the same ranges continually and eating compile time.
876 for (MCRegUnit Unit : TRI->regunits(Regs[CandidatePos].first)) {
877 LiveIntervalUnion::Query &Q = Matrix->query(VirtReg, Unit);
878 const auto &IFIntervals = Q.interferingVRegs(EvictInterferenceCutoff);
879 for (const LiveInterval *Intf : reverse(IFIntervals)) {
880 onEviction(Intf->reg());
881 }
882 }
883
884 return Regs[CandidatePos].first;
885}
886
887const LIFeatureComponents &
888MLEvictAdvisor::getLIFeatureComponents(const LiveInterval &LI) const {
889 RegID ID = LI.reg().id();
890 LIFeatureComponents Empty;
891 auto I = CachedFeatures.insert(std::make_pair(ID, Empty));
892 LIFeatureComponents &Ret = I.first->getSecond();
893 if (!I.second)
894 return Ret;
895
898
900 I = MRI->reg_instr_nodbg_begin(LI.reg()),
901 E = MRI->reg_instr_nodbg_end();
902 I != E;) {
903 MachineInstr *MI = &*(I++);
904
905 ++Ret.NumDefsAndUses;
906 if (!Visited.insert(MI).second)
907 continue;
908
909 if (MI->isIdentityCopy() || MI->isImplicitDef())
910 continue;
911
912 bool Reads, Writes;
913 std::tie(Reads, Writes) = MI->readsWritesVirtualRegister(LI.reg());
914
915 float Freq = MBFI.getBlockFreqRelativeToEntryBlock(MI->getParent());
916 Ret.HottestBlockFreq = std::max(Freq, Ret.HottestBlockFreq);
917
918 Ret.R += (Reads && !Writes) * Freq;
919 Ret.W += (!Reads && Writes) * Freq;
920 Ret.RW += (Reads && Writes) * Freq;
921
922 auto *MBB = MI->getParent();
923 auto *Loop = Loops.getLoopFor(MBB);
924 bool IsExiting = Loop ? Loop->isLoopExiting(MBB) : false;
925
926 if (Writes && IsExiting && LIS->isLiveOutOfMBB(LI, MBB))
927 Ret.IndVarUpdates += Freq;
928
929 if (MI->isCopy() && VirtRegAuxInfo::copyHint(MI, LI.reg(), TRI, *MRI))
930 Ret.HintWeights += Freq;
931 }
933 LI, *LIS, *VRM, *MRI, *MF.getSubtarget().getInstrInfo());
934 return Ret;
935}
936
937// Overall, this currently mimics what we do for weight calculation, but instead
938// of accummulating the various features, we keep them separate.
939void MLEvictAdvisor::extractFeatures(
941 llvm::SmallVectorImpl<float> &Largest, size_t Pos, int64_t IsHint,
942 int64_t LocalIntfsCount, float NumUrgent,
943 SmallVectorImpl<LRStartEndInfo> &LRPosInfo) const {
944 int64_t NumDefsAndUses = 0;
945 int64_t NumBrokenHints = 0;
946 double R = 0.0;
947 double W = 0.0;
948 double RW = 0.0;
949 double IndVarUpdates = 0.0;
950 double HintWeights = 0.0;
951 float StartBBFreq = 0.0;
952 float EndBBFreq = 0.0;
953 float HottestBlockFreq = 0.0;
954 int32_t NumRematerializable = 0;
955 float TotalWeight = 0.0;
956
957 SlotIndex EndSI = LIS->getSlotIndexes()->getZeroIndex();
958 SlotIndex StartSI = LIS->getSlotIndexes()->getLastIndex();
959 int64_t MaxStage = 0;
960 int64_t MinStage =
961 Intervals.empty() ? 0 : std::numeric_limits<int64_t>::max();
962
963 for (const auto *L : Intervals) {
964 const LiveInterval &LI = *L;
965 MaxStage = std::max<int64_t>(
966 MaxStage, static_cast<int64_t>(RA.getExtraInfo().getStage(LI)));
967 MinStage = std::min<int64_t>(
968 MinStage, static_cast<int64_t>(RA.getExtraInfo().getStage(LI)));
969
970 TotalWeight = std::max(TotalWeight, LI.weight());
971
972 if (LI.beginIndex() < StartSI)
973 StartSI = LI.beginIndex();
974
975 if (LI.endIndex() > EndSI)
976 EndSI = LI.endIndex();
977 const LIFeatureComponents &LIFC = getLIFeatureComponents(LI);
978 NumBrokenHints += VRM->hasPreferredPhys(LI.reg());
979
980 NumDefsAndUses += LIFC.NumDefsAndUses;
981 HottestBlockFreq = std::max(HottestBlockFreq, LIFC.HottestBlockFreq);
982 R += LIFC.R;
983 W += LIFC.W;
984 RW += LIFC.RW;
985
986 IndVarUpdates += LIFC.IndVarUpdates;
987
988 HintWeights += LIFC.HintWeights;
989 NumRematerializable += LIFC.IsRemat;
990
992 for (auto CurrentSegment : LI) {
993 LRPosInfo.push_back(
994 LRStartEndInfo{CurrentSegment.start, CurrentSegment.end, Pos});
995 }
996 }
997 }
998 size_t Size = 0;
999 if (!Intervals.empty()) {
1000 StartBBFreq =
1001 MBFI.getBlockFreqRelativeToEntryBlock(LIS->getMBBFromIndex(StartSI));
1002 if (EndSI >= LIS->getSlotIndexes()->getLastIndex())
1003 EndSI = LIS->getSlotIndexes()->getLastIndex().getPrevIndex();
1004 EndBBFreq =
1005 MBFI.getBlockFreqRelativeToEntryBlock(LIS->getMBBFromIndex(EndSI));
1006 Size = StartSI.distance(EndSI);
1007 }
1008 // Set the features at the column 'Pos'.
1009#define SET(ID, TYPE, VAL) \
1010 do { \
1011 Runner->getTensor<TYPE>(FeatureIDs::ID)[Pos] = static_cast<TYPE>(VAL); \
1012 if (!DoNotNormalize.test(FeatureIDs::ID)) \
1013 Largest[FeatureIDs::ID] = \
1014 std::max(Largest[FeatureIDs::ID], static_cast<float>(VAL)); \
1015 } while (false)
1016 SET(mask, int64_t, 1);
1017 SET(is_free, int64_t, Intervals.empty());
1018 SET(nr_urgent, float, NumUrgent);
1019 SET(nr_broken_hints, float, NumBrokenHints);
1020 SET(is_hint, int64_t, IsHint);
1021 SET(is_local, int64_t, LocalIntfsCount);
1022 SET(nr_rematerializable, float, NumRematerializable);
1023 SET(nr_defs_and_uses, float, NumDefsAndUses);
1024 SET(weighed_reads_by_max, float, R);
1025 SET(weighed_writes_by_max, float, W);
1026 SET(weighed_read_writes_by_max, float, RW);
1027 SET(weighed_indvars_by_max, float, IndVarUpdates);
1028 SET(hint_weights_by_max, float, HintWeights);
1029 SET(start_bb_freq_by_max, float, StartBBFreq);
1030 SET(end_bb_freq_by_max, float, EndBBFreq);
1031 SET(hottest_bb_freq_by_max, float, HottestBlockFreq);
1032 SET(liverange_size, float, Size);
1033 SET(use_def_density, float, TotalWeight);
1034 SET(max_stage, int64_t, MaxStage);
1035 SET(min_stage, int64_t, MinStage);
1036#undef SET
1037}
1038
1040 SmallVectorImpl<LRStartEndInfo> &LRPosInfo, MLModelRunner *RegallocRunner,
1041 function_ref<int(SlotIndex)> GetOpcode,
1042 function_ref<float(SlotIndex)> GetMBBFreq,
1043 function_ref<MachineBasicBlock *(SlotIndex)> GetMBBReference,
1044 const int InstructionsIndex, const int InstructionsMappingIndex,
1045 const int MBBFreqIndex, const int MBBMappingIndex,
1046 const SlotIndex LastIndex) {
1047 // This function extracts instruction based features relevant to the eviction
1048 // problem currently being solved. This function ends up extracting two
1049 // tensors.
1050 // 1 - A vector of size max instruction count. It contains the opcodes of the
1051 // instructions spanned by all the intervals in the current instance of the
1052 // eviction problem.
1053 // 2 - A binary mapping matrix of size (LR count * max
1054 // instruction count) which maps where the LRs are live to the actual opcodes
1055 // for which they are live.
1056 // 3 - A vector of size max supported MBB count storing MBB frequencies,
1057 // encompassing all of the MBBs covered by the eviction problem.
1058 // 4 - A vector of size max instruction count of indices to members of the MBB
1059 // frequency vector, mapping each instruction to its associated MBB.
1060
1061 // Start off by sorting the segments based on the beginning slot index.
1062 std::sort(
1063 LRPosInfo.begin(), LRPosInfo.end(),
1064 [](LRStartEndInfo A, LRStartEndInfo B) { return A.Begin < B.Begin; });
1065 size_t InstructionIndex = 0;
1066 size_t CurrentSegmentIndex = 0;
1067 SlotIndex CurrentIndex = LRPosInfo[0].Begin;
1068 std::map<MachineBasicBlock *, size_t> VisitedMBBs;
1069 size_t CurrentMBBIndex = 0;
1070 // This loop processes all the segments sequentially by starting at the
1071 // beginning slot index of the first segment, iterating through all the slot
1072 // indices before the end slot index of that segment (while checking for
1073 // overlaps with segments that start at greater slot indices). After hitting
1074 // that end index, the current segment being processed gets bumped until they
1075 // are all processed or the max instruction count is hit, where everything is
1076 // just truncated.
1077 while (true) {
1078 // If the index that we are currently at is within the current segment and
1079 // we haven't hit the max instruction count, continue processing the current
1080 // segment.
1081 while (CurrentIndex <= LRPosInfo[CurrentSegmentIndex].End &&
1082 InstructionIndex < ModelMaxSupportedInstructionCount) {
1083 int CurrentOpcode = GetOpcode(CurrentIndex);
1084 // If the current machine instruction is null, skip it
1085 if (CurrentOpcode == -1) {
1086 // If we're currently at the last index in the SlotIndex analysis,
1087 // we can't go any further, so return from the function
1088 if (CurrentIndex >= LastIndex) {
1089 return;
1090 }
1091 CurrentIndex = CurrentIndex.getNextIndex();
1092 continue;
1093 }
1094 MachineBasicBlock *CurrentMBBReference = GetMBBReference(CurrentIndex);
1095 if (VisitedMBBs.count(CurrentMBBReference) == 0) {
1096 VisitedMBBs[CurrentMBBReference] = CurrentMBBIndex;
1097 ++CurrentMBBIndex;
1098 }
1099 extractMBBFrequency(CurrentIndex, InstructionIndex, VisitedMBBs,
1100 GetMBBFreq, CurrentMBBReference, RegallocRunner,
1101 MBBFreqIndex, MBBMappingIndex);
1102 // Current code assumes we're not going to get any disjointed segments
1103 assert(LRPosInfo[CurrentSegmentIndex].Begin <= CurrentIndex);
1104 RegallocRunner->getTensor<int64_t>(InstructionsIndex)[InstructionIndex] =
1105 CurrentOpcode < OpcodeValueCutoff ? CurrentOpcode : 0;
1106 // set value in the binary mapping matrix for the current instruction
1107 auto CurrentSegmentPosition = LRPosInfo[CurrentSegmentIndex].Pos;
1108 RegallocRunner->getTensor<int64_t>(
1109 InstructionsMappingIndex)[CurrentSegmentPosition *
1111 InstructionIndex] = 1;
1112 // All of the segments are sorted based on the beginning slot index, but
1113 // this doesn't mean that the beginning slot index of the next segment is
1114 // after the end segment of the one being currently processed. This while
1115 // loop checks for overlapping segments and modifies the portion of the
1116 // column in the mapping matrix for the currently processed instruction
1117 // for the LR it is checking. Also make sure that the beginning of the
1118 // current segment we're checking for overlap in is less than the current
1119 // index, otherwise we're done checking overlaps.
1120 size_t OverlapCheckCurrentSegment = CurrentSegmentIndex + 1;
1121 while (OverlapCheckCurrentSegment < LRPosInfo.size() &&
1122 LRPosInfo[OverlapCheckCurrentSegment].Begin <= CurrentIndex) {
1123 auto OverlapCurrentSegmentPosition =
1124 LRPosInfo[OverlapCheckCurrentSegment].Pos;
1125 if (LRPosInfo[OverlapCheckCurrentSegment].End >= CurrentIndex) {
1126 RegallocRunner->getTensor<int64_t>(
1127 InstructionsMappingIndex)[OverlapCurrentSegmentPosition *
1129 InstructionIndex] = 1;
1130 }
1131 ++OverlapCheckCurrentSegment;
1132 }
1133 ++InstructionIndex;
1134 if (CurrentIndex >= LastIndex) {
1135 return;
1136 }
1137 CurrentIndex = CurrentIndex.getNextIndex();
1138 }
1139 // if we've just finished processing through the last segment or if we've
1140 // hit the maximum number of instructions, break out of the loop.
1141 if (CurrentSegmentIndex == LRPosInfo.size() - 1 ||
1142 InstructionIndex >= ModelMaxSupportedInstructionCount) {
1143 break;
1144 }
1145 // If the segments are not overlapping, we need to move to the beginning
1146 // index of the next segment to avoid having instructions not attached to
1147 // any register.
1148 if (LRPosInfo[CurrentSegmentIndex + 1].Begin >
1149 LRPosInfo[CurrentSegmentIndex].End) {
1150 CurrentIndex = LRPosInfo[CurrentSegmentIndex + 1].Begin;
1151 }
1152 ++CurrentSegmentIndex;
1153 }
1154}
1155
1157 const SlotIndex CurrentIndex, const size_t CurrentInstructionIndex,
1158 std::map<MachineBasicBlock *, size_t> &VisitedMBBs,
1159 function_ref<float(SlotIndex)> GetMBBFreq,
1160 MachineBasicBlock *CurrentMBBReference, MLModelRunner *RegallocRunner,
1161 const int MBBFreqIndex, const int MBBMappingIndex) {
1162 size_t CurrentMBBIndex = VisitedMBBs[CurrentMBBReference];
1163 float CurrentMBBFreq = GetMBBFreq(CurrentIndex);
1164 if (CurrentMBBIndex < ModelMaxSupportedMBBCount) {
1165 RegallocRunner->getTensor<float>(MBBFreqIndex)[CurrentMBBIndex] =
1166 CurrentMBBFreq;
1167 RegallocRunner->getTensor<int64_t>(
1168 MBBMappingIndex)[CurrentInstructionIndex] = CurrentMBBIndex;
1169 }
1170}
1171
1172// Development mode-specific implementations
1173#ifdef LLVM_HAVE_TFLITE
1174
1177 return new DevelopmentModeEvictionAdvisorAnalysisLegacy();
1178}
1179
1180int64_t DevelopmentModeEvictAdvisor::tryFindEvictionCandidatePosition(
1181 const LiveInterval &VirtReg, const AllocationOrder &Order,
1182 unsigned OrderLimit, uint8_t CostPerUseLimit,
1183 const SmallVirtRegSet &FixedRegisters) const {
1184 int64_t Ret = 0;
1185 if (isa<ModelUnderTrainingRunner>(getRunner())) {
1186 Ret = MLEvictAdvisor::tryFindEvictionCandidatePosition(
1187 VirtReg, Order, OrderLimit, CostPerUseLimit, FixedRegisters);
1188 } else {
1189 MCRegister PhysReg = getDefaultAdvisor().tryFindEvictionCandidate(
1190 VirtReg, Order, CostPerUseLimit, FixedRegisters);
1191 // Find the index of the selected PhysReg. We need it for logging,
1192 // otherwise this is wasted cycles (but so would starting development mode
1193 // without a model nor logging)
1194 if (!PhysReg)
1196 else
1197 for (auto I = Order.begin(), E = Order.getOrderLimitEnd(OrderLimit);
1198 I != E; ++I, ++Ret)
1199 if (*I == PhysReg)
1200 break;
1201 }
1202 if (TrainingLog.empty())
1203 return Ret;
1204 // TODO(mtrofin): when we support optional rewards, this can go away. In the
1205 // meantime, we log the "pretend" reward (0) for the previous observation
1206 // before starting a new one.
1207 if (Log->hasObservationInProgress())
1208 Log->logReward<float>(0.0);
1209
1210 Log->startObservation();
1211 size_t CurrentFeature = 0;
1213 ? FeatureIDs::FeaturesWithDevelopmentCount
1215 for (; CurrentFeature < FeatureCount; ++CurrentFeature) {
1216 Log->logTensorValue(CurrentFeature,
1217 reinterpret_cast<const char *>(
1218 getRunner().getTensorUntyped(CurrentFeature)));
1219 }
1220 if (auto *MUTR = dyn_cast<ModelUnderTrainingRunner>(&getRunner()))
1221 for (size_t I = 0; I < MUTR->extraOutputsForLoggingSpecs().size();
1222 ++I, ++CurrentFeature)
1223 Log->logTensorValue(
1224 CurrentFeature,
1225 reinterpret_cast<const char *>(MUTR->getUntypedExtraOutputValue(I)));
1226 // The output is right after the features and the extra outputs
1227 Log->logTensorValue(CurrentFeature, reinterpret_cast<const char *>(&Ret));
1228 Log->endObservation();
1229 return Ret;
1230}
1231
1232bool RegAllocScoring::runOnMachineFunction(MachineFunction &MF) {
1233 std::optional<float> CachedReward;
1234 auto GetReward = [&]() {
1235 if (!CachedReward)
1236 CachedReward = static_cast<float>(
1238 MF, getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI())
1239 .getScore());
1240 return *CachedReward;
1241 };
1242
1243 getAnalysis<RegAllocEvictionAdvisorAnalysisLegacy>().logRewardIfNeeded(
1244 MF, GetReward);
1245 getAnalysis<RegAllocPriorityAdvisorAnalysisLegacy>().logRewardIfNeeded(
1246 MF, GetReward);
1247 return false;
1248}
1249#endif // #ifdef LLVM_HAVE_TFLITE
1250
1251RegAllocEvictionAdvisorProvider *
1253 return new ReleaseModeEvictionAdvisorProvider(Ctx);
1254}
1255
1258#if defined(LLVM_HAVE_TFLITE)
1259 return new DevelopmentModeEvictionAdvisorProvider(Ctx);
1260#endif
1261 return nullptr;
1262}
1263
1268 ? new ReleaseModeEvictionAdvisorAnalysisLegacy()
1269 : nullptr;
1270}
1271
1272// In all cases except development mode, we don't need scoring.
1273#if !defined(LLVM_HAVE_TFLITE)
1274bool RegAllocScoring::runOnMachineFunction(MachineFunction &) { return false; }
1275#endif
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
static constexpr unsigned long long mask(BlockVerifier::State S)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
@ Available
We know the block is fully available. This is a fixpoint.
Definition GVN.cpp:951
Hexagon Hardware Loops
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
Live Register Matrix
#define I(x, y, z)
Definition MD5.cpp:58
NoopSavedModelImpl CompiledModelType
static cl::opt< std::string > InteractiveChannelBaseName("inliner-interactive-channel-base", cl::Hidden, cl::desc("Base file path for the interactive mode. The incoming filename should " "have the name <inliner-interactive-channel-base>.in, while the " "outgoing name should be <inliner-interactive-channel-base>.out"))
static const bool EnableDevelopmentFeatures
static cl::opt< unsigned > MaxEvictionCount("mlregalloc-max-eviction-count", cl::Hidden, cl::desc("The maximum number of times a live range can be " "evicted before preventing it from being evicted"), cl::init(100))
#define RA_EVICT_FEATURES_LIST(M)
#define _FEATURE_IDX_SIMPLE(_, name, __, ___)
#define RA_EVICT_FIRST_DEVELOPMENT_FEATURE(M)
#define SET(ID, TYPE, VAL)
#define _RESET(TYPE, NAME, SHAPE, __)
#define RA_EVICT_REST_DEVELOPMENT_FEATURES(M)
static cl::opt< std::string > InteractiveChannelBaseName("regalloc-evict-interactive-channel-base", cl::Hidden, cl::desc("Base file path for the interactive mode. The incoming filename should " "have the name <regalloc-evict-interactive-channel-base>.in, while the " "outgoing name should be " "<regalloc-evict-interactive-channel-base>.out"))
#define _FEATURE_IDX(A, B, C, D)
#define _DECL_FEATURES(type, name, shape, _)
#define DecisionName
Register Reg
Register const TargetRegisterInfo * TRI
#define T
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
SI optimize exec mask operations pre RA
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
Iterator getOrderLimitEnd(unsigned OrderLimit) const
Iterator begin() const
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:359
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
LLVM_ABI void emitError(const Instruction *I, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
Query interferences between a single live virtual register and a live interval union.
const SmallVectorImpl< const LiveInterval * > & interferingVRegs(unsigned MaxInterferingRegs=std::numeric_limits< unsigned >::max())
LiveInterval - This class represents the liveness of a register, or stack slot.
float weight() const
Register reg() const
bool isSpillable() const
isSpillable - Can this interval be spilled?
SlotIndex beginIndex() const
beginIndex - Return the lowest numbered slot covered.
SlotIndex endIndex() const
endNumber - return the maximum point of the range of the whole, exclusive.
@ IK_VirtReg
Virtual register interference.
Logging utility - given an ordered specification of features, and assuming a scalar reward,...
bool isLoopExiting(const BlockT *BB) const
True if terminator in the block can branch to another block that is outside of the current loop.
Represents a single loop in the control flow graph.
Definition LoopInfo.h:40
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:33
static constexpr unsigned NoRegister
Definition MCRegister.h:52
MLModelRunner interface: abstraction of a mechanism for evaluating a ML model.
virtual void switchContext(StringRef Name)
T * getTensor(I FeatureID)
MachineBlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate machine basic b...
double getBlockFreqRelativeToEntryBlock(const MachineBasicBlock *MBB) const
Compute the frequency of the block, relative to the entry block.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
defusechain_instr_iterator< true, true, true, true > reg_instr_nodbg_iterator
reg_instr_nodbg_iterator/reg_instr_nodbg_begin/reg_instr_nodbg_end - Walk all defs and uses of the sp...
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
A mock class satisfying the interface expected by ReleaseModeModelRunner for its TGen parameter.
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual bool doInitialization(Module &)
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
Definition Pass.h:128
ImmutableAnalysis abstraction for fetching the Eviction Advisor.
virtual void logRewardIfNeeded(const MachineFunction &MF, function_ref< float()> GetReward)
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Common provider for legacy and new pass managers.
virtual std::unique_ptr< RegAllocEvictionAdvisor > getAdvisor(const MachineFunction &MF, const RAGreedy &RA, MachineBlockFrequencyInfo *MBFI, MachineLoopInfo *Loops)=0
virtual void logRewardIfNeeded(const MachineFunction &MF, llvm::function_ref< float()> GetReward)
RegAllocEvictionAdvisorProvider(AdvisorMode Mode, LLVMContext &Ctx)
virtual bool canEvictHintInterference(const LiveInterval &VirtReg, MCRegister PhysReg, const SmallVirtRegSet &FixedRegisters) const =0
Find out if we can evict the live ranges occupying the given PhysReg, which is a hint (preferred regi...
virtual MCRegister tryFindEvictionCandidate(const LiveInterval &VirtReg, const AllocationOrder &Order, uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) const =0
Find a physical register that can be freed by evicting the FixedRegisters, or return NoRegister.
LLVM_ABI_FOR_TEST double getScore() const
Wrapper class representing virtual and physical registers.
Definition Register.h:19
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
Definition Register.h:67
constexpr unsigned id() const
Definition Register.h:95
SlotIndex - An opaque wrapper around machine indexes.
Definition SlotIndexes.h:66
SlotIndex getNextIndex() const
Returns the next index.
int distance(SlotIndex other) const
Return the distance from this index to the given one.
SlotIndex getPrevIndex() const
Returns the previous index.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.
Definition SmallSet.h:175
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
static TensorSpec createSpec(const std::string &Name, const std::vector< int64_t > &Shape, int Port=0)
Definition TensorSpec.h:66
static bool isRematerializable(const LiveInterval &LI, const LiveIntervals &LIS, const VirtRegMap &VRM, const MachineRegisterInfo &MRI, const TargetInstrInfo &TII)
Determine if all values in LI are rematerializable.
static Register copyHint(const MachineInstr *MI, Register Reg, const TargetRegisterInfo &TRI, const MachineRegisterInfo &MRI)
Return the preferred allocation register for reg, given a COPY instruction.
An efficient, type-erasing, non-owning reference to a callable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
bool isEmbeddedModelEvaluatorValid()
static const int ModelMaxSupportedInstructionCount
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1655
SmallSet< Register, 16 > SmallVirtRegSet
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
RegAllocEvictionAdvisorAnalysisLegacy * createReleaseModeAdvisorAnalysisLegacy()
static const int64_t ModelMaxSupportedMBBCount
RegAllocEvictionAdvisorProvider * createDevelopmentModeAdvisorProvider(LLVMContext &Ctx)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2136
LLVM_ABI_FOR_TEST void extractInstructionFeatures(llvm::SmallVectorImpl< LRStartEndInfo > &LRPosInfo, MLModelRunner *RegallocRunner, function_ref< int(SlotIndex)> GetOpcode, function_ref< float(SlotIndex)> GetMBBFreq, function_ref< MachineBasicBlock *(SlotIndex)> GetMBBReference, const int InstructionsIndex, const int InstructionsMappingIndex, const int MBBFreqIndex, const int MBBMappingIndex, const SlotIndex LastIndex)
static const TensorSpec DecisionSpec
RegAllocScore calculateRegAllocScore(const MachineFunction &MF, const MachineBlockFrequencyInfo &MBFI)
Calculate a score.
auto reverse(ContainerTy &&C)
Definition STLExtras.h:406
LLVM_ABI void initializeRegAllocScoringPass(PassRegistry &)
static const std::vector< TensorSpec > InputFeatures
@ RS_Done
There is nothing more we can do to this live range.
unsigned MCRegUnit
Register units are used to compute register aliasing.
Definition MCRegister.h:30
LLVM_ABI FunctionPass * createRegAllocScoringPass()
When learning an eviction policy, extract score(reward) information, otherwise this does nothing.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
cl::opt< unsigned > EvictInterferenceCutoff
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1867
LLVM_ATTRIBUTE_RETURNS_NONNULL RegAllocEvictionAdvisorProvider * createReleaseModeAdvisorProvider(LLVMContext &Ctx)
LLVM_ABI_FOR_TEST void extractMBBFrequency(const SlotIndex CurrentIndex, const size_t CurrentInstructionIndex, std::map< MachineBasicBlock *, size_t > &VisitedMBBs, function_ref< float(SlotIndex)> GetMBBFreq, MachineBasicBlock *CurrentMBBReference, MLModelRunner *RegallocRunner, const int MBBFreqIndex, const int MBBMappingIndex)
static const int64_t NumberOfInterferences
static const std::vector< int64_t > PerLiveRangeShape
RegAllocEvictionAdvisorAnalysisLegacy * createDevelopmentModeAdvisorAnalysisLegacy()
static const int64_t CandidateVirtRegPos
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:867