8
8
9
9
#include " llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h"
10
10
#include " llvm/ADT/ArrayRef.h"
11
+ #include " llvm/SandboxIR/Utils.h"
11
12
12
- using namespace llvm ::sandboxir;
13
+ namespace llvm ::sandboxir {
13
14
14
15
#ifndef NDEBUG
15
16
void DGNode::print (raw_ostream &OS, bool PrintDeps) const {
@@ -50,29 +51,135 @@ MemDGNodeIntervalBuilder::make(const Interval<Instruction> &Instrs,
50
51
cast<MemDGNode>(DAG.getNode (MemBotI)));
51
52
}
52
53
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
+
53
155
Interval<Instruction> DependencyGraph::extend (ArrayRef<Instruction *> Instrs) {
54
156
if (Instrs.empty ())
55
157
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.
61
164
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);
66
167
// Build the Mem node chain.
67
168
if (auto *MemN = dyn_cast<MemDGNode>(N)) {
68
169
MemN->setPrevNode (LastMemN);
69
170
if (LastMemN != nullptr )
70
171
LastMemN->setNextNode (MemN);
71
172
LastMemN = MemN;
72
173
}
73
- LastN = N;
74
174
}
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;
76
183
}
77
184
78
185
#ifndef NDEBUG
@@ -95,3 +202,5 @@ void DependencyGraph::dump() const {
95
202
dbgs () << " \n " ;
96
203
}
97
204
#endif // NDEBUG
205
+
206
+ } // namespace llvm::sandboxir
0 commit comments