Many changes

* Simplify a lot of the inlining stuff.  There are still problems, but not
  many
* Break up the Function representation to have a vector for every different
  node type so it is fast to find nodes of a particular flavor.
* Do more intelligent merging of call values
* Allow elimination of unreachable shadow and allocation nodes
* Generalize indistinguishability testing to allow merging of identical calls.
* Increase shadow node merging power


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@2010 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2002-03-28 17:56:03 +00:00
parent 1d8ec6194a
commit 1120c8b34a
6 changed files with 389 additions and 320 deletions

View File

@ -15,119 +15,37 @@
#include "llvm/Assembly/Writer.h"
#endif
// copyEdgesFromTo - Make a copy of all of the edges to Node to also point
// PV. If there are edges out of Node, the edges are added to the subgraph
// starting at PV.
// Make all of the pointers that point to Val also point to N.
//
static void copyEdgesFromTo(DSNode *Node, const PointerValSet &PVS) {
// Make all of the pointers that pointed to Node now also point to PV...
const vector<PointerValSet*> &PVSToUpdate(Node->getReferrers());
static void copyEdgesFromTo(PointerVal Val, DSNode *N) {
assert(Val.Index == 0 && "copyEdgesFromTo:index != 0 TODO");
const vector<PointerValSet*> &PVSToUpdate(Val.Node->getReferrers());
for (unsigned i = 0, e = PVSToUpdate.size(); i != e; ++i)
for (unsigned pn = 0, pne = PVS.size(); pn != pne; ++pn)
PVSToUpdate[i]->add(PVS[pn]);
PVSToUpdate[i]->add(N); // TODO: support index
}
static void CalculateNodeMapping(ShadowDSNode *Shadow, DSNode *Node,
multimap<ShadowDSNode *, DSNode *> &NodeMapping) {
#ifdef DEBUG_IP_CLOSURE
cerr << "Mapping " << (void*)Shadow << " to " << (void*)Node << "\n";
cerr << "Type = '" << Shadow->getType() << "' and '"
<< Node->getType() << "'\n";
cerr << "Shadow Node:\n";
Shadow->print(cerr);
cerr << "\nMapped Node:\n";
Node->print(cerr);
#endif
assert(Shadow->getType() == Node->getType() &&
"Shadow and mapped nodes disagree about type!");
multimap<ShadowDSNode *, DSNode *>::iterator
NI = NodeMapping.lower_bound(Shadow),
NE = NodeMapping.upper_bound(Shadow);
for (; NI != NE; ++NI)
if (NI->second == Node) return; // Already processed node, return.
NodeMapping.insert(make_pair(Shadow, Node)); // Add a mapping...
// Loop over all of the outgoing links in the shadow node...
//
assert(Node->getNumLinks() == Shadow->getNumLinks() &&
"Same type, but different number of links?");
for (unsigned i = 0, e = Shadow->getNumLinks(); i != e; ++i) {
PointerValSet &Link = Shadow->getLink(i);
// Loop over all of the values coming out of this pointer...
for (unsigned l = 0, le = Link.size(); l != le; ++l) {
// If the outgoing node points to a shadow node, map the shadow node to
// all of the outgoing values in Node.
//
if (ShadowDSNode *ShadOut = dyn_cast<ShadowDSNode>(Link[l].Node)) {
PointerValSet &NLink = Node->getLink(i);
for (unsigned ol = 0, ole = NLink.size(); ol != ole; ++ol)
CalculateNodeMapping(ShadOut, NLink[ol].Node, NodeMapping);
}
}
}
}
static void ResolveNodesTo(const PointerVal &FromPtr,
const PointerValSet &ToVals) {
assert(FromPtr.Index == 0 &&
"Resolved node return pointer should be index 0!");
if (!isa<ShadowDSNode>(FromPtr.Node)) return;
assert(isa<ShadowDSNode>(FromPtr.Node) &&
"Resolved node should be a shadow!");
ShadowDSNode *Shadow = cast<ShadowDSNode>(FromPtr.Node);
assert(Shadow->isCriticalNode() && "Shadow node should be a critical node!");
Shadow->resetCriticalMark();
typedef multimap<ShadowDSNode *, DSNode *> ShadNodeMapTy;
ShadNodeMapTy NodeMapping;
for (unsigned i = 0, e = ToVals.size(); i != e; ++i)
CalculateNodeMapping(Shadow, ToVals[i].Node, NodeMapping);
// Now loop through the shadow node graph, mirroring the edges in the shadow
// graph onto the realized graph...
// Make everything that pointed to the shadow node also point to the values in
// ToVals...
//
for (ShadNodeMapTy::iterator I = NodeMapping.begin(),
E = NodeMapping.end(); I != E; ++I) {
DSNode *Node = I->second;
ShadowDSNode *ShadNode = I->first;
PointerValSet PVSx;
PVSx.add(Node);
copyEdgesFromTo(ShadNode, PVSx);
for (unsigned i = 0, e = ToVals.size(); i != e; ++i)
copyEdgesFromTo(ToVals[i], Shadow);
// Must loop over edges in the shadow graph, adding edges in the real graph
// that correspond to to the edges, but are mapped into real values by the
// NodeMapping.
//
for (unsigned i = 0, e = Node->getNumLinks(); i != e; ++i) {
const PointerValSet &ShadLinks = ShadNode->getLink(i);
PointerValSet &NewLinks = Node->getLink(i);
// Add a link to all of the nodes pointed to by the shadow field...
for (unsigned l = 0, le = ShadLinks.size(); l != le; ++l) {
DSNode *ShadLink = ShadLinks[l].Node;
if (ShadowDSNode *SL = dyn_cast<ShadowDSNode>(ShadLink)) {
// Loop over all of the values in the range
ShadNodeMapTy::iterator St = NodeMapping.lower_bound(SL),
En = NodeMapping.upper_bound(SL);
if (St != En) {
for (; St != En; ++St)
NewLinks.add(PointerVal(St->second, ShadLinks[l].Index));
} else {
// We must retain the shadow node...
NewLinks.add(ShadLinks[l]);
}
} else {
// Otherwise, add a direct link to the data structure pointed to by
// the shadow node...
NewLinks.add(ShadLinks[l]);
}
}
}
}
// Make everything that pointed to the shadow node now also point to the
// values it is equivalent to...
const vector<PointerValSet*> &PVSToUpdate(Shadow->getReferrers());
for (unsigned i = 0, e = PVSToUpdate.size(); i != e; ++i)
PVSToUpdate[i]->add(ToVals);
}
@ -137,20 +55,21 @@ static void ResolveNodesTo(const PointerVal &FromPtr,
static void ResolveNodeTo(DSNode *Node, const PointerValSet &ToVals) {
assert(Node->getNumLinks() == 1 && "Resolved node can only be a scalar!!");
PointerValSet PVS = Node->getLink(0);
const PointerValSet &PVS = Node->getLink(0);
for (unsigned i = 0, e = PVS.size(); i != e; ++i)
ResolveNodesTo(PVS[i], ToVals);
// Only resolve the first pointer, although there many be many pointers here.
// The problem is that the inlined function might return one of the arguments
// to the function, and if so, extra values can be added to the arg or call
// node that point to what the other one got resolved to. Since these will
// be added to the end of the PVS pointed in, we just ignore them.
//
ResolveNodesTo(PVS[0], ToVals);
}
// isResolvableCallNode - Return true if node is a call node and it is a call
// node that we can inline...
//
static bool isResolvableCallNode(DSNode *N) {
// Only operate on call nodes...
CallDSNode *CN = dyn_cast<CallDSNode>(N);
if (CN == 0) return false;
static bool isResolvableCallNode(CallDSNode *CN) {
// Only operate on call nodes with direct method calls
Function *F = CN->getCall()->getCalledFunction();
if (F == 0) return false;
@ -164,35 +83,42 @@ static bool isResolvableCallNode(DSNode *N) {
// of their corresponding method data structure graph...
//
void FunctionDSGraph::computeClosure(const DataStructure &DS) {
vector<DSNode*>::iterator NI = std::find_if(Nodes.begin(), Nodes.end(),
isResolvableCallNode);
typedef pair<vector<PointerValSet>, CallInst *> CallDescriptor;
map<CallDescriptor, PointerValSet> CallMap;
map<Function*, unsigned> InlineCount; // FIXME
unsigned NumInlines = 0;
// Loop over the resolvable call nodes...
while (NI != Nodes.end()) {
CallDSNode *CN = cast<CallDSNode>(*NI);
vector<CallDSNode*>::iterator NI;
NI = std::find_if(CallNodes.begin(), CallNodes.end(), isResolvableCallNode);
while (NI != CallNodes.end()) {
CallDSNode *CN = *NI;
Function *F = CN->getCall()->getCalledFunction();
//if (F == Func) return; // Do not do self inlining
// FIXME: Gross hack to prevent explosions when inlining a recursive func.
if (InlineCount[F]++ > 2) return;
if (NumInlines++ == 30) { // CUTE hack huh?
cerr << "Infinite (?) recursion halted\n";
return;
}
Nodes.erase(NI); // Remove the call node from the graph
CallNodes.erase(NI); // Remove the call node from the graph
unsigned CallNodeOffset = NI-Nodes.begin();
unsigned CallNodeOffset = NI-CallNodes.begin();
// StartNode - The first node of the incorporated graph, last node of the
// preexisting data structure graph...
// Find out if we have already incorporated this node... if so, it will be
// in the CallMap...
//
unsigned StartNode = Nodes.size();
CallDescriptor FDesc(CN->getArgs(), CN->getCall());
map<CallDescriptor, PointerValSet>::iterator CMI = CallMap.find(FDesc);
// Hold the set of values that correspond to the incorporated methods
// return set.
//
PointerValSet RetVals;
if (F != Func) { // If this is not a recursive call...
if (CMI != CallMap.end()) {
// We have already inlined an identical function call!
RetVals = CMI->second;
} else {
// Get the datastructure graph for the new method. Note that we are not
// allowed to modify this graph because it will be the cached graph that
// is returned by other users that want the local datastructure graph for
@ -200,23 +126,58 @@ void FunctionDSGraph::computeClosure(const DataStructure &DS) {
//
const FunctionDSGraph &NewFunction = DS.getDSGraph(F);
unsigned StartShadowNodes = ShadowNodes.size();
// StartNode - The first node of the incorporated graph, last node of the
// preexisting data structure graph...
//
unsigned StartArgNode = ArgNodes.size();
unsigned StartAllocNode = AllocNodes.size();
// Incorporate a copy of the called function graph into the current graph,
// allowing us to do local transformations to local graph to link
// arguments to call values, and call node to return value...
//
RetVals = cloneFunctionIntoSelf(NewFunction, false);
RetVals = cloneFunctionIntoSelf(NewFunction, F == Func);
CallMap[FDesc] = RetVals;
// Only detail is that we need to reset all of the critical shadow nodes
// in the incorporated graph, because they are now no longer critical.
// If the call node has arguments, process them now!
if (CN->getNumArgs()) {
// The ArgNodes of the incorporated graph should be the nodes starting
// at StartNode, ordered the same way as the call arguments. The arg
// nodes are seperated by a single shadow node, but that shadow node
// might get eliminated in the process of optimization.
//
for (unsigned i = 0, e = CN->getNumArgs(); i != e; ++i) {
// Get the arg node of the incorporated method...
ArgDSNode *ArgNode = ArgNodes[StartArgNode];
// Now we make all of the nodes inside of the incorporated method
// point to the real arguments values, not to the shadow nodes for the
// argument.
//
ResolveNodeTo(ArgNode, CN->getArgValues(i));
// Remove the argnode from the set of nodes in this method...
ArgNodes.erase(ArgNodes.begin()+StartArgNode);
// ArgNode is no longer useful, delete now!
delete ArgNode;
}
}
// Loop through the nodes, deleting alloca nodes in the inlined function.
// Since the memory has been released, we cannot access their pointer
// fields (with defined results at least), so it is not possible to use
// any pointers to the alloca. Drop them now, and remove the alloca's
// since they are dead (we just removed all links to them).
//
for (unsigned i = StartShadowNodes, e = ShadowNodes.size(); i != e; ++i)
ShadowNodes[i]->resetCriticalMark();
} else { // We are looking at a recursive function!
StartNode = 0; // Arg nodes start at 0 now...
RetVals = RetNode;
for (unsigned i = StartAllocNode; i != AllocNodes.size(); ++i)
if (AllocNodes[i]->isAllocaNode()) {
AllocDSNode *NDS = AllocNodes[i];
NDS->removeAllIncomingEdges(); // These edges are invalid now
delete NDS; // Node is dead
AllocNodes.erase(AllocNodes.begin()+i); // Remove slot in Nodes array
--i; // Don't skip the next node
}
}
// If the function returns a pointer value... Resolve values pointing to
@ -224,56 +185,6 @@ void FunctionDSGraph::computeClosure(const DataStructure &DS) {
//
if (CN->getNumLinks()) ResolveNodeTo(CN, RetVals);
// If the call node has arguments, process them now!
if (CN->getNumArgs()) {
// The ArgNodes of the incorporated graph should be the nodes starting at
// StartNode, ordered the same way as the call arguments. The arg nodes
// are seperated by a single shadow node, but that shadow node might get
// eliminated in the process of optimization.
//
unsigned ArgOffset = StartNode;
for (unsigned i = 0, e = CN->getNumArgs(); i != e; ++i) {
// Get the arg node of the incorporated method...
while (!isa<ArgDSNode>(Nodes[ArgOffset])) // Scan for next arg node
ArgOffset++;
ArgDSNode *ArgNode = cast<ArgDSNode>(Nodes[ArgOffset]);
// Now we make all of the nodes inside of the incorporated method point
// to the real arguments values, not to the shadow nodes for the
// argument.
//
ResolveNodeTo(ArgNode, CN->getArgValues(i));
if (StartNode) { // Not Self recursion?
// Remove the argnode from the set of nodes in this method...
Nodes.erase(Nodes.begin()+ArgOffset);
// ArgNode is no longer useful, delete now!
delete ArgNode;
} else {
ArgOffset++; // Step to the next argument...
}
}
}
// Loop through the nodes, deleting alloc nodes in the inlined function...
// Since the memory has been released, we cannot access their pointer
// fields (with defined results at least), so it is not possible to use any
// pointers to the alloca. Drop them now, and remove the alloca's since
// they are dead (we just removed all links to them). Only do this if we
// are not self recursing though. :)
//
if (StartNode) // Don't do this if self recursing...
for (unsigned i = StartNode; i != Nodes.size(); ++i)
if (NewDSNode *NDS = dyn_cast<NewDSNode>(Nodes[i]))
if (NDS->isAllocaNode()) {
NDS->removeAllIncomingEdges(); // These edges are invalid now!
delete NDS; // Node is dead
Nodes.erase(Nodes.begin()+i); // Remove slot in Nodes array
--i; // Don't skip the next node
}
// Now the call node is completely destructable. Eliminate it now.
delete CN;
@ -291,6 +202,6 @@ void FunctionDSGraph::computeClosure(const DataStructure &DS) {
//if (F == Func) return; // Only do one self inlining
// Move on to the next call node...
NI = std::find_if(Nodes.begin(), Nodes.end(), isResolvableCallNode);
NI = std::find_if(CallNodes.begin(), CallNodes.end(), isResolvableCallNode);
}
}

View File

@ -90,6 +90,28 @@ const PointerValSet &PointerValSet::operator=(const PointerValSet &PVS) {
return *this;
}
// operator< - Allow insertion into a map...
bool PointerValSet::operator<(const PointerValSet &PVS) const {
if (Vals.size() < PVS.Vals.size()) return true;
if (Vals.size() > PVS.Vals.size()) return false;
if (Vals.size() == 1) return Vals[0] < PVS.Vals[0]; // Most common case
vector<PointerVal> S1(Vals), S2(PVS.Vals);
sort(S1.begin(), S1.end());
sort(S2.begin(), S2.end());
return S1 < S2;
}
bool PointerValSet::operator==(const PointerValSet &PVS) const {
if (Vals.size() != PVS.Vals.size()) return false;
if (Vals.size() == 1) return Vals[0] == PVS.Vals[0]; // Most common case...
vector<PointerVal> S1(Vals), S2(PVS.Vals);
sort(S1.begin(), S1.end());
sort(S2.begin(), S2.end());
return S1 == S2;
}
bool PointerValSet::add(const PointerVal &PV, Value *Pointer) {
if (std::find(Vals.begin(), Vals.end(), PV) != Vals.end())

View File

@ -21,157 +21,216 @@
//#define DEBUG_NODE_ELIMINATE 1
bool AllocDSNode::isEquivalentTo(DSNode *Node) const {
if (AllocDSNode *N = dyn_cast<AllocDSNode>(Node))
return N->Allocation == Allocation;
return false;
}
bool GlobalDSNode::isEquivalentTo(DSNode *Node) const {
if (GlobalDSNode *G = dyn_cast<GlobalDSNode>(Node))
return G->Val == Val;
return false;
}
bool CallDSNode::isEquivalentTo(DSNode *Node) const {
if (CallDSNode *C = dyn_cast<CallDSNode>(Node))
return C->CI == CI && C->ArgLinks == ArgLinks;
return false;
}
bool ArgDSNode::isEquivalentTo(DSNode *Node) const {
return false;
}
// NodesAreEquivalent - Check to see if the nodes are equivalent in all ways
// except node type. Since we know N1 is a shadow node, N2 is allowed to be
// any type.
//
static bool NodesAreEquivalent(const ShadowDSNode *N1, const DSNode *N2) {
assert(N1 != N2 && "A node is always equivalent to itself!");
// Perform simple, fast checks first...
if (N1->getType() != N2->getType() || // Must have same type...
N1->isCriticalNode()) // Must not be a critical node...
return false;
#if 0
return true;
#else
// The shadow node is considered equivalent if it has a subset of the incoming
// edges that N2 does...
if (N1->getReferrers().size() > N2->getReferrers().size()) return false;
// Check to see if the referring (incoming) pointers are all the same...
std::vector<PointerValSet*> N1R = N1->getReferrers();
std::vector<PointerValSet*> N2R = N2->getReferrers();
sort(N1R.begin(), N1R.end());
sort(N2R.begin(), N2R.end());
// The nodes are equivalent if the incoming edges to N1 are a subset of N2.
unsigned i1 = 0, e1 = N1R.size();
unsigned i2 = 0, e2 = N2R.size();
for (; i1 != e1 && i2 < e2; ++i1, ++i2) {
while (N1R[i1] > N2R[i2] && i2 < e2)
++i2;
if (N1R[i1] < N2R[i2]) return false; // Error case...
}
return i1 == e1 && i2 <= e2;
#endif
bool ShadowDSNode::isEquivalentTo(DSNode *Node) const {
return !isCriticalNode(); // Must not be a critical node...
}
// IndistinguishableShadowNode - A shadow node is indistinguishable if some
// other node (shadow or otherwise) has exactly the same incoming and outgoing
// links to it (or if there are no edges coming in, in which it is trivially
// dead).
// isIndistinguishableNode - A node is indistinguishable if some other node
// has exactly the same incoming links to it and if the node considers itself
// to be the same as the other node...
//
static bool IndistinguishableShadowNode(const ShadowDSNode *SN) {
if (SN->getReferrers().empty()) return true; // Node is trivially dead
bool isIndistinguishableNode(DSNode *DN) {
if (DN->getReferrers().empty()) { // No referrers...
if (isa<ShadowDSNode>(DN) || isa<AllocDSNode>(DN))
return true; // Node is trivially dead
else
return false;
}
// Pick a random referrer... Ptr is the things that the referrer points to.
// Since SN is in the Ptr set, look through the set seeing if there are any
// other nodes that are exactly equilivant to SN (with the exception of node
// type), but are not SN. If anything exists, then SN is indistinguishable.
// Since DN is in the Ptr set, look through the set seeing if there are any
// other nodes that are exactly equilivant to DN (with the exception of node
// type), but are not DN. If anything exists, then DN is indistinguishable.
//
const PointerValSet &Ptr = *SN->getReferrers()[0];
const std::vector<PointerValSet*> &Refs = DN->getReferrers();
for (unsigned R = 0, RE = Refs.size(); R != RE; ++R) {
const PointerValSet &Ptr = *Refs[R];
for (unsigned i = 0, e = Ptr.size(); i != e; ++i)
if (Ptr[i].Index == 0 && Ptr[i].Node != cast<DSNode>(SN) &&
NodesAreEquivalent(SN, Ptr[i].Node))
return true;
for (unsigned i = 0, e = Ptr.size(); i != e; ++i) {
DSNode *N2 = Ptr[i].Node;
if (Ptr[i].Index == 0 && N2 != cast<DSNode>(DN) &&
DN->getType() == N2->getType() && DN->isEquivalentTo(N2)) {
// Otherwise, the nodes can be merged. Make sure that N2 contains all
// of the outgoing edges (fields) that DN does...
//
assert(DN->getNumLinks() == N2->getNumLinks() &&
"Same type, diff # fields?");
for (unsigned i = 0, e = DN->getNumLinks(); i != e; ++i)
N2->getLink(i).add(DN->getLink(i));
// Now make sure that all of the nodes that point to the shadow node
// also point to the node that we are merging it with...
//
const std::vector<PointerValSet*> &Refs = DN->getReferrers();
for (unsigned i = 0, e = Refs.size(); i != e; ++i) {
PointerValSet &PVS = *Refs[i];
// FIXME: this is incorrect if the referring pointer has index != 0
//
PVS.add(N2);
}
return true;
}
}
}
// Otherwise, nothing found, perhaps next time....
return false;
}
template<typename NodeTy>
bool removeIndistinguishableNode(std::vector<NodeTy*> &Nodes) {
bool Changed = false;
std::vector<NodeTy*>::iterator I = Nodes.begin();
while (I != Nodes.end()) {
if (isIndistinguishableNode(*I)) {
#ifdef DEBUG_NODE_ELIMINATE
cerr << "Found Indistinguishable Node:\n";
(*I)->print(cerr);
#endif
(*I)->removeAllIncomingEdges();
delete *I;
I = Nodes.erase(I);
Changed = true;
} else {
++I;
}
}
return Changed;
}
// UnlinkUndistinguishableShadowNodes - Eliminate shadow nodes that are not
// distinguishable from some other node in the graph...
//
bool FunctionDSGraph::UnlinkUndistinguishableShadowNodes() {
bool Changed = false;
// Loop over all of the shadow nodes, checking to see if they are
// indistinguishable from some other node. If so, eliminate the node!
//
for (vector<ShadowDSNode*>::iterator I = ShadowNodes.begin();
I != ShadowNodes.end(); )
if (IndistinguishableShadowNode(*I)) {
#ifdef DEBUG_NODE_ELIMINATE
cerr << "Found Indistinguishable Shadow Node:\n";
(*I)->print(cerr);
#endif
(*I)->removeAllIncomingEdges();
// Don't need to dropAllRefs, because nothing can point to it now
delete *I;
I = ShadowNodes.erase(I);
Changed = true;
} else {
++I;
}
return Changed;
return
removeIndistinguishableNode(AllocNodes) |
removeIndistinguishableNode(ShadowNodes) |
removeIndistinguishableNode(GlobalNodes);
}
static void MarkReferredNodesReachable(DSNode *N, vector<ShadowDSNode*> &Nodes,
vector<bool> &Reachable);
static void MarkReferredNodesReachable(DSNode *N,
vector<ShadowDSNode*> &ShadowNodes,
vector<bool> &ReachableShadowNodes,
vector<AllocDSNode*> &AllocNodes,
vector<bool> &ReachableAllocNodes);
static inline void MarkReferredNodeSetReachable(const PointerValSet &PVS,
vector<ShadowDSNode*> &Nodes,
vector<bool> &Reachable) {
vector<ShadowDSNode*> &ShadowNodes,
vector<bool> &ReachableShadowNodes,
vector<AllocDSNode*> &AllocNodes,
vector<bool> &ReachableAllocNodes) {
for (unsigned i = 0, e = PVS.size(); i != e; ++i)
if (ShadowDSNode *Shad = dyn_cast<ShadowDSNode>(PVS[i].Node))
MarkReferredNodesReachable(Shad, Nodes, Reachable);
if (isa<ShadowDSNode>(PVS[i].Node) || isa<ShadowDSNode>(PVS[i].Node))
MarkReferredNodesReachable(PVS[i].Node, ShadowNodes, ReachableShadowNodes,
AllocNodes, ReachableAllocNodes);
}
static void MarkReferredNodesReachable(DSNode *N, vector<ShadowDSNode*> &Nodes,
vector<bool> &Reachable) {
assert(Nodes.size() == Reachable.size());
ShadowDSNode *Shad = dyn_cast<ShadowDSNode>(N);
static void MarkReferredNodesReachable(DSNode *N,
vector<ShadowDSNode*> &ShadowNodes,
vector<bool> &ReachableShadowNodes,
vector<AllocDSNode*> &AllocNodes,
vector<bool> &ReachableAllocNodes) {
assert(ShadowNodes.size() == ReachableShadowNodes.size());
assert(AllocNodes.size() == ReachableAllocNodes.size());
if (Shad) {
if (ShadowDSNode *Shad = dyn_cast<ShadowDSNode>(N)) {
vector<ShadowDSNode*>::iterator I =
std::find(Nodes.begin(), Nodes.end(), Shad);
unsigned i = I-Nodes.begin();
if (Reachable[i]) return; // Recursion detected, abort...
Reachable[i] = true;
std::find(ShadowNodes.begin(), ShadowNodes.end(), Shad);
unsigned i = I-ShadowNodes.begin();
if (ReachableShadowNodes[i]) return; // Recursion detected, abort...
ReachableShadowNodes[i] = true;
} else if (AllocDSNode *Alloc = dyn_cast<AllocDSNode>(N)) {
vector<AllocDSNode*>::iterator I =
std::find(AllocNodes.begin(), AllocNodes.end(), Alloc);
unsigned i = I-AllocNodes.begin();
if (ReachableAllocNodes[i]) return; // Recursion detected, abort...
ReachableAllocNodes[i] = true;
}
for (unsigned i = 0, e = N->getNumLinks(); i != e; ++i)
MarkReferredNodeSetReachable(N->getLink(i), Nodes, Reachable);
MarkReferredNodeSetReachable(N->getLink(i),
ShadowNodes, ReachableShadowNodes,
AllocNodes, ReachableAllocNodes);
const std::vector<PointerValSet> *Links = N->getAuxLinks();
if (Links)
for (unsigned i = 0, e = Links->size(); i != e; ++i)
MarkReferredNodeSetReachable((*Links)[i], Nodes, Reachable);
MarkReferredNodeSetReachable((*Links)[i],
ShadowNodes, ReachableShadowNodes,
AllocNodes, ReachableAllocNodes);
}
bool FunctionDSGraph::RemoveUnreachableShadowNodes() {
bool Changed = false;
while (1) {
// Reachable - Contains true if there is an edge from a nonshadow node to
// the numbered node...
// Reachable*Nodes - Contains true if there is an edge from a reachable
// node to the numbered node...
//
vector<bool> Reachable(ShadowNodes.size());
vector<bool> ReachableShadowNodes(ShadowNodes.size());
vector<bool> ReachableAllocNodes (AllocNodes.size());
// Mark all shadow nodes that have edges from other nodes as reachable.
// Recursively mark any shadow nodes pointed to by the newly live shadow
// nodes as also alive.
//
for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
// Loop over all of the nodes referred and mark them live if they are
// shadow nodes...
MarkReferredNodesReachable(Nodes[i], ShadowNodes, Reachable);
for (unsigned i = 0, e = ArgNodes.size(); i != e; ++i)
MarkReferredNodesReachable(ArgNodes[i],
ShadowNodes, ReachableShadowNodes,
AllocNodes, ReachableAllocNodes);
for (unsigned i = 0, e = GlobalNodes.size(); i != e; ++i)
MarkReferredNodesReachable(GlobalNodes[i],
ShadowNodes, ReachableShadowNodes,
AllocNodes, ReachableAllocNodes);
for (unsigned i = 0, e = CallNodes.size(); i != e; ++i)
MarkReferredNodesReachable(CallNodes[i],
ShadowNodes, ReachableShadowNodes,
AllocNodes, ReachableAllocNodes);
// Mark all nodes in the return set as being reachable...
MarkReferredNodeSetReachable(RetNode, ShadowNodes, Reachable);
MarkReferredNodeSetReachable(RetNode,
ShadowNodes, ReachableShadowNodes,
AllocNodes, ReachableAllocNodes);
// Mark all nodes in the value map as being reachable...
for (std::map<Value*, PointerValSet>::iterator I = ValueMap.begin(),
E = ValueMap.end(); I != E; ++I)
MarkReferredNodeSetReachable(I->second, ShadowNodes, Reachable);
MarkReferredNodeSetReachable(I->second,
ShadowNodes, ReachableShadowNodes,
AllocNodes, ReachableAllocNodes);
// At this point, all reachable shadow nodes have a true value in the
// Reachable vector. This means that any shadow nodes without an entry in
@ -179,26 +238,43 @@ bool FunctionDSGraph::RemoveUnreachableShadowNodes() {
// a two part process, because we must drop all references before we delete
// the shadow nodes [in case cycles exist].
//
vector<ShadowDSNode*> DeadNodes;
bool LocalChange = false;
for (unsigned i = 0; i != ShadowNodes.size(); ++i)
if (!Reachable[i]) {
if (!ReachableShadowNodes[i]) {
// Track all unreachable nodes...
#if DEBUG_NODE_ELIMINATE
cerr << "Unreachable node eliminated:\n";
ShadowNodes[i]->print(cerr);
#endif
DeadNodes.push_back(ShadowNodes[i]);
ShadowNodes[i]->dropAllReferences(); // Drop references to other nodes
Reachable.erase(Reachable.begin()+i); // Remove from reachable...
ShadowNodes[i]->removeAllIncomingEdges();
delete ShadowNodes[i];
// Remove from reachable...
ReachableShadowNodes.erase(ReachableShadowNodes.begin()+i);
ShadowNodes.erase(ShadowNodes.begin()+i); // Remove node entry
--i; // Don't skip the next node.
LocalChange = true;
}
if (DeadNodes.empty()) return Changed; // No more dead nodes...
for (unsigned i = 0; i != AllocNodes.size(); ++i)
if (!ReachableAllocNodes[i]) {
// Track all unreachable nodes...
#if DEBUG_NODE_ELIMINATE
cerr << "Unreachable node eliminated:\n";
AllocNodes[i]->print(cerr);
#endif
AllocNodes[i]->removeAllIncomingEdges();
delete AllocNodes[i];
// Remove from reachable...
ReachableAllocNodes.erase(ReachableAllocNodes.begin()+i);
AllocNodes.erase(AllocNodes.begin()+i); // Remove node entry
--i; // Don't skip the next node.
LocalChange = true;
}
if (!LocalChange) return Changed; // No more dead nodes...
Changed = true;
// All dead nodes are in the DeadNodes vector... delete them now.
for_each(DeadNodes.begin(), DeadNodes.end(), deleter<DSNode>);
}
}

View File

@ -44,7 +44,7 @@ void InitVisitor::visitOperand(Value *V) {
if (!Rep->ValueMap.count(V)) // Only process it once...
if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
GlobalDSNode *N = new GlobalDSNode(GV);
Rep->Nodes.push_back(N);
Rep->GlobalNodes.push_back(N);
Rep->ValueMap[V].add(N);
Rep->addAllUsesToWorkList(GV);
@ -60,7 +60,7 @@ void InitVisitor::visitOperand(Value *V) {
//
void InitVisitor::visitCallInst(CallInst *CI) {
CallDSNode *C = new CallDSNode(CI);
Rep->Nodes.push_back(C);
Rep->CallNodes.push_back(C);
Rep->CallMap[CI] = C;
if (isa<PointerType>(CI->getType())) {
@ -95,8 +95,8 @@ void InitVisitor::visitCallInst(CallInst *CI) {
// global vars...
//
void InitVisitor::visitAllocationInst(AllocationInst *AI) {
NewDSNode *N = new NewDSNode(AI);
Rep->Nodes.push_back(N);
AllocDSNode *N = new AllocDSNode(AI);
Rep->AllocNodes.push_back(N);
Rep->ValueMap[AI].add(N, AI);
@ -144,7 +144,7 @@ void FunctionRepBuilder::initializeWorkList(Function *Func) {
// Only process arguments that are of pointer type...
if (isa<PointerType>((*I)->getType())) {
ArgDSNode *Arg = new ArgDSNode(*I);
Nodes.push_back(Arg);
ArgNodes.push_back(Arg);
// Add a critical shadow value for it to represent what it is pointing
// to and add this to the value map...
@ -326,10 +326,13 @@ void FunctionRepBuilder::visitPHINode(PHINode *PN) {
//
FunctionDSGraph::FunctionDSGraph(Function *F) : Func(F) {
FunctionRepBuilder Builder(this);
Nodes = Builder.getNodes();
ArgNodes = Builder.getArgNodes();
AllocNodes = Builder.getAllocNodes();
ShadowNodes = Builder.getShadowNodes();
RetNode = Builder.getRetNode();
ValueMap = Builder.getValueMap();
GlobalNodes = Builder.getGlobalNodes();
CallNodes = Builder.getCallNodes();
RetNode = Builder.getRetNode();
ValueMap = Builder.getValueMap();
bool Changed = true;
while (Changed) {

View File

@ -61,8 +61,11 @@ class FunctionRepBuilder : InstVisitor<FunctionRepBuilder> {
// Nodes - Keep track of all of the resultant nodes, because there may not
// be edges connecting these to anything.
//
std::vector<DSNode*> Nodes;
std::vector<ArgDSNode*> ArgNodes;
std::vector<AllocDSNode*> AllocNodes;
std::vector<ShadowDSNode*> ShadowNodes;
std::vector<GlobalDSNode*> GlobalNodes;
std::vector<CallDSNode*> CallNodes;
// addAllUsesToWorkList - Add all of the instructions users of the specified
// value to the work list for further processing...
@ -75,11 +78,13 @@ public:
processWorkList();
}
void addNode(DSNode *N) { Nodes.push_back(N); }
const std::vector<DSNode*> &getNodes() const { return Nodes; }
void addShadowNode(ShadowDSNode *N) { ShadowNodes.push_back(N); }
const std::vector<ArgDSNode*> &getArgNodes() const { return ArgNodes; }
const std::vector<AllocDSNode*> &getAllocNodes() const { return AllocNodes; }
const std::vector<ShadowDSNode*> &getShadowNodes() const {return ShadowNodes;}
const std::vector<GlobalDSNode*> &getGlobalNodes() const {return GlobalNodes;}
const std::vector<CallDSNode*> &getCallNodes() const { return CallNodes; }
void addShadowNode(ShadowDSNode *SN) { ShadowNodes.push_back(SN); }
const PointerValSet &getRetNode() const { return RetNode; }

View File

@ -20,8 +20,8 @@
//
static void MapPVS(PointerValSet &PVSOut, const PointerValSet &PVSIn,
map<const DSNode*, DSNode*> &NodeMap) {
assert(PVSOut.empty() && "Value set already initialized!");
map<const DSNode*, DSNode*> &NodeMap, bool ReinitOk = false){
assert((ReinitOk || PVSOut.empty()) && "Value set already initialized!");
for (unsigned i = 0, e = PVSIn.size(); i != e; ++i)
PVSOut.add(PointerVal(NodeMap[PVSIn[i].Node], PVSIn[i].Index));
@ -148,16 +148,16 @@ void DSNode::mapNode(map<const DSNode*, DSNode*> &NodeMap, const DSNode *Old) {
MapPVS(FieldLinks[j], Old->FieldLinks[j], NodeMap);
}
NewDSNode::NewDSNode(AllocationInst *V)
AllocDSNode::AllocDSNode(AllocationInst *V)
: DSNode(NewNode, V->getType()->getElementType()), Allocation(V) {
}
bool NewDSNode::isAllocaNode() const {
bool AllocDSNode::isAllocaNode() const {
return isa<AllocaInst>(Allocation);
}
string NewDSNode::getCaption() const {
string AllocDSNode::getCaption() const {
stringstream OS;
OS << (isMallocNode() ? "new " : "alloca ");
@ -175,7 +175,7 @@ GlobalDSNode::GlobalDSNode(GlobalValue *V)
string GlobalDSNode::getCaption() const {
stringstream OS;
WriteTypeSymbolic(OS, getType(), Val->getParent());
return "global " + OS.str();
return "global " + OS.str() + " %" + Val->getName();
}
@ -243,7 +243,7 @@ string CallDSNode::getCaption() const {
void CallDSNode::mapNode(map<const DSNode*, DSNode*> &NodeMap,
const DSNode *O) {
const CallDSNode *Old = (CallDSNode*)O;
const CallDSNode *Old = cast<CallDSNode>(O);
DSNode::mapNode(NodeMap, Old); // Map base portions first...
assert(ArgLinks.size() == Old->ArgLinks.size() && "# Arguments changed!?");
@ -266,10 +266,16 @@ void FunctionDSGraph::printFunction(std::ostream &O,
const char *Label) const {
O << "\tsubgraph cluster_" << Label << "_Function" << (void*)this << " {\n";
O << "\t\tlabel=\"" << Label << " Function\\ " << Func->getName() << "\";\n";
for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
Nodes[i]->print(O);
for (unsigned i = 0, e = ArgNodes.size(); i != e; ++i)
ArgNodes[i]->print(O);
for (unsigned i = 0, e = AllocNodes.size(); i != e; ++i)
AllocNodes[i]->print(O);
for (unsigned i = 0, e = ShadowNodes.size(); i != e; ++i)
ShadowNodes[i]->print(O);
for (unsigned i = 0, e = GlobalNodes.size(); i != e; ++i)
GlobalNodes[i]->print(O);
for (unsigned i = 0, e = CallNodes.size(); i != e; ++i)
CallNodes[i]->print(O);
if (RetNode.size()) {
O << "\t\tNode" << (void*)this << Label
@ -315,14 +321,30 @@ FunctionDSGraph::FunctionDSGraph(const FunctionDSGraph &DSG) : Func(DSG.Func) {
PointerValSet FunctionDSGraph::cloneFunctionIntoSelf(const FunctionDSGraph &DSG,
bool CloneValueMap) {
map<const DSNode*, DSNode*> NodeMap; // Map from old graph to new graph...
unsigned StartSize = Nodes.size(); // We probably already have nodes...
Nodes.reserve(StartSize+DSG.Nodes.size());
unsigned StartArgSize = ArgNodes.size();
ArgNodes.reserve(StartArgSize+DSG.ArgNodes.size());
unsigned StartAllocSize = AllocNodes.size();
AllocNodes.reserve(StartAllocSize+DSG.AllocNodes.size());
unsigned StartShadowSize = ShadowNodes.size();
ShadowNodes.reserve(StartShadowSize+DSG.ShadowNodes.size());
unsigned StartGlobalSize = GlobalNodes.size();
GlobalNodes.reserve(StartGlobalSize+DSG.GlobalNodes.size());
unsigned StartCallSize = CallNodes.size();
CallNodes.reserve(StartCallSize+DSG.CallNodes.size());
// Clone all of the nodes, keeping track of the mapping...
for (unsigned i = 0, e = DSG.Nodes.size(); i != e; ++i)
Nodes.push_back(NodeMap[DSG.Nodes[i]] = DSG.Nodes[i]->clone());
// Clone all of the arg nodes...
for (unsigned i = 0, e = DSG.ArgNodes.size(); i != e; ++i) {
ArgDSNode *New = cast<ArgDSNode>(DSG.ArgNodes[i]->clone());
NodeMap[DSG.ArgNodes[i]] = New;
ArgNodes.push_back(New);
}
// Clone all of the alloc nodes similarly...
for (unsigned i = 0, e = DSG.AllocNodes.size(); i != e; ++i) {
AllocDSNode *New = cast<AllocDSNode>(DSG.AllocNodes[i]->clone());
NodeMap[DSG.AllocNodes[i]] = New;
AllocNodes.push_back(New);
}
// Clone all of the shadow nodes similarly...
for (unsigned i = 0, e = DSG.ShadowNodes.size(); i != e; ++i) {
@ -331,14 +353,34 @@ PointerValSet FunctionDSGraph::cloneFunctionIntoSelf(const FunctionDSGraph &DSG,
ShadowNodes.push_back(New);
}
// Clone all of the global nodes...
for (unsigned i = 0, e = DSG.GlobalNodes.size(); i != e; ++i) {
GlobalDSNode *New = cast<GlobalDSNode>(DSG.GlobalNodes[i]->clone());
NodeMap[DSG.GlobalNodes[i]] = New;
GlobalNodes.push_back(New);
}
// Clone all of the call nodes...
for (unsigned i = 0, e = DSG.CallNodes.size(); i != e; ++i) {
CallDSNode *New = cast<CallDSNode>(DSG.CallNodes[i]->clone());
NodeMap[DSG.CallNodes[i]] = New;
CallNodes.push_back(New);
}
// Convert all of the links over in the nodes now that the map has been filled
// in all the way...
//
for (unsigned i = 0, e = DSG.Nodes.size(); i != e; ++i)
Nodes[i+StartSize]->mapNode(NodeMap, DSG.Nodes[i]);
for (unsigned i = 0, e = DSG.ArgNodes.size(); i != e; ++i)
ArgNodes[i+StartArgSize]->mapNode(NodeMap, DSG.ArgNodes[i]);
for (unsigned i = 0, e = DSG.AllocNodes.size(); i != e; ++i)
AllocNodes[i+StartAllocSize]->mapNode(NodeMap, DSG.AllocNodes[i]);
for (unsigned i = 0, e = DSG.ShadowNodes.size(); i != e; ++i)
ShadowNodes[i+StartShadowSize]->mapNode(NodeMap, DSG.ShadowNodes[i]);
for (unsigned i = 0, e = DSG.GlobalNodes.size(); i != e; ++i)
GlobalNodes[i+StartGlobalSize]->mapNode(NodeMap, DSG.GlobalNodes[i]);
for (unsigned i = 0, e = DSG.CallNodes.size(); i != e; ++i)
CallNodes[i+StartCallSize]->mapNode(NodeMap, DSG.CallNodes[i]);
if (CloneValueMap) {
// Convert value map... the values themselves stay the same, just the nodes
@ -346,7 +388,7 @@ PointerValSet FunctionDSGraph::cloneFunctionIntoSelf(const FunctionDSGraph &DSG,
//
for (std::map<Value*,PointerValSet>::const_iterator I =DSG.ValueMap.begin(),
E = DSG.ValueMap.end(); I != E; ++I)
MapPVS(ValueMap[I->first], I->second, NodeMap);
MapPVS(ValueMap[I->first], I->second, NodeMap, true);
}
// Convert over return node...
@ -359,10 +401,20 @@ PointerValSet FunctionDSGraph::cloneFunctionIntoSelf(const FunctionDSGraph &DSG,
FunctionDSGraph::~FunctionDSGraph() {
RetNode.clear();
ValueMap.clear();
for_each(Nodes.begin(), Nodes.end(), mem_fun(&DSNode::dropAllReferences));
for_each(ArgNodes.begin(), ArgNodes.end(),
mem_fun(&DSNode::dropAllReferences));
for_each(AllocNodes.begin(), AllocNodes.end(),
mem_fun(&DSNode::dropAllReferences));
for_each(ShadowNodes.begin(), ShadowNodes.end(),
mem_fun(&DSNode::dropAllReferences));
for_each(Nodes.begin(), Nodes.end(), deleter<DSNode>);
for_each(GlobalNodes.begin(), GlobalNodes.end(),
mem_fun(&DSNode::dropAllReferences));
for_each(CallNodes.begin(), CallNodes.end(),
mem_fun(&DSNode::dropAllReferences));
for_each(ArgNodes.begin(), ArgNodes.end(), deleter<DSNode>);
for_each(AllocNodes.begin(), AllocNodes.end(), deleter<DSNode>);
for_each(ShadowNodes.begin(), ShadowNodes.end(), deleter<DSNode>);
for_each(GlobalNodes.begin(), GlobalNodes.end(), deleter<DSNode>);
for_each(CallNodes.begin(), CallNodes.end(), deleter<DSNode>);
}