Skip to content

[AlwaysInline] Avoid unnecessary BFI fetches #117750

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 27, 2024
Merged

Conversation

nikic
Copy link
Contributor

@nikic nikic commented Nov 26, 2024

AlwaysInliner doesn't use BFI itself, it only updates it. If BFI is not already computed, it will spend time to first compute it, and then update it. This is not necessary: If BFI is not available in the first place, there is no need to update it.

This is mainly relevant in debug builds for IR that has a lot of alwaysinline functions.

@llvmbot
Copy link
Member

llvmbot commented Nov 26, 2024

@llvm/pr-subscribers-llvm-transforms

Author: Nikita Popov (nikic)

Changes

AlwaysInliner doesn't use BFI itself, it only updates it. If BFI is not already computed, it will spend time to first compute it, and then update it. This is not necessary: If BFI is not available in the first place, there is no need to update it.

This is mainly relevant in debug builds for IR that has a lot of alwaysinline functions.


Full diff: https://github.com/llvm/llvm-project/pull/117750.diff

1 Files Affected:

  • (modified) llvm/lib/Transforms/IPO/AlwaysInliner.cpp (+15-6)
diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
index 1f787c733079e9..447a0f492775da 100644
--- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
+++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp
@@ -34,7 +34,8 @@ bool AlwaysInlineImpl(
     Module &M, bool InsertLifetime, ProfileSummaryInfo &PSI,
     function_ref<AssumptionCache &(Function &)> GetAssumptionCache,
     function_ref<AAResults &(Function &)> GetAAR,
-    function_ref<BlockFrequencyInfo &(Function &)> GetBFI) {
+    function_ref<BlockFrequencyInfo &(Function &)> GetBFI,
+    function_ref<BlockFrequencyInfo *(Function &)> GetCachedBFI) {
   SmallSetVector<CallBase *, 16> Calls;
   bool Changed = false;
   SmallVector<Function *, 16> InlinedComdatFunctions;
@@ -61,9 +62,11 @@ bool AlwaysInlineImpl(
       DebugLoc DLoc = CB->getDebugLoc();
       BasicBlock *Block = CB->getParent();
 
-      InlineFunctionInfo IFI(GetAssumptionCache, &PSI,
-                             GetBFI ? &GetBFI(*Caller) : nullptr,
-                             GetBFI ? &GetBFI(F) : nullptr);
+      // Only update CallerBFI if already available. The CallerBFI update
+      // requires CalleeBFI.
+      BlockFrequencyInfo *CallerBFI = GetCachedBFI(*Caller);
+      InlineFunctionInfo IFI(GetAssumptionCache, &PSI, CallerBFI,
+                             CallerBFI ? &GetBFI(F) : nullptr);
 
       InlineResult Res = InlineFunction(*CB, IFI, /*MergeAttributes=*/true,
                                         &GetAAR(F), InsertLifetime);
@@ -133,9 +136,12 @@ struct AlwaysInlinerLegacyPass : public ModulePass {
     auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {
       return getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
     };
+    auto GetCachedBFI = [&](Function &) -> BlockFrequencyInfo * {
+      return nullptr;
+    };
 
     return AlwaysInlineImpl(M, InsertLifetime, PSI, GetAssumptionCache, GetAAR,
-                            /*GetBFI*/ nullptr);
+                            /*GetBFI=*/nullptr, GetCachedBFI);
   }
 
   static char ID; // Pass identification, replacement for typeid
@@ -172,13 +178,16 @@ PreservedAnalyses AlwaysInlinerPass::run(Module &M,
   auto GetBFI = [&](Function &F) -> BlockFrequencyInfo & {
     return FAM.getResult<BlockFrequencyAnalysis>(F);
   };
+  auto GetCachedBFI = [&](Function &F) -> BlockFrequencyInfo * {
+    return FAM.getCachedResult<BlockFrequencyAnalysis>(F);
+  };
   auto GetAAR = [&](Function &F) -> AAResults & {
     return FAM.getResult<AAManager>(F);
   };
   auto &PSI = MAM.getResult<ProfileSummaryAnalysis>(M);
 
   bool Changed = AlwaysInlineImpl(M, InsertLifetime, PSI, GetAssumptionCache,
-                                  GetAAR, GetBFI);
+                                  GetAAR, GetBFI, GetCachedBFI);
 
   return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
 }

