Skip to content

Commit 8fbf428

Browse files
committed
[SIL] Added traversal utilities.
Added a utility for performing a backwards DFS from a root and visiting blocks in post order. Added a utility built on top of that which visits a region backwards-reachable from a set of roots in topological order.
1 parent 959b6c4 commit 8fbf428

File tree

1 file changed

+72
-1
lines changed

1 file changed

+72
-1
lines changed

include/swift/SIL/BasicBlockUtils.h

Lines changed: 72 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,76 @@ void findJointPostDominatingSet(
155156
bool checkDominates(SILBasicBlock *sourceBlock, SILBasicBlock *destBlock);
156157
#endif
157158

159+
/// Given a region, specified via \p visitor's \p isInRegion member function,
160+
/// backwards-reachable from \r root, traverse the region backwards, depth-first
161+
/// and visit its nodes in the associated post-order.
162+
///
163+
/// interface Visitor {
164+
/// /// Whether the indicated basic block is within the region of the graph
165+
/// /// that should be traversed.
166+
/// bool isInRegion(SILBasicBlock *)
167+
///
168+
/// /// Visit each block in post-order.
169+
/// void visit(SILBasicBlock *)
170+
/// }
171+
template <typename Visitor>
172+
void visitPostOrderBackwards(SILFunction *function, SILBasicBlock *root,
173+
Visitor visitor) {
174+
SmallVector<std::pair<SILBasicBlock *, SILBasicBlock::pred_iterator>, 32>
175+
stack;
176+
BasicBlockSet visited(function);
177+
stack.push_back({root, root->pred_begin()});
178+
while (!stack.empty()) {
179+
while (stack.back().second != stack.back().first->pred_end()) {
180+
auto predecessor = *stack.back().second;
181+
stack.back().second++;
182+
if (!visitor.isInRegion(predecessor))
183+
continue;
184+
if (visited.insert(predecessor))
185+
stack.push_back({predecessor, predecessor->pred_begin()});
186+
}
187+
visitor.visit(stack.back().first);
188+
stack.pop_back();
189+
}
190+
}
191+
192+
/// Given a region, specified via \p visitor's \p isInRegion member function,
193+
/// backwards-reachable from \r roots, traverse the region in topological order.
194+
/// Node M shall be visited before node N if and only if there is an edge from
195+
/// M to N, except for backedges*.
196+
///
197+
/// * The backedges in question are backedges according to backwards depth-first
198+
/// searches from roots.
199+
///
200+
/// interface Visitor {
201+
/// /// Whether the indicated basic block is within the region of the graph
202+
/// /// that should be traversed.
203+
/// bool isInRegion(SILBasicBlock *)
204+
///
205+
/// /// Visit each block in topological order.
206+
/// void visit(SILBasicBlock *)
207+
/// }
208+
template <typename Visitor>
209+
void visitSortedTopologicallyBackwards(SILFunction *function,
210+
ArrayRef<SILBasicBlock *> roots,
211+
Visitor &visitor) {
212+
BasicBlockSet visited(function);
213+
for (auto *root : roots) {
214+
struct Inner {
215+
Visitor &outer;
216+
BasicBlockSet &visited;
217+
int offset = 0;
218+
Inner(Visitor &outer, BasicBlockSet &visited)
219+
: outer(outer), visited(visited) {}
220+
bool isInRegion(SILBasicBlock *block) {
221+
return !visited.contains(block) && outer.isInRegion(block);
222+
}
223+
void visit(SILBasicBlock *block) { outer.visit(block); }
224+
};
225+
Inner inner(visitor, visited);
226+
visitPostOrderBackwards(function, root, inner);
227+
}
228+
}
158229
} // namespace swift
159230

160231
#endif

0 commit comments

Comments
 (0)