xref: /llvm-project/llvm/lib/CodeGen/MLRegAllocEvictAdvisor.cpp (revision 00f692b94f9aa08ede4aaba6f2aafe17857599c4)
165b40f27SMatt Arsenault //===- MLRegAllocEvictAdvisor.cpp - ML eviction advisor -------------------===//
265b40f27SMatt Arsenault //
365b40f27SMatt Arsenault // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
465b40f27SMatt Arsenault // See https://llvm.org/LICENSE.txt for license information.
565b40f27SMatt Arsenault // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
665b40f27SMatt Arsenault //
765b40f27SMatt Arsenault //===----------------------------------------------------------------------===//
865b40f27SMatt Arsenault //
965b40f27SMatt Arsenault // Implementation of the ML eviction advisor and reward injection pass
1065b40f27SMatt Arsenault //
1165b40f27SMatt Arsenault //===----------------------------------------------------------------------===//
1265b40f27SMatt Arsenault 
1365b40f27SMatt Arsenault #include "AllocationOrder.h"
1465b40f27SMatt Arsenault #include "RegAllocEvictionAdvisor.h"
1565b40f27SMatt Arsenault #include "RegAllocGreedy.h"
1665b40f27SMatt Arsenault #include "llvm/Analysis/InteractiveModelRunner.h"
1765b40f27SMatt Arsenault #include "llvm/Analysis/MLModelRunner.h"
1865b40f27SMatt Arsenault #include "llvm/Analysis/TensorSpec.h"
1965b40f27SMatt Arsenault #if defined(LLVM_HAVE_TF_AOT_REGALLOCEVICTMODEL) || defined(LLVM_HAVE_TFLITE)
2065b40f27SMatt Arsenault #include "llvm/Analysis/ModelUnderTrainingRunner.h"
2165b40f27SMatt Arsenault #include "llvm/Analysis/NoInferenceModelRunner.h"
2265b40f27SMatt Arsenault #include "llvm/Analysis/Utils/TrainingLogger.h"
2365b40f27SMatt Arsenault #endif
2465b40f27SMatt Arsenault #include "MLRegAllocEvictAdvisor.h"
2565b40f27SMatt Arsenault #include "llvm/Analysis/ReleaseModeModelRunner.h"
2665b40f27SMatt Arsenault #include "llvm/CodeGen/CalcSpillWeights.h"
2765b40f27SMatt Arsenault #include "llvm/CodeGen/LiveRegMatrix.h"
2865b40f27SMatt Arsenault #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
2965b40f27SMatt Arsenault #include "llvm/CodeGen/MachineFunction.h"
3065b40f27SMatt Arsenault #include "llvm/CodeGen/MachineLoopInfo.h"
3165b40f27SMatt Arsenault #include "llvm/CodeGen/MachineRegisterInfo.h"
3265b40f27SMatt Arsenault #include "llvm/CodeGen/Passes.h"
3365b40f27SMatt Arsenault #include "llvm/CodeGen/RegisterClassInfo.h"
3465b40f27SMatt Arsenault #include "llvm/CodeGen/VirtRegMap.h"
3538341993SMircea Trofin #include "llvm/IR/Module.h"
3665b40f27SMatt Arsenault #include "llvm/InitializePasses.h"
3765b40f27SMatt Arsenault #include "llvm/Pass.h"
3865b40f27SMatt Arsenault #include "llvm/PassRegistry.h"
3965b40f27SMatt Arsenault #include "llvm/Support/CommandLine.h"
4065b40f27SMatt Arsenault #include "llvm/Support/ErrorHandling.h"
4165b40f27SMatt Arsenault 
4265b40f27SMatt Arsenault #include <array>
4365b40f27SMatt Arsenault #include <bitset>
4465b40f27SMatt Arsenault #include <memory>
45*00f692b9SAiden Grossman #include <unordered_map>
4665b40f27SMatt Arsenault 
4765b40f27SMatt Arsenault using namespace llvm;
4865b40f27SMatt Arsenault 
4965b40f27SMatt Arsenault #define DEBUG_TYPE "ml-regalloc"
5065b40f27SMatt Arsenault 
5165b40f27SMatt Arsenault // Generated header in release (AOT) mode
5265b40f27SMatt Arsenault #if defined(LLVM_HAVE_TF_AOT_REGALLOCEVICTMODEL)
5365b40f27SMatt Arsenault #include "RegAllocEvictModel.h"
5465b40f27SMatt Arsenault using CompiledModelType = RegAllocEvictModel;
5565b40f27SMatt Arsenault #else
5665b40f27SMatt Arsenault using CompiledModelType = NoopSavedModelImpl;
5765b40f27SMatt Arsenault #endif
5865b40f27SMatt Arsenault 
5965b40f27SMatt Arsenault static cl::opt<std::string> InteractiveChannelBaseName(
6065b40f27SMatt Arsenault     "regalloc-evict-interactive-channel-base", cl::Hidden,
6165b40f27SMatt Arsenault     cl::desc(
6265b40f27SMatt Arsenault         "Base file path for the interactive mode. The incoming filename should "
6365b40f27SMatt Arsenault         "have the name <regalloc-evict-interactive-channel-base>.in, while the "
6465b40f27SMatt Arsenault         "outgoing name should be "
6565b40f27SMatt Arsenault         "<regalloc-evict-interactive-channel-base>.out"));
6665b40f27SMatt Arsenault 
67*00f692b9SAiden Grossman static cl::opt<unsigned> MaxEvictionCount(
68*00f692b9SAiden Grossman     "mlregalloc-max-eviction-count", cl::Hidden,
6960325abeSAiden Grossman     cl::desc("The maximum number of times a live range can be "
7060325abeSAiden Grossman              "evicted before preventing it from being evicted"),
71*00f692b9SAiden Grossman     cl::init(100));
7260325abeSAiden Grossman 
7365b40f27SMatt Arsenault // Options that only make sense in development mode
7465b40f27SMatt Arsenault #ifdef LLVM_HAVE_TFLITE
7565b40f27SMatt Arsenault #include "RegAllocScore.h"
7665b40f27SMatt Arsenault #include "llvm/Analysis/Utils/TFUtils.h"
7765b40f27SMatt Arsenault 
7865b40f27SMatt Arsenault static cl::opt<std::string> TrainingLog(
7965b40f27SMatt Arsenault     "regalloc-training-log", cl::Hidden,
8065b40f27SMatt Arsenault     cl::desc("Training log for the register allocator eviction model"));
8165b40f27SMatt Arsenault 
8265b40f27SMatt Arsenault static cl::opt<std::string> ModelUnderTraining(
8365b40f27SMatt Arsenault     "regalloc-model", cl::Hidden,
8465b40f27SMatt Arsenault     cl::desc("The model being trained for register allocation eviction"));
8565b40f27SMatt Arsenault 
8665b40f27SMatt Arsenault static cl::opt<bool> EnableDevelopmentFeatures(
8765b40f27SMatt Arsenault     "regalloc-enable-development-features", cl::Hidden,
8865b40f27SMatt Arsenault     cl::desc("Whether or not to enable features under development for the ML "
8965b40f27SMatt Arsenault              "regalloc advisor"));
9065b40f27SMatt Arsenault 
9165b40f27SMatt Arsenault #else
9265b40f27SMatt Arsenault static const bool EnableDevelopmentFeatures = false;
9365b40f27SMatt Arsenault #endif // #ifdef LLVM_HAVE_TFLITE
9465b40f27SMatt Arsenault 
9565b40f27SMatt Arsenault /// The score injection pass.
9665b40f27SMatt Arsenault /// This pass calculates the score for a function and inserts it in the log, but
9765b40f27SMatt Arsenault /// this happens only in development mode. It's a no-op otherwise.
9865b40f27SMatt Arsenault namespace llvm {
9965b40f27SMatt Arsenault extern cl::opt<unsigned> EvictInterferenceCutoff;
10065b40f27SMatt Arsenault 
10165b40f27SMatt Arsenault class RegAllocScoring : public MachineFunctionPass {
10265b40f27SMatt Arsenault public:
10365b40f27SMatt Arsenault   static char ID;
10465b40f27SMatt Arsenault 
10565b40f27SMatt Arsenault   RegAllocScoring() : MachineFunctionPass(ID) {
10665b40f27SMatt Arsenault     initializeRegAllocScoringPass(*PassRegistry::getPassRegistry());
10765b40f27SMatt Arsenault   }
10865b40f27SMatt Arsenault 
10965b40f27SMatt Arsenault   ~RegAllocScoring() override = default;
11065b40f27SMatt Arsenault 
11165b40f27SMatt Arsenault   StringRef getPassName() const override {
11265b40f27SMatt Arsenault     return "Register Allocation Pass Scoring";
11365b40f27SMatt Arsenault   }
11465b40f27SMatt Arsenault 
11565b40f27SMatt Arsenault   /// RegAllocReward analysis usage.
11665b40f27SMatt Arsenault   void getAnalysisUsage(AnalysisUsage &AU) const override {
11765b40f27SMatt Arsenault     AU.setPreservesAll();
11865b40f27SMatt Arsenault     AU.addRequired<RegAllocEvictionAdvisorAnalysis>();
11965b40f27SMatt Arsenault     AU.addRequired<RegAllocPriorityAdvisorAnalysis>();
12009989996Spaperchalice     AU.addRequired<MachineBlockFrequencyInfoWrapperPass>();
12165b40f27SMatt Arsenault     MachineFunctionPass::getAnalysisUsage(AU);
12265b40f27SMatt Arsenault   }
12365b40f27SMatt Arsenault 
12465b40f27SMatt Arsenault   /// Performs this pass
12565b40f27SMatt Arsenault   bool runOnMachineFunction(MachineFunction &) override;
12665b40f27SMatt Arsenault };
12765b40f27SMatt Arsenault 
12865b40f27SMatt Arsenault char RegAllocScoring::ID = 0;
12965b40f27SMatt Arsenault FunctionPass *createRegAllocScoringPass() { return new RegAllocScoring(); }
13065b40f27SMatt Arsenault 
13165b40f27SMatt Arsenault } // namespace llvm
13265b40f27SMatt Arsenault 
13365b40f27SMatt Arsenault INITIALIZE_PASS(RegAllocScoring, "regallocscoringpass",
13465b40f27SMatt Arsenault                 "Register Allocation Scoring Pass", false, false)
13565b40f27SMatt Arsenault 
13665b40f27SMatt Arsenault // ===================================
13765b40f27SMatt Arsenault // Common ML Advisor declarations
13865b40f27SMatt Arsenault // ===================================
13965b40f27SMatt Arsenault namespace {
14065b40f27SMatt Arsenault // The model can only accept a specified number of opcodes and will error it if
14165b40f27SMatt Arsenault // fed an opcode it hasn't seen before. This constant sets the current cutoff.
14265b40f27SMatt Arsenault static const int OpcodeValueCutoff = 17716;
14365b40f27SMatt Arsenault 
14465b40f27SMatt Arsenault // Most features are as described above, so we'll reuse this vector in defining
14565b40f27SMatt Arsenault // them.
14665b40f27SMatt Arsenault static const std::vector<int64_t> PerLiveRangeShape{1, NumberOfInterferences};
14765b40f27SMatt Arsenault 
14865b40f27SMatt Arsenault // --------------
14965b40f27SMatt Arsenault // Features table
15065b40f27SMatt Arsenault // --------------
15165b40f27SMatt Arsenault // For each interfering live range (incl. the candidate) we collect a number of
15265b40f27SMatt Arsenault // features. However, because the features are of different types (and because
15365b40f27SMatt Arsenault // of ML best practices), we organize the tensors per feature, not per
15465b40f27SMatt Arsenault // candidate. Each such tensor has a scalar value corresponding to the
15565b40f27SMatt Arsenault // interferring live range at that position, in the order in AllocationOrder.
15665b40f27SMatt Arsenault // The last position corresponds to the virt reg seeking allocation.
15765b40f27SMatt Arsenault // Exception to all that is the progression feature, which is just a scalar (see
15865b40f27SMatt Arsenault // its documentation for details).
15965b40f27SMatt Arsenault // Note on naming: the "_by_max" are normalized using the largest value of that
16065b40f27SMatt Arsenault // tensor, as observed in the current decision making stage (i.e. for the
16165b40f27SMatt Arsenault // current call to the advisor's tryFindEvictionCandidate)
16265b40f27SMatt Arsenault //
16365b40f27SMatt Arsenault // The feature list format: type, name, shape, documentation.
16465b40f27SMatt Arsenault // Note: we can really just use int64 and float, hence the modeling of some
16565b40f27SMatt Arsenault // bools as int64 values.
16665b40f27SMatt Arsenault #define RA_EVICT_FEATURES_LIST(M)                                              \
16765b40f27SMatt Arsenault   M(int64_t, mask, PerLiveRangeShape,                                          \
16865b40f27SMatt Arsenault     "boolean values, 0 for unavailable candidates (i.e. if a position is 0, "  \
16965b40f27SMatt Arsenault     "it "                                                                      \
17065b40f27SMatt Arsenault     "can't be evicted)")                                                       \
17165b40f27SMatt Arsenault   M(int64_t, is_free, PerLiveRangeShape,                                       \
17265b40f27SMatt Arsenault     "boolean values, 1 if this phys reg is actually free (no interferences)")  \
17365b40f27SMatt Arsenault   M(float, nr_urgent, PerLiveRangeShape,                                       \
17465b40f27SMatt Arsenault     "number of 'urgent' intervals, normalized. Urgent are those that are OK "  \
17565b40f27SMatt Arsenault     "to break cascades")                                                       \
17665b40f27SMatt Arsenault   M(float, nr_broken_hints, PerLiveRangeShape,                                 \
17765b40f27SMatt Arsenault     "if this position were evicted, how many broken hints would there be")     \
17865b40f27SMatt Arsenault   M(int64_t, is_hint, PerLiveRangeShape,                                       \
17965b40f27SMatt Arsenault     "is this a preferred phys reg for the candidate")                          \
18065b40f27SMatt Arsenault   M(int64_t, is_local, PerLiveRangeShape,                                      \
18165b40f27SMatt Arsenault     "is this live range local to a basic block")                               \
18265b40f27SMatt Arsenault   M(float, nr_rematerializable, PerLiveRangeShape,                             \
18365b40f27SMatt Arsenault     "nr rematerializable ranges")                                              \
18465b40f27SMatt Arsenault   M(float, nr_defs_and_uses, PerLiveRangeShape,                                \
18565b40f27SMatt Arsenault     "bb freq - weighed nr defs and uses")                                      \
18665b40f27SMatt Arsenault   M(float, weighed_reads_by_max, PerLiveRangeShape,                            \
18765b40f27SMatt Arsenault     "bb freq - weighed nr of reads, normalized")                               \
18865b40f27SMatt Arsenault   M(float, weighed_writes_by_max, PerLiveRangeShape,                           \
18965b40f27SMatt Arsenault     "bb feq - weighed nr of writes, normalized")                               \
19065b40f27SMatt Arsenault   M(float, weighed_read_writes_by_max, PerLiveRangeShape,                      \
19165b40f27SMatt Arsenault     "bb freq - weighed nr of uses that are both read and writes, normalized")  \
19265b40f27SMatt Arsenault   M(float, weighed_indvars_by_max, PerLiveRangeShape,                          \
19365b40f27SMatt Arsenault     "bb freq - weighed nr of uses that are indvars, normalized")               \
19465b40f27SMatt Arsenault   M(float, hint_weights_by_max, PerLiveRangeShape,                             \
19565b40f27SMatt Arsenault     "bb freq - weighed nr of uses that are hints, normalized")                 \
19665b40f27SMatt Arsenault   M(float, start_bb_freq_by_max, PerLiveRangeShape,                            \
19765b40f27SMatt Arsenault     "the freq in the start block, normalized")                                 \
19865b40f27SMatt Arsenault   M(float, end_bb_freq_by_max, PerLiveRangeShape,                              \
19965b40f27SMatt Arsenault     "freq of end block, normalized")                                           \
20065b40f27SMatt Arsenault   M(float, hottest_bb_freq_by_max, PerLiveRangeShape,                          \
20165b40f27SMatt Arsenault     "hottest BB freq, normalized")                                             \
20265b40f27SMatt Arsenault   M(float, liverange_size, PerLiveRangeShape,                                  \
20365b40f27SMatt Arsenault     "size (instr index diff) of the LR")                                       \
20465b40f27SMatt Arsenault   M(float, use_def_density, PerLiveRangeShape,                                 \
20565b40f27SMatt Arsenault     "the max weight, as computed by the manual heuristic")                     \
20665b40f27SMatt Arsenault   M(int64_t, max_stage, PerLiveRangeShape,                                     \
20765b40f27SMatt Arsenault     "largest stage of an interval in this LR")                                 \
20865b40f27SMatt Arsenault   M(int64_t, min_stage, PerLiveRangeShape,                                     \
20965b40f27SMatt Arsenault     "lowest stage of an interval in this LR")                                  \
21065b40f27SMatt Arsenault   M(float, progress, {1}, "ratio of current queue size to initial size")
21165b40f27SMatt Arsenault 
21265b40f27SMatt Arsenault #ifdef LLVM_HAVE_TFLITE
21365b40f27SMatt Arsenault #define RA_EVICT_FIRST_DEVELOPMENT_FEATURE(M)                                  \
21465b40f27SMatt Arsenault   M(int64_t, instructions, InstructionsShape,                                  \
21565b40f27SMatt Arsenault     "Opcodes of the instructions covered by the eviction problem")
21665b40f27SMatt Arsenault 
21765b40f27SMatt Arsenault #define RA_EVICT_REST_DEVELOPMENT_FEATURES(M)                                  \
21865b40f27SMatt Arsenault   M(int64_t, instructions_mapping, InstructionsMappingShape,                   \
21965b40f27SMatt Arsenault     "A binary matrix mapping LRs to instruction opcodes")                      \
22065b40f27SMatt Arsenault   M(float, mbb_frequencies, MBBFrequencyShape,                                 \
22165b40f27SMatt Arsenault     "A vector of machine basic block frequencies")                             \
22265b40f27SMatt Arsenault   M(int64_t, mbb_mapping, InstructionsShape,                                   \
2231650f1b3SJay Foad     "A vector of indices mapping instructions to MBBs")
22465b40f27SMatt Arsenault #else
22565b40f27SMatt Arsenault #define RA_EVICT_FIRST_DEVELOPMENT_FEATURE(M)
22665b40f27SMatt Arsenault #define RA_EVICT_REST_DEVELOPMENT_FEATURES(M)
22765b40f27SMatt Arsenault #endif
22865b40f27SMatt Arsenault 
22965b40f27SMatt Arsenault // The model learns to pick one of the mask == 1 interferences. This is the
23065b40f27SMatt Arsenault // name of the output tensor. The contract with the model is that the output
23165b40f27SMatt Arsenault // will be guaranteed to be to a mask == 1 position. Using a macro here to
23265b40f27SMatt Arsenault // avoid 'not used' warnings (and keep cond compilation to a minimum)
23365b40f27SMatt Arsenault #define DecisionName "index_to_evict"
23465b40f27SMatt Arsenault static const TensorSpec DecisionSpec =
23565b40f27SMatt Arsenault     TensorSpec::createSpec<int64_t>(DecisionName, {1});
23665b40f27SMatt Arsenault 
23765b40f27SMatt Arsenault // Named features index.
23865b40f27SMatt Arsenault enum FeatureIDs {
23965b40f27SMatt Arsenault #define _FEATURE_IDX_SIMPLE(_, name, __, ___) name
24065b40f27SMatt Arsenault #define _FEATURE_IDX(A, B, C, D) _FEATURE_IDX_SIMPLE(A, B, C, D),
24165b40f27SMatt Arsenault   RA_EVICT_FEATURES_LIST(_FEATURE_IDX) FeatureCount,
24265b40f27SMatt Arsenault #ifdef LLVM_HAVE_TFLITE
24365b40f27SMatt Arsenault   RA_EVICT_FIRST_DEVELOPMENT_FEATURE(_FEATURE_IDX_SIMPLE) = FeatureCount,
24465b40f27SMatt Arsenault #else
24565b40f27SMatt Arsenault   RA_EVICT_FIRST_DEVELOPMENT_FEATURE(_FEATURE_IDX)
24665b40f27SMatt Arsenault #endif // #ifdef LLVM_HAVE_TFLITE
24765b40f27SMatt Arsenault   RA_EVICT_REST_DEVELOPMENT_FEATURES(_FEATURE_IDX) FeaturesWithDevelopmentCount
24865b40f27SMatt Arsenault #undef _FEATURE_IDX
24965b40f27SMatt Arsenault #undef _FEATURE_IDX_SIMPLE
25065b40f27SMatt Arsenault };
25165b40f27SMatt Arsenault 
25265b40f27SMatt Arsenault // The ML advisor will typically have a sparse input to the evaluator, because
25365b40f27SMatt Arsenault // various phys regs won't be available. It's easier (maintenance-wise) to
25465b40f27SMatt Arsenault // bulk-reset the state of the evaluator each time we are about to use it
25565b40f27SMatt Arsenault // again.
25665b40f27SMatt Arsenault template <typename T> size_t getTotalSize(const std::vector<int64_t> &Shape) {
25765b40f27SMatt Arsenault   size_t Ret = sizeof(T);
25865b40f27SMatt Arsenault   for (const auto V : Shape)
25965b40f27SMatt Arsenault     Ret *= V;
26065b40f27SMatt Arsenault   return Ret;
26165b40f27SMatt Arsenault }
26265b40f27SMatt Arsenault 
26365b40f27SMatt Arsenault void resetInputs(MLModelRunner &Runner) {
26465b40f27SMatt Arsenault #define _RESET(TYPE, NAME, SHAPE, __)                                          \
26565b40f27SMatt Arsenault   std::memset(Runner.getTensorUntyped(FeatureIDs::NAME), 0,                    \
26665b40f27SMatt Arsenault               getTotalSize<TYPE>(SHAPE));
26765b40f27SMatt Arsenault   RA_EVICT_FEATURES_LIST(_RESET)
26865b40f27SMatt Arsenault   if (EnableDevelopmentFeatures) {
26965b40f27SMatt Arsenault     RA_EVICT_FIRST_DEVELOPMENT_FEATURE(_RESET)
27065b40f27SMatt Arsenault     RA_EVICT_REST_DEVELOPMENT_FEATURES(_RESET)
27165b40f27SMatt Arsenault #undef _RESET
27265b40f27SMatt Arsenault   }
27365b40f27SMatt Arsenault }
27465b40f27SMatt Arsenault 
27565b40f27SMatt Arsenault // Per-live interval components that get aggregated into the feature values
27665b40f27SMatt Arsenault // that will be passed to the evaluator.
27765b40f27SMatt Arsenault struct LIFeatureComponents {
27865b40f27SMatt Arsenault   double R = 0;
27965b40f27SMatt Arsenault   double W = 0;
28065b40f27SMatt Arsenault   double RW = 0;
28165b40f27SMatt Arsenault   double IndVarUpdates = 0;
28265b40f27SMatt Arsenault   double HintWeights = 0.0;
283f32e5bdcSMircea Trofin   int64_t NumDefsAndUses = 0;
28465b40f27SMatt Arsenault   float HottestBlockFreq = 0.0;
28565b40f27SMatt Arsenault   bool IsRemat = false;
28665b40f27SMatt Arsenault };
28765b40f27SMatt Arsenault 
28865b40f27SMatt Arsenault using CandidateRegList =
28965b40f27SMatt Arsenault     std::array<std::pair<MCRegister, bool>, NumberOfInterferences>;
29065b40f27SMatt Arsenault using FeaturesListNormalizer =
29165b40f27SMatt Arsenault     llvm::SmallVector<float, FeatureIDs::FeatureCount>;
29265b40f27SMatt Arsenault 
29365b40f27SMatt Arsenault /// The ML evictor (commonalities between release and development mode)
29465b40f27SMatt Arsenault class MLEvictAdvisor : public RegAllocEvictionAdvisor {
29565b40f27SMatt Arsenault public:
29665b40f27SMatt Arsenault   MLEvictAdvisor(const MachineFunction &MF, const RAGreedy &RA,
29765b40f27SMatt Arsenault                  MLModelRunner *Runner, const MachineBlockFrequencyInfo &MBFI,
29865b40f27SMatt Arsenault                  const MachineLoopInfo &Loops);
29965b40f27SMatt Arsenault 
30065b40f27SMatt Arsenault protected:
30165b40f27SMatt Arsenault   const RegAllocEvictionAdvisor &getDefaultAdvisor() const {
30265b40f27SMatt Arsenault     return static_cast<const RegAllocEvictionAdvisor &>(DefaultAdvisor);
30365b40f27SMatt Arsenault   }
30465b40f27SMatt Arsenault 
30565b40f27SMatt Arsenault   // The assumption is that if the Runner could not be constructed, we emit-ed
30665b40f27SMatt Arsenault   // error, and we shouldn't be asking for it here.
30765b40f27SMatt Arsenault   const MLModelRunner &getRunner() const { return *Runner; }
30865b40f27SMatt Arsenault 
30965b40f27SMatt Arsenault   /// This just calls Evaluate on the Runner, but in the development mode
31065b40f27SMatt Arsenault   /// case, if we're just capturing the log of the default advisor, it needs
31165b40f27SMatt Arsenault   /// to call the latter instead, so we need to pass all the necessary
31265b40f27SMatt Arsenault   /// parameters for it. In the development case, it will also log.
31365b40f27SMatt Arsenault   virtual int64_t
31465b40f27SMatt Arsenault   tryFindEvictionCandidatePosition(const LiveInterval &VirtReg,
31565b40f27SMatt Arsenault                                    const AllocationOrder &Order,
31665b40f27SMatt Arsenault                                    unsigned OrderLimit, uint8_t CostPerUseLimit,
31765b40f27SMatt Arsenault                                    const SmallVirtRegSet &FixedRegisters) const;
31865b40f27SMatt Arsenault 
31965b40f27SMatt Arsenault   /// Load the features of the given VirtReg (allocated or not) at column Pos,
32065b40f27SMatt Arsenault   /// but if  that can't be evicted, return false instead.
32165b40f27SMatt Arsenault   bool
32265b40f27SMatt Arsenault   loadInterferenceFeatures(const LiveInterval &VirtReg, MCRegister PhysReg,
32365b40f27SMatt Arsenault                            bool IsHint, const SmallVirtRegSet &FixedRegisters,
32465b40f27SMatt Arsenault                            llvm::SmallVectorImpl<float> &Largest, size_t Pos,
32565b40f27SMatt Arsenault                            SmallVectorImpl<LRStartEndInfo> &LRPosInfo) const;
32665b40f27SMatt Arsenault 
32765b40f27SMatt Arsenault private:
32865b40f27SMatt Arsenault   static float getInitialQueueSize(const MachineFunction &MF);
32965b40f27SMatt Arsenault 
33065b40f27SMatt Arsenault   MCRegister tryFindEvictionCandidate(
33165b40f27SMatt Arsenault       const LiveInterval &VirtReg, const AllocationOrder &Order,
33265b40f27SMatt Arsenault       uint8_t CostPerUseLimit,
33365b40f27SMatt Arsenault       const SmallVirtRegSet &FixedRegisters) const override;
33465b40f27SMatt Arsenault 
33565b40f27SMatt Arsenault   void extractFeatures(const SmallVectorImpl<const LiveInterval *> &Intervals,
33665b40f27SMatt Arsenault                        llvm::SmallVectorImpl<float> &Largest, size_t Pos,
337f32e5bdcSMircea Trofin                        int64_t IsHint, int64_t LocalIntfsCount, float NumUrgent,
33865b40f27SMatt Arsenault                        SmallVectorImpl<LRStartEndInfo> &LRPosInfo) const;
33965b40f27SMatt Arsenault 
34065b40f27SMatt Arsenault   // Point-in-time: we didn't learn this, so we always delegate to the
34165b40f27SMatt Arsenault   // default.
34265b40f27SMatt Arsenault   bool canEvictHintInterference(
34365b40f27SMatt Arsenault       const LiveInterval &VirtReg, MCRegister PhysReg,
34465b40f27SMatt Arsenault       const SmallVirtRegSet &FixedRegisters) const override {
34565b40f27SMatt Arsenault     return getDefaultAdvisor().canEvictHintInterference(VirtReg, PhysReg,
34665b40f27SMatt Arsenault                                                         FixedRegisters);
34765b40f27SMatt Arsenault   }
34865b40f27SMatt Arsenault 
34965b40f27SMatt Arsenault   const LIFeatureComponents &
35065b40f27SMatt Arsenault   getLIFeatureComponents(const LiveInterval &LI) const;
35165b40f27SMatt Arsenault 
35265b40f27SMatt Arsenault   // Hold on to a default advisor for:
35365b40f27SMatt Arsenault   // 1) the implementation of canEvictHintInterference, because we didn't
35465b40f27SMatt Arsenault   // learn that nuance yet; 2) for bootstrapping (logging) in the development
35565b40f27SMatt Arsenault   // mode case.
35665b40f27SMatt Arsenault   const DefaultEvictionAdvisor DefaultAdvisor;
35765b40f27SMatt Arsenault   MLModelRunner *const Runner;
35865b40f27SMatt Arsenault   const MachineBlockFrequencyInfo &MBFI;
35965b40f27SMatt Arsenault   const MachineLoopInfo &Loops;
36065b40f27SMatt Arsenault 
36165b40f27SMatt Arsenault   // Indices of those features we don't want to normalize.
36265b40f27SMatt Arsenault   // This could be static and shared, but its initialization is non-trivial.
36365b40f27SMatt Arsenault   std::bitset<FeatureIDs::FeatureCount> DoNotNormalize;
36465b40f27SMatt Arsenault   const float InitialQSize;
36565b40f27SMatt Arsenault 
36665b40f27SMatt Arsenault   using RegID = unsigned;
36765b40f27SMatt Arsenault   mutable DenseMap<RegID, LIFeatureComponents> CachedFeatures;
368*00f692b9SAiden Grossman 
369*00f692b9SAiden Grossman   mutable std::unordered_map<unsigned, unsigned> VirtRegEvictionCounts;
370*00f692b9SAiden Grossman 
371*00f692b9SAiden Grossman   void onEviction(Register RegBeingEvicted) const {
372*00f692b9SAiden Grossman     // If we cannot find the virtual register in the map, we just assume it has
373*00f692b9SAiden Grossman     // not been evicted before and thus has a value of zero (which is what the
374*00f692b9SAiden Grossman     // subscript operator returns by default).
375*00f692b9SAiden Grossman     ++VirtRegEvictionCounts[RegBeingEvicted.id()];
376*00f692b9SAiden Grossman   }
377*00f692b9SAiden Grossman 
378*00f692b9SAiden Grossman   unsigned getEvictionCount(Register Reg) const {
379*00f692b9SAiden Grossman     auto EvictionCountIt = VirtRegEvictionCounts.find(Reg.id());
380*00f692b9SAiden Grossman     if (EvictionCountIt != VirtRegEvictionCounts.end())
381*00f692b9SAiden Grossman       return EvictionCountIt->second;
382*00f692b9SAiden Grossman     return 0;
383*00f692b9SAiden Grossman   }
38465b40f27SMatt Arsenault };
38565b40f27SMatt Arsenault 
38665b40f27SMatt Arsenault #define _DECL_FEATURES(type, name, shape, _)                                   \
38765b40f27SMatt Arsenault   TensorSpec::createSpec<type>(#name, shape),
38865b40f27SMatt Arsenault 
38965b40f27SMatt Arsenault // ===================================
39065b40f27SMatt Arsenault // Release (AOT) - specifics
39165b40f27SMatt Arsenault // ===================================
39265b40f27SMatt Arsenault class ReleaseModeEvictionAdvisorAnalysis final
39365b40f27SMatt Arsenault     : public RegAllocEvictionAdvisorAnalysis {
39465b40f27SMatt Arsenault public:
39565b40f27SMatt Arsenault   ReleaseModeEvictionAdvisorAnalysis()
39665b40f27SMatt Arsenault       : RegAllocEvictionAdvisorAnalysis(AdvisorMode::Release) {
39765b40f27SMatt Arsenault     if (EnableDevelopmentFeatures) {
39865b40f27SMatt Arsenault       InputFeatures = {RA_EVICT_FEATURES_LIST(
39965b40f27SMatt Arsenault           _DECL_FEATURES) RA_EVICT_FIRST_DEVELOPMENT_FEATURE(_DECL_FEATURES)
40065b40f27SMatt Arsenault                            RA_EVICT_REST_DEVELOPMENT_FEATURES(_DECL_FEATURES)};
40165b40f27SMatt Arsenault     } else {
40265b40f27SMatt Arsenault       InputFeatures = {RA_EVICT_FEATURES_LIST(_DECL_FEATURES)};
40365b40f27SMatt Arsenault     }
40465b40f27SMatt Arsenault   }
40565b40f27SMatt Arsenault   // support for isa<> and dyn_cast.
40665b40f27SMatt Arsenault   static bool classof(const RegAllocEvictionAdvisorAnalysis *R) {
40765b40f27SMatt Arsenault     return R->getAdvisorMode() == AdvisorMode::Release;
40865b40f27SMatt Arsenault   }
40965b40f27SMatt Arsenault 
41065b40f27SMatt Arsenault private:
41165b40f27SMatt Arsenault   std::vector<TensorSpec> InputFeatures;
41265b40f27SMatt Arsenault 
41365b40f27SMatt Arsenault   void getAnalysisUsage(AnalysisUsage &AU) const override {
41409989996Spaperchalice     AU.addRequired<MachineBlockFrequencyInfoWrapperPass>();
41579d0de2aSpaperchalice     AU.addRequired<MachineLoopInfoWrapperPass>();
41665b40f27SMatt Arsenault     RegAllocEvictionAdvisorAnalysis::getAnalysisUsage(AU);
41765b40f27SMatt Arsenault   }
41865b40f27SMatt Arsenault 
41965b40f27SMatt Arsenault   std::unique_ptr<RegAllocEvictionAdvisor>
42065b40f27SMatt Arsenault   getAdvisor(const MachineFunction &MF, const RAGreedy &RA) override {
42165b40f27SMatt Arsenault     if (!Runner) {
42265b40f27SMatt Arsenault       if (InteractiveChannelBaseName.empty())
42365b40f27SMatt Arsenault         Runner = std::make_unique<ReleaseModeModelRunner<CompiledModelType>>(
42465b40f27SMatt Arsenault             MF.getFunction().getContext(), InputFeatures, DecisionName);
42565b40f27SMatt Arsenault       else
42665b40f27SMatt Arsenault         Runner = std::make_unique<InteractiveModelRunner>(
42765b40f27SMatt Arsenault             MF.getFunction().getContext(), InputFeatures, DecisionSpec,
42865b40f27SMatt Arsenault             InteractiveChannelBaseName + ".out",
42965b40f27SMatt Arsenault             InteractiveChannelBaseName + ".in");
43065b40f27SMatt Arsenault     }
43165b40f27SMatt Arsenault     return std::make_unique<MLEvictAdvisor>(
43209989996Spaperchalice         MF, RA, Runner.get(),
43309989996Spaperchalice         getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI(),
43479d0de2aSpaperchalice         getAnalysis<MachineLoopInfoWrapperPass>().getLI());
43565b40f27SMatt Arsenault   }
43665b40f27SMatt Arsenault   std::unique_ptr<MLModelRunner> Runner;
43765b40f27SMatt Arsenault };
43865b40f27SMatt Arsenault 
43965b40f27SMatt Arsenault // ===================================
44065b40f27SMatt Arsenault // Development mode-specifics
44165b40f27SMatt Arsenault // ===================================
44265b40f27SMatt Arsenault //
44365b40f27SMatt Arsenault // Features we log
44465b40f27SMatt Arsenault #ifdef LLVM_HAVE_TFLITE
44565b40f27SMatt Arsenault static const TensorSpec Reward = TensorSpec::createSpec<float>("reward", {1});
44665b40f27SMatt Arsenault 
44765b40f27SMatt Arsenault // Features we bind on the model. The tensor names have a prefix, and we also
44865b40f27SMatt Arsenault // need to include some tensors that are expected to be present by the
44965b40f27SMatt Arsenault // training algo.
45065b40f27SMatt Arsenault // TODO: can we just get rid of these?
45165b40f27SMatt Arsenault #define _DECL_TRAIN_FEATURES(type, name, shape, _)                             \
45265b40f27SMatt Arsenault   TensorSpec::createSpec<type>(std::string("action_") + #name, shape),
45365b40f27SMatt Arsenault 
45465b40f27SMatt Arsenault class DevelopmentModeEvictAdvisor : public MLEvictAdvisor {
45565b40f27SMatt Arsenault public:
45665b40f27SMatt Arsenault   DevelopmentModeEvictAdvisor(const MachineFunction &MF, const RAGreedy &RA,
45765b40f27SMatt Arsenault                               MLModelRunner *Runner,
45865b40f27SMatt Arsenault                               const MachineBlockFrequencyInfo &MBFI,
45965b40f27SMatt Arsenault                               const MachineLoopInfo &Loops, Logger *Log)
46065b40f27SMatt Arsenault       : MLEvictAdvisor(MF, RA, Runner, MBFI, Loops), Log(Log) {}
46165b40f27SMatt Arsenault 
46265b40f27SMatt Arsenault private:
46365b40f27SMatt Arsenault   int64_t tryFindEvictionCandidatePosition(
46465b40f27SMatt Arsenault       const LiveInterval &VirtReg, const AllocationOrder &Order,
46565b40f27SMatt Arsenault       unsigned OrderLimit, uint8_t CostPerUseLimit,
46665b40f27SMatt Arsenault       const SmallVirtRegSet &FixedRegisters) const override;
46765b40f27SMatt Arsenault 
46865b40f27SMatt Arsenault   Logger *const Log;
46965b40f27SMatt Arsenault };
47065b40f27SMatt Arsenault 
47165b40f27SMatt Arsenault class DevelopmentModeEvictionAdvisorAnalysis final
47265b40f27SMatt Arsenault     : public RegAllocEvictionAdvisorAnalysis {
47365b40f27SMatt Arsenault public:
47465b40f27SMatt Arsenault   DevelopmentModeEvictionAdvisorAnalysis()
47565b40f27SMatt Arsenault       : RegAllocEvictionAdvisorAnalysis(AdvisorMode::Development) {
47665b40f27SMatt Arsenault     if (EnableDevelopmentFeatures) {
47765b40f27SMatt Arsenault       InputFeatures = {RA_EVICT_FEATURES_LIST(
47865b40f27SMatt Arsenault           _DECL_FEATURES) RA_EVICT_FIRST_DEVELOPMENT_FEATURE(_DECL_FEATURES)
47965b40f27SMatt Arsenault                            RA_EVICT_REST_DEVELOPMENT_FEATURES(_DECL_FEATURES)};
48065b40f27SMatt Arsenault       TrainingInputFeatures = {
48165b40f27SMatt Arsenault           RA_EVICT_FEATURES_LIST(_DECL_TRAIN_FEATURES)
48265b40f27SMatt Arsenault               RA_EVICT_FIRST_DEVELOPMENT_FEATURE(_DECL_TRAIN_FEATURES)
48365b40f27SMatt Arsenault                   RA_EVICT_REST_DEVELOPMENT_FEATURES(_DECL_TRAIN_FEATURES)
48465b40f27SMatt Arsenault                       TensorSpec::createSpec<float>("action_discount", {1}),
48565b40f27SMatt Arsenault           TensorSpec::createSpec<int32_t>("action_step_type", {1}),
48665b40f27SMatt Arsenault           TensorSpec::createSpec<float>("action_reward", {1})};
48765b40f27SMatt Arsenault     } else {
48865b40f27SMatt Arsenault       InputFeatures = {RA_EVICT_FEATURES_LIST(_DECL_FEATURES)};
48965b40f27SMatt Arsenault       TrainingInputFeatures = {
49065b40f27SMatt Arsenault           RA_EVICT_FEATURES_LIST(_DECL_TRAIN_FEATURES)
49165b40f27SMatt Arsenault               TensorSpec::createSpec<float>("action_discount", {1}),
49265b40f27SMatt Arsenault           TensorSpec::createSpec<int32_t>("action_step_type", {1}),
49365b40f27SMatt Arsenault           TensorSpec::createSpec<float>("action_reward", {1})};
49465b40f27SMatt Arsenault     }
49565b40f27SMatt Arsenault   }
49665b40f27SMatt Arsenault   // support for isa<> and dyn_cast.
49765b40f27SMatt Arsenault   static bool classof(const RegAllocEvictionAdvisorAnalysis *R) {
49865b40f27SMatt Arsenault     return R->getAdvisorMode() == AdvisorMode::Development;
49965b40f27SMatt Arsenault   }
50065b40f27SMatt Arsenault 
50165b40f27SMatt Arsenault   void logRewardIfNeeded(const MachineFunction &MF,
50265b40f27SMatt Arsenault                          llvm::function_ref<float()> GetReward) override {
50365b40f27SMatt Arsenault     if (!Log || !Log->hasAnyObservationForContext(MF.getName()))
50465b40f27SMatt Arsenault       return;
50565b40f27SMatt Arsenault     // The function pass manager would run all the function passes for a
50665b40f27SMatt Arsenault     // function, so we assume the last context belongs to this function. If
50765b40f27SMatt Arsenault     // this invariant ever changes, we can implement at that time switching
50865b40f27SMatt Arsenault     // contexts. At this point, it'd be an error
50965b40f27SMatt Arsenault     if (Log->currentContext() != MF.getName()) {
51065b40f27SMatt Arsenault       MF.getFunction().getContext().emitError(
51165b40f27SMatt Arsenault           "The training log context shouldn't have had changed.");
51265b40f27SMatt Arsenault     }
51365b40f27SMatt Arsenault     if (Log->hasObservationInProgress())
51465b40f27SMatt Arsenault       Log->logReward<float>(GetReward());
51565b40f27SMatt Arsenault   }
51665b40f27SMatt Arsenault 
51765b40f27SMatt Arsenault private:
51865b40f27SMatt Arsenault   std::vector<TensorSpec> InputFeatures;
51965b40f27SMatt Arsenault   std::vector<TensorSpec> TrainingInputFeatures;
52065b40f27SMatt Arsenault 
52165b40f27SMatt Arsenault   void getAnalysisUsage(AnalysisUsage &AU) const override {
52209989996Spaperchalice     AU.addRequired<MachineBlockFrequencyInfoWrapperPass>();
52379d0de2aSpaperchalice     AU.addRequired<MachineLoopInfoWrapperPass>();
52465b40f27SMatt Arsenault     RegAllocEvictionAdvisorAnalysis::getAnalysisUsage(AU);
52565b40f27SMatt Arsenault   }
52665b40f27SMatt Arsenault 
52765b40f27SMatt Arsenault   bool doInitialization(Module &M) override {
52865b40f27SMatt Arsenault     LLVMContext &Ctx = M.getContext();
52965b40f27SMatt Arsenault     if (ModelUnderTraining.empty() && TrainingLog.empty()) {
53065b40f27SMatt Arsenault       Ctx.emitError("Regalloc development mode should be requested with at "
53165b40f27SMatt Arsenault                     "least logging enabled and/or a training model");
53265b40f27SMatt Arsenault       return false;
53365b40f27SMatt Arsenault     }
53465b40f27SMatt Arsenault     if (ModelUnderTraining.empty())
53565b40f27SMatt Arsenault       Runner = std::make_unique<NoInferenceModelRunner>(Ctx, InputFeatures);
53665b40f27SMatt Arsenault     else
53765b40f27SMatt Arsenault       Runner = ModelUnderTrainingRunner::createAndEnsureValid(
53865b40f27SMatt Arsenault           Ctx, ModelUnderTraining, DecisionName, TrainingInputFeatures);
53965b40f27SMatt Arsenault     if (!Runner) {
54065b40f27SMatt Arsenault       Ctx.emitError("Regalloc: could not set up the model runner");
54165b40f27SMatt Arsenault       return false;
54265b40f27SMatt Arsenault     }
54365b40f27SMatt Arsenault     if (TrainingLog.empty())
54465b40f27SMatt Arsenault       return false;
54565b40f27SMatt Arsenault     std::error_code EC;
54665b40f27SMatt Arsenault     auto OS = std::make_unique<raw_fd_ostream>(TrainingLog, EC);
54765b40f27SMatt Arsenault     if (EC) {
54865b40f27SMatt Arsenault       M.getContext().emitError(EC.message() + ":" + TrainingLog);
54965b40f27SMatt Arsenault       return false;
55065b40f27SMatt Arsenault     }
55165b40f27SMatt Arsenault     std::vector<TensorSpec> LFS = InputFeatures;
55265b40f27SMatt Arsenault     if (auto *MUTR = dyn_cast<ModelUnderTrainingRunner>(Runner.get()))
55365b40f27SMatt Arsenault       append_range(LFS, MUTR->extraOutputsForLoggingSpecs());
55465b40f27SMatt Arsenault     // We always log the output; in particular, if we're not evaluating, we
55565b40f27SMatt Arsenault     // don't have an output spec json file. That's why we handle the
55665b40f27SMatt Arsenault     // 'normal' output separately.
55765b40f27SMatt Arsenault     LFS.push_back(DecisionSpec);
55865b40f27SMatt Arsenault 
55965b40f27SMatt Arsenault     Log = std::make_unique<Logger>(std::move(OS), LFS, Reward,
56065b40f27SMatt Arsenault                                    /*IncludeReward*/ true);
56165b40f27SMatt Arsenault     return false;
56265b40f27SMatt Arsenault   }
56365b40f27SMatt Arsenault 
56465b40f27SMatt Arsenault   std::unique_ptr<RegAllocEvictionAdvisor>
56565b40f27SMatt Arsenault   getAdvisor(const MachineFunction &MF, const RAGreedy &RA) override {
56665b40f27SMatt Arsenault     if (!Runner)
56765b40f27SMatt Arsenault       return nullptr;
56865b40f27SMatt Arsenault     if (Log)
56965b40f27SMatt Arsenault       Log->switchContext(MF.getName());
57065b40f27SMatt Arsenault     return std::make_unique<DevelopmentModeEvictAdvisor>(
57109989996Spaperchalice         MF, RA, Runner.get(),
57209989996Spaperchalice         getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI(),
57379d0de2aSpaperchalice         getAnalysis<MachineLoopInfoWrapperPass>().getLI(), Log.get());
57465b40f27SMatt Arsenault   }
57565b40f27SMatt Arsenault 
57665b40f27SMatt Arsenault   std::unique_ptr<MLModelRunner> Runner;
57765b40f27SMatt Arsenault   std::unique_ptr<Logger> Log;
57865b40f27SMatt Arsenault };
57965b40f27SMatt Arsenault 
58065b40f27SMatt Arsenault #endif // #ifdef LLVM_HAVE_TFLITE
58165b40f27SMatt Arsenault } // namespace
58265b40f27SMatt Arsenault 
58365b40f27SMatt Arsenault float MLEvictAdvisor::getInitialQueueSize(const MachineFunction &MF) {
58465b40f27SMatt Arsenault   auto &MRI = MF.getRegInfo();
58550249263SMatt Arsenault   unsigned NumUsedRegs = 0;
58665b40f27SMatt Arsenault   for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
58765b40f27SMatt Arsenault     Register Reg = Register::index2VirtReg(I);
58850249263SMatt Arsenault     if (!MRI.reg_nodbg_empty(Reg))
58950249263SMatt Arsenault       ++NumUsedRegs;
59065b40f27SMatt Arsenault   }
59150249263SMatt Arsenault   return static_cast<float>(NumUsedRegs);
59265b40f27SMatt Arsenault }
59365b40f27SMatt Arsenault 
59465b40f27SMatt Arsenault MLEvictAdvisor::MLEvictAdvisor(const MachineFunction &MF, const RAGreedy &RA,
59565b40f27SMatt Arsenault                                MLModelRunner *Runner,
59665b40f27SMatt Arsenault                                const MachineBlockFrequencyInfo &MBFI,
59765b40f27SMatt Arsenault                                const MachineLoopInfo &Loops)
59865b40f27SMatt Arsenault     : RegAllocEvictionAdvisor(MF, RA), DefaultAdvisor(MF, RA),
59965b40f27SMatt Arsenault       Runner(std::move(Runner)), MBFI(MBFI), Loops(Loops),
60065b40f27SMatt Arsenault       InitialQSize(MLEvictAdvisor::getInitialQueueSize(MF)) {
60165b40f27SMatt Arsenault   assert(this->Runner);
60265b40f27SMatt Arsenault   Runner->switchContext(MF.getName());
60365b40f27SMatt Arsenault   DoNotNormalize.set(FeatureIDs::mask);
60465b40f27SMatt Arsenault   DoNotNormalize.set(FeatureIDs::is_free);
60565b40f27SMatt Arsenault   DoNotNormalize.set(FeatureIDs::is_hint);
60665b40f27SMatt Arsenault   DoNotNormalize.set(FeatureIDs::is_local);
60765b40f27SMatt Arsenault   DoNotNormalize.set(FeatureIDs::min_stage);
60865b40f27SMatt Arsenault   DoNotNormalize.set(FeatureIDs::max_stage);
60965b40f27SMatt Arsenault   DoNotNormalize.set(FeatureIDs::progress);
61065b40f27SMatt Arsenault }
61165b40f27SMatt Arsenault 
61265b40f27SMatt Arsenault int64_t MLEvictAdvisor::tryFindEvictionCandidatePosition(
61365b40f27SMatt Arsenault     const LiveInterval &, const AllocationOrder &, unsigned, uint8_t,
61465b40f27SMatt Arsenault     const SmallVirtRegSet &) const {
61565b40f27SMatt Arsenault   int64_t Ret = Runner->evaluate<int64_t>();
61665b40f27SMatt Arsenault   assert(Ret >= 0);
61765b40f27SMatt Arsenault   assert(Ret <= CandidateVirtRegPos);
61865b40f27SMatt Arsenault   return Ret;
61965b40f27SMatt Arsenault }
62065b40f27SMatt Arsenault 
62165b40f27SMatt Arsenault bool MLEvictAdvisor::loadInterferenceFeatures(
62265b40f27SMatt Arsenault     const LiveInterval &VirtReg, MCRegister PhysReg, bool IsHint,
62365b40f27SMatt Arsenault     const SmallVirtRegSet &FixedRegisters,
62465b40f27SMatt Arsenault     llvm::SmallVectorImpl<float> &Largest, size_t Pos,
62565b40f27SMatt Arsenault     llvm::SmallVectorImpl<LRStartEndInfo> &LRPosInfo) const {
62665b40f27SMatt Arsenault   // It is only possible to evict virtual register interference.
62765b40f27SMatt Arsenault   if (Matrix->checkInterference(VirtReg, PhysReg) > LiveRegMatrix::IK_VirtReg) {
62865b40f27SMatt Arsenault     // leave unavailable
62965b40f27SMatt Arsenault     return false;
63065b40f27SMatt Arsenault   }
63165b40f27SMatt Arsenault 
63265b40f27SMatt Arsenault   const bool IsLocal = LIS->intervalIsInOneMBB(VirtReg);
63365b40f27SMatt Arsenault   int64_t LocalIntfs = 0;
634f32e5bdcSMircea Trofin   float NumUrgent = 0.0f;
63565b40f27SMatt Arsenault 
63665b40f27SMatt Arsenault   // The cascade tracking is the same as in the default advisor
63765b40f27SMatt Arsenault   unsigned Cascade = RA.getExtraInfo().getCascadeOrCurrentNext(VirtReg.reg());
63865b40f27SMatt Arsenault 
63965b40f27SMatt Arsenault   SmallVector<const LiveInterval *, MaxInterferences> InterferingIntervals;
64065b40f27SMatt Arsenault   for (MCRegUnit Unit : TRI->regunits(PhysReg)) {
64165b40f27SMatt Arsenault     LiveIntervalUnion::Query &Q = Matrix->query(VirtReg, Unit);
64265b40f27SMatt Arsenault     // Different from the default heuristic, we don't make any assumptions
64365b40f27SMatt Arsenault     // about what having more than 10 results in the query may mean.
64465b40f27SMatt Arsenault     const auto &IFIntervals = Q.interferingVRegs(EvictInterferenceCutoff);
64565b40f27SMatt Arsenault     if (IFIntervals.empty() && InterferingIntervals.empty())
64665b40f27SMatt Arsenault       continue;
64765b40f27SMatt Arsenault     if (IFIntervals.size() >= EvictInterferenceCutoff)
64865b40f27SMatt Arsenault       return false;
64965b40f27SMatt Arsenault     InterferingIntervals.append(IFIntervals.begin(), IFIntervals.end());
65065b40f27SMatt Arsenault     for (const LiveInterval *Intf : reverse(IFIntervals)) {
65165b40f27SMatt Arsenault       assert(Intf->reg().isVirtual() &&
65265b40f27SMatt Arsenault              "Only expecting virtual register interference from query");
65365b40f27SMatt Arsenault       // This is the same set of legality checks as in the default case: don't
65465b40f27SMatt Arsenault       // try to evict fixed regs or 'done' ones. Also don't break cascades,
65565b40f27SMatt Arsenault       // except in the urgent case, with the same nuances used in the default
65665b40f27SMatt Arsenault       // heuristic.
65765b40f27SMatt Arsenault       // We could try sharing this between the advisors, but it may end up
65865b40f27SMatt Arsenault       // more complex than it is right now.
65965b40f27SMatt Arsenault       if (FixedRegisters.count(Intf->reg()))
66065b40f27SMatt Arsenault         return false;
66165b40f27SMatt Arsenault       if (RA.getExtraInfo().getStage(*Intf) == RS_Done)
66265b40f27SMatt Arsenault         return false;
66365b40f27SMatt Arsenault       bool Urgent =
66465b40f27SMatt Arsenault           !VirtReg.isSpillable() &&
66565b40f27SMatt Arsenault           (Intf->isSpillable() ||
66665b40f27SMatt Arsenault            RegClassInfo.getNumAllocatableRegs(MRI->getRegClass(VirtReg.reg())) <
66765b40f27SMatt Arsenault                RegClassInfo.getNumAllocatableRegs(
66865b40f27SMatt Arsenault                    MRI->getRegClass(Intf->reg())));
66960325abeSAiden Grossman 
67065b40f27SMatt Arsenault       unsigned IntfCascade = RA.getExtraInfo().getCascade(Intf->reg());
67160325abeSAiden Grossman       // There is a potential that the model could be adversarial and
67260325abeSAiden Grossman       // continually evict live ranges over and over again, leading to a
67360325abeSAiden Grossman       // large amount of compile time being spent in regalloc. If we hit the
67476f25892SAiden Grossman       // threshold, prevent the range from being evicted. We still let the
67576f25892SAiden Grossman       // range through if it is urgent as we are required to produce an
67676f25892SAiden Grossman       // eviction if the candidate is not spillable.
677*00f692b9SAiden Grossman       if (getEvictionCount(Intf->reg()) > MaxEvictionCount && !Urgent)
67860325abeSAiden Grossman         return false;
67960325abeSAiden Grossman 
68060325abeSAiden Grossman       // Only evict older cascades or live ranges without a cascade.
68165b40f27SMatt Arsenault       if (Cascade <= IntfCascade) {
68265b40f27SMatt Arsenault         if (!Urgent)
68365b40f27SMatt Arsenault           return false;
684f32e5bdcSMircea Trofin         ++NumUrgent;
68565b40f27SMatt Arsenault       }
68665b40f27SMatt Arsenault 
68765b40f27SMatt Arsenault       LocalIntfs += (IsLocal && LIS->intervalIsInOneMBB(*Intf) &&
68865b40f27SMatt Arsenault                      (!EnableLocalReassign || !canReassign(*Intf, PhysReg)));
68965b40f27SMatt Arsenault     }
69065b40f27SMatt Arsenault   }
69165b40f27SMatt Arsenault   // OK, so if we made it this far, this LR is an eviction candidate, load its
69265b40f27SMatt Arsenault   // features.
69365b40f27SMatt Arsenault   extractFeatures(InterferingIntervals, Largest, Pos, IsHint, LocalIntfs,
694f32e5bdcSMircea Trofin                   NumUrgent, LRPosInfo);
69565b40f27SMatt Arsenault   return true;
69665b40f27SMatt Arsenault }
69765b40f27SMatt Arsenault 
69865b40f27SMatt Arsenault MCRegister MLEvictAdvisor::tryFindEvictionCandidate(
69965b40f27SMatt Arsenault     const LiveInterval &VirtReg, const AllocationOrder &Order,
70065b40f27SMatt Arsenault     uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) const {
70165b40f27SMatt Arsenault   auto MaybeOrderLimit = getOrderLimit(VirtReg, Order, CostPerUseLimit);
70265b40f27SMatt Arsenault   if (!MaybeOrderLimit)
70365b40f27SMatt Arsenault     return MCRegister::NoRegister;
70465b40f27SMatt Arsenault   unsigned OrderLimit = *MaybeOrderLimit;
70565b40f27SMatt Arsenault 
70665b40f27SMatt Arsenault   // The heuristic sets initial costs such as, if CostPerUseLimit is
70765b40f27SMatt Arsenault   // max<uint8_t>, then any of the costs of the legally-evictable intervals
70865b40f27SMatt Arsenault   // would be lower. When that happens, one of those will be selected.
70965b40f27SMatt Arsenault   // Therefore, we allow the candidate be selected, unless the candidate is
71065b40f27SMatt Arsenault   // unspillable, in which case it would be incorrect to not find a register
71165b40f27SMatt Arsenault   // for it.
71265b40f27SMatt Arsenault   const bool MustFindEviction =
71365b40f27SMatt Arsenault       (!VirtReg.isSpillable() && CostPerUseLimit == static_cast<uint8_t>(~0u));
71465b40f27SMatt Arsenault   // Number of available candidates - if 0, no need to continue.
71565b40f27SMatt Arsenault   size_t Available = 0;
71665b40f27SMatt Arsenault   // Make sure we don't have leftover partial state from an attempt where we
71765b40f27SMatt Arsenault   // had no available candidates and bailed out early.
71865b40f27SMatt Arsenault   resetInputs(*Runner);
71965b40f27SMatt Arsenault 
72065b40f27SMatt Arsenault   // Track the index->register mapping because AllocationOrder doesn't do that
72165b40f27SMatt Arsenault   // and we'd have to scan it.
72265b40f27SMatt Arsenault   // Also track their mask, to write asserts/debug.
72365b40f27SMatt Arsenault   CandidateRegList Regs;
72465b40f27SMatt Arsenault   Regs.fill({0, false});
72565b40f27SMatt Arsenault 
72665b40f27SMatt Arsenault   // Track the largest value of features seen during this eviction session. We
72765b40f27SMatt Arsenault   // only normalize (some of) the float features, but it's just simpler to
72865b40f27SMatt Arsenault   // dimension 'Largest' to all the features, especially since we have the
72965b40f27SMatt Arsenault   // 'DoNotNormalize' list.
73065b40f27SMatt Arsenault   FeaturesListNormalizer Largest(FeatureIDs::FeatureCount, 0.0);
73165b40f27SMatt Arsenault 
73265b40f27SMatt Arsenault   // Same overal idea as in the default eviction policy - we visit the values
73365b40f27SMatt Arsenault   // of AllocationOrder one at a time. If it's not legally available, we mask
73465b40f27SMatt Arsenault   // off the corresponding feature column (==do nothing because we already
73565b40f27SMatt Arsenault   // reset all the features to 0) Use Pos to capture the column we load
73665b40f27SMatt Arsenault   // features at - in AllocationOrder order.
73765b40f27SMatt Arsenault   size_t Pos = 0;
73865b40f27SMatt Arsenault   SmallVector<LRStartEndInfo, NumberOfInterferences> LRPosInfo;
73965b40f27SMatt Arsenault   for (auto I = Order.begin(), E = Order.getOrderLimitEnd(OrderLimit); I != E;
74065b40f27SMatt Arsenault        ++I, ++Pos) {
74165b40f27SMatt Arsenault     MCRegister PhysReg = *I;
74265b40f27SMatt Arsenault     assert(!Regs[Pos].second);
74365b40f27SMatt Arsenault     assert(PhysReg);
74465b40f27SMatt Arsenault     if (!canAllocatePhysReg(CostPerUseLimit, PhysReg)) {
74565b40f27SMatt Arsenault       continue;
74665b40f27SMatt Arsenault     }
74765b40f27SMatt Arsenault     if (loadInterferenceFeatures(VirtReg, PhysReg, I.isHint(), FixedRegisters,
74865b40f27SMatt Arsenault                                  Largest, Pos, LRPosInfo)) {
74965b40f27SMatt Arsenault       ++Available;
75065b40f27SMatt Arsenault       Regs[Pos] = std::make_pair(PhysReg, true);
75165b40f27SMatt Arsenault     }
75265b40f27SMatt Arsenault   }
75365b40f27SMatt Arsenault   if (Available == 0) {
75465b40f27SMatt Arsenault     // Nothing to decide, nothing to learn.
75565b40f27SMatt Arsenault     assert(!MustFindEviction);
75665b40f27SMatt Arsenault     return MCRegister::NoRegister;
75765b40f27SMatt Arsenault   }
75865b40f27SMatt Arsenault   const size_t ValidPosLimit = Pos;
75965b40f27SMatt Arsenault   // If we must find eviction, the candidate should be masked out of the
76065b40f27SMatt Arsenault   // decision making process.
76165b40f27SMatt Arsenault   Regs[CandidateVirtRegPos].second = !MustFindEviction;
76265b40f27SMatt Arsenault   if (!MustFindEviction)
76365b40f27SMatt Arsenault     extractFeatures(SmallVector<const LiveInterval *, 1>(1, &VirtReg), Largest,
76465b40f27SMatt Arsenault                     CandidateVirtRegPos, /*IsHint*/ 0,
76565b40f27SMatt Arsenault                     /*LocalIntfsCount*/ 0,
766f32e5bdcSMircea Trofin                     /*NumUrgent*/ 0.0, LRPosInfo);
76765b40f27SMatt Arsenault   assert(InitialQSize > 0.0 && "We couldn't have gotten here if we had "
76865b40f27SMatt Arsenault                                "nothing to allocate initially.");
76965b40f27SMatt Arsenault #ifdef LLVM_HAVE_TFLITE
77065b40f27SMatt Arsenault   if (EnableDevelopmentFeatures) {
77165b40f27SMatt Arsenault     extractInstructionFeatures(
77265b40f27SMatt Arsenault         LRPosInfo, Runner,
77365b40f27SMatt Arsenault         [this](SlotIndex InputIndex) -> int {
77465b40f27SMatt Arsenault           auto *CurrentMachineInstruction =
77565b40f27SMatt Arsenault               LIS->getInstructionFromIndex(InputIndex);
77665b40f27SMatt Arsenault           if (!CurrentMachineInstruction) {
77765b40f27SMatt Arsenault             return -1;
77865b40f27SMatt Arsenault           }
77965b40f27SMatt Arsenault           return CurrentMachineInstruction->getOpcode();
78065b40f27SMatt Arsenault         },
78165b40f27SMatt Arsenault         [this](SlotIndex InputIndex) -> float {
78265b40f27SMatt Arsenault           auto *CurrentMachineInstruction =
78365b40f27SMatt Arsenault               LIS->getInstructionFromIndex(InputIndex);
78465b40f27SMatt Arsenault           return MBFI.getBlockFreqRelativeToEntryBlock(
78565b40f27SMatt Arsenault               CurrentMachineInstruction->getParent());
78665b40f27SMatt Arsenault         },
78765b40f27SMatt Arsenault         [this](SlotIndex InputIndex) -> MachineBasicBlock * {
78865b40f27SMatt Arsenault           auto *CurrentMachineInstruction =
78965b40f27SMatt Arsenault               LIS->getInstructionFromIndex(InputIndex);
79065b40f27SMatt Arsenault           return CurrentMachineInstruction->getParent();
79165b40f27SMatt Arsenault         },
79265b40f27SMatt Arsenault         FeatureIDs::instructions, FeatureIDs::instructions_mapping,
79365b40f27SMatt Arsenault         FeatureIDs::mbb_frequencies, FeatureIDs::mbb_mapping,
79465b40f27SMatt Arsenault         LIS->getSlotIndexes()->getLastIndex());
79565b40f27SMatt Arsenault   }
79665b40f27SMatt Arsenault #endif // #ifdef LLVM_HAVE_TFLITE
79765b40f27SMatt Arsenault   // Normalize the features.
79865b40f27SMatt Arsenault   for (auto &V : Largest)
79965b40f27SMatt Arsenault     V = V ? V : 1.0;
80065b40f27SMatt Arsenault   for (size_t FeatureIndex = 0; FeatureIndex < FeatureIDs::FeatureCount;
80165b40f27SMatt Arsenault        ++FeatureIndex) {
80265b40f27SMatt Arsenault     if (DoNotNormalize.test(FeatureIndex))
80365b40f27SMatt Arsenault       continue;
80465b40f27SMatt Arsenault     for (size_t Pos = 0; Pos < NumberOfInterferences; ++Pos) {
80565b40f27SMatt Arsenault       Runner->getTensor<float>(FeatureIndex)[Pos] /= Largest[FeatureIndex];
80665b40f27SMatt Arsenault     }
80765b40f27SMatt Arsenault   }
80865b40f27SMatt Arsenault   *Runner->getTensor<float>(FeatureIDs::progress) =
80965b40f27SMatt Arsenault       static_cast<float>(RA.getQueueSize()) / InitialQSize;
81065b40f27SMatt Arsenault 
81165b40f27SMatt Arsenault   // Get a decision.
81265b40f27SMatt Arsenault   size_t CandidatePos = tryFindEvictionCandidatePosition(
81365b40f27SMatt Arsenault       VirtReg, Order, OrderLimit, CostPerUseLimit, FixedRegisters);
81465b40f27SMatt Arsenault   // The contract with the ML side is that CandidatePos is mask == 1 (i.e.
81565b40f27SMatt Arsenault   // Regs[CandidatePos].second)
81665b40f27SMatt Arsenault   assert(Regs[CandidatePos].second);
81765b40f27SMatt Arsenault   if (CandidatePos == CandidateVirtRegPos) {
81865b40f27SMatt Arsenault     assert(!MustFindEviction);
81965b40f27SMatt Arsenault     return MCRegister::NoRegister;
82065b40f27SMatt Arsenault   }
82165b40f27SMatt Arsenault   assert(CandidatePos < ValidPosLimit);
82265b40f27SMatt Arsenault   (void)ValidPosLimit;
823*00f692b9SAiden Grossman 
824*00f692b9SAiden Grossman   // Update information about how many times the virtual registers being
825*00f692b9SAiden Grossman   // evicted have been evicted so that we can prevent the model from evicting
826*00f692b9SAiden Grossman   // the same ranges continually and eating compile time.
827*00f692b9SAiden Grossman   if (CandidatePos == CandidateVirtRegPos) {
828*00f692b9SAiden Grossman     onEviction(VirtReg.reg());
829*00f692b9SAiden Grossman   } else {
830*00f692b9SAiden Grossman     for (MCRegUnit Unit : TRI->regunits(Regs[CandidatePos].first)) {
831*00f692b9SAiden Grossman       LiveIntervalUnion::Query &Q = Matrix->query(VirtReg, Unit);
832*00f692b9SAiden Grossman       const auto &IFIntervals = Q.interferingVRegs(EvictInterferenceCutoff);
833*00f692b9SAiden Grossman       for (const LiveInterval *Intf : reverse(IFIntervals)) {
834*00f692b9SAiden Grossman         onEviction(Intf->reg());
835*00f692b9SAiden Grossman       }
836*00f692b9SAiden Grossman     }
837*00f692b9SAiden Grossman   }
838*00f692b9SAiden Grossman 
83965b40f27SMatt Arsenault   return Regs[CandidatePos].first;
84065b40f27SMatt Arsenault }
84165b40f27SMatt Arsenault 
84265b40f27SMatt Arsenault const LIFeatureComponents &
84365b40f27SMatt Arsenault MLEvictAdvisor::getLIFeatureComponents(const LiveInterval &LI) const {
84465b40f27SMatt Arsenault   RegID ID = LI.reg().id();
84565b40f27SMatt Arsenault   LIFeatureComponents Empty;
84665b40f27SMatt Arsenault   auto I = CachedFeatures.insert(std::make_pair(ID, Empty));
84765b40f27SMatt Arsenault   LIFeatureComponents &Ret = I.first->getSecond();
84865b40f27SMatt Arsenault   if (!I.second)
84965b40f27SMatt Arsenault     return Ret;
85065b40f27SMatt Arsenault 
85165b40f27SMatt Arsenault   SmallPtrSet<MachineInstr *, 8> Visited;
85265b40f27SMatt Arsenault   const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
85365b40f27SMatt Arsenault 
85465b40f27SMatt Arsenault   for (MachineRegisterInfo::reg_instr_nodbg_iterator
85565b40f27SMatt Arsenault            I = MRI->reg_instr_nodbg_begin(LI.reg()),
85665b40f27SMatt Arsenault            E = MRI->reg_instr_nodbg_end();
85765b40f27SMatt Arsenault        I != E;) {
85865b40f27SMatt Arsenault     MachineInstr *MI = &*(I++);
85965b40f27SMatt Arsenault 
860f32e5bdcSMircea Trofin     ++Ret.NumDefsAndUses;
86165b40f27SMatt Arsenault     if (!Visited.insert(MI).second)
86265b40f27SMatt Arsenault       continue;
86365b40f27SMatt Arsenault 
86465b40f27SMatt Arsenault     if (MI->isIdentityCopy() || MI->isImplicitDef())
86565b40f27SMatt Arsenault       continue;
86665b40f27SMatt Arsenault 
86765b40f27SMatt Arsenault     bool Reads, Writes;
86865b40f27SMatt Arsenault     std::tie(Reads, Writes) = MI->readsWritesVirtualRegister(LI.reg());
86965b40f27SMatt Arsenault 
87065b40f27SMatt Arsenault     float Freq = MBFI.getBlockFreqRelativeToEntryBlock(MI->getParent());
87165b40f27SMatt Arsenault     Ret.HottestBlockFreq = std::max(Freq, Ret.HottestBlockFreq);
87265b40f27SMatt Arsenault 
87365b40f27SMatt Arsenault     Ret.R += (Reads && !Writes) * Freq;
87465b40f27SMatt Arsenault     Ret.W += (!Reads && Writes) * Freq;
87565b40f27SMatt Arsenault     Ret.RW += (Reads && Writes) * Freq;
87665b40f27SMatt Arsenault 
87765b40f27SMatt Arsenault     auto *MBB = MI->getParent();
87865b40f27SMatt Arsenault     auto *Loop = Loops.getLoopFor(MBB);
87965b40f27SMatt Arsenault     bool IsExiting = Loop ? Loop->isLoopExiting(MBB) : false;
88065b40f27SMatt Arsenault 
88165b40f27SMatt Arsenault     if (Writes && IsExiting && LIS->isLiveOutOfMBB(LI, MBB))
88265b40f27SMatt Arsenault       Ret.IndVarUpdates += Freq;
88365b40f27SMatt Arsenault 
88465b40f27SMatt Arsenault     if (MI->isCopy() && VirtRegAuxInfo::copyHint(MI, LI.reg(), TRI, *MRI))
88565b40f27SMatt Arsenault       Ret.HintWeights += Freq;
88665b40f27SMatt Arsenault   }
88765b40f27SMatt Arsenault   Ret.IsRemat = VirtRegAuxInfo::isRematerializable(
88865b40f27SMatt Arsenault       LI, *LIS, *VRM, *MF.getSubtarget().getInstrInfo());
88965b40f27SMatt Arsenault   return Ret;
89065b40f27SMatt Arsenault }
89165b40f27SMatt Arsenault 
89265b40f27SMatt Arsenault // Overall, this currently mimics what we do for weight calculation, but instead
89365b40f27SMatt Arsenault // of accummulating the various features, we keep them separate.
89465b40f27SMatt Arsenault void MLEvictAdvisor::extractFeatures(
89565b40f27SMatt Arsenault     const SmallVectorImpl<const LiveInterval *> &Intervals,
89665b40f27SMatt Arsenault     llvm::SmallVectorImpl<float> &Largest, size_t Pos, int64_t IsHint,
897f32e5bdcSMircea Trofin     int64_t LocalIntfsCount, float NumUrgent,
89865b40f27SMatt Arsenault     SmallVectorImpl<LRStartEndInfo> &LRPosInfo) const {
899f32e5bdcSMircea Trofin   int64_t NumDefsAndUses = 0;
900f32e5bdcSMircea Trofin   int64_t NumBrokenHints = 0;
90165b40f27SMatt Arsenault   double R = 0.0;
90265b40f27SMatt Arsenault   double W = 0.0;
90365b40f27SMatt Arsenault   double RW = 0.0;
90465b40f27SMatt Arsenault   double IndVarUpdates = 0.0;
90565b40f27SMatt Arsenault   double HintWeights = 0.0;
90665b40f27SMatt Arsenault   float StartBBFreq = 0.0;
90765b40f27SMatt Arsenault   float EndBBFreq = 0.0;
90865b40f27SMatt Arsenault   float HottestBlockFreq = 0.0;
909f32e5bdcSMircea Trofin   int32_t NumRematerializable = 0;
91065b40f27SMatt Arsenault   float TotalWeight = 0.0;
91165b40f27SMatt Arsenault 
91265b40f27SMatt Arsenault   SlotIndex EndSI = LIS->getSlotIndexes()->getZeroIndex();
91365b40f27SMatt Arsenault   SlotIndex StartSI = LIS->getSlotIndexes()->getLastIndex();
91465b40f27SMatt Arsenault   int64_t MaxStage = 0;
91565b40f27SMatt Arsenault   int64_t MinStage =
91665b40f27SMatt Arsenault       Intervals.empty() ? 0 : std::numeric_limits<int64_t>::max();
91765b40f27SMatt Arsenault 
91865b40f27SMatt Arsenault   for (const auto *L : Intervals) {
91965b40f27SMatt Arsenault     const LiveInterval &LI = *L;
92065b40f27SMatt Arsenault     MaxStage = std::max<int64_t>(
92165b40f27SMatt Arsenault         MaxStage, static_cast<int64_t>(RA.getExtraInfo().getStage(LI)));
92265b40f27SMatt Arsenault     MinStage = std::min<int64_t>(
92365b40f27SMatt Arsenault         MinStage, static_cast<int64_t>(RA.getExtraInfo().getStage(LI)));
92465b40f27SMatt Arsenault 
92565b40f27SMatt Arsenault     TotalWeight = std::max(TotalWeight, LI.weight());
92665b40f27SMatt Arsenault 
92765b40f27SMatt Arsenault     if (LI.beginIndex() < StartSI)
92865b40f27SMatt Arsenault       StartSI = LI.beginIndex();
92965b40f27SMatt Arsenault 
93065b40f27SMatt Arsenault     if (LI.endIndex() > EndSI)
93165b40f27SMatt Arsenault       EndSI = LI.endIndex();
93265b40f27SMatt Arsenault     const LIFeatureComponents &LIFC = getLIFeatureComponents(LI);
933f32e5bdcSMircea Trofin     NumBrokenHints += VRM->hasPreferredPhys(LI.reg());
93465b40f27SMatt Arsenault 
935f32e5bdcSMircea Trofin     NumDefsAndUses += LIFC.NumDefsAndUses;
93665b40f27SMatt Arsenault     HottestBlockFreq = std::max(HottestBlockFreq, LIFC.HottestBlockFreq);
93765b40f27SMatt Arsenault     R += LIFC.R;
93865b40f27SMatt Arsenault     W += LIFC.W;
93965b40f27SMatt Arsenault     RW += LIFC.RW;
94065b40f27SMatt Arsenault 
94165b40f27SMatt Arsenault     IndVarUpdates += LIFC.IndVarUpdates;
94265b40f27SMatt Arsenault 
94365b40f27SMatt Arsenault     HintWeights += LIFC.HintWeights;
944f32e5bdcSMircea Trofin     NumRematerializable += LIFC.IsRemat;
94565b40f27SMatt Arsenault 
94665b40f27SMatt Arsenault     if (EnableDevelopmentFeatures) {
94765b40f27SMatt Arsenault       for (auto CurrentSegment : LI) {
94865b40f27SMatt Arsenault         LRPosInfo.push_back(
94965b40f27SMatt Arsenault             LRStartEndInfo{CurrentSegment.start, CurrentSegment.end, Pos});
95065b40f27SMatt Arsenault       }
95165b40f27SMatt Arsenault     }
95265b40f27SMatt Arsenault   }
95365b40f27SMatt Arsenault   size_t Size = 0;
95465b40f27SMatt Arsenault   if (!Intervals.empty()) {
95565b40f27SMatt Arsenault     StartBBFreq =
95665b40f27SMatt Arsenault         MBFI.getBlockFreqRelativeToEntryBlock(LIS->getMBBFromIndex(StartSI));
95765b40f27SMatt Arsenault     if (EndSI >= LIS->getSlotIndexes()->getLastIndex())
95865b40f27SMatt Arsenault       EndSI = LIS->getSlotIndexes()->getLastIndex().getPrevIndex();
95965b40f27SMatt Arsenault     EndBBFreq =
96065b40f27SMatt Arsenault         MBFI.getBlockFreqRelativeToEntryBlock(LIS->getMBBFromIndex(EndSI));
96165b40f27SMatt Arsenault     Size = StartSI.distance(EndSI);
96265b40f27SMatt Arsenault   }
96365b40f27SMatt Arsenault   // Set the features at the column 'Pos'.
96465b40f27SMatt Arsenault #define SET(ID, TYPE, VAL)                                                     \
96565b40f27SMatt Arsenault   do {                                                                         \
96665b40f27SMatt Arsenault     Runner->getTensor<TYPE>(FeatureIDs::ID)[Pos] = static_cast<TYPE>(VAL);     \
96765b40f27SMatt Arsenault     if (!DoNotNormalize.test(FeatureIDs::ID))                                  \
96865b40f27SMatt Arsenault       Largest[FeatureIDs::ID] =                                                \
96965b40f27SMatt Arsenault           std::max(Largest[FeatureIDs::ID], static_cast<float>(VAL));          \
97065b40f27SMatt Arsenault   } while (false)
97165b40f27SMatt Arsenault   SET(mask, int64_t, 1);
97265b40f27SMatt Arsenault   SET(is_free, int64_t, Intervals.empty());
973f32e5bdcSMircea Trofin   SET(nr_urgent, float, NumUrgent);
974f32e5bdcSMircea Trofin   SET(nr_broken_hints, float, NumBrokenHints);
97565b40f27SMatt Arsenault   SET(is_hint, int64_t, IsHint);
97665b40f27SMatt Arsenault   SET(is_local, int64_t, LocalIntfsCount);
977f32e5bdcSMircea Trofin   SET(nr_rematerializable, float, NumRematerializable);
978f32e5bdcSMircea Trofin   SET(nr_defs_and_uses, float, NumDefsAndUses);
97965b40f27SMatt Arsenault   SET(weighed_reads_by_max, float, R);
98065b40f27SMatt Arsenault   SET(weighed_writes_by_max, float, W);
98165b40f27SMatt Arsenault   SET(weighed_read_writes_by_max, float, RW);
98265b40f27SMatt Arsenault   SET(weighed_indvars_by_max, float, IndVarUpdates);
98365b40f27SMatt Arsenault   SET(hint_weights_by_max, float, HintWeights);
98465b40f27SMatt Arsenault   SET(start_bb_freq_by_max, float, StartBBFreq);
98565b40f27SMatt Arsenault   SET(end_bb_freq_by_max, float, EndBBFreq);
98665b40f27SMatt Arsenault   SET(hottest_bb_freq_by_max, float, HottestBlockFreq);
98765b40f27SMatt Arsenault   SET(liverange_size, float, Size);
98865b40f27SMatt Arsenault   SET(use_def_density, float, TotalWeight);
98965b40f27SMatt Arsenault   SET(max_stage, int64_t, MaxStage);
99065b40f27SMatt Arsenault   SET(min_stage, int64_t, MinStage);
99165b40f27SMatt Arsenault #undef SET
99265b40f27SMatt Arsenault }
99365b40f27SMatt Arsenault 
9941753008bSRahul Joshi void llvm::extractInstructionFeatures(
99565b40f27SMatt Arsenault     SmallVectorImpl<LRStartEndInfo> &LRPosInfo, MLModelRunner *RegallocRunner,
99665b40f27SMatt Arsenault     function_ref<int(SlotIndex)> GetOpcode,
99765b40f27SMatt Arsenault     function_ref<float(SlotIndex)> GetMBBFreq,
99865b40f27SMatt Arsenault     function_ref<MachineBasicBlock *(SlotIndex)> GetMBBReference,
99965b40f27SMatt Arsenault     const int InstructionsIndex, const int InstructionsMappingIndex,
100065b40f27SMatt Arsenault     const int MBBFreqIndex, const int MBBMappingIndex,
100165b40f27SMatt Arsenault     const SlotIndex LastIndex) {
100265b40f27SMatt Arsenault   // This function extracts instruction based features relevant to the eviction
100365b40f27SMatt Arsenault   // problem currently being solved. This function ends up extracting two
100465b40f27SMatt Arsenault   // tensors.
100565b40f27SMatt Arsenault   // 1 - A vector of size max instruction count. It contains the opcodes of the
100665b40f27SMatt Arsenault   // instructions spanned by all the intervals in the current instance of the
100765b40f27SMatt Arsenault   // eviction problem.
100865b40f27SMatt Arsenault   // 2 - A binary mapping matrix of size (LR count * max
100965b40f27SMatt Arsenault   // instruction count) which maps where the LRs are live to the actual opcodes
101065b40f27SMatt Arsenault   // for which they are live.
101165b40f27SMatt Arsenault   // 3 - A vector of size max supported MBB count storing MBB frequencies,
101265b40f27SMatt Arsenault   // encompassing all of the MBBs covered by the eviction problem.
101365b40f27SMatt Arsenault   // 4 - A vector of size max instruction count of indices to members of the MBB
101465b40f27SMatt Arsenault   // frequency vector, mapping each instruction to its associated MBB.
101565b40f27SMatt Arsenault 
101665b40f27SMatt Arsenault   // Start off by sorting the segments based on the beginning slot index.
1017fef144ceSKazu Hirata   std::sort(
1018fef144ceSKazu Hirata       LRPosInfo.begin(), LRPosInfo.end(),
1019fef144ceSKazu Hirata       [](LRStartEndInfo A, LRStartEndInfo B) { return A.Begin < B.Begin; });
102065b40f27SMatt Arsenault   size_t InstructionIndex = 0;
102165b40f27SMatt Arsenault   size_t CurrentSegmentIndex = 0;
102265b40f27SMatt Arsenault   SlotIndex CurrentIndex = LRPosInfo[0].Begin;
102365b40f27SMatt Arsenault   std::map<MachineBasicBlock *, size_t> VisitedMBBs;
102465b40f27SMatt Arsenault   size_t CurrentMBBIndex = 0;
102565b40f27SMatt Arsenault   // This loop processes all the segments sequentially by starting at the
102665b40f27SMatt Arsenault   // beginning slot index of the first segment, iterating through all the slot
102765b40f27SMatt Arsenault   // indices before the end slot index of that segment (while checking for
102865b40f27SMatt Arsenault   // overlaps with segments that start at greater slot indices). After hitting
102965b40f27SMatt Arsenault   // that end index, the current segment being processed gets bumped until they
103065b40f27SMatt Arsenault   // are all processed or the max instruction count is hit, where everything is
103165b40f27SMatt Arsenault   // just truncated.
103265b40f27SMatt Arsenault   while (true) {
103365b40f27SMatt Arsenault     // If the index that we are currently at is within the current segment and
103465b40f27SMatt Arsenault     // we haven't hit the max instruction count, continue processing the current
103565b40f27SMatt Arsenault     // segment.
103665b40f27SMatt Arsenault     while (CurrentIndex <= LRPosInfo[CurrentSegmentIndex].End &&
103765b40f27SMatt Arsenault            InstructionIndex < ModelMaxSupportedInstructionCount) {
103865b40f27SMatt Arsenault       int CurrentOpcode = GetOpcode(CurrentIndex);
103965b40f27SMatt Arsenault       // If the current machine instruction is null, skip it
104065b40f27SMatt Arsenault       if (CurrentOpcode == -1) {
104165b40f27SMatt Arsenault         // If we're currently at the last index in the SlotIndex analysis,
104265b40f27SMatt Arsenault         // we can't go any further, so return from the function
104365b40f27SMatt Arsenault         if (CurrentIndex >= LastIndex) {
104465b40f27SMatt Arsenault           return;
104565b40f27SMatt Arsenault         }
104665b40f27SMatt Arsenault         CurrentIndex = CurrentIndex.getNextIndex();
104765b40f27SMatt Arsenault         continue;
104865b40f27SMatt Arsenault       }
104965b40f27SMatt Arsenault       MachineBasicBlock *CurrentMBBReference = GetMBBReference(CurrentIndex);
105065b40f27SMatt Arsenault       if (VisitedMBBs.count(CurrentMBBReference) == 0) {
105165b40f27SMatt Arsenault         VisitedMBBs[CurrentMBBReference] = CurrentMBBIndex;
105265b40f27SMatt Arsenault         ++CurrentMBBIndex;
105365b40f27SMatt Arsenault       }
105465b40f27SMatt Arsenault       extractMBBFrequency(CurrentIndex, InstructionIndex, VisitedMBBs,
105565b40f27SMatt Arsenault                           GetMBBFreq, CurrentMBBReference, RegallocRunner,
105665b40f27SMatt Arsenault                           MBBFreqIndex, MBBMappingIndex);
105765b40f27SMatt Arsenault       // Current code assumes we're not going to get any disjointed segments
105865b40f27SMatt Arsenault       assert(LRPosInfo[CurrentSegmentIndex].Begin <= CurrentIndex);
105965b40f27SMatt Arsenault       RegallocRunner->getTensor<int64_t>(InstructionsIndex)[InstructionIndex] =
106065b40f27SMatt Arsenault           CurrentOpcode < OpcodeValueCutoff ? CurrentOpcode : 0;
106165b40f27SMatt Arsenault       // set value in the binary mapping matrix for the current instruction
106265b40f27SMatt Arsenault       auto CurrentSegmentPosition = LRPosInfo[CurrentSegmentIndex].Pos;
106365b40f27SMatt Arsenault       RegallocRunner->getTensor<int64_t>(
106465b40f27SMatt Arsenault           InstructionsMappingIndex)[CurrentSegmentPosition *
106565b40f27SMatt Arsenault                                         ModelMaxSupportedInstructionCount +
106665b40f27SMatt Arsenault                                     InstructionIndex] = 1;
106765b40f27SMatt Arsenault       // All of the segments are sorted based on the beginning slot index, but
106865b40f27SMatt Arsenault       // this doesn't mean that the beginning slot index of the next segment is
106965b40f27SMatt Arsenault       // after the end segment of the one being currently processed. This while
107065b40f27SMatt Arsenault       // loop checks for overlapping segments and modifies the portion of the
107165b40f27SMatt Arsenault       // column in the mapping matrix for the currently processed instruction
107265b40f27SMatt Arsenault       // for the LR it is checking. Also make sure that the beginning of the
107365b40f27SMatt Arsenault       // current segment we're checking for overlap in is less than the current
107465b40f27SMatt Arsenault       // index, otherwise we're done checking overlaps.
107565b40f27SMatt Arsenault       size_t OverlapCheckCurrentSegment = CurrentSegmentIndex + 1;
107665b40f27SMatt Arsenault       while (OverlapCheckCurrentSegment < LRPosInfo.size() &&
107765b40f27SMatt Arsenault              LRPosInfo[OverlapCheckCurrentSegment].Begin <= CurrentIndex) {
107865b40f27SMatt Arsenault         auto OverlapCurrentSegmentPosition =
107965b40f27SMatt Arsenault             LRPosInfo[OverlapCheckCurrentSegment].Pos;
108065b40f27SMatt Arsenault         if (LRPosInfo[OverlapCheckCurrentSegment].End >= CurrentIndex) {
108165b40f27SMatt Arsenault           RegallocRunner->getTensor<int64_t>(
108265b40f27SMatt Arsenault               InstructionsMappingIndex)[OverlapCurrentSegmentPosition *
108365b40f27SMatt Arsenault                                             ModelMaxSupportedInstructionCount +
108465b40f27SMatt Arsenault                                         InstructionIndex] = 1;
108565b40f27SMatt Arsenault         }
108665b40f27SMatt Arsenault         ++OverlapCheckCurrentSegment;
108765b40f27SMatt Arsenault       }
108865b40f27SMatt Arsenault       ++InstructionIndex;
108965b40f27SMatt Arsenault       if (CurrentIndex >= LastIndex) {
109065b40f27SMatt Arsenault         return;
109165b40f27SMatt Arsenault       }
109265b40f27SMatt Arsenault       CurrentIndex = CurrentIndex.getNextIndex();
109365b40f27SMatt Arsenault     }
109465b40f27SMatt Arsenault     // if we've just finished processing through the last segment or if we've
109565b40f27SMatt Arsenault     // hit the maximum number of instructions, break out of the loop.
109665b40f27SMatt Arsenault     if (CurrentSegmentIndex == LRPosInfo.size() - 1 ||
109765b40f27SMatt Arsenault         InstructionIndex >= ModelMaxSupportedInstructionCount) {
109865b40f27SMatt Arsenault       break;
109965b40f27SMatt Arsenault     }
110065b40f27SMatt Arsenault     // If the segments are not overlapping, we need to move to the beginning
110165b40f27SMatt Arsenault     // index of the next segment to avoid having instructions not attached to
110265b40f27SMatt Arsenault     // any register.
110365b40f27SMatt Arsenault     if (LRPosInfo[CurrentSegmentIndex + 1].Begin >
110465b40f27SMatt Arsenault         LRPosInfo[CurrentSegmentIndex].End) {
110565b40f27SMatt Arsenault       CurrentIndex = LRPosInfo[CurrentSegmentIndex + 1].Begin;
110665b40f27SMatt Arsenault     }
110765b40f27SMatt Arsenault     ++CurrentSegmentIndex;
110865b40f27SMatt Arsenault   }
110965b40f27SMatt Arsenault }
111065b40f27SMatt Arsenault 
11111753008bSRahul Joshi void llvm::extractMBBFrequency(
11121753008bSRahul Joshi     const SlotIndex CurrentIndex, const size_t CurrentInstructionIndex,
111365b40f27SMatt Arsenault     std::map<MachineBasicBlock *, size_t> &VisitedMBBs,
111465b40f27SMatt Arsenault     function_ref<float(SlotIndex)> GetMBBFreq,
11151753008bSRahul Joshi     MachineBasicBlock *CurrentMBBReference, MLModelRunner *RegallocRunner,
11161753008bSRahul Joshi     const int MBBFreqIndex, const int MBBMappingIndex) {
111765b40f27SMatt Arsenault   size_t CurrentMBBIndex = VisitedMBBs[CurrentMBBReference];
111865b40f27SMatt Arsenault   float CurrentMBBFreq = GetMBBFreq(CurrentIndex);
111965b40f27SMatt Arsenault   if (CurrentMBBIndex < ModelMaxSupportedMBBCount) {
112065b40f27SMatt Arsenault     RegallocRunner->getTensor<float>(MBBFreqIndex)[CurrentMBBIndex] =
112165b40f27SMatt Arsenault         CurrentMBBFreq;
112265b40f27SMatt Arsenault     RegallocRunner->getTensor<int64_t>(
112365b40f27SMatt Arsenault         MBBMappingIndex)[CurrentInstructionIndex] = CurrentMBBIndex;
112465b40f27SMatt Arsenault   }
112565b40f27SMatt Arsenault }
112665b40f27SMatt Arsenault 
112765b40f27SMatt Arsenault // Development mode-specific implementations
112865b40f27SMatt Arsenault #ifdef LLVM_HAVE_TFLITE
112965b40f27SMatt Arsenault 
113065b40f27SMatt Arsenault RegAllocEvictionAdvisorAnalysis *llvm::createDevelopmentModeAdvisor() {
113165b40f27SMatt Arsenault   return new DevelopmentModeEvictionAdvisorAnalysis();
113265b40f27SMatt Arsenault }
113365b40f27SMatt Arsenault 
113465b40f27SMatt Arsenault int64_t DevelopmentModeEvictAdvisor::tryFindEvictionCandidatePosition(
113565b40f27SMatt Arsenault     const LiveInterval &VirtReg, const AllocationOrder &Order,
113665b40f27SMatt Arsenault     unsigned OrderLimit, uint8_t CostPerUseLimit,
113765b40f27SMatt Arsenault     const SmallVirtRegSet &FixedRegisters) const {
113865b40f27SMatt Arsenault   int64_t Ret = 0;
113965b40f27SMatt Arsenault   if (isa<ModelUnderTrainingRunner>(getRunner())) {
114065b40f27SMatt Arsenault     Ret = MLEvictAdvisor::tryFindEvictionCandidatePosition(
114165b40f27SMatt Arsenault         VirtReg, Order, OrderLimit, CostPerUseLimit, FixedRegisters);
114265b40f27SMatt Arsenault   } else {
114365b40f27SMatt Arsenault     MCRegister PhysReg = getDefaultAdvisor().tryFindEvictionCandidate(
114465b40f27SMatt Arsenault         VirtReg, Order, CostPerUseLimit, FixedRegisters);
114565b40f27SMatt Arsenault     // Find the index of the selected PhysReg. We need it for logging,
114665b40f27SMatt Arsenault     // otherwise this is wasted cycles (but so would starting development mode
114765b40f27SMatt Arsenault     // without a model nor logging)
114865b40f27SMatt Arsenault     if (!PhysReg)
114965b40f27SMatt Arsenault       Ret = CandidateVirtRegPos;
115065b40f27SMatt Arsenault     else
115165b40f27SMatt Arsenault       for (auto I = Order.begin(), E = Order.getOrderLimitEnd(OrderLimit);
115265b40f27SMatt Arsenault            I != E; ++I, ++Ret)
115365b40f27SMatt Arsenault         if (*I == PhysReg)
115465b40f27SMatt Arsenault           break;
115565b40f27SMatt Arsenault   }
115665b40f27SMatt Arsenault   if (TrainingLog.empty())
115765b40f27SMatt Arsenault     return Ret;
115865b40f27SMatt Arsenault   // TODO(mtrofin): when we support optional rewards, this can go away. In the
115965b40f27SMatt Arsenault   // meantime, we log the "pretend" reward (0) for the previous observation
116065b40f27SMatt Arsenault   // before starting a new one.
116165b40f27SMatt Arsenault   if (Log->hasObservationInProgress())
116265b40f27SMatt Arsenault     Log->logReward<float>(0.0);
116365b40f27SMatt Arsenault 
116465b40f27SMatt Arsenault   Log->startObservation();
116565b40f27SMatt Arsenault   size_t CurrentFeature = 0;
116665b40f27SMatt Arsenault   size_t FeatureCount = EnableDevelopmentFeatures
116765b40f27SMatt Arsenault                             ? FeatureIDs::FeaturesWithDevelopmentCount
116865b40f27SMatt Arsenault                             : FeatureIDs::FeatureCount;
116965b40f27SMatt Arsenault   for (; CurrentFeature < FeatureCount; ++CurrentFeature) {
117065b40f27SMatt Arsenault     Log->logTensorValue(CurrentFeature,
117165b40f27SMatt Arsenault                         reinterpret_cast<const char *>(
117265b40f27SMatt Arsenault                             getRunner().getTensorUntyped(CurrentFeature)));
117365b40f27SMatt Arsenault   }
117465b40f27SMatt Arsenault   if (auto *MUTR = dyn_cast<ModelUnderTrainingRunner>(&getRunner()))
117565b40f27SMatt Arsenault     for (size_t I = 0; I < MUTR->extraOutputsForLoggingSpecs().size();
117665b40f27SMatt Arsenault          ++I, ++CurrentFeature)
117765b40f27SMatt Arsenault       Log->logTensorValue(
117865b40f27SMatt Arsenault           CurrentFeature,
117965b40f27SMatt Arsenault           reinterpret_cast<const char *>(MUTR->getUntypedExtraOutputValue(I)));
118065b40f27SMatt Arsenault   // The output is right after the features and the extra outputs
118165b40f27SMatt Arsenault   Log->logTensorValue(CurrentFeature, reinterpret_cast<const char *>(&Ret));
118265b40f27SMatt Arsenault   Log->endObservation();
118365b40f27SMatt Arsenault   return Ret;
118465b40f27SMatt Arsenault }
118565b40f27SMatt Arsenault 
118665b40f27SMatt Arsenault bool RegAllocScoring::runOnMachineFunction(MachineFunction &MF) {
118765b40f27SMatt Arsenault   std::optional<float> CachedReward;
118865b40f27SMatt Arsenault   auto GetReward = [&]() {
118965b40f27SMatt Arsenault     if (!CachedReward)
119065b40f27SMatt Arsenault       CachedReward = static_cast<float>(
119109989996Spaperchalice           calculateRegAllocScore(
119209989996Spaperchalice               MF, getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI())
119365b40f27SMatt Arsenault               .getScore());
119465b40f27SMatt Arsenault     return *CachedReward;
119565b40f27SMatt Arsenault   };
119665b40f27SMatt Arsenault 
119765b40f27SMatt Arsenault   getAnalysis<RegAllocEvictionAdvisorAnalysis>().logRewardIfNeeded(MF,
119865b40f27SMatt Arsenault                                                                    GetReward);
119965b40f27SMatt Arsenault   getAnalysis<RegAllocPriorityAdvisorAnalysis>().logRewardIfNeeded(MF,
120065b40f27SMatt Arsenault                                                                    GetReward);
120165b40f27SMatt Arsenault   return false;
120265b40f27SMatt Arsenault }
120365b40f27SMatt Arsenault #endif // #ifdef LLVM_HAVE_TFLITE
120465b40f27SMatt Arsenault 
120565b40f27SMatt Arsenault RegAllocEvictionAdvisorAnalysis *llvm::createReleaseModeAdvisor() {
120665b40f27SMatt Arsenault   return llvm::isEmbeddedModelEvaluatorValid<CompiledModelType>() ||
120765b40f27SMatt Arsenault                  !InteractiveChannelBaseName.empty()
120865b40f27SMatt Arsenault              ? new ReleaseModeEvictionAdvisorAnalysis()
120965b40f27SMatt Arsenault              : nullptr;
121065b40f27SMatt Arsenault }
121165b40f27SMatt Arsenault 
121265b40f27SMatt Arsenault // In all cases except development mode, we don't need scoring.
121365b40f27SMatt Arsenault #if !defined(LLVM_HAVE_TFLITE)
121465b40f27SMatt Arsenault bool RegAllocScoring::runOnMachineFunction(MachineFunction &) { return false; }
121565b40f27SMatt Arsenault #endif
1216