[llvm] [BlockExtractor] Invalidate analyses after splitting landing pads (PR #217853)
Advit Arora via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 21 06:10:42 PDT 2026
https://github.com/advitrocks9 updated https://github.com/llvm/llvm-project/pull/217853
>From 8d6a1da121106ac04568297a285332596a01aaee Mon Sep 17 00:00:00 2001
From: Advit Arora <advitarora2 at gmail.com>
Date: Fri, 21 Aug 2026 14:20:58 +0530
Subject: [PATCH 1/2] [BlockExtractor] Invalidate analyses after splitting
landing pads
`-passes=extract-blocks` with no block list still edits the CFG. `splitLandingPadPreds` runs over every function before the block list is consulted and splits any landing pad whose predecessors include a landing pad other than the invoking block, but it never touched `runOnModule`'s `Changed` flag, so the pass returned `PreservedAnalyses::all()` and the DominatorTree cached by an earlier function pass survived a CFG it no longer describes.
Two consumers fall over on the reporter's input.
```
opt -passes='function(sroa),extract-blocks,function(instcombine)' test.ll -S
```
gives `br i1 poison` on a condition that is `icmp eq i32 0, 0`, because `prepareWorklist` asks the stale tree about blocks it has no node for. And
```
opt -passes='function(sroa),extract-blocks,function(jump-threading)' test.ll -disable-output
```
trips `assert(TN)` in `SemiNCAInfo::DeleteUnreachable`. Splicing `function(invalidate<domtree>)` in after `extract-blocks` makes both go away.
Make the split report itself; the existing ternary in `BlockExtractorPass::run` picks `none()` from there. A module the split does not touch still reports `all()`.
The test pins the contract rather than either symptom: `require<domtree>` on both sides of the pass under `-debug-pass-manager`, then `verify<domtree>` after it. Both RUN lines fail on an unpatched tree, the second aborting with the two blocks the split created missing from the cached tree.
Fixes https://github.com/llvm/llvm-project/issues/213833
---
llvm/lib/Transforms/IPO/BlockExtractor.cpp | 9 +++--
.../BlockExtractor/invalidate-analyses.ll | 33 +++++++++++++++++++
2 files changed, 39 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/Transforms/BlockExtractor/invalidate-analyses.ll
diff --git a/llvm/lib/Transforms/IPO/BlockExtractor.cpp b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
index 23991afc511a0..9bede77c8ac89 100644
--- a/llvm/lib/Transforms/IPO/BlockExtractor.cpp
+++ b/llvm/lib/Transforms/IPO/BlockExtractor.cpp
@@ -58,7 +58,7 @@ class BlockExtractor {
BlocksByName;
void loadFile();
- void splitLandingPadPreds(Function &F);
+ bool splitLandingPadPreds(Function &F);
};
} // end anonymous namespace
@@ -94,7 +94,8 @@ void BlockExtractor::loadFile() {
/// Extracts the landing pads to make sure all of them have only one
/// predecessor.
-void BlockExtractor::splitLandingPadPreds(Function &F) {
+bool BlockExtractor::splitLandingPadPreds(Function &F) {
+ bool Changed = false;
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
if (!isa<InvokeInst>(&I))
@@ -119,8 +120,10 @@ void BlockExtractor::splitLandingPadPreds(Function &F) {
SmallVector<BasicBlock *, 2> NewBBs;
SplitLandingPadPredecessors(LPad, Parent, ".1", ".2", NewBBs);
+ Changed = true;
}
}
+ return Changed;
}
bool BlockExtractor::runOnModule(Module &M) {
@@ -129,7 +132,7 @@ bool BlockExtractor::runOnModule(Module &M) {
// Get all the functions.
SmallVector<Function *, 4> Functions;
for (Function &F : M) {
- splitLandingPadPreds(F);
+ Changed |= splitLandingPadPreds(F);
Functions.push_back(&F);
}
diff --git a/llvm/test/Transforms/BlockExtractor/invalidate-analyses.ll b/llvm/test/Transforms/BlockExtractor/invalidate-analyses.ll
new file mode 100644
index 0000000000000..a558c0925f4e0
--- /dev/null
+++ b/llvm/test/Transforms/BlockExtractor/invalidate-analyses.ll
@@ -0,0 +1,33 @@
+; RUN: opt -passes='function(require<domtree>),extract-blocks,function(require<domtree>)' -debug-pass-manager -disable-output %s 2>&1 | FileCheck %s
+; RUN: opt -passes='function(require<domtree>),extract-blocks,function(verify<domtree>)' -disable-output %s
+
+; The landing pad split runs even with an empty block list, so the CFG changes.
+
+; CHECK: Running analysis: DominatorTreeAnalysis on foo
+; CHECK: Running pass: BlockExtractorPass
+; CHECK: Running analysis: DominatorTreeAnalysis on foo
+
+define void @foo() personality ptr @__gxx_personality_v0 {
+entry:
+ invoke void @bar()
+ to label %exit unwind label %lpad
+
+lpad:
+ %0 = landingpad { ptr, i32 }
+ catch ptr null
+ invoke void @bar()
+ to label %exit unwind label %lpad2
+
+lpad2:
+ %1 = landingpad { ptr, i32 }
+ cleanup
+ invoke void @bar()
+ to label %exit unwind label %lpad
+
+exit:
+ ret void
+}
+
+declare void @bar()
+
+declare i32 @__gxx_personality_v0(...)
>From 571fff7d3aa94b917a48b9200400f5d4ea6ac6f8 Mon Sep 17 00:00:00 2001
From: Advit Arora <advitarora2 at gmail.com>
Date: Fri, 21 Aug 2026 18:40:25 +0530
Subject: [PATCH 2/2] [BlockExtractor] Simplify invalidate-analyses test
---
llvm/test/Transforms/BlockExtractor/invalidate-analyses.ll | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/llvm/test/Transforms/BlockExtractor/invalidate-analyses.ll b/llvm/test/Transforms/BlockExtractor/invalidate-analyses.ll
index a558c0925f4e0..24c220979a921 100644
--- a/llvm/test/Transforms/BlockExtractor/invalidate-analyses.ll
+++ b/llvm/test/Transforms/BlockExtractor/invalidate-analyses.ll
@@ -1,11 +1,7 @@
-; RUN: opt -passes='function(require<domtree>),extract-blocks,function(require<domtree>)' -debug-pass-manager -disable-output %s 2>&1 | FileCheck %s
; RUN: opt -passes='function(require<domtree>),extract-blocks,function(verify<domtree>)' -disable-output %s
; The landing pad split runs even with an empty block list, so the CFG changes.
-
-; CHECK: Running analysis: DominatorTreeAnalysis on foo
-; CHECK: Running pass: BlockExtractorPass
-; CHECK: Running analysis: DominatorTreeAnalysis on foo
+; Ensure that we properly invalidate analyses.
define void @foo() personality ptr @__gxx_personality_v0 {
entry:
More information about the llvm-commits
mailing list