llvm-project

Форк
0
/
MLInlineAdvisor.cpp 
571 строка · 22.1 Кб
1
//===- MLInlineAdvisor.cpp - machine learned InlineAdvisor ----------------===//
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
// This file implements the interface between the inliner and a learned model.
10
// It delegates model evaluation to either the AOT compiled model (the
11
// 'release' mode) or a runtime-loaded model (the 'development' case).
12
//
13
//===----------------------------------------------------------------------===//
14
#include "llvm/Analysis/MLInlineAdvisor.h"
15
#include "llvm/ADT/SCCIterator.h"
16
#include "llvm/Analysis/AssumptionCache.h"
17
#include "llvm/Analysis/BlockFrequencyInfo.h"
18
#include "llvm/Analysis/CallGraph.h"
19
#include "llvm/Analysis/FunctionPropertiesAnalysis.h"
20
#include "llvm/Analysis/InlineCost.h"
21
#include "llvm/Analysis/InlineModelFeatureMaps.h"
22
#include "llvm/Analysis/InteractiveModelRunner.h"
23
#include "llvm/Analysis/LazyCallGraph.h"
24
#include "llvm/Analysis/LoopInfo.h"
25
#include "llvm/Analysis/MLModelRunner.h"
26
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
27
#include "llvm/Analysis/ProfileSummaryInfo.h"
28
#include "llvm/Analysis/ReleaseModeModelRunner.h"
29
#include "llvm/Analysis/TargetTransformInfo.h"
30
#include "llvm/IR/Dominators.h"
31
#include "llvm/IR/InstIterator.h"
32
#include "llvm/IR/Module.h"
33
#include "llvm/IR/PassManager.h"
34
#include "llvm/Support/CommandLine.h"
35

36
using namespace llvm;
37

38
static cl::opt<std::string> InteractiveChannelBaseName(
39
    "inliner-interactive-channel-base", cl::Hidden,
40
    cl::desc(
41
        "Base file path for the interactive mode. The incoming filename should "
42
        "have the name <inliner-interactive-channel-base>.in, while the "
43
        "outgoing name should be <inliner-interactive-channel-base>.out"));
44
static const std::string InclDefaultMsg =
45
    (Twine("In interactive mode, also send the default policy decision: ") +
46
     DefaultDecisionName + ".")
47
        .str();
48
static cl::opt<bool>
49
    InteractiveIncludeDefault("inliner-interactive-include-default", cl::Hidden,
50
                              cl::desc(InclDefaultMsg));
51

52
enum class SkipMLPolicyCriteria { Never, IfCallerIsNotCold };
53

54
static cl::opt<SkipMLPolicyCriteria> SkipPolicy(
55
    "ml-inliner-skip-policy", cl::Hidden, cl::init(SkipMLPolicyCriteria::Never),
56
    cl::values(clEnumValN(SkipMLPolicyCriteria::Never, "never", "never"),
57
               clEnumValN(SkipMLPolicyCriteria::IfCallerIsNotCold,
58
                          "if-caller-not-cold", "if the caller is not cold")));
59

60
static cl::opt<std::string> ModelSelector("ml-inliner-model-selector",
61
                                          cl::Hidden, cl::init(""));
62

63
#if defined(LLVM_HAVE_TF_AOT_INLINERSIZEMODEL)
64
// codegen-ed file
65
#include "InlinerSizeModel.h" // NOLINT
66
using CompiledModelType = llvm::InlinerSizeModel;
67
#else
68
using CompiledModelType = NoopSavedModelImpl;
69
#endif
70

