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" 17*81ad6265SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h" 18e8d8bef9SDimitry Andric #include "llvm/Support/LineIterator.h" 19*81ad6265SDimitry Andric #include "llvm/Support/MemoryBuffer.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, 29*81ad6265SDimitry Andric const ReplayInlinerSettings &ReplaySettings, bool EmitRemarks, 30*81ad6265SDimitry Andric InlineContext IC) 31*81ad6265SDimitry Andric : InlineAdvisor(M, FAM, IC), OriginalAdvisor(std::move(OriginalAdvisor)), 3204eeddc0SDimitry Andric ReplaySettings(ReplaySettings), EmitRemarks(EmitRemarks) { 33349cc55cSDimitry Andric 34349cc55cSDimitry Andric auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(ReplaySettings.ReplayFile); 35e8d8bef9SDimitry Andric std::error_code EC = BufferOrErr.getError(); 36e8d8bef9SDimitry Andric if (EC) { 37e8d8bef9SDimitry Andric Context.emitError("Could not open remarks file: " + EC.message()); 38e8d8bef9SDimitry Andric return; 39e8d8bef9SDimitry Andric } 40e8d8bef9SDimitry Andric 41e8d8bef9SDimitry Andric // Example for inline remarks to parse: 42349cc55cSDimitry Andric // main:3:1.1: '_Z3subii' inlined into 'main' at callsite sum:1 @ 43349cc55cSDimitry Andric // main:3:1.1; 44e8d8bef9SDimitry Andric // We use the callsite string after `at callsite` to replay inlining. 45e8d8bef9SDimitry Andric line_iterator LineIt(*BufferOrErr.get(), /*SkipBlanks=*/true); 46349cc55cSDimitry Andric const std::string PositiveRemark = "' inlined into '"; 47349cc55cSDimitry Andric const std::string NegativeRemark = "' will not be inlined into '"; 48349cc55cSDimitry Andric 49e8d8bef9SDimitry Andric for (; !LineIt.is_at_eof(); ++LineIt) { 50e8d8bef9SDimitry Andric StringRef Line = *LineIt; 51e8d8bef9SDimitry Andric auto Pair = Line.split(" at callsite "); 52e8d8bef9SDimitry Andric 53349cc55cSDimitry Andric bool IsPositiveRemark = true; 54349cc55cSDimitry Andric if (Pair.first.contains(NegativeRemark)) 55349cc55cSDimitry Andric IsPositiveRemark = false; 56349cc55cSDimitry Andric 57349cc55cSDimitry Andric auto CalleeCaller = 58349cc55cSDimitry Andric Pair.first.split(IsPositiveRemark ? PositiveRemark : NegativeRemark); 59349cc55cSDimitry Andric 60349cc55cSDimitry Andric StringRef Callee = CalleeCaller.first.rsplit(": '").second; 61349cc55cSDimitry Andric StringRef Caller = CalleeCaller.second.rsplit("'").first; 62e8d8bef9SDimitry Andric 63e8d8bef9SDimitry Andric auto CallSite = Pair.second.split(";").first; 64e8d8bef9SDimitry Andric 65349cc55cSDimitry Andric if (Callee.empty() || Caller.empty() || CallSite.empty()) { 66349cc55cSDimitry Andric Context.emitError("Invalid remark format: " + Line); 67349cc55cSDimitry Andric return; 68349cc55cSDimitry Andric } 69e8d8bef9SDimitry Andric 70e8d8bef9SDimitry Andric std::string Combined = (Callee + CallSite).str(); 71349cc55cSDimitry Andric InlineSitesFromRemarks[Combined] = IsPositiveRemark; 72349cc55cSDimitry Andric if (ReplaySettings.ReplayScope == ReplayInlinerSettings::Scope::Function) 73349cc55cSDimitry Andric CallersToReplay.insert(Caller); 74e8d8bef9SDimitry Andric } 75e8d8bef9SDimitry Andric 76e8d8bef9SDimitry Andric HasReplayRemarks = true; 77e8d8bef9SDimitry Andric } 78e8d8bef9SDimitry Andric 79*81ad6265SDimitry Andric std::unique_ptr<InlineAdvisor> 80*81ad6265SDimitry Andric llvm::getReplayInlineAdvisor(Module &M, FunctionAnalysisManager &FAM, 81*81ad6265SDimitry Andric LLVMContext &Context, 82349cc55cSDimitry Andric std::unique_ptr<InlineAdvisor> OriginalAdvisor, 83*81ad6265SDimitry Andric const ReplayInlinerSettings &ReplaySettings, 84*81ad6265SDimitry Andric bool EmitRemarks, InlineContext IC) { 85349cc55cSDimitry Andric auto Advisor = std::make_unique<ReplayInlineAdvisor>( 86*81ad6265SDimitry Andric M, FAM, Context, std::move(OriginalAdvisor), ReplaySettings, EmitRemarks, 87*81ad6265SDimitry Andric IC); 88349cc55cSDimitry Andric if (!Advisor->areReplayRemarksLoaded()) 89349cc55cSDimitry Andric Advisor.reset(); 90349cc55cSDimitry Andric return Advisor; 91349cc55cSDimitry Andric } 92349cc55cSDimitry Andric 93e8d8bef9SDimitry Andric std::unique_ptr<InlineAdvice> ReplayInlineAdvisor::getAdviceImpl(CallBase &CB) { 94e8d8bef9SDimitry Andric assert(HasReplayRemarks); 95e8d8bef9SDimitry Andric 96e8d8bef9SDimitry Andric Function &Caller = *CB.getCaller(); 97e8d8bef9SDimitry Andric auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(Caller); 98e8d8bef9SDimitry Andric 99349cc55cSDimitry Andric // Decision not made by replay system 100349cc55cSDimitry Andric if (!hasInlineAdvice(*CB.getFunction())) { 101349cc55cSDimitry Andric // If there's a registered original advisor, return its decision 102349cc55cSDimitry Andric if (OriginalAdvisor) 103349cc55cSDimitry Andric return OriginalAdvisor->getAdvice(CB); 104e8d8bef9SDimitry Andric 105349cc55cSDimitry Andric // If no decision is made above, return non-decision 106349cc55cSDimitry Andric return {}; 107e8d8bef9SDimitry Andric } 108e8d8bef9SDimitry Andric 109349cc55cSDimitry Andric std::string CallSiteLoc = 110349cc55cSDimitry Andric formatCallSiteLocation(CB.getDebugLoc(), ReplaySettings.ReplayFormat); 111349cc55cSDimitry Andric StringRef Callee = CB.getCalledFunction()->getName(); 112349cc55cSDimitry Andric std::string Combined = (Callee + CallSiteLoc).str(); 113349cc55cSDimitry Andric 114349cc55cSDimitry Andric // Replay decision, if it has one 115349cc55cSDimitry Andric auto Iter = InlineSitesFromRemarks.find(Combined); 116349cc55cSDimitry Andric if (Iter != InlineSitesFromRemarks.end()) { 117349cc55cSDimitry Andric if (InlineSitesFromRemarks[Combined]) { 118349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Replay Inliner: Inlined " << Callee << " @ " 119349cc55cSDimitry Andric << CallSiteLoc << "\n"); 120349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>( 121349cc55cSDimitry Andric this, CB, llvm::InlineCost::getAlways("previously inlined"), ORE, 122e8d8bef9SDimitry Andric EmitRemarks); 123349cc55cSDimitry Andric } else { 124349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Replay Inliner: Not Inlined " << Callee << " @ " 125349cc55cSDimitry Andric << CallSiteLoc << "\n"); 126349cc55cSDimitry Andric // A negative inline is conveyed by "None" Optional<InlineCost> 127349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>(this, CB, None, ORE, 128349cc55cSDimitry Andric EmitRemarks); 129349cc55cSDimitry Andric } 130349cc55cSDimitry Andric } 131349cc55cSDimitry Andric 132349cc55cSDimitry Andric // Fallback decisions 133349cc55cSDimitry Andric if (ReplaySettings.ReplayFallback == 134349cc55cSDimitry Andric ReplayInlinerSettings::Fallback::AlwaysInline) 135349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>( 136349cc55cSDimitry Andric this, CB, llvm::InlineCost::getAlways("AlwaysInline Fallback"), ORE, 137349cc55cSDimitry Andric EmitRemarks); 138349cc55cSDimitry Andric else if (ReplaySettings.ReplayFallback == 139349cc55cSDimitry Andric ReplayInlinerSettings::Fallback::NeverInline) 140349cc55cSDimitry Andric // A negative inline is conveyed by "None" Optional<InlineCost> 141349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>(this, CB, None, ORE, 142349cc55cSDimitry Andric EmitRemarks); 143349cc55cSDimitry Andric else { 144349cc55cSDimitry Andric assert(ReplaySettings.ReplayFallback == 145349cc55cSDimitry Andric ReplayInlinerSettings::Fallback::Original); 146349cc55cSDimitry Andric // If there's a registered original advisor, return its decision 147349cc55cSDimitry Andric if (OriginalAdvisor) 148349cc55cSDimitry Andric return OriginalAdvisor->getAdvice(CB); 149349cc55cSDimitry Andric } 150349cc55cSDimitry Andric 151349cc55cSDimitry Andric // If no decision is made above, return non-decision 152349cc55cSDimitry Andric return {}; 153e8d8bef9SDimitry Andric } 154