blob: 0cf08b2df647a12910989728d9966c2af4cd33ab [file] [log] [blame]
//===- EquivClassGraphs.cpp - Merge equiv-class graphs & inline bottom-up -===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass is the same as the complete bottom-up graphs, but
// with functions partitioned into equivalence classes and a single merged
// DS graph for all functions in an equivalence class. After this merging,
// graphs are inlined bottom-up on the SCCs of the final (CBU) call graph.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "ECGraphs"
#include "dsa/DataStructure.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "dsa/DSGraph.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/EquivalenceClasses.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/FormattedStream.h"
#include <fstream>
using namespace llvm;
namespace {
RegisterPass<EquivBUDataStructures> X("dsa-eq",
"Equivalence-class Bottom-up Data Structure Analysis");
}
char EquivBUDataStructures::ID = 0;
// runOnModule - Calculate the bottom up data structure graphs for each function
// in the program.
//
bool EquivBUDataStructures::runOnModule(Module &M) {
init(&getAnalysis<CompleteBUDataStructures>(), true, true, false, true);
//make a list of all the DSGraphs
std::set<DSGraph *>graphList;
for(Module::iterator F = M.begin(); F != M.end(); ++F)
{
if(!(F->isDeclaration()))
graphList.insert(getOrCreateGraph(F));
}
//update the EQ class from indirect calls
buildIndirectFunctionSets();
formGlobalECs();
mergeGraphsByGlobalECs();
//remove all the DSGraph, that still have references
for(Module::iterator F = M.begin(); F != M.end(); ++F)
{
if(!(F->isDeclaration()))
graphList.erase(getOrCreateGraph(F));
}
// free memory for the DSGraphs, no longer in use.
for(std::set<DSGraph*>::iterator i = graphList.begin(),e = graphList.end();
i!=e;i++) {
delete (*i);
}
DEBUG(verifyMerging());
formGlobalECs();
for (Module::iterator F = M.begin(); F != M.end(); ++F) {
if (!(F->isDeclaration())) {
if (DSGraph * Graph = getOrCreateGraph(F)) {
cloneGlobalsInto(Graph, DSGraph::DontCloneCallNodes |
DSGraph::DontCloneAuxCallNodes);
}
}
}
bool result = runOnModuleInternal(M);
// CBU contains the correct call graph.
// Restore it, so that subsequent passes and clients can get it.
restoreCorrectCallGraph();
return result;
}
// Verifies that all the functions in an equivalence calss have been merged.
// This is required by to be true by poolallocation.
void
EquivBUDataStructures::verifyMerging() {
EquivalenceClasses<const GlobalValue*>::iterator EQSI = GlobalECs.begin();
EquivalenceClasses<const GlobalValue*>::iterator EQSE = GlobalECs.end();
for (;EQSI != EQSE; ++EQSI) {
if (!EQSI->isLeader()) continue;
EquivalenceClasses<const GlobalValue*>::member_iterator MI;
bool first = true;
DSGraph *firstG = 0;
for (MI = GlobalECs.member_begin(EQSI); MI != GlobalECs.member_end(); ++MI){
if (const Function* F = dyn_cast<Function>(*MI)){
if (F->isDeclaration())
continue;
if(first) {
firstG = getOrCreateGraph(F);
first = false;
}
DSGraph *G = getOrCreateGraph(F);
if( G != firstG) {
assert(G == firstG && "all functions in a Global EC do not have a merged graph");
}
}
}
}
}
//
// Method: mergeGraphsByGlobalECs()
//
// Description:
// Merge all graphs that are in the same equivalence class. This ensures
// that transforms like Automatic Pool Allocation only see one graph for a
// call site.
//
// After this method is executed, all functions in an equivalence class will
// have the *same* DSGraph.
//
void
EquivBUDataStructures::mergeGraphsByGlobalECs() {
//
// Merge the graphs for each equivalence class. We first scan all elements
// in the equivalence classes and look for those elements which are leaders.
// For each leader, we scan through all of its members and merge the DSGraphs
// for members which are functions.
//
EquivalenceClasses<const GlobalValue*>::iterator EQSI = GlobalECs.begin();
EquivalenceClasses<const GlobalValue*>::iterator EQSE = GlobalECs.end();
for (;EQSI != EQSE; ++EQSI) {
//
// If this element is not a leader, then skip it.
//
if (!EQSI->isLeader()) continue;
DSGraph* BaseGraph = 0;
std::vector<DSNodeHandle> Args;
//
// Iterate through all members of this equivalence class, looking for
// functions.
//
EquivalenceClasses<const GlobalValue*>::member_iterator MI;
for (MI = GlobalECs.member_begin(EQSI); MI != GlobalECs.member_end(); ++MI){
if (const Function* F = dyn_cast<Function>(*MI)) {
//
// If the function has no body, then it has no DSGraph.
//
// FIXME: I don't believe this is correct; the stdlib pass can assign
// DSGraphs to C standard library functions.
//
if (F->isDeclaration())
continue;
//
// We have one of three possibilities:
// 1) This is the first function we've seen. If so, grab its DSGraph
// and the DSNodes for its arguments.
//
// 2) We have already seen this function before. Do nothing.
//
// 3) We haven't seen this function before, and it's not the first one
// we've seen. Merge its DSGraph into the DSGraph we're creating.
//
if (!BaseGraph) {
BaseGraph = getOrCreateGraph(F);
BaseGraph->getFunctionArgumentsForCall(F, Args);
} else if (BaseGraph->containsFunction(F)) {
//
// The DSGraph for this function has already been merged into the
// graph that we are creating. However, that does not mean that
// function arguments of this function have been merged with the
// function arguments of the other functions in the equivalence graph
// (or even with functions belonging to the same SCC in the call
// graph). Furthermore, it doesn't necessarily imply that the
// contained function's DSGraph is the same as the one we're
// building; it is possible (I think) for only the function's DSNodes
// and other information to have been merged in.
//
// For these reasons, we will merge the function argument DSNodes and
// set this function's DSGraph to be the same graph used for all
// other function's in this equivalence class.
//
//
// Merge the arguments together.
//
std::vector<DSNodeHandle> NextArgs;
BaseGraph->getFunctionArgumentsForCall(F, NextArgs);
unsigned i = 0, e = Args.size();
for (; i != e; ++i) {
if (i == NextArgs.size()) break;
Args[i].mergeWith(NextArgs[i]);
}
for (e = NextArgs.size(); i != e; ++i)
Args.push_back(NextArgs[i]);
//
// Make this function use the DSGraph that we're creating for all of
// the functions in this equivalence class.
//
setDSGraph(*F, BaseGraph);
} else {
//
// Merge in the DSGraph.
//
BaseGraph->cloneInto(getOrCreateGraph(F));
//
// Merge the arguments together.
//
std::vector<DSNodeHandle> NextArgs;
BaseGraph->getFunctionArgumentsForCall(F, NextArgs);
unsigned i = 0, e = Args.size();
for (; i != e; ++i) {
if (i == NextArgs.size()) break;
Args[i].mergeWith(NextArgs[i]);
}
for (e = NextArgs.size(); i != e; ++i)
Args.push_back(NextArgs[i]);
//
// Make this function use the DSGraph that we're creating for all of
// the functions in this equivalence class.
//
setDSGraph(*F, BaseGraph);
}
}
}
//
// Update the globals graph with any information that has changed due to
// graph merging.
//
if (BaseGraph)
cloneIntoGlobals(BaseGraph, DSGraph::DontCloneCallNodes |
DSGraph::DontCloneAuxCallNodes |
DSGraph::StripAllocaBit);
}
}