@@ -180,6 +180,16 @@ class CanonicalOSSAConsumeInfo final {
180180 SWIFT_ASSERT_ONLY_DECL (void dump () const LLVM_ATTRIBUTE_USED);
181181};
182182
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+
183193// / Canonicalize OSSA lifetimes.
184194// /
185195// / Allows the allocation of analysis state to be reused across calls to
@@ -221,11 +231,11 @@ class CanonicalizeOSSALifetime final {
221231private:
222232 // / If true, then debug_value instructions outside of non-debug
223233 // / liveness may be pruned during canonicalization.
224- bool pruneDebugMode;
234+ const PruneDebugInsts_t pruneDebugMode;
225235
226236 // / If true, lifetimes will not be shortened except when necessary to avoid
227237 // / copies.
228- bool maximizeLifetime;
238+ const MaximizeLifetime_t maximizeLifetime;
229239
230240 // If present, will be used to ensure that the lifetime is not shortened to
231241 // end inside an access scope which it previously enclosed. (Note that ending
@@ -246,6 +256,9 @@ class CanonicalizeOSSALifetime final {
246256 // / The SILValue to canonicalize.
247257 SILValue currentDef;
248258
259+ // / Instructions beyond which liveness is not extended by destroy uses.
260+ ArrayRef<SILInstruction *> currentLexicalLifetimeEnds;
261+
249262 // / Original points in the CFG where the current value's lifetime is consumed
250263 // / or destroyed. Each block either contains a consuming instruction (e.g.
251264 // / `destroy_value`) or is on the availability boundary of the value in a
@@ -306,13 +319,15 @@ class CanonicalizeOSSALifetime final {
306319 struct LivenessState {
307320 BitfieldRef<SSAPrunedLiveness>::StackState state;
308321
309- LivenessState (CanonicalizeOSSALifetime &parent, SILValue def)
322+ LivenessState (CanonicalizeOSSALifetime &parent, SILValue def,
323+ ArrayRef<SILInstruction *> lexicalLifetimeEnds)
310324 : state(parent.liveness, def->getFunction ()) {
311- parent.initializeLiveness (def);
325+ parent.initializeLiveness (def, lexicalLifetimeEnds );
312326 }
313327 };
314328
315- CanonicalizeOSSALifetime (bool pruneDebugMode, bool maximizeLifetime,
329+ CanonicalizeOSSALifetime (PruneDebugInsts_t pruneDebugMode,
330+ MaximizeLifetime_t maximizeLifetime,
316331 SILFunction *function,
317332 NonLocalAccessBlockAnalysis *accessBlockAnalysis,
318333 DominanceInfo *domTree,
@@ -324,7 +339,8 @@ class CanonicalizeOSSALifetime final {
324339
325340 SILValue getCurrentDef () const { return currentDef; }
326341
327- void initializeLiveness (SILValue def) {
342+ void initializeLiveness (SILValue def,
343+ ArrayRef<SILInstruction *> lexicalLifetimeEnds) {
328344 assert (consumingBlocks.empty () && debugValues.empty ());
329345 // Clear the cached analysis pointer just in case the client invalidates the
330346 // analysis, freeing its memory.
@@ -333,6 +349,7 @@ class CanonicalizeOSSALifetime final {
333349 destroys.clear ();
334350
335351 currentDef = def;
352+ currentLexicalLifetimeEnds = lexicalLifetimeEnds;
336353
337354 if (maximizeLifetime || respectsDeinitBarriers ()) {
338355 liveness->initializeDiscoveredBlocks (&discoveredBlocks);
@@ -347,8 +364,18 @@ class CanonicalizeOSSALifetime final {
347364 }
348365
349366 // / 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.
352379 // /
353380 // / Return true if any change was made to \p def's extended lifetime. \p def
354381 // / itself will not be deleted and no instructions outside of \p def's
@@ -358,7 +385,8 @@ class CanonicalizeOSSALifetime final {
358385 // / This only deletes instructions within \p def's extended lifetime. Use
359386 // / InstructionDeleter::cleanUpDeadInstructions() to recursively delete dead
360387 // / operands.
361- bool canonicalizeValueLifetime (SILValue def);
388+ bool canonicalizeValueLifetime (
389+ SILValue def, ArrayRef<SILInstruction *> lexicalLifetimeEnds = {});
362390
363391 // / Compute the liveness information for \p def. But do not do any rewriting
364392 // / or computation of boundaries.
@@ -448,6 +476,10 @@ class CanonicalizeOSSALifetime final {
448476 void extendLivenessToDeinitBarriers ();
449477
450478 void extendUnconsumedLiveness (PrunedLivenessBoundary const &boundary);
479+ void visitExtendedUnconsumedBoundary (
480+ ArrayRef<SILInstruction *> ends,
481+ llvm::function_ref<void (SILInstruction *, PrunedLiveness::LifetimeEnding)>
482+ visitor);
451483
452484 void insertDestroysOnBoundary (PrunedLivenessBoundary const &boundary);
453485
0 commit comments