71
std::unique_ptr<InlineAdvisor>
72
llvm::getReleaseModeAdvisor(Module &M, ModuleAnalysisManager &MAM,
73
                            std::function<bool(CallBase &)> GetDefaultAdvice) {
74
  if (!llvm::isEmbeddedModelEvaluatorValid<CompiledModelType>() &&
75
      InteractiveChannelBaseName.empty())
76
    return nullptr;
77
  std::unique_ptr<MLModelRunner> AOTRunner;
78
  if (InteractiveChannelBaseName.empty())
79
    AOTRunner = std::make_unique<ReleaseModeModelRunner<CompiledModelType>>(
80
        M.getContext(), FeatureMap, DecisionName,
81
        EmbeddedModelRunnerOptions().setModelSelector(ModelSelector));
82
  else {
83
    auto Features = FeatureMap;
84
    if (InteractiveIncludeDefault)
85
      Features.push_back(DefaultDecisionSpec);
86
    AOTRunner = std::make_unique<InteractiveModelRunner>(
87
        M.getContext(), Features, InlineDecisionSpec,
88
        InteractiveChannelBaseName + ".out",
89
        InteractiveChannelBaseName + ".in");
90
  }
91
  return std::make_unique<MLInlineAdvisor>(M, MAM, std::move(AOTRunner),
92
                                           GetDefaultAdvice);
93
}
94

95
#define DEBUG_TYPE "inline-ml"
96

97
static cl::opt<float> SizeIncreaseThreshold(
98
    "ml-advisor-size-increase-threshold", cl::Hidden,
99
    cl::desc("Maximum factor by which expected native size may increase before "
100
             "blocking any further inlining."),
101
    cl::init(2.0));
102

103
static cl::opt<bool> KeepFPICache(
104
    "ml-advisor-keep-fpi-cache", cl::Hidden,
105
    cl::desc(
106
        "For test - keep the ML Inline advisor's FunctionPropertiesInfo cache"),
107
    cl::init(false));
108

109
// clang-format off
110
const std::vector<TensorSpec> llvm::FeatureMap{
111
#define POPULATE_NAMES(DTYPE, SHAPE, NAME, __) TensorSpec::createSpec<DTYPE>(#NAME, SHAPE),
112
// InlineCost features - these must come first
113
  INLINE_COST_FEATURE_ITERATOR(POPULATE_NAMES)
114

115
// Non-cost features
116
  INLINE_FEATURE_ITERATOR(POPULATE_NAMES)
117
#undef POPULATE_NAMES
118
};
119
// clang-format on
120

121
const char *const llvm::DecisionName = "inlining_decision";
122
const TensorSpec llvm::InlineDecisionSpec =
123
    TensorSpec::createSpec<int64_t>(DecisionName, {1});
124
const char *const llvm::DefaultDecisionName = "inlining_default";
125
const TensorSpec llvm::DefaultDecisionSpec =
126
    TensorSpec::createSpec<int64_t>(DefaultDecisionName, {1});
127
const char *const llvm::RewardName = "delta_size";
128

129
CallBase *getInlinableCS(Instruction &I) {
130
  if (auto *CS = dyn_cast<CallBase>(&I))
131
    if (Function *Callee = CS->getCalledFunction()) {
132
      if (!Callee->isDeclaration()) {
133
        return CS;
134
      }
135
    }
136
  return nullptr;
137
}
138

139
MLInlineAdvisor::MLInlineAdvisor(
140
    Module &M, ModuleAnalysisManager &MAM,
141
    std::unique_ptr<MLModelRunner> Runner,
142
    std::function<bool(CallBase &)> GetDefaultAdvice)
143
    : InlineAdvisor(
144
          M, MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager()),
145
      ModelRunner(std::move(Runner)), GetDefaultAdvice(GetDefaultAdvice),
146
      CG(MAM.getResult<LazyCallGraphAnalysis>(M)),
147
      InitialIRSize(getModuleIRSize()), CurrentIRSize(InitialIRSize),
