In the new call graph, find the SCCs in bottom-up order.

With this change we generate the SCCs in the call graph (for the kinds
of calls we currently recognize) in bottom-up, which we can then
iterate over directly or in reverse for invocation- and
reverse-invocation-order traversal of the call graph.

(This still isn't hooked up - but will be after some dumping routines
and verification of the output).

Swift SVN r21552
This commit is contained in:
Mark Lacey
2014-08-29 00:32:17 +00:00
parent 24e361635b
commit 36365d79df
2 changed files with 109 additions and 1 deletions

View File

@@ -11,7 +11,12 @@
//===----------------------------------------------------------------------===//
#include "swift/SILAnalysis/CallGraphAnalysis.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include <algorithm>
#include <utility>
using namespace swift;
@@ -153,3 +158,87 @@ void CallGraph::addEdges(SILFunction *F) {
if (auto *AI = dyn_cast<ApplyInst>(&I))
addEdgesForApply(AI, CallerNode);
}
static void orderCallees(const CallGraphEdge::CalleeSetType &Callees,
llvm::SmallVectorImpl<CallGraphNode *> &OrderedNodes) {
for (auto *Node : Callees)
OrderedNodes.push_back(Node);
std::sort(OrderedNodes.begin(), OrderedNodes.end(),
[](CallGraphNode *left, CallGraphNode *right) {
return left->getOrdinal() < right->getOrdinal();
});
}
/// Finds SCCs in the call graph. Our call graph has an unconventional
/// form where each edge of the graph is really a multi-edge that can
/// point to multiple call graph nodes in the case where we can call
/// one of several different functions.
class CallGraphSCCFinder {
public:
CallGraphSCCFinder(llvm::SmallVectorImpl<CallGraphSCC *> &TheSCCs)
: NextDFSNum(0), TheSCCs(TheSCCs) {}
void DFS(CallGraphNode *Node) {
// Set the DFSNum for this node if we haven't already, and if we
// have, which indicates it's already been visited, return.
if (!DFSNum.insert(std::make_pair(Node, NextDFSNum)).second)
return;
assert(MinDFSNum.find(Node) == MinDFSNum.end() &&
"Node should not already have a minimum DFS number!");
MinDFSNum[Node] = NextDFSNum;
++NextDFSNum;
DFSStack.insert(Node);
for (auto *CallSite : Node->getCallSites()) {
llvm::SmallVector<CallGraphNode *, 4> OrderedNodes;
orderCallees(CallSite->getCalleeSet(), OrderedNodes);
for (auto *CalleeNode : OrderedNodes) {
if (DFSNum.find(CalleeNode) == DFSNum.end()) {
DFS(CalleeNode);
MinDFSNum[Node] = std::min(MinDFSNum[Node], MinDFSNum[CalleeNode]);
} else if (DFSStack.count(CalleeNode)) {
MinDFSNum[Node] = std::min(MinDFSNum[Node], DFSNum[CalleeNode]);
}
}
}
// If this node is the root of an SCC (including SCCs with a
// single node), pop the SCC and push it on our SCC stack.
if (DFSNum[Node] == MinDFSNum[Node]) {
auto *SCC = new CallGraphSCC();
CallGraphNode *Popped;
do {
Popped = DFSStack.pop_back_val();
SCC->SCCNodes.push_back(Popped);
} while (Popped != Node);
TheSCCs.push_back(SCC);
}
}
private:
unsigned NextDFSNum;
llvm::SmallVectorImpl<CallGraphSCC *> &TheSCCs;
llvm::DenseMap<CallGraphNode *, unsigned> DFSNum;
llvm::DenseMap<CallGraphNode *, unsigned> MinDFSNum;
llvm::SetVector<CallGraphNode *> DFSStack;
};
void CallGraph::computeBottomUpSCCOrder() {
if (!BottomUpSCCOrder.empty()) {
for (auto *SCC : BottomUpSCCOrder)
delete SCC;
BottomUpSCCOrder.clear();
}
for (auto *Node : getCallGraphRoots())
CallGraphSCCFinder(BottomUpSCCOrder).DFS(Node);
}