Copy link
Contributor

@fhahn fhahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@nikic nikic merged commit 43ee6f7 into llvm:main Nov 27, 2024
8 checks passed
@nikic nikic deleted the always-inline-bfi branch November 27, 2024 14:53
@mikaelholmen
Copy link
Collaborator

Hi,

I noticed that the following starts crashing with this patch:
opt -passes="function(pgo-memop-opt,loop(loop-unroll-full)),always-inline" bbi-102250.ll -S -o /dev/null
We hit

opt: ../lib/Analysis/BlockFrequencyInfoImpl.cpp:716: void findIrreducibleHeaders(const BlockFrequencyInfoImplBase &, const IrreducibleGraph &, const std::vector<const IrreducibleGraph::IrrNode *> &, LoopData::NodeList &, LoopData::NodeList &): Assertion `Headers.size() >= 2 && "Expected irreducible CFG; -loop-info is likely invalid"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: ../../main-github/llvm/build-all/bin/opt -passes=function(pgo-memop-opt,loop(loop-unroll-full)),always-inline bbi-102250.ll -S -o /dev/null
1.	Running pass "always-inline" on module "bbi-102250.ll"
 #0 0x0000558433a323a6 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (../../main-github/llvm/build-all/bin/opt+0x441d3a6)
 #1 0x0000558433a2fdce llvm::sys::RunSignalHandlers() (../../main-github/llvm/build-all/bin/opt+0x441adce)
 #2 0x0000558433a32c59 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007fa2d92e6cf0 __restore_rt (/lib64/libpthread.so.0+0x12cf0)
 #4 0x00007fa2d6c97acf raise (/lib64/libc.so.6+0x4eacf)
 #5 0x00007fa2d6c6aea5 abort (/lib64/libc.so.6+0x21ea5)
 #6 0x00007fa2d6c6ad79 _nl_load_domain.cold.0 (/lib64/libc.so.6+0x21d79)
 #7 0x00007fa2d6c90426 (/lib64/libc.so.6+0x47426)
 #8 0x0000558434109987 llvm::BlockFrequencyInfoImplBase::analyzeIrreducible(llvm::bfi_detail::IrreducibleGraph const&, llvm::BlockFrequencyInfoImplBase::LoopData*, std::_List_iterator<llvm::BlockFrequencyInfoImplBase::LoopData>) (../../main-github/llvm/build-all/bin/opt+0x4af4987)
 #9 0x00005584340fa85e llvm::BlockFrequencyInfoImpl<llvm::BasicBlock>::computeIrreducibleMass(llvm::BlockFrequencyInfoImplBase::LoopData*, std::_List_iterator<llvm::BlockFrequencyInfoImplBase::LoopData>) (../../main-github/llvm/build-all/bin/opt+0x4ae585e)
#10 0x00005584340f201a llvm::BlockFrequencyInfoImpl<llvm::BasicBlock>::calculate(llvm::Function const&, llvm::BranchProbabilityInfo const&, llvm::LoopInfo const&) (../../main-github/llvm/build-all/bin/opt+0x4add01a)
#11 0x00005584340f1973 llvm::BlockFrequencyInfo::calculate(llvm::Function const&, llvm::BranchProbabilityInfo const&, llvm::LoopInfo const&) (../../main-github/llvm/build-all/bin/opt+0x4adc973)
#12 0x00005584340f403a llvm::BlockFrequencyAnalysis::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (../../main-github/llvm/build-all/bin/opt+0x4adf03a)
#13 0x000055843566677b llvm::detail::AnalysisPassModel<llvm::Function, llvm::BlockFrequencyAnalysis, llvm::AnalysisManager<llvm::Function>::Invalidator>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) PassBuilder.cpp:0:0
#14 0x0000558433c52984 llvm::AnalysisManager<llvm::Function>::getResultImpl(llvm::AnalysisKey*, llvm::Function&) (../../main-github/llvm/build-all/bin/opt+0x463d984)
#15 0x00005584345934ab llvm::BlockFrequencyInfo& llvm::function_ref<llvm::BlockFrequencyInfo& (llvm::Function&)>::callback_fn<llvm::AlwaysInlinerPass::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&)::$_1>(long, llvm::Function&) AlwaysInliner.cpp:0:0
#16 0x0000558434591bb9 (anonymous namespace)::AlwaysInlineImpl(llvm::Module&, bool, llvm::ProfileSummaryInfo&, llvm::function_ref<llvm::AssumptionCache& (llvm::Function&)>, llvm::function_ref<llvm::AAResults& (llvm::Function&)>, llvm::function_ref<llvm::BlockFrequencyInfo& (llvm::Function&)>, llvm::function_ref<llvm::BlockFrequencyInfo* (llvm::Function&)>) AlwaysInliner.cpp:0:0
#17 0x00005584345916a1 llvm::AlwaysInlinerPass::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (../../main-github/llvm/build-all/bin/opt+0x4f7c6a1)
#18 0x0000558434e5adfd llvm::detail::PassModel<llvm::Module, llvm::AlwaysInlinerPass, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) PassBuilderPipelines.cpp:0:0
#19 0x0000558433c4e217 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (../../main-github/llvm/build-all/bin/opt+0x4639217)
#20 0x0000558434dee09c llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (../../main-github/llvm/build-all/bin/opt+0x57d909c)
#21 0x00005584339f570a optMain (../../main-github/llvm/build-all/bin/opt+0x43e070a)
#22 0x00007fa2d6c83d85 __libc_start_main (/lib64/libc.so.6+0x3ad85)
#23 0x00005584339f32ee _start (../../main-github/llvm/build-all/bin/opt+0x43de2ee)
Abort (core dumped)

bbi-102250.ll.gz

@nikic
Copy link
Contributor Author

nikic commented Dec 11, 2024

Thanks for the report. Also reproduces with -passes="function(require<block-freq>,loop(loop-unroll-full)),always-inline".

The problem here is that we can't really fetch analyses during inlining at all, because AlwaysInliner doesn't invalidate existing analyses incrementally (i.e. for each modified function).

But then, now that I look closed, if we actually inline anything, then we're not preserving any analysis at all, so there is no need to update BFI in the first place.

nikic added a commit to nikic/llvm-project that referenced this pull request Dec 11, 2024
This is a followup to llvm#117750. Currently, AlwaysInline only
invalidates analyses at the end, by returning that no analyses
are preserved. However, this means that analyses fetched during
inlining may be outdated. The aforementioned PR exposed this issue.

Instead, bring the logic closer to what the normal inliner does,
by directly invalidating the caller in FAM. This should make sure
that we don't receive any outdated analyses even if they are fetched
during inlining.

Also drop the BFI updating entirely -- there's no point in doing
it if we're going to invalidate everything anyway.
@nikic
Copy link
Contributor Author

nikic commented Dec 11, 2024

Candidate fix: #119566

nikic added a commit to nikic/llvm-project that referenced this pull request Dec 12, 2024
This is a followup to llvm#117750. Currently, AlwaysInline only
invalidates analyses at the end, by returning that no analyses
are preserved. However, this means that analyses fetched during
inlining may be outdated. The aforementioned PR exposed this issue.

Instead, bring the logic closer to what the normal inliner does,
by directly invalidating the caller in FAM. This should make sure
that we don't receive any outdated analyses even if they are fetched
during inlining.

Also drop the BFI updating entirely -- there's no point in doing
it if we're going to invalidate everything anyway.
nikic added a commit that referenced this pull request Dec 12, 2024
This is a followup to #117750. Currently, AlwaysInline only invalidates
analyses at the end, by returning that no analyses are preserved.
However, this means that analyses fetched during inlining may be
outdated. The aforementioned PR exposed this issue.

Instead, bring the logic closer to what the normal inliner does, by
directly invalidating the caller in FAM. This should make sure that we
don't receive any outdated analyses even if they are fetched during
inlining.

Also drop the BFI updating entirely -- there's no point in doing it if
we're going to invalidate everything anyway.
@mikaelholmen
Copy link
Collaborator

Candidate fix: #119566

Thank you! I've verifed that the fix you pushed solves the original problem I saw.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants