12
12
// /
13
13
// / Incrementally compute and represent basic block liveness of a single live
14
14
// / 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
16
18
// / definition blocks, typically a single block. The client then incrementally
17
19
// / updates liveness by providing a set of "interesting" uses one at a time.
18
20
// /
92
94
93
95
namespace swift {
94
96
97
+ class DeadEndBlocks ;
98
+
95
99
// / Discover "pruned" liveness for an arbitrary set of uses. The client builds
96
100
// / liveness by first initializing "def" blocks, then incrementally feeding uses
97
101
// / to updateForUse().
@@ -131,16 +135,33 @@ class PrunedLiveBlocks {
131
135
// the value is also liveout of the block.
132
136
llvm::SmallDenseMap<SILBasicBlock *, bool , 4 > liveBlocks;
133
137
138
+ // Optional vector of live blocks for clients that deterministically iterate.
139
+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks;
140
+
134
141
// Once the first use has been seen, no definitions can be added.
135
142
SWIFT_ASSERT_ONLY_DECL (bool seenUse = false );
136
143
137
144
public:
145
+ PrunedLiveBlocks (SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
146
+ : discoveredBlocks(discoveredBlocks) {
147
+ assert (!discoveredBlocks || discoveredBlocks->empty ());
148
+ }
149
+
138
150
bool empty () const { return liveBlocks.empty (); }
139
151
140
- void clear () { liveBlocks.clear (); SWIFT_ASSERT_ONLY (seenUse = false ); }
152
+ void clear () {
153
+ liveBlocks.clear ();
154
+ SWIFT_ASSERT_ONLY (seenUse = false );
155
+ }
141
156
142
157
unsigned numLiveBlocks () const { return liveBlocks.size (); }
143
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
+
144
165
void initializeDefBlock (SILBasicBlock *defBB) {
145
166
assert (!seenUse && " cannot initialize more defs with partial liveness" );
146
167
markBlockLive (defBB, LiveWithin);
@@ -160,6 +181,8 @@ class PrunedLiveBlocks {
160
181
void markBlockLive (SILBasicBlock *bb, IsLive isLive) {
161
182
assert (isLive != Dead && " erasing live blocks isn't implemented." );
162
183
liveBlocks[bb] = (isLive == LiveOut);
184
+ if (discoveredBlocks)
185
+ discoveredBlocks->push_back (bb);
163
186
}
164
187
165
188
void computeUseBlockLiveness (SILBasicBlock *userBB);
@@ -168,13 +191,18 @@ class PrunedLiveBlocks {
168
191
// / PrunedLiveness tracks PrunedLiveBlocks along with "interesting" use
169
192
// / points. The set of interesting uses is a superset of all uses on the
170
193
// / 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
176
202
// / 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.
178
206
// /
179
207
// / Note: unlike OwnershipLiveRange, this represents a lifetime in terms of the
180
208
// / CFG boundary rather that the use set, and, because it is "pruned", it only
@@ -196,6 +224,9 @@ class PrunedLiveness {
196
224
llvm::SmallDenseMap<SILInstruction *, bool , 8 > users;
197
225
198
226
public:
227
+ PrunedLiveness (SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
228
+ : liveBlocks(discoveredBlocks) {}
229
+
199
230
bool empty () const {
200
231
assert (!liveBlocks.empty () || users.empty ());
201
232
return liveBlocks.empty ();
@@ -208,6 +239,12 @@ class PrunedLiveness {
208
239
209
240
unsigned numLiveBlocks () const { return liveBlocks.numLiveBlocks (); }
210
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
+
211
248
void initializeDefBlock (SILBasicBlock *defBB) {
212
249
liveBlocks.initializeDefBlock (defBB);
213
250
}
@@ -223,6 +260,9 @@ class PrunedLiveness {
223
260
// / Returns false if this cannot be done.
224
261
bool updateForBorrowingOperand (Operand *op);
225
262
263
+ // / Update this liveness to extend across the given liveness.
264
+ void extendAcrossLiveness (PrunedLiveness &otherLiveness);
265
+
226
266
PrunedLiveBlocks::IsLive getBlockLiveness (SILBasicBlock *bb) const {
227
267
return liveBlocks.getBlockLiveness (bb);
228
268
}
@@ -237,6 +277,55 @@ class PrunedLiveness {
237
277
return NonUser;
238
278
return useIter->second ? LifetimeEndingUse : NonLifetimeEndingUse;
239
279
}
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);
240
329
};
241
330
242
331
} // namespace swift
0 commit comments