[llvm] [SandboxVec][Scheduler] Boilerplate and initial implementation. (PR #112449)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 15 15:54:37 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: vporpo (vporpo)
<details>
<summary>Changes</summary>
This patch implements a ready-list-based scheduler that operates on DependencyGraph.
It is used by the sandbox vectorizer to test the legality of vectorizing a group of instrs.
SchedBundle is a helper container, containing all DGNodes that correspond to the instructions that we are attempting to schedule with trySchedule(Instrs).
---
Full diff: https://github.com/llvm/llvm-project/pull/112449.diff
8 Files Affected:
- (modified) llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h (+7)
- (added) llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h (+124)
- (modified) llvm/lib/Transforms/Vectorize/CMakeLists.txt (+1)
- (modified) llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp (+3-1)
- (added) llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp (+154)
- (modified) llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt (+1)
- (modified) llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp (+12)
- (added) llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp (+167)
``````````diff
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
index ae3ceed447c40b..5be05bc80c4925 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
@@ -113,8 +113,15 @@ class DGNode {
virtual ~DGNode() = default;
/// \Returns the number of unscheduled successors.
unsigned getNumUnscheduledSuccs() const { return UnscheduledSuccs; }
+ void decrUnscheduledSuccs() {
+ assert(UnscheduledSuccs > 0 && "Counting error!");
+ --UnscheduledSuccs;
+ }
+ /// \Returns true if all dependent successors have been scheduled.
+ bool ready() const { return UnscheduledSuccs == 0; }
/// \Returns true if this node has been scheduled.
bool scheduled() const { return Scheduled; }
+ void setScheduled(bool NewVal) { Scheduled = NewVal; }
/// \Returns true if this is before \p Other in program order.
bool comesBefore(const DGNode *Other) { return I->comesBefore(Other->I); }
using iterator = PredIterator;
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
new file mode 100644
index 00000000000000..60ebcc02e7f169
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h
@@ -0,0 +1,124 @@
+//===- Scheduler.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the bottom-up list scheduler used by the vectorizer. It is used for
+// checking the legality of vectorization and for scheduling instructions in
+// such a way that makes vectorization possible, if legal.
+//
+// The legality check is performed by `trySchedule(Instrs)`, which will try to
+// schedule the IR until all instructions in `Instrs` can be scheduled together
+// back-to-back. If this fails then it is illegal to vectorize `Instrs`.
+//
+// Internally the scheduler uses the vectorizer-specific DependencyGraph class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SCHEDULER_H
+#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SCHEDULER_H
+
+#include "llvm/SandboxIR/Instruction.h"
+#include "llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h"
+#include <queue>
+
+namespace llvm::sandboxir {
+
+class PriorityCmp {
+public:
+ bool operator()(const DGNode *N1, const DGNode *N2) {
+ // TODO: This should be a hierarchical comparator.
+ return N1->getInstruction()->comesBefore(N2->getInstruction());
+ }
+};
+
+/// The list holding nodes that are ready to schedule. Used by the scheduler.
+class ReadyList {
+ PriorityCmp Cmp;
+ /// Control/Other dependencies are not modeled by the DAG to save memory.
+ /// These have to be modeled in the ready list for correctness.
+ /// This means that the list will hold back nodes that need to meet such
+ /// unmodeled dependencies.
+ std::priority_queue<DGNode *, std::vector<DGNode *>, PriorityCmp> List;
+
+public:
+ ReadyList() : List(Cmp) {}
+ void insert(DGNode *N) { List.push(N); }
+ DGNode *pop() {
+ auto *Back = List.top();
+ List.pop();
+ return Back;
+ }
+ bool empty() const { return List.empty(); }
+#ifndef NDEBUG
+ void dump(raw_ostream &OS) const;
+ LLVM_DUMP_METHOD void dump() const;
+#endif // NDEBUG
+};
+
+/// The nodes that need to be scheduled back-to-back in a single scheduling
+/// cycle form a SchedBundle.
+class SchedBundle {
+public:
+ using ContainerTy = SmallVector<DGNode *, 4>;
+
+private:
+ ContainerTy Nodes;
+
+public:
+ SchedBundle() = default;
+ SchedBundle(ContainerTy &&Nodes) : Nodes(std::move(Nodes)) {}
+ using iterator = ContainerTy::iterator;
+ using const_iterator = ContainerTy::const_iterator;
+ iterator begin() { return Nodes.begin(); }
+ iterator end() { return Nodes.end(); }
+ const_iterator begin() const { return Nodes.begin(); }
+ const_iterator end() const { return Nodes.end(); }
+ /// \Returns the bundle node that comes before the others in program order.
+ DGNode *getTop() const;
+ /// \Returns the bundle node that comes after the others in program order.
+ DGNode *getBot() const;
+ /// Move all bundle instructions to \p Where back-to-back.
+ void cluster(BasicBlock::iterator Where);
+#ifndef NDEBUG
+ void dump(raw_ostream &OS) const;
+ LLVM_DUMP_METHOD void dump() const;
+#endif
+};
+
+/// The list scheduler.
+class Scheduler {
+ ReadyList ReadyList;
+ DependencyGraph DAG;
+ std::optional<BasicBlock::iterator> ScheduleTopItOpt;
+ SmallVector<std::unique_ptr<SchedBundle>> Bndls;
+
+ /// \Returns a scheduling bundle containing \p Instrs.
+ SchedBundle *createBundle(ArrayRef<Instruction *> Instrs);
+ /// Schedule nodes until we can schedule \p Instrs back-to-back.
+ bool tryScheduleUntil(ArrayRef<Instruction *> Instrs);
+
+ void scheduleAndUpdateReadyList(SchedBundle &Bndl);
+
+ /// Disable copies.
+ Scheduler(const Scheduler &) = delete;
+ Scheduler &operator=(const Scheduler &) = delete;
+
+public:
+ Scheduler(AAResults &AA) : DAG(AA) {}
+ ~Scheduler() {}
+
+ bool trySchedule(ArrayRef<Instruction *> Instrs);
+
+#ifndef NDEBUG
+ void dump(raw_ostream &OS) const;
+ LLVM_DUMP_METHOD void dump() const;
+#endif
+};
+
+} // namespace llvm::sandboxir
+
+#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SCHEDULER_H
diff --git a/llvm/lib/Transforms/Vectorize/CMakeLists.txt b/llvm/lib/Transforms/Vectorize/CMakeLists.txt
index f4e98e576379a4..fc4355af5af6b9 100644
--- a/llvm/lib/Transforms/Vectorize/CMakeLists.txt
+++ b/llvm/lib/Transforms/Vectorize/CMakeLists.txt
@@ -9,6 +9,7 @@ add_llvm_component_library(LLVMVectorize
SandboxVectorizer/Passes/RegionsFromMetadata.cpp
SandboxVectorizer/SandboxVectorizer.cpp
SandboxVectorizer/SandboxVectorizerPassBuilder.cpp
+ SandboxVectorizer/Scheduler.cpp
SandboxVectorizer/SeedCollector.cpp
SLPVectorizer.cpp
Vectorize.cpp
diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp
index 9bbeca4fc15494..07435f0fb3151d 100644
--- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp
+++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp
@@ -286,7 +286,9 @@ void DependencyGraph::createNewNodes(const Interval<Instruction> &NewInterval) {
MemDGNodeIntervalBuilder::getBotMemDGNode(TopInterval, *this);
MemDGNode *LinkBotN =
MemDGNodeIntervalBuilder::getTopMemDGNode(BotInterval, *this);
- assert(LinkTopN->comesBefore(LinkBotN) && "Wrong order!");
+ assert((LinkTopN == nullptr || LinkBotN == nullptr ||
+ LinkTopN->comesBefore(LinkBotN)) &&
+ "Wrong order!");
if (LinkTopN != nullptr && LinkBotN != nullptr) {
LinkTopN->setNextNode(LinkBotN);
LinkBotN->setPrevNode(LinkTopN);
diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
new file mode 100644
index 00000000000000..37c197cc859980
--- /dev/null
+++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Scheduler.cpp
@@ -0,0 +1,154 @@
+//===- Scheduler.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h"
+
+namespace llvm::sandboxir {
+
+DGNode *SchedBundle::getTop() const {
+ DGNode *TopN = Nodes.front();
+ for (auto *N : drop_begin(Nodes)) {
+ if (N->getInstruction()->comesBefore(TopN->getInstruction()))
+ TopN = N;
+ }
+ return TopN;
+}
+
+DGNode *SchedBundle::getBot() const {
+ DGNode *BotN = Nodes.front();
+ for (auto *N : drop_begin(Nodes)) {
+ if (BotN->getInstruction()->comesBefore(N->getInstruction()))
+ BotN = N;
+ }
+ return BotN;
+}
+
+void SchedBundle::cluster(BasicBlock::iterator Where) {
+ for (auto *N : Nodes) {
+ auto *I = N->getInstruction();
+ if (I->getIterator() == Where)
+ ++Where; // Try to maintain bundle order.
+ I->moveBefore(*Where.getNodeParent(), Where);
+ }
+}
+
+#ifndef NDEBUG
+void SchedBundle::dump(raw_ostream &OS) const {
+ for (auto *N : Nodes)
+ OS << *N;
+}
+
+void SchedBundle::dump() const {
+ dump(dbgs());
+ dbgs() << "\n";
+}
+#endif // NDEBUG
+
+#ifndef NDEBUG
+void ReadyList::dump(raw_ostream &OS) const {
+ auto ListCopy = List;
+ while (!ListCopy.empty()) {
+ OS << *ListCopy.top() << "\n";
+ ListCopy.pop();
+ }
+}
+
+void ReadyList::dump() const {
+ dump(dbgs());
+ dbgs() << "\n";
+}
+#endif // NDEBUG
+
+void Scheduler::scheduleAndUpdateReadyList(SchedBundle &Bndl) {
+ // Find where we should schedule the instructions.
+ assert(ScheduleTopItOpt && "Should have been set by now!");
+ auto Where = *ScheduleTopItOpt;
+ // Move all instructions in `Bndl` to `Where`.
+ Bndl.cluster(Where);
+ // Update the last scheduled bundle.
+ ScheduleTopItOpt = Bndl.getTop()->getInstruction()->getIterator();
+ // 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();
+ }
+}
+
+SchedBundle *Scheduler::createBundle(ArrayRef<Instruction *> Instrs) {
+ SchedBundle::ContainerTy Nodes;
+ Nodes.reserve(Instrs.size());
+ for (auto *I : Instrs)
+ Nodes.push_back(DAG.getNode(I));
+ auto BndlPtr = std::make_unique<SchedBundle>(std::move(Nodes));
+ auto *Bndl = BndlPtr.get();
+ Bndls.push_back(std::move(BndlPtr));
+ return Bndl;
+}
+
+bool Scheduler::tryScheduleUntil(ArrayRef<Instruction *> Instrs) {
+ // Use a set for fast lookups.
+ DenseSet<Instruction *> InstrsToDefer(Instrs.begin(), Instrs.end());
+ SmallVector<DGNode *, 8> DeferredNodes;
+
+ // Keep scheduling ready nodes.
+ while (!ReadyList.empty()) {
+ auto *ReadyN = ReadyList.pop();
+ // We defer scheduling of instructions in `Instrs` until we can schedule all
+ // of them at the same time in a single scheduling bundle.
+ if (InstrsToDefer.contains(ReadyN->getInstruction())) {
+ DeferredNodes.push_back(ReadyN);
+ bool ReadyToScheduleDeferred = DeferredNodes.size() == Instrs.size();
+ if (ReadyToScheduleDeferred) {
+ scheduleAndUpdateReadyList(*createBundle(Instrs));
+ return true;
+ }
+ } else {
+ scheduleAndUpdateReadyList(*createBundle({ReadyN->getInstruction()}));
+ }
+ }
+ assert(DeferredNodes.size() != Instrs.size() &&
+ "We should have succesfully scheduled and early-returned!");
+ return false;
+}
+
+bool Scheduler::trySchedule(ArrayRef<Instruction *> Instrs) {
+ assert(all_of(drop_begin(Instrs),
+ [Instrs](Instruction *I) {
+ return I->getParent() == (*Instrs.begin())->getParent();
+ }) &&
+ "Instrs not in the same BB!");
+ // Extend the DAG to include Instrs.
+ Interval<Instruction> Extension = DAG.extend(Instrs);
+ // TODO: Set the window of the DAG that we are interested in.
+ // We start scheduling at the bottom instr of Instrs.
+ auto getBottomI = [](ArrayRef<Instruction *> Instrs) -> Instruction * {
+ return *min_element(Instrs,
+ [](auto *I1, auto *I2) { return I1->comesBefore(I2); });
+ };
+ ScheduleTopItOpt = std::next(getBottomI(Instrs)->getIterator());
+ // Add nodes to ready list.
+ for (auto &I : Extension) {
+ auto *N = DAG.getNode(&I);
+ if (N->ready())
+ ReadyList.insert(N);
+ }
+ // Try schedule all nodes until we can schedule Instrs back-to-back.
+ return tryScheduleUntil(Instrs);
+}
+
+#ifndef NDEBUG
+void Scheduler::dump(raw_ostream &OS) const {
+ OS << "ReadyList:\n";
+ ReadyList.dump(OS);
+}
+void Scheduler::dump() const { dump(dbgs()); }
+#endif // NDEBUG
+
+} // namespace llvm::sandboxir
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt
index dcd7232db5f60c..24512cb0225e8e 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/CMakeLists.txt
@@ -11,5 +11,6 @@ add_llvm_unittest(SandboxVectorizerTests
DependencyGraphTest.cpp
IntervalTest.cpp
LegalityTest.cpp
+ SchedulerTest.cpp
SeedCollectorTest.cpp
)
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp
index 3f84ad1f731de8..c00599ae1c4ef2 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp
@@ -254,6 +254,18 @@ define void @foo(ptr %ptr, i8 %v0, i8 %v1) {
EXPECT_EQ(N0->getNumUnscheduledSuccs(), 1u); // N1
EXPECT_EQ(N1->getNumUnscheduledSuccs(), 0u);
EXPECT_EQ(N2->getNumUnscheduledSuccs(), 0u);
+
+ // Check decrUnscheduledSuccs.
+ N0->decrUnscheduledSuccs();
+ EXPECT_EQ(N0->getNumUnscheduledSuccs(), 0u);
+#ifndef NDEBUG
+ EXPECT_DEATH(N0->decrUnscheduledSuccs(), ".*Counting.*");
+#endif // NDEBUG
+
+ // Check scheduled(), setScheduled().
+ EXPECT_FALSE(N0->scheduled());
+ N0->setScheduled(true);
+ EXPECT_TRUE(N0->scheduled());
}
TEST_F(DependencyGraphTest, Preds) {
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
new file mode 100644
index 00000000000000..14f48e77a6fb65
--- /dev/null
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/SchedulerTest.cpp
@@ -0,0 +1,167 @@
+//===- SchedulerTest.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/Analysis/BasicAliasAnalysis.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/SandboxIR/Context.h"
+#include "llvm/SandboxIR/Function.h"
+#include "llvm/SandboxIR/Instruction.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+struct SchedulerTest : public testing::Test {
+ LLVMContext C;
+ std::unique_ptr<Module> M;
+ std::unique_ptr<AssumptionCache> AC;
+ std::unique_ptr<DominatorTree> DT;
+ std::unique_ptr<BasicAAResult> BAA;
+ std::unique_ptr<AAResults> AA;
+
+ void parseIR(LLVMContext &C, const char *IR) {
+ SMDiagnostic Err;
+ M = parseAssemblyString(IR, Err, C);
+ if (!M)
+ Err.print("DependencyGraphTest", errs());
+ }
+
+ AAResults &getAA(llvm::Function &LLVMF) {
+ TargetLibraryInfoImpl TLII;
+ TargetLibraryInfo TLI(TLII);
+ AA = std::make_unique<AAResults>(TLI);
+ AC = std::make_unique<AssumptionCache>(LLVMF);
+ DT = std::make_unique<DominatorTree>(LLVMF);
+ BAA = std::make_unique<BasicAAResult>(M->getDataLayout(), LLVMF, TLI, *AC,
+ DT.get());
+ AA->addAAResult(*BAA);
+ return *AA;
+ }
+ /// \Returns true if there is a dependency: SrcN->DstN.
+ bool memDependency(sandboxir::DGNode *SrcN, sandboxir::DGNode *DstN) {
+ if (auto *MemDstN = dyn_cast<sandboxir::MemDGNode>(DstN))
+ return MemDstN->hasMemPred(SrcN);
+ return false;
+ }
+};
+
+TEST_F(SchedulerTest, SchedBundle) {
+ parseIR(C, R"IR(
+define void @foo(ptr %ptr, i8 %v0, i8 %v1) {
+ store i8 %v0, ptr %ptr
+ %other = add i8 %v0, %v1
+ store i8 %v1, 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 *S0 = cast<sandboxir::StoreInst>(&*It++);
+ auto *Other = &*It++;
+ auto *S1 = cast<sandboxir::StoreInst>(&*It++);
+ auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
+
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()});
+ auto *SN0 = DAG.getNode(S0);
+ auto *SN1 = DAG.getNode(S1);
+ sandboxir::SchedBundle Bndl({SN0, SN1});
+
+ // Check getTop().
+ EXPECT_EQ(Bndl.getTop(), SN0);
+ // Check getBot().
+ EXPECT_EQ(Bndl.getBot(), SN1);
+ // Check cluster().
+ Bndl.cluster(S1->getIterator());
+ {
+ auto It = BB->begin();
+ EXPECT_EQ(&*It++, Other);
+ EXPECT_EQ(&*It++, S0);
+ EXPECT_EQ(&*It++, S1);
+ EXPECT_EQ(&*It++, Ret);
+ S0->moveBefore(Other);
+ }
+
+ Bndl.cluster(S0->getIterator());
+ {
+ auto It = BB->begin();
+ EXPECT_EQ(&*It++, S0);
+ EXPECT_EQ(&*It++, S1);
+ EXPECT_EQ(&*It++, Other);
+ EXPECT_EQ(&*It++, Ret);
+ S1->moveAfter(Other);
+ }
+
+ Bndl.cluster(Other->getIterator());
+ {
+ auto It = BB->begin();
+ EXPECT_EQ(&*It++, S0);
+ EXPECT_EQ(&*It++, S1);
+ EXPECT_EQ(&*It++, Other);
+ EXPECT_EQ(&*It++, Ret);
+ S1->moveAfter(Other);
+ }
+
+ Bndl.cluster(Ret->getIterator());
+ {
+ auto It = BB->begin();
+ EXPECT_EQ(&*It++, Other);
+ EXPECT_EQ(&*It++, S0);
+ EXPECT_EQ(&*It++, S1);
+ EXPECT_EQ(&*It++, Ret);
+ Other->moveBefore(S1);
+ }
+
+ Bndl.cluster(BB->end());
+ {
+ auto It = BB->begin();
+ EXPECT_EQ(&*It++, Other);
+ EXPECT_EQ(&*It++, Ret);
+ EXPECT_EQ(&*It++, S0);
+ EXPECT_EQ(&*It++, S1);
+ Ret->moveAfter(S1);
+ Other->moveAfter(S0);
+ }
+ // Check iterators.
+ EXPECT_THAT(Bndl, testing::ElementsAre(SN0, SN1));
+ EXPECT_THAT((const sandboxir::SchedBundle &)Bndl,
+ testing::ElementsAre(SN0, SN1));
+}
+
+TEST_F(SchedulerTest, Basic) {
+ parseIR(C, R"IR(
+define void @foo(ptr %ptr, i8 %v0, i8 %v1) {
+ store i8 %v0, ptr %ptr
+ store i8 %v1, 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 *S0 = cast<sandboxir::StoreInst>(&*It++);
+ auto *S1 = cast<sandboxir::StoreInst>(&*It++);
+ auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
+
+ sandboxir::Scheduler Sched(getAA(*LLVMF));
+ EXPECT_TRUE(Sched.trySchedule({Ret}));
+ EXPECT_TRUE(Sched.trySchedule({S1}));
+ EXPECT_TRUE(Sched.trySchedule({S0}));
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/112449
More information about the llvm-commits
mailing list