[llvm] [SandboxVec][Scheduler][DAG] Fix the update of DGNode on setOperand (PR #214110)

Anshil Gandhi via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 7 10:54:05 PDT 2026


gandhi56 wrote:

Hey @vporpo, could you try this test:

```

// Rewiring a use while a schedule is live must not leave a stale entry in the
// ready list. `DependencyGraph::notifySetUse()` bumps the UnscheduledSuccs
// counter of the new operand's node, which makes that node un-ready, but
// nothing removes it from the scheduler's ready list. Compare with
// `Scheduler::notifyCreateInstr()`, which calls `ReadyList.remove()` before
// incrementing the counter. `tryScheduleUntil()` then pops the stale node and,
// since it does not belong to a bundle yet, schedules it as a singleton
// without re-checking readiness, placing the definition below its user.
TEST_F(SchedulerTest, StaleReadyListAfterSetUse_BottomUp) {
  parseIR(C, R"IR(
define void @foo(ptr %ptr, i8 %arg) {
  %t = add i8 %arg, %arg
  %p = add i8 %arg, %arg
  %u = add i8 %arg, %arg
  %x = add i8 %u, %arg
  store i8 %arg, ptr %ptr
  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 *T = cast<sandboxir::BinaryOperator>(&*It++);
  auto *P = cast<sandboxir::BinaryOperator>(&*It++);
  auto *U = cast<sandboxir::BinaryOperator>(&*It++);
  auto *X = cast<sandboxir::BinaryOperator>(&*It++);
  auto *S = cast<sandboxir::StoreInst>(&*It++);

  sandboxir::Scheduler Sched(getAA(*LLVMF), Ctx, BottomUp);
  auto &DAG = sandboxir::SchedulerInternalsAttorney::getDAG(Sched);

  EXPECT_TRUE(Sched.trySchedule({S}));
  // This extends the DAG up to %t and puts %t, %p and %x in the ready list (%u
  // is not ready because %x uses it). Only %t gets scheduled because it is the
  // first one popped, so %p and %x are left in the ready list.
  EXPECT_TRUE(Sched.trySchedule({T}));
  auto *PN = DAG.getNode(P);
  auto *UN = DAG.getNode(U);
  ASSERT_FALSE(PN->scheduled());
  ASSERT_FALSE(UN->scheduled());
  ASSERT_EQ(PN->getNumUnscheduledSuccs(), 0u);

  // Add the def-use edge %p->%u. %p is no longer ready, but it is still sitting
  // in the ready list.
  U->setOperand(0, P);
  EXPECT_EQ(PN->getNumUnscheduledSuccs(), 1u);

  // Scheduling %x pops the stale %p first and schedules it.
  EXPECT_TRUE(Sched.trySchedule({X}));
  // %p must not be scheduled while it still has an unscheduled successor, and
  // it must not end up below the user we just wired it to.
  EXPECT_FALSE(PN->scheduled() && !UN->scheduled());
  EXPECT_TRUE(P->comesBefore(U));
}
```

https://github.com/llvm/llvm-project/pull/214110


More information about the llvm-commits mailing list