[InlineAdvisor] New inliner advisor to replay inlining from optimization remarks
This change added a new inline advisor that takes optimization remarks from previous inlining as input, and provides the decision as advice so current inlining can replay inline decisions of a different compilation. Dwarf inline stack with line and discriminator is used as anchor for call sites including call context. The change can be useful for Inliner tuning as it provides a channel to allow external input for tweaking inline decisions. Existing alternatives like alwaysinline attribute is per-function, not per-callsite. Per-callsite inline intrinsic can be another solution (not yet existing), but it's intrusive to implement and also does not differentiate call context.
A switch -sample-profile-inline-replay=<inline_remarks_file> is added to hook up the new inline advisor with SampleProfileLoader's inline decision for replay. Since SampleProfileLoader does top-down inlining, inline decision can be specialized for each call context, hence we should be able to replay inlining accurately. However with a bottom-up inliner like CGSCC inlining, the replay can be limited due to lack of specialization for different call context. Apart from that limitation, the new inline advisor can still be used by regular CGSCC inliner later if needed for tuning purpose.
This is a resubmit of https://reviews.llvm.org/D83743
diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index 8bb3769..f50439b 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -102,6 +102,7 @@
RegionPass.cpp
RegionPrinter.cpp
ReleaseModeModelRunner.cpp
+ ReplayInlineAdvisor.cpp
ScalarEvolution.cpp
ScalarEvolutionAliasAnalysis.cpp
ScalarEvolutionDivision.cpp
diff --git a/llvm/lib/Analysis/InlineAdvisor.cpp b/llvm/lib/Analysis/InlineAdvisor.cpp
index ee92450..960141d 100644
--- a/llvm/lib/Analysis/InlineAdvisor.cpp
+++ b/llvm/lib/Analysis/InlineAdvisor.cpp
@@ -371,9 +371,35 @@
return IC;
}
+std::string llvm::getCallSiteLocation(DebugLoc DLoc) {
+ std::ostringstream CallSiteLoc;
+ bool First = true;
+ for (DILocation *DIL = DLoc.get(); DIL; DIL = DIL->getInlinedAt()) {
+ if (!First)
+ CallSiteLoc << " @ ";
+ // Note that negative line offset is actually possible, but we use
+ // unsigned int to match line offset representation in remarks so
+ // it's directly consumable by relay advisor.
+ uint32_t Offset =
+ DIL->getLine() - DIL->getScope()->getSubprogram()->getLine();
+ uint32_t Discriminator = DIL->getBaseDiscriminator();
+ StringRef Name = DIL->getScope()->getSubprogram()->getLinkageName();
+ if (Name.empty())
+ Name = DIL->getScope()->getSubprogram()->getName();
+ CallSiteLoc << Name.str() << ":" << llvm::utostr(Offset);
+ if (Discriminator) {
+ CallSiteLoc << "." << llvm::utostr(Discriminator);
+ }
+ First = false;
+ }
+
+ return CallSiteLoc.str();
+}
+
void llvm::addLocationToRemarks(OptimizationRemark &Remark, DebugLoc DLoc) {
- if (!DLoc.get())
+ if (!DLoc.get()) {
return;
+ }
bool First = true;
Remark << " at callsite ";
diff --git a/llvm/lib/Analysis/ReplayInlineAdvisor.cpp b/llvm/lib/Analysis/ReplayInlineAdvisor.cpp
new file mode 100644
index 0000000..d2dd030
--- /dev/null
+++ b/llvm/lib/Analysis/ReplayInlineAdvisor.cpp
@@ -0,0 +1,60 @@
+//===- ReplayInlineAdvisor.cpp - Replay InlineAdvisor ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements ReplayInlineAdvisor that replays inline decision based
+// on previous inline remarks from optimization remark log.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/ReplayInlineAdvisor.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Support/LineIterator.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "inline-replay"
+
+ReplayInlineAdvisor::ReplayInlineAdvisor(FunctionAnalysisManager &FAM,
+ LLVMContext &Context,
+ StringRef RemarksFile)
+ : InlineAdvisor(FAM), HasReplayRemarks(false) {
+ auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(RemarksFile);
+ std::error_code EC = BufferOrErr.getError();
+ if (EC) {
+ Context.emitError("Could not open remarks file: " + EC.message());
+ return;
+ }
+
+ // Example for inline remarks to parse:
+ // _Z3subii inlined into main [details] at callsite sum:1 @ main:3.1
+ // We use the callsite string after `at callsite` to replay inlining.
+ line_iterator LineIt(*BufferOrErr.get(), /*SkipBlanks=*/true);
+ for (; !LineIt.is_at_eof(); ++LineIt) {
+ StringRef Line = *LineIt;
+ auto Pair = Line.split(" at callsite ");
+ if (Pair.second.empty())
+ continue;
+ InlineSitesFromRemarks.insert(Pair.second);
+ }
+ HasReplayRemarks = true;
+}
+
+std::unique_ptr<InlineAdvice> ReplayInlineAdvisor::getAdvice(CallBase &CB) {
+ assert(HasReplayRemarks);
+
+ Function &Caller = *CB.getCaller();
+ auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(Caller);
+
+ if (InlineSitesFromRemarks.empty())
+ return std::make_unique<InlineAdvice>(this, CB, ORE, false);
+
+ std::string CallSiteLoc = getCallSiteLocation(CB.getDebugLoc());
+ bool InlineRecommended = InlineSitesFromRemarks.count(CallSiteLoc) > 0;
+ return std::make_unique<InlineAdvice>(this, CB, ORE, InlineRecommended);
+}