diff options
author | vporpo <vporpodas@google.com> | 2025-03-19 18:18:45 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-19 18:18:45 -0700 |
commit | 08dda4dcbf6427e357830d9c7f7ac3b422fc75f6 (patch) | |
tree | d10ce1e0254058a371ee471890415df6acf9f051 /llvm/lib/Analysis/InlineCost.cpp | |
parent | fd7be0d2e9e2cb7d43c9cb97edbb36da59a5b595 (diff) | |
download | llvm-08dda4dcbf6427e357830d9c7f7ac3b422fc75f6.zip llvm-08dda4dcbf6427e357830d9c7f7ac3b422fc75f6.tar.gz llvm-08dda4dcbf6427e357830d9c7f7ac3b422fc75f6.tar.bz2 |
[Analysis][EphemeralValuesCache][InlineCost] Ephemeral values caching for the CallAnalyzer (#130210)
This patch does two things:
1. It implements an ephemeral values cache analysis pass that collects the ephemeral values of a function and caches them for fast lookups. The collection of the ephemeral values is done lazily when the user calls `EphemeralValuesCache::ephValues()`.
2. It adds caching of ephemeral values using the `EphemeralValuesCache` to speed up `CallAnalyzer::analyze()`. Without caching this can take a long time to run in cases where the function contains a large number of `@llvm.assume()` calls and a large number of callsites. The time is spent in `collectEphemeralvalues()`.
Diffstat (limited to 'llvm/lib/Analysis/InlineCost.cpp')
-rw-r--r-- | llvm/lib/Analysis/InlineCost.cpp | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp index c6b927c..df212eb3 100644 --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -20,6 +20,7 @@ #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/CodeMetrics.h" #include "llvm/Analysis/ConstantFolding.h" +#include "llvm/Analysis/EphemeralValuesCache.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/MemoryBuiltins.h" @@ -269,6 +270,9 @@ protected: /// easily cacheable. Instead, use the cover function paramHasAttr. CallBase &CandidateCall; + /// Getter for the cache of ephemeral values. + function_ref<EphemeralValuesCache &(Function &)> GetEphValuesCache = nullptr; + /// Extension points for handling callsite features. // Called before a basic block was analyzed. virtual void onBlockStart(const BasicBlock *BB) {} @@ -462,7 +466,7 @@ protected: // Custom analysis routines. InlineResult analyzeBlock(BasicBlock *BB, - SmallPtrSetImpl<const Value *> &EphValues); + const SmallPtrSetImpl<const Value *> &EphValues); // Disable several entry points to the visitor so we don't accidentally use // them by declaring but not defining them here. @@ -510,10 +514,12 @@ public: function_ref<BlockFrequencyInfo &(Function &)> GetBFI = nullptr, function_ref<const TargetLibraryInfo &(Function &)> GetTLI = nullptr, ProfileSummaryInfo *PSI = nullptr, - OptimizationRemarkEmitter *ORE = nullptr) + OptimizationRemarkEmitter *ORE = nullptr, + function_ref<EphemeralValuesCache &(Function &)> GetEphValuesCache = + nullptr) : TTI(TTI), GetAssumptionCache(GetAssumptionCache), GetBFI(GetBFI), GetTLI(GetTLI), PSI(PSI), F(Callee), DL(F.getDataLayout()), ORE(ORE), - CandidateCall(Call) {} + CandidateCall(Call), GetEphValuesCache(GetEphValuesCache) {} InlineResult analyze(); @@ -1126,9 +1132,11 @@ public: function_ref<const TargetLibraryInfo &(Function &)> GetTLI = nullptr, ProfileSummaryInfo *PSI = nullptr, OptimizationRemarkEmitter *ORE = nullptr, bool BoostIndirect = true, - bool IgnoreThreshold = false) + bool IgnoreThreshold = false, + function_ref<EphemeralValuesCache &(Function &)> GetEphValuesCache = + nullptr) : CallAnalyzer(Callee, Call, TTI, GetAssumptionCache, GetBFI, GetTLI, PSI, - ORE), + ORE, GetEphValuesCache), ComputeFullInlineCost(OptComputeFullInlineCost || Params.ComputeFullInlineCost || ORE || isCostBenefitAnalysisEnabled()), @@ -2566,7 +2574,7 @@ bool CallAnalyzer::visitInstruction(Instruction &I) { /// viable, and true if inlining remains viable. InlineResult CallAnalyzer::analyzeBlock(BasicBlock *BB, - SmallPtrSetImpl<const Value *> &EphValues) { + const SmallPtrSetImpl<const Value *> &EphValues) { for (Instruction &I : *BB) { // FIXME: Currently, the number of instructions in a function regardless of // our ability to simplify them during inline to constants or dead code, @@ -2781,11 +2789,15 @@ InlineResult CallAnalyzer::analyze() { NumConstantOffsetPtrArgs = ConstantOffsetPtrs.size(); NumAllocaArgs = SROAArgValues.size(); - // FIXME: If a caller has multiple calls to a callee, we end up recomputing - // the ephemeral values multiple times (and they're completely determined by - // the callee, so this is purely duplicate work). - SmallPtrSet<const Value *, 32> EphValues; - CodeMetrics::collectEphemeralValues(&F, &GetAssumptionCache(F), EphValues); + // Collecting the ephemeral values of `F` can be expensive, so use the + // ephemeral values cache if available. + SmallPtrSet<const Value *, 32> EphValuesStorage; + const SmallPtrSetImpl<const Value *> *EphValues = &EphValuesStorage; + if (GetEphValuesCache) + EphValues = &GetEphValuesCache(F).ephValues(); + else + CodeMetrics::collectEphemeralValues(&F, &GetAssumptionCache(F), + EphValuesStorage); // The worklist of live basic blocks in the callee *after* inlining. We avoid // adding basic blocks of the callee which can be proven to be dead for this @@ -2824,7 +2836,7 @@ InlineResult CallAnalyzer::analyze() { // Analyze the cost of this block. If we blow through the threshold, this // returns false, and we can bail on out. - InlineResult IR = analyzeBlock(BB, EphValues); + InlineResult IR = analyzeBlock(BB, *EphValues); if (!IR.isSuccess()) return IR; @@ -2967,9 +2979,11 @@ InlineCost llvm::getInlineCost( function_ref<AssumptionCache &(Function &)> GetAssumptionCache, function_ref<const TargetLibraryInfo &(Function &)> GetTLI, function_ref<BlockFrequencyInfo &(Function &)> GetBFI, - ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { + ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE, + function_ref<EphemeralValuesCache &(Function &)> GetEphValuesCache) { return getInlineCost(Call, Call.getCalledFunction(), Params, CalleeTTI, - GetAssumptionCache, GetTLI, GetBFI, PSI, ORE); + GetAssumptionCache, GetTLI, GetBFI, PSI, ORE, + GetEphValuesCache); } std::optional<int> llvm::getInliningCostEstimate( @@ -3089,7 +3103,8 @@ InlineCost llvm::getInlineCost( function_ref<AssumptionCache &(Function &)> GetAssumptionCache, function_ref<const TargetLibraryInfo &(Function &)> GetTLI, function_ref<BlockFrequencyInfo &(Function &)> GetBFI, - ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { + ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE, + function_ref<EphemeralValuesCache &(Function &)> GetEphValuesCache) { auto UserDecision = llvm::getAttributeBasedInliningDecision(Call, Callee, CalleeTTI, GetTLI); @@ -3105,7 +3120,9 @@ InlineCost llvm::getInlineCost( << ")\n"); InlineCostCallAnalyzer CA(*Callee, Call, Params, CalleeTTI, - GetAssumptionCache, GetBFI, GetTLI, PSI, ORE); + GetAssumptionCache, GetBFI, GetTLI, PSI, ORE, + /*BoostIndirect=*/true, /*IgnoreThreshold=*/false, + GetEphValuesCache); InlineResult ShouldInline = CA.analyze(); LLVM_DEBUG(CA.dump()); |