|
13 | 13 | #ifndef SWIFT_SIL_BASICBLOCKUTILS_H
|
14 | 14 | #define SWIFT_SIL_BASICBLOCKUTILS_H
|
15 | 15 |
|
16 |
| -#include "swift/SIL/SILValue.h" |
17 | 16 | #include "swift/SIL/BasicBlockBits.h"
|
| 17 | +#include "swift/SIL/BasicBlockDatastructures.h" |
| 18 | +#include "swift/SIL/SILValue.h" |
18 | 19 | #include "llvm/ADT/SetVector.h"
|
19 | 20 | #include "llvm/ADT/SmallPtrSet.h"
|
20 | 21 | #include "llvm/ADT/SmallVector.h"
|
@@ -155,6 +156,81 @@ void findJointPostDominatingSet(
|
155 | 156 | bool checkDominates(SILBasicBlock *sourceBlock, SILBasicBlock *destBlock);
|
156 | 157 | #endif
|
157 | 158 |
|
| 159 | +/// Walk depth-first the region backwards reachable from the provided roots |
| 160 | +/// constrained by \p region's \p isInRegion member function. |
| 161 | +/// |
| 162 | +/// interface Region { |
| 163 | +/// /// Whether the indicated basic block is within the region of the graph |
| 164 | +/// /// that should be traversed. |
| 165 | +/// bool isInRegion(SILBasicBlock *) |
| 166 | +/// } |
| 167 | +template <typename Region> |
| 168 | +struct SILCFGBackwardDFS { |
| 169 | + Region ®ion; |
| 170 | + ArrayRef<SILBasicBlock *> roots; |
| 171 | + Optional<SmallVector<SILBasicBlock *, 16>> cachedPostOrder; |
| 172 | + Optional<BasicBlockSet> cachedVisited; |
| 173 | + |
| 174 | + SILCFGBackwardDFS(Region ®ion, ArrayRef<SILBasicBlock *> roots) |
| 175 | + : region(region), roots(roots) {} |
| 176 | + |
| 177 | + /// Visit the blocks of the region in post-order. |
| 178 | + /// |
| 179 | + /// interface Visitor { |
| 180 | + /// /// Visit each block in topological order. |
| 181 | + /// void visit(SILBasicBlock *) |
| 182 | + /// } |
| 183 | + template <typename Visitor> |
| 184 | + void visitPostOrder(Visitor &visitor) { |
| 185 | + if (roots.empty()) |
| 186 | + return; |
| 187 | + auto *function = roots.front()->getParent(); |
| 188 | + cachedVisited.emplace(function); |
| 189 | + for (auto *root : roots) { |
| 190 | + SmallVector<std::pair<SILBasicBlock *, SILBasicBlock::pred_iterator>, 32> |
| 191 | + stack; |
| 192 | + if (!region.isInRegion(root)) |
| 193 | + continue; |
| 194 | + stack.push_back({root, root->pred_begin()}); |
| 195 | + while (!stack.empty()) { |
| 196 | + while (stack.back().second != stack.back().first->pred_end()) { |
| 197 | + auto predecessor = *stack.back().second; |
| 198 | + stack.back().second++; |
| 199 | + if (!region.isInRegion(predecessor)) |
| 200 | + continue; |
| 201 | + if (cachedVisited->insert(predecessor)) |
| 202 | + stack.push_back({predecessor, predecessor->pred_begin()}); |
| 203 | + } |
| 204 | + visitor.visit(stack.back().first); |
| 205 | + stack.pop_back(); |
| 206 | + } |
| 207 | + } |
| 208 | + } |
| 209 | + |
| 210 | + /// Visit the region in post-order and cache the visited blocks. |
| 211 | + void cachePostOrder() { |
| 212 | + if (cachedPostOrder) |
| 213 | + return; |
| 214 | + struct Visitor { |
| 215 | + SILCFGBackwardDFS<Region> &dfs; |
| 216 | + void visit(SILBasicBlock *block) { |
| 217 | + dfs.cachedPostOrder->push_back(block); |
| 218 | + } |
| 219 | + }; |
| 220 | + cachedPostOrder.emplace(); |
| 221 | + Visitor visitor{*this}; |
| 222 | + visitPostOrder(visitor); |
| 223 | + } |
| 224 | + |
| 225 | + /// The region in post-order. |
| 226 | + ArrayRef<SILBasicBlock *> postOrder() { |
| 227 | + cachePostOrder(); |
| 228 | + return *cachedPostOrder; |
| 229 | + }; |
| 230 | + |
| 231 | + /// The region in reverse post-order. |
| 232 | + auto reversePostOrder() { return llvm::reverse(postOrder()); } |
| 233 | +}; |
158 | 234 | } // namespace swift
|
159 | 235 |
|
160 | 236 | #endif
|
0 commit comments