Skip to content

Commit da914d4

Browse files
committed
[SIL] Added SILCFGBackwardDFS.
The utility provides a standard way for backwards traversing a region of a function constrained by a predicate (isInRegion) starting from some root blocks. It exposes a visit function for post-order and iterable collections for post-order and reverse post-order. Adding corresponding pre-order functionality will be straightforward.
1 parent fa21114 commit da914d4

File tree

1 file changed

+77
-1
lines changed

1 file changed

+77
-1
lines changed

include/swift/SIL/BasicBlockUtils.h

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
#ifndef SWIFT_SIL_BASICBLOCKUTILS_H
1414
#define SWIFT_SIL_BASICBLOCKUTILS_H
1515

16-
#include "swift/SIL/SILValue.h"
1716
#include "swift/SIL/BasicBlockBits.h"
17+
#include "swift/SIL/BasicBlockDatastructures.h"
18+
#include "swift/SIL/SILValue.h"
1819
#include "llvm/ADT/SetVector.h"
1920
#include "llvm/ADT/SmallPtrSet.h"
2021
#include "llvm/ADT/SmallVector.h"
@@ -155,6 +156,81 @@ void findJointPostDominatingSet(
155156
bool checkDominates(SILBasicBlock *sourceBlock, SILBasicBlock *destBlock);
156157
#endif
157158

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 &region;
170+
ArrayRef<SILBasicBlock *> roots;
171+
Optional<SmallVector<SILBasicBlock *, 16>> cachedPostOrder;
172+
Optional<BasicBlockSet> cachedVisited;
173+
174+
SILCFGBackwardDFS(Region &region, 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+
};
158234
} // namespace swift
159235

160236
#endif

0 commit comments

Comments
 (0)