1 //===- ReplayInlineAdvisor.cpp - Replay InlineAdvisor ---------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements ReplayInlineAdvisor that replays inline decisions based 10 // on previous inline remarks from optimization remark log. This is a best 11 // effort approach useful for testing compiler/source changes while holding 12 // inlining steady. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/Analysis/ReplayInlineAdvisor.h" 17 #include "llvm/IR/DebugInfoMetadata.h" 18 #include "llvm/IR/Instructions.h" 19 #include "llvm/Support/LineIterator.h" 20 #include <memory> 21 22 using namespace llvm; 23 24 #define DEBUG_TYPE "replay-inline" 25 26 ReplayInlineAdvisor::ReplayInlineAdvisor( 27 Module &M, FunctionAnalysisManager &FAM, LLVMContext &Context, 28 std::unique_ptr<InlineAdvisor> OriginalAdvisor, 29 const ReplayInlinerSettings &ReplaySettings, bool EmitRemarks) 30 : InlineAdvisor(M, FAM), OriginalAdvisor(std::move(OriginalAdvisor)), 31 ReplaySettings(ReplaySettings), EmitRemarks(EmitRemarks) { 32 33 auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(ReplaySettings.ReplayFile); 34 std::error_code EC = BufferOrErr.getError(); 35 if (EC) { 36 Context.emitError("Could not open remarks file: " + EC.message()); 37 return; 38 } 39 40 // Example for inline remarks to parse: 41 // main:3:1.1: '_Z3subii' inlined into 'main' at callsite sum:1 @ 42 // main:3:1.1; 43 // We use the callsite string after `at callsite` to replay inlining. 44 line_iterator LineIt(*BufferOrErr.get(), /*SkipBlanks=*/true); 45 const std::string PositiveRemark = "' inlined into '"; 46 const std::string NegativeRemark = "' will not be inlined into '"; 47 48 for (; !LineIt.is_at_eof(); ++LineIt) { 49 StringRef Line = *LineIt; 50 auto Pair = Line.split(" at callsite "); 51 52 bool IsPositiveRemark = true; 53 if (Pair.first.contains(NegativeRemark)) 54 IsPositiveRemark = false; 55 56 auto CalleeCaller = 57 Pair.first.split(IsPositiveRemark ? PositiveRemark : NegativeRemark); 58 59 StringRef Callee = CalleeCaller.first.rsplit(": '").second; 60 StringRef Caller = CalleeCaller.second.rsplit("'").first; 61 62 auto CallSite = Pair.second.split(";").first; 63 64 if (Callee.empty() || Caller.empty() || CallSite.empty()) { 65 Context.emitError("Invalid remark format: " + Line); 66 return; 67 } 68 69 std::string Combined = (Callee + CallSite).str(); 70 InlineSitesFromRemarks[Combined] = IsPositiveRemark; 71 if (ReplaySettings.ReplayScope == ReplayInlinerSettings::Scope::Function) 72 CallersToReplay.insert(Caller); 73 } 74 75 HasReplayRemarks = true; 76 } 77 78 std::unique_ptr<InlineAdvisor> llvm::getReplayInlineAdvisor( 79 Module &M, FunctionAnalysisManager &FAM, LLVMContext &Context, 80 std::unique_ptr<InlineAdvisor> OriginalAdvisor, 81 const ReplayInlinerSettings &ReplaySettings, bool EmitRemarks) { 82 auto Advisor = std::make_unique<ReplayInlineAdvisor>( 83 M, FAM, Context, std::move(OriginalAdvisor), ReplaySettings, EmitRemarks); 84 if (!Advisor->areReplayRemarksLoaded()) 85 Advisor.reset(); 86 return Advisor; 87 } 88 89 std::unique_ptr<InlineAdvice> ReplayInlineAdvisor::getAdviceImpl(CallBase &CB) { 90 assert(HasReplayRemarks); 91 92 Function &Caller = *CB.getCaller(); 93 auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(Caller); 94 95 // Decision not made by replay system 96 if (!hasInlineAdvice(*CB.getFunction())) { 97 // If there's a registered original advisor, return its decision 98 if (OriginalAdvisor) 99 return OriginalAdvisor->getAdvice(CB); 100 101 // If no decision is made above, return non-decision 102 return {}; 103 } 104 105 std::string CallSiteLoc = 106 formatCallSiteLocation(CB.getDebugLoc(), ReplaySettings.ReplayFormat); 107 StringRef Callee = CB.getCalledFunction()->getName(); 108 std::string Combined = (Callee + CallSiteLoc).str(); 109 110 // Replay decision, if it has one 111 auto Iter = InlineSitesFromRemarks.find(Combined); 112 if (Iter != InlineSitesFromRemarks.end()) { 113 if (InlineSitesFromRemarks[Combined]) { 114 LLVM_DEBUG(dbgs() << "Replay Inliner: Inlined " << Callee << " @ " 115 << CallSiteLoc << "\n"); 116 return std::make_unique<DefaultInlineAdvice>( 117 this, CB, llvm::InlineCost::getAlways("previously inlined"), ORE, 118 EmitRemarks); 119 } else { 120 LLVM_DEBUG(dbgs() << "Replay Inliner: Not Inlined " << Callee << " @ " 121 << CallSiteLoc << "\n"); 122 // A negative inline is conveyed by "None" Optional<InlineCost> 123 return std::make_unique<DefaultInlineAdvice>(this, CB, None, ORE, 124 EmitRemarks); 125 } 126 } 127 128 // Fallback decisions 129 if (ReplaySettings.ReplayFallback == 130 ReplayInlinerSettings::Fallback::AlwaysInline) 131 return std::make_unique<DefaultInlineAdvice>( 132 this, CB, llvm::InlineCost::getAlways("AlwaysInline Fallback"), ORE, 133 EmitRemarks); 134 else if (ReplaySettings.ReplayFallback == 135 ReplayInlinerSettings::Fallback::NeverInline) 136 // A negative inline is conveyed by "None" Optional<InlineCost> 137 return std::make_unique<DefaultInlineAdvice>(this, CB, None, ORE, 138 EmitRemarks); 139 else { 140 assert(ReplaySettings.ReplayFallback == 141 ReplayInlinerSettings::Fallback::Original); 142 // If there's a registered original advisor, return its decision 143 if (OriginalAdvisor) 144 return OriginalAdvisor->getAdvice(CB); 145 } 146 147 // If no decision is made above, return non-decision 148 return {}; 149 } 150