llvm.org GIT mirror llvm / c864edb
Add Hybrid Cycle Detection to Andersen's analysis. Patch by Curtis Dunham. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@47959 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Berlin 12 years ago
1 changed file(s) with 276 addition(s) and 36 deletion(s). Raw diff Collapse all Expand all
3030 // address taking.
3131 //
3232 // The offline constraint graph optimization portion includes offline variable
33 // substitution algorithms intended to computer pointer and location
33 // substitution algorithms intended to compute pointer and location
3434 // equivalences. Pointer equivalences are those pointers that will have the
3535 // same points-to sets, and location equivalences are those variables that
36 // always appear together in points-to sets.
36 // always appear together in points-to sets. It also includes an offline
37 // cycle detection algorithm that allows cycles to be collapsed sooner
38 // during solving.
3739 //
3840 // The inclusion constraint solving phase iteratively propagates the inclusion
3941 // constraints until a fixed point is reached. This is an O(N^3) algorithm.
4749 // CallReturnPos. The arguments start at getNode(F) + CallArgPos.
4850 //
4951 // Future Improvements:
50 // Offline detection of online cycles. Use of BDD's.
52 // Use of BDD's.
5153 //===----------------------------------------------------------------------===//
5254
5355 #define DEBUG_TYPE "anders-aa"
417419 // pointer equivalent but not location equivalent variables. -1 if we have
418420 // no representative node for this pointer equivalence class yet.
419421 std::vector PENLEClass2Node;
422 // Union/Find for HCD
423 std::vector HCDSCCRep;
424 // HCD's offline-detected cycles; "Statically DeTected"
425 // -1 if not part of such a cycle, otherwise a representative node.
426 std::vector SDT;
427 // Whether to use SDT (UniteNodes can use it during solving, but not before)
428 bool SDTActive;
420429
421430 public:
422431 static char ID;
545554 void RewriteConstraints();
546555 void HU();
547556 void HVN();
557 void HCD();
558 void Search(unsigned Node);
548559 void UnitePointerEquivalences();
549560 void SolveConstraints();
550561 bool QueryNode(unsigned Node);
19841995 }
19851996 }
19861997
1998 /// The technique used here is described in "The Ant and the
1999 /// Grasshopper: Fast and Accurate Pointer Analysis for Millions of
2000 /// Lines of Code. In Programming Language Design and Implementation
2001 /// (PLDI), June 2007." It is known as the "HCD" (Hybrid Cycle
2002 /// Detection) algorithm. It is called a hybrid because it performs an
2003 /// offline analysis and uses its results during the solving (online)
2004 /// phase. This is just the offline portion; the results of this
2005 /// operation are stored in SDT and are later used in SolveContraints()
2006 /// and UniteNodes().
2007 void Andersens::HCD() {
2008 DOUT << "Starting HCD.\n";
2009 HCDSCCRep.resize(GraphNodes.size());
2010
2011 for (unsigned i = 0; i < GraphNodes.size(); ++i) {
2012 GraphNodes[i].Edges = new SparseBitVector<>;
2013 HCDSCCRep[i] = i;
2014 }
2015
2016 for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
2017 Constraint &C = Constraints[i];
2018 assert (C.Src < GraphNodes.size() && C.Dest < GraphNodes.size());
2019 if (C.Type == Constraint::AddressOf) {
2020 continue;
2021 } else if (C.Type == Constraint::Load) {
2022 if( C.Offset == 0 )
2023 GraphNodes[C.Dest].Edges->set(C.Src + FirstRefNode);
2024 } else if (C.Type == Constraint::Store) {
2025 if( C.Offset == 0 )
2026 GraphNodes[C.Dest + FirstRefNode].Edges->set(C.Src);
2027 } else {
2028 GraphNodes[C.Dest].Edges->set(C.Src);
2029 }
2030 }
2031
2032 Node2DFS.insert(Node2DFS.begin(), GraphNodes.size(), 0);
2033 Node2Deleted.insert(Node2Deleted.begin(), GraphNodes.size(), false);
2034 Node2Visited.insert(Node2Visited.begin(), GraphNodes.size(), false);
2035 SDT.insert(SDT.begin(), GraphNodes.size() / 2, -1);
2036
2037 DFSNumber = 0;
2038 for (unsigned i = 0; i < GraphNodes.size(); ++i) {
2039 unsigned Node = HCDSCCRep[i];
2040 if (!Node2Deleted[Node])
2041 Search(Node);
2042 }
2043
2044 for (unsigned i = 0; i < GraphNodes.size(); ++i)
2045 if (GraphNodes[i].Edges != NULL) {
2046 delete GraphNodes[i].Edges;
2047 GraphNodes[i].Edges = NULL;
2048 }
2049
2050 while( !SCCStack.empty() )
2051 SCCStack.pop();
2052
2053 Node2DFS.clear();
2054 Node2Visited.clear();
2055 Node2Deleted.clear();
2056 HCDSCCRep.clear();
2057 DOUT << "HCD complete.\n";
2058 }
2059
2060 // Component of HCD:
2061 // Use Nuutila's variant of Tarjan's algorithm to detect
2062 // Strongly-Connected Components (SCCs). For non-trivial SCCs
2063 // containing ref nodes, insert the appropriate information in SDT.
2064 void Andersens::Search(unsigned Node) {
2065 unsigned MyDFS = DFSNumber++;
2066
2067 Node2Visited[Node] = true;
2068 Node2DFS[Node] = MyDFS;
2069
2070 for (SparseBitVector<>::iterator Iter = GraphNodes[Node].Edges->begin(),
2071 End = GraphNodes[Node].Edges->end();
2072 Iter != End;
2073 ++Iter) {
2074 unsigned J = HCDSCCRep[*Iter];
2075 assert(GraphNodes[J].isRep() && "Debug check; must be representative");
2076 if (!Node2Deleted[J]) {
2077 if (!Node2Visited[J])
2078 Search(J);
2079 if (Node2DFS[Node] > Node2DFS[J])
2080 Node2DFS[Node] = Node2DFS[J];
2081 }
2082 }
2083
2084 if( MyDFS != Node2DFS[Node] ) {
2085 SCCStack.push(Node);
2086 return;
2087 }
2088
2089 // This node is the root of a SCC, so process it.
2090 //
2091 // If the SCC is "non-trivial" (not a singleton) and contains a reference
2092 // node, we place this SCC into SDT. We unite the nodes in any case.
2093 if (!SCCStack.empty() && Node2DFS[SCCStack.top()] >= MyDFS) {
2094 SparseBitVector<> SCC;
2095
2096 SCC.set(Node);
2097
2098 bool Ref = (Node >= FirstRefNode);
2099
2100 Node2Deleted[Node] = true;
2101
2102 do {
2103 unsigned P = SCCStack.top(); SCCStack.pop();
2104 Ref |= (P >= FirstRefNode);
2105 SCC.set(P);
2106 HCDSCCRep[P] = Node;
2107 } while (!SCCStack.empty() && Node2DFS[SCCStack.top()] >= MyDFS);
2108
2109 if (Ref) {
2110 unsigned Rep = SCC.find_first();
2111 assert(Rep < FirstRefNode && "The SCC didn't have a non-Ref node!");
2112
2113 SparseBitVector<>::iterator i = SCC.begin();
2114
2115 // Skip over the non-ref nodes
2116 while( *i < FirstRefNode )
2117 ++i;
2118
2119 while( i != SCC.end() )
2120 SDT[ (*i++) - FirstRefNode ] = Rep;
2121 }
2122 }
2123 }
2124
2125
19872126 /// Optimize the constraints by performing offline variable substitution and
19882127 /// other optimizations.
19892128 void Andersens::OptimizeConstraints() {
19902129 DOUT << "Beginning constraint optimization\n";
2130
2131 SDTActive = false;
19912132
19922133 // Function related nodes need to stay in the same relative position and can't
19932134 // be location equivalent.
20502191 if (FindNode(i) == i) {
20512192 Node *N = &GraphNodes[i];
20522193 delete N->PointsTo;
2194 N->PointsTo = NULL;
20532195 delete N->PredEdges;
2196 N->PredEdges = NULL;
20542197 delete N->ImplicitPredEdges;
2198 N->ImplicitPredEdges = NULL;
20552199 delete N->PointedToBy;
2056 }
2057 }
2200 N->PointedToBy = NULL;
2201 }
2202 }
2203
2204 // perform Hybrid Cycle Detection (HCD)
2205 HCD();
2206 SDTActive = true;
2207
2208 // No longer any need for the upper half of GraphNodes (for ref nodes).
20582209 GraphNodes.erase(GraphNodes.begin() + FirstRefNode, GraphNodes.end());
2210
2211 // HCD complete.
2212
20592213 DOUT << "Finished constraint optimization\n";
20602214 FirstRefNode = 0;
20612215 FirstAdrNode = 0;
22202374 }
22212375 }
22222376 std::queue TarjanWL;
2377 #if !FULL_UNIVERSAL
2378 // "Rep and special variables" - in order for HCD to maintain conservative
2379 // results when !FULL_UNIVERSAL, we need to treat the special variables in
2380 // the same way that the !FULL_UNIVERSAL tweak does throughout the rest of
2381 // the analysis - it's ok to add edges from the special nodes, but never
2382 // *to* the special nodes.
2383 std::vector RSV;
2384 #endif
22232385 while( !CurrWL->empty() ) {
22242386 DOUT << "Starting iteration #" << ++NumIters << "\n";
22252387
22582420 continue;
22592421
22602422 *(CurrNode->OldPointsTo) |= CurrPointsTo;
2423
2424 // Check the offline-computed equivalencies from HCD.
2425 bool SCC = false;
2426 unsigned Rep;
2427
2428 if (SDT[CurrNodeIndex] >= 0) {
2429 SCC = true;
2430 Rep = FindNode(SDT[CurrNodeIndex]);
2431
2432 #if !FULL_UNIVERSAL
2433 RSV.clear();
2434 #endif
2435 for (SparseBitVector<>::iterator bi = CurrPointsTo.begin();
2436 bi != CurrPointsTo.end(); ++bi) {
2437 unsigned Node = FindNode(*bi);
2438 #if !FULL_UNIVERSAL
2439 if (Node < NumberSpecialNodes) {
2440 RSV.push_back(Node);
2441 continue;
2442 }
2443 #endif
2444 Rep = UniteNodes(Rep,Node);
2445 }
2446 #if !FULL_UNIVERSAL
2447 RSV.push_back(Rep);
2448 #endif
2449
2450 NextWL->insert(&GraphNodes[Rep]);
2451
2452 if ( ! CurrNode->isRep() )
2453 continue;
2454 }
2455
22612456 Seen.clear();
22622457
22632458 /* Now process the constraints for this node. */
23002495 li++;
23012496 continue;
23022497 }
2303 // TODO: hybrid cycle detection would go here, we should check
2498
2499 // See if we can use Hybrid Cycle Detection (that is, check
23042500 // if it was a statically detected offline equivalence that
2305 // involves pointers , and if so, remove the redundant constraints.
2306
2307 const SparseBitVector<> &Solution = CurrPointsTo;
2308
2309 for (SparseBitVector<>::iterator bi = Solution.begin();
2310 bi != Solution.end();
2311 ++bi) {
2312 CurrMember = *bi;
2313
2314 // Need to increment the member by K since that is where we are
2315 // supposed to copy to/from. Note that in positive weight cycles,
2316 // which occur in address taking of fields, K can go past
2317 // MaxK[CurrMember] elements, even though that is all it could point
2318 // to.
2319 if (K > 0 && K > MaxK[CurrMember])
2320 continue;
2321 else
2322 CurrMember = FindNode(CurrMember + K);
2323
2324 // Add an edge to the graph, so we can just do regular bitmap ior next
2325 // time. It may also let us notice a cycle.
2326 #if !FULL_UNIVERSAL
2327 if (*Dest < NumberSpecialNodes)
2328 continue;
2329 #endif
2501 // involves pointers; if so, remove the redundant constraints).
2502 if( SCC && K == 0 ) {
2503 #if FULL_UNIVERSAL
2504 CurrMember = Rep;
2505
23302506 if (GraphNodes[*Src].Edges->test_and_set(*Dest))
23312507 if (GraphNodes[*Dest].PointsTo |= *(GraphNodes[*Src].PointsTo))
23322508 NextWL->insert(&GraphNodes[*Dest]);
2333
2509 #else
2510 for (unsigned i=0; i < RSV.size(); ++i) {
2511 CurrMember = RSV[i];
2512
2513 if (*Dest < NumberSpecialNodes)
2514 continue;
2515 if (GraphNodes[*Src].Edges->test_and_set(*Dest))
2516 if (GraphNodes[*Dest].PointsTo |= *(GraphNodes[*Src].PointsTo))
2517 NextWL->insert(&GraphNodes[*Dest]);
2518 }
2519 #endif
2520 // since all future elements of the points-to set will be
2521 // equivalent to the current ones, the complex constraints
2522 // become redundant.
2523 //
2524 std::list::iterator lk = li; li++;
2525 #if !FULL_UNIVERSAL
2526 // In this case, we can still erase the constraints when the
2527 // elements of the points-to sets are referenced by *Dest,
2528 // but not when they are referenced by *Src (i.e. for a Load
2529 // constraint). This is because if another special variable is
2530 // put into the points-to set later, we still need to add the
2531 // new edge from that special variable.
2532 if( lk->Type != Constraint::Load)
2533 #endif
2534 GraphNodes[CurrNodeIndex].Constraints.erase(lk);
2535 } else {
2536 const SparseBitVector<> &Solution = CurrPointsTo;
2537
2538 for (SparseBitVector<>::iterator bi = Solution.begin();
2539 bi != Solution.end();
2540 ++bi) {
2541 CurrMember = *bi;
2542
2543 // Need to increment the member by K since that is where we are
2544 // supposed to copy to/from. Note that in positive weight cycles,
2545 // which occur in address taking of fields, K can go past
2546 // MaxK[CurrMember] elements, even though that is all it could point
2547 // to.
2548 if (K > 0 && K > MaxK[CurrMember])
2549 continue;
2550 else
2551 CurrMember = FindNode(CurrMember + K);
2552
2553 // Add an edge to the graph, so we can just do regular
2554 // bitmap ior next time. It may also let us notice a cycle.
2555 #if !FULL_UNIVERSAL
2556 if (*Dest < NumberSpecialNodes)
2557 continue;
2558 #endif
2559 if (GraphNodes[*Src].Edges->test_and_set(*Dest))
2560 if (GraphNodes[*Dest].PointsTo |= *(GraphNodes[*Src].PointsTo))
2561 NextWL->insert(&GraphNodes[*Dest]);
2562
2563 }
2564 li++;
23342565 }
2335 li++;
23362566 }
23372567 SparseBitVector<> NewEdges;
23382568 SparseBitVector<> ToErase;
23502580 // got an edge for the representative, delete the current edge.
23512581 if (Rep == CurrNodeIndex ||
23522582 (Rep != DestVar && NewEdges.test(Rep))) {
2353 ToErase.set(DestVar);
2354 continue;
2583 ToErase.set(DestVar);
2584 continue;
23552585 }
23562586
23572587 std::pair edge(CurrNodeIndex,Rep);
23942624 delete N->OldPointsTo;
23952625 delete N->Edges;
23962626 }
2627 SDTActive = false;
2628 SDT.clear();
23972629 }
23982630
23992631 //===----------------------------------------------------------------------===//
24602692 DEBUG(PrintNode(SecondNode));
24612693 DOUT << "\n";
24622694
2463 // TODO: Handle SDT
2695 if (SDTActive)
2696 if (SDT[Second] >= 0)
2697 if (SDT[First] < 0)
2698 SDT[First] = SDT[Second];
2699 else {
2700 UniteNodes( FindNode(SDT[First]), FindNode(SDT[Second]) );
2701 First = FindNode(First);
2702 }
2703
24642704 return First;
24652705 }
24662706