[llvm] [SandboxVec][Scheduler] Don't allow rescheduling of already scheduled (PR #128050)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Feb 20 10:47:14 PST 2025
https://github.com/vporpo created https://github.com/llvm/llvm-project/pull/128050
This patch implements the check for not allowing re-scheduling of instructions that have already been scheduled in a scheduling bundle. Rescheduling should only happen if the instructions were temporarily scheduled in singleton bundles during a previous call to `trySchedule()`.
>From 0e72a3eae354a3d419bcdea15bb9f5357f175200 Mon Sep 17 00:00:00 2001
From: Vasileios Porpodas <vporpodas at google.com>
Date: Thu, 6 Feb 2025 08:53:41 -0800
Subject: [PATCH] [SandboxVec][Scheduler] Don't allow rescheduling of already
scheduled
This patch implements the check for not allowing re-scheduling of
instructions that have already been scheduled in a scheduling bundle.
Rescheduling should only happen if the instructions were temporarily
scheduled in singleton bundles during a previous call to `trySchedule()`.
---
.../Vectorize/SandboxVectorizer/Scheduler.h | 19 +-
.../Vectorize/SandboxVectorizer/Scheduler.cpp | 60 +++--
.../SandboxVectorizer/bottomup_basic.ll | 30 +++
.../SandboxVectorizer/SchedulerTest.cpp | 222 +++++++++++++++++-
4 files changed, 300 insertions(+), 31 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
index 6b56f348f328c..c8ca65a155704 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
@@ -130,6 +130,10 @@ class SchedBundle {
N->clearSchedBundle();
}
bool empty() const { return Nodes.empty(); }
+ /// Singleton bundles are created when scheduling instructions temporarily to
+ /// fill in the schedule until we schedule the vector bundle. These are
+ /// non-vector bundles containing just a single instruction.
+ bool isSingleton() const { return Nodes.size() == 1u; }
DGNode *back() const { return Nodes.back(); }
using iterator = ContainerTy::iterator;
using const_iterator = ContainerTy::const_iterator;
@@ -187,10 +191,12 @@ class Scheduler {
/// The scheduling state of the instructions in the bundle.
enum class BndlSchedState {
NoneScheduled, ///> No instruction in the bundle was previously scheduled.
- PartiallyOrDifferentlyScheduled, ///> Only some of the instrs in the bundle
- /// were previously scheduled, or all of
- /// them were but not in the same
- /// SchedBundle.
+ AlreadyScheduled, ///> At least one instruction in the bundle belongs to a
+ /// different non-singleton scheduling bundle.
+ TemporarilyScheduled, ///> Instructions were temporarily scheduled as
+ /// singleton bundles or some of them were not
+ /// scheduled at all. None of them were in a vector
+ ///(non-singleton) bundle.
FullyScheduled, ///> All instrs in the bundle were previously scheduled and
/// were in the same SchedBundle.
};
@@ -243,6 +249,11 @@ class Scheduler {
class SchedulerInternalsAttorney {
public:
static DependencyGraph &getDAG(Scheduler &Sched) { return Sched.DAG; }
+ using BndlSchedState = Scheduler::BndlSchedState;
+ static BndlSchedState getBndlSchedState(const Scheduler &Sched,
+ ArrayRef<Instruction *> Instrs) {
+ return Sched.getBndlSchedState(Instrs);
+ }
};
} // namespace llvm::sandboxir
diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
index 3e37e07aabc5c..ad46683d95063 100644
--- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
+++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
@@ -161,30 +161,36 @@ bool Scheduler::tryScheduleUntil(ArrayRef<Instruction *> Instrs) {
Scheduler::BndlSchedState
Scheduler::getBndlSchedState(ArrayRef<Instruction *> Instrs) const {
assert(!Instrs.empty() && "Expected non-empty bundle");
- bool PartiallyScheduled = false;
- bool FullyScheduled = true;
- for (auto *I : Instrs) {
+ auto *N0 = DAG.getNode(Instrs[0]);
+ auto *SB0 = N0 != nullptr ? N0->getSchedBundle() : nullptr;
+ bool AllUnscheduled = SB0 == nullptr;
+ bool FullyScheduled = SB0 != nullptr && !SB0->isSingleton();
+ for (auto *I : drop_begin(Instrs)) {
auto *N = DAG.getNode(I);
- if (N != nullptr && N->scheduled())
- PartiallyScheduled = true;
- else
- FullyScheduled = false;
- }
- if (FullyScheduled) {
- // If not all instrs in the bundle are in the same SchedBundle then this
- // should be considered as partially-scheduled, because we will need to
- // re-schedule.
- SchedBundle *SB = DAG.getNode(Instrs[0])->getSchedBundle();
- assert(SB != nullptr && "FullyScheduled assumes that there is an SB!");
- if (any_of(drop_begin(Instrs), [this, SB](sandboxir::Value *SBV) {
- return DAG.getNode(cast<sandboxir::Instruction>(SBV))
- ->getSchedBundle() != SB;
- }))
+ auto *SB = N != nullptr ? N->getSchedBundle() : nullptr;
+ if (SB != nullptr) {
+ // We found a scheduled instr, so there is now way all are unscheduled.
+ AllUnscheduled = false;
+ if (SB->isSingleton()) {
+ // We found an instruction in a temporarily scheduled singleton. There
+ // is no way that all instructions are scheduled in the same bundle.
+ FullyScheduled = false;
+ }
+ }
+
+ if (SB != SB0) {
+ // Either one of SB, SB0 is null, or they are in different bundles, so
+ // Instrs are definitely not in the same vector bundle.
FullyScheduled = false;
+ // One of SB, SB0 are in a vector bundle and they differ.
+ if ((SB != nullptr && !SB->isSingleton()) ||
+ (SB0 != nullptr && !SB0->isSingleton()))
+ return BndlSchedState::AlreadyScheduled;
+ }
}
- return FullyScheduled ? BndlSchedState::FullyScheduled
- : PartiallyScheduled ? BndlSchedState::PartiallyOrDifferentlyScheduled
- : BndlSchedState::NoneScheduled;
+ return AllUnscheduled ? BndlSchedState::NoneScheduled
+ : FullyScheduled ? BndlSchedState::FullyScheduled
+ : BndlSchedState::TemporarilyScheduled;
}
void Scheduler::trimSchedule(ArrayRef<Instruction *> Instrs) {
@@ -203,13 +209,14 @@ void Scheduler::trimSchedule(ArrayRef<Instruction *> Instrs) {
//
Instruction *TopI = &*ScheduleTopItOpt.value();
Instruction *LowestI = VecUtils::getLowest(Instrs);
- // Destroy the schedule bundles from LowestI all the way to the top.
+ // Destroy the singleton schedule bundles from LowestI all the way to the top.
for (auto *I = LowestI, *E = TopI->getPrevNode(); I != E;
I = I->getPrevNode()) {
auto *N = DAG.getNode(I);
if (N == nullptr)
continue;
- if (auto *SB = N->getSchedBundle())
+ auto *SB = N->getSchedBundle();
+ if (SB->isSingleton())
eraseBundle(SB);
}
// The DAG Nodes contain state like the number of UnscheduledSuccs and the
@@ -259,7 +266,12 @@ bool Scheduler::trySchedule(ArrayRef<Instruction *> Instrs) {
case BndlSchedState::FullyScheduled:
// Nothing to do.
return true;
- case BndlSchedState::PartiallyOrDifferentlyScheduled:
+ case BndlSchedState::AlreadyScheduled:
+ // Instructions are part of a different vector schedule, so we can't
+ // schedule \p Instrs in the same bundle (without destroying the existing
+ // schedule).
+ return false;
+ case BndlSchedState::TemporarilyScheduled:
// If one or more instrs are already scheduled we need to destroy the
// top-most part of the schedule that includes the instrs in the bundle and
// re-schedule.
diff --git a/llvm/test/Transforms/SandboxVectorizer/bottomup_basic.ll b/llvm/test/Transforms/SandboxVectorizer/bottomup_basic.ll
index fc5795708c7d8..531ed8cb618fc 100644
--- a/llvm/test/Transforms/SandboxVectorizer/bottomup_basic.ll
+++ b/llvm/test/Transforms/SandboxVectorizer/bottomup_basic.ll
@@ -386,3 +386,33 @@ define void @vecInstrsPlacement(ptr %ptr0) {
store double %add1, ptr %ptr1
ret void
}
+
+; During the bottom-up traversal we form bundle {ldA0,ldA1} but later when we
+; visit the RHS operands of the additions we try to form {ldA1,ldA2}
+; which is not allowed.
+define void @instrsInMultipleBundles(ptr noalias %ptr) {
+; CHECK-LABEL: define void @instrsInMultipleBundles(
+; CHECK-SAME: ptr noalias [[PTR:%.*]]) {
+; CHECK-NEXT: [[GEP0:%.*]] = getelementptr i8, ptr [[PTR]], i64 0
+; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[PTR]], i64 2
+; CHECK-NEXT: [[LDA2:%.*]] = load i8, ptr [[GEP2]], align 1
+; CHECK-NEXT: [[VECL:%.*]] = load <2 x i8>, ptr [[GEP0]], align 1
+; CHECK-NEXT: [[VEXT:%.*]] = extractelement <2 x i8> [[VECL]], i32 1
+; CHECK-NEXT: [[VINS:%.*]] = insertelement <2 x i8> poison, i8 [[VEXT]], i32 0
+; CHECK-NEXT: [[VINS1:%.*]] = insertelement <2 x i8> [[VINS]], i8 [[LDA2]], i32 1
+; CHECK-NEXT: [[VEC:%.*]] = add <2 x i8> [[VECL]], [[VINS1]]
+; CHECK-NEXT: store <2 x i8> [[VEC]], ptr [[GEP0]], align 1
+; CHECK-NEXT: ret void
+;
+ %gep0 = getelementptr i8, ptr %ptr, i64 0
+ %gep1 = getelementptr i8, ptr %ptr, i64 1
+ %gep2 = getelementptr i8, ptr %ptr, i64 2
+ %ldA0 = load i8, ptr %gep0
+ %ldA1 = load i8, ptr %gep1
+ %ldA2 = load i8, ptr %gep2
+ %add0 = add i8 %ldA0, %ldA1
+ %add1 = add i8 %ldA1, %ldA2
+ store i8 %add0, ptr %gep0
+ store i8 %add1, ptr %gep1
+ ret void
+}
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
index 97724100ba341..854d2bcde9537 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
@@ -210,9 +210,10 @@ define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) {
EXPECT_TRUE(Sched.trySchedule({L0, L1}));
}
-TEST_F(SchedulerTest, RescheduleAlreadyScheduled) {
+TEST_F(SchedulerTest, TrimSchedule) {
parseIR(C, R"IR(
-define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) {
+define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %arg) {
+ %zext = zext i8 0 to i32
%ld0 = load i8, ptr %ptr0
%ld1 = load i8, ptr %ptr1
%add0 = add i8 %ld0, %ld0
@@ -227,6 +228,7 @@ define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) {
auto *F = Ctx.createFunction(LLVMF);
auto *BB = &*F->begin();
auto It = BB->begin();
+ auto *Z = cast<sandboxir::CastInst>(&*It++);
auto *L0 = cast<sandboxir::LoadInst>(&*It++);
auto *L1 = cast<sandboxir::LoadInst>(&*It++);
auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++);
@@ -240,10 +242,224 @@ define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) {
EXPECT_TRUE(Sched.trySchedule({S0, S1}));
EXPECT_TRUE(Sched.trySchedule({L0, L1}));
// At this point Add0 and Add1 should have been individually scheduled
- // as single bundles.
+ // as singleton bundles, but {S0,S1} and {L0,L1} as vector bundles.
// Check if rescheduling works.
EXPECT_TRUE(Sched.trySchedule({Add0, Add1}));
+ // These should fail because {L0,L1} is a vector bundle.
+ EXPECT_FALSE(Sched.trySchedule({L0, Z}));
+ EXPECT_FALSE(Sched.trySchedule({L1, Z}));
+ // This should succeed because it matches the original vec bundle.
+ EXPECT_TRUE(Sched.trySchedule({L0, L1}));
+}
+
+// Test that an instruction can't belong in two bundles!
+TEST_F(SchedulerTest, CheckBundles) {
+ parseIR(C, R"IR(
+define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, ptr noalias %ptr2) {
+ %L0 = load i8, ptr %ptr0
+ %L1 = load i8, ptr %ptr1 ; This belongs in 2 bundles!
+ %L2 = load i8, ptr %ptr2
+ %add0 = add i8 %L0, %L1
+ %add1 = add i8 %L1, %L2
+ store i8 %add0, ptr %ptr0
+ store i8 %add1, ptr %ptr1
+ 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 *L0 = cast<sandboxir::LoadInst>(&*It++);
+ auto *L1 = cast<sandboxir::LoadInst>(&*It++);
+ auto *L2 = cast<sandboxir::LoadInst>(&*It++);
+ auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *S0 = cast<sandboxir::StoreInst>(&*It++);
+ auto *S1 = cast<sandboxir::StoreInst>(&*It++);
+
+ sandboxir::Scheduler Sched(getAA(*LLVMF), Ctx);
+ EXPECT_TRUE(Sched.trySchedule({S0, S1}));
+ EXPECT_TRUE(Sched.trySchedule({Add0, Add1}));
+ EXPECT_TRUE(Sched.trySchedule({L0, L1}));
+ // This should fail because L1 is already part of {L0,L1}
+ EXPECT_FALSE(Sched.trySchedule({L1, L2}));
+ EXPECT_FALSE(Sched.trySchedule({L2, L1}));
+}
+
+// Try schedule a bundle {L1,L2} where L1 is already scheduled in {L0,L1}
+// but L2 is not in the DAG at all
+TEST_F(SchedulerTest, CheckBundles2) {
+ parseIR(C, R"IR(
+define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, ptr noalias %ptr2) {
+ %L2 = load i8, ptr %ptr2 ; This is not in the DAG
+ %L1 = load i8, ptr %ptr1 ; This belongs in 2 bundles!
+ %L0 = load i8, ptr %ptr0
+ %add1 = add i8 %L1, %L2
+ %add0 = add i8 %L0, %L1
+ store i8 %add1, ptr %ptr1
+ store i8 %add0, ptr %ptr0
+ 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 *L2 = cast<sandboxir::LoadInst>(&*It++);
+ auto *L1 = cast<sandboxir::LoadInst>(&*It++);
+ auto *L0 = cast<sandboxir::LoadInst>(&*It++);
+ auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *S1 = cast<sandboxir::StoreInst>(&*It++);
+ auto *S0 = cast<sandboxir::StoreInst>(&*It++);
+
+ sandboxir::Scheduler Sched(getAA(*LLVMF), Ctx);
+ EXPECT_TRUE(Sched.trySchedule({S0, S1}));
+ EXPECT_TRUE(Sched.trySchedule({Add0, Add1}));
+ EXPECT_TRUE(Sched.trySchedule({L0, L1}));
+ // This should fail because L1 is already part of {L0,L1}.
+ EXPECT_FALSE(Sched.trySchedule({L1, L2}));
+ EXPECT_FALSE(Sched.trySchedule({L2, L1}));
+}
+
+// Try schedule a bundle {L1,L2} where L1 is already scheduled in {L0,L1}
+// but L2 is in the DAG but isn't scheduled.
+TEST_F(SchedulerTest, CheckBundles3) {
+ parseIR(C, R"IR(
+define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, ptr noalias %ptr2) {
+ %L2 = load i8, ptr %ptr2 ; This is not in the DAG
+ %L1 = load i8, ptr %ptr1 ; This belongs in 2 bundles!
+ %L0 = load i8, ptr %ptr0
+ %add1 = add i8 %L1, %L2
+ %add0 = add i8 %L0, %L1
+ store i8 %add1, ptr %ptr1
+ store i8 %add0, ptr %ptr0
+ 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 *L2 = cast<sandboxir::LoadInst>(&*It++);
+ auto *L1 = cast<sandboxir::LoadInst>(&*It++);
+ auto *L0 = cast<sandboxir::LoadInst>(&*It++);
+ auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *S1 = cast<sandboxir::StoreInst>(&*It++);
+ auto *S0 = cast<sandboxir::StoreInst>(&*It++);
+
+ sandboxir::Scheduler Sched(getAA(*LLVMF), Ctx);
+ EXPECT_TRUE(Sched.trySchedule({S0, S1}));
+ EXPECT_TRUE(Sched.trySchedule({Add0, Add1}));
+ EXPECT_TRUE(Sched.trySchedule({L0, L1}));
+ // Add L2 to the DAG, but don't schedule it.
+ auto &DAG = sandboxir::SchedulerInternalsAttorney::getDAG(Sched);
+ DAG.extend(L2);
+ // This should fail because L1 is already part of {L0,L1}.
+ EXPECT_FALSE(Sched.trySchedule({L1, L2}));
+ EXPECT_FALSE(Sched.trySchedule({L2, L1}));
+}
+
+// Check that Scheduler::getBndlSchedState() works correctly.
+TEST_F(SchedulerTest, GetBndlSchedState) {
+ parseIR(C, R"IR(
+define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, ptr noalias %ptr2) {
+ %L2 = load i8, ptr %ptr2 ; This is not in the DAG
+ %L1 = load i8, ptr %ptr1 ; This belongs in 2 bundles!
+ %L0 = load i8, ptr %ptr0
+ %add1 = add i8 %L1, %L2
+ %add0 = add i8 %L0, %L1
+ store i8 %add1, ptr %ptr1
+ store i8 %add0, ptr %ptr0
+ 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 *L2 = cast<sandboxir::LoadInst>(&*It++);
+ auto *L1 = cast<sandboxir::LoadInst>(&*It++);
+ auto *L0 = cast<sandboxir::LoadInst>(&*It++);
+ auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++);
+ auto *S1 = cast<sandboxir::StoreInst>(&*It++);
+ auto *S0 = cast<sandboxir::StoreInst>(&*It++);
+
+ sandboxir::Scheduler Sched(getAA(*LLVMF), Ctx);
+ auto &DAG = sandboxir::SchedulerInternalsAttorney::getDAG(Sched);
+ auto GetBndlSchedState = [&Sched](ArrayRef<sandboxir::Instruction *> Instrs) {
+ return sandboxir::SchedulerInternalsAttorney::getBndlSchedState(Sched,
+ Instrs);
+ };
+ using BndlSchedState = sandboxir::SchedulerInternalsAttorney::BndlSchedState;
+ // Check when instructions are not in the DAG.
+ EXPECT_EQ(GetBndlSchedState({S0}), BndlSchedState::NoneScheduled);
+ EXPECT_EQ(GetBndlSchedState({S0, S1}), BndlSchedState::NoneScheduled);
+ EXPECT_EQ(GetBndlSchedState({S0, S1}), BndlSchedState::NoneScheduled);
+ // Check when instructions are in the DAG.
+ DAG.extend({S0, S1});
+ EXPECT_EQ(GetBndlSchedState({S0}), BndlSchedState::NoneScheduled);
+ EXPECT_EQ(GetBndlSchedState({S0, S1}), BndlSchedState::NoneScheduled);
+ EXPECT_EQ(GetBndlSchedState({S0, S1}), BndlSchedState::NoneScheduled);
+ // One instruction in the DAG and the other not in the DAG.
+ EXPECT_EQ(GetBndlSchedState({S0, Add0}), BndlSchedState::NoneScheduled);
+
+ // Check with scheduled instructions.
+ Sched.clear(); // Manually extending the DAG messes with the scheduler.
+ EXPECT_TRUE(Sched.trySchedule({S0, S1}));
+ // Check fully scheduled.
+ EXPECT_EQ(GetBndlSchedState({S0, S1}), BndlSchedState::FullyScheduled);
+ // Check scheduled + not in DAG.
+ EXPECT_EQ(GetBndlSchedState({S0, Add0}), BndlSchedState::AlreadyScheduled);
+ EXPECT_EQ(GetBndlSchedState({Add0, S0}), BndlSchedState::AlreadyScheduled);
+ EXPECT_EQ(GetBndlSchedState({Add0, S1}), BndlSchedState::AlreadyScheduled);
+ EXPECT_EQ(GetBndlSchedState({Add0, Add1}), BndlSchedState::NoneScheduled);
+ // Extend DAG such that Add0 and Add1 are in the DAG but are not scheduled.
+ DAG.extend({Add0, Add1});
+ // Check both in DAG but not scheduled.
+ EXPECT_EQ(GetBndlSchedState({Add0, Add1}), BndlSchedState::NoneScheduled);
+ // Check scheduled + in DAG but not scheduled.
+ EXPECT_EQ(GetBndlSchedState({S0, Add0}), BndlSchedState::AlreadyScheduled);
+ EXPECT_EQ(GetBndlSchedState({Add0, S0}), BndlSchedState::AlreadyScheduled);
+ EXPECT_EQ(GetBndlSchedState({Add0, S1}), BndlSchedState::AlreadyScheduled);
+
+ Sched.clear(); // Manually extending the DAG messes with the scheduler.
+ // Schedule instructions towards the top so that intermediate instructions
+ // (namely Add0, Add1) get temporarily scheduled in singleton bundles.
+ EXPECT_TRUE(Sched.trySchedule({S0, S1}));
EXPECT_TRUE(Sched.trySchedule({L0, L1}));
+ // Check fully scheduled.
+ EXPECT_EQ(GetBndlSchedState({L0, L1}), BndlSchedState::FullyScheduled);
+ // Check both singletons.
+ EXPECT_EQ(GetBndlSchedState({Add0, Add1}),
+ BndlSchedState::TemporarilyScheduled);
+ // Check single singleton.
+ EXPECT_EQ(GetBndlSchedState({Add0}), BndlSchedState::TemporarilyScheduled);
+ EXPECT_EQ(GetBndlSchedState({Add1}), BndlSchedState::TemporarilyScheduled);
+ // Check singleton + scheduled.
+ EXPECT_EQ(GetBndlSchedState({L0, S1}), BndlSchedState::AlreadyScheduled);
+ EXPECT_EQ(GetBndlSchedState({S1, L0}), BndlSchedState::AlreadyScheduled);
+ EXPECT_EQ(GetBndlSchedState({L0, Add1}), BndlSchedState::AlreadyScheduled);
+ EXPECT_EQ(GetBndlSchedState({Add1, L0}), BndlSchedState::AlreadyScheduled);
+ // Check singleton + not in DAG.
+ EXPECT_EQ(GetBndlSchedState({Add1, L2}),
+ BndlSchedState::TemporarilyScheduled);
+ EXPECT_EQ(GetBndlSchedState({L2, Add0}),
+ BndlSchedState::TemporarilyScheduled);
+
+ // Check duplicates.
+ // TODO: Should duplicates be allowed?
+ EXPECT_EQ(GetBndlSchedState({L2, L2}), BndlSchedState::NoneScheduled);
+ EXPECT_EQ(GetBndlSchedState({S0, S0}), BndlSchedState::FullyScheduled);
+ EXPECT_EQ(GetBndlSchedState({Add0, Add1}),
+ BndlSchedState::TemporarilyScheduled);
}
// Check scheduling in the following order: {A0,A1},{B0,B1},{C0,C1},{D0,D1}
More information about the llvm-commits
mailing list