LLVM 20.0.0git
DependencyGraph.cpp
Go to the documentation of this file.
1//===- DependencyGraph.cpp ------------------------------------------===//
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
10#include "llvm/ADT/ArrayRef.h"
14
15namespace llvm::sandboxir {
16
18 // If it's a DGNode then we dereference the operand iterator.
19 if (!isa<MemDGNode>(N)) {
20 assert(OpIt != OpItE && "Can't dereference end iterator!");
21 return DAG->getNode(cast<Instruction>((Value *)*OpIt));
22 }
23 // It's a MemDGNode, so we check if we return either the use-def operand,
24 // or a mem predecessor.
25 if (OpIt != OpItE)
26 return DAG->getNode(cast<Instruction>((Value *)*OpIt));
27 // It's a MemDGNode with OpIt == end, so we need to use MemIt.
28 assert(MemIt != cast<MemDGNode>(N)->MemPreds.end() &&
29 "Cant' dereference end iterator!");
30 return *MemIt;
31}
32
34 // If it's a DGNode then we increment the use-def iterator.
35 if (!isa<MemDGNode>(N)) {
36 assert(OpIt != OpItE && "Already at end!");
37 ++OpIt;
38 // Skip operands that are not instructions.
39 OpIt = skipNonInstr(OpIt, OpItE);
40 return *this;
41 }
42 // It's a MemDGNode, so if we are not at the end of the use-def iterator we
43 // need to first increment that.
44 if (OpIt != OpItE) {
45 ++OpIt;
46 // Skip operands that are not instructions.
47 OpIt = skipNonInstr(OpIt, OpItE);
48 return *this;
49 }
50 // It's a MemDGNode with OpIt == end, so we need to increment MemIt.
51 assert(MemIt != cast<MemDGNode>(N)->MemPreds.end() && "Already at end!");
52 ++MemIt;
53 return *this;
54}
55
57 assert(DAG == Other.DAG && "Iterators of different DAGs!");
58 assert(N == Other.N && "Iterators of different nodes!");
59 return OpIt == Other.OpIt && MemIt == Other.MemIt;
60}
61
63 if (SB == nullptr)
64 return;
65 SB->eraseFromBundle(this);
66}
67
68#ifndef NDEBUG
69void DGNode::print(raw_ostream &OS, bool PrintDeps) const {
70 OS << *I << " USuccs:" << UnscheduledSuccs << " Sched:" << Scheduled << "\n";
71}
72void DGNode::dump() const { print(dbgs()); }
73void MemDGNode::print(raw_ostream &OS, bool PrintDeps) const {
74 DGNode::print(OS, false);
75 if (PrintDeps) {
76 // Print memory preds.
77 static constexpr const unsigned Indent = 4;
78 for (auto *Pred : MemPreds)
79 OS.indent(Indent) << "<-" << *Pred->getInstruction() << "\n";
80 }
81}
82#endif // NDEBUG
83
86 const DependencyGraph &DAG) {
87 Instruction *I = Intvl.top();
88 Instruction *BeforeI = Intvl.bottom();
89 // Walk down the chain looking for a mem-dep candidate instruction.
90 while (!DGNode::isMemDepNodeCandidate(I) && I != BeforeI)
91 I = I->getNextNode();
93 return nullptr;
94 return cast<MemDGNode>(DAG.getNode(I));
95}
96
99 const DependencyGraph &DAG) {
100 Instruction *I = Intvl.bottom();
101 Instruction *AfterI = Intvl.top();
102 // Walk up the chain looking for a mem-dep candidate instruction.
103 while (!DGNode::isMemDepNodeCandidate(I) && I != AfterI)
104 I = I->getPrevNode();
106 return nullptr;
107 return cast<MemDGNode>(DAG.getNode(I));
108}
109
112 DependencyGraph &DAG) {
113 auto *TopMemN = getTopMemDGNode(Instrs, DAG);
114 // If we couldn't find a mem node in range TopN - BotN then it's empty.
115 if (TopMemN == nullptr)
116 return {};
117 auto *BotMemN = getBotMemDGNode(Instrs, DAG);
118 assert(BotMemN != nullptr && "TopMemN should be null too!");
119 // Now that we have the mem-dep nodes, create and return the range.
120 return Interval<MemDGNode>(TopMemN, BotMemN);
121}
122
123DependencyGraph::DependencyType
124DependencyGraph::getRoughDepType(Instruction *FromI, Instruction *ToI) {
125 // TODO: Perhaps compile-time improvement by skipping if neither is mem?
126 if (FromI->mayWriteToMemory()) {
127 if (ToI->mayReadFromMemory())
128 return DependencyType::ReadAfterWrite;
129 if (ToI->mayWriteToMemory())
130 return DependencyType::WriteAfterWrite;
131 } else if (FromI->mayReadFromMemory()) {
132 if (ToI->mayWriteToMemory())
133 return DependencyType::WriteAfterRead;
134 }
135 if (isa<sandboxir::PHINode>(FromI) || isa<sandboxir::PHINode>(ToI))
136 return DependencyType::Control;
137 if (ToI->isTerminator())
138 return DependencyType::Control;
141 return DependencyType::Other;
142 return DependencyType::None;
143}
144
145static bool isOrdered(Instruction *I) {
146 auto IsOrdered = [](Instruction *I) {
147 if (auto *LI = dyn_cast<LoadInst>(I))
148 return !LI->isUnordered();
149 if (auto *SI = dyn_cast<StoreInst>(I))
150 return !SI->isUnordered();
152 return true;
153 return false;
154 };
155 bool Is = IsOrdered(I);
157 "An ordered instruction must be a MemDepCandidate!");
158 return Is;
159}
160
161bool DependencyGraph::alias(Instruction *SrcI, Instruction *DstI,
162 DependencyType DepType) {
163 std::optional<MemoryLocation> DstLocOpt =
165 if (!DstLocOpt)
166 return true;
167 // Check aliasing.
168 assert((SrcI->mayReadFromMemory() || SrcI->mayWriteToMemory()) &&
169 "Expected a mem instr");
170 // TODO: Check AABudget
171 ModRefInfo SrcModRef =
172 isOrdered(SrcI)
174 : Utils::aliasAnalysisGetModRefInfo(*BatchAA, SrcI, *DstLocOpt);
175 switch (DepType) {
176 case DependencyType::ReadAfterWrite:
177 case DependencyType::WriteAfterWrite:
178 return isModSet(SrcModRef);
179 case DependencyType::WriteAfterRead:
180 return isRefSet(SrcModRef);
181 default:
182 llvm_unreachable("Expected only RAW, WAW and WAR!");
183 }
184}
185
186bool DependencyGraph::hasDep(Instruction *SrcI, Instruction *DstI) {
187 DependencyType RoughDepType = getRoughDepType(SrcI, DstI);
188 switch (RoughDepType) {
189 case DependencyType::ReadAfterWrite:
190 case DependencyType::WriteAfterWrite:
191 case DependencyType::WriteAfterRead:
192 return alias(SrcI, DstI, RoughDepType);
193 case DependencyType::Control:
194 // Adding actual dep edges from PHIs/to terminator would just create too
195 // many edges, which would be bad for compile-time.
196 // So we ignore them in the DAG formation but handle them in the
197 // scheduler, while sorting the ready list.
198 return false;
199 case DependencyType::Other:
200 return true;
201 case DependencyType::None:
202 return false;
203 }
204 llvm_unreachable("Unknown DependencyType enum");
205}
206
207void DependencyGraph::scanAndAddDeps(MemDGNode &DstN,
208 const Interval<MemDGNode> &SrcScanRange) {
209 assert(isa<MemDGNode>(DstN) &&
210 "DstN is the mem dep destination, so it must be mem");
211 Instruction *DstI = DstN.getInstruction();
212 // Walk up the instruction chain from ScanRange bottom to top, looking for
213 // memory instrs that may alias.
214 for (MemDGNode &SrcN : reverse(SrcScanRange)) {
215 Instruction *SrcI = SrcN.getInstruction();
216 if (hasDep(SrcI, DstI))
217 DstN.addMemPred(&SrcN);
218 }
219}
220
221void DependencyGraph::setDefUseUnscheduledSuccs(
222 const Interval<Instruction> &NewInterval) {
223 // +---+
224 // | | Def
225 // | | |
226 // | | v
227 // | | Use
228 // +---+
229 // Set the intra-interval counters in NewInterval.
230 for (Instruction &I : NewInterval) {
231 for (Value *Op : I.operands()) {
232 auto *OpI = dyn_cast<Instruction>(Op);
233 if (OpI == nullptr)
234 continue;
235 // TODO: For now don't cross BBs.
236 if (OpI->getParent() != I.getParent())
237 continue;
238 if (!NewInterval.contains(OpI))
239 continue;
240 auto *OpN = getNode(OpI);
241 if (OpN == nullptr)
242 continue;
243 ++OpN->UnscheduledSuccs;
244 }
245 }
246
247 // Now handle the cross-interval edges.
248 bool NewIsAbove = DAGInterval.empty() || NewInterval.comesBefore(DAGInterval);
249 const auto &TopInterval = NewIsAbove ? NewInterval : DAGInterval;
250 const auto &BotInterval = NewIsAbove ? DAGInterval : NewInterval;
251 // +---+
252 // |Top|
253 // | | Def
254 // +---+ |
255 // | | v
256 // |Bot| Use
257 // | |
258 // +---+
259 // Walk over all instructions in "BotInterval" and update the counter
260 // of operands that are in "TopInterval".
261 for (Instruction &BotI : BotInterval) {
262 auto *BotN = getNode(&BotI);
263 // Skip scheduled nodes.
264 if (BotN->scheduled())
265 continue;
266 for (Value *Op : BotI.operands()) {
267 auto *OpI = dyn_cast<Instruction>(Op);
268 if (OpI == nullptr)
269 continue;
270 if (!TopInterval.contains(OpI))
271 continue;
272 auto *OpN = getNode(OpI);
273 if (OpN == nullptr)
274 continue;
275 ++OpN->UnscheduledSuccs;
276 }
277 }
278}
279
280void DependencyGraph::createNewNodes(const Interval<Instruction> &NewInterval) {
281 // Create Nodes only for the new sections of the DAG.
282 DGNode *LastN = getOrCreateNode(NewInterval.top());
283 MemDGNode *LastMemN = dyn_cast<MemDGNode>(LastN);
284 for (Instruction &I : drop_begin(NewInterval)) {
285 auto *N = getOrCreateNode(&I);
286 // Build the Mem node chain.
287 if (auto *MemN = dyn_cast<MemDGNode>(N)) {
288 MemN->setPrevNode(LastMemN);
289 LastMemN = MemN;
290 }
291 }
292 // Link new MemDGNode chain with the old one, if any.
293 if (!DAGInterval.empty()) {
294 bool NewIsAbove = NewInterval.comesBefore(DAGInterval);
295 const auto &TopInterval = NewIsAbove ? NewInterval : DAGInterval;
296 const auto &BotInterval = NewIsAbove ? DAGInterval : NewInterval;
297 MemDGNode *LinkTopN =
299 MemDGNode *LinkBotN =
301 assert((LinkTopN == nullptr || LinkBotN == nullptr ||
302 LinkTopN->comesBefore(LinkBotN)) &&
303 "Wrong order!");
304 if (LinkTopN != nullptr && LinkBotN != nullptr) {
305 LinkTopN->setNextNode(LinkBotN);
306 }
307#ifndef NDEBUG
308 // TODO: Remove this once we've done enough testing.
309 // Check that the chain is well formed.
310 auto UnionIntvl = DAGInterval.getUnionInterval(NewInterval);
311 MemDGNode *ChainTopN =
313 MemDGNode *ChainBotN =
315 if (ChainTopN != nullptr && ChainBotN != nullptr) {
316 for (auto *N = ChainTopN->getNextNode(), *LastN = ChainTopN; N != nullptr;
317 LastN = N, N = N->getNextNode()) {
318 assert(N == LastN->getNextNode() && "Bad chain!");
319 assert(N->getPrevNode() == LastN && "Bad chain!");
320 }
321 }
322#endif // NDEBUG
323 }
324
325 setDefUseUnscheduledSuccs(NewInterval);
326}
327
328MemDGNode *DependencyGraph::getMemDGNodeBefore(DGNode *N, bool IncludingN,
329 MemDGNode *SkipN) const {
330 auto *I = N->getInstruction();
331 for (auto *PrevI = IncludingN ? I : I->getPrevNode(); PrevI != nullptr;
332 PrevI = PrevI->getPrevNode()) {
333 auto *PrevN = getNodeOrNull(PrevI);
334 if (PrevN == nullptr)
335 return nullptr;
336 auto *PrevMemN = dyn_cast<MemDGNode>(PrevN);
337 if (PrevMemN != nullptr && PrevMemN != SkipN)
338 return PrevMemN;
339 }
340 return nullptr;
341}
342
343MemDGNode *DependencyGraph::getMemDGNodeAfter(DGNode *N, bool IncludingN,
344 MemDGNode *SkipN) const {
345 auto *I = N->getInstruction();
346 for (auto *NextI = IncludingN ? I : I->getNextNode(); NextI != nullptr;
347 NextI = NextI->getNextNode()) {
348 auto *NextN = getNodeOrNull(NextI);
349 if (NextN == nullptr)
350 return nullptr;
351 auto *NextMemN = dyn_cast<MemDGNode>(NextN);
352 if (NextMemN != nullptr && NextMemN != SkipN)
353 return NextMemN;
354 }
355 return nullptr;
356}
357
358void DependencyGraph::notifyCreateInstr(Instruction *I) {
359 auto *MemN = dyn_cast<MemDGNode>(getOrCreateNode(I));
360 // TODO: Update the dependencies for the new node.
361
362 // Update the MemDGNode chain if this is a memory node.
363 if (MemN != nullptr) {
364 if (auto *PrevMemN = getMemDGNodeBefore(MemN, /*IncludingN=*/false)) {
365 PrevMemN->NextMemN = MemN;
366 MemN->PrevMemN = PrevMemN;
367 }
368 if (auto *NextMemN = getMemDGNodeAfter(MemN, /*IncludingN=*/false)) {
369 NextMemN->PrevMemN = MemN;
370 MemN->NextMemN = NextMemN;
371 }
372 }
373}
374
375void DependencyGraph::notifyMoveInstr(Instruction *I, const BBIterator &To) {
376 // NOTE: This function runs before `I` moves to its new destination.
377 BasicBlock *BB = To.getNodeParent();
378 assert(!(To != BB->end() && &*To == I->getNextNode()) &&
379 !(To == BB->end() && std::next(I->getIterator()) == BB->end()) &&
380 "Should not have been called if destination is same as origin.");
381
382 // TODO: We can only handle fully internal movements within DAGInterval or at
383 // the borders, i.e., right before the top or right after the bottom.
384 assert(To.getNodeParent() == I->getParent() &&
385 "TODO: We don't support movement across BBs!");
386 assert(
387 (To == std::next(DAGInterval.bottom()->getIterator()) ||
388 (To != BB->end() && std::next(To) == DAGInterval.top()->getIterator()) ||
389 (To != BB->end() && DAGInterval.contains(&*To))) &&
390 "TODO: To should be either within the DAGInterval or right "
391 "before/after it.");
392
393 // Make a copy of the DAGInterval before we update it.
394 auto OrigDAGInterval = DAGInterval;
395
396 // Maintain the DAGInterval.
397 DAGInterval.notifyMoveInstr(I, To);
398
399 // TODO: Perhaps check if this is legal by checking the dependencies?
400
401 // Update the MemDGNode chain to reflect the instr movement if necessary.
403 if (N == nullptr)
404 return;
405 MemDGNode *MemN = dyn_cast<MemDGNode>(N);
406 if (MemN == nullptr)
407 return;
408
409 // First safely detach it from the existing chain.
410 MemN->detachFromChain();
411
412 // Now insert it back into the chain at the new location.
413 //
414 // We won't always have a DGNode to insert before it. If `To` is BB->end() or
415 // if it points to an instr after DAGInterval.bottom() then we will have to
416 // find a node to insert *after*.
417 //
418 // BB: BB:
419 // I1 I1 ^
420 // I2 I2 | DAGInteval [I1 to I3]
421 // I3 I3 V
422 // I4 I4 <- `To` == right after DAGInterval
423 // <- `To` == BB->end()
424 //
425 if (To == BB->end() ||
426 To == std::next(OrigDAGInterval.bottom()->getIterator())) {
427 // If we don't have a node to insert before, find a node to insert after and
428 // update the chain.
429 DGNode *InsertAfterN = getNode(&*std::prev(To));
430 MemN->setPrevNode(
431 getMemDGNodeBefore(InsertAfterN, /*IncludingN=*/true, /*SkipN=*/MemN));
432 } else {
433 // We have a node to insert before, so update the chain.
434 DGNode *BeforeToN = getNode(&*To);
435 MemN->setPrevNode(
436 getMemDGNodeBefore(BeforeToN, /*IncludingN=*/false, /*SkipN=*/MemN));
437 MemN->setNextNode(
438 getMemDGNodeAfter(BeforeToN, /*IncludingN=*/true, /*SkipN=*/MemN));
439 }
440}
441
442void DependencyGraph::notifyEraseInstr(Instruction *I) {
443 // Update the MemDGNode chain if this is a memory node.
444 if (auto *MemN = dyn_cast_or_null<MemDGNode>(getNodeOrNull(I))) {
445 auto *PrevMemN = getMemDGNodeBefore(MemN, /*IncludingN=*/false);
446 auto *NextMemN = getMemDGNodeAfter(MemN, /*IncludingN=*/false);
447 if (PrevMemN != nullptr)
448 PrevMemN->NextMemN = NextMemN;
449 if (NextMemN != nullptr)
450 NextMemN->PrevMemN = PrevMemN;
451 }
452
453 InstrToNodeMap.erase(I);
454
455 // TODO: Update the dependencies.
456}
457
459 if (Instrs.empty())
460 return {};
461
462 Interval<Instruction> InstrsInterval(Instrs);
463 Interval<Instruction> Union = DAGInterval.getUnionInterval(InstrsInterval);
464 auto NewInterval = Union.getSingleDiff(DAGInterval);
465 if (NewInterval.empty())
466 return {};
467
468 createNewNodes(NewInterval);
469
470 // Create the dependencies.
471 //
472 // 1. This is a new DAG, DAGInterval is empty. Fully scan the whole interval.
473 // +---+ - -
474 // | | SrcN | |
475 // | | | | SrcRange |
476 // |New| v | | DstRange
477 // | | DstN - |
478 // | | |
479 // +---+ -
480 // We are scanning for deps with destination in NewInterval and sources in
481 // NewInterval until DstN, for each DstN.
482 auto FullScan = [this](const Interval<Instruction> Intvl) {
483 auto DstRange = MemDGNodeIntervalBuilder::make(Intvl, *this);
484 if (!DstRange.empty()) {
485 for (MemDGNode &DstN : drop_begin(DstRange)) {
486 auto SrcRange = Interval<MemDGNode>(DstRange.top(), DstN.getPrevNode());
487 scanAndAddDeps(DstN, SrcRange);
488 }
489 }
490 };
491 if (DAGInterval.empty()) {
492 assert(NewInterval == InstrsInterval && "Expected empty DAGInterval!");
493 FullScan(NewInterval);
494 }
495 // 2. The new section is below the old section.
496 // +---+ -
497 // | | |
498 // |Old| SrcN |
499 // | | | |
500 // +---+ | | SrcRange
501 // +---+ | | -
502 // | | | | |
503 // |New| v | | DstRange
504 // | | DstN - |
505 // | | |
506 // +---+ -
507 // We are scanning for deps with destination in NewInterval because the deps
508 // in DAGInterval have already been computed. We consider sources in the whole
509 // range including both NewInterval and DAGInterval until DstN, for each DstN.
510 else if (DAGInterval.bottom()->comesBefore(NewInterval.top())) {
511 auto DstRange = MemDGNodeIntervalBuilder::make(NewInterval, *this);
512 auto SrcRangeFull = MemDGNodeIntervalBuilder::make(
513 DAGInterval.getUnionInterval(NewInterval), *this);
514 for (MemDGNode &DstN : DstRange) {
515 auto SrcRange =
516 Interval<MemDGNode>(SrcRangeFull.top(), DstN.getPrevNode());
517 scanAndAddDeps(DstN, SrcRange);
518 }
519 }
520 // 3. The new section is above the old section.
521 else if (NewInterval.bottom()->comesBefore(DAGInterval.top())) {
522 // +---+ - -
523 // | | SrcN | |
524 // |New| | | SrcRange | DstRange
525 // | | v | |
526 // | | DstN - |
527 // | | |
528 // +---+ -
529 // +---+
530 // |Old|
531 // | |
532 // +---+
533 // When scanning for deps with destination in NewInterval we need to fully
534 // scan the interval. This is the same as the scanning for a new DAG.
535 FullScan(NewInterval);
536
537 // +---+ -
538 // | | |
539 // |New| SrcN | SrcRange
540 // | | | |
541 // | | | |
542 // | | | |
543 // +---+ | -
544 // +---+ | -
545 // |Old| v | DstRange
546 // | | DstN |
547 // +---+ -
548 // When scanning for deps with destination in DAGInterval we need to
549 // consider sources from the NewInterval only, because all intra-DAGInterval
550 // dependencies have already been created.
551 auto DstRangeOld = MemDGNodeIntervalBuilder::make(DAGInterval, *this);
552 auto SrcRange = MemDGNodeIntervalBuilder::make(NewInterval, *this);
553 for (MemDGNode &DstN : DstRangeOld)
554 scanAndAddDeps(DstN, SrcRange);
555 } else {
556 llvm_unreachable("We don't expect extending in both directions!");
557 }
558
559 DAGInterval = Union;
560 return NewInterval;
561}
562
563#ifndef NDEBUG
565 // InstrToNodeMap is unordered so we need to create an ordered vector.
567 Nodes.reserve(InstrToNodeMap.size());
568 for (const auto &Pair : InstrToNodeMap)
569 Nodes.push_back(Pair.second.get());
570 // Sort them based on which one comes first in the BB.
571 sort(Nodes, [](DGNode *N1, DGNode *N2) {
572 return N1->getInstruction()->comesBefore(N2->getInstruction());
573 });
574 for (auto *N : Nodes)
575 N->print(OS, /*PrintDeps=*/true);
576}
577
579 print(dbgs());
580 dbgs() << "\n";
581}
582#endif // NDEBUG
583
584} // namespace llvm::sandboxir
#define I(x, y, z)
Definition: MD5.cpp:58
std::pair< uint64_t, uint64_t > Interval
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:163
bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
void reserve(size_type N)
Definition: SmallVector.h:663
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A DependencyGraph Node that points to an Instruction and contains memory dependency edges.
virtual void print(raw_ostream &OS, bool PrintDeps=true) const
static bool isMemDepCandidate(Instruction *I)
We consider I as a Memory Dependency Candidate instruction if it reads/write memory or if it has side...
unsigned UnscheduledSuccs
The number of unscheduled successors.
SchedBundle * SB
The scheduler bundle that this node belongs to.
bool Scheduled
This is true if this node has been scheduled.
static bool isMemDepNodeCandidate(Instruction *I)
\Returns true if I is a memory dependency candidate instruction.
static bool isFenceLike(Instruction *I)
\Returns true if I is fence like. It excludes non-mem intrinsics.
LLVM_DUMP_METHOD void dump() const
Instruction * getInstruction() const
static bool isStackSaveOrRestoreIntrinsic(Instruction *I)
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
DGNode * getOrCreateNode(Instruction *I)
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:42
static MemDGNode * getBotMemDGNode(const Interval< Instruction > &Intvl, const DependencyGraph &DAG)
Scans the instruction chain in Intvl bottom-up, returning the bottom-most MemDGNode,...
static 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 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...
virtual void print(raw_ostream &OS, bool PrintDeps=true) const override
Iterate over both def-use and mem dependencies.
bool operator==(const PredIterator &Other) const
static ModRefInfo aliasAnalysisGetModRefInfo(BatchAAResults &BatchAA, const Instruction *I, const std::optional< MemoryLocation > &OptLoc)
Equivalent to BatchAA::getModRefInfo().
Definition: Utils.h:123
static std::optional< llvm::MemoryLocation > memoryLocationGetOrNone(const Instruction *I)
Equivalent to MemoryLocation::getOrNone(I).
Definition: Utils.h:85
A SandboxIR Value has users. This is the base class.
Definition: Value.h:63
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BasicBlock
Various leaf nodes.
Definition: ISDOpcodes.h:71
static bool isOrdered(Instruction *I)
static User::op_iterator skipNonInstr(User::op_iterator OpIt, User::op_iterator OpItE)
While OpIt points to a Value that is not an Instruction keep incrementing it.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:329
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:420
bool isModSet(const ModRefInfo MRI)
Definition: ModRef.h:48
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1664
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
ModRefInfo
Flags indicating whether a memory access modifies or references memory.
Definition: ModRef.h:27
@ ModRef
The access may reference and may modify the value stored in memory.
@ Other
Any other memory.
DWARFExpression::Operation Op
bool isRefSet(const ModRefInfo MRI)
Definition: ModRef.h:51
#define N