@@ -122,14 +122,21 @@ class VisitUnreachableLifetimeEnds {
122
122
// / The value whose dead-end block lifetime ends are to be visited.
123
123
SILValue value;
124
124
125
+ // / Whether to allow leaks.
126
+ // /
127
+ // / Here, that entails allowing walks to reach non-unreachable terminators and
128
+ // / not creating lifetime ends before them.
129
+ OSSALifetimeCompletion::AllowLeaks_t allowLeaks;
130
+
125
131
// / The non-lifetime-ending boundary of `value`.
126
132
BasicBlockSet starts;
127
133
// / The region between (inclusive) the `starts` and the unreachable blocks.
128
134
BasicBlockSetVector region;
129
135
130
136
public:
131
- VisitUnreachableLifetimeEnds (SILValue value)
132
- : value(value), starts(value->getFunction ()),
137
+ VisitUnreachableLifetimeEnds (SILValue value,
138
+ OSSALifetimeCompletion::AllowLeaks_t allowLeaks)
139
+ : value(value), allowLeaks(allowLeaks), starts(value->getFunction ()),
133
140
region(value->getFunction ()) {}
134
141
135
142
// / Region discovery.
@@ -232,9 +239,17 @@ void VisitUnreachableLifetimeEnds::computeRegion(
232
239
// (3) Forward walk to find the region in which `value` might be available.
233
240
while (auto *block = regionWorklist.pop ()) {
234
241
if (block->succ_empty ()) {
235
- // This assert will fail unless there is already a lifetime-ending
236
- // instruction on each path to normal function exits.
237
- assert (isa<UnreachableInst>(block->getTerminator ()));
242
+ // This is a function-exiting block.
243
+ //
244
+ // In valid-but-lifetime-incomplete OSSA there must be a lifetime-ending
245
+ // instruction on each path from the def that exits the function normally.
246
+ // Thus finding a value available at the end of such a block means that
247
+ // the block does _not_ must not exits the function normally; in other
248
+ // words its terminator must be an UnreachableInst.
249
+ //
250
+ // In invalid OSSA, indicated by the `allowLeaks` flag, no such guarantee
251
+ // exists.
252
+ assert (isa<UnreachableInst>(block->getTerminator ()) || allowLeaks);
238
253
}
239
254
for (auto *successor : block->getSuccessorBlocks ()) {
240
255
regionWorklist.pushIfNotVisited (successor);
@@ -300,6 +315,12 @@ void VisitUnreachableLifetimeEnds::visitAvailabilityBoundary(
300
315
if (!block->succ_empty () && !hasUnavailableSuccessor ()) {
301
316
continue ;
302
317
}
318
+ if (allowLeaks && block->succ_empty () &&
319
+ !isa<UnreachableInst>(block->getTerminator ())) {
320
+ // Availability extends to the end of a function-exiting-normally block.
321
+ // If leaks are allowed, don't visit.
322
+ continue ;
323
+ }
303
324
assert (hasUnavailableSuccessor () ||
304
325
isa<UnreachableInst>(block->getTerminator ()));
305
326
visit (block->getTerminator ());
@@ -308,10 +329,10 @@ void VisitUnreachableLifetimeEnds::visitAvailabilityBoundary(
308
329
} // end anonymous namespace
309
330
310
331
void OSSALifetimeCompletion::visitUnreachableLifetimeEnds (
311
- SILValue value, const SSAPrunedLiveness &liveness,
332
+ SILValue value, AllowLeaks_t allowLeaks, const SSAPrunedLiveness &liveness,
312
333
llvm::function_ref<void (SILInstruction *)> visit) {
313
334
314
- VisitUnreachableLifetimeEnds visitor (value);
335
+ VisitUnreachableLifetimeEnds visitor (value, allowLeaks );
315
336
316
337
visitor.computeRegion (liveness);
317
338
@@ -322,12 +343,12 @@ void OSSALifetimeCompletion::visitUnreachableLifetimeEnds(
322
343
visitor.visitAvailabilityBoundary (result, visit);
323
344
}
324
345
325
- static bool
326
- endLifetimeAtAvailabilityBoundary ( SILValue value,
327
- const SSAPrunedLiveness &liveness) {
346
+ static bool endLifetimeAtAvailabilityBoundary (
347
+ SILValue value, OSSALifetimeCompletion::AllowLeaks_t allowLeaks ,
348
+ const SSAPrunedLiveness &liveness) {
328
349
bool changed = false ;
329
350
OSSALifetimeCompletion::visitUnreachableLifetimeEnds (
330
- value, liveness, [&](auto *unreachable) {
351
+ value, allowLeaks, liveness, [&](auto *unreachable) {
331
352
SILBuilderWithScope builder (unreachable);
332
353
endOSSALifetime (value, builder);
333
354
changed = true ;
@@ -354,7 +375,12 @@ bool OSSALifetimeCompletion::analyzeAndUpdateLifetime(SILValue value,
354
375
changed |= endLifetimeAtLivenessBoundary (value, liveness.getLiveness ());
355
376
break ;
356
377
case Boundary::Availability:
357
- changed |= endLifetimeAtAvailabilityBoundary (value, liveness.getLiveness ());
378
+ changed |= endLifetimeAtAvailabilityBoundary (value, DoNotAllowLeaks,
379
+ liveness.getLiveness ());
380
+ break ;
381
+ case Boundary::AvailabilityWithLeaks:
382
+ changed |= endLifetimeAtAvailabilityBoundary (value, AllowLeaks,
383
+ liveness.getLiveness ());
358
384
break ;
359
385
}
360
386
// TODO: Rebuild outer adjacent phis on demand (SILGen does not currently
@@ -379,7 +405,9 @@ static FunctionTest OSSALifetimeCompletionTest(
379
405
arguments.takeString ())
380
406
.Case (" liveness" , OSSALifetimeCompletion::Boundary::Liveness)
381
407
.Case (" availability" ,
382
- OSSALifetimeCompletion::Boundary::Availability);
408
+ OSSALifetimeCompletion::Boundary::Availability)
409
+ .Case (" availability_with_leaks" ,
410
+ OSSALifetimeCompletion::Boundary::AvailabilityWithLeaks);
383
411
llvm::outs () << " OSSA lifetime completion on " << kind
384
412
<< " boundary: " << value;
385
413
OSSALifetimeCompletion completion (&function, /* domInfo*/ nullptr );
0 commit comments