@@ -390,6 +390,14 @@ void DeadEndBlocks::compute() {
390
390
// Post Dominance Set Completion Utilities
391
391
// ===----------------------------------------------------------------------===//
392
392
393
+ static bool endsInUnreachable (SILBasicBlock *block) {
394
+ // Handle the case where a single "unreachable" block (e.g. containing a call
395
+ // to fatalError()), is jumped to from multiple source blocks.
396
+ if (SILBasicBlock *singleSucc = block->getSingleSuccessorBlock ())
397
+ block = singleSucc;
398
+ return isa<UnreachableInst>(block->getTerminator ());
399
+ }
400
+
393
401
void JointPostDominanceSetComputer::findJointPostDominatingSet (
394
402
SILBasicBlock *dominatingBlock, ArrayRef<SILBasicBlock *> dominatedBlockSet,
395
403
function_ref<void (SILBasicBlock *)> inputBlocksFoundDuringWalk,
@@ -403,47 +411,31 @@ void JointPostDominanceSetComputer::findJointPostDominatingSet(
403
411
// dominatingBlock, then we return success since a block post-doms its self so
404
412
// it is already complete.
405
413
//
406
- // NOTE: We do not consider this a visiteed
407
- if (dominatedBlockSet.size () == 1 ) {
408
- if (dominatingBlock == dominatedBlockSet[0 ]) {
409
- if (inputBlocksInJointPostDomSet)
410
- inputBlocksInJointPostDomSet (dominatingBlock);
411
- return ;
412
- }
414
+ // NOTE: We do not consider this a visited
415
+ if (dominatedBlockSet.size () == 1 && dominatingBlock == dominatedBlockSet[0 ]) {
416
+ if (inputBlocksInJointPostDomSet)
417
+ inputBlocksInJointPostDomSet (dominatingBlock);
418
+ return ;
413
419
}
414
420
415
421
// At the top of where we for sure are going to use state... make sure we
416
422
// always clean up any resources that we use!
417
423
SWIFT_DEFER { clear (); };
418
424
419
- // / A set that guards our worklist. Any block before it is added to worklist
420
- // / should be checked against visitedBlocks.
421
- SILFunction *function = dominatingBlock->getParent ();
422
- BasicBlockSet visitedBlocks (function);
425
+ // / All blocks visited during the backwards walk of the CFG, but not including
426
+ // / the initial blocks in `dominatedBlockSet`.
427
+ BasicBlockSet visitedBlocks (dominatingBlock->getParent ());
423
428
424
- // / The set of blocks where we begin our walk.
425
- BasicBlockSet initialBlocks (function );
429
+ // / All blocks in `dominatedBlockSet` (= blocks where we begin our walk) .
430
+ BasicBlockSet initialBlocks (visitedBlocks. getFunction () );
426
431
427
- // / True for blocks which are in blocksThatLeakIfNeverVisited.
428
- BasicBlockFlag isLeakingBlock (function);
429
-
430
- // Otherwise, we need to compute our joint post dominating set. We do this by
431
- // performing a backwards walk up the CFG tracking back liveness until we find
432
- // our dominating block. As we walk up, we keep track of any successor blocks
433
- // that we need to visit before the walk completes lest we leak. After we
434
- // finish the walk, these leaking blocks are a valid (albeit not unique)
435
- // completion of the post dom set.
432
+ // Compute our joint post dominating set. We do this by performing a backwards
433
+ // walk up the CFG tracking back liveness until we find our dominating block.
436
434
for (auto *block : dominatedBlockSet) {
437
- // Skip dead end blocks.
438
- if (deadEndBlocks.isDeadEnd (block))
439
- continue ;
440
-
441
435
// We require dominatedBlockSet to be a set and thus assert if we hit it to
442
436
// flag user error to our caller.
443
- bool succeededInserting = visitedBlocks.insert (block);
444
- (void )succeededInserting;
445
- assert (succeededInserting &&
446
- " Repeat Elt: dominatedBlockSet should be a set?!" );
437
+ assert (!initialBlocks.contains (block) &&
438
+ " dominatedBlockSet must not contain duplicate elements" );
447
439
initialBlocks.insert (block);
448
440
worklist.push_back (block);
449
441
}
@@ -452,64 +444,64 @@ void JointPostDominanceSetComputer::findJointPostDominatingSet(
452
444
while (!worklist.empty ()) {
453
445
auto *block = worklist.pop_back_val ();
454
446
455
- // Then if our block is not one of our initial blocks, add the block's
456
- // successors to blocksThatLeakIfNeverVisited.
457
- if (!initialBlocks.contains (block)) {
458
- for (auto *succBlock : block->getSuccessorBlocks ()) {
459
- if (visitedBlocks.contains (succBlock))
460
- continue ;
461
- if (deadEndBlocks.isDeadEnd (succBlock))
462
- continue ;
463
- blocksThatLeakIfNeverVisited.push_back (succBlock);
464
- isLeakingBlock.set (succBlock);
465
- }
466
- }
467
-
468
447
// If we are the dominating block, we are done.
469
448
if (dominatingBlock == block)
470
449
continue ;
471
450
472
- // Otherwise for each predecessor that we have, first check if it was one of
473
- // our initial blocks (signaling a loop) and then add it to the worklist if
474
- // we haven't visited it already.
475
451
for (auto *predBlock : block->getPredecessorBlocks ()) {
476
- if (initialBlocks.contains (predBlock)) {
477
- reachableInputBlocks.push_back (predBlock);
478
- for (auto *succBlock : predBlock->getSuccessorBlocks ()) {
479
- if (visitedBlocks.contains (succBlock))
480
- continue ;
481
- if (deadEndBlocks.isDeadEnd (succBlock))
482
- continue ;
483
- if (!isLeakingBlock.testAndSet (succBlock))
484
- blocksThatLeakIfNeverVisited.push_back (succBlock);
485
- }
486
- }
487
452
if (visitedBlocks.insert (predBlock))
488
453
worklist.push_back (predBlock);
489
454
}
490
455
}
491
456
492
- // After our worklist has emptied, any not visited blocks in
493
- // blocksThatLeakIfNeverVisited are "leaking blocks".
494
- for (auto *leakingBlock : blocksThatLeakIfNeverVisited) {
495
- if (!visitedBlocks.contains (leakingBlock))
496
- foundJointPostDomSetCompletionBlocks (leakingBlock);
497
- }
498
-
499
- // Then unique our list of reachable input blocks and pass them to our
500
- // callback.
501
- sortUnique (reachableInputBlocks);
502
- for (auto *block : reachableInputBlocks)
503
- inputBlocksFoundDuringWalk (block);
457
+ // Do the same walk over all visited blocks again to find the "leaking"
458
+ // blocks. These leaking blocks are the completion of the post dom set.
459
+ //
460
+ // Note that we could also keep all visited blocks in a SmallVector in the
461
+ // first run. But the worklist algorithm is fast and we don't want
462
+ // to risk that the small vector overflows (the set of visited blocks can be
463
+ // much larger than the maximum worklist size).
464
+ BasicBlockSet visitedBlocksInSecondRun (visitedBlocks.getFunction ());
465
+ assert (worklist.empty ());
466
+ worklist.append (dominatedBlockSet.begin (), dominatedBlockSet.end ());
467
+ while (!worklist.empty ()) {
468
+ auto *block = worklist.pop_back_val ();
469
+ if (dominatingBlock == block)
470
+ continue ;
504
471
505
- // Then if were asked to find the subset of our input blocks that are in the
506
- // joint-postdominance set, compute that.
507
- if (!inputBlocksInJointPostDomSet)
508
- return ;
472
+ for (auto *predBlock : block->getPredecessorBlocks ()) {
473
+ assert (visitedBlocks.contains (predBlock));
474
+ if (visitedBlocksInSecondRun.insert (predBlock)) {
475
+ worklist.push_back (predBlock);
476
+
477
+ for (auto *succBlock : predBlock->getSuccessorBlocks ()) {
478
+ // All not-visited successors of a visited block are "leaking" blocks.
479
+ if (!visitedBlocks.contains (succBlock) &&
480
+ // For this purpose also the initial blocks count as "visited",
481
+ // although they are not added to the visitedBlocks set.
482
+ !initialBlocks.contains (succBlock) &&
483
+ // Ignore blocks which end in an unreachable. This is a very
484
+ // simple check, but covers most of the cases, e.g. block which
485
+ // calls fatalError().
486
+ !endsInUnreachable (succBlock)) {
487
+ assert (succBlock->getSinglePredecessorBlock () == predBlock &&
488
+ " CFG must not contain critical edge" );
489
+ // Note that since there are no critical edges in the CFG, we are
490
+ // not calling the closure for a leaking successor block twice.
491
+ foundJointPostDomSetCompletionBlocks (succBlock);
492
+ }
493
+ }
494
+ }
495
+ }
496
+ }
509
497
510
498
// Pass back the reachable input blocks that were not reachable from other
511
499
// input blocks to.
512
- for (auto *block : dominatedBlockSet)
513
- if (lower_bound (reachableInputBlocks, block) == reachableInputBlocks.end ())
500
+ for (auto *block : dominatedBlockSet) {
501
+ if (visitedBlocks.contains (block)) {
502
+ inputBlocksFoundDuringWalk (block);
503
+ } else if (inputBlocksInJointPostDomSet) {
514
504
inputBlocksInJointPostDomSet (block);
505
+ }
506
+ }
515
507
}
0 commit comments