1e8d8bef9SDimitry Andric //===- ReplayInlineAdvisor.cpp - Replay InlineAdvisor ---------------------===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric // 9e8d8bef9SDimitry Andric // This file implements ReplayInlineAdvisor that replays inline decisions based 10e8d8bef9SDimitry Andric // on previous inline remarks from optimization remark log. This is a best 11e8d8bef9SDimitry Andric // effort approach useful for testing compiler/source changes while holding 12e8d8bef9SDimitry Andric // inlining steady. 13e8d8bef9SDimitry Andric // 14e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 15e8d8bef9SDimitry Andric 16e8d8bef9SDimitry Andric #include "llvm/Analysis/ReplayInlineAdvisor.h" 17e8d8bef9SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 18e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h" 19e8d8bef9SDimitry Andric #include "llvm/Support/LineIterator.h" 20349cc55cSDimitry Andric #include <memory> 21e8d8bef9SDimitry Andric 22e8d8bef9SDimitry Andric using namespace llvm; 23e8d8bef9SDimitry Andric 24349cc55cSDimitry Andric #define DEBUG_TYPE "replay-inline" 25e8d8bef9SDimitry Andric 26e8d8bef9SDimitry Andric ReplayInlineAdvisor::ReplayInlineAdvisor( 27e8d8bef9SDimitry Andric Module &M, FunctionAnalysisManager &FAM, LLVMContext &Context, 28349cc55cSDimitry Andric std::unique_ptr<InlineAdvisor> OriginalAdvisor, 29349cc55cSDimitry Andric const ReplayInlinerSettings &ReplaySettings, bool EmitRemarks) 30e8d8bef9SDimitry Andric : InlineAdvisor(M, FAM), OriginalAdvisor(std::move(OriginalAdvisor)), 31*04eeddc0SDimitry Andric ReplaySettings(ReplaySettings), EmitRemarks(EmitRemarks) { 32349cc55cSDimitry Andric 33349cc55cSDimitry Andric auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(ReplaySettings.ReplayFile); 34e8d8bef9SDimitry Andric std::error_code EC = BufferOrErr.getError(); 35e8d8bef9SDimitry Andric if (EC) { 36e8d8bef9SDimitry Andric Context.emitError("Could not open remarks file: " + EC.message()); 37e8d8bef9SDimitry Andric return; 38e8d8bef9SDimitry Andric } 39e8d8bef9SDimitry Andric 40e8d8bef9SDimitry Andric // Example for inline remarks to parse: 41349cc55cSDimitry Andric // main:3:1.1: '_Z3subii' inlined into 'main' at callsite sum:1 @ 42349cc55cSDimitry Andric // main:3:1.1; 43e8d8bef9SDimitry Andric // We use the callsite string after `at callsite` to replay inlining. 44e8d8bef9SDimitry Andric line_iterator LineIt(*BufferOrErr.get(), /*SkipBlanks=*/true); 45349cc55cSDimitry Andric const std::string PositiveRemark = "' inlined into '"; 46349cc55cSDimitry Andric const std::string NegativeRemark = "' will not be inlined into '"; 47349cc55cSDimitry Andric 48e8d8bef9SDimitry Andric for (; !LineIt.is_at_eof(); ++LineIt) { 49e8d8bef9SDimitry Andric StringRef Line = *LineIt; 50e8d8bef9SDimitry Andric auto Pair = Line.split(" at callsite "); 51e8d8bef9SDimitry Andric 52349cc55cSDimitry Andric bool IsPositiveRemark = true; 53349cc55cSDimitry Andric if (Pair.first.contains(NegativeRemark)) 54349cc55cSDimitry Andric IsPositiveRemark = false; 55349cc55cSDimitry Andric 56349cc55cSDimitry Andric auto CalleeCaller = 57349cc55cSDimitry Andric Pair.first.split(IsPositiveRemark ? PositiveRemark : NegativeRemark); 58349cc55cSDimitry Andric 59349cc55cSDimitry Andric StringRef Callee = CalleeCaller.first.rsplit(": '").second; 60349cc55cSDimitry Andric StringRef Caller = CalleeCaller.second.rsplit("'").first; 61e8d8bef9SDimitry Andric 62e8d8bef9SDimitry Andric auto CallSite = Pair.second.split(";").first; 63e8d8bef9SDimitry Andric 64349cc55cSDimitry Andric if (Callee.empty() || Caller.empty() || CallSite.empty()) { 65349cc55cSDimitry Andric Context.emitError("Invalid remark format: " + Line); 66349cc55cSDimitry Andric return; 67349cc55cSDimitry Andric } 68e8d8bef9SDimitry Andric 69e8d8bef9SDimitry Andric std::string Combined = (Callee + CallSite).str(); 70349cc55cSDimitry Andric InlineSitesFromRemarks[Combined] = IsPositiveRemark; 71349cc55cSDimitry Andric if (ReplaySettings.ReplayScope == ReplayInlinerSettings::Scope::Function) 72349cc55cSDimitry Andric CallersToReplay.insert(Caller); 73e8d8bef9SDimitry Andric } 74e8d8bef9SDimitry Andric 75e8d8bef9SDimitry Andric HasReplayRemarks = true; 76e8d8bef9SDimitry Andric } 77e8d8bef9SDimitry Andric 78349cc55cSDimitry Andric std::unique_ptr<InlineAdvisor> llvm::getReplayInlineAdvisor( 79349cc55cSDimitry Andric Module &M, FunctionAnalysisManager &FAM, LLVMContext &Context, 80349cc55cSDimitry Andric std::unique_ptr<InlineAdvisor> OriginalAdvisor, 81349cc55cSDimitry Andric const ReplayInlinerSettings &ReplaySettings, bool EmitRemarks) { 82349cc55cSDimitry Andric auto Advisor = std::make_unique<ReplayInlineAdvisor>( 83349cc55cSDimitry Andric M, FAM, Context, std::move(OriginalAdvisor), ReplaySettings, EmitRemarks); 84349cc55cSDimitry Andric if (!Advisor->areReplayRemarksLoaded()) 85349cc55cSDimitry Andric Advisor.reset(); 86349cc55cSDimitry Andric return Advisor; 87349cc55cSDimitry Andric } 88349cc55cSDimitry Andric 89e8d8bef9SDimitry Andric std::unique_ptr<InlineAdvice> ReplayInlineAdvisor::getAdviceImpl(CallBase &CB) { 90e8d8bef9SDimitry Andric assert(HasReplayRemarks); 91e8d8bef9SDimitry Andric 92e8d8bef9SDimitry Andric Function &Caller = *CB.getCaller(); 93e8d8bef9SDimitry Andric auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(Caller); 94e8d8bef9SDimitry Andric 95349cc55cSDimitry Andric // Decision not made by replay system 96349cc55cSDimitry Andric if (!hasInlineAdvice(*CB.getFunction())) { 97349cc55cSDimitry Andric // If there's a registered original advisor, return its decision 98349cc55cSDimitry Andric if (OriginalAdvisor) 99349cc55cSDimitry Andric return OriginalAdvisor->getAdvice(CB); 100e8d8bef9SDimitry Andric 101349cc55cSDimitry Andric // If no decision is made above, return non-decision 102349cc55cSDimitry Andric return {}; 103e8d8bef9SDimitry Andric } 104e8d8bef9SDimitry Andric 105349cc55cSDimitry Andric std::string CallSiteLoc = 106349cc55cSDimitry Andric formatCallSiteLocation(CB.getDebugLoc(), ReplaySettings.ReplayFormat); 107349cc55cSDimitry Andric StringRef Callee = CB.getCalledFunction()->getName(); 108349cc55cSDimitry Andric std::string Combined = (Callee + CallSiteLoc).str(); 109349cc55cSDimitry Andric 110349cc55cSDimitry Andric // Replay decision, if it has one 111349cc55cSDimitry Andric auto Iter = InlineSitesFromRemarks.find(Combined); 112349cc55cSDimitry Andric if (Iter != InlineSitesFromRemarks.end()) { 113349cc55cSDimitry Andric if (InlineSitesFromRemarks[Combined]) { 114349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Replay Inliner: Inlined " << Callee << " @ " 115349cc55cSDimitry Andric << CallSiteLoc << "\n"); 116349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>( 117349cc55cSDimitry Andric this, CB, llvm::InlineCost::getAlways("previously inlined"), ORE, 118e8d8bef9SDimitry Andric EmitRemarks); 119349cc55cSDimitry Andric } else { 120349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Replay Inliner: Not Inlined " << Callee << " @ " 121349cc55cSDimitry Andric << CallSiteLoc << "\n"); 122349cc55cSDimitry Andric // A negative inline is conveyed by "None" Optional<InlineCost> 123349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>(this, CB, None, ORE, 124349cc55cSDimitry Andric EmitRemarks); 125349cc55cSDimitry Andric } 126349cc55cSDimitry Andric } 127349cc55cSDimitry Andric 128349cc55cSDimitry Andric // Fallback decisions 129349cc55cSDimitry Andric if (ReplaySettings.ReplayFallback == 130349cc55cSDimitry Andric ReplayInlinerSettings::Fallback::AlwaysInline) 131349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>( 132349cc55cSDimitry Andric this, CB, llvm::InlineCost::getAlways("AlwaysInline Fallback"), ORE, 133349cc55cSDimitry Andric EmitRemarks); 134349cc55cSDimitry Andric else if (ReplaySettings.ReplayFallback == 135349cc55cSDimitry Andric ReplayInlinerSettings::Fallback::NeverInline) 136349cc55cSDimitry Andric // A negative inline is conveyed by "None" Optional<InlineCost> 137349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>(this, CB, None, ORE, 138349cc55cSDimitry Andric EmitRemarks); 139349cc55cSDimitry Andric else { 140349cc55cSDimitry Andric assert(ReplaySettings.ReplayFallback == 141349cc55cSDimitry Andric ReplayInlinerSettings::Fallback::Original); 142349cc55cSDimitry Andric // If there's a registered original advisor, return its decision 143349cc55cSDimitry Andric if (OriginalAdvisor) 144349cc55cSDimitry Andric return OriginalAdvisor->getAdvice(CB); 145349cc55cSDimitry Andric } 146349cc55cSDimitry Andric 147349cc55cSDimitry Andric // If no decision is made above, return non-decision 148349cc55cSDimitry Andric return {}; 149e8d8bef9SDimitry Andric } 150