Skip to content

Commit 60dc24b

Browse files
authored
Merge pull request swiftlang#39577 from atrick/liveness-boundary
2 parents c997596 + 1bb27f6 commit 60dc24b

File tree

11 files changed

+414
-132
lines changed

11 files changed

+414
-132
lines changed

include/swift/SILOptimizer/Utils/PrunedLiveness.h renamed to include/swift/SIL/PrunedLiveness.h

Lines changed: 97 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
///
1313
/// Incrementally compute and represent basic block liveness of a single live
1414
/// range. The live range is defined by points in the CFG, independent of any
15-
/// particular SSA value. The client initializes liveness with a set of
15+
/// particular SSA value; however, it must be contiguous. Unlike traditional
16+
/// variable liveness, a definition within the live range does not create a
17+
/// "hole" in the live range. The client initializes liveness with a set of
1618
/// definition blocks, typically a single block. The client then incrementally
1719
/// updates liveness by providing a set of "interesting" uses one at a time.
1820
///
@@ -92,6 +94,8 @@
9294

9395
namespace swift {
9496

97+
class DeadEndBlocks;
98+
9599
/// Discover "pruned" liveness for an arbitrary set of uses. The client builds
96100
/// liveness by first initializing "def" blocks, then incrementally feeding uses
97101
/// to updateForUse().
@@ -131,16 +135,33 @@ class PrunedLiveBlocks {
131135
// the value is also liveout of the block.
132136
llvm::SmallDenseMap<SILBasicBlock *, bool, 4> liveBlocks;
133137

138+
// Optional vector of live blocks for clients that deterministically iterate.
139+
SmallVectorImpl<SILBasicBlock *> *discoveredBlocks;
140+
134141
// Once the first use has been seen, no definitions can be added.
135142
SWIFT_ASSERT_ONLY_DECL(bool seenUse = false);
136143

137144
public:
145+
PrunedLiveBlocks(SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr)
146+
: discoveredBlocks(discoveredBlocks) {
147+
assert(!discoveredBlocks || discoveredBlocks->empty());
148+
}
149+
138150
bool empty() const { return liveBlocks.empty(); }
139151

140-
void clear() { liveBlocks.clear(); SWIFT_ASSERT_ONLY(seenUse = false); }
152+
void clear() {
153+
liveBlocks.clear();
154+
SWIFT_ASSERT_ONLY(seenUse = false);
155+
}
141156

142157
unsigned numLiveBlocks() const { return liveBlocks.size(); }
143158

159+
/// If the constructor was provided with a vector to populate, then this
160+
/// returns the list of all live blocks with no duplicates.
161+
ArrayRef<SILBasicBlock *> getDiscoveredBlocks() const {
162+
return *discoveredBlocks;
163+
}
164+
144165
void initializeDefBlock(SILBasicBlock *defBB) {
145166
assert(!seenUse && "cannot initialize more defs with partial liveness");
146167
markBlockLive(defBB, LiveWithin);
@@ -160,6 +181,8 @@ class PrunedLiveBlocks {
160181
void markBlockLive(SILBasicBlock *bb, IsLive isLive) {
161182
assert(isLive != Dead && "erasing live blocks isn't implemented.");
162183
liveBlocks[bb] = (isLive == LiveOut);
184+
if (discoveredBlocks)
185+
discoveredBlocks->push_back(bb);
163186
}
164187

165188
void computeUseBlockLiveness(SILBasicBlock *userBB);
@@ -168,13 +191,18 @@ class PrunedLiveBlocks {
168191
/// PrunedLiveness tracks PrunedLiveBlocks along with "interesting" use
169192
/// points. The set of interesting uses is a superset of all uses on the
170193
/// liveness boundary. Filtering out uses that are obviously not on the liveness
171-
/// boundary improves efficiency over tracking all uses. Additionally, all
172-
/// interesting uses that are "lifetime-ending" are flagged. These uses must be
173-
/// on the liveness boundary by their nature, regardless of any other uses. It
174-
/// is up to the client to determine which uses are lifetime-ending. In OSSA,
175-
/// the lifetime-ending property might be detemined by
194+
/// boundary improves efficiency over tracking all uses.
195+
///
196+
/// Additionally, all interesting uses that are potentially "lifetime-ending"
197+
/// are flagged. These instruction are included as interesting use points, even
198+
/// if they don't occur on the liveness boundary. Lifetime-ending uses that end
199+
/// up on the final liveness boundary may be used to end the lifetime. It is up
200+
/// to the client to determine which uses are potentially lifetime-ending. In
201+
/// OSSA, the lifetime-ending property might be detemined by
176202
/// OwnershipConstraint::isLifetimeEnding(). In non-OSSA, it might be determined
177-
/// by deallocation.
203+
/// by deallocation. If a lifetime-ending use ends up within the liveness
204+
/// boundary, then it is up to the client to figure out how to "extend" the
205+
/// lifetime beyond those uses.
178206
///
179207
/// Note: unlike OwnershipLiveRange, this represents a lifetime in terms of the
180208
/// CFG boundary rather that the use set, and, because it is "pruned", it only
@@ -196,6 +224,9 @@ class PrunedLiveness {
196224
llvm::SmallDenseMap<SILInstruction *, bool, 8> users;
197225

198226
public:
227+
PrunedLiveness(SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr)
228+
: liveBlocks(discoveredBlocks) {}
229+
199230
bool empty() const {
200231
assert(!liveBlocks.empty() || users.empty());
201232
return liveBlocks.empty();
@@ -208,6 +239,12 @@ class PrunedLiveness {
208239

209240
unsigned numLiveBlocks() const { return liveBlocks.numLiveBlocks(); }
210241

242+
/// If the constructor was provided with a vector to populate, then this
243+
/// returns the list of all live blocks with no duplicates.
244+
ArrayRef<SILBasicBlock *> getDiscoveredBlocks() const {
245+
return liveBlocks.getDiscoveredBlocks();
246+
}
247+
211248
void initializeDefBlock(SILBasicBlock *defBB) {
212249
liveBlocks.initializeDefBlock(defBB);
213250
}
@@ -223,6 +260,9 @@ class PrunedLiveness {
223260
/// Returns false if this cannot be done.
224261
bool updateForBorrowingOperand(Operand *op);
225262

263+
/// Update this liveness to extend across the given liveness.
264+
void extendAcrossLiveness(PrunedLiveness &otherLiveness);
265+
226266
PrunedLiveBlocks::IsLive getBlockLiveness(SILBasicBlock *bb) const {
227267
return liveBlocks.getBlockLiveness(bb);
228268
}
@@ -237,6 +277,55 @@ class PrunedLiveness {
237277
return NonUser;
238278
return useIter->second ? LifetimeEndingUse : NonLifetimeEndingUse;
239279
}
280+
281+
/// Return true if \p inst occurs before the liveness boundary. Used when the
282+
/// client already knows that inst occurs after the start of liveness.
283+
bool isWithinBoundary(SILInstruction *inst) const;
284+
285+
bool areUsesWithinBoundary(ArrayRef<Operand *> uses,
286+
DeadEndBlocks &deadEndBlocks) const;
287+
288+
/// Compute liveness for a single SSA definition.
289+
void computeSSALiveness(SILValue def);
290+
};
291+
292+
/// Record the last use points and CFG edges that form the boundary of
293+
/// PrunedLiveness.
294+
struct PrunedLivenessBoundary {
295+
SmallVector<SILInstruction *, 8> lastUsers;
296+
SmallVector<SILBasicBlock *, 8> boundaryEdges;
297+
298+
/// Visit the point at which a lifetime-ending instruction must be inserted,
299+
/// excluding dead-end blocks. This is only useful when it is known that none
300+
/// of the lastUsers ends the lifetime, for example when creating a new borrow
301+
/// scope to enclose all uses.
302+
void visitInsertionPoints(
303+
llvm::function_ref<void(SILBasicBlock::iterator insertPt)> visitor,
304+
DeadEndBlocks *deBlocks = nullptr);
305+
306+
/// Compute the boundary from the blocks discovered during liveness analysis.
307+
///
308+
/// Precondition: \p liveness.getDiscoveredBlocks() is a valid list of all
309+
/// live blocks with no duplicates.
310+
///
311+
/// The computed boundary will completely post-dominate, including dead end
312+
/// paths. The client should query DeadEndBlocks to ignore those dead end
313+
/// paths.
314+
void compute(const PrunedLiveness &liveness);
315+
316+
/// Compute the boundary from a backward CFG traversal from a known set of
317+
/// jointly post-dominating blocks. Avoids the need to record an ordered list
318+
/// of live blocks during liveness analysis. It's ok if postDomBlocks has
319+
/// duplicates or extraneous blocks, as long as they jointly post-dominate all
320+
/// live blocks that aren't on dead-end paths.
321+
///
322+
/// If the jointly post-dominating destroys do not include dead end paths,
323+
/// then any uses on those paths will not be included in the boundary. The
324+
/// resulting partial boundary will have holes along those paths. The dead end
325+
/// successors of blocks in this live set on are not necessarilly identified
326+
/// by DeadEndBlocks.
327+
void compute(const PrunedLiveness &liveness,
328+
ArrayRef<SILBasicBlock *> postDomBlocks);
240329
};
241330

242331
} // namespace swift

include/swift/SILOptimizer/Utils/CanonicalOSSALifetime.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@
9898

9999
#include "swift/Basic/DAGNodeWorklist.h"
100100
#include "swift/Basic/SmallPtrSetVector.h"
101+
#include "swift/SIL/PrunedLiveness.h"
101102
#include "swift/SIL/SILInstruction.h"
102103
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
103104
#include "swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h"
104105
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
105-
#include "swift/SILOptimizer/Utils/PrunedLiveness.h"
106106
#include "llvm/ADT/DenseMap.h"
107107
#include "llvm/ADT/SetVector.h"
108108

include/swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@
3030
#include "swift/Basic/DAGNodeWorklist.h"
3131
#include "swift/Basic/SmallPtrSetVector.h"
3232
#include "swift/SIL/OwnershipUtils.h"
33+
#include "swift/SIL/PrunedLiveness.h"
3334
#include "swift/SIL/SILInstruction.h"
3435
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
3536
#include "swift/SILOptimizer/Analysis/NonLocalAccessBlockAnalysis.h"
3637
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
37-
#include "swift/SILOptimizer/Utils/PrunedLiveness.h"
3838
#include "llvm/ADT/DenseMap.h"
3939
#include "llvm/ADT/SetVector.h"
4040

include/swift/SILOptimizer/Utils/ValueLifetime.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,19 @@ namespace swift {
4545
/// lastUser or boundaryEdge. But with infinite loops, it is possible for both
4646
/// lastUsers and boundaryEdges to be empty even if there are uses within the
4747
/// loop.
48+
///
49+
/// TODO: combine this with PrunedLivenessBoundary.
4850
struct ValueLifetimeBoundary {
4951
SmallVector<SILInstruction *, 8> lastUsers;
5052
SmallVector<SILBasicBlock *, 8> boundaryEdges;
53+
54+
/// Visit the point at which a lifetime-ending instruction must be inserted,
55+
/// excluding dead-end blocks. This is only useful when it is known that none
56+
/// of the lastUsers ends the lifetime, for example when creating a new borrow
57+
/// scope to enclose all uses.
58+
void visitInsertionPoints(
59+
llvm::function_ref<void(SILBasicBlock::iterator insertPt)> visitor,
60+
DeadEndBlocks *deBlocks = nullptr);
5161
};
5262

5363
/// Computes the lifetime frontier for a given value with respect to a

lib/SIL/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ target_sources(swiftSIL PRIVATE
1313
OwnershipUtils.cpp
1414
PrettyStackTrace.cpp
1515
Projection.cpp
16+
PrunedLiveness.cpp
1617
SILBridging.cpp
1718
SILInstructionWorklist.cpp
1819
SILRemarkStreamer.cpp

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
#include "swift/Basic/SmallPtrSetVector.h"
1616
#include "swift/SIL/InstructionUtils.h"
1717
#include "swift/SIL/LinearLifetimeChecker.h"
18-
#include "swift/SIL/Projection.h"
1918
#include "swift/SIL/MemAccessUtils.h"
19+
#include "swift/SIL/Projection.h"
20+
#include "swift/SIL/PrunedLiveness.h"
2021
#include "swift/SIL/SILArgument.h"
2122
#include "swift/SIL/SILInstruction.h"
2223

0 commit comments

Comments
 (0)