88
99#include " llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h"
1010#include " llvm/ADT/ArrayRef.h"
11+ #include " llvm/SandboxIR/Utils.h"
1112
12- using namespace llvm ::sandboxir;
13+ namespace llvm ::sandboxir {
1314
1415#ifndef NDEBUG
1516void DGNode::print (raw_ostream &OS, bool PrintDeps) const {
@@ -50,29 +51,135 @@ MemDGNodeIntervalBuilder::make(const Interval<Instruction> &Instrs,
5051 cast<MemDGNode>(DAG.getNode (MemBotI)));
5152}
5253
54+ DependencyGraph::DependencyType
55+ DependencyGraph::getRoughDepType (Instruction *FromI, Instruction *ToI) {
56+ // TODO: Perhaps compile-time improvement by skipping if neither is mem?
57+ if (FromI->mayWriteToMemory ()) {
58+ if (ToI->mayReadFromMemory ())
59+ return DependencyType::RAW;
60+ if (ToI->mayWriteToMemory ())
61+ return DependencyType::WAW;
62+ } else if (FromI->mayReadFromMemory ()) {
63+ if (ToI->mayWriteToMemory ())
64+ return DependencyType::WAR;
65+ if (ToI->mayReadFromMemory ())
66+ return DependencyType::RAR;
67+ }
68+ if (isa<sandboxir::PHINode>(FromI) || isa<sandboxir::PHINode>(ToI))
69+ return DependencyType::CTRL;
70+ if (ToI->isTerminator ())
71+ return DependencyType::CTRL;
72+ if (DGNode::isStackSaveOrRestoreIntrinsic (FromI) ||
73+ DGNode::isStackSaveOrRestoreIntrinsic (ToI))
74+ return DependencyType::OTHER;
75+ return DependencyType::NONE;
76+ }
77+
78+ static bool isOrdered (Instruction *I) {
79+ auto IsOrdered = [](Instruction *I) {
80+ if (auto *LI = dyn_cast<LoadInst>(I))
81+ return !LI->isUnordered ();
82+ if (auto *SI = dyn_cast<StoreInst>(I))
83+ return !SI->isUnordered ();
84+ if (DGNode::isFenceLike (I))
85+ return true ;
86+ return false ;
87+ };
88+ bool Is = IsOrdered (I);
89+ assert ((!Is || DGNode::isMemDepCandidate (I)) &&
90+ " An ordered instruction must be a MemDepCandidate!" );
91+ return Is;
92+ }
93+
94+ bool DependencyGraph::alias (Instruction *SrcI, Instruction *DstI,
95+ DependencyType DepType) {
96+ std::optional<MemoryLocation> DstLocOpt =
97+ Utils::memoryLocationGetOrNone (DstI);
98+ if (!DstLocOpt)
99+ return true ;
100+ // Check aliasing.
101+ assert ((SrcI->mayReadFromMemory () || SrcI->mayWriteToMemory ()) &&
102+ " Expected a mem instr" );
103+ // TODO: Check AABudget
104+ ModRefInfo SrcModRef =
105+ isOrdered (SrcI)
106+ ? ModRefInfo::Mod
107+ : Utils::aliasAnalysisGetModRefInfo (*BatchAA, SrcI, *DstLocOpt);
108+ switch (DepType) {
109+ case DependencyType::RAW:
110+ case DependencyType::WAW:
111+ return isModSet (SrcModRef);
112+ case DependencyType::WAR:
113+ return isRefSet (SrcModRef);
114+ default :
115+ llvm_unreachable (" Expected only RAW, WAW and WAR!" );
116+ }
117+ }
118+
119+ bool DependencyGraph::hasDep (Instruction *SrcI, Instruction *DstI) {
120+ DependencyType RoughDepType = getRoughDepType (SrcI, DstI);
121+ switch (RoughDepType) {
122+ case DependencyType::RAR:
123+ return false ;
124+ case DependencyType::RAW:
125+ case DependencyType::WAW:
126+ case DependencyType::WAR:
127+ return alias (SrcI, DstI, RoughDepType);
128+ case DependencyType::CTRL:
129+ // Adding actual dep edges from PHIs/to terminator would just create too
130+ // many edges, which would be bad for compile-time.
131+ // So we ignore them in the DAG formation but handle them in the
132+ // scheduler, while sorting the ready list.
133+ return false ;
134+ case DependencyType::OTHER:
135+ return true ;
136+ case DependencyType::NONE:
137+ return false ;
138+ }
139+ }
140+
141+ void DependencyGraph::scanAndAddDeps (DGNode &DstN,
142+ const Interval<MemDGNode> &SrcScanRange) {
143+ assert (isa<MemDGNode>(DstN) &&
144+ " DstN is the mem dep destination, so it must be mem" );
145+ Instruction *DstI = DstN.getInstruction ();
146+ // Walk up the instruction chain from ScanRange bottom to top, looking for
147+ // memory instrs that may alias.
148+ for (MemDGNode &SrcN : reverse (SrcScanRange)) {
149+ Instruction *SrcI = SrcN.getInstruction ();
150+ if (hasDep (SrcI, DstI))
151+ DstN.addMemPred (&SrcN);
152+ }
153+ }
154+
53155Interval<Instruction> DependencyGraph::extend (ArrayRef<Instruction *> Instrs) {
54156 if (Instrs.empty ())
55157 return {};
56- // TODO: For now create a chain of dependencies.
57- Interval<Instruction> Interval (Instrs);
58- auto *TopI = Interval.top ();
59- auto *BotI = Interval.bottom ();
60- DGNode *LastN = getOrCreateNode (TopI);
158+
159+ Interval<Instruction> InstrInterval (Instrs);
160+
161+ DGNode *LastN = getOrCreateNode (InstrInterval.top ());
162+ // Create DGNodes for all instrs in Interval to avoid future Instruction to
163+ // DGNode lookups.
61164 MemDGNode *LastMemN = dyn_cast<MemDGNode>(LastN);
62- for (Instruction *I = TopI->getNextNode (), *E = BotI->getNextNode (); I != E;
63- I = I->getNextNode ()) {
64- auto *N = getOrCreateNode (I);
65- N->addMemPred (LastMemN);
165+ for (Instruction &I : drop_begin (InstrInterval)) {
166+ auto *N = getOrCreateNode (&I);
66167 // Build the Mem node chain.
67168 if (auto *MemN = dyn_cast<MemDGNode>(N)) {
68169 MemN->setPrevNode (LastMemN);
69170 if (LastMemN != nullptr )
70171 LastMemN->setNextNode (MemN);
71172 LastMemN = MemN;
72173 }
73- LastN = N;
74174 }
75- return Interval;
175+ // Create the dependencies.
176+ auto DstRange = MemDGNodeIntervalBuilder::make (InstrInterval, *this );
177+ for (MemDGNode &DstN : drop_begin (DstRange)) {
178+ auto SrcRange = Interval<MemDGNode>(DstRange.top (), DstN.getPrevNode ());
179+ scanAndAddDeps (DstN, SrcRange);
180+ }
181+
182+ return InstrInterval;
76183}
77184
78185#ifndef NDEBUG
@@ -95,3 +202,5 @@ void DependencyGraph::dump() const {
95202 dbgs () << " \n " ;
96203}
97204#endif // NDEBUG
205+
206+ } // namespace llvm::sandboxir
0 commit comments