diff options
| author | David Bolvansky <david.bolvansky@gmail.com> | 2018-07-31 14:25:24 +0000 |
|---|---|---|
| committer | David Bolvansky <david.bolvansky@gmail.com> | 2018-07-31 14:25:24 +0000 |
| commit | b562dbabdad4f4842b7eb20c44cdf9e25bd5af54 (patch) | |
| tree | 49f12546edbe9e5dc16c80507e919eb677aa9513 /llvm/lib/Transforms | |
| parent | 4a31bcff3f6574b4ad2ad48282d5fb85b1cb27c1 (diff) | |
| download | bcm5719-llvm-b562dbabdad4f4842b7eb20c44cdf9e25bd5af54.tar.gz bcm5719-llvm-b562dbabdad4f4842b7eb20c44cdf9e25bd5af54.zip | |
Enrich inline messages
Summary:
This patch improves Inliner to provide causes/reasons for negative inline decisions.
1. It adds one new message field to InlineCost to report causes for Always and Never instances. All Never and Always instantiations must provide a simple message.
2. Several functions that used to return the inlining results as boolean are changed to return InlineResult which carries the cause for negative decision.
3. Changed remark priniting and debug output messages to provide the additional messages and related inline cost.
4. Adjusted tests for changed printing.
Patch by: yrouban (Yevgeny Rouban)
Reviewers: craig.topper, sammccall, sgraenitz, NutshellySima, shchenz, chandlerc, apilipenko, javed.absar, tejohnson, dblaikie, sanjoy, eraman, xbolva00
Reviewed By: tejohnson, xbolva00
Subscribers: xbolva00, llvm-commits, arsenm, mehdi_amini, eraman, haicheng, steven_wu, dexonsmith
Differential Revision: https://reviews.llvm.org/D49412
llvm-svn: 338387
Diffstat (limited to 'llvm/lib/Transforms')
| -rw-r--r-- | llvm/lib/Transforms/IPO/AlwaysInliner.cpp | 4 | ||||
| -rw-r--r-- | llvm/lib/Transforms/IPO/Inliner.cpp | 120 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Utils/InlineFunction.cpp | 29 |
3 files changed, 84 insertions, 69 deletions
diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp index 3b735ddd192..07138718ce2 100644 --- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp +++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp @@ -150,7 +150,7 @@ InlineCost AlwaysInlinerLegacyPass::getInlineCost(CallSite CS) { // declarations. if (Callee && !Callee->isDeclaration() && CS.hasFnAttr(Attribute::AlwaysInline) && isInlineViable(*Callee)) - return InlineCost::getAlways(); + return InlineCost::getAlways("always inliner"); - return InlineCost::getNever(); + return InlineCost::getNever("always inliner"); } diff --git a/llvm/lib/Transforms/IPO/Inliner.cpp b/llvm/lib/Transforms/IPO/Inliner.cpp index 3da0c2e83eb..ef55aca306f 100644 --- a/llvm/lib/Transforms/IPO/Inliner.cpp +++ b/llvm/lib/Transforms/IPO/Inliner.cpp @@ -64,6 +64,7 @@ #include <algorithm> #include <cassert> #include <functional> +#include <sstream> #include <tuple> #include <utility> #include <vector> @@ -275,8 +276,9 @@ static bool InlineCallIfPossible( // Try to inline the function. Get the list of static allocas that were // inlined. - if (!InlineFunction(CS, IFI, &AAR, InsertLifetime)) - return false; + InlineResult IR = InlineFunction(CS, IFI, &AAR, InsertLifetime); + if (!IR) + return IR; if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No) ImportedFunctionsStats.recordInline(*Caller, *Callee); @@ -286,7 +288,7 @@ static bool InlineCallIfPossible( if (!DisableInlinedAllocaMerging) mergeInlinedArrayAllocas(Caller, IFI, InlinedArrayAllocas, InlineHistory); - return true; + return IR; // success } /// Return true if inlining of CS can block the caller from being @@ -365,6 +367,33 @@ shouldBeDeferred(Function *Caller, CallSite CS, InlineCost IC, return false; } +template <class RemarkT> +RemarkT &operator<<(RemarkT &&R, const InlineCost &IC) { + using namespace ore; + if (IC.isAlways()) { + R << "(cost=always)"; + } else if (IC.isNever()) { + R << "(cost=never)"; + } else { + R << "(cost=" << ore::NV("Cost", IC.getCost()) + << ", threshold=" << ore::NV("Threshold", IC.getThreshold()) << ")"; + } + if (const char *Reason = IC.getReason()) + R << ": " << ore::NV("Reason", Reason); + return R; +} + +static std::basic_ostream<char> &operator<<(std::basic_ostream<char> &R, + const ore::NV &Arg) { + return R << Arg.Val; +} + +static std::string inlineCostStr(const InlineCost &IC) { + std::stringstream Remark; + Remark << IC; + return Remark.str(); +} + /// Return the cost only if the inliner should attempt to inline at the given /// CallSite. If we return the cost, we will emit an optimisation remark later /// using that cost, so we won't do so from this function. @@ -379,35 +408,32 @@ shouldInline(CallSite CS, function_ref<InlineCost(CallSite CS)> GetInlineCost, Function *Caller = CS.getCaller(); if (IC.isAlways()) { - LLVM_DEBUG(dbgs() << " Inlining: cost=always" + LLVM_DEBUG(dbgs() << " Inlining " << inlineCostStr(IC) << ", Call: " << *CS.getInstruction() << "\n"); return IC; } if (IC.isNever()) { - LLVM_DEBUG(dbgs() << " NOT Inlining: cost=never" + LLVM_DEBUG(dbgs() << " NOT Inlining " << inlineCostStr(IC) << ", Call: " << *CS.getInstruction() << "\n"); ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "NeverInline", Call) << NV("Callee", Callee) << " not inlined into " - << NV("Caller", Caller) - << " because it should never be inlined (cost=never)"; + << NV("Caller", Caller) << " because it should never be inlined " + << IC; }); - return None; + return IC; } if (!IC) { - LLVM_DEBUG(dbgs() << " NOT Inlining: cost=" << IC.getCost() - << ", thres=" << IC.getThreshold() + LLVM_DEBUG(dbgs() << " NOT Inlining " << inlineCostStr(IC) << ", Call: " << *CS.getInstruction() << "\n"); ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "TooCostly", Call) << NV("Callee", Callee) << " not inlined into " - << NV("Caller", Caller) << " because too costly to inline (cost=" - << NV("Cost", IC.getCost()) - << ", threshold=" << NV("Threshold", IC.getThreshold()) << ")"; + << NV("Caller", Caller) << " because too costly to inline " << IC; }); - return None; + return IC; } int TotalSecondaryCost = 0; @@ -428,8 +454,7 @@ shouldInline(CallSite CS, function_ref<InlineCost(CallSite CS)> GetInlineCost, return None; } - LLVM_DEBUG(dbgs() << " Inlining: cost=" << IC.getCost() - << ", thres=" << IC.getThreshold() + LLVM_DEBUG(dbgs() << " Inlining " << inlineCostStr(IC) << ", Call: " << *CS.getInstruction() << '\n'); return IC; } @@ -461,6 +486,18 @@ bool LegacyInlinerBase::runOnSCC(CallGraphSCC &SCC) { return inlineCalls(SCC); } +static void emit_inlined_into(OptimizationRemarkEmitter &ORE, DebugLoc &DLoc, + const BasicBlock *Block, const Function &Callee, + const Function &Caller, const InlineCost &IC) { + ORE.emit([&]() { + bool AlwaysInline = IC.isAlways(); + StringRef RemarkName = AlwaysInline ? "AlwaysInline" : "Inlined"; + return OptimizationRemark(DEBUG_TYPE, RemarkName, DLoc, Block) + << ore::NV("Callee", &Callee) << " inlined into " + << ore::NV("Caller", &Caller) << " with " << IC; + }); +} + static bool inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG, std::function<AssumptionCache &(Function &)> GetAssumptionCache, @@ -585,8 +622,9 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG, Optional<InlineCost> OIC = shouldInline(CS, GetInlineCost, ORE); // If the policy determines that we should inline this function, // delete the call instead. - if (!OIC) + if (!OIC || !*OIC) { continue; + } // If this call site is dead and it is to a readonly function, we should // just delete the call instead of trying to inline it, regardless of @@ -606,34 +644,21 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG, // Attempt to inline the function. using namespace ore; - if (!InlineCallIfPossible(CS, InlineInfo, InlinedArrayAllocas, - InlineHistoryID, InsertLifetime, AARGetter, - ImportedFunctionsStats)) { + InlineResult IR = InlineCallIfPossible( + CS, InlineInfo, InlinedArrayAllocas, InlineHistoryID, + InsertLifetime, AARGetter, ImportedFunctionsStats); + if (!IR) { ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block) << NV("Callee", Callee) << " will not be inlined into " - << NV("Caller", Caller); + << NV("Caller", Caller) << ": " << NV("Reason", IR.message); }); continue; } ++NumInlined; - ORE.emit([&]() { - bool AlwaysInline = OIC->isAlways(); - StringRef RemarkName = AlwaysInline ? "AlwaysInline" : "Inlined"; - OptimizationRemark R(DEBUG_TYPE, RemarkName, DLoc, Block); - R << NV("Callee", Callee) << " inlined into "; - R << NV("Caller", Caller); - if (AlwaysInline) - R << " with cost=always"; - else { - R << " with cost=" << NV("Cost", OIC->getCost()); - R << " (threshold=" << NV("Threshold", OIC->getThreshold()); - R << ")"; - } - return R; - }); + emit_inlined_into(ORE, DLoc, Block, *Callee, *Caller, *OIC); // If inlining this function gave us any new call sites, throw them // onto our worklist to process. They are useful inline candidates. @@ -971,7 +996,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, Optional<InlineCost> OIC = shouldInline(CS, GetInlineCost, ORE); // Check whether we want to inline this callsite. - if (!OIC) + if (!OIC || !*OIC) continue; // Setup the data structure used to plumb customization into the @@ -987,32 +1012,19 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, using namespace ore; - if (!InlineFunction(CS, IFI)) { + InlineResult IR = InlineFunction(CS, IFI); + if (!IR) { ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block) << NV("Callee", &Callee) << " will not be inlined into " - << NV("Caller", &F); + << NV("Caller", &F) << ": " << NV("Reason", IR.message); }); continue; } DidInline = true; InlinedCallees.insert(&Callee); - ORE.emit([&]() { - bool AlwaysInline = OIC->isAlways(); - StringRef RemarkName = AlwaysInline ? "AlwaysInline" : "Inlined"; - OptimizationRemark R(DEBUG_TYPE, RemarkName, DLoc, Block); - R << NV("Callee", &Callee) << " inlined into "; - R << NV("Caller", &F); - if (AlwaysInline) - R << " with cost=always"; - else { - R << " with cost=" << NV("Cost", OIC->getCost()); - R << " (threshold=" << NV("Threshold", OIC->getThreshold()); - R << ")"; - } - return R; - }); + emit_inlined_into(ORE, DLoc, Block, Callee, F, *OIC); // Add any new callsites to defined functions to the worklist. if (!IFI.InlinedCallSites.empty()) { diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index ddc6e07e2f5..f8226f529ee 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -84,13 +84,15 @@ PreserveAlignmentAssumptions("preserve-alignment-assumptions-during-inlining", cl::init(true), cl::Hidden, cl::desc("Convert align attributes to assumptions during inlining.")); -bool llvm::InlineFunction(CallInst *CI, InlineFunctionInfo &IFI, - AAResults *CalleeAAR, bool InsertLifetime) { +llvm::InlineResult llvm::InlineFunction(CallInst *CI, InlineFunctionInfo &IFI, + AAResults *CalleeAAR, + bool InsertLifetime) { return InlineFunction(CallSite(CI), IFI, CalleeAAR, InsertLifetime); } -bool llvm::InlineFunction(InvokeInst *II, InlineFunctionInfo &IFI, - AAResults *CalleeAAR, bool InsertLifetime) { +llvm::InlineResult llvm::InlineFunction(InvokeInst *II, InlineFunctionInfo &IFI, + AAResults *CalleeAAR, + bool InsertLifetime) { return InlineFunction(CallSite(II), IFI, CalleeAAR, InsertLifetime); } @@ -1491,9 +1493,10 @@ static void updateCalleeCount(BlockFrequencyInfo *CallerBFI, BasicBlock *CallBB, /// instruction 'call B' is inlined, and 'B' calls 'C', then the call to 'C' now /// exists in the instruction stream. Similarly this will inline a recursive /// function by one level. -bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, - AAResults *CalleeAAR, bool InsertLifetime, - Function *ForwardVarArgsTo) { +llvm::InlineResult llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, + AAResults *CalleeAAR, + bool InsertLifetime, + Function *ForwardVarArgsTo) { Instruction *TheCall = CS.getInstruction(); assert(TheCall->getParent() && TheCall->getFunction() && "Instruction not in function!"); @@ -1504,7 +1507,7 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, Function *CalledFunc = CS.getCalledFunction(); if (!CalledFunc || // Can't inline external function or indirect CalledFunc->isDeclaration()) // call! - return false; + return "external or indirect"; // The inliner does not know how to inline through calls with operand bundles // in general ... @@ -1518,7 +1521,7 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, if (Tag == LLVMContext::OB_funclet) continue; - return false; + return "unsupported operand bundle"; } } @@ -1537,7 +1540,7 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, if (!Caller->hasGC()) Caller->setGC(CalledFunc->getGC()); else if (CalledFunc->getGC() != Caller->getGC()) - return false; + return "incompatible GC"; } // Get the personality function from the callee if it contains a landing pad. @@ -1561,7 +1564,7 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, // TODO: This isn't 100% true. Some personality functions are proper // supersets of others and can be used in place of the other. else if (CalledPersonality != CallerPersonality) - return false; + return "incompatible personality"; } // We need to figure out which funclet the callsite was in so that we may @@ -1586,7 +1589,7 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, // for catchpads. for (const BasicBlock &CalledBB : *CalledFunc) { if (isa<CatchSwitchInst>(CalledBB.getFirstNonPHI())) - return false; + return "catch in cleanup funclet"; } } } else if (isAsynchronousEHPersonality(Personality)) { @@ -1594,7 +1597,7 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, // funclet in the callee. for (const BasicBlock &CalledBB : *CalledFunc) { if (CalledBB.isEHPad()) - return false; + return "SEH in cleanup funclet"; } } } |

