[llvm] [Inliner] Fix assertion failure in BlockAddress::get during inlining (PR #176044)
Aniket Singh via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 18 01:14:10 PST 2026
https://github.com/Aniketsingh54 updated https://github.com/llvm/llvm-project/pull/176044
>From cf13f699fc215ac781278dc62d5b6c769acf4142 Mon Sep 17 00:00:00 2001
From: Aniket Singh <amiket.singh.3200.00 at gmail.com>
Date: Sat, 17 Jan 2026 04:20:21 +0530
Subject: [PATCH] [Inliner] Disallow inlining of blockaddresses
BlockAddress users were previously allowed to be inlined if they were used
by a CallBrInst. However, CallBrInst no longer uses BlockAddress, so this
exception is no longer valid.
This patch removes the exception and simplifies the check. It now rejects
inlining immediately if a block address is taken, rather than iterating
through users. This prevents the inliner from attempting to inline
functions with escaping BlockAddresses, avoiding an assertion failure
in BlockAddress::get()
Fixes #175516
---
llvm/lib/Analysis/InlineCost.cpp | 13 ++++-------
.../Inline/blockaddress-inlining.ll | 23 +++++++++++++++++++
2 files changed, 27 insertions(+), 9 deletions(-)
create mode 100644 llvm/test/Transforms/Inline/blockaddress-inlining.ll
diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp
index 5169b43834edc..0e49b1903d410 100644
--- a/llvm/lib/Analysis/InlineCost.cpp
+++ b/llvm/lib/Analysis/InlineCost.cpp
@@ -2980,7 +2980,7 @@ InlineResult CallAnalyzer::analyze() {
onBlockStart(BB);
- // Disallow inlining a blockaddress with uses other than strictly callbr.
+ // Disallow inlining a blockaddress.
// A blockaddress only has defined behavior for an indirect branch in the
// same function, and we do not currently support inlining indirect
// branches. But, the inliner may not see an indirect branch that ends up
@@ -2989,9 +2989,7 @@ InlineResult CallAnalyzer::analyze() {
// invalid cross-function reference.
// FIXME: pr/39560: continue relaxing this overt restriction.
if (BB->hasAddressTaken())
- for (User *U : BlockAddress::get(&*BB)->users())
- if (!isa<CallBrInst>(*U))
- return InlineResult::failure("blockaddress used outside of callbr");
+ return InlineResult::failure("blockaddress used");
// Analyze the cost of this block. If we blow through the threshold, this
// returns false, and we can bail on out.
@@ -3320,12 +3318,9 @@ InlineResult llvm::isInlineViable(Function &F) {
if (isa<IndirectBrInst>(BB.getTerminator()))
return InlineResult::failure("contains indirect branches");
- // Disallow inlining of blockaddresses which are used by non-callbr
- // instructions.
+ // Disallow inlining of blockaddresses.
if (BB.hasAddressTaken())
- for (User *U : BlockAddress::get(&BB)->users())
- if (!isa<CallBrInst>(*U))
- return InlineResult::failure("blockaddress used outside of callbr");
+ return InlineResult::failure("blockaddress used");
for (auto &II : BB) {
CallBase *Call = dyn_cast<CallBase>(&II);
diff --git a/llvm/test/Transforms/Inline/blockaddress-inlining.ll b/llvm/test/Transforms/Inline/blockaddress-inlining.ll
new file mode 100644
index 0000000000000..37f58562c7aee
--- /dev/null
+++ b/llvm/test/Transforms/Inline/blockaddress-inlining.ll
@@ -0,0 +1,23 @@
+; RUN: opt -S -passes=always-inline %s | FileCheck %s
+
+; Ensure that a function with a blockaddress usage is NOT inlined.
+; Previously, this caused a crash because the inliner tried to inline it anyway.
+
+define void @callee(i32 %b) alwaysinline {
+entry:
+ callbr void asm sideeffect "", "r,!i"(ptr blockaddress(@callee, %target))
+ to label %fallthrough [label %target]
+
+fallthrough:
+ ret void
+
+target:
+ ret void
+}
+
+define void @caller() {
+; CHECK-LABEL: define void @caller()
+; CHECK: call void @callee
+ call void @callee(i32 1)
+ ret void
+}
More information about the llvm-commits
mailing list