Skip to content

Commit 85c486c

Browse files
committed
Add a utility to run a function on blocks in dominance order,
pushing scopes for various tracking objects as needed.
1 parent c915dd5 commit 85c486c

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

include/swift/Basic/ScopedTracking.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===--- ScopedTracking.h - Utilities for scoped tracking -------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines some miscellaneous utilities that are useful when
14+
// working with tracked values that can be saved and restored in a scoped
15+
// fashion.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_BASIC_SCOPEDTRACKING_H
20+
#define SWIFT_BASIC_SCOPEDTRACKING_H
21+
22+
namespace llvm {
23+
template <class K, class V, class T, class A>
24+
class ScopedHashTable;
25+
template <class K, class V, class T, class A>
26+
class ScopedHashTableScope;
27+
}
28+
29+
namespace swift {
30+
31+
/// Must declare a nested type scope_type which can be initialized
32+
/// with an l-value reference to the tracker type.
33+
template <class Tracker>
34+
struct ScopedTrackingTraits;
35+
36+
template <class K, class V, class T, class A>
37+
struct ScopedTrackingTraits<llvm::ScopedHashTable<K,V,T,A>> {
38+
using scope_type = llvm::ScopedHashTableScope<K,V,T,A>;
39+
};
40+
41+
/// A class which stores scopes for multiple trackers. Can be
42+
/// initialized with a pack of l-value references to the trackers.
43+
template <class... Trackers>
44+
class TrackingScopes;
45+
46+
template <>
47+
class TrackingScopes<> {
48+
public:
49+
TrackingScopes() {}
50+
};
51+
52+
template <class Tracker, class... OtherTrackers>
53+
class TrackingScopes<Tracker, OtherTrackers...> {
54+
typename ScopedTrackingTraits<Tracker>::scope_type Scope;
55+
TrackingScopes<OtherTrackers...> OtherScopes;
56+
public:
57+
TrackingScopes(Tracker &tracker, OtherTrackers &...otherTrackers)
58+
: Scope(tracker), OtherScopes(otherTrackers...) {}
59+
};
60+
61+
} // end namespace swift
62+
63+
#endif

include/swift/SIL/Dominance.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define SWIFT_SIL_DOMINANCE_H
2020

2121
#include "llvm/Support/GenericDomTree.h"
22+
#include "swift/Basic/ScopedTracking.h"
2223
#include "swift/SIL/CFG.h"
2324

2425
extern template class llvm::DominatorTreeBase<swift::SILBasicBlock, false>;
@@ -184,6 +185,62 @@ class PostDominanceInfo : public PostDominatorTreeBase {
184185
using super::properlyDominates;
185186
};
186187

188+
/// Invoke the given callback for all the reachable blocks
189+
/// in a function. It will be called in a depth-first,
190+
/// dominance-consistent order.
191+
///
192+
/// Furthermore, prior to running each block, a tracking scope will
193+
/// be entered for each of the trackers passed in, as if by:
194+
///
195+
/// typename ScopedTrackingTraits<Tracker>::scope_type scope(tracker);
196+
///
197+
/// This allows state to be saved and restored for each of the trackers,
198+
/// such that each tracker will only represent state that was computed
199+
/// in a dominating block.
200+
template <class... Trackers, class Fn>
201+
void runInDominanceOrderWithScopes(DominanceInfo *dominance, Fn &&fn,
202+
Trackers &...trackers) {
203+
using TrackingStackNode = TrackingScopes<Trackers...>;
204+
llvm::SmallVector<std::unique_ptr<TrackingStackNode>, 8> trackingStack;
205+
206+
// The stack of work to do. A null item means to pop the top
207+
// entry off the tracking stack.
208+
llvm::SmallVector<DominanceInfoNode *, 16> workStack;
209+
workStack.push_back(dominance->getRootNode());
210+
211+
while (!workStack.empty()) {
212+
auto node = workStack.pop_back_val();
213+
214+
// If the node is null, pop the top entry off the tracking stack.
215+
if (node == nullptr) {
216+
(void) trackingStack.pop_back_val();
217+
continue;
218+
}
219+
220+
auto bb = node->getBlock();
221+
222+
// If the node has no children, build the stack node in local
223+
// storage to avoid having to heap-allocate it.
224+
if (node->isLeaf()) {
225+
TrackingStackNode stackNode(trackers...);
226+
227+
fn(bb);
228+
229+
// Otherwise, we have to use the more general approach.
230+
} else {
231+
// Push a tracking stack node.
232+
trackingStack.emplace_back(new TrackingStackNode(trackers...));
233+
// Push a work command to pop the tracking stack node.
234+
workStack.push_back(nullptr);
235+
// Push all the child nodes as work items.
236+
workStack.append(node->begin(), node->end());
237+
238+
fn(bb);
239+
}
240+
}
241+
242+
assert(trackingStack.empty());
243+
}
187244

188245
} // end namespace swift
189246

0 commit comments

Comments
 (0)