Skip to content

[SandboxVec][Scheduler] Don't insert scheduled instrs into the ready list #127688

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 19, 2025

Conversation

vporpo
Copy link
Contributor

@vporpo vporpo commented Feb 18, 2025

In a particular scenario (see test) we used to insert scheduled instructions into the ready list. This patch fixes this by fixing the trimSchedule() function.

…list

In a particular scenario (see test) we used to insert scheduled instructions
into the ready list. This patch fixes this by fixing the trimSchedule()
function.
@llvmbot
Copy link
Member

llvmbot commented Feb 18, 2025

@llvm/pr-subscribers-llvm-transforms

Author: vporpo (vporpo)

Changes

In a particular scenario (see test) we used to insert scheduled instructions into the ready list. This patch fixes this by fixing the trimSchedule() function.


Full diff: https://github.com/llvm/llvm-project/pull/127688.diff

4 Files Affected:

  • (modified) llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h (+4)
  • (modified) llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h (+12-1)
  • (modified) llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp (+44-18)
  • (modified) llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp (+71)
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
index b25f96571741e..ede51c28fc94d 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
@@ -123,6 +123,10 @@ class DGNode {
     --UnscheduledSuccs;
   }
   void incrUnscheduledSuccs() { ++UnscheduledSuccs; }
+  void resetScheduleState() {
+    UnscheduledSuccs = 0;
+    Scheduled = false;
+  }
   /// \Returns true if all dependent successors have been scheduled.
   bool ready() const { return UnscheduledSuccs == 0; }
   /// \Returns true if this node has been scheduled.
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
index 6c2315af0e797..6b56f348f328c 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
@@ -61,7 +61,18 @@ class ReadyListContainer {
 
 public:
   ReadyListContainer() : List(Cmp) {}
-  void insert(DGNode *N) { List.push(N); }
+  void insert(DGNode *N) {
+#ifndef NDEBUG
+    assert(!N->scheduled() && "Don't insert a scheduled node!");
+    auto ListCopy = List;
+    while (!ListCopy.empty()) {
+      DGNode *Top = ListCopy.top();
+      ListCopy.pop();
+      assert(Top != N && "Node already exists in ready list!");
+    }
+#endif
+    List.push(N);
+  }
   DGNode *pop() {
     auto *Back = List.top();
     List.pop();
diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
index 2f7d7087ca880..3e37e07aabc5c 100644
--- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
+++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
@@ -77,12 +77,12 @@ void Scheduler::scheduleAndUpdateReadyList(SchedBundle &Bndl) {
   // Set nodes as "scheduled" and decrement the UnsceduledSuccs counter of all
   // dependency predecessors.
   for (DGNode *N : Bndl) {
-    N->setScheduled(true);
     for (auto *DepN : N->preds(DAG)) {
       DepN->decrUnscheduledSuccs();
-      if (DepN->ready())
+      if (DepN->ready() && !DepN->scheduled())
         ReadyList.insert(DepN);
     }
+    N->setScheduled(true);
   }
 }
 
@@ -188,6 +188,19 @@ Scheduler::getBndlSchedState(ArrayRef<Instruction *> Instrs) const {
 }
 
 void Scheduler::trimSchedule(ArrayRef<Instruction *> Instrs) {
+  //                                |  Legend: N: DGNode
+  //  N <- DAGInterval.top()        |          B: SchedBundle
+  //  N                             |          *: Contains instruction in Instrs
+  //  B <- TopI (Top of schedule)   +-------------------------------------------
+  //  B
+  //  B *
+  //  B
+  //  B * <- LowestI (Lowest in Instrs)
+  //  B
+  //  N
+  //  N
+  //  N <- DAGInterval.bottom()
+  //
   Instruction *TopI = &*ScheduleTopItOpt.value();
   Instruction *LowestI = VecUtils::getLowest(Instrs);
   // Destroy the schedule bundles from LowestI all the way to the top.
@@ -199,13 +212,28 @@ void Scheduler::trimSchedule(ArrayRef<Instruction *> Instrs) {
     if (auto *SB = N->getSchedBundle())
       eraseBundle(SB);
   }
-  // TODO: For now we clear the DAG. Trim view once it gets implemented.
-  Bndls.clear();
-  DAG.clear();
-
-  // Since we are scheduling NewRegion from scratch, we clear the ready lists.
-  // The nodes currently in the list may not be ready after clearing the View.
+  // The DAG Nodes contain state like the number of UnscheduledSuccs and the
+  // Scheduled flag. We need to reset their state. We need to do this for all
+  // nodes from LowestI to the top of the schedule. DAG Nodes that are above the
+  // top of schedule that depend on nodes that got reset need to have their
+  // UnscheduledSuccs adjusted.
+  Interval<Instruction> ResetIntvl(TopI, LowestI);
+  for (Instruction &I : ResetIntvl) {
+    auto *N = DAG.getNode(&I);
+    N->resetScheduleState();
+    // Recompute UnscheduledSuccs for nodes not only in ResetIntvl but even for
+    // nodes above the top of schedule.
+    for (auto *PredN : N->preds(DAG))
+      PredN->incrUnscheduledSuccs();
+  }
+  // Refill the ready list by visiting all nodes from the top of DAG to LowestI.
   ReadyList.clear();
+  Interval<Instruction> RefillIntvl(DAG.getInterval().top(), LowestI);
+  for (Instruction &I : RefillIntvl) {
+    auto *N = DAG.getNode(&I);
+    if (N->ready())
+      ReadyList.insert(N);
+  }
 }
 
 bool Scheduler::trySchedule(ArrayRef<Instruction *> Instrs) {
@@ -214,6 +242,12 @@ bool Scheduler::trySchedule(ArrayRef<Instruction *> Instrs) {
                   return I->getParent() == (*Instrs.begin())->getParent();
                 }) &&
          "Instrs not in the same BB, should have been rejected by Legality!");
+  // TODO: For now don't cross BBs.
+  if (!DAG.getInterval().empty()) {
+    auto *BB = DAG.getInterval().top()->getParent();
+    if (any_of(Instrs, [BB](auto *I) { return I->getParent() != BB; }))
+      return false;
+  }
   if (ScheduledBB == nullptr)
     ScheduledBB = Instrs[0]->getParent();
   // We don't support crossing BBs for now.
@@ -230,21 +264,13 @@ bool Scheduler::trySchedule(ArrayRef<Instruction *> Instrs) {
     // top-most part of the schedule that includes the instrs in the bundle and
     // re-schedule.
     trimSchedule(Instrs);
-    ScheduleTopItOpt = std::nullopt;
-    [[fallthrough]];
+    ScheduleTopItOpt = std::next(VecUtils::getLowest(Instrs)->getIterator());
+    return tryScheduleUntil(Instrs);
   case BndlSchedState::NoneScheduled: {
     // TODO: Set the window of the DAG that we are interested in.
     if (!ScheduleTopItOpt)
       // We start scheduling at the bottom instr of Instrs.
       ScheduleTopItOpt = std::next(VecUtils::getLowest(Instrs)->getIterator());
-
-    // TODO: For now don't cross BBs.
-    if (!DAG.getInterval().empty()) {
-      auto *BB = DAG.getInterval().top()->getParent();
-      if (any_of(Instrs, [BB](auto *I) { return I->getParent() != BB; }))
-        return false;
-    }
-
     // Extend the DAG to include Instrs.
     Interval<Instruction> Extension = DAG.extend(Instrs);
     // Add nodes to ready list.
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
index 0d5d86acaee89..7d88337e77faa 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
@@ -246,6 +246,77 @@ define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) {
   EXPECT_TRUE(Sched.trySchedule({L0, L1}));
 }
 
+// Check scheduling in the following order: {A0,A1},{B0,B1},{C0,C1},{D0,D1}
+// assuming program order: B0,B1,C0,C1,D0,D1,E0,D1.
+// This will effectively schedule nodes below already scheduled nodes, which
+// can expose issues in the code that adds nodes to the ready list.
+// For example, we schedule {D0,D1} while {C0,C1} are scheduled and there is
+// a dependency D0->C0 and D1->C1.
+//
+//                   {A0,A1}  {B0,B1}  {C0,C1}  {D0,D1}
+//   B0,B1                    | S
+//   |\                       |
+//   | C0,C1                  |        | S      | S
+//   |  | \                   |                 |
+//   |  |  D0,D1              |                 | S
+//   | /                      |
+//   A0,A1             | S    | S
+//                 +------------------------+
+//                 | Legend   |: DAG        |
+//                 |          S: Scheduled  |
+TEST_F(SchedulerTest, ScheduledPredecessors) {
+  parseIR(C, R"IR(
+define void @foo(ptr noalias %ptrA0, ptr noalias %ptrA1,
+                 ptr noalias %ptrB0, ptr noalias %ptrB1,
+                 ptr noalias %ptrD0, ptr noalias %ptrD1) {
+  %B0 = load i8, ptr %ptrB0
+  %B1 = load i8, ptr %ptrB1
+  %C0 = add i8 %B0, 0
+  %C1 = add i8 %B1, 1
+  store i8 %C0, ptr %ptrD0
+  store i8 %C1, ptr %ptrD1
+  store i8 %B0, ptr %ptrA0
+  store i8 %B1, ptr %ptrA1
+  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 *B1 = cast<sandboxir::LoadInst>(&*It++);
+  auto *B0 = cast<sandboxir::LoadInst>(&*It++);
+  auto *C1 = cast<sandboxir::BinaryOperator>(&*It++);
+  auto *C0 = cast<sandboxir::BinaryOperator>(&*It++);
+  auto *D1 = cast<sandboxir::StoreInst>(&*It++);
+  auto *D0 = cast<sandboxir::StoreInst>(&*It++);
+  auto *A1 = cast<sandboxir::StoreInst>(&*It++);
+  auto *A0 = cast<sandboxir::StoreInst>(&*It++);
+  auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
+
+  sandboxir::Scheduler Sched(getAA(*LLVMF), Ctx);
+  EXPECT_TRUE(Sched.trySchedule({A0, A1}));
+  // NOTE: We schedule the intermediate nodes between {A0,A1} and {B0,B1} by
+  // hand one by one to make sure they are scheduled in that order because
+  // the scheduler may reorder them a bit if we let it do it.
+  EXPECT_TRUE(Sched.trySchedule(D0));
+  EXPECT_TRUE(Sched.trySchedule(D1));
+  EXPECT_TRUE(Sched.trySchedule(C0));
+  EXPECT_TRUE(Sched.trySchedule(C1));
+  EXPECT_TRUE(Sched.trySchedule({B0, B1}));
+  // At this point all nodes must have been scheduled from B0,B1 to A0,A1.
+  // The ones in between are scheduled as single-instruction nodes.
+  // So when we attempt to schedule {C0,C1} we will need to reschedule.
+  // At this point we will trim the schedule from {C0,C1} upwards.
+  EXPECT_TRUE(Sched.trySchedule({C0, C1}));
+  // Now the schedule should only contain {C0,C1} which should be marked as
+  // "scheduled".
+  // {D0,D1} are below {C0,C1}, so we grow the DAG downwards, while
+  // {C0,C1} are marked as "scheduled" above them.
+  EXPECT_TRUE(Sched.trySchedule({D0, D1}));
+}
+
 TEST_F(SchedulerTest, DontCrossBBs) {
   parseIR(C, R"IR(
 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v0, i8 %v1) {

@llvmbot
Copy link
Member

llvmbot commented Feb 18, 2025

@llvm/pr-subscribers-vectorizers

Author: vporpo (vporpo)

Changes

In a particular scenario (see test) we used to insert scheduled instructions into the ready list. This patch fixes this by fixing the trimSchedule() function.


Full diff: https://github.com/llvm/llvm-project/pull/127688.diff

4 Files Affected:

  • (modified) llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h (+4)
  • (modified) llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h (+12-1)
  • (modified) llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp (+44-18)
  • (modified) llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp (+71)
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
index b25f96571741e..ede51c28fc94d 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
@@ -123,6 +123,10 @@ class DGNode {
     --UnscheduledSuccs;
   }
   void incrUnscheduledSuccs() { ++UnscheduledSuccs; }
+  void resetScheduleState() {
+    UnscheduledSuccs = 0;
+    Scheduled = false;
+  }
   /// \Returns true if all dependent successors have been scheduled.
   bool ready() const { return UnscheduledSuccs == 0; }
   /// \Returns true if this node has been scheduled.
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
index 6c2315af0e797..6b56f348f328c 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
@@ -61,7 +61,18 @@ class ReadyListContainer {
 
 public:
   ReadyListContainer() : List(Cmp) {}
-  void insert(DGNode *N) { List.push(N); }
+  void insert(DGNode *N) {
+#ifndef NDEBUG
+    assert(!N->scheduled() && "Don't insert a scheduled node!");
+    auto ListCopy = List;
+    while (!ListCopy.empty()) {
+      DGNode *Top = ListCopy.top();
+      ListCopy.pop();
+      assert(Top != N && "Node already exists in ready list!");
+    }
+#endif
+    List.push(N);
+  }
   DGNode *pop() {
     auto *Back = List.top();
     List.pop();
diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
index 2f7d7087ca880..3e37e07aabc5c 100644
--- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
+++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
@@ -77,12 +77,12 @@ void Scheduler::scheduleAndUpdateReadyList(SchedBundle &Bndl) {
   // Set nodes as "scheduled" and decrement the UnsceduledSuccs counter of all
   // dependency predecessors.
   for (DGNode *N : Bndl) {
-    N->setScheduled(true);
     for (auto *DepN : N->preds(DAG)) {
       DepN->decrUnscheduledSuccs();
-      if (DepN->ready())
+      if (DepN->ready() && !DepN->scheduled())
         ReadyList.insert(DepN);
     }
+    N->setScheduled(true);
   }
 }
 
@@ -188,6 +188,19 @@ Scheduler::getBndlSchedState(ArrayRef<Instruction *> Instrs) const {
 }
 
 void Scheduler::trimSchedule(ArrayRef<Instruction *> Instrs) {
+  //                                |  Legend: N: DGNode
+  //  N <- DAGInterval.top()        |          B: SchedBundle
+  //  N                             |          *: Contains instruction in Instrs
+  //  B <- TopI (Top of schedule)   +-------------------------------------------
+  //  B
+  //  B *
+  //  B
+  //  B * <- LowestI (Lowest in Instrs)
+  //  B
+  //  N
+  //  N
+  //  N <- DAGInterval.bottom()
+  //
   Instruction *TopI = &*ScheduleTopItOpt.value();
   Instruction *LowestI = VecUtils::getLowest(Instrs);
   // Destroy the schedule bundles from LowestI all the way to the top.
@@ -199,13 +212,28 @@ void Scheduler::trimSchedule(ArrayRef<Instruction *> Instrs) {
     if (auto *SB = N->getSchedBundle())
       eraseBundle(SB);
   }
-  // TODO: For now we clear the DAG. Trim view once it gets implemented.
-  Bndls.clear();
-  DAG.clear();
-
-  // Since we are scheduling NewRegion from scratch, we clear the ready lists.
-  // The nodes currently in the list may not be ready after clearing the View.
+  // The DAG Nodes contain state like the number of UnscheduledSuccs and the
+  // Scheduled flag. We need to reset their state. We need to do this for all
+  // nodes from LowestI to the top of the schedule. DAG Nodes that are above the
+  // top of schedule that depend on nodes that got reset need to have their
+  // UnscheduledSuccs adjusted.
+  Interval<Instruction> ResetIntvl(TopI, LowestI);
+  for (Instruction &I : ResetIntvl) {
+    auto *N = DAG.getNode(&I);
+    N->resetScheduleState();
+    // Recompute UnscheduledSuccs for nodes not only in ResetIntvl but even for
+    // nodes above the top of schedule.
+    for (auto *PredN : N->preds(DAG))
+      PredN->incrUnscheduledSuccs();
+  }
+  // Refill the ready list by visiting all nodes from the top of DAG to LowestI.
   ReadyList.clear();
+  Interval<Instruction> RefillIntvl(DAG.getInterval().top(), LowestI);
+  for (Instruction &I : RefillIntvl) {
+    auto *N = DAG.getNode(&I);
+    if (N->ready())
+      ReadyList.insert(N);
+  }
 }
 
 bool Scheduler::trySchedule(ArrayRef<Instruction *> Instrs) {
@@ -214,6 +242,12 @@ bool Scheduler::trySchedule(ArrayRef<Instruction *> Instrs) {
                   return I->getParent() == (*Instrs.begin())->getParent();
                 }) &&
          "Instrs not in the same BB, should have been rejected by Legality!");
+  // TODO: For now don't cross BBs.
+  if (!DAG.getInterval().empty()) {
+    auto *BB = DAG.getInterval().top()->getParent();
+    if (any_of(Instrs, [BB](auto *I) { return I->getParent() != BB; }))
+      return false;
+  }
   if (ScheduledBB == nullptr)
     ScheduledBB = Instrs[0]->getParent();
   // We don't support crossing BBs for now.
@@ -230,21 +264,13 @@ bool Scheduler::trySchedule(ArrayRef<Instruction *> Instrs) {
     // top-most part of the schedule that includes the instrs in the bundle and
     // re-schedule.
     trimSchedule(Instrs);
-    ScheduleTopItOpt = std::nullopt;
-    [[fallthrough]];
+    ScheduleTopItOpt = std::next(VecUtils::getLowest(Instrs)->getIterator());
+    return tryScheduleUntil(Instrs);
   case BndlSchedState::NoneScheduled: {
     // TODO: Set the window of the DAG that we are interested in.
     if (!ScheduleTopItOpt)
       // We start scheduling at the bottom instr of Instrs.
       ScheduleTopItOpt = std::next(VecUtils::getLowest(Instrs)->getIterator());
-
-    // TODO: For now don't cross BBs.
-    if (!DAG.getInterval().empty()) {
-      auto *BB = DAG.getInterval().top()->getParent();
-      if (any_of(Instrs, [BB](auto *I) { return I->getParent() != BB; }))
-        return false;
-    }
-
     // Extend the DAG to include Instrs.
     Interval<Instruction> Extension = DAG.extend(Instrs);
     // Add nodes to ready list.
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
index 0d5d86acaee89..7d88337e77faa 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
@@ -246,6 +246,77 @@ define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) {
   EXPECT_TRUE(Sched.trySchedule({L0, L1}));
 }
 
+// Check scheduling in the following order: {A0,A1},{B0,B1},{C0,C1},{D0,D1}
+// assuming program order: B0,B1,C0,C1,D0,D1,E0,D1.
+// This will effectively schedule nodes below already scheduled nodes, which
+// can expose issues in the code that adds nodes to the ready list.
+// For example, we schedule {D0,D1} while {C0,C1} are scheduled and there is
+// a dependency D0->C0 and D1->C1.
+//
+//                   {A0,A1}  {B0,B1}  {C0,C1}  {D0,D1}
+//   B0,B1                    | S
+//   |\                       |
+//   | C0,C1                  |        | S      | S
+//   |  | \                   |                 |
+//   |  |  D0,D1              |                 | S
+//   | /                      |
+//   A0,A1             | S    | S
+//                 +------------------------+
+//                 | Legend   |: DAG        |
+//                 |          S: Scheduled  |
+TEST_F(SchedulerTest, ScheduledPredecessors) {
+  parseIR(C, R"IR(
+define void @foo(ptr noalias %ptrA0, ptr noalias %ptrA1,
+                 ptr noalias %ptrB0, ptr noalias %ptrB1,
+                 ptr noalias %ptrD0, ptr noalias %ptrD1) {
+  %B0 = load i8, ptr %ptrB0
+  %B1 = load i8, ptr %ptrB1
+  %C0 = add i8 %B0, 0
+  %C1 = add i8 %B1, 1
+  store i8 %C0, ptr %ptrD0
+  store i8 %C1, ptr %ptrD1
+  store i8 %B0, ptr %ptrA0
+  store i8 %B1, ptr %ptrA1
+  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 *B1 = cast<sandboxir::LoadInst>(&*It++);
+  auto *B0 = cast<sandboxir::LoadInst>(&*It++);
+  auto *C1 = cast<sandboxir::BinaryOperator>(&*It++);
+  auto *C0 = cast<sandboxir::BinaryOperator>(&*It++);
+  auto *D1 = cast<sandboxir::StoreInst>(&*It++);
+  auto *D0 = cast<sandboxir::StoreInst>(&*It++);
+  auto *A1 = cast<sandboxir::StoreInst>(&*It++);
+  auto *A0 = cast<sandboxir::StoreInst>(&*It++);
+  auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
+
+  sandboxir::Scheduler Sched(getAA(*LLVMF), Ctx);
+  EXPECT_TRUE(Sched.trySchedule({A0, A1}));
+  // NOTE: We schedule the intermediate nodes between {A0,A1} and {B0,B1} by
+  // hand one by one to make sure they are scheduled in that order because
+  // the scheduler may reorder them a bit if we let it do it.
+  EXPECT_TRUE(Sched.trySchedule(D0));
+  EXPECT_TRUE(Sched.trySchedule(D1));
+  EXPECT_TRUE(Sched.trySchedule(C0));
+  EXPECT_TRUE(Sched.trySchedule(C1));
+  EXPECT_TRUE(Sched.trySchedule({B0, B1}));
+  // At this point all nodes must have been scheduled from B0,B1 to A0,A1.
+  // The ones in between are scheduled as single-instruction nodes.
+  // So when we attempt to schedule {C0,C1} we will need to reschedule.
+  // At this point we will trim the schedule from {C0,C1} upwards.
+  EXPECT_TRUE(Sched.trySchedule({C0, C1}));
+  // Now the schedule should only contain {C0,C1} which should be marked as
+  // "scheduled".
+  // {D0,D1} are below {C0,C1}, so we grow the DAG downwards, while
+  // {C0,C1} are marked as "scheduled" above them.
+  EXPECT_TRUE(Sched.trySchedule({D0, D1}));
+}
+
 TEST_F(SchedulerTest, DontCrossBBs) {
   parseIR(C, R"IR(
 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v0, i8 %v1) {

@vporpo vporpo merged commit 0cc7381 into llvm:main Feb 19, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Feb 19, 2025

LLVM Buildbot has detected a new failure on builder ppc64le-lld-multistage-test running on ppc64le-lld-multistage-test while building llvm at step 12 "build-stage2-unified-tree".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/168/builds/8852

Here is the relevant piece of the build log for the reference
Step 12 (build-stage2-unified-tree) failure: build (failure)
...
16.085 [1/8/15] Building CXX object tools/clang/utils/TableGen/CMakeFiles/clang-tblgen.dir/ClangASTPropertiesEmitter.cpp.o
28.245 [1/7/16] Building CXX object tools/clang/utils/TableGen/CMakeFiles/clang-tblgen.dir/ClangOpenCLBuiltinEmitter.cpp.o
36.525 [1/6/17] Building CXX object tools/clang/utils/TableGen/CMakeFiles/clang-tblgen.dir/RISCVVEmitter.cpp.o
37.859 [1/5/18] Building CXX object tools/clang/utils/TableGen/CMakeFiles/clang-tblgen.dir/ClangDiagnosticsEmitter.cpp.o
39.715 [1/4/19] Building CXX object tools/clang/utils/TableGen/CMakeFiles/clang-tblgen.dir/SveEmitter.cpp.o
51.440 [1/3/20] Building CXX object tools/clang/utils/TableGen/CMakeFiles/clang-tblgen.dir/MveEmitter.cpp.o
53.538 [1/2/21] Building CXX object tools/clang/utils/TableGen/CMakeFiles/clang-tblgen.dir/NeonEmitter.cpp.o
70.923 [1/1/22] Building CXX object tools/clang/utils/TableGen/CMakeFiles/clang-tblgen.dir/ClangAttrEmitter.cpp.o
70.980 [0/1/23] Linking CXX executable bin/clang-tblgen
152.738 [3978/190/2297] Building CXX object unittests/Transforms/Vectorize/SandboxVectorizer/CMakeFiles/SandboxVectorizerTests.dir/SchedulerTest.cpp.o
FAILED: unittests/Transforms/Vectorize/SandboxVectorizer/CMakeFiles/SandboxVectorizerTests.dir/SchedulerTest.cpp.o 
ccache /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/install/stage1/bin/clang++ -DGTEST_HAS_RTTI=0 -DLLVM_BUILD_STATIC -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage2/unittests/Transforms/Vectorize/SandboxVectorizer -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/unittests/Transforms/Vectorize/SandboxVectorizer -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/build/stage2/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/third-party/unittest/googletest/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/third-party/unittest/googlemock/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -O3 -DNDEBUG -std=c++17  -Wno-variadic-macros -Wno-gnu-zero-variadic-macro-arguments -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -Wno-suggest-override -MD -MT unittests/Transforms/Vectorize/SandboxVectorizer/CMakeFiles/SandboxVectorizerTests.dir/SchedulerTest.cpp.o -MF unittests/Transforms/Vectorize/SandboxVectorizer/CMakeFiles/SandboxVectorizerTests.dir/SchedulerTest.cpp.o.d -o unittests/Transforms/Vectorize/SandboxVectorizer/CMakeFiles/SandboxVectorizerTests.dir/SchedulerTest.cpp.o -c /home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
/home/buildbots/llvm-external-buildbots/workers/ppc64le-lld-multistage-test/ppc64le-lld-multistage-test/llvm-project/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp:296:9: error: unused variable 'Ret' [-Werror,-Wunused-variable]
  296 |   auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
      |         ^~~
1 error generated.
163.573 [3978/35/2452] Building CXX object unittests/Support/CMakeFiles/SupportTests.dir/VirtualFileSystemTest.cpp.o
164.808 [3978/33/2454] Building CXX object lib/Transforms/IPO/CMakeFiles/LLVMipo.dir/Attributor.cpp.o
164.992 [3978/32/2455] Building CXX object lib/Bitcode/Reader/CMakeFiles/LLVMBitReader.dir/BitcodeReader.cpp.o
165.022 [3978/31/2456] Building CXX object unittests/Support/CMakeFiles/SupportTests.dir/MathExtrasTest.cpp.o
165.216 [3978/30/2457] Building CXX object lib/Transforms/Utils/CMakeFiles/LLVMTransformUtils.dir/SimplifyCFG.cpp.o
165.491 [3978/29/2458] Building CXX object lib/Analysis/CMakeFiles/LLVMAnalysis.dir/TargetLibraryInfo.cpp.o
166.130 [3978/28/2459] Building CXX object tools/llvm-profdata/CMakeFiles/llvm-profdata.dir/llvm-profdata.cpp.o
166.477 [3978/27/2460] Building CXX object unittests/TargetParser/CMakeFiles/TargetParserTests.dir/TargetParserTest.cpp.o
166.620 [3978/26/2461] Building CXX object lib/Frontend/OpenMP/CMakeFiles/LLVMFrontendOpenMP.dir/OMPIRBuilder.cpp.o
166.945 [3978/25/2462] Building CXX object lib/Object/CMakeFiles/LLVMObject.dir/ELF.cpp.o
167.966 [3978/24/2463] Building CXX object lib/CodeGen/SelectionDAG/CMakeFiles/LLVMSelectionDAG.dir/SelectionDAG.cpp.o
168.103 [3978/23/2464] Building CXX object lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/LiveDebugValues/InstrRefBasedImpl.cpp.o
168.505 [3978/22/2465] Building CXX object unittests/IR/CMakeFiles/IRTests.dir/MetadataTest.cpp.o
170.557 [3978/21/2466] Building CXX object lib/CodeGen/CMakeFiles/LLVMCodeGen.dir/CodeGenPrepare.cpp.o
171.229 [3978/20/2467] Building CXX object lib/Analysis/CMakeFiles/LLVMAnalysis.dir/ScalarEvolution.cpp.o
171.531 [3978/19/2468] Building CXX object unittests/ADT/CMakeFiles/ADTTests.dir/DenseMapTest.cpp.o
171.580 [3978/18/2469] Building CXX object unittests/ProfileData/CMakeFiles/ProfileDataTests.dir/InstrProfTest.cpp.o
172.038 [3978/17/2470] Building CXX object lib/CodeGen/SelectionDAG/CMakeFiles/LLVMSelectionDAG.dir/SelectionDAGBuilder.cpp.o
174.375 [3978/16/2471] Building CXX object unittests/ADT/CMakeFiles/ADTTests.dir/APFloatTest.cpp.o
175.048 [3978/15/2472] Building CXX object unittests/Frontend/CMakeFiles/LLVMFrontendTests.dir/OpenMPDecompositionTest.cpp.o
176.026 [3978/14/2473] Building CXX object lib/Transforms/Vectorize/CMakeFiles/LLVMVectorize.dir/LoopVectorize.cpp.o
179.991 [3978/13/2474] Building CXX object unittests/Transforms/Scalar/CMakeFiles/ScalarTests.dir/LoopPassManagerTest.cpp.o
180.110 [3978/12/2475] Building CXX object unittests/SandboxIR/CMakeFiles/SandboxIRTests.dir/SandboxIRTest.cpp.o
180.682 [3978/11/2476] Building CXX object lib/Transforms/IPO/CMakeFiles/LLVMipo.dir/MemProfContextDisambiguation.cpp.o
180.683 [3978/10/2477] Building CXX object tools/obj2yaml/CMakeFiles/obj2yaml.dir/elf2yaml.cpp.o
180.949 [3978/9/2478] Building CXX object lib/Passes/CMakeFiles/LLVMPasses.dir/PassBuilderPipelines.cpp.o
182.014 [3978/8/2479] Building CXX object lib/Transforms/IPO/CMakeFiles/LLVMipo.dir/AttributorAttributes.cpp.o
182.229 [3978/7/2480] Building CXX object lib/CodeGen/SelectionDAG/CMakeFiles/LLVMSelectionDAG.dir/DAGCombiner.cpp.o
182.497 [3978/6/2481] Building CXX object unittests/IR/CMakeFiles/IRTests.dir/PassBuilderCallbacksTest.cpp.o
186.892 [3978/5/2482] Building CXX object unittests/Frontend/CMakeFiles/LLVMFrontendTests.dir/OpenMPIRBuilderTest.cpp.o
190.842 [3978/4/2483] Building CXX object lib/Transforms/IPO/CMakeFiles/LLVMipo.dir/OpenMPOpt.cpp.o
228.695 [3978/3/2484] Building CXX object lib/Transforms/Vectorize/CMakeFiles/LLVMVectorize.dir/SLPVectorizer.cpp.o
241.278 [3978/2/2485] Building CXX object unittests/ADT/CMakeFiles/ADTTests.dir/SmallVectorTest.cpp.o

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants