[llvm] [SandboxVec][DAG] Fix notifyEraseInstr to skip scheduled neighbors (PR #212868)

Anshil Gandhi via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 29 22:47:02 PDT 2026


https://github.com/gandhi56 updated https://github.com/llvm/llvm-project/pull/212868

>From 528ee3726d0c363c9c8c37c1f6154e678790f852 Mon Sep 17 00:00:00 2001
From: Anshil Gandhi <gandhi21299 at gmail.com>
Date: Wed, 29 Jul 2026 16:45:40 -0400
Subject: [PATCH] [SandboxIR] Fix notifyEraseInstr to skip scheduled neighbors

Guard both loops with !PredN->scheduled() / !SuccN->scheduled() so
scheduled neighbors are left untouched, and add a unit test that erases
a node with one scheduled and one unscheduled predecessor to cover the
fix.
---
 .../SandboxVectorizer/DependencyGraph.cpp     |  3 +-
 .../SandboxVectorizer/DependencyGraphTest.cpp | 43 +++++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp
index 11149a16b044f..55d5419bd2f59 100644
--- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp
+++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp
@@ -583,7 +583,8 @@ void DependencyGraph::notifyEraseInstr(Instruction *I) {
     // If this is a non-mem node we only need to update UnscheduledSuccs.
     if (!N->scheduled()) {
       for (auto *PredN : N->preds(*this))
-        PredN->decrUnscheduledSuccs();
+        if (!PredN->scheduled())
+          PredN->decrUnscheduledSuccs();
       for (auto *SuccN : N->succs(*this))
         SuccN->decrUnscheduledPreds();
     }
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp
index 831976875f8d3..b789b421d1563 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp
@@ -1516,3 +1516,46 @@ define void @foo(i8 %v0) {
   Add0->setOperand(0, Sched);
   EXPECT_EQ(Add0N->getNumUnscheduledPreds(), 0u);
 }
+
+// When erasing a non-mem instruction we must not touch the UnscheduledSuccs
+// of an already-scheduled predecessor, since that counter is set to
+// std::nullopt once a node is scheduled.
+TEST_F(DependencyGraphTest, EraseInstrCallbackNonMemWithScheduledPred) {
+  parseIR(C, R"IR(
+define void @foo(i8 %v0) {
+  %predSched = add i8 %v0, 0
+  %predUnsched = add i8 %v0, 1
+  %n = add i8 %predSched, %predUnsched
+  ret void
+}
+)IR");
+  llvm::Function *LLVMF = &*M->getFunction("foo");
+  sandboxir::Context Ctx(C);
+  auto *F = Ctx.createFunction(LLVMF);
+  auto *BB = &*F->begin();
+  auto It = BB->begin();
+  auto *PredSched = cast<sandboxir::BinaryOperator>(&*It++);
+  auto *PredUnsched = cast<sandboxir::BinaryOperator>(&*It++);
+  auto *N = cast<sandboxir::BinaryOperator>(&*It++);
+
+  sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx);
+  DAG.extend({PredSched, N});
+  auto *PredSchedN = DAG.getNode(PredSched);
+  auto *PredUnschedN = DAG.getNode(PredUnsched);
+  EXPECT_EQ(PredSchedN->getNumUnscheduledSuccs(), 1u);
+  EXPECT_EQ(PredUnschedN->getNumUnscheduledSuccs(), 1u);
+
+  // Mark one of N's predecessors as scheduled. Its UnscheduledSuccs becomes
+  // std::nullopt.
+  PredSchedN->setScheduled();
+
+  // Erase N, which is *not* scheduled. This must not attempt to decrement
+  // the (now invalid) UnscheduledSuccs of PredSchedN, but should still
+  // update the counter of the unscheduled predecessor.
+  N->eraseFromParent();
+  EXPECT_EQ(DAG.getNode(N), nullptr);
+  EXPECT_EQ(PredUnschedN->getNumUnscheduledSuccs(), 0u);
+#ifndef NDEBUG
+  EXPECT_FALSE(PredSchedN->validUnscheduledSuccs());
+#endif
+}



More information about the llvm-commits mailing list