Skip to content

Commit 37a57c0

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 90fb61c commit 37a57c0

File tree

1 file changed

+75
-1
lines changed

1 file changed

+75
-1
lines changed

include/swift/SIL/CFG.h

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,84 @@ class SILCfgTraits : public CfgTraits<SILCfgTraitsBase, SILCfgTraits> {
217217
template <> struct CfgTraitsFor<swift::SILBasicBlock> {
218218
using CfgTraits = SILCfgTraits;
219219
};
220-
221220
#endif
222221

223222
} // end llvm namespace
224223

224+
#include "swift/SIL/BasicBlockDatastructures.h"
225+
226+
namespace swift {
227+
/// Given a region, specified via \p visitor's \p isInRegion member function,
228+
/// backwards-reachable from \r root, traverse the region backwards, depth-first
229+
/// and visit its nodes in the associated post-order.
230+
///
231+
/// interface Visitor {
232+
/// /// Whether the indicated basic block is within the region of the graph
233+
/// /// that should be traversed.
234+
/// bool isInRegion(SILBasicBlock *)
235+
///
236+
/// /// Visit each block in post-order.
237+
/// void visit(SILBasicBlock *)
238+
/// }
239+
template <typename Visitor>
240+
void visitPostOrderBackwards(SILFunction *function, SILBasicBlock *root,
241+
Visitor visitor) {
242+
SmallVector<std::pair<SILBasicBlock *, SILBasicBlock::pred_iterator>, 32>
243+
stack;
244+
BasicBlockSet visited(function);
245+
stack.push_back({root, root->pred_begin()});
246+
while (!stack.empty()) {
247+
while (stack.back().second != stack.back().first->pred_end()) {
248+
auto predecessor = *stack.back().second;
249+
stack.back().second++;
250+
if (!visitor.isInRegion(predecessor))
251+
continue;
252+
if (visited.insert(predecessor))
253+
stack.push_back({predecessor, predecessor->pred_begin()});
254+
}
255+
visitor.visit(stack.back().first);
256+
stack.pop_back();
257+
}
258+
}
259+
260+
/// Given a region, specified via \p visitor's \p isInRegion member function,
261+
/// backwards-reachable from \r roots, traverse the region in topological order.
262+
/// Node M shall be visited before node N if and only if there is an edge from
263+
/// M to N, except for backedges*.
264+
///
265+
/// * The backedges in question are backedges according to backwards depth-first
266+
/// searches from roots.
267+
///
268+
/// interface Visitor {
269+
/// /// Whether the indicated basic block is within the region of the graph
270+
/// /// that should be traversed.
271+
/// bool isInRegion(SILBasicBlock *)
272+
///
273+
/// /// Visit each block in topological order.
274+
/// void visit(SILBasicBlock *)
275+
/// }
276+
template <typename Visitor>
277+
void visitSortedTopologicallyBackwards(SILFunction *function,
278+
ArrayRef<SILBasicBlock *> roots,
279+
Visitor &visitor) {
280+
BasicBlockSet visited(function);
281+
for (auto *root : roots) {
282+
struct Inner {
283+
Visitor &outer;
284+
BasicBlockSet &visited;
285+
int offset = 0;
286+
Inner(Visitor &outer, BasicBlockSet &visited)
287+
: outer(outer), visited(visited) {}
288+
bool isInRegion(SILBasicBlock *block) {
289+
return !visited.contains(block) && outer.isInRegion(block);
290+
}
291+
void visit(SILBasicBlock *block) { outer.visit(block); }
292+
};
293+
Inner inner(visitor, visited);
294+
visitPostOrderBackwards(function, root, inner);
295+
}
296+
}
297+
} // namespace swift
298+
225299
#endif
226300

0 commit comments

Comments
 (0)