llvm.org GIT mirror llvm / 3a3f163
Changes from Curtis Dunham implementing lazy cycle detection algorithm. Changes from me implementing different way of representing points-to anything. Changes from me that improve slightly on LCD. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44895 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Berlin 12 years ago
1 changed file(s) with 295 addition(s) and 133 deletion(s). Raw diff Collapse all Expand all
7070 #include
7171 #include
7272 #include
73 #include
74
75 // Determining the actual set of nodes the universal set can consist of is very
76 // expensive because it means propagating around very large sets. We rely on
77 // other analysis being able to determine which nodes can never be pointed to in
78 // order to disambiguate further than "points-to anything".
79 #define FULL_UNIVERSAL 0
7380
7481 using namespace llvm;
7582 STATISTIC(NumIters , "Number of iterations to reach convergence");
7683 STATISTIC(NumConstraints, "Number of constraints");
7784 STATISTIC(NumNodes , "Number of nodes");
7885 STATISTIC(NumUnified , "Number of variables unified");
86 STATISTIC(NumErased , "Number of redundant constraints erased");
7987
8088 namespace {
8189 const unsigned SelfRep = (unsigned)-1;
156164 }
157165 };
158166
167 // Information DenseSet requires implemented in order to be able to do
168 // it's thing
169 struct PairKeyInfo {
170 static inline std::pair getEmptyKey() {
171 return std::make_pair(~0UL, ~0UL);
172 }
173 static inline std::pair getTombstoneKey() {
174 return std::make_pair(~0UL - 1, ~0UL - 1);
175 }
176 static unsigned getHashValue(const std::pair &P) {
177 return P.first ^ P.second;
178 }
179 static unsigned isEqual(const std::pair &LHS,
180 const std::pair &RHS) {
181 return LHS == RHS;
182 }
183 };
184
159185 struct ConstraintKeyInfo {
160186 static inline Constraint getEmptyKey() {
161187 return Constraint(Constraint::Copy, ~0UL, ~0UL, ~0UL);
179205 // artificial Node's that represent the set of pointed-to variables shared
180206 // for each location equivalent Node.
181207 struct Node {
208 private:
209 static unsigned Counter;
210
211 public:
182212 Value *Val;
183213 SparseBitVector<> *Edges;
184214 SparseBitVector<> *PointsTo;
185215 SparseBitVector<> *OldPointsTo;
186 bool Changed;
187216 std::list Constraints;
188217
189218 // Pointer and location equivalence labels
211240 // standard union-find representation with path compression. NodeRep
212241 // gives the index into GraphNodes for the representative Node.
213242 unsigned NodeRep;
214 public:
243
244 // Modification timestamp. Assigned from Counter.
245 // Used for work list prioritization.
246 unsigned Timestamp;
215247
216248 Node(bool direct = true) :
217 Val(0), Edges(0), PointsTo(0), OldPointsTo(0), Changed(false),
249 Val(0), Edges(0), PointsTo(0), OldPointsTo(0),
218250 PointerEquivLabel(0), LocationEquivLabel(0), PredEdges(0),
219251 ImplicitPredEdges(0), PointedToBy(0), NumInEdges(0),
220252 StoredInHash(false), Direct(direct), AddressTaken(false),
221 NodeRep(SelfRep) { }
253 NodeRep(SelfRep), Timestamp(0) { }
222254
223255 Node *setValue(Value *V) {
224256 assert(Val == 0 && "Value already set for this node!");
245277 /// intersects with the points-to set of the specified node on any nodes
246278 /// except for the specified node to ignore.
247279 bool intersectsIgnoring(Node *N, unsigned) const;
280
281 // Timestamp a node (used for work list prioritization)
282 void Stamp() {
283 Timestamp = Counter++;
284 }
285
286 bool isRep() {
287 return( (int) NodeRep < 0 );
288 }
289 };
290
291 struct WorkListElement {
292 Node* node;
293 unsigned Timestamp;
294 WorkListElement(Node* n, unsigned t) : node(n), Timestamp(t) {}
295
296 // Note that we reverse the sense of the comparison because we
297 // actually want to give low timestamps the priority over high,
298 // whereas priority is typically interpreted as a greater value is
299 // given high priority.
300 bool operator<(const WorkListElement& that) const {
301 return( this->Timestamp > that.Timestamp );
302 }
303 };
304
305 // Priority-queue based work list specialized for Nodes.
306 class WorkList {
307 std::priority_queue Q;
308
309 public:
310 void insert(Node* n) {
311 Q.push( WorkListElement(n, n->Timestamp) );
312 }
313
314 // We automatically discard non-representative nodes and nodes
315 // that were in the work list twice (we keep a copy of the
316 // timestamp in the work list so we can detect this situation by
317 // comparing against the node's current timestamp).
318 Node* pop() {
319 while( !Q.empty() ) {
320 WorkListElement x = Q.top(); Q.pop();
321 Node* INode = x.node;
322
323 if( INode->isRep() &&
324 INode->Timestamp == x.Timestamp ) {
325 return(x.node);
326 }
327 }
328 return(0);
329 }
330
331 bool empty() {
332 return Q.empty();
333 }
248334 };
249335
250336 /// GraphNodes - This vector is populated as part of the object
289375 };
290376 // Stack for Tarjan's
291377 std::stack SCCStack;
292 // Topological Index -> Graph node
293 std::vector Topo2Node;
294 // Graph Node -> Topological Index;
295 std::vector Node2Topo;
296378 // Map from Graph Node to DFS number
297379 std::vector Node2DFS;
298380 // Map from Graph Node to Deleted from graph.
299381 std::vector Node2Deleted;
300 // Current DFS and RPO numbers
382 // Same as Node Maps, but implemented as std::map because it is faster to
383 // clear
384 std::map Tarjan2DFS;
385 std::map Tarjan2Deleted;
386 // Current DFS number
301387 unsigned DFSNumber;
302 unsigned RPONumber;
388
389 // Work lists.
390 WorkList w1, w2;
391 WorkList *CurrWL, *NextWL; // "current" and "next" work lists
303392
304393 // Offline variable substitution related things
305394
442531 return Index;
443532 }
444533
445 unsigned UniteNodes(unsigned First, unsigned Second);
534 unsigned UniteNodes(unsigned First, unsigned Second,
535 bool UnionByRank = true);
446536 unsigned FindNode(unsigned Node);
447537
448538 void IdentifyObjects(Module &M);
457547 void HVN();
458548 void UnitePointerEquivalences();
459549 void SolveConstraints();
460 void QueryNode(unsigned Node);
550 bool QueryNode(unsigned Node);
461551 void Condense(unsigned Node);
462552 void HUValNum(unsigned Node);
463553 void HVNValNum(unsigned Node);
502592 RegisterPass X("anders-aa",
503593 "Andersen's Interprocedural Alias Analysis");
504594 RegisterAnalysisGroup Y(X);
595
596 // Initialize Timestamp Counter (static).
597 unsigned Andersens::Node::Counter = 0;
505598 }
506599
507600 ModulePass *llvm::createAndersensPass() { return new Andersens(); }
9801073 UniversalSet));
9811074 // Memory objects passed into external function calls can have the
9821075 // universal set point to them.
1076 #if FULL_UNIVERSAL
9831077 Constraints.push_back(Constraint(Constraint::Copy,
9841078 UniversalSet,
9851079 getNode(I)));
1080 #else
1081 Constraints.push_back(Constraint(Constraint::Copy,
1082 getNode(I),
1083 UniversalSet));
1084 #endif
9861085 }
9871086
9881087 // If this is an external varargs function, it can also store pointers
11381237 UniversalSet));
11391238 }
11401239 } else if (F && isa(F->getFunctionType()->getReturnType())) {
1240 #if FULL_UNIVERSAL
11411241 Constraints.push_back(Constraint(Constraint::Copy,
11421242 UniversalSet,
11431243 getNode(CallValue) + CallReturnPos));
1244 #else
1245 Constraints.push_back(Constraint(Constraint::Copy,
1246 getNode(CallValue) + CallReturnPos,
1247 UniversalSet));
1248 #endif
1249
1250
11441251 }
11451252
11461253 CallSite::arg_iterator ArgI = CS.arg_begin(), ArgE = CS.arg_end();
11581265 UniversalSet));
11591266 }
11601267 } else if (isa((*ArgI)->getType())) {
1268 #if FULL_UNIVERSAL
11611269 Constraints.push_back(Constraint(Constraint::Copy,
11621270 UniversalSet,
11631271 getNode(*ArgI)));
1272 #else
1273 Constraints.push_back(Constraint(Constraint::Copy,
1274 getNode(*ArgI),
1275 UniversalSet));
1276 #endif
11641277 }
11651278 } else {
11661279 //Indirect Call
18361949 if (!GraphNodes[NodeIndex].AddressTaken) {
18371950 if (PEClass2Node[NodeLabel] != -1) {
18381951 // We found an existing node with the same pointer label, so unify them.
1839 return UniteNodes(PEClass2Node[NodeLabel], NodeIndex);
1952 // We specifically request that Union-By-Rank not be used so that
1953 // PEClass2Node[NodeLabel] U= NodeIndex and not the other way around.
1954 return UniteNodes(PEClass2Node[NodeLabel], NodeIndex, false);
18401955 } else {
18411956 PEClass2Node[NodeLabel] = NodeIndex;
18421957 PENLEClass2Node[NodeLabel] = NodeIndex;
19512066 void Andersens::UnitePointerEquivalences() {
19522067 DOUT << "Uniting remaining pointer equivalences\n";
19532068 for (unsigned i = 0; i < GraphNodes.size(); ++i) {
1954 if (GraphNodes[i].AddressTaken && GraphNodes[i].NodeRep == SelfRep) {
2069 if (GraphNodes[i].AddressTaken && GraphNodes[i].isRep()) {
19552070 unsigned Label = GraphNodes[i].PointerEquivLabel;
19562071
19572072 if (Label && PENLEClass2Node[Label] != -1)
19812096 }
19822097 }
19832098
1984 // Perform cycle detection, DFS, and RPO finding.
1985 void Andersens::QueryNode(unsigned Node) {
1986 assert(GraphNodes[Node].NodeRep == SelfRep && "Querying a non-rep node");
2099 // Perform DFS and cycle detection.
2100 bool Andersens::QueryNode(unsigned Node) {
2101 assert(GraphNodes[Node].isRep() && "Querying a non-rep node");
19872102 unsigned OurDFS = ++DFSNumber;
19882103 SparseBitVector<> ToErase;
19892104 SparseBitVector<> NewEdges;
1990 Node2DFS[Node] = OurDFS;
2105 Tarjan2DFS[Node] = OurDFS;
2106
2107 // Changed denotes a change from a recursive call that we will bubble up.
2108 // Merged is set if we actually merge a node ourselves.
2109 bool Changed = false, Merged = false;
19912110
19922111 for (SparseBitVector<>::iterator bi = GraphNodes[Node].Edges->begin();
19932112 bi != GraphNodes[Node].Edges->end();
19942113 ++bi) {
19952114 unsigned RepNode = FindNode(*bi);
1996 // If we are going to add an edge to repnode, we have no need for the edge
1997 // to e anymore.
2115 // If this edge points to a non-representative node but we are
2116 // already planning to add an edge to its representative, we have no
2117 // need for this edge anymore.
19982118 if (RepNode != *bi && NewEdges.test(RepNode)){
19992119 ToErase.set(*bi);
20002120 continue;
20012121 }
20022122
20032123 // Continue about our DFS.
2004 if (!Node2Deleted[RepNode]){
2005 if (Node2DFS[RepNode] == 0) {
2006 QueryNode(RepNode);
2007 // May have been changed by query
2124 if (!Tarjan2Deleted[RepNode]){
2125 if (Tarjan2DFS[RepNode] == 0) {
2126 Changed |= QueryNode(RepNode);
2127 // May have been changed by QueryNode
20082128 RepNode = FindNode(RepNode);
20092129 }
2010 if (Node2DFS[RepNode] < Node2DFS[Node])
2011 Node2DFS[Node] = Node2DFS[RepNode];
2012 }
2013 // We may have just discovered that e belongs to a cycle, in which case we
2014 // can also erase it.
2130 if (Tarjan2DFS[RepNode] < Tarjan2DFS[Node])
2131 Tarjan2DFS[Node] = Tarjan2DFS[RepNode];
2132 }
2133
2134 // We may have just discovered that this node is part of a cycle, in
2135 // which case we can also erase it.
20152136 if (RepNode != *bi) {
20162137 ToErase.set(*bi);
20172138 NewEdges.set(RepNode);
20212142 GraphNodes[Node].Edges->intersectWithComplement(ToErase);
20222143 GraphNodes[Node].Edges |= NewEdges;
20232144
2024 // If this node is a root of a non-trivial SCC, place it on our worklist to be
2025 // processed
2026 if (OurDFS == Node2DFS[Node]) {
2027 bool Changed = false;
2028 while (!SCCStack.empty() && Node2DFS[SCCStack.top()] >= OurDFS) {
2029 Node = UniteNodes(Node, FindNode(SCCStack.top()));
2145 // If this node is a root of a non-trivial SCC, place it on our
2146 // worklist to be processed.
2147 if (OurDFS == Tarjan2DFS[Node]) {
2148 while (!SCCStack.empty() && Tarjan2DFS[SCCStack.top()] >= OurDFS) {
2149 Node = UniteNodes(Node, SCCStack.top());
20302150
20312151 SCCStack.pop();
2032 Changed = true;
2033 }
2034 Node2Deleted[Node] = true;
2035 RPONumber++;
2036
2037 Topo2Node.at(GraphNodes.size() - RPONumber) = Node;
2038 Node2Topo[Node] = GraphNodes.size() - RPONumber;
2039 if (Changed)
2040 GraphNodes[Node].Changed = true;
2152 Merged = true;
2153 }
2154 Tarjan2Deleted[Node] = true;
2155
2156 if (Merged)
2157 NextWL->insert(&GraphNodes[Node]);
20412158 } else {
20422159 SCCStack.push(Node);
20432160 }
2044 }
2045
2161
2162 return(Changed | Merged);
2163 }
20462164
20472165 /// SolveConstraints - This stage iteratively processes the constraints list
20482166 /// propagating constraints (adding edges to the Nodes in the points-to graph)
20492167 /// until a fixed point is reached.
20502168 ///
2169 /// We use a variant of the technique called "Lazy Cycle Detection", which is
2170 /// described in "The Ant and the Grasshopper: Fast and Accurate Pointer
2171 /// Analysis for Millions of Lines of Code. In Programming Language Design and
2172 /// Implementation (PLDI), June 2007."
2173 /// The paper describes performing cycle detection one node at a time, which can
2174 /// be expensive if there are no cycles, but there are long chains of nodes that
2175 /// it heuristically believes are cycles (because it will DFS from each node
2176 /// without state from previous nodes).
2177 /// Instead, we use the heuristic to build a worklist of nodes to check, then
2178 /// cycle detect them all at the same time to do this more cheaply. This
2179 /// catches cycles slightly later than the original technique did, but does it
2180 /// make significantly cheaper.
2181
20512182 void Andersens::SolveConstraints() {
2052 bool Changed = true;
2053 unsigned Iteration = 0;
2183 CurrWL = &w1;
2184 NextWL = &w2;
20542185
20552186 OptimizeConstraints();
20562187 #undef DEBUG_TYPE
20682199 CreateConstraintGraph();
20692200 UnitePointerEquivalences();
20702201 assert(SCCStack.empty() && "SCC Stack should be empty by now!");
2071 Topo2Node.insert(Topo2Node.begin(), GraphNodes.size(), Unvisited);
2072 Node2Topo.insert(Node2Topo.begin(), GraphNodes.size(), Unvisited);
20732202 Node2DFS.clear();
20742203 Node2Deleted.clear();
20752204 Node2DFS.insert(Node2DFS.begin(), GraphNodes.size(), 0);
20762205 Node2Deleted.insert(Node2Deleted.begin(), GraphNodes.size(), false);
20772206 DFSNumber = 0;
2078 RPONumber = 0;
2079 // Order graph and mark starting nodes as changed.
2207 DenseSet Seen;
2208 DenseSet, PairKeyInfo> EdgesChecked;
2209
2210 // Order graph and add initial nodes to work list.
20802211 for (unsigned i = 0; i < GraphNodes.size(); ++i) {
2081 unsigned N = FindNode(i);
20822212 Node *INode = &GraphNodes[i];
2083 if (Node2DFS[N] == 0) {
2084 QueryNode(N);
2085 // Mark as changed if it's a representation and can contribute to the
2086 // calculation right now.
2087 if (INode->NodeRep == SelfRep && !INode->PointsTo->empty()
2088 && (!INode->Edges->empty() || !INode->Constraints.empty()))
2089 INode->Changed = true;
2090 }
2091 }
2092
2093 do {
2094 Changed = false;
2095 ++NumIters;
2096 DOUT << "Starting iteration #" << Iteration++ << "\n";
2097 // TODO: In the microoptimization category, we could just make Topo2Node
2098 // a fast map and thus only contain the visited nodes.
2099 for (unsigned i = 0; i < GraphNodes.size(); ++i) {
2100 unsigned CurrNodeIndex = Topo2Node[i];
2101 Node *CurrNode;
2102
2103 // We may not revisit all nodes on every iteration
2104 if (CurrNodeIndex == Unvisited)
2105 continue;
2106 CurrNode = &GraphNodes[CurrNodeIndex];
2107 // See if this is a node we need to process on this iteration
2108 if (!CurrNode->Changed || CurrNode->NodeRep != SelfRep)
2109 continue;
2110 CurrNode->Changed = false;
2111
2213
2214 // Add to work list if it's a representative and can contribute to the
2215 // calculation right now.
2216 if (INode->isRep() && !INode->PointsTo->empty()
2217 && (!INode->Edges->empty() || !INode->Constraints.empty())) {
2218 INode->Stamp();
2219 CurrWL->insert(INode);
2220 }
2221 }
2222 std::queue TarjanWL;
2223 while( !CurrWL->empty() ) {
2224 DOUT << "Starting iteration #" << ++NumIters << "\n";
2225
2226 Node* CurrNode;
2227 unsigned CurrNodeIndex;
2228
2229 // Actual cycle checking code. We cycle check all of the lazy cycle
2230 // candidates from the last iteration in one go.
2231 if (!TarjanWL.empty()) {
2232 DFSNumber = 0;
2233
2234 Tarjan2DFS.clear();
2235 Tarjan2Deleted.clear();
2236 while (!TarjanWL.empty()) {
2237 unsigned int ToTarjan = TarjanWL.front();
2238 TarjanWL.pop();
2239 if (!Tarjan2Deleted[ToTarjan]
2240 && GraphNodes[ToTarjan].isRep()
2241 && Tarjan2DFS[ToTarjan] == 0)
2242 QueryNode(ToTarjan);
2243 }
2244 }
2245
2246 // Add to work list if it's a representative and can contribute to the
2247 // calculation right now.
2248 while( (CurrNode = CurrWL->pop()) != NULL ) {
2249 CurrNodeIndex = CurrNode - &GraphNodes[0];
2250 CurrNode->Stamp();
2251
2252
21122253 // Figure out the changed points to bits
21132254 SparseBitVector<> CurrPointsTo;
21142255 CurrPointsTo.intersectWithComplement(CurrNode->PointsTo,
21152256 CurrNode->OldPointsTo);
2116 if (CurrPointsTo.empty()){
2257 if (CurrPointsTo.empty())
21172258 continue;
2118 }
2259
21192260 *(CurrNode->OldPointsTo) |= CurrPointsTo;
2261 Seen.clear();
21202262
21212263 /* Now process the constraints for this node. */
21222264 for (std::list::iterator li = CurrNode->Constraints.begin();
21242266 li->Src = FindNode(li->Src);
21252267 li->Dest = FindNode(li->Dest);
21262268
2127 // TODO: We could delete redundant constraints here.
2269 // Delete redundant constraints
2270 if( Seen.count(*li) ) {
2271 std::list::iterator lk = li; li++;
2272
2273 CurrNode->Constraints.erase(lk);
2274 ++NumErased;
2275 continue;
2276 }
2277 Seen.insert(*li);
2278
21282279 // Src and Dest will be the vars we are going to process.
21292280 // This may look a bit ugly, but what it does is allow us to process
21302281 // both store and load constraints with the same code.
21722323
21732324 // Add an edge to the graph, so we can just do regular bitmap ior next
21742325 // time. It may also let us notice a cycle.
2175 if (GraphNodes[*Src].Edges->test_and_set(*Dest)) {
2176 if (GraphNodes[*Dest].PointsTo |= *(GraphNodes[*Src].PointsTo)) {
2177 GraphNodes[*Dest].Changed = true;
2178 // If we changed a node we've already processed, we need another
2179 // iteration.
2180 if (Node2Topo[*Dest] <= i)
2181 Changed = true;
2182 }
2183 }
2326 #if !FULL_UNIVERSAL
2327 if (*Dest < NumberSpecialNodes)
2328 continue;
2329 #endif
2330 if (GraphNodes[*Src].Edges->test_and_set(*Dest))
2331 if (GraphNodes[*Dest].PointsTo |= *(GraphNodes[*Src].PointsTo))
2332 NextWL->insert(&GraphNodes[*Dest]);
2333
21842334 }
21852335 li++;
21862336 }
21892339
21902340 // Now all we have left to do is propagate points-to info along the
21912341 // edges, erasing the redundant edges.
2192
2193
21942342 for (SparseBitVector<>::iterator bi = CurrNode->Edges->begin();
21952343 bi != CurrNode->Edges->end();
21962344 ++bi) {
21982346 unsigned DestVar = *bi;
21992347 unsigned Rep = FindNode(DestVar);
22002348
2201 // If we ended up with this node as our destination, or we've already
2202 // got an edge for the representative, delete the current edge.
2203 if (Rep == CurrNodeIndex ||
2204 (Rep != DestVar && NewEdges.test(Rep))) {
2205 ToErase.set(DestVar);
2206 continue;
2349 // If we ended up with this node as our destination, or we've already
2350 // got an edge for the representative, delete the current edge.
2351 if (Rep == CurrNodeIndex ||
2352 (Rep != DestVar && NewEdges.test(Rep))) {
2353 ToErase.set(DestVar);
2354 continue;
2355 }
2356
2357 std::pair edge(CurrNodeIndex,Rep);
2358
2359 // This is where we do lazy cycle detection.
2360 // If this is a cycle candidate (equal points-to sets and this
2361 // particular edge has not been cycle-checked previously), add to the
2362 // list to check for cycles on the next iteration.
2363 if (!EdgesChecked.count(edge) &&
2364 *(GraphNodes[Rep].PointsTo) == *(CurrNode->PointsTo)) {
2365 EdgesChecked.insert(edge);
2366 TarjanWL.push(Rep);
22072367 }
22082368 // Union the points-to sets into the dest
2369 #if !FULL_UNIVERSAL
2370 if (Rep >= NumberSpecialNodes)
2371 #endif
22092372 if (GraphNodes[Rep].PointsTo |= CurrPointsTo) {
2210 GraphNodes[Rep].Changed = true;
2211 if (Node2Topo[Rep] <= i)
2212 Changed = true;
2373 NextWL->insert(&GraphNodes[Rep]);
22132374 }
22142375 // If this edge's destination was collapsed, rewrite the edge.
22152376 if (Rep != DestVar) {
22202381 CurrNode->Edges->intersectWithComplement(ToErase);
22212382 CurrNode->Edges |= NewEdges;
22222383 }
2223 if (Changed) {
2224 DFSNumber = RPONumber = 0;
2225 Node2Deleted.clear();
2226 Topo2Node.clear();
2227 Node2Topo.clear();
2228 Node2DFS.clear();
2229 Topo2Node.insert(Topo2Node.begin(), GraphNodes.size(), Unvisited);
2230 Node2Topo.insert(Node2Topo.begin(), GraphNodes.size(), Unvisited);
2231 Node2DFS.insert(Node2DFS.begin(), GraphNodes.size(), 0);
2232 Node2Deleted.insert(Node2Deleted.begin(), GraphNodes.size(), false);
2233 // Rediscover the DFS/Topo ordering, and cycle detect.
2234 for (unsigned j = 0; j < GraphNodes.size(); j++) {
2235 unsigned JRep = FindNode(j);
2236 if (Node2DFS[JRep] == 0)
2237 QueryNode(JRep);
2238 }
2239 }
2240
2241 } while (Changed);
2242
2243 Node2Topo.clear();
2244 Topo2Node.clear();
2384
2385 // Switch to other work list.
2386 WorkList* t = CurrWL; CurrWL = NextWL; NextWL = t;
2387 }
2388
2389
22452390 Node2DFS.clear();
22462391 Node2Deleted.clear();
22472392 for (unsigned i = 0; i < GraphNodes.size(); ++i) {
22572402
22582403 // Unite nodes First and Second, returning the one which is now the
22592404 // representative node. First and Second are indexes into GraphNodes
2260 unsigned Andersens::UniteNodes(unsigned First, unsigned Second) {
2405 unsigned Andersens::UniteNodes(unsigned First, unsigned Second,
2406 bool UnionByRank) {
22612407 assert (First < GraphNodes.size() && Second < GraphNodes.size() &&
22622408 "Attempting to merge nodes that don't exist");
2263 // TODO: implement union by rank
2409
22642410 Node *FirstNode = &GraphNodes[First];
22652411 Node *SecondNode = &GraphNodes[Second];
22662412
2267 assert (SecondNode->NodeRep == SelfRep && FirstNode->NodeRep == SelfRep &&
2413 assert (SecondNode->isRep() && FirstNode->isRep() &&
22682414 "Trying to unite two non-representative nodes!");
22692415 if (First == Second)
22702416 return First;
22712417
2418 if (UnionByRank) {
2419 int RankFirst = (int) FirstNode ->NodeRep;
2420 int RankSecond = (int) SecondNode->NodeRep;
2421
2422 // Rank starts at -1 and gets decremented as it increases.
2423 // Translation: higher rank, lower NodeRep value, which is always negative.
2424 if (RankFirst > RankSecond) {
2425 unsigned t = First; First = Second; Second = t;
2426 Node* tp = FirstNode; FirstNode = SecondNode; SecondNode = tp;
2427 } else if (RankFirst == RankSecond) {
2428 FirstNode->NodeRep = (unsigned) (RankFirst - 1);
2429 }
2430 }
2431
22722432 SecondNode->NodeRep = First;
2273 FirstNode->Changed |= SecondNode->Changed;
2433 #if !FULL_UNIVERSAL
2434 if (First >= NumberSpecialNodes)
2435 #endif
22742436 if (FirstNode->PointsTo && SecondNode->PointsTo)
22752437 FirstNode->PointsTo |= *(SecondNode->PointsTo);
22762438 if (FirstNode->Edges && SecondNode->Edges)
22772439 FirstNode->Edges |= *(SecondNode->Edges);
2278 if (!FirstNode->Constraints.empty() && !SecondNode->Constraints.empty())
2440 if (!SecondNode->Constraints.empty())
22792441 FirstNode->Constraints.splice(FirstNode->Constraints.begin(),
22802442 SecondNode->Constraints);
22812443 if (FirstNode->OldPointsTo) {
23082470 assert (NodeIndex < GraphNodes.size()
23092471 && "Attempting to find a node that can't exist");
23102472 Node *N = &GraphNodes[NodeIndex];
2311 if (N->NodeRep == SelfRep)
2473 if (N->isRep())
23122474 return NodeIndex;
23132475 else
23142476 return (N->NodeRep = FindNode(N->NodeRep));