xref: /llvm-project/llvm/unittests/ADT/SCCIteratorTest.cpp (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
1dea551c5SDuncan Sands //===----- llvm/unittest/ADT/SCCIteratorTest.cpp - SCCIterator tests ------===//
2dea551c5SDuncan Sands //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6dea551c5SDuncan Sands //
7dea551c5SDuncan Sands //===----------------------------------------------------------------------===//
8dea551c5SDuncan Sands 
9dea551c5SDuncan Sands #include "llvm/ADT/SCCIterator.h"
10608ca250STim Shen #include "TestGraph.h"
119a67b073SChandler Carruth #include "gtest/gtest.h"
1291d3cfedSDuncan P. N. Exon Smith #include <limits.h>
13dea551c5SDuncan Sands 
14dea551c5SDuncan Sands using namespace llvm;
15dea551c5SDuncan Sands 
16dea551c5SDuncan Sands namespace llvm {
17dea551c5SDuncan Sands 
TEST(SCCIteratorTest,AllSmallGraphs)18dea551c5SDuncan Sands TEST(SCCIteratorTest, AllSmallGraphs) {
19dea551c5SDuncan Sands   // Test SCC computation against every graph with NUM_NODES nodes or less.
20dea551c5SDuncan Sands   // Since SCC considers every node to have an implicit self-edge, we only
21dea551c5SDuncan Sands   // create graphs for which every node has a self-edge.
22dea551c5SDuncan Sands #define NUM_NODES 4
23dea551c5SDuncan Sands #define NUM_GRAPHS (NUM_NODES * (NUM_NODES - 1))
24dea551c5SDuncan Sands   typedef Graph<NUM_NODES> GT;
25dea551c5SDuncan Sands 
26be64bbf9SDuncan Sands   /// Enumerate all graphs using NUM_GRAPHS bits.
27fee04343SGabor Horvath   static_assert(NUM_GRAPHS < sizeof(unsigned) * CHAR_BIT, "Too many graphs!");
28be64bbf9SDuncan Sands   for (unsigned GraphDescriptor = 0; GraphDescriptor < (1U << NUM_GRAPHS);
29be64bbf9SDuncan Sands        ++GraphDescriptor) {
30dea551c5SDuncan Sands     GT G;
31dea551c5SDuncan Sands 
32dea551c5SDuncan Sands     // Add edges as specified by the descriptor.
33251daee2SDuncan Sands     unsigned DescriptorCopy = GraphDescriptor;
34dea551c5SDuncan Sands     for (unsigned i = 0; i != NUM_NODES; ++i)
35dea551c5SDuncan Sands       for (unsigned j = 0; j != NUM_NODES; ++j) {
36dea551c5SDuncan Sands         // Always add a self-edge.
37dea551c5SDuncan Sands         if (i == j) {
38dea551c5SDuncan Sands           G.AddEdge(i, j);
39dea551c5SDuncan Sands           continue;
40dea551c5SDuncan Sands         }
41dea551c5SDuncan Sands         if (DescriptorCopy & 1)
42dea551c5SDuncan Sands           G.AddEdge(i, j);
43dea551c5SDuncan Sands         DescriptorCopy >>= 1;
44dea551c5SDuncan Sands       }
45dea551c5SDuncan Sands 
46dea551c5SDuncan Sands     // Test the SCC logic on this graph.
47dea551c5SDuncan Sands 
48dea551c5SDuncan Sands     /// NodesInSomeSCC - Those nodes which are in some SCC.
49dea551c5SDuncan Sands     GT::NodeSubset NodesInSomeSCC;
50dea551c5SDuncan Sands 
51dea551c5SDuncan Sands     for (scc_iterator<GT> I = scc_begin(G), E = scc_end(G); I != E; ++I) {
52d2b2facbSDuncan P. N. Exon Smith       const std::vector<GT::NodeType *> &SCC = *I;
53dea551c5SDuncan Sands 
54dea551c5SDuncan Sands       // Get the nodes in this SCC as a NodeSubset rather than a vector.
55dea551c5SDuncan Sands       GT::NodeSubset NodesInThisSCC;
56dea551c5SDuncan Sands       for (unsigned i = 0, e = SCC.size(); i != e; ++i)
57dea551c5SDuncan Sands         NodesInThisSCC.AddNode(SCC[i]->first);
58dea551c5SDuncan Sands 
59dea551c5SDuncan Sands       // There should be at least one node in every SCC.
60dea551c5SDuncan Sands       EXPECT_FALSE(NodesInThisSCC.isEmpty());
61dea551c5SDuncan Sands 
62dea551c5SDuncan Sands       // Check that every node in the SCC is reachable from every other node in
63dea551c5SDuncan Sands       // the SCC.
64dea551c5SDuncan Sands       for (unsigned i = 0; i != NUM_NODES; ++i)
65fcae62d6SGalina Kistanova         if (NodesInThisSCC.count(i)) {
66dea551c5SDuncan Sands           EXPECT_TRUE(NodesInThisSCC.isSubsetOf(G.NodesReachableFrom(i)));
67fcae62d6SGalina Kistanova         }
68dea551c5SDuncan Sands 
69dea551c5SDuncan Sands       // OK, now that we now that every node in the SCC is reachable from every
70dea551c5SDuncan Sands       // other, this means that the set of nodes reachable from any node in the
71dea551c5SDuncan Sands       // SCC is the same as the set of nodes reachable from every node in the
72dea551c5SDuncan Sands       // SCC.  Check that for every node N not in the SCC but reachable from the
73dea551c5SDuncan Sands       // SCC, no element of the SCC is reachable from N.
74dea551c5SDuncan Sands       for (unsigned i = 0; i != NUM_NODES; ++i)
75dea551c5SDuncan Sands         if (NodesInThisSCC.count(i)) {
76dea551c5SDuncan Sands           GT::NodeSubset NodesReachableFromSCC = G.NodesReachableFrom(i);
77dea551c5SDuncan Sands           GT::NodeSubset ReachableButNotInSCC =
78dea551c5SDuncan Sands             NodesReachableFromSCC.Meet(NodesInThisSCC.Complement());
79dea551c5SDuncan Sands 
80dea551c5SDuncan Sands           for (unsigned j = 0; j != NUM_NODES; ++j)
81fcae62d6SGalina Kistanova             if (ReachableButNotInSCC.count(j)) {
82dea551c5SDuncan Sands               EXPECT_TRUE(G.NodesReachableFrom(j).Meet(NodesInThisSCC).isEmpty());
83fcae62d6SGalina Kistanova             }
84dea551c5SDuncan Sands 
85dea551c5SDuncan Sands           // The result must be the same for all other nodes in this SCC, so
86dea551c5SDuncan Sands           // there is no point in checking them.
87dea551c5SDuncan Sands           break;
88dea551c5SDuncan Sands         }
89dea551c5SDuncan Sands 
90dea551c5SDuncan Sands       // This is indeed a SCC: a maximal set of nodes for which each node is
91dea551c5SDuncan Sands       // reachable from every other.
92dea551c5SDuncan Sands 
93dea551c5SDuncan Sands       // Check that we didn't already see this SCC.
94dea551c5SDuncan Sands       EXPECT_TRUE(NodesInSomeSCC.Meet(NodesInThisSCC).isEmpty());
95dea551c5SDuncan Sands 
96dea551c5SDuncan Sands       NodesInSomeSCC = NodesInSomeSCC.Join(NodesInThisSCC);
976d0f0ffeSDuncan Sands 
986d0f0ffeSDuncan Sands       // Check a property that is specific to the LLVM SCC iterator and
996d0f0ffeSDuncan Sands       // guaranteed by it: if a node in SCC S1 has an edge to a node in
1006d0f0ffeSDuncan Sands       // SCC S2, then S1 is visited *after* S2.  This means that the set
1016d0f0ffeSDuncan Sands       // of nodes reachable from this SCC must be contained either in the
1026d0f0ffeSDuncan Sands       // union of this SCC and all previously visited SCC's.
1036d0f0ffeSDuncan Sands 
1046d0f0ffeSDuncan Sands       for (unsigned i = 0; i != NUM_NODES; ++i)
1056d0f0ffeSDuncan Sands         if (NodesInThisSCC.count(i)) {
1066d0f0ffeSDuncan Sands           GT::NodeSubset NodesReachableFromSCC = G.NodesReachableFrom(i);
1076d0f0ffeSDuncan Sands           EXPECT_TRUE(NodesReachableFromSCC.isSubsetOf(NodesInSomeSCC));
1086d0f0ffeSDuncan Sands           // The result must be the same for all other nodes in this SCC, so
1096d0f0ffeSDuncan Sands           // there is no point in checking them.
1106d0f0ffeSDuncan Sands           break;
1116d0f0ffeSDuncan Sands         }
112dea551c5SDuncan Sands     }
113dea551c5SDuncan Sands 
114dea551c5SDuncan Sands     // Finally, check that the nodes in some SCC are exactly those that are
115dea551c5SDuncan Sands     // reachable from the initial node.
116dea551c5SDuncan Sands     EXPECT_EQ(NodesInSomeSCC, G.NodesReachableFrom(0));
117be64bbf9SDuncan Sands   }
118dea551c5SDuncan Sands }
119dea551c5SDuncan Sands 
12091d3cfedSDuncan P. N. Exon Smith }
121