148
      PSI(MAM.getResult<ProfileSummaryAnalysis>(M)) {
149
  assert(ModelRunner);
150
  ModelRunner->switchContext("");
151
  // Extract the 'call site height' feature - the position of a call site
152
  // relative to the farthest statically reachable SCC node. We don't mutate
153
  // this value while inlining happens. Empirically, this feature proved
154
  // critical in behavioral cloning - i.e. training a model to mimic the manual
155
  // heuristic's decisions - and, thus, equally important for training for
156
  // improvement.
157
  CallGraph CGraph(M);
158
  for (auto I = scc_begin(&CGraph); !I.isAtEnd(); ++I) {
159
    const std::vector<CallGraphNode *> &CGNodes = *I;
160
    unsigned Level = 0;
161
    for (auto *CGNode : CGNodes) {
162
      Function *F = CGNode->getFunction();
163
      if (!F || F->isDeclaration())
164
        continue;
165
      for (auto &I : instructions(F)) {
166
        if (auto *CS = getInlinableCS(I)) {
167
          auto *Called = CS->getCalledFunction();
168
          auto Pos = FunctionLevels.find(&CG.get(*Called));
169
          // In bottom up traversal, an inlinable callee is either in the
170
          // same SCC, or to a function in a visited SCC. So not finding its
171
          // level means we haven't visited it yet, meaning it's in this SCC.
172
          if (Pos == FunctionLevels.end())
173
            continue;
174
          Level = std::max(Level, Pos->second + 1);
175
        }
176
      }
177
    }
178
    for (auto *CGNode : CGNodes) {
179
      Function *F = CGNode->getFunction();
180
      if (F && !F->isDeclaration())
181
        FunctionLevels[&CG.get(*F)] = Level;
182
    }
183
  }
184
  for (auto KVP : FunctionLevels) {
185
    AllNodes.insert(KVP.first);
186
    EdgeCount += getLocalCalls(KVP.first->getFunction());
187
  }
188
  NodeCount = AllNodes.size();
189
}
190

191
unsigned MLInlineAdvisor::getInitialFunctionLevel(const Function &F) const {
192
  return CG.lookup(F) ? FunctionLevels.at(CG.lookup(F)) : 0;
193
}
194

195
void MLInlineAdvisor::onPassEntry(LazyCallGraph::SCC *CurSCC) {
196
  if (!CurSCC || ForceStop)
197
    return;
198
  FPICache.clear();
199
  // Function passes executed between InlinerPass runs may have changed the
200
  // module-wide features.
201
  // The cgscc pass manager rules are such that:
202
  // - if a pass leads to merging SCCs, then the pipeline is restarted on the
203
  // merged SCC
204
  // - if a pass leads to splitting the SCC, then we continue with one of the
205
  // splits
206
  // This means that the NodesInLastSCC is a superset (not strict) of the nodes
207
  // that subsequent passes would have processed
208
  // - in addition, if new Nodes were created by a pass (e.g. CoroSplit),
209
  // they'd be adjacent to Nodes in the last SCC. So we just need to check the
210
  // boundary of Nodes in NodesInLastSCC for Nodes we haven't seen. We don't
211
  // care about the nature of the Edge (call or ref). `FunctionLevels`-wise, we
212
  // record them at the same level as the original node (this is a choice, may
213
  // need revisiting).
214
  // - nodes are only deleted at the end of a call graph walk where they are
215
  // batch deleted, so we shouldn't see any dead nodes here.
216
  while (!NodesInLastSCC.empty()) {
217
    const auto *N = *NodesInLastSCC.begin();
218
    assert(!N->isDead());
219
    NodesInLastSCC.erase(N);
220
    EdgeCount += getLocalCalls(N->getFunction());
221
    const auto NLevel = FunctionLevels.at(N);
222
    for (const auto &E : *(*N)) {
223
      const auto *AdjNode = &E.getNode();
224
      assert(!AdjNode->isDead() && !AdjNode->getFunction().isDeclaration());
225
      auto I = AllNodes.insert(AdjNode);
226
      // We've discovered a new function.
227
      if (I.second) {
228
        ++NodeCount;
229
        NodesInLastSCC.insert(AdjNode);
230
        FunctionLevels[AdjNode] = NLevel;
231
      }
232
    }
233
  }
234

235
  EdgeCount -= EdgesOfLastSeenNodes;
236
  EdgesOfLastSeenNodes = 0;
237

238
  // (Re)use NodesInLastSCC to remember the nodes in the SCC right now,
239
  // in case the SCC is split before onPassExit and some nodes are split out
240
  assert(NodesInLastSCC.empty());
241
  for (const auto &N : *CurSCC)
242
    NodesInLastSCC.insert(&N);
243
}
244

