94
94
95
95
namespace swift {
96
96
97
+ class DeadEndBlocks ;
98
+
97
99
// / Discover "pruned" liveness for an arbitrary set of uses. The client builds
98
100
// / liveness by first initializing "def" blocks, then incrementally feeding uses
99
101
// / to updateForUse().
@@ -133,10 +135,18 @@ class PrunedLiveBlocks {
133
135
// the value is also liveout of the block.
134
136
llvm::SmallDenseMap<SILBasicBlock *, bool , 4 > liveBlocks;
135
137
138
+ // Optional vector of live blocks for clients that deterministically iterate.
139
+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks;
140
+
136
141
// Once the first use has been seen, no definitions can be added.
137
142
SWIFT_ASSERT_ONLY_DECL (bool seenUse = false );
138
143
139
144
public:
145
+ PrunedLiveBlocks (SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
146
+ : discoveredBlocks(discoveredBlocks) {
147
+ assert (!discoveredBlocks || discoveredBlocks->empty ());
148
+ }
149
+
140
150
bool empty () const { return liveBlocks.empty (); }
141
151
142
152
void clear () {
@@ -146,6 +156,12 @@ class PrunedLiveBlocks {
146
156
147
157
unsigned numLiveBlocks () const { return liveBlocks.size (); }
148
158
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
+
149
165
void initializeDefBlock (SILBasicBlock *defBB) {
150
166
assert (!seenUse && " cannot initialize more defs with partial liveness" );
151
167
markBlockLive (defBB, LiveWithin);
@@ -165,6 +181,8 @@ class PrunedLiveBlocks {
165
181
void markBlockLive (SILBasicBlock *bb, IsLive isLive) {
166
182
assert (isLive != Dead && " erasing live blocks isn't implemented." );
167
183
liveBlocks[bb] = (isLive == LiveOut);
184
+ if (discoveredBlocks)
185
+ discoveredBlocks->push_back (bb);
168
186
}
169
187
170
188
void computeUseBlockLiveness (SILBasicBlock *userBB);
@@ -173,13 +191,18 @@ class PrunedLiveBlocks {
173
191
// / PrunedLiveness tracks PrunedLiveBlocks along with "interesting" use
174
192
// / points. The set of interesting uses is a superset of all uses on the
175
193
// / liveness boundary. Filtering out uses that are obviously not on the liveness
176
- // / boundary improves efficiency over tracking all uses. Additionally, all
177
- // / interesting uses that are "lifetime-ending" are flagged. These uses must be
178
- // / on the liveness boundary by their nature, regardless of any other uses. It
179
- // / is up to the client to determine which uses are lifetime-ending. In OSSA,
180
- // / 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
181
202
// / OwnershipConstraint::isLifetimeEnding(). In non-OSSA, it might be determined
182
- // / 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.
183
206
// /
184
207
// / Note: unlike OwnershipLiveRange, this represents a lifetime in terms of the
185
208
// / CFG boundary rather that the use set, and, because it is "pruned", it only
@@ -201,6 +224,9 @@ class PrunedLiveness {
201
224
llvm::SmallDenseMap<SILInstruction *, bool , 8 > users;
202
225
203
226
public:
227
+ PrunedLiveness (SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
228
+ : liveBlocks(discoveredBlocks) {}
229
+
204
230
bool empty () const {
205
231
assert (!liveBlocks.empty () || users.empty ());
206
232
return liveBlocks.empty ();
@@ -213,6 +239,12 @@ class PrunedLiveness {
213
239
214
240
unsigned numLiveBlocks () const { return liveBlocks.numLiveBlocks (); }
215
241
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
+
216
248
void initializeDefBlock (SILBasicBlock *defBB) {
217
249
liveBlocks.initializeDefBlock (defBB);
218
250
}
@@ -228,6 +260,9 @@ class PrunedLiveness {
228
260
// / Returns false if this cannot be done.
229
261
bool updateForBorrowingOperand (Operand *op);
230
262
263
+ // / Update this liveness to extend across the given liveness.
264
+ void extendAcrossLiveness (PrunedLiveness &otherLiveness);
265
+
231
266
PrunedLiveBlocks::IsLive getBlockLiveness (SILBasicBlock *bb) const {
232
267
return liveBlocks.getBlockLiveness (bb);
233
268
}
@@ -245,7 +280,49 @@ class PrunedLiveness {
245
280
246
281
// / Return true if \p inst occurs before the liveness boundary. Used when the
247
282
// / client already knows that inst occurs after the start of liveness.
248
- bool isWithinBoundary (SILInstruction *inst);
283
+ bool isWithinBoundary (SILInstruction *inst) const ;
284
+
285
+ bool areUsesWithinBoundary (ArrayRef<Operand *> uses,
286
+ DeadEndBlocks &deadEndBlocks) const ;
287
+ };
288
+
289
+ // / Record the last use points and CFG edges that form the boundary of
290
+ // / PrunedLiveness.
291
+ struct PrunedLivenessBoundary {
292
+ SmallVector<SILInstruction *, 8 > lastUsers;
293
+ SmallVector<SILBasicBlock *, 8 > boundaryEdges;
294
+
295
+ // / Visit the point at which a lifetime-ending instruction must be inserted,
296
+ // / excluding dead-end blocks. This is only useful when it is known that none
297
+ // / of the lastUsers ends the lifetime, for example when creating a new borrow
298
+ // / scope to enclose all uses.
299
+ void visitInsertionPoints (
300
+ llvm::function_ref<void (SILBasicBlock::iterator insertPt)> visitor,
301
+ DeadEndBlocks *deBlocks = nullptr);
302
+
303
+ // / Compute the boundary from the blocks discovered during liveness analysis.
304
+ // /
305
+ // / Precondition: \p liveness.getDiscoveredBlocks() is a valid list of all
306
+ // / live blocks with no duplicates.
307
+ // /
308
+ // / The computed boundary will completely post-dominate, including dead end
309
+ // / paths. The client should query DeadEndBlocks to ignore those dead end
310
+ // / paths.
311
+ void compute (const PrunedLiveness &liveness);
312
+
313
+ // / Compute the boundary from a backward CFG traversal from a known set of
314
+ // / jointly post-dominating blocks. Avoids the need to record an ordered list
315
+ // / of live blocks during liveness analysis. It's ok if postDomBlocks has
316
+ // / duplicates or extraneous blocks, as long as they jointly post-dominate all
317
+ // / live blocks that aren't on dead-end paths.
318
+ // /
319
+ // / If the jointly post-dominating destroys do not include dead end paths,
320
+ // / then any uses on those paths will not be included in the boundary. The
321
+ // / resulting partial boundary will have holes along those paths. The dead end
322
+ // / successors of blocks in this live set on are not necessarilly identified
323
+ // / by DeadEndBlocks.
324
+ void compute (const PrunedLiveness &liveness,
325
+ ArrayRef<SILBasicBlock *> postDomBlocks);
249
326
};
250
327
251
328
} // namespace swift
0 commit comments