@@ -180,6 +180,16 @@ class CanonicalOSSAConsumeInfo final {
180
180
SWIFT_ASSERT_ONLY_DECL (void dump () const LLVM_ATTRIBUTE_USED);
181
181
};
182
182
183
+ enum PruneDebugInsts_t : bool {
184
+ DontPruneDebugInsts = false ,
185
+ PruneDebugInsts = true ,
186
+ };
187
+
188
+ enum MaximizeLifetime_t : bool {
189
+ DontMaximizeLifetime = false ,
190
+ MaximizeLifetime = true ,
191
+ };
192
+
183
193
// / Canonicalize OSSA lifetimes.
184
194
// /
185
195
// / Allows the allocation of analysis state to be reused across calls to
@@ -221,11 +231,11 @@ class CanonicalizeOSSALifetime final {
221
231
private:
222
232
// / If true, then debug_value instructions outside of non-debug
223
233
// / liveness may be pruned during canonicalization.
224
- bool pruneDebugMode;
234
+ const PruneDebugInsts_t pruneDebugMode;
225
235
226
236
// / If true, lifetimes will not be shortened except when necessary to avoid
227
237
// / copies.
228
- bool maximizeLifetime;
238
+ const MaximizeLifetime_t maximizeLifetime;
229
239
230
240
// If present, will be used to ensure that the lifetime is not shortened to
231
241
// end inside an access scope which it previously enclosed. (Note that ending
@@ -246,6 +256,9 @@ class CanonicalizeOSSALifetime final {
246
256
// / The SILValue to canonicalize.
247
257
SILValue currentDef;
248
258
259
+ // / Instructions beyond which liveness is not extended by destroy uses.
260
+ ArrayRef<SILInstruction *> currentLexicalLifetimeEnds;
261
+
249
262
// / Original points in the CFG where the current value's lifetime is consumed
250
263
// / or destroyed. Each block either contains a consuming instruction (e.g.
251
264
// / `destroy_value`) or is on the availability boundary of the value in a
@@ -306,13 +319,15 @@ class CanonicalizeOSSALifetime final {
306
319
struct LivenessState {
307
320
BitfieldRef<SSAPrunedLiveness>::StackState state;
308
321
309
- LivenessState (CanonicalizeOSSALifetime &parent, SILValue def)
322
+ LivenessState (CanonicalizeOSSALifetime &parent, SILValue def,
323
+ ArrayRef<SILInstruction *> lexicalLifetimeEnds)
310
324
: state(parent.liveness, def->getFunction ()) {
311
- parent.initializeLiveness (def);
325
+ parent.initializeLiveness (def, lexicalLifetimeEnds );
312
326
}
313
327
};
314
328
315
- CanonicalizeOSSALifetime (bool pruneDebugMode, bool maximizeLifetime,
329
+ CanonicalizeOSSALifetime (PruneDebugInsts_t pruneDebugMode,
330
+ MaximizeLifetime_t maximizeLifetime,
316
331
SILFunction *function,
317
332
NonLocalAccessBlockAnalysis *accessBlockAnalysis,
318
333
DominanceInfo *domTree,
@@ -324,7 +339,8 @@ class CanonicalizeOSSALifetime final {
324
339
325
340
SILValue getCurrentDef () const { return currentDef; }
326
341
327
- void initializeLiveness (SILValue def) {
342
+ void initializeLiveness (SILValue def,
343
+ ArrayRef<SILInstruction *> lexicalLifetimeEnds) {
328
344
assert (consumingBlocks.empty () && debugValues.empty ());
329
345
// Clear the cached analysis pointer just in case the client invalidates the
330
346
// analysis, freeing its memory.
@@ -333,6 +349,7 @@ class CanonicalizeOSSALifetime final {
333
349
destroys.clear ();
334
350
335
351
currentDef = def;
352
+ currentLexicalLifetimeEnds = lexicalLifetimeEnds;
336
353
337
354
if (maximizeLifetime || respectsDeinitBarriers ()) {
338
355
liveness->initializeDiscoveredBlocks (&discoveredBlocks);
@@ -347,8 +364,18 @@ class CanonicalizeOSSALifetime final {
347
364
}
348
365
349
366
// / Top-Level API: rewrites copies and destroys within \p def's extended
350
- // / lifetime. \p lifetime caches transient analysis state across multiple
351
- // / calls.
367
+ // / lifetime.
368
+ // /
369
+ // / For lexical values, canonicalization respects deinit barriers, introducing
370
+ // / copies as needed to maintain lifetimes beyond final consuming uses to the
371
+ // / original lexical lifetime end. When a lexical value is explicitly
372
+ // / consumed (via the `consume` keyword), however, the lifetime does not
373
+ // / extend to original destroys beyond that consume--the value must be dead
374
+ // / after the corresponding marker instructions (`move_value`); to support
375
+ // / this shortening, the marker instructions must be provided as \p
376
+ // / lexicalLifetimeEnds. When provided, deinit barriers will be respected
377
+ // / except to the extent doing so would result in the value being live after
378
+ // / the marker instructions.
352
379
// /
353
380
// / Return true if any change was made to \p def's extended lifetime. \p def
354
381
// / itself will not be deleted and no instructions outside of \p def's
@@ -358,7 +385,8 @@ class CanonicalizeOSSALifetime final {
358
385
// / This only deletes instructions within \p def's extended lifetime. Use
359
386
// / InstructionDeleter::cleanUpDeadInstructions() to recursively delete dead
360
387
// / operands.
361
- bool canonicalizeValueLifetime (SILValue def);
388
+ bool canonicalizeValueLifetime (
389
+ SILValue def, ArrayRef<SILInstruction *> lexicalLifetimeEnds = {});
362
390
363
391
// / Compute the liveness information for \p def. But do not do any rewriting
364
392
// / or computation of boundaries.
@@ -448,6 +476,10 @@ class CanonicalizeOSSALifetime final {
448
476
void extendLivenessToDeinitBarriers ();
449
477
450
478
void extendUnconsumedLiveness (PrunedLivenessBoundary const &boundary);
479
+ void visitExtendedUnconsumedBoundary (
480
+ ArrayRef<SILInstruction *> ends,
481
+ llvm::function_ref<void (SILInstruction *, PrunedLiveness::LifetimeEnding)>
482
+ visitor);
451
483
452
484
void insertDestroysOnBoundary (PrunedLivenessBoundary const &boundary);
453
485
0 commit comments