diff --git a/llvm/include/llvm/Analysis/InlineAdvisor.h b/llvm/include/llvm/Analysis/InlineAdvisor.h --- a/llvm/include/llvm/Analysis/InlineAdvisor.h +++ b/llvm/include/llvm/Analysis/InlineAdvisor.h @@ -40,6 +40,26 @@ /// training. enum class InliningAdvisorMode : int { Default, Release, Development }; +enum class InlineAdvisorContext : int { + // Each entry represent an inline driver that talks to InlineAdvisor interface + // for advices. + // Some inline passes (e.g., AlwaysInliner) call OptimizationRemarkEmitter + // directly, so no corresponding entries. + EarlyInliner, + CGSCCInliner, + ModuleInliner, + ReplayCGSCCInliner, + ReplaySampleProfileInliner, +}; + +/// Provides context on when an inline advisor is constructed in the pipeline +/// (e.g., link phase, inline driver). +struct InlineAdvisorParams { + ThinOrFullLTOPhase LTOPhase; + + InlineAdvisorContext Context; +}; + class InlineAdvisor; /// Capture state between an inlining decision having had been made, and /// its impact being observable. When collecting model training data, this @@ -170,14 +190,28 @@ OS << "Unimplemented InlineAdvisor print\n"; } + /// IMPORTANT: + /// + /// 1. Pass name is annotated only when `--annotate-inline-phase` is true and + /// inline advisor constructor provides InlineAdvisorParams. + /// 2. When annotated, The annotated inline pass name indicates the pass + /// instance where inline decision is made; however the specific pass instance + /// may not be the accurate reason. + /// For example, a inline decision in postlink CGSCC pass could be a result + /// of applying heuristics, but could be a result of mandatory inline as + /// well. + const char *getAnnotatedInlinePassName(); + protected: - InlineAdvisor(Module &M, FunctionAnalysisManager &FAM); + InlineAdvisor(Module &M, FunctionAnalysisManager &FAM, + Optional IAP = NoneType::None); virtual std::unique_ptr getAdviceImpl(CallBase &CB) = 0; virtual std::unique_ptr getMandatoryAdvice(CallBase &CB, bool Advice); Module &M; FunctionAnalysisManager &FAM; + const Optional IAP; std::unique_ptr ImportedFunctionsStats; enum class MandatoryInliningKind { NotMandatory, Always, Never }; diff --git a/llvm/lib/Analysis/InlineAdvisor.cpp b/llvm/lib/Analysis/InlineAdvisor.cpp --- a/llvm/lib/Analysis/InlineAdvisor.cpp +++ b/llvm/lib/Analysis/InlineAdvisor.cpp @@ -81,7 +81,8 @@ void recordUnsuccessfulInliningImpl(const InlineResult &Result) override { if (IsInliningRecommended) ORE.emit([&]() { - return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block) + return OptimizationRemarkMissed(Advisor->getAnnotatedInlinePassName(), + "NotInlined", DLoc, Block) << "'" << NV("Callee", Callee) << "' is not AlwaysInline into '" << NV("Caller", Caller) << "': " << NV("Reason", Result.getFailureReason()); @@ -100,7 +101,8 @@ llvm::setInlineRemark(*OriginalCB, std::string(Result.getFailureReason()) + "; " + inlineCostStr(*OIC)); ORE.emit([&]() { - return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block) + return OptimizationRemarkMissed(Advisor->getAnnotatedInlinePassName(), + "NotInlined", DLoc, Block) << "'" << NV("Callee", Callee) << "' is not inlined into '" << NV("Caller", Caller) << "': " << NV("Reason", Result.getFailureReason()); @@ -109,12 +111,16 @@ void DefaultInlineAdvice::recordInliningWithCalleeDeletedImpl() { if (EmitRemarks) - emitInlinedIntoBasedOnCost(ORE, DLoc, Block, *Callee, *Caller, *OIC); + emitInlinedIntoBasedOnCost(ORE, DLoc, Block, *Callee, *Caller, *OIC, + /* ForProfileContext= */ false, + Advisor->getAnnotatedInlinePassName()); } void DefaultInlineAdvice::recordInliningImpl() { if (EmitRemarks) - emitInlinedIntoBasedOnCost(ORE, DLoc, Block, *Callee, *Caller, *OIC); + emitInlinedIntoBasedOnCost(ORE, DLoc, Block, *Callee, *Caller, *OIC, + /* ForProfileContext= */ false, + Advisor->getAnnotatedInlinePassName()); } llvm::Optional static getDefaultInlineAdvice( @@ -500,8 +506,9 @@ PassName); } -InlineAdvisor::InlineAdvisor(Module &M, FunctionAnalysisManager &FAM) - : M(M), FAM(FAM) { +InlineAdvisor::InlineAdvisor(Module &M, FunctionAnalysisManager &FAM, + Optional IAP) + : M(M), FAM(FAM), IAP(IAP) { if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No) { ImportedFunctionsStats = std::make_unique(); @@ -523,6 +530,49 @@ Advice); } +static inline const char *getLTOPhase(ThinOrFullLTOPhase LTOPhase) { + switch (LTOPhase) { + case (ThinOrFullLTOPhase::None): + return "main"; + case (ThinOrFullLTOPhase::ThinLTOPreLink): + case (ThinOrFullLTOPhase::FullLTOPreLink): + return "prelink"; + case (ThinOrFullLTOPhase::ThinLTOPostLink): + case (ThinOrFullLTOPhase::FullLTOPostLink): + return "postlink"; + } + llvm_unreachable("unreachable"); +} + +static inline const char *getInlineAdvisorContext(InlineAdvisorContext IAC) { + switch (IAC) { + case (InlineAdvisorContext::EarlyInliner): + return "early-inline"; + case (InlineAdvisorContext::CGSCCInliner): + return "cgscc-inline"; + case (InlineAdvisorContext::ModuleInliner): + return "module-inline"; + case (InlineAdvisorContext::ReplayCGSCCInliner): + return "replay-cgscc-inline"; + case (InlineAdvisorContext::ReplaySampleProfileInliner): + return "replay-sample-profile-inline"; + } + llvm_unreachable("unreachable"); +} + +const char *InlineAdvisor::getAnnotatedInlinePassName() { + if (!IAP.hasValue()) + return DEBUG_TYPE; + + // IAP is constant and initialized in ctor, so compute the annotated name only + // once. + static const std::string PassName = + std::string(getLTOPhase(IAP.getValue().LTOPhase)) + "-" + + std::string(getInlineAdvisorContext(IAP.getValue().Context)); + + return PassName.c_str(); +} + InlineAdvisor::MandatoryInliningKind InlineAdvisor::getMandatoryKind(CallBase &CB, FunctionAnalysisManager &FAM, OptimizationRemarkEmitter &ORE) {