LLVM 23.0.0git
Scheduler.h
Go to the documentation of this file.
1//===- Scheduler.h ----------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This is the bottom-up list scheduler used by the vectorizer. It is used for
10// checking the legality of vectorization and for scheduling instructions in
11// such a way that makes vectorization possible, if legal.
12//
13// The legality check is performed by `trySchedule(Instrs)`, which will try to
14// schedule the IR until all instructions in `Instrs` can be scheduled together
15// back-to-back. If this fails then it is illegal to vectorize `Instrs`.
16//
17// Internally the scheduler uses the vectorizer-specific DependencyGraph class.
18//
19//===----------------------------------------------------------------------===//
20
21#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SCHEDULER_H
22#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SCHEDULER_H
23
27#include <queue>
28
29namespace llvm::sandboxir {
30
32public:
33 bool operator()(const DGNode *N1, const DGNode *N2) {
34 // Given that the DAG does not model dependencies such that PHIs are always
35 // at the top, or terminators always at the bottom, we need to force the
36 // priority here in the comparator of the ready list container.
37 auto *I1 = N1->getInstruction();
38 auto *I2 = N2->getInstruction();
39 bool IsTerm1 = I1->isTerminator();
40 bool IsTerm2 = I2->isTerminator();
41 if (IsTerm1 != IsTerm2)
42 // Terminators have the lowest priority.
43 return IsTerm1 > IsTerm2;
44 bool IsPHI1 = isa<PHINode>(I1);
45 bool IsPHI2 = isa<PHINode>(I2);
46 if (IsPHI1 != IsPHI2)
47 // PHIs have the highest priority.
48 return IsPHI1 < IsPHI2;
49 // Otherwise rely on the instruction order.
50 return I2->comesBefore(I1);
51 }
52};
53
54/// The list holding nodes that are ready to schedule. Used by the scheduler.
56 PriorityCmp Cmp;
57 /// Control/Other dependencies are not modeled by the DAG to save memory.
58 /// These have to be modeled in the ready list for correctness.
59 /// This means that the list will hold back nodes that need to meet such
60 /// unmodeled dependencies.
61 std::priority_queue<DGNode *, std::vector<DGNode *>, PriorityCmp> List;
62
63public:
64 ReadyListContainer() : List(Cmp) {}
65 void insert(DGNode *N) {
66#ifndef NDEBUG
67 assert(!N->scheduled() && "Don't insert a scheduled node!");
68 auto ListCopy = List;
69 while (!ListCopy.empty()) {
70 DGNode *Top = ListCopy.top();
71 ListCopy.pop();
72 assert(Top != N && "Node already exists in ready list!");
73 }
74#endif
75 List.push(N);
76 }
78 auto *Back = List.top();
79 List.pop();
80 return Back;
81 }
82 bool empty() const { return List.empty(); }
83 void clear() { List = {}; }
84 /// \Removes \p N if found in the ready list.
85 void remove(DGNode *N) {
86 // TODO: Use a more efficient data-structure for the ready list because the
87 // priority queue does not support fast removals.
89 Keep.reserve(List.size());
90 while (!List.empty()) {
91 auto *Top = List.top();
92 List.pop();
93 if (Top == N)
94 break;
95 Keep.push_back(Top);
96 }
97 for (auto *KeepN : Keep)
98 List.push(KeepN);
99 }
100#ifndef NDEBUG
101 void dump(raw_ostream &OS) const;
102 LLVM_DUMP_METHOD void dump() const;
103#endif // NDEBUG
104};
105
110#ifndef NDEBUG
111StringLiteral schedDirectionToStr(SchedDirection Dir);
112#endif
113
114/// The nodes that need to be scheduled back-to-back in a single scheduling
115/// cycle form a SchedBundle.
117public:
119
120private:
121 ContainerTy Nodes;
122
123 /// Called by the DGNode destructor to avoid accessing freed memory.
124 void eraseFromBundle(DGNode *N) { llvm::erase(Nodes, N); }
125 friend void DGNode::setSchedBundle(SchedBundle &); // For eraseFromBunde().
126 friend DGNode::~DGNode(); // For eraseFromBundle().
127
128public:
129 SchedBundle() = default;
130 SchedBundle(ContainerTy &&Nodes) : Nodes(std::move(Nodes)) {
131 for (auto *N : this->Nodes)
132 N->setSchedBundle(*this);
133 }
134 /// Copy CTOR (unimplemented).
135 SchedBundle(const SchedBundle &Other) = delete;
136 /// Copy Assignment (unimplemented).
139 for (auto *N : this->Nodes)
140 N->clearSchedBundle();
141 }
142 bool empty() const { return Nodes.empty(); }
143 /// Singleton bundles are created when scheduling instructions temporarily to
144 /// fill in the schedule until we schedule the vector bundle. These are
145 /// non-vector bundles containing just a single instruction.
146 bool isSingleton() const { return Nodes.size() == 1u; }
147 DGNode *back() const { return Nodes.back(); }
150 iterator begin() { return Nodes.begin(); }
151 iterator end() { return Nodes.end(); }
152 const_iterator begin() const { return Nodes.begin(); }
153 const_iterator end() const { return Nodes.end(); }
154 /// \Returns the bundle node that comes before the others in program order.
155 LLVM_ABI DGNode *getTop() const;
156 /// \Returns the bundle node that comes after the others in program order.
157 LLVM_ABI DGNode *getBot() const;
158 /// Move all bundle instructions to \p Where back-to-back.
160 /// \Returns true if all nodes in the bundle are ready.
161 bool ready(SchedDirection Dir) const {
162 return all_of(Nodes, [Dir](const auto *N) {
163 return Dir == SchedDirection::BottomUp ? N->readyBottomUp()
164 : N->readyTopDown();
165 });
166 }
167#ifndef NDEBUG
168 void dump(raw_ostream &OS) const;
169 LLVM_DUMP_METHOD void dump() const;
170#endif
171};
172
173/// The list scheduler.
174class Scheduler {
175 /// This is a list-scheduler and this is the list containing the instructions
176 /// that are ready, meaning that all their dependency successors have already
177 /// been scheduled.
178 ReadyListContainer ReadyList;
179 /// The dependency graph is used by the scheduler to determine the legal
180 /// ordering of instructions.
181 DependencyGraph DAG;
182 friend class SchedulerInternalsAttorney; // For DAG.
183 Context &Ctx;
184 /// This is the top of the schedule, i.e. the location where the scheduler
185 /// is about to place the scheduled instructions. It gets updated as we
186 /// schedule.
187 std::optional<BasicBlock::iterator> ScheduleTopItOpt;
188 // TODO: This is wasting memory in exchange for fast removal using a raw ptr.
190 /// The BB that we are currently scheduling.
191 BasicBlock *ScheduledBB = nullptr;
192 /// The ID of the callback we register with Sandbox IR.
193 std::optional<Context::CallbackID> CreateInstrCB;
194 /// Called by Sandbox IR's callback system, after \p I has been created.
195 /// NOTE: This should run after DAG's callback has run.
196 // TODO: Perhaps call DAG's notify function from within this one?
197 LLVM_ABI void notifyCreateInstr(Instruction *I);
198
199 /// \Returns a scheduling bundle containing \p Instrs.
200 SchedBundle *createBundle(ArrayRef<Instruction *> Instrs);
201 void eraseBundle(SchedBundle *SB);
202 /// Schedule nodes until we can schedule \p Instrs back-to-back.
203 bool tryScheduleUntil(ArrayRef<Instruction *> Instrs);
204 /// Schedules all nodes in \p Bndl, marks them as scheduled, updates the
205 /// UnscheduledSuccs counter of all dependency predecessors, and adds any of
206 /// them that become ready to the ready list.
207 void scheduleAndUpdateReadyList(SchedBundle &Bndl);
208 /// The scheduling state of the instructions in the bundle.
209 enum class BndlSchedState {
210 NoneScheduled, ///> No instruction in the bundle was previously scheduled.
211 AlreadyScheduled, ///> At least one instruction in the bundle belongs to a
212 /// different non-singleton scheduling bundle.
213 TemporarilyScheduled, ///> Instructions were temporarily scheduled as
214 /// singleton bundles or some of them were not
215 /// scheduled at all. None of them were in a vector
216 ///(non-singleton) bundle.
217 FullyScheduled, ///> All instrs in the bundle were previously scheduled and
218 /// were in the same SchedBundle.
219 };
220 /// \Returns whether none/some/all of \p Instrs have been scheduled.
221 LLVM_ABI BndlSchedState
222 getBndlSchedState(ArrayRef<Instruction *> Instrs) const;
223 /// Destroy the top-most part of the schedule that includes \p Instrs.
224 void trimSchedule(ArrayRef<Instruction *> Instrs);
225 /// Disable copies.
226 Scheduler(const Scheduler &) = delete;
227 Scheduler &operator=(const Scheduler &) = delete;
228
229private:
231
232public:
233 Scheduler(AAResults &AA, Context &Ctx) : DAG(AA, Ctx), Ctx(Ctx) {
234 // NOTE: The scheduler's callback depends on the DAG's callback running
235 // before it and updating the DAG accordingly.
236 CreateInstrCB = Ctx.registerCreateInstrCallback(
237 [this](Instruction *I) { notifyCreateInstr(I); });
238 }
240 if (CreateInstrCB)
241 Ctx.unregisterCreateInstrCallback(*CreateInstrCB);
242 }
244 assert(Bndls.empty() && DAG.empty() && ReadyList.empty() &&
245 !ScheduleTopItOpt && ScheduledBB == nullptr &&
246 "We can't change the direction during scheduling!");
247 Dir = NewDir;
248 }
249 /// Tries to build a schedule that includes all of \p Instrs scheduled at the
250 /// same scheduling cycle. This essentially checks that there are no
251 /// dependencies among \p Instrs. This function may involve scheduling
252 /// intermediate instructions or canceling and re-scheduling if needed.
253 /// \Returns true on success, false otherwise.
255 /// Clear the scheduler's state, including the DAG.
256 void clear() {
257 Bndls.clear();
258 // TODO: clear view once it lands.
259 DAG.clear();
260 ReadyList.clear();
261 ScheduleTopItOpt = std::nullopt;
262 ScheduledBB = nullptr;
263 assert(Bndls.empty() && DAG.empty() && ReadyList.empty() &&
264 !ScheduleTopItOpt && ScheduledBB == nullptr &&
265 "Expected empty state!");
266 }
267
268#ifndef NDEBUG
269 void dump(raw_ostream &OS) const;
270 LLVM_DUMP_METHOD void dump() const;
271#endif
272};
273
274/// A client-attorney class for accessing the Scheduler's internals (used for
275/// unit tests).
277public:
278 static DependencyGraph &getDAG(Scheduler &Sched) { return Sched.DAG; }
279 using BndlSchedState = Scheduler::BndlSchedState;
282 return Sched.getBndlSchedState(Instrs);
283 }
284};
285
286} // namespace llvm::sandboxir
287
288#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SCHEDULER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_ABI
Definition Compiler.h:215
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition Compiler.h:663
#define I(x, y, z)
Definition MD5.cpp:57
PostRA Machine Instruction Scheduler
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
InstListType::iterator iterator
Instruction iterators...
Definition BasicBlock.h:170
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition StringRef.h:888
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
A DependencyGraph Node that points to an Instruction and contains memory dependency edges.
void setSchedBundle(SchedBundle &SB)
Instruction * getInstruction() const
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
Definition Instruction.h:43
bool operator()(const DGNode *N1, const DGNode *N2)
Definition Scheduler.h:33
The list holding nodes that are ready to schedule. Used by the scheduler.
Definition Scheduler.h:55
LLVM_DUMP_METHOD void dump() const
Definition Scheduler.cpp:75
void remove(DGNode *N)
\Removes N if found in the ready list.
Definition Scheduler.h:85
The nodes that need to be scheduled back-to-back in a single scheduling cycle form a SchedBundle.
Definition Scheduler.h:116
LLVM_ABI DGNode * getBot() const
\Returns the bundle node that comes after the others in program order.
Definition Scheduler.cpp:36
SchedBundle(ContainerTy &&Nodes)
Definition Scheduler.h:130
SchedBundle & operator=(const SchedBundle &Other)=delete
Copy Assignment (unimplemented).
LLVM_ABI DGNode * getTop() const
\Returns the bundle node that comes before the others in program order.
Definition Scheduler.cpp:27
bool isSingleton() const
Singleton bundles are created when scheduling instructions temporarily to fill in the schedule until ...
Definition Scheduler.h:146
SmallVector< DGNode *, 4 > ContainerTy
Definition Scheduler.h:118
const_iterator begin() const
Definition Scheduler.h:152
LLVM_DUMP_METHOD void dump() const
Definition Scheduler.cpp:60
SchedBundle(const SchedBundle &Other)=delete
Copy CTOR (unimplemented).
ContainerTy::iterator iterator
Definition Scheduler.h:148
const_iterator end() const
Definition Scheduler.h:153
ContainerTy::const_iterator const_iterator
Definition Scheduler.h:149
LLVM_ABI void cluster(BasicBlock::iterator Where)
Move all bundle instructions to Where back-to-back.
Definition Scheduler.cpp:45
bool ready(SchedDirection Dir) const
\Returns true if all nodes in the bundle are ready.
Definition Scheduler.h:161
A client-attorney class for accessing the Scheduler's internals (used for unit tests).
Definition Scheduler.h:276
static BndlSchedState getBndlSchedState(const Scheduler &Sched, ArrayRef< Instruction * > Instrs)
Definition Scheduler.h:280
Scheduler::BndlSchedState BndlSchedState
Definition Scheduler.h:279
static DependencyGraph & getDAG(Scheduler &Sched)
Definition Scheduler.h:278
The list scheduler.
Definition Scheduler.h:174
void setDirection(SchedDirection NewDir)
Definition Scheduler.h:243
friend class SchedulerInternalsAttorney
Definition Scheduler.h:182
LLVM_DUMP_METHOD void dump() const
LLVM_ABI bool trySchedule(ArrayRef< Instruction * > Instrs)
Tries to build a schedule that includes all of Instrs scheduled at the same scheduling cycle.
void clear()
Clear the scheduler's state, including the DAG.
Definition Scheduler.h:256
Scheduler(AAResults &AA, Context &Ctx)
Definition Scheduler.h:233
Abstract Attribute helper functions.
Definition Attributor.h:165
StringLiteral schedDirectionToStr(SchedDirection Dir)
Definition Scheduler.cpp:15
BasicBlock(llvm::BasicBlock *BB, Context &SBCtx)
Definition BasicBlock.h:75
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1739
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
Definition STLExtras.h:2200
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
@ Other
Any other memory.
Definition ModRef.h:68
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1917
@ Keep
No function return thunk.
Definition CodeGen.h:162
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:860
#define N