[llvm-branch-commits] [llvm] [DTU] fix dominator tree update eliding reachable nodes (PR #177683)
Mircea Trofin via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Feb 20 06:53:24 PST 2026
https://github.com/mtrofin updated https://github.com/llvm/llvm-project/pull/177683
>From 32d5e5401ab4c151de1a8664415de620b1c6ac3f Mon Sep 17 00:00:00 2001
From: Mircea Trofin <mtrofin at google.com>
Date: Wed, 21 Jan 2026 19:09:54 -0800
Subject: [PATCH] domtree
---
.../llvm/Support/GenericDomTreeConstruction.h | 7 +-
.../unittests/Analysis/DomTreeUpdaterTest.cpp | 220 ++++++++++++++++++
2 files changed, 225 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
index 709b2d59c9713..511c28400e347 100644
--- a/llvm/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/llvm/include/llvm/Support/GenericDomTreeConstruction.h
@@ -1127,9 +1127,12 @@ template <typename DomTreeT> struct SemiNCAInfo {
SNCA.clear();
// Identify nodes that remain in the affected subtree.
- auto DescendBelow = [MinLevel, &DT](NodePtr, NodePtr To) {
+ auto DescendBelow = [MinLevel, &DT](NodePtr R, NodePtr To) {
const TreeNodePtr ToTN = DT.getNode(To);
- return ToTN && ToTN->getLevel() > MinLevel;
+ if (ToTN)
+ return ToTN->getLevel() > MinLevel;
+ DT.createNode(To, DT.getNode(R));
+ return true;
};
SNCA.runDFS(MinNode->getBlock(), 0, DescendBelow, 0);
diff --git a/llvm/unittests/Analysis/DomTreeUpdaterTest.cpp b/llvm/unittests/Analysis/DomTreeUpdaterTest.cpp
index 9f5fe5742a44d..7d15bf7c8f79f 100644
--- a/llvm/unittests/Analysis/DomTreeUpdaterTest.cpp
+++ b/llvm/unittests/Analysis/DomTreeUpdaterTest.cpp
@@ -7,15 +7,19 @@
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/DomTreeUpdater.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Dominators.h"
+#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -829,3 +833,219 @@ brfalse: ; preds = %brtrue, %entry
DominatorTree NewDT(*F);
ASSERT_FALSE(NewDT.compare(DTU.getDomTree()));
}
+
+TEST(DomTreeUpdater, BlockStillReachable) {
+ StringRef ModuleString = R"(
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @the_caller(i1 %arg) personality ptr null {
+bb:
+ br i1 %arg, label %bb9, label %bb1
+
+bb1: ; preds = %bb
+ br i1 %arg, label %bb2, label %bb10
+
+bb2: ; preds = %bb1
+ br i1 %arg, label %bb3, label %bb6
+
+bb3: ; preds = %bb2
+ invoke void @the_callee(ptr null)
+ to label %bb4 unwind label %bb5
+
+bb4: ; preds = %bb3
+ unreachable
+
+bb5: ; preds = %bb3
+ %landingpad = landingpad { ptr, i32 }
+ cleanup
+ br label %bb8
+
+bb6: ; preds = %bb2
+ br label %bb8
+
+bb8: ; preds = %bb6, %bb5
+ br label %bb12
+
+bb9: ; preds = %bb
+ ret i32 0
+
+bb10: ; preds = %bb1
+ br label %bb12
+
+bb12: ; preds = %bb10, %bb8
+ resume { ptr, i32 } zeroinitializer
+}
+
+
+define void @the_callee(ptr %arg) alwaysinline personality ptr null {
+bb:
+ invoke void @foo(ptr null, ptr null)
+ to label %bb1 unwind label %bb2
+
+bb1: ; preds = %bb
+ unreachable
+
+bb2: ; preds = %bb
+ %landingpad = landingpad { ptr, i32 }
+ cleanup
+ resume { ptr, i32 } zeroinitializer
+}
+
+declare void @foo(ptr, ptr)
+
+ )";
+ // Make the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
+ Function *Caller = M->getFunction("the_caller");
+ Function *Callee = M->getFunction("the_callee");
+ ASSERT_NE(Caller, nullptr);
+ ASSERT_NE(Callee, nullptr);
+ InvokeInst *CallWombat1 = [&]() -> InvokeInst * {
+ for (auto &BB : *Caller)
+ for (auto &I : BB)
+ if (auto *Inv = dyn_cast<InvokeInst>(&I))
+ if (Inv->getCalledFunction() && (Inv->getCalledFunction() == Callee))
+ return Inv;
+ return nullptr;
+ }();
+ ASSERT_NE(CallWombat1, nullptr);
+ DominatorTree DT(*Caller);
+ ASSERT_TRUE(DT.verify(DominatorTree::VerificationLevel::Full));
+
+ InlineFunctionInfo IFI;
+ InlineFunction(*CallWombat1, IFI);
+
+ auto GetBBByName = [&](StringRef Name) -> BasicBlock * {
+ for (auto &BB : *Caller)
+ if (BB.getName() == Name)
+ return &BB;
+ return nullptr;
+ };
+ SmallVector<DominatorTree::UpdateType, 2> DomTreeUpdates;
+ DomTreeUpdates.push_back({DominatorTree::UpdateKind::Insert,
+ GetBBByName("bb3"), GetBBByName("bb1.i")});
+ DomTreeUpdates.push_back({DominatorTree::UpdateKind::Insert,
+ GetBBByName("bb3"), GetBBByName("bb2.i")});
+ DomTreeUpdates.push_back({DominatorTree::UpdateKind::Delete,
+ GetBBByName("bb3"), GetBBByName("bb4")});
+ DomTreeUpdates.push_back({DominatorTree::UpdateKind::Delete,
+ GetBBByName("bb3"), GetBBByName("bb5")});
+ DomTreeUpdates.push_back({DominatorTree::UpdateKind::Delete,
+ GetBBByName("bb5"), GetBBByName("bb8")});
+
+ DT.applyUpdates(DomTreeUpdates);
+
+ ASSERT_TRUE(DT.verify(DominatorTree::VerificationLevel::Full));
+}
+
+TEST(DomTreeUpdater, BlockStillReachableStepByStep) {
+ StringRef ModuleString = R"(
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @the_caller(i1 %arg) personality ptr null {
+bb:
+ br i1 %arg, label %bb9, label %bb1
+
+bb1: ; preds = %bb
+ br i1 %arg, label %bb2, label %bb10
+
+bb2: ; preds = %bb1
+ br i1 %arg, label %bb3, label %bb6
+
+bb3: ; preds = %bb2
+ invoke void @the_callee(ptr null)
+ to label %bb4 unwind label %bb5
+
+bb4: ; preds = %bb3
+ unreachable
+
+bb5: ; preds = %bb3
+ %landingpad = landingpad { ptr, i32 }
+ cleanup
+ br label %bb8
+
+bb6: ; preds = %bb2
+ br label %bb8
+
+bb8: ; preds = %bb6, %bb5
+ br label %bb12
+
+bb9: ; preds = %bb
+ ret i32 0
+
+bb10: ; preds = %bb1
+ br label %bb12
+
+bb12: ; preds = %bb10, %bb8
+ resume { ptr, i32 } zeroinitializer
+}
+
+
+define void @the_callee(ptr %arg) alwaysinline personality ptr null {
+bb:
+ invoke void @foo(ptr null, ptr null)
+ to label %bb1 unwind label %bb2
+
+bb1: ; preds = %bb
+ unreachable
+
+bb2: ; preds = %bb
+ %landingpad = landingpad { ptr, i32 }
+ cleanup
+ resume { ptr, i32 } zeroinitializer
+}
+
+declare void @foo(ptr, ptr)
+
+ )";
+ // Make the module.
+ LLVMContext Context;
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
+ Function *Caller = M->getFunction("the_caller");
+ Function *Callee = M->getFunction("the_callee");
+ ASSERT_NE(Caller, nullptr);
+ ASSERT_NE(Callee, nullptr);
+ InvokeInst *CallWombat1 = [&]() -> InvokeInst * {
+ for (auto &BB : *Caller)
+ for (auto &I : BB)
+ if (auto *Inv = dyn_cast<InvokeInst>(&I))
+ if (Inv->getCalledFunction() && (Inv->getCalledFunction() == Callee))
+ return Inv;
+ return nullptr;
+ }();
+ ASSERT_NE(CallWombat1, nullptr);
+ DominatorTree DT(*Caller);
+ ASSERT_TRUE(DT.verify(DominatorTree::VerificationLevel::Full));
+
+ InlineFunctionInfo IFI;
+ InlineFunction(*CallWombat1, IFI);
+
+ auto GetBBByName = [&](StringRef Name) -> BasicBlock * {
+ for (auto &BB : *Caller)
+ if (BB.getName() == Name)
+ return &BB;
+ return nullptr;
+ };
+ SmallVector<DominatorTree::UpdateType, 2> DomTreeUpdates;
+ DomTreeUpdates.push_back({DominatorTree::UpdateKind::Insert,
+ GetBBByName("bb3"), GetBBByName("bb1.i")});
+ DomTreeUpdates.push_back({DominatorTree::UpdateKind::Insert,
+ GetBBByName("bb3"), GetBBByName("bb2.i")});
+
+ DT.applyUpdates(DomTreeUpdates);
+
+ ASSERT_NE(DT.getNode(GetBBByName("bb5.body")), nullptr);
+
+ DomTreeUpdates.clear();
+ DomTreeUpdates.push_back({DominatorTree::UpdateKind::Delete,
+ GetBBByName("bb3"), GetBBByName("bb4")});
+ DomTreeUpdates.push_back({DominatorTree::UpdateKind::Delete,
+ GetBBByName("bb3"), GetBBByName("bb5")});
+ DomTreeUpdates.push_back({DominatorTree::UpdateKind::Delete,
+ GetBBByName("bb5"), GetBBByName("bb8")});
+
+ DT.applyUpdates(DomTreeUpdates);
+
+ ASSERT_TRUE(DT.verify(DominatorTree::VerificationLevel::Full));
+}
More information about the llvm-branch-commits
mailing list