30 const DependencyGraph &DAG) {
31 auto Skip = [&DAG](
auto OpIt) {
33 return I ==
nullptr || DAG.getNode(
I) ==
nullptr;
35 while (OpIt != OpItE && Skip(OpIt))
43 assert(OpIt != OpItE &&
"Can't dereference end iterator!");
52 "Cant' dereference end iterator!");
59 assert(OpIt != OpItE &&
"Already at end!");
62 OpIt = PredIterator::skipBadIt(OpIt, OpItE, *DAG);
70 OpIt = PredIterator::skipBadIt(OpIt, OpItE, *DAG);
80 assert(DAG ==
Other.DAG &&
"Iterators of different DAGs!");
81 assert(N ==
Other.N &&
"Iterators of different nodes!");
82 return OpIt ==
Other.OpIt && MemIt ==
Other.MemIt;
90 return I ==
nullptr || DAG.
getNode(
I) ==
nullptr;
92 while (UserIt != UserItE && Skip(UserIt))
100 assert(UserIt != UserItE &&
"Can't dereference end iterator!");
105 if (UserIt != UserItE)
109 "Cant' dereference end iterator!");
116 assert(UserIt != UserItE &&
"Already at end!");
119 UserIt = SuccIterator::skipOutOfScope(UserIt, UserItE, *DAG);
124 if (UserIt != UserItE) {
127 UserIt = SuccIterator::skipOutOfScope(UserIt, UserItE, *DAG);
137 assert(DAG ==
Other.DAG &&
"Iterators of different DAGs!");
138 assert(N ==
Other.N &&
"Iterators of different nodes!");
139 return UserIt ==
Other.UserIt && MemIt ==
Other.MemIt;
143 if (this->SB !=
nullptr)
144 this->SB->eraseFromBundle(
this);
151 SB->eraseFromBundle(
this);
156 OS << *
I <<
" Unsched:";
168 static constexpr unsigned Indent = 4;
169 for (
auto *
Pred : MemPreds)
170 OS.
indent(Indent) <<
"<-" << *
Pred->getInstruction() <<
"\n";
182 I =
I->getNextNode();
195 I =
I->getPrevNode();
208 if (TopMemN ==
nullptr)
211 assert(BotMemN !=
nullptr &&
"TopMemN should be null too!");
216DependencyGraph::DependencyType
221 return DependencyType::ReadAfterWrite;
223 return DependencyType::WriteAfterWrite;
226 return DependencyType::WriteAfterRead;
229 return DependencyType::Control;
231 return DependencyType::Control;
234 return DependencyType::Other;
235 return DependencyType::None;
241 return !LI->isUnordered();
243 return !
SI->isUnordered();
248 bool Is = IsOrdered(
I);
250 "An ordered instruction must be a MemDepCandidate!");
255 DependencyType DepType) {
256 std::optional<MemoryLocation> DstLocOpt =
262 "Expected a mem instr");
269 case DependencyType::ReadAfterWrite:
270 case DependencyType::WriteAfterWrite:
272 case DependencyType::WriteAfterRead:
280 DependencyType RoughDepType = getRoughDepType(SrcI, DstI);
281 switch (RoughDepType) {
282 case DependencyType::ReadAfterWrite:
283 case DependencyType::WriteAfterWrite:
284 case DependencyType::WriteAfterRead:
285 return alias(SrcI, DstI, RoughDepType);
286 case DependencyType::Control:
292 case DependencyType::Other:
294 case DependencyType::None:
300void DependencyGraph::scanAndAddDeps(
MemDGNode &DstN,
303 "DstN is the mem dep destination, so it must be mem");
309 if (hasDep(SrcI, DstI))
310 DstN.addMemPred(&SrcN, Dir);
314void DependencyGraph::setDefUseUnscheduledSuccs(
324 unsigned CntUnschedPreds = 0;
330 if (OpI->getParent() !=
I.getParent())
332 if (!NewInterval.contains(OpI))
338 OpN->incrUnscheduledDeps();
339 if (!OpN->scheduled())
347 bool NewIsAbove = DAGInterval.empty() || NewInterval.comesBefore(DAGInterval);
348 const auto &TopInterval = NewIsAbove ? NewInterval : DAGInterval;
349 const auto &BotInterval = NewIsAbove ? DAGInterval : NewInterval;
363 if (BotN->scheduled())
365 unsigned CntUnscheduledPreds = 0;
366 for (
Value *
Op : BotI.operands()) {
373 if (!TopInterval.contains(OpI))
375 if (!OpN->scheduled()) {
377 OpN->incrUnscheduledDeps();
378 ++CntUnscheduledPreds;
382 *BotN->UnscheduledDeps += CntUnscheduledPreds;
394 MemN->setPrevNode(LastMemN);
399 if (!DAGInterval.empty()) {
400 bool NewIsAbove = NewInterval.comesBefore(DAGInterval);
401 const auto &TopInterval = NewIsAbove ? NewInterval : DAGInterval;
402 const auto &BotInterval = NewIsAbove ? DAGInterval : NewInterval;
407 assert((LinkTopN ==
nullptr || LinkBotN ==
nullptr ||
408 LinkTopN->comesBefore(LinkBotN)) &&
410 if (LinkTopN !=
nullptr && LinkBotN !=
nullptr) {
411 LinkTopN->setNextNode(LinkBotN);
416 auto UnionIntvl = DAGInterval.getUnionInterval(NewInterval);
421 if (ChainTopN !=
nullptr && ChainBotN !=
nullptr) {
422 for (
auto *
N = ChainTopN->getNextNode(), *LastN = ChainTopN;
N !=
nullptr;
423 LastN =
N,
N =
N->getNextNode()) {
424 assert(
N == LastN->getNextNode() &&
"Bad chain!");
425 assert(
N->getPrevNode() == LastN &&
"Bad chain!");
431 setDefUseUnscheduledSuccs(NewInterval);
437 for (
auto *PrevI = IncludingN ?
I :
I->getPrevNode(); PrevI !=
nullptr;
438 PrevI = PrevI->getPrevNode()) {
440 if (PrevN ==
nullptr)
443 if (PrevMemN !=
nullptr && PrevMemN != SkipN)
452 for (
auto *NextI = IncludingN ?
I :
I->getNextNode(); NextI !=
nullptr;
453 NextI = NextI->getNextNode()) {
455 if (NextN ==
nullptr)
458 if (NextMemN !=
nullptr && NextMemN != SkipN)
464void DependencyGraph::notifyCreateInstr(
Instruction *
I) {
469 if (!(DAGInterval.contains(
I) || DAGInterval.touches(
I)))
472 DAGInterval = DAGInterval.getUnionInterval({
I,
I});
477 Sched->notifyCreateInstrBeforeDAGUpdates(
N);
480 if (
MemN !=
nullptr) {
481 if (
auto *PrevMemN = getMemDGNodeBefore(
MemN,
false)) {
482 PrevMemN->NextMemN =
MemN;
483 MemN->PrevMemN = PrevMemN;
485 if (
auto *NextMemN = getMemDGNodeAfter(
MemN,
false)) {
486 NextMemN->PrevMemN =
MemN;
487 MemN->NextMemN = NextMemN;
492 if (DAGInterval.top()->comesBefore(
I)) {
495 scanAndAddDeps(*
MemN, SrcInterval);
498 if (
I->comesBefore(DAGInterval.bottom())) {
506 if (Sched !=
nullptr) {
507 Sched->notifyCreateInstrAfterDAGUpdates(
N);
511void DependencyGraph::notifyMoveInstr(
Instruction *
I,
const BBIterator &To) {
517 assert(!(To != BB->end() && &*To ==
I->getNextNode()) &&
518 !(To == BB->end() && std::next(
I->getIterator()) == BB->end()) &&
519 "Should not have been called if destination is same as origin.");
523 assert(To.getNodeParent() ==
I->getParent() &&
524 "TODO: We don't support movement across BBs!");
526 (To == std::next(DAGInterval.bottom()->getIterator()) ||
527 (To != BB->end() && std::next(To) == DAGInterval.top()->getIterator()) ||
528 (To != BB->end() && DAGInterval.contains(&*To))) &&
529 "TODO: To should be either within the DAGInterval or right "
533 auto OrigDAGInterval = DAGInterval;
536 DAGInterval.notifyMoveInstr(
I, To);
549 MemN->detachFromChain();
564 if (To == BB->end() ||
565 To == std::next(OrigDAGInterval.bottom()->getIterator())) {
570 getMemDGNodeBefore(InsertAfterN,
true,
MemN));
575 getMemDGNodeBefore(BeforeToN,
false,
MemN));
577 getMemDGNodeAfter(BeforeToN,
true,
MemN));
591 auto *PrevMemN = getMemDGNodeBefore(
MemN,
false);
592 auto *NextMemN = getMemDGNodeAfter(
MemN,
false);
593 if (PrevMemN !=
nullptr)
594 PrevMemN->NextMemN = NextMemN;
595 if (NextMemN !=
nullptr)
596 NextMemN->PrevMemN = PrevMemN;
599 while (!
MemN->memPreds().empty()) {
600 auto *PredN = *
MemN->memPreds().begin();
601 MemN->removeMemPred(PredN, Dir);
603 while (!
MemN->memSuccs().empty()) {
604 auto *SuccN = *
MemN->memSuccs().begin();
605 SuccN->removeMemPred(
MemN, Dir);
610 if (Sched !=
nullptr)
611 Sched->notifyEraseInstr(
I);
614 InstrToNodeMap.erase(
I);
617void DependencyGraph::notifySetUse(
const Use &U,
Value *NewSrc) {
628 if (UserI ==
nullptr)
631 if (UserN ==
nullptr)
635 if (UserN->scheduled())
640 if (
auto *CurrSrcN =
getNode(CurrSrcI)) {
642 if (!CurrSrcN->scheduled()) {
644 CurrSrcN->decrUnscheduledDeps();
646 UserN->decrUnscheduledDeps();
651 if (
auto *NewSrcN =
getNode(NewSrcI)) {
653 if (!NewSrcN->scheduled()) {
655 NewSrcN->incrUnscheduledDeps();
657 UserN->incrUnscheduledDeps();
669 auto NewInterval = Union.getSingleDiff(DAGInterval);
670 if (NewInterval.empty())
673 createNewNodes(NewInterval);
689 if (!DstRange.empty()) {
692 scanAndAddDeps(DstN, SrcRange);
697 if (MemDAGInterval.empty()) {
698 FullScan(NewInterval);
715 else if (DAGInterval.bottom()->comesBefore(NewInterval.top())) {
717 auto SrcRangeFull = MemDAGInterval.getUnionInterval(DstRange);
721 scanAndAddDeps(DstN, SrcRange);
725 else if (NewInterval.bottom()->comesBefore(DAGInterval.top())) {
739 FullScan(NewInterval);
755 auto DstRangeOld = MemDAGInterval;
758 scanAndAddDeps(DstN, SrcRange);
771 Nodes.
reserve(InstrToNodeMap.size());
772 for (
const auto &Pair : InstrToNodeMap)
778 for (
auto *
N : Nodes)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
bool empty() const
Check if the array is empty.
LLVM_ABI bool mayWriteToMemory() const LLVM_READONLY
Return true if this instruction may modify memory.
LLVM_ABI bool mayReadFromMemory() const LLVM_READONLY
Return true if this instruction may read memory.
void reserve(size_type N)
void push_back(const T &Elt)
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...
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
An ArrayRef of Values or Instructions that we can print/dump for debugging.
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...
std::optional< unsigned > UnscheduledDeps
The number of unscheduled successors (predecessors) depending on the scheduling direction.
void setSchedBundle(SchedBundle &SB)
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
LLVM_ABI Interval< Instruction > extend(BndlRef< Instruction * > Instrs)
Build/extend the dependency graph such that it includes Instrs.
DGNode * getNodeOrNull(Instruction *I) const
Like getNode() but returns nullptr if I is nullptr.
void print(raw_ostream &OS) const
DGNode * getOrCreateNode(Instruction *I)
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
bool mayWriteToMemory() const
bool mayReadFromMemory() const
bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
bool isTerminator() const
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 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...
void print(raw_ostream &OS, bool PrintDeps=true) const override
LLVM_ABI value_type operator*()
LLVM_ABI PredIterator & operator++()
LLVM_ABI bool operator==(const PredIterator &Other) const
LLVM_ABI value_type operator*()
LLVM_ABI bool operator==(const SuccIterator &Other) const
LLVM_ABI SuccIterator & operator++()
Represents a Def-use/Use-def edge in SandboxIR.
static ModRefInfo aliasAnalysisGetModRefInfo(BatchAAResults &BatchAA, const Instruction *I, const std::optional< MemoryLocation > &OptLoc)
Equivalent to BatchAA::getModRefInfo().
static std::optional< llvm::MemoryLocation > memoryLocationGetOrNone(const Instruction *I)
Equivalent to MemoryLocation::getOrNone(I).
A SandboxIR Value has users. This is the base class.
mapped_iterator< sandboxir::UserUseIterator, UseToUser > user_iterator
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static bool isOrdered(Instruction *I)
StringLiteral schedDirectionToStr(SchedDirection Dir)
template class LLVM_TEMPLATE_ABI Interval< MemDGNode >
BasicBlock(llvm::BasicBlock *BB, Context &SBCtx)
template class LLVM_TEMPLATE_ABI Interval< Instruction >
friend class Instruction
Iterator for Instructions in a `BasicBlock.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto dyn_cast_or_null(const Y &Val)
auto reverse(ContainerTy &&C)
bool isModSet(const ModRefInfo MRI)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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...
ModRefInfo
Flags indicating whether a memory access modifies or references memory.
@ ModRef
The access may reference and may modify the value stored in memory.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool isRefSet(const ModRefInfo MRI)