LLVM 24.0.0git
DependencyGraph.h
Go to the documentation of this file.
1//===- DependencyGraph.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 file declares the dependency graph used by the vectorizer's instruction
10// scheduler.
11//
12// The nodes of the graph are objects of the `DGNode` class. Each `DGNode`
13// object points to an instruction.
14// The edges between `DGNode`s are implicitly defined by an ordered set of
15// predecessor nodes, to save memory.
16// Finally the whole dependency graph is an object of the `DependencyGraph`
17// class, which also provides the API for creating/extending the graph from
18// input Sandbox IR.
19//
20//===----------------------------------------------------------------------===//
21
22#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_DEPENDENCYGRAPH_H
23#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_DEPENDENCYGRAPH_H
24
25#include "llvm/ADT/DenseMap.h"
32
33namespace llvm::sandboxir {
34
35class DependencyGraph;
36class MemDGNode;
37class SchedBundle;
38
43#ifndef NDEBUG
44StringLiteral schedDirectionToStr(SchedDirection Dir);
45#endif
46
47/// SubclassIDs for isa/dyn_cast etc.
48enum class DGNodeID {
51};
52
53class DGNode;
54class MemDGNode;
55class DependencyGraph;
56
57// Defined in Transforms/Vectorize/SandboxVectorizer/Interval.cpp
58extern template class LLVM_TEMPLATE_ABI Interval<MemDGNode>;
59
60/// Iterate over both def-use and mem dependencies.
61class PredIterator {
65 DGNode *N = nullptr;
66 DependencyGraph *DAG = nullptr;
67
68 PredIterator(const User::op_iterator &OpIt, const User::op_iterator &OpItE,
70 DependencyGraph &DAG)
71 : OpIt(OpIt), OpItE(OpItE), MemIt(MemIt), N(N), DAG(&DAG) {}
72 PredIterator(const User::op_iterator &OpIt, const User::op_iterator &OpItE,
73 DGNode *N, DependencyGraph &DAG)
74 : OpIt(OpIt), OpItE(OpItE), N(N), DAG(&DAG) {}
75 friend class DGNode; // For constructor
76 friend class MemDGNode; // For constructor
77
78 /// Skip iterators that don't point instructions or are outside \p DAG,
79 /// starting from \p OpIt and ending before \p OpItE.n
80 LLVM_ABI static User::op_iterator skipBadIt(User::op_iterator OpIt,
82 const DependencyGraph &DAG);
83
84public:
85 using difference_type = std::ptrdiff_t;
86 using value_type = DGNode *;
89 using iterator_category = std::input_iterator_tag;
91 LLVM_ABI PredIterator &operator++();
92 PredIterator operator++(int) {
93 auto Copy = *this;
94 ++(*this);
95 return Copy;
96 }
97 LLVM_ABI bool operator==(const PredIterator &Other) const;
98 bool operator!=(const PredIterator &Other) const { return !(*this == Other); }
99};
100
101/// Iterate over both def-use and mem dependencies.
102class SuccIterator {
103 User::user_iterator UserIt;
104 User::user_iterator UserItE;
106 DGNode *N = nullptr;
107 DependencyGraph *DAG = nullptr;
108
109 SuccIterator(const Value::user_iterator &UserIt,
110 const Value::user_iterator &UserItE,
112 DependencyGraph &DAG)
113 : UserIt(UserIt), UserItE(UserItE), MemIt(MemIt), N(N), DAG(&DAG) {}
114 SuccIterator(const User::user_iterator &UserIt,
115 const User::user_iterator &UserItE, DGNode *N,
116 DependencyGraph &DAG)
117 : UserIt(UserIt), UserItE(UserItE), N(N), DAG(&DAG) {}
118 friend class DGNode; // For constructor
119 friend class MemDGNode; // For constructor
120
121 /// Skip iterators that don't point to instructions or are outside \p DAG,
122 /// starting from \p OpIt and ending before \p OpItE.
124 skipOutOfScope(User::user_iterator UserIt, User::user_iterator UserItE,
125 const DependencyGraph &DAG);
126
127public:
128 using difference_type = std::ptrdiff_t;
132 using iterator_category = std::input_iterator_tag;
134 LLVM_ABI SuccIterator &operator++();
135 SuccIterator operator++(int) {
136 auto Copy = *this;
137 ++(*this);
138 return Copy;
139 }
140 LLVM_ABI bool operator==(const SuccIterator &Other) const;
141 bool operator!=(const SuccIterator &Other) const { return !(*this == Other); }
142};
143
144/// A DependencyGraph Node that points to an Instruction and contains memory
145/// dependency edges.
147protected:
149 // TODO: Use a PointerIntPair for SubclassID and I.
150 /// For isa/dyn_cast etc.
152 /// The number of unscheduled successors. Optional represents whether the
153 /// value is meaningless, e.g., after a node gets scheduled.
154 std::optional<unsigned> UnscheduledSuccs = 0;
155 std::optional<unsigned> UnscheduledPreds = 0;
156 /// This is true if this node has been scheduled.
157 bool Scheduled = false;
158 /// The scheduler bundle that this node belongs to.
159 SchedBundle *SB = nullptr;
160
162 void clearSchedBundle() { this->SB = nullptr; }
163 friend class SchedBundle; // For setSchedBundle(), clearSchedBundle().
164
166 friend class MemDGNode; // For constructor.
167 friend class DependencyGraph; // For UnscheduledSuccs
168
169public:
171 assert(!isMemDepNodeCandidate(I) && "Expected Non-Mem instruction, ");
172 }
173 DGNode(const DGNode &Other) = delete;
174 virtual ~DGNode();
175 /// \Returns the number of unscheduled successors.
176 unsigned getNumUnscheduledSuccs() const {
177 assert((bool)UnscheduledSuccs && "Invalid UnscheduledSuccs!");
178 return *UnscheduledSuccs;
179 }
180 /// \Returns the number of unscheduled predecessors.
181 unsigned getNumUnscheduledPreds() const {
182 assert((bool)UnscheduledPreds && "Invalid UnscheduledPreds!");
183 return *UnscheduledPreds;
184 }
185#ifndef NDEBUG
186 /// \returns true unscheduled successors contains valid data (for testing).
187 bool validUnscheduledSuccs() const { return (bool)UnscheduledSuccs; }
188 /// \returns true unscheduled predecessors contains valid data (for testing).
189 bool validUnscheduledPreds() const { return (bool)UnscheduledPreds; }
190#endif
191 // TODO: Make this private?
193 assert(*UnscheduledSuccs > 0 && "Counting error!");
195 }
198 assert(*UnscheduledPreds > 0 && "Counting error!");
200 }
202
206 Scheduled = false;
207 }
208 /// \Returns true if all dependent successors (or predecessors during top-down
209 /// scheduling) have been scheduled.
210 bool readyBottomUp() const { return UnscheduledSuccs == 0; }
211 bool readyTopDown() const { return UnscheduledPreds == 0; }
212 /// \Returns true if this node has been scheduled.
213 bool scheduled() const { return Scheduled; }
215 Scheduled = true;
216 // UnscheduledSuccs is meaningless from this point on, so prohibit its use.
217 UnscheduledSuccs = std::nullopt;
218 UnscheduledPreds = std::nullopt;
219 }
220 /// \Returns the scheduling bundle that this node belongs to, or nullptr.
221 SchedBundle *getSchedBundle() const { return SB; }
222 /// \Returns true if this is before \p Other in program order.
223 bool comesBefore(const DGNode *Other) { return I->comesBefore(Other->I); }
226 return PredIterator(
227 PredIterator::skipBadIt(I->op_begin(), I->op_end(), DAG), I->op_end(),
228 this, DAG);
229 }
231 return PredIterator(I->op_end(), I->op_end(), this, DAG);
232 }
234 return const_cast<DGNode *>(this)->preds_begin(DAG);
235 }
237 return const_cast<DGNode *>(this)->preds_end(DAG);
238 }
239 /// \Returns a range of DAG predecessors nodes. If this is a MemDGNode then
240 /// this will also include the memory dependency predecessors.
241 /// Please note that this can include the same node more than once, if for
242 /// example it's both a use-def predecessor and a mem dep predecessor.
246
249 return SuccIterator(
250 SuccIterator::skipOutOfScope(I->user_begin(), I->user_end(), DAG),
251 I->user_end(), this, DAG);
252 }
254 return SuccIterator(I->user_end(), I->user_end(), this, DAG);
255 }
257 return const_cast<DGNode *>(this)->succs_begin(DAG);
258 }
260 return const_cast<DGNode *>(this)->succs_end(DAG);
261 }
262 /// \Returns a range of DAG successor nodes. If this is a MemDGNode then
263 /// this will also include the memory dependency successors.
264 /// Please note that this can include the same node more than once, if for
265 /// example it's both a use-def predecessor and a mem dep successor.
269
271 if (auto *II = dyn_cast<IntrinsicInst>(I)) {
272 auto IID = II->getIntrinsicID();
273 return IID == Intrinsic::stackrestore || IID == Intrinsic::stacksave;
274 }
275 return false;
276 }
277
278 /// \Returns true if intrinsic \p I touches memory. This is used by the
279 /// dependency graph.
281 auto IID = I->getIntrinsicID();
282 return IID != Intrinsic::sideeffect && IID != Intrinsic::pseudoprobe;
283 }
284
285 /// We consider \p I as a Memory Dependency Candidate instruction if it
286 /// reads/write memory or if it has side-effects. This is used by the
287 /// dependency graph.
290 return I->mayReadOrWriteMemory() &&
292 }
293
294 /// \Returns true if \p I is fence like. It excludes non-mem intrinsics.
295 static bool isFenceLike(Instruction *I) {
297 return I->isFenceLike() &&
299 }
300
301 /// \Returns true if \p I is a memory dependency candidate instruction.
303 AllocaInst *Alloca;
304 return isMemDepCandidate(I) ||
305 ((Alloca = dyn_cast<AllocaInst>(I)) &&
306 Alloca->isUsedWithInAlloca()) ||
308 }
309
310 Instruction *getInstruction() const { return I; }
311
312#ifndef NDEBUG
313 virtual void print(raw_ostream &OS, bool PrintDeps = true) const;
315 N.print(OS);
316 return OS;
317 }
318 LLVM_DUMP_METHOD void dump() const;
319#endif // NDEBUG
320};
321
322/// A DependencyGraph Node for instructions that may read/write memory, or have
323/// some ordering constraints, like with stacksave/stackrestore and
324/// alloca/inalloca.
325class MemDGNode final : public DGNode {
326 MemDGNode *PrevMemN = nullptr;
327 MemDGNode *NextMemN = nullptr;
328 /// Memory predecessors.
329 DenseSet<MemDGNode *> MemPreds;
330 /// Memory successors.
331 DenseSet<MemDGNode *> MemSuccs;
332 friend class PredIterator; // For MemPreds.
333 friend class SuccIterator; // For MemSuccs.
334 /// Creates both edges: this<->N.
335 void setNextNode(MemDGNode *N) {
336 assert(N != this && "About to point to self!");
337 NextMemN = N;
338 if (NextMemN != nullptr)
339 NextMemN->PrevMemN = this;
340 }
341 /// Creates both edges: N<->this.
342 void setPrevNode(MemDGNode *N) {
343 assert(N != this && "About to point to self!");
344 PrevMemN = N;
345 if (PrevMemN != nullptr)
346 PrevMemN->NextMemN = this;
347 }
348 friend class DependencyGraph; // For setNextNode(), setPrevNode().
349 void detachFromChain() {
350 if (PrevMemN != nullptr)
351 PrevMemN->NextMemN = NextMemN;
352 if (NextMemN != nullptr)
353 NextMemN->PrevMemN = PrevMemN;
354 PrevMemN = nullptr;
355 NextMemN = nullptr;
356 }
357
358public:
360 assert(isMemDepNodeCandidate(I) && "Expected Mem instruction!");
361 }
362 static bool classof(const DGNode *Other) {
363 return Other->SubclassID == DGNodeID::MemDGNode;
364 }
366 auto OpEndIt = I->op_end();
367 return PredIterator(PredIterator::skipBadIt(I->op_begin(), OpEndIt, DAG),
368 OpEndIt, MemPreds.begin(), this, DAG);
369 }
371 return PredIterator(I->op_end(), I->op_end(), MemPreds.end(), this, DAG);
372 }
374 auto UserEndIt = I->user_end();
375 return SuccIterator(
376 SuccIterator::skipOutOfScope(I->user_begin(), UserEndIt, DAG),
377 UserEndIt, MemSuccs.begin(), this, DAG);
378 }
380 return SuccIterator(I->user_end(), I->user_end(), MemSuccs.end(), this,
381 DAG);
382 }
383 /// \Returns the previous Mem DGNode in instruction order.
384 MemDGNode *getPrevNode() const { return PrevMemN; }
385 /// \Returns the next Mem DGNode in instruction order.
386 MemDGNode *getNextNode() const { return NextMemN; }
387 /// Adds the mem dependency edge PredN->this. This also increments the
388 /// UnscheduledSuccs counter of the predecessor if this node has not been
389 /// scheduled.
390 void addMemPred(MemDGNode *PredN) {
391 [[maybe_unused]] auto Inserted = MemPreds.insert(PredN).second;
392 assert(Inserted && "PredN already exists!");
393 assert(PredN != this && "Trying to add a dependency to self!");
394 PredN->MemSuccs.insert(this);
395 if (!Scheduled) {
396 if (!PredN->Scheduled) {
397 PredN->incrUnscheduledSuccs();
399 }
400 }
401 }
402 /// Removes the memory dependency PredN->this. This also updates the
403 /// UnscheduledSuccs counter of PredN if this node has not been scheduled.
405 MemPreds.erase(PredN);
406 PredN->MemSuccs.erase(this);
407 if (!Scheduled) {
408 if (!PredN->Scheduled) {
409 PredN->decrUnscheduledSuccs();
411 }
412 }
413 }
414 /// \Returns true if there is a memory dependency N->this.
415 bool hasMemPred(DGNode *N) const {
416 if (auto *MN = dyn_cast<MemDGNode>(N))
417 return MemPreds.count(MN);
418 return false;
419 }
420 /// \Returns all memory dependency predecessors. Used by tests.
422 return make_range(MemPreds.begin(), MemPreds.end());
423 }
424 /// \Returns all memory dependency successors.
426 return make_range(MemSuccs.begin(), MemSuccs.end());
427 }
428#ifndef NDEBUG
429 void print(raw_ostream &OS, bool PrintDeps = true) const override;
430#endif // NDEBUG
431};
432
433/// Convenience builders for a MemDGNode interval.
435public:
436 /// Scans the instruction chain in \p Intvl top-down, returning the top-most
437 /// MemDGNode, or nullptr.
439 const DependencyGraph &DAG);
440 /// Scans the instruction chain in \p Intvl bottom-up, returning the
441 /// bottom-most MemDGNode, or nullptr.
443 const DependencyGraph &DAG);
444 /// Given \p Instrs it finds their closest mem nodes in the interval and
445 /// returns the corresponding mem range. Note: BotN (or its neighboring mem
446 /// node) is included in the range.
448 DependencyGraph &DAG);
449 static Interval<MemDGNode> makeEmpty() { return {}; }
450};
451
453private:
455 /// The DAG spans across all instructions in this interval.
456 Interval<Instruction> DAGInterval;
457
458 SchedDirection Dir;
459
460 Context *Ctx = nullptr;
461 std::optional<Context::CallbackID> CreateInstrCB;
462 std::optional<Context::CallbackID> EraseInstrCB;
463 std::optional<Context::CallbackID> MoveInstrCB;
464 std::optional<Context::CallbackID> SetUseCB;
465
466 std::unique_ptr<BatchAAResults> BatchAA;
467
468 enum class DependencyType {
469 ReadAfterWrite, ///> Memory dependency write -> read
470 WriteAfterWrite, ///> Memory dependency write -> write
471 WriteAfterRead, ///> Memory dependency read -> write
472 Control, ///> Control-related dependency, like with PHI/Terminator
473 Other, ///> Currently used for stack related instrs
474 None, ///> No memory/other dependency
475 };
476 /// \Returns the dependency type depending on whether instructions may
477 /// read/write memory or whether they are some specific opcode-related
478 /// restrictions.
479 /// Note: It does not check whether a memory dependency is actually correct,
480 /// as it won't call AA. Therefore it returns the worst-case dep type.
481 static DependencyType getRoughDepType(Instruction *FromI, Instruction *ToI);
482
483 // TODO: Implement AABudget.
484 /// \Returns true if there is a memory/other dependency \p SrcI->DstI.
485 bool alias(Instruction *SrcI, Instruction *DstI, DependencyType DepType);
486
487 bool hasDep(sandboxir::Instruction *SrcI, sandboxir::Instruction *DstI);
488
489 /// Go through all mem nodes in \p SrcScanRange and try to add dependencies to
490 /// \p DstN.
491 void scanAndAddDeps(MemDGNode &DstN, const Interval<MemDGNode> &SrcScanRange);
492
493 /// Sets the UnscheduledSuccs of all DGNodes in \p NewInterval based on
494 /// def-use edges.
495 void setDefUseUnscheduledSuccs(const Interval<Instruction> &NewInterval);
496
497 /// Create DAG nodes for instrs in \p NewInterval and update the MemNode
498 /// chain.
499 void createNewNodes(const Interval<Instruction> &NewInterval);
500
501 /// Helper for `notify*Instr()`. \Returns the first MemDGNode that comes
502 /// before \p N, skipping \p SkipN, including or excluding \p N based on
503 /// \p IncludingN, or nullptr if not found.
504 MemDGNode *getMemDGNodeBefore(DGNode *N, bool IncludingN,
505 MemDGNode *SkipN = nullptr) const;
506 /// Helper for `notifyMoveInstr()`. \Returns the first MemDGNode that comes
507 /// after \p N, skipping \p SkipN, including or excluding \p N based on \p
508 /// IncludingN, or nullptr if not found.
509 MemDGNode *getMemDGNodeAfter(DGNode *N, bool IncludingN,
510 MemDGNode *SkipN = nullptr) const;
511
512 /// Called by the callbacks when a new instruction \p I has been created.
513 LLVM_ABI void notifyCreateInstr(Instruction *I);
514 /// Called by the callbacks when instruction \p I is about to get
515 /// deleted.
516 LLVM_ABI void notifyEraseInstr(Instruction *I);
517 /// Called by the callbacks when instruction \p I is about to be moved to
518 /// \p To.
519 LLVM_ABI void notifyMoveInstr(Instruction *I, const BBIterator &To);
520 /// Called by the callbacks when \p U's source is about to be set to \p NewSrc
521 LLVM_ABI void notifySetUse(const Use &U, Value *NewSrc);
522
523public:
524 /// This constructor also registers callbacks.
526 : Dir(Dir), Ctx(&Ctx), BatchAA(std::make_unique<BatchAAResults>(AA)) {
527 CreateInstrCB = Ctx.registerCreateInstrCallback(
528 [this](Instruction *I) { notifyCreateInstr(I); });
529 EraseInstrCB = Ctx.registerEraseInstrCallback(
530 [this](Instruction *I) { notifyEraseInstr(I); });
531 MoveInstrCB = Ctx.registerMoveInstrCallback(
532 [this](Instruction *I, const BBIterator &To) {
533 notifyMoveInstr(I, To);
534 });
535 SetUseCB = Ctx.registerSetUseCallback(
536 [this](const Use &U, Value *NewSrc) { notifySetUse(U, NewSrc); });
537 }
539 if (CreateInstrCB)
540 Ctx->unregisterCreateInstrCallback(*CreateInstrCB);
541 if (EraseInstrCB)
542 Ctx->unregisterEraseInstrCallback(*EraseInstrCB);
543 if (MoveInstrCB)
544 Ctx->unregisterMoveInstrCallback(*MoveInstrCB);
545 if (SetUseCB)
546 Ctx->unregisterSetUseCallback(*SetUseCB);
547 }
548
550 auto It = InstrToNodeMap.find(I);
551 return It != InstrToNodeMap.end() ? It->second.get() : nullptr;
552 }
553 /// Like getNode() but returns nullptr if \p I is nullptr.
555 if (I == nullptr)
556 return nullptr;
557 return getNode(I);
558 }
560 auto [It, NotInMap] = InstrToNodeMap.try_emplace(I);
561 if (NotInMap) {
563 It->second = std::make_unique<MemDGNode>(I);
564 else
565 It->second = std::make_unique<DGNode>(I);
566 }
567 return It->second.get();
568 }
569 /// Build/extend the dependency graph such that it includes \p Instrs. Returns
570 /// the range of instructions added to the DAG.
572 /// \Returns the range of instructions included in the DAG.
573 Interval<Instruction> getInterval() const { return DAGInterval; }
574 void clear() {
575 InstrToNodeMap.clear();
576 DAGInterval = {};
577 }
578#ifndef NDEBUG
579 /// \Returns true if the DAG's state is clear. Used in assertions.
580 bool empty() const {
581 bool IsEmpty = InstrToNodeMap.empty();
582 assert(IsEmpty == DAGInterval.empty() &&
583 "Interval and InstrToNodeMap out of sync!");
584 return IsEmpty;
585 }
586 void print(raw_ostream &OS) const;
587 LLVM_DUMP_METHOD void dump() const;
588#endif // NDEBUG
589};
590} // namespace llvm::sandboxir
591
592#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_DEPENDENCYGRAPH_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_ABI
Definition Compiler.h:215
#define LLVM_TEMPLATE_ABI
Definition Compiler.h:216
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition Compiler.h:678
This file defines the DenseMap class.
#define I(x, y, z)
Definition MD5.cpp:57
std::pair< uint64_t, uint64_t > Interval
uint64_t IntrinsicInst * II
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This class is a wrapper over an AAResults, and it is intended to be used only when there are no IR ch...
Represent a node in the directed graph.
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition StringRef.h:888
A range adaptor for a pair of iterators.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
bool isUsedWithInAlloca() const
Return true if this alloca is used as an inalloca argument to a call.
A DependencyGraph Node that points to an Instruction and contains memory dependency edges.
static bool isMemDepCandidate(Instruction *I)
We consider I as a Memory Dependency Candidate instruction if it reads/write memory or if it has side...
virtual iterator preds_end(DependencyGraph &DAG)
static bool isMemIntrinsic(IntrinsicInst *I)
\Returns true if intrinsic I touches memory.
iterator preds_begin(DependencyGraph &DAG) const
unsigned getNumUnscheduledPreds() const
\Returns the number of unscheduled predecessors.
DGNode(Instruction *I, DGNodeID ID)
unsigned getNumUnscheduledSuccs() const
\Returns the number of unscheduled successors.
bool readyBottomUp() const
\Returns true if all dependent successors (or predecessors during top-down scheduling) have been sche...
void setSchedBundle(SchedBundle &SB)
bool scheduled() const
\Returns true if this node has been scheduled.
virtual succ_iterator succs_end(DependencyGraph &DAG)
bool validUnscheduledSuccs() const
succ_iterator succs_end(DependencyGraph &DAG) const
iterator_range< iterator > preds(DependencyGraph &DAG) const
\Returns a range of DAG predecessors nodes.
iterator preds_end(DependencyGraph &DAG) const
SchedBundle * SB
The scheduler bundle that this node belongs to.
bool Scheduled
This is true if this node has been scheduled.
std::optional< unsigned > UnscheduledSuccs
The number of unscheduled successors.
static bool isMemDepNodeCandidate(Instruction *I)
\Returns true if I is a memory dependency candidate instruction.
SchedBundle * getSchedBundle() const
\Returns the scheduling bundle that this node belongs to, or nullptr.
iterator_range< succ_iterator > succs(DependencyGraph &DAG) const
\Returns a range of DAG successor nodes.
DGNodeID SubclassID
For isa/dyn_cast etc.
DGNode(const DGNode &Other)=delete
static bool isFenceLike(Instruction *I)
\Returns true if I is fence like. It excludes non-mem intrinsics.
Instruction * getInstruction() const
static bool isStackSaveOrRestoreIntrinsic(Instruction *I)
bool comesBefore(const DGNode *Other)
\Returns true if this is before Other in program order.
virtual succ_iterator succs_begin(DependencyGraph &DAG)
bool validUnscheduledPreds() const
friend raw_ostream & operator<<(raw_ostream &OS, DGNode &N)
std::optional< unsigned > UnscheduledPreds
virtual iterator preds_begin(DependencyGraph &DAG)
succ_iterator succs_begin(DependencyGraph &DAG) const
Interval< Instruction > getInterval() const
\Returns the range of instructions included in the DAG.
bool empty() const
\Returns true if the DAG's state is clear. Used in assertions.
LLVM_DUMP_METHOD void dump() const
DGNode * getNode(Instruction *I) const
DGNode * getNodeOrNull(Instruction *I) const
Like getNode() but returns nullptr if I is nullptr.
void print(raw_ostream &OS) const
DependencyGraph(SchedDirection Dir, AAResults &AA, Context &Ctx)
This constructor also registers callbacks.
DGNode * getOrCreateNode(Instruction *I)
LLVM_ABI Interval< Instruction > extend(ArrayRef< Instruction * > Instrs)
Build/extend the dependency graph such that it includes Instrs.
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
Definition Instruction.h:43
Convenience builders for a MemDGNode interval.
static LLVM_ABI MemDGNode * getBotMemDGNode(const Interval< Instruction > &Intvl, const DependencyGraph &DAG)
Scans the instruction chain in Intvl bottom-up, returning the bottom-most MemDGNode,...
static Interval< MemDGNode > makeEmpty()
static LLVM_ABI MemDGNode * getTopMemDGNode(const Interval< Instruction > &Intvl, const DependencyGraph &DAG)
Scans the instruction chain in Intvl top-down, returning the top-most MemDGNode, or nullptr.
static LLVM_ABI Interval< MemDGNode > make(const Interval< Instruction > &Instrs, DependencyGraph &DAG)
Given Instrs it finds their closest mem nodes in the interval and returns the corresponding mem range...
A DependencyGraph Node for instructions that may read/write memory, or have some ordering constraints...
iterator preds_end(DependencyGraph &DAG) override
iterator preds_begin(DependencyGraph &DAG) override
bool hasMemPred(DGNode *N) const
\Returns true if there is a memory dependency N->this.
static bool classof(const DGNode *Other)
iterator_range< DenseSet< MemDGNode * >::const_iterator > memPreds() const
\Returns all memory dependency predecessors. Used by tests.
MemDGNode * getNextNode() const
\Returns the next Mem DGNode in instruction order.
iterator_range< DenseSet< MemDGNode * >::const_iterator > memSuccs() const
\Returns all memory dependency successors.
succ_iterator succs_begin(DependencyGraph &DAG) override
void removeMemPred(MemDGNode *PredN)
Removes the memory dependency PredN->this.
MemDGNode * getPrevNode() const
\Returns the previous Mem DGNode in instruction order.
void addMemPred(MemDGNode *PredN)
Adds the mem dependency edge PredN->this.
succ_iterator succs_end(DependencyGraph &DAG) override
Iterate over both def-use and mem dependencies.
bool operator!=(const PredIterator &Other) const
LLVM_ABI PredIterator & operator++()
std::input_iterator_tag iterator_category
The nodes that need to be scheduled back-to-back in a single scheduling cycle form a SchedBundle.
Definition Scheduler.h:115
Iterate over both def-use and mem dependencies.
LLVM_ABI SuccIterator & operator++()
bool operator!=(const SuccIterator &Other) const
std::input_iterator_tag iterator_category
Represents a Def-use/Use-def edge in SandboxIR.
Definition Use.h:43
OperandUseIterator op_iterator
Definition User.h:98
A SandboxIR Value has users. This is the base class.
Definition Value.h:72
mapped_iterator< sandboxir::UserUseIterator, UseToUser > user_iterator
Definition Value.h:239
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
Abstract Attribute helper functions.
Definition Attributor.h:165
StringLiteral schedDirectionToStr(SchedDirection Dir)
DGNodeID
SubclassIDs for isa/dyn_cast etc.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
APInt operator*(APInt a, uint64_t RHS)
Definition APInt.h:2266
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
@ Other
Any other memory.
Definition ModRef.h:68
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
#define N