[llvm] r206954 - [LCG] Add a unittest for the LazyCallGraph. I had a weak moment and

Evgeniy Stepanov eugeni.stepanov at gmail.com
Wed Apr 23 04:14:58 PDT 2014


GCC warns:
../unittests/Analysis/LazyCallGraphTest.cpp:45:1: warning: multi-line comment

Does Clang miss this diagnostic?


On Wed, Apr 23, 2014 at 12:08 PM, Chandler Carruth <chandlerc at gmail.com> wrote:
> Author: chandlerc
> Date: Wed Apr 23 03:08:49 2014
> New Revision: 206954
>
> URL: http://llvm.org/viewvc/llvm-project?rev=206954&view=rev
> Log:
> [LCG] Add a unittest for the LazyCallGraph. I had a weak moment and
> resisted this for too long. Just with the basic testing here I was able
> to exercise the analysis in more detail and sift out both type signature
> bugs in the API and a bug in the DFS numbering. All of these are fixed
> here as well.
>
> The unittests will be much more important for the mutation support where
> it is necessary to craft minimal mutations and then inspect the state of
> the graph. There is just no way to do that with a standard FileCheck
> test. However, unittesting these kinds of analyses is really quite easy,
> especially as they're designed with the new pass manager where there is
> essentially no infrastructure required to rig up the core logic and
> exercise it at an API level.
>
> As a minor aside about the DFS numbering bug, the DFS numbering used in
> LCG is a bit unusual. Rather than numbering from 0, we number from 1,
> and use 0 as the sentinel "unvisited" state. Other implementations often
> use '-1' for this, but I find it easier to deal with 0 and it shouldn't
> make any real difference provided someone doesn't write silly bugs like
> forgetting to actually initialize the DFS numbering. Oops. ;]
>
> Added:
>     llvm/trunk/unittests/Analysis/LazyCallGraphTest.cpp
> Modified:
>     llvm/trunk/include/llvm/Analysis/LazyCallGraph.h
>     llvm/trunk/lib/Analysis/LazyCallGraph.cpp
>     llvm/trunk/unittests/Analysis/CMakeLists.txt
>
> Modified: llvm/trunk/include/llvm/Analysis/LazyCallGraph.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LazyCallGraph.h?rev=206954&r1=206953&r2=206954&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/Analysis/LazyCallGraph.h (original)
> +++ llvm/trunk/include/llvm/Analysis/LazyCallGraph.h Wed Apr 23 03:08:49 2014
> @@ -134,8 +134,8 @@ public:
>          : G(&G), NI(Nodes.end()) {}
>
>    public:
> -    bool operator==(const iterator &Arg) { return NI == Arg.NI; }
> -    bool operator!=(const iterator &Arg) { return !operator==(Arg); }
> +    bool operator==(const iterator &Arg) const { return NI == Arg.NI; }
> +    bool operator!=(const iterator &Arg) const { return !operator==(Arg); }
>
>      reference operator*() const {
>        if (NI->is<Node *>())
> @@ -260,10 +260,10 @@ public:
>          : G(&G), C(nullptr) {}
>
>    public:
> -    bool operator==(const postorder_scc_iterator &Arg) {
> +    bool operator==(const postorder_scc_iterator &Arg) const {
>        return G == Arg.G && C == Arg.C;
>      }
> -    bool operator!=(const postorder_scc_iterator &Arg) {
> +    bool operator!=(const postorder_scc_iterator &Arg) const {
>        return !operator==(Arg);
>      }
>
>
> Modified: llvm/trunk/lib/Analysis/LazyCallGraph.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LazyCallGraph.cpp?rev=206954&r1=206953&r2=206954&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/LazyCallGraph.cpp (original)
> +++ llvm/trunk/lib/Analysis/LazyCallGraph.cpp Wed Apr 23 03:08:49 2014
> @@ -203,6 +203,8 @@ LazyCallGraph::SCC *LazyCallGraph::getNe
>      if (SCCEntryNodes.empty())
>        return nullptr;
>
> +    // Reset the DFS numbering.
> +    NextDFSNumber = 1;
>      Node *N = get(*SCCEntryNodes.pop_back_val());
>      DFSStack.push_back(std::make_pair(N, N->begin()));
>    }
>
> Modified: llvm/trunk/unittests/Analysis/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Analysis/CMakeLists.txt?rev=206954&r1=206953&r2=206954&view=diff
> ==============================================================================
> --- llvm/trunk/unittests/Analysis/CMakeLists.txt (original)
> +++ llvm/trunk/unittests/Analysis/CMakeLists.txt Wed Apr 23 03:08:49 2014
> @@ -7,5 +7,6 @@ set(LLVM_LINK_COMPONENTS
>
>  add_llvm_unittest(AnalysisTests
>    CFGTest.cpp
> +  LazyCallGraphTest.cpp
>    ScalarEvolutionTest.cpp
>    )
>
> Added: llvm/trunk/unittests/Analysis/LazyCallGraphTest.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Analysis/LazyCallGraphTest.cpp?rev=206954&view=auto
> ==============================================================================
> --- llvm/trunk/unittests/Analysis/LazyCallGraphTest.cpp (added)
> +++ llvm/trunk/unittests/Analysis/LazyCallGraphTest.cpp Wed Apr 23 03:08:49 2014
> @@ -0,0 +1,251 @@
> +//===- LazyCallGraphTest.cpp - Unit tests for the lazy CG analysis --------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/Analysis/LazyCallGraph.h"
> +#include "llvm/AsmParser/Parser.h"
> +#include "llvm/IR/Function.h"
> +#include "llvm/IR/LLVMContext.h"
> +#include "llvm/IR/Module.h"
> +#include "llvm/Support/ErrorHandling.h"
> +#include "llvm/Support/SourceMgr.h"
> +#include "gtest/gtest.h"
> +#include <memory>
> +
> +using namespace llvm;
> +
> +namespace {
> +
> +std::unique_ptr<Module> parseAssembly(const char *Assembly) {
> +  auto M = make_unique<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);
> +
> +  // A failure here means that the test itself is buggy.
> +  if (!Parsed)
> +    report_fatal_error(OS.str().c_str());
> +
> +  return M;
> +}
> +
> +// IR forming a call graph with a diamond of triangle-shaped SCCs:
> +//
> +//         d1
> +//        /  \
> +//       d3--d2
> +//      /     \
> +//     b1     c1
> +//   /  \    /  \
> +//  b3--b2  c3--c2
> +//       \  /
> +//        a1
> +//       /  \
> +//      a3--a2
> +//
> +// All call edges go up between SCCs, and clockwise around the SCC.
> +static const char DiamondOfTriangles[] =
> +     "define void @a1() {\n"
> +     "entry:\n"
> +     "  call void @a2()\n"
> +     "  call void @b2()\n"
> +     "  call void @c3()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @a2() {\n"
> +     "entry:\n"
> +     "  call void @a3()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @a3() {\n"
> +     "entry:\n"
> +     "  call void @a1()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @b1() {\n"
> +     "entry:\n"
> +     "  call void @b2()\n"
> +     "  call void @d3()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @b2() {\n"
> +     "entry:\n"
> +     "  call void @b3()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @b3() {\n"
> +     "entry:\n"
> +     "  call void @b1()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @c1() {\n"
> +     "entry:\n"
> +     "  call void @c2()\n"
> +     "  call void @d2()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @c2() {\n"
> +     "entry:\n"
> +     "  call void @c3()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @c3() {\n"
> +     "entry:\n"
> +     "  call void @c1()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @d1() {\n"
> +     "entry:\n"
> +     "  call void @d2()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @d2() {\n"
> +     "entry:\n"
> +     "  call void @d3()\n"
> +     "  ret void\n"
> +     "}\n"
> +     "define void @d3() {\n"
> +     "entry:\n"
> +     "  call void @d1()\n"
> +     "  ret void\n"
> +     "}\n";
> +
> +TEST(LazyCallGraphTest, BasicGraphFormation) {
> +  std::unique_ptr<Module> M = parseAssembly(DiamondOfTriangles);
> +  LazyCallGraph CG(*M);
> +
> +  // The order of the entry nodes should be stable w.r.t. the source order of
> +  // the IR, and everything in our module is an entry node, so just directly
> +  // build variables for each node.
> +  auto I = CG.begin();
> +  LazyCallGraph::Node *A1 = *I++;
> +  EXPECT_EQ("a1", A1->getFunction().getName());
> +  LazyCallGraph::Node *A2 = *I++;
> +  EXPECT_EQ("a2", A2->getFunction().getName());
> +  LazyCallGraph::Node *A3 = *I++;
> +  EXPECT_EQ("a3", A3->getFunction().getName());
> +  LazyCallGraph::Node *B1 = *I++;
> +  EXPECT_EQ("b1", B1->getFunction().getName());
> +  LazyCallGraph::Node *B2 = *I++;
> +  EXPECT_EQ("b2", B2->getFunction().getName());
> +  LazyCallGraph::Node *B3 = *I++;
> +  EXPECT_EQ("b3", B3->getFunction().getName());
> +  LazyCallGraph::Node *C1 = *I++;
> +  EXPECT_EQ("c1", C1->getFunction().getName());
> +  LazyCallGraph::Node *C2 = *I++;
> +  EXPECT_EQ("c2", C2->getFunction().getName());
> +  LazyCallGraph::Node *C3 = *I++;
> +  EXPECT_EQ("c3", C3->getFunction().getName());
> +  LazyCallGraph::Node *D1 = *I++;
> +  EXPECT_EQ("d1", D1->getFunction().getName());
> +  LazyCallGraph::Node *D2 = *I++;
> +  EXPECT_EQ("d2", D2->getFunction().getName());
> +  LazyCallGraph::Node *D3 = *I++;
> +  EXPECT_EQ("d3", D3->getFunction().getName());
> +  EXPECT_EQ(CG.end(), I);
> +
> +  // Build vectors and sort them for the rest of the assertions to make them
> +  // independent of order.
> +  std::vector<std::string> Nodes;
> +
> +  for (LazyCallGraph::Node *N : *A1)
> +    Nodes.push_back(N->getFunction().getName());
> +  std::sort(Nodes.begin(), Nodes.end());
> +  EXPECT_EQ("a2", Nodes[0]);
> +  EXPECT_EQ("b2", Nodes[1]);
> +  EXPECT_EQ("c3", Nodes[2]);
> +  Nodes.clear();
> +
> +  EXPECT_EQ(A2->end(), std::next(A2->begin()));
> +  EXPECT_EQ("a3", A2->begin()->getFunction().getName());
> +  EXPECT_EQ(A3->end(), std::next(A3->begin()));
> +  EXPECT_EQ("a1", A3->begin()->getFunction().getName());
> +
> +  for (LazyCallGraph::Node *N : *B1)
> +    Nodes.push_back(N->getFunction().getName());
> +  std::sort(Nodes.begin(), Nodes.end());
> +  EXPECT_EQ("b2", Nodes[0]);
> +  EXPECT_EQ("d3", Nodes[1]);
> +  Nodes.clear();
> +
> +  EXPECT_EQ(B2->end(), std::next(B2->begin()));
> +  EXPECT_EQ("b3", B2->begin()->getFunction().getName());
> +  EXPECT_EQ(B3->end(), std::next(B3->begin()));
> +  EXPECT_EQ("b1", B3->begin()->getFunction().getName());
> +
> +  for (LazyCallGraph::Node *N : *C1)
> +    Nodes.push_back(N->getFunction().getName());
> +  std::sort(Nodes.begin(), Nodes.end());
> +  EXPECT_EQ("c2", Nodes[0]);
> +  EXPECT_EQ("d2", Nodes[1]);
> +  Nodes.clear();
> +
> +  EXPECT_EQ(C2->end(), std::next(C2->begin()));
> +  EXPECT_EQ("c3", C2->begin()->getFunction().getName());
> +  EXPECT_EQ(C3->end(), std::next(C3->begin()));
> +  EXPECT_EQ("c1", C3->begin()->getFunction().getName());
> +
> +  EXPECT_EQ(D1->end(), std::next(D1->begin()));
> +  EXPECT_EQ("d2", D1->begin()->getFunction().getName());
> +  EXPECT_EQ(D2->end(), std::next(D2->begin()));
> +  EXPECT_EQ("d3", D2->begin()->getFunction().getName());
> +  EXPECT_EQ(D3->end(), std::next(D3->begin()));
> +  EXPECT_EQ("d1", D3->begin()->getFunction().getName());
> +
> +  // Now lets look at the SCCs.
> +  auto SCCI = CG.postorder_scc_begin();
> +
> +  LazyCallGraph::SCC *D = *SCCI++;
> +  for (LazyCallGraph::Node *N : *D)
> +    Nodes.push_back(N->getFunction().getName());
> +  std::sort(Nodes.begin(), Nodes.end());
> +  EXPECT_EQ("d1", Nodes[0]);
> +  EXPECT_EQ("d2", Nodes[1]);
> +  EXPECT_EQ("d3", Nodes[2]);
> +  EXPECT_EQ(3u, Nodes.size());
> +  Nodes.clear();
> +
> +  LazyCallGraph::SCC *C = *SCCI++;
> +  for (LazyCallGraph::Node *N : *C)
> +    Nodes.push_back(N->getFunction().getName());
> +  std::sort(Nodes.begin(), Nodes.end());
> +  EXPECT_EQ("c1", Nodes[0]);
> +  EXPECT_EQ("c2", Nodes[1]);
> +  EXPECT_EQ("c3", Nodes[2]);
> +  EXPECT_EQ(3u, Nodes.size());
> +  Nodes.clear();
> +
> +  LazyCallGraph::SCC *B = *SCCI++;
> +  for (LazyCallGraph::Node *N : *B)
> +    Nodes.push_back(N->getFunction().getName());
> +  std::sort(Nodes.begin(), Nodes.end());
> +  EXPECT_EQ("b1", Nodes[0]);
> +  EXPECT_EQ("b2", Nodes[1]);
> +  EXPECT_EQ("b3", Nodes[2]);
> +  EXPECT_EQ(3u, Nodes.size());
> +  Nodes.clear();
> +
> +  LazyCallGraph::SCC *A = *SCCI++;
> +  for (LazyCallGraph::Node *N : *A)
> +    Nodes.push_back(N->getFunction().getName());
> +  std::sort(Nodes.begin(), Nodes.end());
> +  EXPECT_EQ("a1", Nodes[0]);
> +  EXPECT_EQ("a2", Nodes[1]);
> +  EXPECT_EQ("a3", Nodes[2]);
> +  EXPECT_EQ(3u, Nodes.size());
> +  Nodes.clear();
> +
> +  EXPECT_EQ(CG.postorder_scc_end(), SCCI);
> +}
> +
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits



More information about the llvm-commits mailing list