|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
13 | 13 | #include "swift/SIL/BasicBlockUtils.h"
|
| 14 | +#include "swift/Basic/STLExtras.h" |
14 | 15 | #include "swift/SIL/Dominance.h"
|
15 | 16 | #include "swift/SIL/LoopInfo.h"
|
16 | 17 | #include "swift/SIL/SILArgument.h"
|
17 | 18 | #include "swift/SIL/SILBasicBlock.h"
|
18 | 19 | #include "swift/SIL/SILBuilder.h"
|
19 | 20 | #include "swift/SIL/SILFunction.h"
|
20 | 21 | #include "swift/SIL/TerminatorUtils.h"
|
| 22 | +#include "llvm/ADT/STLExtras.h" |
21 | 23 |
|
22 | 24 | using namespace swift;
|
23 | 25 |
|
@@ -378,3 +380,111 @@ void DeadEndBlocks::compute() {
|
378 | 380 | ReachableBlocks.insert(Pred);
|
379 | 381 | }
|
380 | 382 | }
|
| 383 | + |
| 384 | +//===----------------------------------------------------------------------===// |
| 385 | +// Post Dominance Set Completion Utilities |
| 386 | +//===----------------------------------------------------------------------===// |
| 387 | + |
| 388 | +void JointPostDominanceSetComputer::findJointPostDominatingSet( |
| 389 | + SILBasicBlock *dominatingBlock, ArrayRef<SILBasicBlock *> dominatedBlockSet, |
| 390 | + function_ref<void(SILBasicBlock *)> foundInputBlocksNotInJointPostDomSet, |
| 391 | + function_ref<void(SILBasicBlock *)> foundJointPostDomSetCompletionBlocks, |
| 392 | + function_ref<void(SILBasicBlock *)> foundInputBlocksInJointPostDomSet) { |
| 393 | + // If our reachable block set is empty, assert. This is most likely programmer |
| 394 | + // error. |
| 395 | + assert(dominatedBlockSet.size() != 0); |
| 396 | + |
| 397 | + // If we have a reachable block set with a single block and that block is |
| 398 | + // dominatingBlock, then we return success since a block post-doms its self so |
| 399 | + // it is already complete. |
| 400 | + if (dominatedBlockSet.size() == 1) { |
| 401 | + if (dominatingBlock == dominatedBlockSet[0]) { |
| 402 | + if (foundInputBlocksInJointPostDomSet) |
| 403 | + foundInputBlocksInJointPostDomSet(dominatingBlock); |
| 404 | + return; |
| 405 | + } |
| 406 | + } |
| 407 | + |
| 408 | + // At the top of where we for sure are going to use state... make sure we |
| 409 | + // always clean up any resources that we use! |
| 410 | + SWIFT_DEFER { clear(); }; |
| 411 | + |
| 412 | + // Otherwise, we need to compute our joint post dominating set. We do this by |
| 413 | + // performing a backwards walk up the CFG tracking back liveness until we find |
| 414 | + // our dominating block. As we walk up, we keep track of any successor blocks |
| 415 | + // that we need to visit before the walk completes lest we leak. After we |
| 416 | + // finish the walk, these leaking blocks are a valid (albeit not unique) |
| 417 | + // completion of the post dom set. |
| 418 | + for (auto *block : dominatedBlockSet) { |
| 419 | + // Skip dead end blocks. |
| 420 | + if (deadEndBlocks.isDeadEnd(block)) |
| 421 | + continue; |
| 422 | + |
| 423 | + // We require dominatedBlockSet to be a set and thus assert if we hit it to |
| 424 | + // flag user error to our caller. |
| 425 | + bool succeededInserting = visitedBlocks.insert(block).second; |
| 426 | + (void)succeededInserting; |
| 427 | + assert(succeededInserting && |
| 428 | + "Repeat Elt: dominatedBlockSet should be a set?!"); |
| 429 | + initialBlocks.insert(block); |
| 430 | + worklist.push_back(block); |
| 431 | + } |
| 432 | + |
| 433 | + // Then until we run out of blocks... |
| 434 | + while (!worklist.empty()) { |
| 435 | + auto *block = worklist.pop_back_val(); |
| 436 | + |
| 437 | + // First remove block from blocksThatLeakIfNeverVisited if it is there since |
| 438 | + // we know that it isn't leaking since we are visiting it now. |
| 439 | + blocksThatLeakIfNeverVisited.remove(block); |
| 440 | + |
| 441 | + // Then if our block is not one of our initial blocks, add the block's |
| 442 | + // successors to blocksThatLeakIfNeverVisited. |
| 443 | + if (!initialBlocks.count(block)) { |
| 444 | + for (auto *succBlock : block->getSuccessorBlocks()) { |
| 445 | + if (visitedBlocks.count(succBlock)) |
| 446 | + continue; |
| 447 | + if (deadEndBlocks.isDeadEnd(succBlock)) |
| 448 | + continue; |
| 449 | + blocksThatLeakIfNeverVisited.insert(succBlock); |
| 450 | + } |
| 451 | + } |
| 452 | + |
| 453 | + // If we are the dominating block, we are done. |
| 454 | + if (dominatingBlock == block) |
| 455 | + continue; |
| 456 | + |
| 457 | + // Otherwise for each predecessor that we have, first check if it was one of |
| 458 | + // our initial blocks (signaling a loop) and then add it to the worklist if |
| 459 | + // we haven't visited it already. |
| 460 | + for (auto *predBlock : block->getPredecessorBlocks()) { |
| 461 | + if (initialBlocks.count(predBlock)) { |
| 462 | + reachableInputBlocks.push_back(predBlock); |
| 463 | + } |
| 464 | + if (visitedBlocks.insert(predBlock).second) |
| 465 | + worklist.push_back(predBlock); |
| 466 | + } |
| 467 | + } |
| 468 | + |
| 469 | + // After our worklist has emptied, any blocks left in |
| 470 | + // blocksThatLeakIfNeverVisited are "leaking blocks". |
| 471 | + for (auto *leakingBlock : blocksThatLeakIfNeverVisited) |
| 472 | + foundJointPostDomSetCompletionBlocks(leakingBlock); |
| 473 | + |
| 474 | + // Then unique our list of reachable input blocks and pass them to our |
| 475 | + // callback. |
| 476 | + sortUnique(reachableInputBlocks); |
| 477 | + for (auto *block : reachableInputBlocks) |
| 478 | + foundInputBlocksNotInJointPostDomSet(block); |
| 479 | + |
| 480 | + // Then if were asked to find the subset of our input blocks that are in the |
| 481 | + // joint-postdominance set, compute that. |
| 482 | + if (!foundInputBlocksInJointPostDomSet) |
| 483 | + return; |
| 484 | + |
| 485 | + // Pass back the reachable input blocks that were not reachable from other |
| 486 | + // input blocks to. |
| 487 | + for (auto *block : dominatedBlockSet) |
| 488 | + if (lower_bound(reachableInputBlocks, block) == reachableInputBlocks.end()) |
| 489 | + foundInputBlocksInJointPostDomSet(block); |
| 490 | +} |
0 commit comments