[llvm] Refund inline cost for blocks terminating in unreachable (PR #213983)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 4 08:29:03 PDT 2026


https://github.com/stephenduong1004 created https://github.com/llvm/llvm-project/pull/213983

This patch addresses the `FIXME` in `CallAnalyzer::visitUnreachableInst` by refunding the accumulated cost of a basic block if it terminates in an `unreachable` instruction. 

Currently, `unreachable` instructions themselves have zero cost. However, the instructions leading up to them are still added to the inline cost budget. Because `analyzeBlock` bails out early if `shouldStop()` evaluates to true, functions with multiple dead-end panic branches artificially inflate their cost and fail to inline.

This is particularly helpful for Rust when compiled with `panic=abort`. While `panic=unwind` generates `invoke` + `landingpad` blocks, `panic=abort` generates a standard `call` + `unreachable` sequence. 


>From 82802d3f5e65800c7505138d833ad1f56219e40e Mon Sep 17 00:00:00 2001
From: Stephen <stephenduong at google.com>
Date: Tue, 4 Aug 2026 11:24:19 -0400
Subject: [PATCH] refund unreachable inline cost

---
 llvm/lib/Analysis/InlineCost.cpp | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp
index 6cd84376d8a98..bad818a4a8fc2 100644
--- a/llvm/lib/Analysis/InlineCost.cpp
+++ b/llvm/lib/Analysis/InlineCost.cpp
@@ -865,6 +865,12 @@ class InlineCostCallAnalyzer final : public CallAnalyzer {
     }
 
     auto *TI = BB->getTerminator();
+
+    // Refund the accumulated cost of dead-end panic paths.
+    if (isa<UnreachableInst>(TI)) {
+      addCost(CostAtBBStart - Cost);
+    }
+
     // If we had any successors at this point, than post-inlining is likely to
     // have them as well. Note that we assume any basic blocks which existed
     // due to branches or switches which folded above will also fold after
@@ -2706,9 +2712,6 @@ bool CallAnalyzer::visitCatchReturnInst(CatchReturnInst &CRI) {
 }
 
 bool CallAnalyzer::visitUnreachableInst(UnreachableInst &I) {
-  // FIXME: It might be reasonably to discount the cost of instructions leading
-  // to unreachable as they have the lowest possible impact on both runtime and
-  // code size.
   return true; // No actual code is needed for unreachable.
 }
 
@@ -2737,6 +2740,8 @@ bool CallAnalyzer::visitInstruction(Instruction &I) {
 InlineResult
 CallAnalyzer::analyzeBlock(BasicBlock *BB,
                            const SmallPtrSetImpl<const Value *> &EphValues) {
+  bool IsUnreachablePath = isa<UnreachableInst>(BB->getTerminator());
+
   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,
@@ -2753,9 +2758,13 @@ CallAnalyzer::analyzeBlock(BasicBlock *BB,
     if (EphValues.count(&I))
       continue;
 
-    ++NumInstructions;
-    if (isa<ExtractElementInst>(I) || I.getType()->isVectorTy())
-      ++NumVectorInstructions;
+    // Do not increment raw instruction counts for unreachable
+    // paths to prevent penalizing the vector bonus heuristic.
+    if (!IsUnreachablePath) {
+      ++NumInstructions;
+      if (isa<ExtractElementInst>(I) || I.getType()->isVectorTy())
+        ++NumVectorInstructions;
+    }
 
     // If the instruction simplified to a constant, there is no cost to this
     // instruction. Visit the instructions using our InstVisitor to account for
@@ -2814,7 +2823,7 @@ CallAnalyzer::analyzeBlock(BasicBlock *BB,
       return IR;
     }
 
-    if (shouldStop())
+    if (!IsUnreachablePath && shouldStop())
       return InlineResult::failure(
           "Call site analysis is not favorable to inlining.");
   }



More information about the llvm-commits mailing list