|
13 | 13 | #include "llvm/Analysis/LoopInfo.h"
|
14 | 14 | #include "llvm/Analysis/Passes.h"
|
15 | 15 | #include "llvm/Analysis/ValueTracking.h"
|
| 16 | +#include "llvm/Analysis/PostDominators.h" |
16 | 17 | #include "llvm/IR/AssemblyAnnotationWriter.h"
|
17 | 18 | #include "llvm/IR/DataLayout.h"
|
18 | 19 | #include "llvm/IR/InstIterator.h"
|
@@ -353,7 +354,19 @@ ModulePass *llvm::createMustBeExecutedContextPrinter() {
|
353 | 354 | }
|
354 | 355 |
|
355 | 356 | bool MustBeExecutedContextPrinter::runOnModule(Module &M) {
|
356 |
| - MustBeExecutedContextExplorer Explorer(true); |
| 357 | + // We provide non-PM analysis here because the old PM doesn't like to query |
| 358 | + // function passes from a module pass. Given that this is a printer, we don't |
| 359 | + // care much about memory leaks. |
| 360 | + GetterTy<LoopInfo> LIGetter = [this](const Function &F) { |
| 361 | + DominatorTree *DT = new DominatorTree(const_cast<Function &>(F)); |
| 362 | + LoopInfo *LI = new LoopInfo(*DT); |
| 363 | + return LI; |
| 364 | + }; |
| 365 | + GetterTy<PostDominatorTree> PDTGetter = [this](const Function &F) { |
| 366 | + PostDominatorTree *PDT = new PostDominatorTree(const_cast<Function &>(F)); |
| 367 | + return PDT; |
| 368 | + }; |
| 369 | + MustBeExecutedContextExplorer Explorer(true, LIGetter, PDTGetter); |
357 | 370 | for (Function &F : M) {
|
358 | 371 | for (Instruction &I : instructions(F)) {
|
359 | 372 | dbgs() << "-- Explore context of: " << I << "\n";
|
@@ -443,6 +456,173 @@ bool MustExecutePrinter::runOnFunction(Function &F) {
|
443 | 456 | return false;
|
444 | 457 | }
|
445 | 458 |
|
| 459 | +/// Return true if \p L might be an endless loop. |
| 460 | +static bool maybeEndlessLoop(const Loop &L) { |
| 461 | + if (L.getHeader()->getParent()->hasFnAttribute(Attribute::WillReturn)) |
| 462 | + return false; |
| 463 | + // TODO: Actually try to prove it is not. |
| 464 | + // TODO: If maybeEndlessLoop is going to be expensive, cache it. |
| 465 | + return true; |
| 466 | +} |
| 467 | + |
| 468 | +static bool mayContainIrreducibleControl(const Function &F, const LoopInfo *LI) { |
| 469 | + if (!LI) |
| 470 | + return false; |
| 471 | + using RPOTraversal = ReversePostOrderTraversal<const Function *>; |
| 472 | + RPOTraversal FuncRPOT(&F); |
| 473 | + return !containsIrreducibleCFG<const BasicBlock *, const RPOTraversal, |
| 474 | + const LoopInfo>(FuncRPOT, *LI); |
| 475 | +} |
| 476 | + |
| 477 | +/// Lookup \p Key in \p Map and return the result, potentially after |
| 478 | +/// initializing the optional through \p Fn(\p args). |
| 479 | +template <typename K, typename V, typename FnTy, typename... ArgsTy> |
| 480 | +static V getOrCreateCachedOptional(K Key, DenseMap<K, Optional<V>> &Map, |
| 481 | + FnTy &&Fn, ArgsTy&&... args) { |
| 482 | + Optional<V> &OptVal = Map[Key]; |
| 483 | + if (!OptVal.hasValue()) |
| 484 | + OptVal = Fn(std::forward<ArgsTy>(args)...); |
| 485 | + return OptVal.getValue(); |
| 486 | +} |
| 487 | + |
| 488 | +const BasicBlock * |
| 489 | +MustBeExecutedContextExplorer::findForwardJoinPoint(const BasicBlock *InitBB) { |
| 490 | + const LoopInfo *LI = LIGetter(*InitBB->getParent()); |
| 491 | + const PostDominatorTree *PDT = PDTGetter(*InitBB->getParent()); |
| 492 | + |
| 493 | + LLVM_DEBUG(dbgs() << "\tFind forward join point for " << InitBB->getName() |
| 494 | + << (LI ? " [LI]" : "") << (PDT ? " [PDT]" : "")); |
| 495 | + |
| 496 | + const Function &F = *InitBB->getParent(); |
| 497 | + const Loop *L = LI ? LI->getLoopFor(InitBB) : nullptr; |
| 498 | + const BasicBlock *HeaderBB = L ? L->getHeader() : InitBB; |
| 499 | + bool WillReturnAndNoThrow = (F.hasFnAttribute(Attribute::WillReturn) || |
| 500 | + (L && !maybeEndlessLoop(*L))) && |
| 501 | + F.doesNotThrow(); |
| 502 | + LLVM_DEBUG(dbgs() << (L ? " [in loop]" : "") |
| 503 | + << (WillReturnAndNoThrow ? " [WillReturn] [NoUnwind]" : "") |
| 504 | + << "\n"); |
| 505 | + |
| 506 | + // Determine the adjacent blocks in the given direction but exclude (self) |
| 507 | + // loops under certain circumstances. |
| 508 | + SmallVector<const BasicBlock *, 8> Worklist; |
| 509 | + for (const BasicBlock *SuccBB : successors(InitBB)) { |
| 510 | + bool IsLatch = SuccBB == HeaderBB; |
| 511 | + // Loop latches are ignored in forward propagation if the loop cannot be |
| 512 | + // endless and may not throw: control has to go somewhere. |
| 513 | + if (!WillReturnAndNoThrow || !IsLatch) |
| 514 | + Worklist.push_back(SuccBB); |
| 515 | + } |
| 516 | + LLVM_DEBUG(dbgs() << "\t\t#Worklist: " << Worklist.size() << "\n"); |
| 517 | + |
| 518 | + // If there are no other adjacent blocks, there is no join point. |
| 519 | + if (Worklist.empty()) |
| 520 | + return nullptr; |
| 521 | + |
| 522 | + // If there is one adjacent block, it is the join point. |
| 523 | + if (Worklist.size() == 1) |
| 524 | + return Worklist[0]; |
| 525 | + |
| 526 | + // Try to determine a join block through the help of the post-dominance |
| 527 | + // tree. If no tree was provided, we perform simple pattern matching for one |
| 528 | + // block conditionals and one block loops only. |
| 529 | + const BasicBlock *JoinBB = nullptr; |
| 530 | + if (PDT) |
| 531 | + if (const auto *InitNode = PDT->getNode(InitBB)) |
| 532 | + if (const auto *IDomNode = InitNode->getIDom()) |
| 533 | + JoinBB = IDomNode->getBlock(); |
| 534 | + |
| 535 | + if (!JoinBB && Worklist.size() == 2) { |
| 536 | + const BasicBlock *Succ0 = Worklist[0]; |
| 537 | + const BasicBlock *Succ1 = Worklist[1]; |
| 538 | + const BasicBlock *Succ0UniqueSucc = Succ0->getUniqueSuccessor(); |
| 539 | + const BasicBlock *Succ1UniqueSucc = Succ1->getUniqueSuccessor(); |
| 540 | + if (Succ0UniqueSucc == InitBB) { |
| 541 | + // InitBB -> Succ0 -> InitBB |
| 542 | + // InitBB -> Succ1 = JoinBB |
| 543 | + JoinBB = Succ1; |
| 544 | + } else if (Succ1UniqueSucc == InitBB) { |
| 545 | + // InitBB -> Succ1 -> InitBB |
| 546 | + // InitBB -> Succ0 = JoinBB |
| 547 | + JoinBB = Succ0; |
| 548 | + } else if (Succ0 == Succ1UniqueSucc) { |
| 549 | + // InitBB -> Succ0 = JoinBB |
| 550 | + // InitBB -> Succ1 -> Succ0 = JoinBB |
| 551 | + JoinBB = Succ0; |
| 552 | + } else if (Succ1 == Succ0UniqueSucc) { |
| 553 | + // InitBB -> Succ0 -> Succ1 = JoinBB |
| 554 | + // InitBB -> Succ1 = JoinBB |
| 555 | + JoinBB = Succ1; |
| 556 | + } else if (Succ0UniqueSucc == Succ1UniqueSucc) { |
| 557 | + // InitBB -> Succ0 -> JoinBB |
| 558 | + // InitBB -> Succ1 -> JoinBB |
| 559 | + JoinBB = Succ0UniqueSucc; |
| 560 | + } |
| 561 | + } |
| 562 | + |
| 563 | + if (!JoinBB && L) |
| 564 | + JoinBB = L->getUniqueExitBlock(); |
| 565 | + |
| 566 | + if (!JoinBB) |
| 567 | + return nullptr; |
| 568 | + |
| 569 | + LLVM_DEBUG(dbgs() << "\t\tJoin block candidate: " << JoinBB->getName() << "\n"); |
| 570 | + |
| 571 | + // In forward direction we check if control will for sure reach JoinBB from |
| 572 | + // InitBB, thus it can not be "stopped" along the way. Ways to "stop" control |
| 573 | + // are: infinite loops and instructions that do not necessarily transfer |
| 574 | + // execution to their successor. To check for them we traverse the CFG from |
| 575 | + // the adjacent blocks to the JoinBB, looking at all intermediate blocks. |
| 576 | + |
| 577 | + // If we know the function is "will-return" and "no-throw" there is no need |
| 578 | + // for futher checks. |
| 579 | + if (!F.hasFnAttribute(Attribute::WillReturn) || !F.doesNotThrow()) { |
| 580 | + |
| 581 | + auto BlockTransfersExecutionToSuccessor = [](const BasicBlock *BB) { |
| 582 | + return isGuaranteedToTransferExecutionToSuccessor(BB); |
| 583 | + }; |
| 584 | + |
| 585 | + SmallPtrSet<const BasicBlock *, 16> Visited; |
| 586 | + while (!Worklist.empty()) { |
| 587 | + const BasicBlock *ToBB = Worklist.pop_back_val(); |
| 588 | + if (ToBB == JoinBB) |
| 589 | + continue; |
| 590 | + |
| 591 | + // Make sure all loops in-between are finite. |
| 592 | + if (!Visited.insert(ToBB).second) { |
| 593 | + if (!F.hasFnAttribute(Attribute::WillReturn)) { |
| 594 | + if (!LI) |
| 595 | + return nullptr; |
| 596 | + |
| 597 | + bool MayContainIrreducibleControl = getOrCreateCachedOptional( |
| 598 | + &F, IrreducibleControlMap, mayContainIrreducibleControl, F, LI); |
| 599 | + if (MayContainIrreducibleControl) |
| 600 | + return nullptr; |
| 601 | + |
| 602 | + const Loop *L = LI->getLoopFor(ToBB); |
| 603 | + if (L && maybeEndlessLoop(*L)) |
| 604 | + return nullptr; |
| 605 | + } |
| 606 | + |
| 607 | + continue; |
| 608 | + } |
| 609 | + |
| 610 | + // Make sure the block has no instructions that could stop control |
| 611 | + // transfer. |
| 612 | + bool TransfersExecution = getOrCreateCachedOptional( |
| 613 | + ToBB, BlockTransferMap, BlockTransfersExecutionToSuccessor, ToBB); |
| 614 | + if (!TransfersExecution) |
| 615 | + return nullptr; |
| 616 | + |
| 617 | + for (const BasicBlock *AdjacentBB : successors(ToBB)) |
| 618 | + Worklist.push_back(AdjacentBB); |
| 619 | + } |
| 620 | + } |
| 621 | + |
| 622 | + LLVM_DEBUG(dbgs() << "\tJoin block: " << JoinBB->getName() << "\n"); |
| 623 | + return JoinBB; |
| 624 | +} |
| 625 | + |
446 | 626 | const Instruction *
|
447 | 627 | MustBeExecutedContextExplorer::getMustBeExecutedNextInstruction(
|
448 | 628 | MustBeExecutedIterator &It, const Instruction *PP) {
|
@@ -490,6 +670,12 @@ MustBeExecutedContextExplorer::getMustBeExecutedNextInstruction(
|
490 | 670 | return &PP->getSuccessor(0)->front();
|
491 | 671 | }
|
492 | 672 |
|
| 673 | + // Multiple successors mean we need to find the join point where control flow |
| 674 | + // converges again. We use the findForwardJoinPoint helper function with |
| 675 | + // information about the function and helper analyses, if available. |
| 676 | + if (const BasicBlock *JoinBB = findForwardJoinPoint(PP->getParent())) |
| 677 | + return &JoinBB->front(); |
| 678 | + |
493 | 679 | LLVM_DEBUG(dbgs() << "\tNo join point found\n");
|
494 | 680 | return nullptr;
|
495 | 681 | }
|
|
0 commit comments