Reimplement isPotentiallyReachable to make nocapture deduction much stronger.
Adds unit tests for it too.

Split BasicBlockUtils into an analysis-half and a transforms-half, and put the
analysis bits into a new Analysis/CFG.{h,cpp}. Promote isPotentiallyReachable
into llvm::isPotentiallyReachable and move it into Analysis/CFG.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@187283 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/unittests/Analysis/CFGTest.cpp b/unittests/Analysis/CFGTest.cpp
new file mode 100644
index 0000000..2358803
--- /dev/null
+++ b/unittests/Analysis/CFGTest.cpp
@@ -0,0 +1,359 @@
+//===- CFGTest.cpp - CFG tests --------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/CFG.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Analysis/Dominators.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Assembly/Parser.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/InstIterator.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Pass.h"
+#include "llvm/PassManager.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+// This fixture assists in running the isPotentiallyReachable utility four ways
+// and ensuring it produces the correct answer each time.
+class IsPotentiallyReachableTest : public testing::Test {
+protected:
+  void ParseAssembly(const char *Assembly) {
+    M.reset(new Module("Module", getGlobalContext()));
+
+    SMDiagnostic Error;
+    bool Parsed = ParseAssemblyString(Assembly, M.get(),
+                                      Error, M->getContext()) == M.get();
+
+    std::string errMsg;
+    raw_string_ostream os(errMsg);
+    Error.print("", os);
+
+    if (!Parsed) {
+      // A failure here means that the test itself is buggy.
+      report_fatal_error(os.str().c_str());
+    }
+
+    Function *F = M->getFunction("test");
+    if (F == NULL)
+      report_fatal_error("Test must have a function named @test");
+
+    A = B = NULL;
+    for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
+      if (I->hasName()) {
+        if (I->getName() == "A")
+          A = &*I;
+        else if (I->getName() == "B")
+          B = &*I;
+      }
+    }
+    if (A == NULL)
+      report_fatal_error("@test must have an instruction %A");
+    if (B == NULL)
+      report_fatal_error("@test must have an instruction %B");
+  }
+
+  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, 0, true, true);
+        PassRegistry::getPassRegistry()->registerPass(*PI, false);
+        initializeLoopInfoPass(*PassRegistry::getPassRegistry());
+        initializeDominatorTreePass(*PassRegistry::getPassRegistry());
+        return 0;
+      }
+
+      void getAnalysisUsage(AnalysisUsage &AU) const {
+        AU.setPreservesAll();
+        AU.addRequired<LoopInfo>();
+        AU.addRequired<DominatorTree>();
+      }
+
+      bool runOnFunction(Function &F) {
+        if (!F.hasName() || F.getName() != "test")
+          return false;
+
+        LoopInfo *LI = &getAnalysis<LoopInfo>();
+        DominatorTree *DT = &getAnalysis<DominatorTree>();
+        EXPECT_EQ(isPotentiallyReachable(A, B, 0, 0), ExpectedResult);
+        EXPECT_EQ(isPotentiallyReachable(A, B, DT, 0), ExpectedResult);
+        EXPECT_EQ(isPotentiallyReachable(A, B, 0, LI), ExpectedResult);
+        EXPECT_EQ(isPotentiallyReachable(A, B, DT, LI), ExpectedResult);
+        return false;
+      }
+      bool ExpectedResult;
+      Instruction *A, *B;
+    };
+
+    static int initialize = IsPotentiallyReachableTestPass::initialize();
+    (void)initialize;
+
+    IsPotentiallyReachableTestPass *P =
+        new IsPotentiallyReachableTestPass(ExpectedResult, A, B);
+    PassManager PM;
+    PM.add(P);
+    PM.run(*M);
+  }
+private:
+  OwningPtr<Module> M;
+  Instruction *A, *B;
+};
+
+}
+
+TEST_F(IsPotentiallyReachableTest, SameBlockNoPath) {
+  ParseAssembly(
+      "define void @test() {\n"
+      "entry:\n"
+      "  bitcast i8 undef to i8\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  bitcast i8 undef to i8\n"
+      "  bitcast i8 undef to i8\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  ret void\n"
+      "}\n");
+  ExpectPath(false);
+}
+
+TEST_F(IsPotentiallyReachableTest, SameBlockPath) {
+  ParseAssembly(
+      "define void @test() {\n"
+      "entry:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  bitcast i8 undef to i8\n"
+      "  bitcast i8 undef to i8\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  ret void\n"
+      "}\n");
+  ExpectPath(true);
+}
+
+TEST_F(IsPotentiallyReachableTest, StraightNoPath) {
+  ParseAssembly(
+      "define void @test() {\n"
+      "entry:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  br label %exit\n"
+      "exit:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  ret void\n"
+      "}");
+  ExpectPath(false);
+}
+
+TEST_F(IsPotentiallyReachableTest, StraightPath) {
+  ParseAssembly(
+      "define void @test() {\n"
+      "entry:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  br label %exit\n"
+      "exit:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  ret void\n"
+      "}");
+  ExpectPath(true);
+}
+
+TEST_F(IsPotentiallyReachableTest, DestUnreachable) {
+  ParseAssembly(
+      "define void @test() {\n"
+      "entry:\n"
+      "  br label %midblock\n"
+      "midblock:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  ret void\n"
+      "unreachable:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  br label %midblock\n"
+      "}");
+  ExpectPath(false);
+}
+
+TEST_F(IsPotentiallyReachableTest, BranchToReturn) {
+  ParseAssembly(
+      "define void @test(i1 %x) {\n"
+      "entry:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  br i1 %x, label %block1, label %block2\n"
+      "block1:\n"
+      "  ret void\n"
+      "block2:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  ret void\n"
+      "}");
+  ExpectPath(true);
+}
+
+TEST_F(IsPotentiallyReachableTest, SimpleLoop1) {
+  ParseAssembly(
+      "declare i1 @switch()\n"
+      "\n"
+      "define void @test() {\n"
+      "entry:\n"
+      "  br label %loop\n"
+      "loop:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  %x = call i1 @switch()\n"
+      "  br i1 %x, label %loop, label %exit\n"
+      "exit:\n"
+      "  ret void\n"
+      "}");
+  ExpectPath(true);
+}
+
+TEST_F(IsPotentiallyReachableTest, SimpleLoop2) {
+  ParseAssembly(
+      "declare i1 @switch()\n"
+      "\n"
+      "define void @test() {\n"
+      "entry:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  br label %loop\n"
+      "loop:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  %x = call i1 @switch()\n"
+      "  br i1 %x, label %loop, label %exit\n"
+      "exit:\n"
+      "  ret void\n"
+      "}");
+  ExpectPath(false);
+}
+
+TEST_F(IsPotentiallyReachableTest, SimpleLoop3) {
+  ParseAssembly(
+      "declare i1 @switch()\n"
+      "\n"
+      "define void @test() {\n"
+      "entry:\n"
+      "  br label %loop\n"
+      "loop:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  %x = call i1 @switch()\n"
+      "  br i1 %x, label %loop, label %exit\n"
+      "exit:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  ret void\n"
+      "}");
+  ExpectPath(false);
+}
+
+
+TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOther1) {
+  ParseAssembly(
+      "declare i1 @switch()\n"
+      "\n"
+      "define void @test() {\n"
+      "entry:\n"
+      "  br label %loop1\n"
+      "loop1:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  %x = call i1 @switch()\n"
+      "  br i1 %x, label %loop1, label %loop1exit\n"
+      "loop1exit:\n"
+      "  br label %loop2\n"
+      "loop2:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  %y = call i1 @switch()\n"
+      "  br i1 %x, label %loop2, label %loop2exit\n"
+      "loop2exit:"
+      "  ret void\n"
+      "}");
+  ExpectPath(true);
+}
+
+TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOther2) {
+  ParseAssembly(
+      "declare i1 @switch()\n"
+      "\n"
+      "define void @test() {\n"
+      "entry:\n"
+      "  br label %loop1\n"
+      "loop1:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  %x = call i1 @switch()\n"
+      "  br i1 %x, label %loop1, label %loop1exit\n"
+      "loop1exit:\n"
+      "  br label %loop2\n"
+      "loop2:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  %y = call i1 @switch()\n"
+      "  br i1 %x, label %loop2, label %loop2exit\n"
+      "loop2exit:"
+      "  ret void\n"
+      "}");
+  ExpectPath(false);
+}
+
+TEST_F(IsPotentiallyReachableTest, OneLoopAfterTheOtherInsideAThirdLoop) {
+  ParseAssembly(
+      "declare i1 @switch()\n"
+      "\n"
+      "define void @test() {\n"
+      "entry:\n"
+      "  br label %outerloop3\n"
+      "outerloop3:\n"
+      "  br label %innerloop1\n"
+      "innerloop1:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  %x = call i1 @switch()\n"
+      "  br i1 %x, label %innerloop1, label %innerloop1exit\n"
+      "innerloop1exit:\n"
+      "  br label %innerloop2\n"
+      "innerloop2:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  %y = call i1 @switch()\n"
+      "  br i1 %x, label %innerloop2, label %innerloop2exit\n"
+      "innerloop2exit:"
+      "  ;; In outer loop3 now.\n"
+      "  %z = call i1 @switch()\n"
+      "  br i1 %z, label %outerloop3, label %exit\n"
+      "exit:\n"
+      "  ret void\n"
+      "}");
+  ExpectPath(true);
+}
+
+TEST_F(IsPotentiallyReachableTest, BranchInsideLoop) {
+  ParseAssembly(
+      "declare i1 @switch()\n"
+      "\n"
+      "define void @test() {\n"
+      "entry:\n"
+      "  br label %loop\n"
+      "loop:\n"
+      "  %x = call i1 @switch()\n"
+      "  br i1 %x, label %nextloopblock, label %exit\n"
+      "nextloopblock:\n"
+      "  %y = call i1 @switch()\n"
+      "  br i1 %y, label %left, label %right\n"
+      "left:\n"
+      "  %A = bitcast i8 undef to i8\n"
+      "  br label %loop\n"
+      "right:\n"
+      "  %B = bitcast i8 undef to i8\n"
+      "  br label %loop\n"
+      "exit:\n"
+      "  ret void\n"
+      "}");
+  ExpectPath(true);
+}
diff --git a/unittests/Analysis/CMakeLists.txt b/unittests/Analysis/CMakeLists.txt
index 7991a41..5cae68a 100644
--- a/unittests/Analysis/CMakeLists.txt
+++ b/unittests/Analysis/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(LLVM_LINK_COMPONENTS
   Analysis
+  AsmParser
   )
 
 add_llvm_unittest(AnalysisTests
diff --git a/unittests/Analysis/Makefile b/unittests/Analysis/Makefile
index b548d25..527f452 100644
--- a/unittests/Analysis/Makefile
+++ b/unittests/Analysis/Makefile
@@ -9,7 +9,7 @@
 
 LEVEL = ../..
 TESTNAME = Analysis
-LINK_COMPONENTS := analysis
+LINK_COMPONENTS := analysis asmparser
 
 include $(LEVEL)/Makefile.config
 include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest