[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