#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());
- 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]);
-}
-
-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.
+static void copyEdgesFromTo(PointerVal Val, DSNode *N) {
+ assert(Val.Index == 0 && "copyEdgesFromTo:index != 0 TODO");
- 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);
- }
- }
- }
+ const vector<PointerValSet*> &PVSToUpdate(Val.Node->getReferrers());
+ for (unsigned i = 0, e = PVSToUpdate.size(); i != e; ++i)
+ PVSToUpdate[i]->add(N); // TODO: support index
}
-
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;
+ // Make everything that pointed to the shadow node also point to the values in
+ // ToVals...
+ //
for (unsigned i = 0, e = ToVals.size(); i != e; ++i)
- CalculateNodeMapping(Shadow, ToVals[i].Node, NodeMapping);
+ copyEdgesFromTo(ToVals[i], Shadow);
- // Now loop through the shadow node graph, mirroring the edges in the shadow
- // graph onto the realized graph...
- //
- 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);
-
- // 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);
}
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;
// 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
//
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);
-
- // 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.
- //
- 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;
- }
-
- // If the function returns a pointer value... Resolve values pointing to
- // the shadow nodes pointed to by CN to now point the values in RetVals...
- //
- 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.
+ RetVals = cloneFunctionIntoSelf(NewFunction, F == Func);
+ CallMap[FDesc] = 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.
//
- ResolveNodeTo(ArgNode, CN->getArgValues(i));
-
- if (StartNode) { // Not Self recursion?
+ 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...
- Nodes.erase(Nodes.begin()+ArgOffset);
-
+ ArgNodes.erase(ArgNodes.begin()+StartArgNode);
+
// ArgNode is no longer useful, delete now!
delete ArgNode;
- } else {
- ArgOffset++; // Step to the next argument...
}
}
+
+ // 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 = 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
+ }
}
- // 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 the function returns a pointer value... Resolve values pointing to
+ // the shadow nodes pointed to by CN to now point the values in RetVals...
//
- 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
- }
-
+ if (CN->getNumLinks()) ResolveNodeTo(CN, RetVals);
// Now the call node is completely destructable. Eliminate it now.
delete CN;
//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);
}
}
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())
//#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).
-//
-static bool IndistinguishableShadowNode(const ShadowDSNode *SN) {
- if (SN->getReferrers().empty()) return true; // Node 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...
+//
+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];
-
- 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;
+ 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) {
+ 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;
}
-
-// UnlinkUndistinguishableShadowNodes - Eliminate shadow nodes that are not
-// distinguishable from some other node in the graph...
-//
-bool FunctionDSGraph::UnlinkUndistinguishableShadowNodes() {
+template<typename NodeTy>
+bool removeIndistinguishableNode(std::vector<NodeTy*> &Nodes) {
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)) {
+ std::vector<NodeTy*>::iterator I = Nodes.begin();
+ while (I != Nodes.end()) {
+ if (isIndistinguishableNode(*I)) {
#ifdef DEBUG_NODE_ELIMINATE
- cerr << "Found Indistinguishable Shadow Node:\n";
+ cerr << "Found Indistinguishable 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);
+ I = Nodes.erase(I);
Changed = true;
} else {
++I;
}
+ }
return Changed;
}
-static void MarkReferredNodesReachable(DSNode *N, vector<ShadowDSNode*> &Nodes,
- vector<bool> &Reachable);
+// UnlinkUndistinguishableShadowNodes - Eliminate shadow nodes that are not
+// distinguishable from some other node in the graph...
+//
+bool FunctionDSGraph::UnlinkUndistinguishableShadowNodes() {
+ // Loop over all of the shadow nodes, checking to see if they are
+ // indistinguishable from some other node. If so, eliminate the node!
+ //
+ return
+ removeIndistinguishableNode(AllocNodes) |
+ removeIndistinguishableNode(ShadowNodes) |
+ removeIndistinguishableNode(GlobalNodes);
+}
+
+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
// 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];
- Changed = true;
+ // 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...
- // All dead nodes are in the DeadNodes vector... delete them now.
- for_each(DeadNodes.begin(), DeadNodes.end(), deleter<DSNode>);
+ Changed = true;
}
}
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);
//
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())) {
// 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);
// 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...
//
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) {
// 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...
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; }
//
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));
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 ");
string GlobalDSNode::getCaption() const {
stringstream OS;
WriteTypeSymbolic(OS, getType(), Val->getParent());
- return "global " + OS.str();
+ return "global " + OS.str() + " %" + Val->getName();
}
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!?");
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
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 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 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 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) {
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
//
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...
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>);
}