|
19 | 19 |
|
20 | 20 | #include "swift/SIL/StackList.h"
|
21 | 21 | #include "swift/SIL/BasicBlockBits.h"
|
| 22 | +#include <deque> |
22 | 23 |
|
23 | 24 | namespace swift {
|
24 | 25 |
|
@@ -61,10 +62,12 @@ class BasicBlockSetVector {
|
61 | 62 | }
|
62 | 63 | };
|
63 | 64 |
|
64 |
| -/// A utility for processing basic blocks in a worklist. |
| 65 | +/// A utility for processing basic blocks in a worklist that uses |
| 66 | +/// last-in-first-out order. |
65 | 67 | ///
|
66 |
| -/// It is basically a combination of a block vector and a block set. It can be |
67 |
| -/// used for typical worklist-processing algorithms. |
| 68 | +/// It is basically a combination of a stack list and a block set. It can be |
| 69 | +/// used for typical worklist-processing algorithms and is recommended in |
| 70 | +/// nearly all situations as its implementation is well-optimized. |
68 | 71 | class BasicBlockWorklist {
|
69 | 72 | StackList<SILBasicBlock *> worklist;
|
70 | 73 | BasicBlockSet visited;
|
@@ -119,6 +122,70 @@ class BasicBlockWorklist {
|
119 | 122 | bool isVisited(SILBasicBlock *block) const { return visited.contains(block); }
|
120 | 123 | };
|
121 | 124 |
|
| 125 | + |
| 126 | +/// A utility for processing basic blocks in a work-queue that uses |
| 127 | +/// first-in-first-out order. |
| 128 | +/// |
| 129 | +/// It is basically a combination of a std::deque and a block set. It can be |
| 130 | +/// used for certain kinds of worklist-processing algorithms. |
| 131 | +/// |
| 132 | +/// When in doubt, you should reach for a BasicBlockWorklist instead. |
| 133 | +class BasicBlockWorkqueue { |
| 134 | + std::deque<SILBasicBlock*> workqueue; |
| 135 | + BasicBlockSet visited; |
| 136 | + |
| 137 | +public: |
| 138 | + /// Construct an empty workqueue. |
| 139 | + BasicBlockWorkqueue(SILFunction *function) |
| 140 | + : workqueue(), visited(function) {} |
| 141 | + |
| 142 | + /// Initialize the workqueue with \p initialBlock. |
| 143 | + BasicBlockWorkqueue(SILBasicBlock *initialBlock) |
| 144 | + : BasicBlockWorkqueue(initialBlock->getParent()) { |
| 145 | + push(initialBlock); |
| 146 | + } |
| 147 | + |
| 148 | + /// Pops the next element from the front of the workqueue or returns null, |
| 149 | + /// if the workqueue is empty. |
| 150 | + SILBasicBlock *pop() { |
| 151 | + if (workqueue.empty()) |
| 152 | + return nullptr; |
| 153 | + SILBasicBlock *block = workqueue.front(); |
| 154 | + workqueue.pop_front(); |
| 155 | + return block; |
| 156 | + } |
| 157 | + |
| 158 | + /// Pushes \p block onto the end of the workqueue if \p block has never been |
| 159 | + /// pushed before. |
| 160 | + bool pushIfNotVisited(SILBasicBlock *block) { |
| 161 | + if (visited.insert(block)) { |
| 162 | + workqueue.push_back(block); |
| 163 | + return true; |
| 164 | + } |
| 165 | + return false; |
| 166 | + } |
| 167 | + |
| 168 | + /// Like `pushIfNotVisited`, but requires that \p block has never been on the |
| 169 | + /// workqueue before. |
| 170 | + void push(SILBasicBlock *block) { |
| 171 | + assert(!visited.contains(block)); |
| 172 | + visited.insert(block); |
| 173 | + workqueue.push_back(block); |
| 174 | + } |
| 175 | + |
| 176 | + /// Like `pop`, but marks the returned block as "unvisited". This means, that |
| 177 | + /// the block can be pushed onto the queue again. |
| 178 | + SILBasicBlock *popAndForget() { |
| 179 | + SILBasicBlock *block = pop(); |
| 180 | + if (block) |
| 181 | + visited.erase(block); |
| 182 | + return block; |
| 183 | + } |
| 184 | + |
| 185 | + /// Returns true if \p block was visited, i.e. has been added to the workqueue |
| 186 | + bool isVisited(SILBasicBlock *block) const { return visited.contains(block); } |
| 187 | +}; |
| 188 | + |
122 | 189 | } // namespace swift
|
123 | 190 |
|
124 | 191 | #endif
|
0 commit comments