[llvm] r357447 - Add an optional list of blocks to avoid when looking for a path in isPotentiallyReachable.

Nick Lewycky via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 1 18:05:48 PDT 2019


Author: nicholas
Date: Mon Apr  1 18:05:48 2019
New Revision: 357447

URL: http://llvm.org/viewvc/llvm-project?rev=357447&view=rev
Log:
Add an optional list of blocks to avoid when looking for a path in isPotentiallyReachable.

The leads to some ambiguous overloads, so update three callers.

Differential Revision: https://reviews.llvm.org/D60085

Modified:
    llvm/trunk/include/llvm/Analysis/CFG.h
    llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
    llvm/trunk/lib/Analysis/CFG.cpp
    llvm/trunk/lib/Analysis/CaptureTracking.cpp
    llvm/trunk/lib/CodeGen/DwarfEHPrepare.cpp
    llvm/trunk/unittests/Analysis/CFGTest.cpp

Modified: llvm/trunk/include/llvm/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/CFG.h?rev=357447&r1=357446&r2=357447&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/CFG.h (original)
+++ llvm/trunk/include/llvm/Analysis/CFG.h Mon Apr  1 18:05:48 2019
@@ -47,8 +47,8 @@ unsigned GetSuccessorNumber(const BasicB
 bool isCriticalEdge(const Instruction *TI, unsigned SuccNum,
                     bool AllowIdenticalEdges = false);
 
-/// Determine whether instruction 'To' is reachable from 'From',
-/// returning true if uncertain.
+/// Determine whether instruction 'To' is reachable from 'From', without passing
+/// through any blocks in ExclusionSet, returning true if uncertain.
 ///
 /// Determine whether there is a path from From to To within a single function.
 /// Returns false only if we can prove that once 'From' has been executed then
@@ -62,9 +62,10 @@ bool isCriticalEdge(const Instruction *T
 /// we find a block that dominates the block containing 'To'. DT is most useful
 /// on branchy code but not loops, and LI is most useful on code with loops but
 /// does not help on branchy code outside loops.
-bool isPotentiallyReachable(const Instruction *From, const Instruction *To,
-                            const DominatorTree *DT = nullptr,
-                            const LoopInfo *LI = nullptr);
+bool isPotentiallyReachable(
+    const Instruction *From, const Instruction *To,
+    const SmallPtrSetImpl<BasicBlock *> *ExclusionSet = nullptr,
+    const DominatorTree *DT = nullptr, const LoopInfo *LI = nullptr);
 
 /// Determine whether block 'To' is reachable from 'From', returning
 /// true if uncertain.
@@ -88,6 +89,20 @@ bool isPotentiallyReachableFromMany(Smal
                                     const DominatorTree *DT = nullptr,
                                     const LoopInfo *LI = nullptr);
 
+/// Determine whether there is at least one path from a block in
+/// 'Worklist' to 'StopBB' without passing through any blocks in
+/// 'ExclusionSet', returning true if uncertain.
+///
+/// Determine whether there is a path from at least one block in Worklist to
+/// StopBB within a single function without passing through any of the blocks
+/// in 'ExclusionSet'. Returns false only if we can prove that once any block
+/// in 'Worklist' has been reached then 'StopBB' can not be executed.
+/// Conservatively returns true.
+bool isPotentiallyReachableFromMany(
+    SmallVectorImpl<BasicBlock *> &Worklist, BasicBlock *StopBB,
+    const SmallPtrSetImpl<BasicBlock *> *ExclusionSet,
+    const DominatorTree *DT = nullptr, const LoopInfo *LI = nullptr);
+
 /// Return true if the control flow in \p RPOTraversal is irreducible.
 ///
 /// This is a generic implementation to detect CFG irreducibility based on loop

Modified: llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp?rev=357447&r1=357446&r2=357447&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp Mon Apr  1 18:05:48 2019
@@ -1906,7 +1906,7 @@ bool BasicAAResult::isValueEqualInPotent
   // the Values cannot come from different iterations of a potential cycle the
   // phi nodes could be involved in.
   for (auto *P : VisitedPhiBBs)
-    if (isPotentiallyReachable(&P->front(), Inst, DT, LI))
+    if (isPotentiallyReachable(&P->front(), Inst, nullptr, DT, LI))
       return false;
 
   return true;

Modified: llvm/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFG.cpp?rev=357447&r1=357446&r2=357447&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CFG.cpp (original)
+++ llvm/trunk/lib/Analysis/CFG.cpp Mon Apr  1 18:05:48 2019
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Analysis/CFG.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/IR/Dominators.h"
@@ -119,22 +120,33 @@ static const Loop *getOutermostLoop(cons
   return L;
 }
 
-// True if there is a loop which contains both BB1 and BB2.
-static bool loopContainsBoth(const LoopInfo *LI,
-                             const BasicBlock *BB1, const BasicBlock *BB2) {
-  const Loop *L1 = getOutermostLoop(LI, BB1);
-  const Loop *L2 = getOutermostLoop(LI, BB2);
-  return L1 != nullptr && L1 == L2;
-}
-
 bool llvm::isPotentiallyReachableFromMany(
     SmallVectorImpl<BasicBlock *> &Worklist, BasicBlock *StopBB,
-    const DominatorTree *DT, const LoopInfo *LI) {
+    const SmallPtrSetImpl<BasicBlock *> *ExclusionSet, const DominatorTree *DT,
+    const LoopInfo *LI) {
   // When the stop block is unreachable, it's dominated from everywhere,
   // regardless of whether there's a path between the two blocks.
   if (DT && !DT->isReachableFromEntry(StopBB))
     DT = nullptr;
 
+  // We can't skip directly from a block that dominates the stop block if the
+  // exclusion block is potentially in between.
+  if (ExclusionSet && !ExclusionSet->empty())
+    DT = nullptr;
+
+  // Normally any block in a loop is reachable from any other block in a loop,
+  // however excluded blocks might partition the body of a loop to make that
+  // untrue.
+  SmallPtrSet<const Loop *, 8> LoopsWithHoles;
+  if (LI && ExclusionSet) {
+    for (auto BB : *ExclusionSet) {
+      if (const Loop *L = getOutermostLoop(LI, BB))
+        LoopsWithHoles.insert(L);
+    }
+  }
+
+  const Loop *StopLoop = LI ? getOutermostLoop(LI, StopBB) : nullptr;
+
   // Limit the number of blocks we visit. The goal is to avoid run-away compile
   // times on large CFGs without hampering sensible code. Arbitrarily chosen.
   unsigned Limit = 32;
@@ -145,10 +157,23 @@ bool llvm::isPotentiallyReachableFromMan
       continue;
     if (BB == StopBB)
       return true;
+    if (ExclusionSet && ExclusionSet->count(BB))
+      continue;
     if (DT && DT->dominates(BB, StopBB))
       return true;
-    if (LI && loopContainsBoth(LI, BB, StopBB))
-      return true;
+
+    const Loop *Outer = nullptr;
+    if (LI) {
+      Outer = getOutermostLoop(LI, BB);
+      // If we're in a loop with a hole, not all blocks in the loop are
+      // reachable from all other blocks. That implies we can't simply jump to
+      // the loop's exit blocks, as that exit might need to pass through an
+      // excluded block. Clear Outer so we process BB's successors.
+      if (LoopsWithHoles.count(Outer))
+        Outer = nullptr;
+      if (StopLoop && Outer == StopLoop)
+        return true;
+    }
 
     if (!--Limit) {
       // We haven't been able to prove it one way or the other. Conservatively
@@ -156,7 +181,7 @@ bool llvm::isPotentiallyReachableFromMan
       return true;
     }
 
-    if (const Loop *Outer = LI ? getOutermostLoop(LI, BB) : nullptr) {
+    if (Outer) {
       // All blocks in a single loop are reachable from all other blocks. From
       // any of these blocks, we can skip directly to the exits of the loop,
       // ignoring any other blocks inside the loop body.
@@ -180,11 +205,13 @@ bool llvm::isPotentiallyReachable(const
   Worklist.push_back(const_cast<BasicBlock*>(A));
 
   return isPotentiallyReachableFromMany(Worklist, const_cast<BasicBlock *>(B),
-                                        DT, LI);
+                                        nullptr, DT, LI);
 }
 
-bool llvm::isPotentiallyReachable(const Instruction *A, const Instruction *B,
-                                  const DominatorTree *DT, const LoopInfo *LI) {
+bool llvm::isPotentiallyReachable(
+    const Instruction *A, const Instruction *B,
+    const SmallPtrSetImpl<BasicBlock *> *ExclusionSet, const DominatorTree *DT,
+    const LoopInfo *LI) {
   assert(A->getParent()->getParent() == B->getParent()->getParent() &&
          "This analysis is function-local!");
 
@@ -230,14 +257,16 @@ bool llvm::isPotentiallyReachable(const
     if (DT->isReachableFromEntry(A->getParent()) !=
         DT->isReachableFromEntry(B->getParent()))
       return false;
-    if (A->getParent() == &A->getParent()->getParent()->getEntryBlock() &&
-        DT->isReachableFromEntry(B->getParent()))
-      return true;
-    if (B->getParent() == &A->getParent()->getParent()->getEntryBlock() &&
-        DT->isReachableFromEntry(A->getParent()))
-      return false;
+    if (!ExclusionSet || ExclusionSet->empty()) {
+      if (A->getParent() == &A->getParent()->getParent()->getEntryBlock() &&
+          DT->isReachableFromEntry(B->getParent()))
+        return true;
+      if (B->getParent() == &A->getParent()->getParent()->getEntryBlock() &&
+          DT->isReachableFromEntry(A->getParent()))
+        return false;
+    }
   }
 
   return isPotentiallyReachableFromMany(
-      Worklist, const_cast<BasicBlock *>(B->getParent()), DT, LI);
+      Worklist, const_cast<BasicBlock *>(B->getParent()), ExclusionSet, DT, LI);
 }

Modified: llvm/trunk/lib/Analysis/CaptureTracking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CaptureTracking.cpp?rev=357447&r1=357446&r2=357447&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CaptureTracking.cpp (original)
+++ llvm/trunk/lib/Analysis/CaptureTracking.cpp Mon Apr  1 18:05:48 2019
@@ -101,14 +101,14 @@ namespace {
 
         SmallVector<BasicBlock*, 32> Worklist;
         Worklist.append(succ_begin(BB), succ_end(BB));
-        return !isPotentiallyReachableFromMany(Worklist, BB, DT);
+        return !isPotentiallyReachableFromMany(Worklist, BB, nullptr, DT);
       }
 
       // If the value is defined in the same basic block as use and BeforeHere,
       // there is no need to explore the use if BeforeHere dominates use.
       // Check whether there is a path from I to BeforeHere.
       if (BeforeHere != I && DT->dominates(BeforeHere, I) &&
-          !isPotentiallyReachable(I, BeforeHere, DT))
+          !isPotentiallyReachable(I, BeforeHere, nullptr, DT))
         return true;
 
       return false;

Modified: llvm/trunk/lib/CodeGen/DwarfEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/DwarfEHPrepare.cpp?rev=357447&r1=357446&r2=357447&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/DwarfEHPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/DwarfEHPrepare.cpp Mon Apr  1 18:05:48 2019
@@ -145,7 +145,7 @@ size_t DwarfEHPrepare::pruneUnreachableR
   size_t ResumeIndex = 0;
   for (auto *RI : Resumes) {
     for (auto *LP : CleanupLPads) {
-      if (isPotentiallyReachable(LP, RI, DT)) {
+      if (isPotentiallyReachable(LP, RI, nullptr, DT)) {
         ResumeReachable.set(ResumeIndex);
         break;
       }

Modified: llvm/trunk/unittests/Analysis/CFGTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Analysis/CFGTest.cpp?rev=357447&r1=357446&r2=357447&view=diff
==============================================================================
--- llvm/trunk/unittests/Analysis/CFGTest.cpp (original)
+++ llvm/trunk/unittests/Analysis/CFGTest.cpp Mon Apr  1 18:05:48 2019
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Analysis/CFG.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/AsmParser/Parser.h"
 #include "llvm/IR/Dominators.h"
@@ -57,24 +58,32 @@ protected:
       report_fatal_error("@test must have an instruction %A");
     if (B == nullptr)
       report_fatal_error("@test must have an instruction %B");
+
+    assert(ExclusionSet.empty());
+    for (auto I = F->begin(), E = F->end(); I != E; ++I) {
+      if (I->hasName() && I->getName().startswith("excluded"))
+        ExclusionSet.insert(&*I);
+    }
   }
 
   void ExpectPath(bool ExpectedResult) {
     static char ID;
     class IsPotentiallyReachableTestPass : public FunctionPass {
      public:
-      IsPotentiallyReachableTestPass(bool ExpectedResult,
-                                     Instruction *A, Instruction *B)
-          : FunctionPass(ID), ExpectedResult(ExpectedResult), A(A), B(B) {}
-
-      static int initialize() {
-        PassInfo *PI = new PassInfo("isPotentiallyReachable testing pass",
-                                    "", &ID, nullptr, true, true);
-        PassRegistry::getPassRegistry()->registerPass(*PI, false);
-        initializeLoopInfoWrapperPassPass(*PassRegistry::getPassRegistry());
-        initializeDominatorTreeWrapperPassPass(
-            *PassRegistry::getPassRegistry());
-        return 0;
+       IsPotentiallyReachableTestPass(bool ExpectedResult, Instruction *A,
+                                      Instruction *B,
+                                      SmallPtrSet<BasicBlock *, 4> ExclusionSet)
+           : FunctionPass(ID), ExpectedResult(ExpectedResult), A(A), B(B),
+             ExclusionSet(ExclusionSet) {}
+
+       static int initialize() {
+         PassInfo *PI = new PassInfo("isPotentiallyReachable testing pass", "",
+                                     &ID, nullptr, true, true);
+         PassRegistry::getPassRegistry()->registerPass(*PI, false);
+         initializeLoopInfoWrapperPassPass(*PassRegistry::getPassRegistry());
+         initializeDominatorTreeWrapperPassPass(
+             *PassRegistry::getPassRegistry());
+         return 0;
       }
 
       void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -90,22 +99,26 @@ protected:
         LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
         DominatorTree *DT =
             &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
-        EXPECT_EQ(isPotentiallyReachable(A, B, nullptr, nullptr),
+        EXPECT_EQ(isPotentiallyReachable(A, B, &ExclusionSet, nullptr, nullptr),
+                  ExpectedResult);
+        EXPECT_EQ(isPotentiallyReachable(A, B, &ExclusionSet, DT, nullptr),
+                  ExpectedResult);
+        EXPECT_EQ(isPotentiallyReachable(A, B, &ExclusionSet, nullptr, LI),
+                  ExpectedResult);
+        EXPECT_EQ(isPotentiallyReachable(A, B, &ExclusionSet, DT, LI),
                   ExpectedResult);
-        EXPECT_EQ(isPotentiallyReachable(A, B, DT, nullptr), ExpectedResult);
-        EXPECT_EQ(isPotentiallyReachable(A, B, nullptr, LI), ExpectedResult);
-        EXPECT_EQ(isPotentiallyReachable(A, B, DT, LI), ExpectedResult);
         return false;
       }
       bool ExpectedResult;
       Instruction *A, *B;
+      SmallPtrSet<BasicBlock *, 4> ExclusionSet;
     };
 
     static int initialize = IsPotentiallyReachableTestPass::initialize();
     (void)initialize;
 
     IsPotentiallyReachableTestPass *P =
-        new IsPotentiallyReachableTestPass(ExpectedResult, A, B);
+        new IsPotentiallyReachableTestPass(ExpectedResult, A, B, ExclusionSet);
     legacy::PassManager PM;
     PM.add(P);
     PM.run(*M);
@@ -114,6 +127,7 @@ protected:
   LLVMContext Context;
   std::unique_ptr<Module> M;
   Instruction *A, *B;
+  SmallPtrSet<BasicBlock *, 4> ExclusionSet;
 };
 
 }
@@ -425,3 +439,55 @@ TEST_F(IsPotentiallyReachableTest, Unrea
                 "}");
   ExpectPath(false);
 }
+
+TEST_F(IsPotentiallyReachableTest, SimpleExclusionTest) {
+  ParseAssembly("define void @test() {\n"
+                "entry:\n"
+                "  %A = bitcast i8 undef to i8\n"
+                "  br label %excluded\n"
+                "excluded:\n"
+                "  br label %exit\n"
+                "exit:\n"
+                "  %B = bitcast i8 undef to i8\n"
+                "  ret void\n"
+                "}");
+  ExpectPath(false);
+}
+
+TEST_F(IsPotentiallyReachableTest, DiamondExcludedTest) {
+  ParseAssembly("declare i1 @switch()\n"
+                "\n"
+                "define void @test() {\n"
+                "entry:\n"
+                "  %x = call i1 @switch()\n"
+                "  %A = bitcast i8 undef to i8\n"
+                "  br i1 %x, label %excluded.1, label %excluded.2\n"
+                "excluded.1:\n"
+                "  br label %exit\n"
+                "excluded.2:\n"
+                "  br label %exit\n"
+                "exit:\n"
+                "  %B = bitcast i8 undef to i8\n"
+                "  ret void\n"
+                "}");
+  ExpectPath(false);
+}
+
+TEST_F(IsPotentiallyReachableTest, DiamondOneSideExcludedTest) {
+  ParseAssembly("declare i1 @switch()\n"
+                "\n"
+                "define void @test() {\n"
+                "entry:\n"
+                "  %x = call i1 @switch()\n"
+                "  %A = bitcast i8 undef to i8\n"
+                "  br i1 %x, label %excluded, label %diamond\n"
+                "excluded:\n"
+                "  br label %exit\n"
+                "diamond:\n"
+                "  br label %exit\n"
+                "exit:\n"
+                "  %B = bitcast i8 undef to i8\n"
+                "  ret void\n"
+                "}");
+  ExpectPath(true);
+}




More information about the llvm-commits mailing list