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