@@ -343,25 +343,48 @@ void CanonicalizeOSSALifetime::extendLivenessThroughOverlappingAccess() {
343
343
// liveness computed in Step 1.
344
344
// ===----------------------------------------------------------------------===//
345
345
346
+ // Look past destroys and incidental uses to find a destroy on \p edgeBB that
347
+ // destroys \p def.
348
+ static DestroyValueInst *findDestroyOnCFGEdge (SILBasicBlock *edgeBB,
349
+ SILValue def) {
350
+ for (auto &inst : *edgeBB) {
351
+ if (isIncidentalUse (&inst))
352
+ continue ;
353
+ if (auto *destroy = dyn_cast<DestroyValueInst>(&inst)) {
354
+ if (destroy->getOperand () == def)
355
+ return destroy;
356
+ continue ;
357
+ }
358
+ break ;
359
+ }
360
+ return nullptr ;
361
+ }
362
+
346
363
// / The liveness boundary is at a CFG edge `predBB` -> `succBB`, meaning that
347
364
// / `currentDef` is live out of at least one other `predBB` successor.
348
365
// /
349
366
// / Create and record a final destroy_value at the beginning of `succBB`
350
367
// / (assuming no critical edges).
351
- void CanonicalizeOSSALifetime::insertDestroyOnCFGEdge (
352
- SILBasicBlock *predBB, SILBasicBlock *succBB, bool needsPoison) {
368
+ // /
369
+ // / Avoid deleting and recreating a destroy that was already placed on this
370
+ // / edge. Ignore any intervening destroys that may have been placed while
371
+ // / canonicalizing other values. This is especially important when
372
+ // / canonicalization is called within an iterative worklist such as SILCombine.
373
+ void CanonicalizeOSSALifetime::findOrInsertDestroyOnCFGEdge (
374
+ SILBasicBlock *predBB, SILBasicBlock *succBB, bool needsPoison) {
353
375
354
376
assert (succBB->getSinglePredecessorBlock () == predBB
355
377
&& " value is live-out on another predBB successor: critical edge?" );
356
-
357
- auto pos = succBB->begin ();
358
- // TODO: to improve debugability, consider advancing the poison position ahead
359
- // of operations that are known not to access weak references.
360
- SILBuilderWithScope builder (pos);
361
- auto loc = RegularLocation::getAutoGeneratedLocation (pos->getLoc ());
362
- auto *di = builder.createDestroyValue (loc, currentDef, needsPoison);
363
- getCallbacks ().createdNewInst (di);
364
-
378
+ auto *di = findDestroyOnCFGEdge (succBB, currentDef);
379
+ if (!di) {
380
+ auto pos = succBB->begin ();
381
+ // TODO: to improve debugability, consider advancing the poison position
382
+ // ahead of operations that are known not to access weak references.
383
+ SILBuilderWithScope builder (pos);
384
+ auto loc = RegularLocation::getAutoGeneratedLocation (pos->getLoc ());
385
+ di = builder.createDestroyValue (loc, currentDef, needsPoison);
386
+ getCallbacks ().createdNewInst (di);
387
+ }
365
388
consumes.recordFinalConsume (di);
366
389
367
390
++NumDestroysGenerated;
@@ -431,7 +454,7 @@ void CanonicalizeOSSALifetime::findOrInsertDestroyInBlock(SILBasicBlock *bb) {
431
454
// Insert a destroy after this non-consuming use.
432
455
if (isa<TermInst>(inst)) {
433
456
for (auto &succ : bb->getSuccessors ()) {
434
- insertDestroyOnCFGEdge (bb, succ, poisonRefsMode);
457
+ findOrInsertDestroyOnCFGEdge (bb, succ, poisonRefsMode);
435
458
}
436
459
} else {
437
460
if (existingDestroy) {
@@ -540,7 +563,7 @@ void CanonicalizeOSSALifetime::findOrInsertDestroys() {
540
563
// Continue searching upward to find the pruned liveness boundary.
541
564
for (auto *predBB : bb->getPredecessorBlocks ()) {
542
565
if (liveness.getBlockLiveness (predBB) == PrunedLiveBlocks::LiveOut) {
543
- insertDestroyOnCFGEdge (predBB, bb, poisonRefsMode);
566
+ findOrInsertDestroyOnCFGEdge (predBB, bb, poisonRefsMode);
544
567
} else {
545
568
if (poisonRefsMode) {
546
569
remnantLiveOutBlocks.insert (predBB);
0 commit comments