245
void MLInlineAdvisor::onPassExit(LazyCallGraph::SCC *CurSCC) {
246
  // No need to keep this around - function passes will invalidate it.
247
  if (!KeepFPICache)
248
    FPICache.clear();
249
  if (!CurSCC || ForceStop)
250
    return;
251
  // Keep track of the nodes and edges we last saw. Then, in onPassEntry,
252
  // we update the node count and edge count from the subset of these nodes that
253
  // survived.
254
  EdgesOfLastSeenNodes = 0;
255

256
  // Check on nodes that were in SCC onPassEntry
257
  for (const LazyCallGraph::Node *N : NodesInLastSCC) {
258
    assert(!N->isDead());
259
    EdgesOfLastSeenNodes += getLocalCalls(N->getFunction());
260
  }
261

262
  // Check on nodes that may have got added to SCC
263
  for (const auto &N : *CurSCC) {
264
    assert(!N.isDead());
265
    auto I = NodesInLastSCC.insert(&N);
266
    if (I.second)
267
      EdgesOfLastSeenNodes += getLocalCalls(N.getFunction());
268
  }
269
  assert(NodeCount >= NodesInLastSCC.size());
270
  assert(EdgeCount >= EdgesOfLastSeenNodes);
271
}
272

273
int64_t MLInlineAdvisor::getLocalCalls(Function &F) {
274
  return getCachedFPI(F).DirectCallsToDefinedFunctions;
275
}
276

277
// Update the internal state of the advisor, and force invalidate feature
278
// analysis. Currently, we maintain minimal (and very simple) global state - the
279
// number of functions and the number of static calls. We also keep track of the
280
// total IR size in this module, to stop misbehaving policies at a certain bloat
281
// factor (SizeIncreaseThreshold)
282
void MLInlineAdvisor::onSuccessfulInlining(const MLInlineAdvice &Advice,
283
                                           bool CalleeWasDeleted) {
284
  assert(!ForceStop);
285
  Function *Caller = Advice.getCaller();
286
  Function *Callee = Advice.getCallee();
287
  // The caller features aren't valid anymore.
288
  {
289
    PreservedAnalyses PA = PreservedAnalyses::all();
290
    PA.abandon<FunctionPropertiesAnalysis>();
291
    PA.abandon<DominatorTreeAnalysis>();
292
    PA.abandon<LoopAnalysis>();
293
    FAM.invalidate(*Caller, PA);
294
  }
295
  Advice.updateCachedCallerFPI(FAM);
296
  int64_t IRSizeAfter =
297
      getIRSize(*Caller) + (CalleeWasDeleted ? 0 : Advice.CalleeIRSize);
298
  CurrentIRSize += IRSizeAfter - (Advice.CallerIRSize + Advice.CalleeIRSize);
299
  if (CurrentIRSize > SizeIncreaseThreshold * InitialIRSize)
300
    ForceStop = true;
301

302
  // We can delta-update module-wide features. We know the inlining only changed
303
  // the caller, and maybe the callee (by deleting the latter).
304
  // Nodes are simple to update.
305
  // For edges, we 'forget' the edges that the caller and callee used to have
306
  // before inlining, and add back what they currently have together.
307
  int64_t NewCallerAndCalleeEdges =
308
      getCachedFPI(*Caller).DirectCallsToDefinedFunctions;
309

310
  // A dead function's node is not actually removed from the call graph until
311
  // the end of the call graph walk, but the node no longer belongs to any valid
312
  // SCC.
313
  if (CalleeWasDeleted) {
314
    --NodeCount;
315
    NodesInLastSCC.erase(CG.lookup(*Callee));
316
    DeadFunctions.insert(Callee);
317
  } else {
318
    NewCallerAndCalleeEdges +=
319
        getCachedFPI(*Callee).DirectCallsToDefinedFunctions;
320
  }
321
  EdgeCount += (NewCallerAndCalleeEdges - Advice.CallerAndCalleeEdges);
322
  assert(CurrentIRSize >= 0 && EdgeCount >= 0 && NodeCount >= 0);
323
}
324

325
int64_t MLInlineAdvisor::getModuleIRSize() const {
326
  int64_t Ret = 0;
327
  for (auto &F : M)
328
    if (!F.isDeclaration())
329
      Ret += getIRSize(F);
330
  return Ret;
331
}
332

333
FunctionPropertiesInfo &MLInlineAdvisor::getCachedFPI(Function &F) const {
334
  auto InsertPair =
335
      FPICache.insert(std::make_pair(&F, FunctionPropertiesInfo()));
336
  if (!InsertPair.second)
337
    return InsertPair.first->second;
338
  InsertPair.first->second = FAM.getResult<FunctionPropertiesAnalysis>(F);
339
  return InsertPair.first->second;
340
}
341

342
std::unique_ptr<InlineAdvice> MLInlineAdvisor::getAdviceImpl(CallBase &CB) {
343
  if (auto Skip = getSkipAdviceIfUnreachableCallsite(CB))
344
    return Skip;
345

346
  auto &Caller = *CB.getCaller();
347
  auto &Callee = *CB.getCalledFunction();
348

349
  auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {
350
    return FAM.getResult<AssumptionAnalysis>(F);
351
  };
352
  auto &TIR = FAM.getResult<TargetIRAnalysis>(Callee);
353
  auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(Caller);
354

355
  if (SkipPolicy == SkipMLPolicyCriteria::IfCallerIsNotCold) {
356
    if (!PSI.isFunctionEntryCold(&Caller))
357
      return std::make_unique<InlineAdvice>(this, CB, ORE,
358
                                            GetDefaultAdvice(CB));
359
  }
360
  auto MandatoryKind = InlineAdvisor::getMandatoryKind(CB, FAM, ORE);
361
  // If this is a "never inline" case, there won't be any changes to internal
362
  // state we need to track, so we can just return the base InlineAdvice, which
363
  // will do nothing interesting.
364
  // Same thing if this is a recursive case.
365
  if (MandatoryKind == InlineAdvisor::MandatoryInliningKind::Never ||
366
      &Caller == &Callee)
367
    return getMandatoryAdvice(CB, false);
368

369
  bool Mandatory =
370
      MandatoryKind == InlineAdvisor::MandatoryInliningKind::Always;
371

372
  // If we need to stop, we won't want to track anymore any state changes, so
373
  // we just return the base InlineAdvice, which acts as a noop.
374
  if (ForceStop) {
375
    ORE.emit([&] {
376
      return OptimizationRemarkMissed(DEBUG_TYPE, "ForceStop", &CB)
377
             << "Won't attempt inlining because module size grew too much.";
378
    });
379
    return std::make_unique<InlineAdvice>(this, CB, ORE, Mandatory);
380
  }
381

382
  int CostEstimate = 0;
383
  if (!Mandatory) {
384
    auto IsCallSiteInlinable =
385
        llvm::getInliningCostEstimate(CB, TIR, GetAssumptionCache);
386
    if (!IsCallSiteInlinable) {
387
      // We can't inline this for correctness reasons, so return the base
388
      // InlineAdvice, as we don't care about tracking any state changes (which
389
      // won't happen).
390
      return std::make_unique<InlineAdvice>(this, CB, ORE, false);
391
    }
392
    CostEstimate = *IsCallSiteInlinable;
393
  }
394

395
  const auto CostFeatures =
396
      llvm::getInliningCostFeatures(CB, TIR, GetAssumptionCache);
397
  if (!CostFeatures) {
398
    return std::make_unique<InlineAdvice>(this, CB, ORE, false);
399
  }
400

401
  if (Mandatory)
402
    return getMandatoryAdvice(CB, true);
403

404
  auto NrCtantParams = 0;
405
  for (auto I = CB.arg_begin(), E = CB.arg_end(); I != E; ++I) {
406
    NrCtantParams += (isa<Constant>(*I));
407
  }
408

409
  auto &CallerBefore = getCachedFPI(Caller);
410
  auto &CalleeBefore = getCachedFPI(Callee);
411

412
  *ModelRunner->getTensor<int64_t>(FeatureIndex::callee_basic_block_count) =
413
      CalleeBefore.BasicBlockCount;
414
  *ModelRunner->getTensor<int64_t>(FeatureIndex::callsite_height) =
415
      getInitialFunctionLevel(Caller);
416
  *ModelRunner->getTensor<int64_t>(FeatureIndex::node_count) = NodeCount;
417
  *ModelRunner->getTensor<int64_t>(FeatureIndex::nr_ctant_params) =
418
      NrCtantParams;
419
  *ModelRunner->getTensor<int64_t>(FeatureIndex::edge_count) = EdgeCount;
420
  *ModelRunner->getTensor<int64_t>(FeatureIndex::caller_users) =
421
      CallerBefore.Uses;
422
  *ModelRunner->getTensor<int64_t>(
423
      FeatureIndex::caller_conditionally_executed_blocks) =
424
      CallerBefore.BlocksReachedFromConditionalInstruction;
425
  *ModelRunner->getTensor<int64_t>(FeatureIndex::caller_basic_block_count) =
426
      CallerBefore.BasicBlockCount;
427
  *ModelRunner->getTensor<int64_t>(
428
      FeatureIndex::callee_conditionally_executed_blocks) =
429
      CalleeBefore.BlocksReachedFromConditionalInstruction;
430
  *ModelRunner->getTensor<int64_t>(FeatureIndex::callee_users) =
431
      CalleeBefore.Uses;
432
  *ModelRunner->getTensor<int64_t>(FeatureIndex::cost_estimate) = CostEstimate;
433
  *ModelRunner->getTensor<int64_t>(FeatureIndex::is_callee_avail_external) =
434
      Callee.hasAvailableExternallyLinkage();
435
  *ModelRunner->getTensor<int64_t>(FeatureIndex::is_caller_avail_external) =
436
      Caller.hasAvailableExternallyLinkage();
437

438
  // Add the cost features
439
  for (size_t I = 0;
440
       I < static_cast<size_t>(InlineCostFeatureIndex::NumberOfFeatures); ++I) {
441
    *ModelRunner->getTensor<int64_t>(inlineCostFeatureToMlFeature(
442
        static_cast<InlineCostFeatureIndex>(I))) = CostFeatures->at(I);
443
  }
444
  // This one would have been set up to be right at the end.
445
  if (!InteractiveChannelBaseName.empty() && InteractiveIncludeDefault)
446
    *ModelRunner->getTensor<int64_t>(InlineCostFeatureIndex::NumberOfFeatures) =
447
        GetDefaultAdvice(CB);
448
  return getAdviceFromModel(CB, ORE);
449
}
450

