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" 20*349cc55cSDimitry Andric #include <memory> 21e8d8bef9SDimitry Andric 22e8d8bef9SDimitry Andric using namespace llvm; 23e8d8bef9SDimitry Andric 24*349cc55cSDimitry Andric #define DEBUG_TYPE "replay-inline" 25e8d8bef9SDimitry Andric 26e8d8bef9SDimitry Andric ReplayInlineAdvisor::ReplayInlineAdvisor( 27e8d8bef9SDimitry Andric Module &M, FunctionAnalysisManager &FAM, LLVMContext &Context, 28*349cc55cSDimitry Andric std::unique_ptr<InlineAdvisor> OriginalAdvisor, 29*349cc55cSDimitry Andric const ReplayInlinerSettings &ReplaySettings, bool EmitRemarks) 30e8d8bef9SDimitry Andric : InlineAdvisor(M, FAM), OriginalAdvisor(std::move(OriginalAdvisor)), 31*349cc55cSDimitry Andric HasReplayRemarks(false), ReplaySettings(ReplaySettings), 32*349cc55cSDimitry Andric EmitRemarks(EmitRemarks) { 33*349cc55cSDimitry Andric 34*349cc55cSDimitry 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: 42*349cc55cSDimitry Andric // main:3:1.1: '_Z3subii' inlined into 'main' at callsite sum:1 @ 43*349cc55cSDimitry 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); 46*349cc55cSDimitry Andric const std::string PositiveRemark = "' inlined into '"; 47*349cc55cSDimitry Andric const std::string NegativeRemark = "' will not be inlined into '"; 48*349cc55cSDimitry Andric 49e8d8bef9SDimitry Andric for (; !LineIt.is_at_eof(); ++LineIt) { 50e8d8bef9SDimitry Andric StringRef Line = *LineIt; 51e8d8bef9SDimitry Andric auto Pair = Line.split(" at callsite "); 52e8d8bef9SDimitry Andric 53*349cc55cSDimitry Andric bool IsPositiveRemark = true; 54*349cc55cSDimitry Andric if (Pair.first.contains(NegativeRemark)) 55*349cc55cSDimitry Andric IsPositiveRemark = false; 56*349cc55cSDimitry Andric 57*349cc55cSDimitry Andric auto CalleeCaller = 58*349cc55cSDimitry Andric Pair.first.split(IsPositiveRemark ? PositiveRemark : NegativeRemark); 59*349cc55cSDimitry Andric 60*349cc55cSDimitry Andric StringRef Callee = CalleeCaller.first.rsplit(": '").second; 61*349cc55cSDimitry Andric StringRef Caller = CalleeCaller.second.rsplit("'").first; 62e8d8bef9SDimitry Andric 63e8d8bef9SDimitry Andric auto CallSite = Pair.second.split(";").first; 64e8d8bef9SDimitry Andric 65*349cc55cSDimitry Andric if (Callee.empty() || Caller.empty() || CallSite.empty()) { 66*349cc55cSDimitry Andric Context.emitError("Invalid remark format: " + Line); 67*349cc55cSDimitry Andric return; 68*349cc55cSDimitry Andric } 69e8d8bef9SDimitry Andric 70e8d8bef9SDimitry Andric std::string Combined = (Callee + CallSite).str(); 71*349cc55cSDimitry Andric InlineSitesFromRemarks[Combined] = IsPositiveRemark; 72*349cc55cSDimitry Andric if (ReplaySettings.ReplayScope == ReplayInlinerSettings::Scope::Function) 73*349cc55cSDimitry Andric CallersToReplay.insert(Caller); 74e8d8bef9SDimitry Andric } 75e8d8bef9SDimitry Andric 76e8d8bef9SDimitry Andric HasReplayRemarks = true; 77e8d8bef9SDimitry Andric } 78e8d8bef9SDimitry Andric 79*349cc55cSDimitry Andric std::unique_ptr<InlineAdvisor> llvm::getReplayInlineAdvisor( 80*349cc55cSDimitry Andric Module &M, FunctionAnalysisManager &FAM, LLVMContext &Context, 81*349cc55cSDimitry Andric std::unique_ptr<InlineAdvisor> OriginalAdvisor, 82*349cc55cSDimitry Andric const ReplayInlinerSettings &ReplaySettings, bool EmitRemarks) { 83*349cc55cSDimitry Andric auto Advisor = std::make_unique<ReplayInlineAdvisor>( 84*349cc55cSDimitry Andric M, FAM, Context, std::move(OriginalAdvisor), ReplaySettings, EmitRemarks); 85*349cc55cSDimitry Andric if (!Advisor->areReplayRemarksLoaded()) 86*349cc55cSDimitry Andric Advisor.reset(); 87*349cc55cSDimitry Andric return Advisor; 88*349cc55cSDimitry Andric } 89*349cc55cSDimitry Andric 90e8d8bef9SDimitry Andric std::unique_ptr<InlineAdvice> ReplayInlineAdvisor::getAdviceImpl(CallBase &CB) { 91e8d8bef9SDimitry Andric assert(HasReplayRemarks); 92e8d8bef9SDimitry Andric 93e8d8bef9SDimitry Andric Function &Caller = *CB.getCaller(); 94e8d8bef9SDimitry Andric auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(Caller); 95e8d8bef9SDimitry Andric 96*349cc55cSDimitry Andric // Decision not made by replay system 97*349cc55cSDimitry Andric if (!hasInlineAdvice(*CB.getFunction())) { 98*349cc55cSDimitry Andric // If there's a registered original advisor, return its decision 99*349cc55cSDimitry Andric if (OriginalAdvisor) 100*349cc55cSDimitry Andric return OriginalAdvisor->getAdvice(CB); 101e8d8bef9SDimitry Andric 102*349cc55cSDimitry Andric // If no decision is made above, return non-decision 103*349cc55cSDimitry Andric return {}; 104e8d8bef9SDimitry Andric } 105e8d8bef9SDimitry Andric 106*349cc55cSDimitry Andric std::string CallSiteLoc = 107*349cc55cSDimitry Andric formatCallSiteLocation(CB.getDebugLoc(), ReplaySettings.ReplayFormat); 108*349cc55cSDimitry Andric StringRef Callee = CB.getCalledFunction()->getName(); 109*349cc55cSDimitry Andric std::string Combined = (Callee + CallSiteLoc).str(); 110*349cc55cSDimitry Andric 111*349cc55cSDimitry Andric // Replay decision, if it has one 112*349cc55cSDimitry Andric auto Iter = InlineSitesFromRemarks.find(Combined); 113*349cc55cSDimitry Andric if (Iter != InlineSitesFromRemarks.end()) { 114*349cc55cSDimitry Andric if (InlineSitesFromRemarks[Combined]) { 115*349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Replay Inliner: Inlined " << Callee << " @ " 116*349cc55cSDimitry Andric << CallSiteLoc << "\n"); 117*349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>( 118*349cc55cSDimitry Andric this, CB, llvm::InlineCost::getAlways("previously inlined"), ORE, 119e8d8bef9SDimitry Andric EmitRemarks); 120*349cc55cSDimitry Andric } else { 121*349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "Replay Inliner: Not Inlined " << Callee << " @ " 122*349cc55cSDimitry Andric << CallSiteLoc << "\n"); 123*349cc55cSDimitry Andric // A negative inline is conveyed by "None" Optional<InlineCost> 124*349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>(this, CB, None, ORE, 125*349cc55cSDimitry Andric EmitRemarks); 126*349cc55cSDimitry Andric } 127*349cc55cSDimitry Andric } 128*349cc55cSDimitry Andric 129*349cc55cSDimitry Andric // Fallback decisions 130*349cc55cSDimitry Andric if (ReplaySettings.ReplayFallback == 131*349cc55cSDimitry Andric ReplayInlinerSettings::Fallback::AlwaysInline) 132*349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>( 133*349cc55cSDimitry Andric this, CB, llvm::InlineCost::getAlways("AlwaysInline Fallback"), ORE, 134*349cc55cSDimitry Andric EmitRemarks); 135*349cc55cSDimitry Andric else if (ReplaySettings.ReplayFallback == 136*349cc55cSDimitry Andric ReplayInlinerSettings::Fallback::NeverInline) 137*349cc55cSDimitry Andric // A negative inline is conveyed by "None" Optional<InlineCost> 138*349cc55cSDimitry Andric return std::make_unique<DefaultInlineAdvice>(this, CB, None, ORE, 139*349cc55cSDimitry Andric EmitRemarks); 140*349cc55cSDimitry Andric else { 141*349cc55cSDimitry Andric assert(ReplaySettings.ReplayFallback == 142*349cc55cSDimitry Andric ReplayInlinerSettings::Fallback::Original); 143*349cc55cSDimitry Andric // If there's a registered original advisor, return its decision 144*349cc55cSDimitry Andric if (OriginalAdvisor) 145*349cc55cSDimitry Andric return OriginalAdvisor->getAdvice(CB); 146*349cc55cSDimitry Andric } 147*349cc55cSDimitry Andric 148*349cc55cSDimitry Andric // If no decision is made above, return non-decision 149*349cc55cSDimitry Andric return {}; 150e8d8bef9SDimitry Andric } 151