diff --git a/include/llvm/Analysis/DSGraph.h b/include/llvm/Analysis/DSGraph.h index 2a683655851..6eed55ddf7e 100644 --- a/include/llvm/Analysis/DSGraph.h +++ b/include/llvm/Analysis/DSGraph.h @@ -361,19 +361,40 @@ inline void DSNodeHandle::mergeWith(const DSNodeHandle &Node) { /// DSCallSite - Representation of a call site via its call instruction, /// the DSNode handle for the callee function (or function pointer), and /// the DSNode handles for the function arguments. +/// +/// One unusual aspect of this callsite record is the ResolvingCaller member. +/// If this is non-null, then it indicates the function that allowed a call-site +/// to finally be resolved. Because of indirect calls, this function may not +/// actually be the function that contains the Call instruction itself. This is +/// used by the BU and TD passes to communicate. /// class DSCallSite { CallInst *Inst; // Actual call site DSNodeHandle RetVal; // Returned value DSNodeHandle Callee; // The function node called std::vector CallArgs; // The pointer arguments + Function *ResolvingCaller; // See comments above - static DSNode *mapLookup(const DSNode *Node, - const std::map &NodeMap) { - if (Node == 0) return 0; - std::map::const_iterator I = NodeMap.find(Node); - assert(I != NodeMap.end() && "Not not in mapping!"); - return I->second; + static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, + const std::map &NodeMap) { + if (DSNode *N = Src.getNode()) { + std::map::const_iterator I = NodeMap.find(N); + assert(I != NodeMap.end() && "Not not in mapping!"); + + NH.setOffset(Src.getOffset()); + NH.setNode(I->second); + } + } + + static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, + const std::map &NodeMap) { + if (DSNode *N = Src.getNode()) { + std::map::const_iterator I = NodeMap.find(N); + assert(I != NodeMap.end() && "Not not in mapping!"); + + NH.setOffset(Src.getOffset()+I->second.getOffset()); + NH.setNode(I->second.getNode()); + } } DSCallSite(); // DO NOT IMPLEMENT @@ -383,32 +404,29 @@ public: /// DSCallSite(CallInst &inst, const DSNodeHandle &rv, const DSNodeHandle &callee, std::vector &Args) - : Inst(&inst), RetVal(rv), Callee(callee) { + : Inst(&inst), RetVal(rv), Callee(callee), ResolvingCaller(0) { Args.swap(CallArgs); } DSCallSite(const DSCallSite &DSCS) // Simple copy ctor : Inst(DSCS.Inst), RetVal(DSCS.RetVal), - Callee(DSCS.Callee), CallArgs(DSCS.CallArgs) {} + Callee(DSCS.Callee), CallArgs(DSCS.CallArgs), + ResolvingCaller(DSCS.ResolvingCaller) {} /// Mapping copy constructor - This constructor takes a preexisting call site /// to copy plus a map that specifies how the links should be transformed. /// This is useful when moving a call site from one graph to another. /// - DSCallSite(const DSCallSite &FromCall, - const std::map &NodeMap) { + template + DSCallSite(const DSCallSite &FromCall, const MapTy &NodeMap) { Inst = FromCall.Inst; - RetVal.setOffset(FromCall.RetVal.getOffset()); - RetVal.setNode(mapLookup(FromCall.RetVal.getNode(), NodeMap)); - Callee.setOffset(FromCall.Callee.getOffset()); - Callee.setNode(mapLookup(FromCall.Callee.getNode(), NodeMap)); - CallArgs.reserve(FromCall.CallArgs.size()); + InitNH(RetVal, FromCall.RetVal, NodeMap); + InitNH(Callee, FromCall.Callee, NodeMap); - for (unsigned i = 0, e = FromCall.CallArgs.size(); i != e; ++i) { - const DSNodeHandle &OldNH = FromCall.CallArgs[i]; - CallArgs.push_back(DSNodeHandle(mapLookup(OldNH.getNode(), NodeMap), - OldNH.getOffset())); - } + CallArgs.resize(FromCall.CallArgs.size()); + for (unsigned i = 0, e = FromCall.CallArgs.size(); i != e; ++i) + InitNH(CallArgs[i], FromCall.CallArgs[i], NodeMap); + ResolvingCaller = FromCall.ResolvingCaller; } // Accessor functions... @@ -420,6 +438,9 @@ public: const DSNodeHandle &getCallee() const { return Callee; } unsigned getNumPtrArgs() const { return CallArgs.size(); } + Function *getResolvingCaller() const { return ResolvingCaller; } + void setResolvingCaller(Function *F) { ResolvingCaller = F; } + DSNodeHandle &getPtrArg(unsigned i) { assert(i < CallArgs.size() && "Argument to getPtrArgNode is out of range!"); return CallArgs[i]; @@ -478,7 +499,7 @@ public: // destination graph, you may optionally do this by specifying a map to record // this into. DSGraph(const DSGraph &DSG); - DSGraph(const DSGraph &DSG, std::map &BUNodeMapTy); + DSGraph(const DSGraph &DSG, std::map &BUNodeMap); ~DSGraph(); bool hasFunction() const { return Func != 0; } diff --git a/include/llvm/Analysis/DataStructure.h b/include/llvm/Analysis/DataStructure.h index 2dc4ce4d1e8..d44732a4863 100644 --- a/include/llvm/Analysis/DataStructure.h +++ b/include/llvm/Analysis/DataStructure.h @@ -11,6 +11,7 @@ class Type; class DSGraph; +class DSNode; class DSNodeHandle; class DSCallSite; class LocalDataStructures; // A collection of local graphs for a program @@ -108,6 +109,15 @@ private: class TDDataStructures : public Pass { // DSInfo, one graph for each function std::map DSInfo; + + // Each graph in DSInfo is based on a graph in the BUDS object. The BUMaps + // member keeps the mappings from the BU graphs to the TD graphs as they are + // calculated by calculateGraph. This information is used to properly + // implement resolving of call sites, where the call sites in the BUGraph are + // in terms of the caller function's graph in the BUGraph. + // + typedef std::map BUNodeMapTy; + std::map BUMaps; public: ~TDDataStructures() { releaseMemory(); } @@ -134,8 +144,7 @@ public: private: DSGraph &calculateGraph(Function &F); - void ResolveCallSite(DSGraph &Graph, - const DSCallSite &CallSite); + void ResolveCallSite(DSGraph &Graph, const DSCallSite &CallSite); }; #if 0 diff --git a/include/llvm/Analysis/DataStructure/DSGraph.h b/include/llvm/Analysis/DataStructure/DSGraph.h index 2a683655851..6eed55ddf7e 100644 --- a/include/llvm/Analysis/DataStructure/DSGraph.h +++ b/include/llvm/Analysis/DataStructure/DSGraph.h @@ -361,19 +361,40 @@ inline void DSNodeHandle::mergeWith(const DSNodeHandle &Node) { /// DSCallSite - Representation of a call site via its call instruction, /// the DSNode handle for the callee function (or function pointer), and /// the DSNode handles for the function arguments. +/// +/// One unusual aspect of this callsite record is the ResolvingCaller member. +/// If this is non-null, then it indicates the function that allowed a call-site +/// to finally be resolved. Because of indirect calls, this function may not +/// actually be the function that contains the Call instruction itself. This is +/// used by the BU and TD passes to communicate. /// class DSCallSite { CallInst *Inst; // Actual call site DSNodeHandle RetVal; // Returned value DSNodeHandle Callee; // The function node called std::vector CallArgs; // The pointer arguments + Function *ResolvingCaller; // See comments above - static DSNode *mapLookup(const DSNode *Node, - const std::map &NodeMap) { - if (Node == 0) return 0; - std::map::const_iterator I = NodeMap.find(Node); - assert(I != NodeMap.end() && "Not not in mapping!"); - return I->second; + static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, + const std::map &NodeMap) { + if (DSNode *N = Src.getNode()) { + std::map::const_iterator I = NodeMap.find(N); + assert(I != NodeMap.end() && "Not not in mapping!"); + + NH.setOffset(Src.getOffset()); + NH.setNode(I->second); + } + } + + static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src, + const std::map &NodeMap) { + if (DSNode *N = Src.getNode()) { + std::map::const_iterator I = NodeMap.find(N); + assert(I != NodeMap.end() && "Not not in mapping!"); + + NH.setOffset(Src.getOffset()+I->second.getOffset()); + NH.setNode(I->second.getNode()); + } } DSCallSite(); // DO NOT IMPLEMENT @@ -383,32 +404,29 @@ public: /// DSCallSite(CallInst &inst, const DSNodeHandle &rv, const DSNodeHandle &callee, std::vector &Args) - : Inst(&inst), RetVal(rv), Callee(callee) { + : Inst(&inst), RetVal(rv), Callee(callee), ResolvingCaller(0) { Args.swap(CallArgs); } DSCallSite(const DSCallSite &DSCS) // Simple copy ctor : Inst(DSCS.Inst), RetVal(DSCS.RetVal), - Callee(DSCS.Callee), CallArgs(DSCS.CallArgs) {} + Callee(DSCS.Callee), CallArgs(DSCS.CallArgs), + ResolvingCaller(DSCS.ResolvingCaller) {} /// Mapping copy constructor - This constructor takes a preexisting call site /// to copy plus a map that specifies how the links should be transformed. /// This is useful when moving a call site from one graph to another. /// - DSCallSite(const DSCallSite &FromCall, - const std::map &NodeMap) { + template + DSCallSite(const DSCallSite &FromCall, const MapTy &NodeMap) { Inst = FromCall.Inst; - RetVal.setOffset(FromCall.RetVal.getOffset()); - RetVal.setNode(mapLookup(FromCall.RetVal.getNode(), NodeMap)); - Callee.setOffset(FromCall.Callee.getOffset()); - Callee.setNode(mapLookup(FromCall.Callee.getNode(), NodeMap)); - CallArgs.reserve(FromCall.CallArgs.size()); + InitNH(RetVal, FromCall.RetVal, NodeMap); + InitNH(Callee, FromCall.Callee, NodeMap); - for (unsigned i = 0, e = FromCall.CallArgs.size(); i != e; ++i) { - const DSNodeHandle &OldNH = FromCall.CallArgs[i]; - CallArgs.push_back(DSNodeHandle(mapLookup(OldNH.getNode(), NodeMap), - OldNH.getOffset())); - } + CallArgs.resize(FromCall.CallArgs.size()); + for (unsigned i = 0, e = FromCall.CallArgs.size(); i != e; ++i) + InitNH(CallArgs[i], FromCall.CallArgs[i], NodeMap); + ResolvingCaller = FromCall.ResolvingCaller; } // Accessor functions... @@ -420,6 +438,9 @@ public: const DSNodeHandle &getCallee() const { return Callee; } unsigned getNumPtrArgs() const { return CallArgs.size(); } + Function *getResolvingCaller() const { return ResolvingCaller; } + void setResolvingCaller(Function *F) { ResolvingCaller = F; } + DSNodeHandle &getPtrArg(unsigned i) { assert(i < CallArgs.size() && "Argument to getPtrArgNode is out of range!"); return CallArgs[i]; @@ -478,7 +499,7 @@ public: // destination graph, you may optionally do this by specifying a map to record // this into. DSGraph(const DSGraph &DSG); - DSGraph(const DSGraph &DSG, std::map &BUNodeMapTy); + DSGraph(const DSGraph &DSG, std::map &BUNodeMap); ~DSGraph(); bool hasFunction() const { return Func != 0; } diff --git a/include/llvm/Analysis/DataStructure/DataStructure.h b/include/llvm/Analysis/DataStructure/DataStructure.h index 2dc4ce4d1e8..d44732a4863 100644 --- a/include/llvm/Analysis/DataStructure/DataStructure.h +++ b/include/llvm/Analysis/DataStructure/DataStructure.h @@ -11,6 +11,7 @@ class Type; class DSGraph; +class DSNode; class DSNodeHandle; class DSCallSite; class LocalDataStructures; // A collection of local graphs for a program @@ -108,6 +109,15 @@ private: class TDDataStructures : public Pass { // DSInfo, one graph for each function std::map DSInfo; + + // Each graph in DSInfo is based on a graph in the BUDS object. The BUMaps + // member keeps the mappings from the BU graphs to the TD graphs as they are + // calculated by calculateGraph. This information is used to properly + // implement resolving of call sites, where the call sites in the BUGraph are + // in terms of the caller function's graph in the BUGraph. + // + typedef std::map BUNodeMapTy; + std::map BUMaps; public: ~TDDataStructures() { releaseMemory(); } @@ -134,8 +144,7 @@ public: private: DSGraph &calculateGraph(Function &F); - void ResolveCallSite(DSGraph &Graph, - const DSCallSite &CallSite); + void ResolveCallSite(DSGraph &Graph, const DSCallSite &CallSite); }; #if 0 diff --git a/lib/Analysis/DataStructure/BottomUpClosure.cpp b/lib/Analysis/DataStructure/BottomUpClosure.cpp index 53b997f69a3..73786c96c5e 100644 --- a/lib/Analysis/DataStructure/BottomUpClosure.cpp +++ b/lib/Analysis/DataStructure/BottomUpClosure.cpp @@ -143,7 +143,9 @@ DSGraph &BUDataStructures::calculateGraph(Function &F) { // Record that the original DSCallSite was a call site of FI. // This may or may not have been known when the DSCallSite was // originally created. - CallSites[&FI].push_back(Call); + std::vector &CallSitesForFunc = CallSites[&FI]; + CallSitesForFunc.push_back(Call); + CallSitesForFunc.back().setResolvingCaller(&F); // Clone the callee's graph into the current graph, keeping // track of where scalars in the old graph _used_ to point, diff --git a/lib/Analysis/DataStructure/TopDownClosure.cpp b/lib/Analysis/DataStructure/TopDownClosure.cpp index 653d2ca8f69..c573a52c9e0 100644 --- a/lib/Analysis/DataStructure/TopDownClosure.cpp +++ b/lib/Analysis/DataStructure/TopDownClosure.cpp @@ -20,6 +20,7 @@ Y("tddatastructure", "Top-down Data Structure Analysis Closure"); // our memory... here... // void TDDataStructures::releaseMemory() { + BUMaps.clear(); for (std::map::iterator I = DSInfo.begin(), E = DSInfo.end(); I != E; ++I) delete I->second; @@ -76,7 +77,14 @@ DSGraph &TDDataStructures::calculateGraph(Function &F) { BUDataStructures &BU = getAnalysis(); DSGraph &BUGraph = BU.getDSGraph(F); - Graph = new DSGraph(BUGraph); + + // Copy the BU graph, keeping a mapping from the BUGraph to the current Graph + std::map BUNodeMap; + Graph = new DSGraph(BUGraph, BUNodeMap); + + // Convert the mapping from a node-to-node map into a node-to-nodehandle map + BUMaps[&F].insert(BUNodeMap.begin(), BUNodeMap.end()); + BUNodeMap.clear(); // We are done with the temporary map. const std::vector *CallSitesP = BU.getCallSites(F); if (CallSitesP == 0) { @@ -90,14 +98,19 @@ DSGraph &TDDataStructures::calculateGraph(Function &F) { DEBUG(std::cerr << " [TD] Inlining callers for: " << F.getName() << "\n"); const std::vector &CallSites = *CallSitesP; for (unsigned c = 0, ce = CallSites.size(); c != ce; ++c) { - const DSCallSite &CallSite = CallSites[c]; // Copy - Function &Caller = CallSite.getCaller(); - assert(!Caller.isExternal() && "Externals function cannot 'call'!"); + const DSCallSite &CallSite = CallSites[c]; + Function &Caller = *CallSite.getResolvingCaller(); + assert(&Caller && !Caller.isExternal() && + "Externals function cannot 'call'!"); DEBUG(std::cerr << "\t [TD] Inlining caller #" << c << " '" << Caller.getName() << "' into callee: " << F.getName() << "\n"); - if (&Caller != &F) { + if (&Caller == &F) { + // Self-recursive call: this can happen after a cycle of calls is inlined. + ResolveCallSite(*Graph, CallSite); + } else { + // Recursively compute the graph for the Caller. It should be fully // resolved except if there is mutual recursion... // @@ -111,6 +124,9 @@ DSGraph &TDDataStructures::calculateGraph(Function &F) { std::map OldValMap; std::map OldNodeMap; + // Translate call site from having links into the BU graph + DSCallSite CallSiteInCG(CallSite, BUMaps[&Caller]); + // Clone the Caller's graph into the current graph, keeping // track of where scalars in the old graph _used_ to point... // Do this here because it only needs to happens once for each Caller! @@ -121,20 +137,17 @@ DSGraph &TDDataStructures::calculateGraph(Function &F) { /*StripAllocas*/ false, /*CopyCallers*/ true, /*CopyOrigCalls*/false); - - // Make a temporary copy of the call site, and transform the argument node - // pointers. - // + ResolveCallSite(*Graph, DSCallSite(CallSiteInCG, OldNodeMap)); } - ResolveCallSite(*Graph, CallSite); } // Recompute the Incomplete markers and eliminate unreachable nodes. +#if 0 Graph->maskIncompleteMarkers(); Graph->markIncompleteNodes(/*markFormals*/ !F.hasInternalLinkage() /*&& FIXME: NEED TO CHECK IF ALL CALLERS FOUND!*/); Graph->removeDeadNodes(/*KeepAllGlobals*/ false, /*KeepCalls*/ false); - +#endif DEBUG(std::cerr << " [TD] Done inlining callers for: " << F.getName() << " [" << Graph->getGraphSize() << "+" << Graph->getFunctionCalls().size() << "]\n");