451
std::unique_ptr<MLInlineAdvice>
452
MLInlineAdvisor::getAdviceFromModel(CallBase &CB,
453
                                    OptimizationRemarkEmitter &ORE) {
454
  return std::make_unique<MLInlineAdvice>(
455
      this, CB, ORE, static_cast<bool>(ModelRunner->evaluate<int64_t>()));
456
}
457

458
std::unique_ptr<InlineAdvice>
459
MLInlineAdvisor::getSkipAdviceIfUnreachableCallsite(CallBase &CB) {
460
  if (!FAM.getResult<DominatorTreeAnalysis>(*CB.getCaller())
461
           .isReachableFromEntry(CB.getParent()))
462
    return std::make_unique<InlineAdvice>(this, CB, getCallerORE(CB), false);
463
  return nullptr;
464
}
465

466
std::unique_ptr<InlineAdvice> MLInlineAdvisor::getMandatoryAdvice(CallBase &CB,
467
                                                                  bool Advice) {
468
  // Make sure we track inlinings in all cases - mandatory or not.
469
  if (auto Skip = getSkipAdviceIfUnreachableCallsite(CB))
470
    return Skip;
471
  if (Advice && !ForceStop)
472
    return getMandatoryAdviceImpl(CB);
473

474
  // If this is a "never inline" case, there won't be any changes to internal
475
  // state we need to track, so we can just return the base InlineAdvice, which
476
  // will do nothing interesting.
477
  // Same if we are forced to stop - we don't track anymore.
478
  return std::make_unique<InlineAdvice>(this, CB, getCallerORE(CB), Advice);
479
}
480

481
std::unique_ptr<MLInlineAdvice>
482
MLInlineAdvisor::getMandatoryAdviceImpl(CallBase &CB) {
483
  return std::make_unique<MLInlineAdvice>(this, CB, getCallerORE(CB), true);
484
}
485

