29
29
#include " llvm/Transforms/Utils/LowerMemIntrinsics.h"
30
30
#include < queue>
31
31
#include < stack>
32
+ #include < unordered_set>
32
33
33
34
using namespace llvm ;
34
35
using namespace SPIRV ;
@@ -42,184 +43,6 @@ namespace {
42
43
using BlockSet = std::unordered_set<BasicBlock *>;
43
44
using Edge = std::pair<BasicBlock *, BasicBlock *>;
44
45
45
- // This class implements a partial ordering visitor, which visits a cyclic graph
46
- // in natural topological-like ordering. Topological ordering is not defined for
47
- // directed graphs with cycles, so this assumes cycles are a single node, and
48
- // ignores back-edges. The cycle is visited from the entry in the same
49
- // topological-like ordering.
50
- //
51
- // This means once we visit a node, we know all the possible ancestors have been
52
- // visited.
53
- //
54
- // clang-format off
55
- //
56
- // Given this graph:
57
- //
58
- // ,-> B -\
59
- // A -+ +---> D ----> E -> F -> G -> H
60
- // `-> C -/ ^ |
61
- // +-----------------+
62
- //
63
- // Visit order is:
64
- // A, [B, C in any order], D, E, F, G, H
65
- //
66
- // clang-format on
67
- //
68
- // Changing the function CFG between the construction of the visitor and
69
- // visiting is undefined. The visitor can be reused, but if the CFG is updated,
70
- // the visitor must be rebuilt.
71
- class PartialOrderingVisitor {
72
- DomTreeBuilder::BBDomTree DT;
73
- LoopInfo LI;
74
- BlockSet Visited = {};
75
-
76
- struct OrderInfo {
77
- size_t Rank;
78
- size_t TraversalIndex;
79
- };
80
-
81
- using BlockToOrderInfoMap = std::unordered_map<BasicBlock *, OrderInfo>;
82
- BlockToOrderInfoMap BlockToOrder;
83
-
84
- // std::unordered_map<BasicBlock *, std::pair<size_t, size_t>> B2R = {};
85
- std::vector<BasicBlock *> Order = {};
86
-
87
- // Get all basic-blocks reachable from Start.
88
- BlockSet getReachableFrom (BasicBlock *Start) {
89
- std::queue<BasicBlock *> ToVisit;
90
- ToVisit.push (Start);
91
-
92
- BlockSet Output;
93
- while (ToVisit.size () != 0 ) {
94
- BasicBlock *BB = ToVisit.front ();
95
- ToVisit.pop ();
96
-
97
- if (Output.count (BB) != 0 )
98
- continue ;
99
- Output.insert (BB);
100
-
101
- for (BasicBlock *Successor : successors (BB)) {
102
- if (DT.dominates (Successor, BB))
103
- continue ;
104
- ToVisit.push (Successor);
105
- }
106
- }
107
-
108
- return Output;
109
- }
110
-
111
- size_t visit (BasicBlock *BB, size_t Rank) {
112
- if (Visited.count (BB) != 0 )
113
- return Rank;
114
-
115
- Loop *L = LI.getLoopFor (BB);
116
- const bool isLoopHeader = LI.isLoopHeader (BB);
117
-
118
- if (BlockToOrder.count (BB) == 0 ) {
119
- OrderInfo Info = {Rank, Visited.size ()};
120
- BlockToOrder.emplace (BB, Info);
121
- } else {
122
- BlockToOrder[BB].Rank = std::max (BlockToOrder[BB].Rank , Rank);
123
- }
124
-
125
- for (BasicBlock *Predecessor : predecessors (BB)) {
126
- if (isLoopHeader && L->contains (Predecessor)) {
127
- continue ;
128
- }
129
-
130
- if (BlockToOrder.count (Predecessor) == 0 ) {
131
- return Rank;
132
- }
133
- }
134
-
135
- Visited.insert (BB);
136
-
137
- SmallVector<BasicBlock *, 2 > OtherSuccessors;
138
- SmallVector<BasicBlock *, 2 > LoopSuccessors;
139
-
140
- for (BasicBlock *Successor : successors (BB)) {
141
- // Ignoring back-edges.
142
- if (DT.dominates (Successor, BB))
143
- continue ;
144
-
145
- if (isLoopHeader && L->contains (Successor)) {
146
- LoopSuccessors.push_back (Successor);
147
- } else
148
- OtherSuccessors.push_back (Successor);
149
- }
150
-
151
- for (BasicBlock *BB : LoopSuccessors)
152
- Rank = std::max (Rank, visit (BB, Rank + 1 ));
153
-
154
- size_t OutputRank = Rank;
155
- for (BasicBlock *Item : OtherSuccessors)
156
- OutputRank = std::max (OutputRank, visit (Item, Rank + 1 ));
157
- return OutputRank;
158
- };
159
-
160
- public:
161
- // Build the visitor to operate on the function F.
162
- PartialOrderingVisitor (Function &F) {
163
- DT.recalculate (F);
164
- LI = LoopInfo (DT);
165
-
166
- visit (&*F.begin (), 0 );
167
-
168
- Order.reserve (F.size ());
169
- for (auto &[BB, Info] : BlockToOrder)
170
- Order.emplace_back (BB);
171
-
172
- std::sort (
173
- Order.begin (), Order.end (),
174
- [&](const auto &LHS, const auto &RHS) { return compare (LHS, RHS); });
175
- }
176
-
177
- bool compare (const BasicBlock *LHS, const BasicBlock *RHS) const {
178
- const OrderInfo &InfoLHS = BlockToOrder.at (const_cast <BasicBlock *>(LHS));
179
- const OrderInfo &InfoRHS = BlockToOrder.at (const_cast <BasicBlock *>(RHS));
180
- if (InfoLHS.Rank != InfoRHS.Rank )
181
- return InfoLHS.Rank < InfoRHS.Rank ;
182
- return InfoLHS.TraversalIndex < InfoRHS.TraversalIndex ;
183
- }
184
-
185
- // Visit the function starting from the basic block |Start|, and calling |Op|
186
- // on each visited BB. This traversal ignores back-edges, meaning this won't
187
- // visit a node to which |Start| is not an ancestor.
188
- // If Op returns |true|, the visitor continues. If |Op| returns false, the
189
- // visitor will stop at that rank. This means if 2 nodes share the same rank,
190
- // and Op returns false when visiting the first, the second will be visited
191
- // afterwards. But none of their successors will.
192
- void partialOrderVisit (BasicBlock &Start,
193
- std::function<bool (BasicBlock *)> Op) {
194
- BlockSet Reachable = getReachableFrom (&Start);
195
- assert (BlockToOrder.count (&Start) != 0 );
196
-
197
- // Skipping blocks with a rank inferior to |Start|'s rank.
198
- auto It = Order.begin ();
199
- while (It != Order.end () && *It != &Start)
200
- ++It;
201
-
202
- // This is unexpected. Worst case |Start| is the last block,
203
- // so It should point to the last block, not past-end.
204
- assert (It != Order.end ());
205
-
206
- // By default, there is no rank limit. Setting it to the maximum value.
207
- std::optional<size_t > EndRank = std::nullopt;
208
- for (; It != Order.end (); ++It) {
209
- if (EndRank.has_value () && BlockToOrder[*It].Rank > *EndRank)
210
- break ;
211
-
212
- if (Reachable.count (*It) == 0 ) {
213
- continue ;
214
- }
215
-
216
- if (!Op (*It)) {
217
- EndRank = BlockToOrder[*It].Rank ;
218
- }
219
- }
220
- }
221
- };
222
-
223
46
// Helper function to do a partial order visit from the block |Start|, calling
224
47
// |Op| on each visited node.
225
48
void partialOrderVisit (BasicBlock &Start,
@@ -1318,44 +1141,6 @@ class SPIRVStructurizer : public FunctionPass {
1318
1141
return Modified;
1319
1142
}
1320
1143
1321
- // Sort blocks in a partial ordering, so each block is after all its
1322
- // dominators. This should match both the SPIR-V and the MIR requirements.
1323
- bool sortBlocks (Function &F) {
1324
- if (F.size () == 0 )
1325
- return false ;
1326
-
1327
- bool Modified = false ;
1328
-
1329
- std::vector<BasicBlock *> Order;
1330
- Order.reserve (F.size ());
1331
-
1332
- PartialOrderingVisitor Visitor (F);
1333
- Visitor.partialOrderVisit (*F.begin (), [&Order](BasicBlock *Block) {
1334
- Order.push_back (Block);
1335
- return true ;
1336
- });
1337
-
1338
- assert (&*F.begin () == Order[0 ]);
1339
- BasicBlock *LastBlock = &*F.begin ();
1340
- for (BasicBlock *BB : Order) {
1341
- if (BB != LastBlock && &*LastBlock->getNextNode () != BB) {
1342
- Modified = true ;
1343
- BB->moveAfter (LastBlock);
1344
- }
1345
- LastBlock = BB;
1346
- }
1347
- #if 0
1348
- for (auto It = Order.begin() + 1; It != Order.end(); ++It) {
1349
- if (*It != &*LastBlock->getNextNode()) {
1350
- Modified = true;
1351
- (*It)->moveAfter(LastBlock);
1352
- }
1353
- LastBlock = *It;
1354
- }
1355
- #endif
1356
- return Modified;
1357
- }
1358
-
1359
1144
public:
1360
1145
static char ID;
1361
1146
0 commit comments