//===----- llvm/unittest/ADT/SCCIteratorTest.cpp - SCCIterator tests ------===////// The LLVM Compiler Infrastructure//// This file is distributed under the University of Illinois Open Source// License. See LICENSE.TXT for details.////===----------------------------------------------------------------------===//#include"llvm/ADT/SCCIterator.h"#include"llvm/ADT/GraphTraits.h"#include"gtest/gtest.h"#include<limits.h>usingnamespacellvm;namespacellvm{/// Graph<N> - A graph with N nodes. Note that N can be at most 8.template<unsignedN>classGraph{private:// Disable copying.Graph(constGraph&);Graph&operator=(constGraph&);staticvoidValidateIndex(unsignedIdx){assert(Idx<N&&"Invalid node index!");}public:/// NodeSubset - A subset of the graph's nodes.classNodeSubset{typedefunsignedcharBitVector;// Where the limitation N <= 8 comes from.BitVectorElements;NodeSubset(BitVectore):Elements(e){}public:/// NodeSubset - Default constructor, creates an empty subset.NodeSubset():Elements(0){assert(N<=sizeof(BitVector)*CHAR_BIT&&"Graph too big!");}/// NodeSubset - Copy constructor.NodeSubset(constNodeSubset&other):Elements(other.Elements){}/// Comparison operators.booloperator==(constNodeSubset&other)const{returnother.Elements==this->Elements;}booloperator!=(constNodeSubset&other)const{return!(*this==other);}/// AddNode - Add the node with the given index to the subset.voidAddNode(unsignedIdx){ValidateIndex(Idx);Elements|=1U<<Idx;}/// DeleteNode - Remove the node with the given index from the subset.voidDeleteNode(unsignedIdx){ValidateIndex(Idx);Elements&=~(1U<<Idx);}/// count - Return true if the node with the given index is in the subset.boolcount(unsignedIdx){ValidateIndex(Idx);return(Elements&(1U<<Idx))!=0;}/// isEmpty - Return true if this is the empty set.boolisEmpty()const{returnElements==0;}/// isSubsetOf - Return true if this set is a subset of the given one.boolisSubsetOf(constNodeSubset&other)const{return(this->Elements|other.Elements)==other.Elements;}/// Complement - Return the complement of this subset.NodeSubsetComplement()const{return~(unsigned)this->Elements&((1U<<N)-1);}/// Join - Return the union of this subset and the given one.NodeSubsetJoin(constNodeSubset&other)const{returnthis->Elements|other.Elements;}/// Meet - Return the intersection of this subset and the given one.NodeSubsetMeet(constNodeSubset&other)const{returnthis->Elements&other.Elements;}};/// NodeType - Node index and set of children of the node.typedefstd::pair<unsigned,NodeSubset>NodeType;private:/// Nodes - The list of nodes for this graph.NodeTypeNodes[N];public:/// Graph - Default constructor. Creates an empty graph.Graph(){// Let each node know which node it is. This allows us to find the start of// the Nodes array given a pointer to any element of it.for(unsignedi=0;i!=N;++i)Nodes[i].first=i;}/// AddEdge - Add an edge from the node with index FromIdx to the node with/// index ToIdx.voidAddEdge(unsignedFromIdx,unsignedToIdx){ValidateIndex(FromIdx);Nodes[FromIdx].second.AddNode(ToIdx);}/// DeleteEdge - Remove the edge (if any) from the node with index FromIdx to/// the node with index ToIdx.voidDeleteEdge(unsignedFromIdx,unsignedToIdx){ValidateIndex(FromIdx);Nodes[FromIdx].second.DeleteNode(ToIdx);}/// AccessNode - Get a pointer to the node with the given index.NodeType*AccessNode(unsignedIdx)const{ValidateIndex(Idx);// The constant cast is needed when working with GraphTraits, which insists// on taking a constant Graph.returnconst_cast<NodeType*>(&Nodes[Idx]);}/// NodesReachableFrom - Return the set of all nodes reachable from the given/// node.NodeSubsetNodesReachableFrom(unsignedIdx)const{// This algorithm doesn't scale, but that doesn't matter given the small// size of our graphs.NodeSubsetReachable;// The initial node is reachable.Reachable.AddNode(Idx);do{NodeSubsetPrevious(Reachable);// Add in all nodes which are children of a reachable node.for(unsignedi=0;i!=N;++i)if(Previous.count(i))Reachable=Reachable.Join(Nodes[i].second);// If nothing changed then we have found all reachable nodes.if(Reachable==Previous)returnReachable;// Rinse and repeat.}while(1);}/// ChildIterator - Visit all children of a node.classChildIterator{friendclassGraph;/// FirstNode - Pointer to first node in the graph's Nodes array.NodeType*FirstNode;/// Children - Set of nodes which are children of this one and that haven't/// yet been visited.NodeSubsetChildren;ChildIterator();// Disable default constructor.protected:ChildIterator(NodeType*F,NodeSubsetC):FirstNode(F),Children(C){}public:/// ChildIterator - Copy constructor.ChildIterator(constChildIterator&other):FirstNode(other.FirstNode),Children(other.Children){}/// Comparison operators.booloperator==(constChildIterator&other)const{returnother.FirstNode==this->FirstNode&&other.Children==this->Children;}booloperator!=(constChildIterator&other)const{return!(*this==other);}/// Prefix increment operator.ChildIterator&operator++(){// Find the next unvisited child node.for(unsignedi=0;i!=N;++i)if(Children.count(i)){// Remove that child - it has been visited. This is the increment!Children.DeleteNode(i);return*this;}assert(false&&"Incrementing end iterator!");return*this;// Avoid compiler warnings.}/// Postfix increment operator.ChildIteratoroperator++(int){ChildIteratorResult(*this);++(*this);returnResult;}/// Dereference operator.NodeType*operator*(){// Find the next unvisited child node.for(unsignedi=0;i!=N;++i)if(Children.count(i))// Return a pointer to it.returnFirstNode+i;assert(false&&"Dereferencing end iterator!");return0;// Avoid compiler warning.}};/// child_begin - Return an iterator pointing to the first child of the given/// node.staticChildIteratorchild_begin(NodeType*Parent){returnChildIterator(Parent-Parent->first,Parent->second);}/// child_end - Return the end iterator for children of the given node.staticChildIteratorchild_end(NodeType*Parent){returnChildIterator(Parent-Parent->first,NodeSubset());}};template<unsignedN>structGraphTraits<Graph<N>>{typedeftypenameGraph<N>::NodeTypeNodeType;typedeftypenameGraph<N>::ChildIteratorChildIteratorType;staticinlineNodeType*getEntryNode(constGraph<N>&G){returnG.AccessNode(0);}staticinlineChildIteratorTypechild_begin(NodeType*Node){returnGraph<N>::child_begin(Node);}staticinlineChildIteratorTypechild_end(NodeType*Node){returnGraph<N>::child_end(Node);}};TEST(SCCIteratorTest,AllSmallGraphs){// Test SCC computation against every graph with NUM_NODES nodes or less.// Since SCC considers every node to have an implicit self-edge, we only// create graphs for which every node has a self-edge.#define NUM_NODES 4#define NUM_GRAPHS (NUM_NODES * (NUM_NODES - 1))typedefGraph<NUM_NODES>GT;/// Enumerate all graphs using NUM_GRAPHS bits.assert(NUM_GRAPHS<sizeof(unsigned)*CHAR_BIT&&"Too many graphs!");for(unsignedGraphDescriptor=0;GraphDescriptor<(1U<<NUM_GRAPHS);++GraphDescriptor){GTG;// Add edges as specified by the descriptor.unsignedDescriptorCopy=GraphDescriptor;for(unsignedi=0;i!=NUM_NODES;++i)for(unsignedj=0;j!=NUM_NODES;++j){// Always add a self-edge.if(i==j){G.AddEdge(i,j);continue;}if(DescriptorCopy&1)G.AddEdge(i,j);DescriptorCopy>>=1;}// Test the SCC logic on this graph./// NodesInSomeSCC - Those nodes which are in some SCC.GT::NodeSubsetNodesInSomeSCC;for(scc_iterator<GT>I=scc_begin(G),E=scc_end(G);I!=E;++I){std::vector<GT::NodeType*>&SCC=*I;// Get the nodes in this SCC as a NodeSubset rather than a vector.GT::NodeSubsetNodesInThisSCC;for(unsignedi=0,e=SCC.size();i!=e;++i)NodesInThisSCC.AddNode(SCC[i]->first);// There should be at least one node in every SCC.EXPECT_FALSE(NodesInThisSCC.isEmpty());// Check that every node in the SCC is reachable from every other node in// the SCC.for(unsignedi=0;i!=NUM_NODES;++i)if(NodesInThisSCC.count(i))EXPECT_TRUE(NodesInThisSCC.isSubsetOf(G.NodesReachableFrom(i)));// OK, now that we now that every node in the SCC is reachable from every// other, this means that the set of nodes reachable from any node in the// SCC is the same as the set of nodes reachable from every node in the// SCC. Check that for every node N not in the SCC but reachable from the// SCC, no element of the SCC is reachable from N.for(unsignedi=0;i!=NUM_NODES;++i)if(NodesInThisSCC.count(i)){GT::NodeSubsetNodesReachableFromSCC=G.NodesReachableFrom(i);GT::NodeSubsetReachableButNotInSCC=NodesReachableFromSCC.Meet(NodesInThisSCC.Complement());for(unsignedj=0;j!=NUM_NODES;++j)if(ReachableButNotInSCC.count(j))EXPECT_TRUE(G.NodesReachableFrom(j).Meet(NodesInThisSCC).isEmpty());// The result must be the same for all other nodes in this SCC, so// there is no point in checking them.break;}// This is indeed a SCC: a maximal set of nodes for which each node is// reachable from every other.// Check that we didn't already see this SCC.EXPECT_TRUE(NodesInSomeSCC.Meet(NodesInThisSCC).isEmpty());NodesInSomeSCC=NodesInSomeSCC.Join(NodesInThisSCC);// Check a property that is specific to the LLVM SCC iterator and// guaranteed by it: if a node in SCC S1 has an edge to a node in// SCC S2, then S1 is visited *after* S2. This means that the set// of nodes reachable from this SCC must be contained either in the// union of this SCC and all previously visited SCC's.for(unsignedi=0;i!=NUM_NODES;++i)if(NodesInThisSCC.count(i)){GT::NodeSubsetNodesReachableFromSCC=G.NodesReachableFrom(i);EXPECT_TRUE(NodesReachableFromSCC.isSubsetOf(NodesInSomeSCC));// The result must be the same for all other nodes in this SCC, so// there is no point in checking them.break;}}// Finally, check that the nodes in some SCC are exactly those that are// reachable from the initial node.EXPECT_EQ(NodesInSomeSCC,G.NodesReachableFrom(0));}}}