486
void MLInlineAdvisor::print(raw_ostream &OS) const {
487
  OS << "[MLInlineAdvisor] Nodes: " << NodeCount << " Edges: " << EdgeCount
488
     << " EdgesOfLastSeenNodes: " << EdgesOfLastSeenNodes << "\n";
489
  OS << "[MLInlineAdvisor] FPI:\n";
490
  for (auto I : FPICache) {
491
    OS << I.first->getName() << ":\n";
492
    I.second.print(OS);
493
    OS << "\n";
494
  }
495
  OS << "\n";
496
  OS << "[MLInlineAdvisor] FuncLevels:\n";
497
  for (auto I : FunctionLevels)
498
    OS << (DeadFunctions.contains(&I.first->getFunction())
499
               ? "<deleted>"
500
               : I.first->getFunction().getName())
501
       << " : " << I.second << "\n";
502

503
  OS << "\n";
504
}
505

506
MLInlineAdvice::MLInlineAdvice(MLInlineAdvisor *Advisor, CallBase &CB,
507
                               OptimizationRemarkEmitter &ORE,
508
                               bool Recommendation)
509
    : InlineAdvice(Advisor, CB, ORE, Recommendation),
510
      CallerIRSize(Advisor->isForcedToStop() ? 0 : Advisor->getIRSize(*Caller)),
511
      CalleeIRSize(Advisor->isForcedToStop() ? 0 : Advisor->getIRSize(*Callee)),
512
      CallerAndCalleeEdges(Advisor->isForcedToStop()
513
                               ? 0
514
                               : (Advisor->getLocalCalls(*Caller) +
515
                                  Advisor->getLocalCalls(*Callee))),
516
      PreInlineCallerFPI(Advisor->getCachedFPI(*Caller)) {
517
  if (Recommendation)
518
    FPU.emplace(Advisor->getCachedFPI(*getCaller()), CB);
519
}
520

521
void MLInlineAdvice::reportContextForRemark(
522
    DiagnosticInfoOptimizationBase &OR) {
523
  using namespace ore;
524
  OR << NV("Callee", Callee->getName());
525
  for (size_t I = 0; I < NumberOfFeatures; ++I)
526
    OR << NV(FeatureMap[I].name(),
527
             *getAdvisor()->getModelRunner().getTensor<int64_t>(I));
528
  OR << NV("ShouldInline", isInliningRecommended());
529
}
530

531
void MLInlineAdvice::updateCachedCallerFPI(FunctionAnalysisManager &FAM) const {
532
  FPU->finish(FAM);
533
}
534

535
void MLInlineAdvice::recordInliningImpl() {
536
  ORE.emit([&]() {
537
    OptimizationRemark R(DEBUG_TYPE, "InliningSuccess", DLoc, Block);
538
    reportContextForRemark(R);
539
    return R;
540
  });
541
  getAdvisor()->onSuccessfulInlining(*this, /*CalleeWasDeleted*/ false);
542
}
543

544
void MLInlineAdvice::recordInliningWithCalleeDeletedImpl() {
545
  ORE.emit([&]() {
546
    OptimizationRemark R(DEBUG_TYPE, "InliningSuccessWithCalleeDeleted", DLoc,
547
                         Block);
548
    reportContextForRemark(R);
549
    return R;
550
  });
551
  getAdvisor()->onSuccessfulInlining(*this, /*CalleeWasDeleted*/ true);
552
}
553

554
void MLInlineAdvice::recordUnsuccessfulInliningImpl(
555
    const InlineResult &Result) {
556
  getAdvisor()->getCachedFPI(*Caller) = PreInlineCallerFPI;
557
  ORE.emit([&]() {
558
    OptimizationRemarkMissed R(DEBUG_TYPE, "InliningAttemptedAndUnsuccessful",
559
                               DLoc, Block);
560
    reportContextForRemark(R);
561
    return R;
562
  });
563
}
564
void MLInlineAdvice::recordUnattemptedInliningImpl() {
565
  assert(!FPU);
566
  ORE.emit([&]() {
567
    OptimizationRemarkMissed R(DEBUG_TYPE, "IniningNotAttempted", DLoc, Block);
568
    reportContextForRemark(R);
569
    return R;
570
  });
571
}
572

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.