/// 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<DSNodeHandle> CallArgs; // The pointer arguments
+ Function *ResolvingCaller; // See comments above
+
+ static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src,
+ const std::map<const DSNode*, DSNode*> &NodeMap) {
+ if (DSNode *N = Src.getNode()) {
+ std::map<const DSNode*, DSNode*>::const_iterator I = NodeMap.find(N);
+ assert(I != NodeMap.end() && "Not not in mapping!");
+
+ NH.setOffset(Src.getOffset());
+ NH.setNode(I->second);
+ }
+ }
- static DSNode *mapLookup(const DSNode *Node,
- const std::map<const DSNode*, DSNode*> &NodeMap) {
- if (Node == 0) return 0;
- std::map<const DSNode*, DSNode*>::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<const DSNode*, DSNodeHandle> &NodeMap) {
+ if (DSNode *N = Src.getNode()) {
+ std::map<const DSNode*, DSNodeHandle>::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
///
DSCallSite(CallInst &inst, const DSNodeHandle &rv, const DSNodeHandle &callee,
std::vector<DSNodeHandle> &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<const DSNode*, DSNode*> &NodeMap) {
+ template<typename MapTy>
+ 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());
-
- 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()));
- }
+ InitNH(RetVal, FromCall.RetVal, NodeMap);
+ InitNH(Callee, FromCall.Callee, NodeMap);
+
+ 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...
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];
// 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<const DSNode*, DSNode*> &BUNodeMapTy);
+ DSGraph(const DSGraph &DSG, std::map<const DSNode*, DSNode*> &BUNodeMap);
~DSGraph();
bool hasFunction() const { return Func != 0; }
class Type;
class DSGraph;
+class DSNode;
class DSNodeHandle;
class DSCallSite;
class LocalDataStructures; // A collection of local graphs for a program
class TDDataStructures : public Pass {
// DSInfo, one graph for each function
std::map<const Function*, DSGraph*> 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<const DSNode*, DSNodeHandle> BUNodeMapTy;
+ std::map<const Function*, BUNodeMapTy> BUMaps;
public:
~TDDataStructures() { releaseMemory(); }
private:
DSGraph &calculateGraph(Function &F);
- void ResolveCallSite(DSGraph &Graph,
- const DSCallSite &CallSite);
+ void ResolveCallSite(DSGraph &Graph, const DSCallSite &CallSite);
};
#if 0
/// 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<DSNodeHandle> CallArgs; // The pointer arguments
+ Function *ResolvingCaller; // See comments above
+
+ static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src,
+ const std::map<const DSNode*, DSNode*> &NodeMap) {
+ if (DSNode *N = Src.getNode()) {
+ std::map<const DSNode*, DSNode*>::const_iterator I = NodeMap.find(N);
+ assert(I != NodeMap.end() && "Not not in mapping!");
+
+ NH.setOffset(Src.getOffset());
+ NH.setNode(I->second);
+ }
+ }
- static DSNode *mapLookup(const DSNode *Node,
- const std::map<const DSNode*, DSNode*> &NodeMap) {
- if (Node == 0) return 0;
- std::map<const DSNode*, DSNode*>::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<const DSNode*, DSNodeHandle> &NodeMap) {
+ if (DSNode *N = Src.getNode()) {
+ std::map<const DSNode*, DSNodeHandle>::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
///
DSCallSite(CallInst &inst, const DSNodeHandle &rv, const DSNodeHandle &callee,
std::vector<DSNodeHandle> &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<const DSNode*, DSNode*> &NodeMap) {
+ template<typename MapTy>
+ 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());
-
- 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()));
- }
+ InitNH(RetVal, FromCall.RetVal, NodeMap);
+ InitNH(Callee, FromCall.Callee, NodeMap);
+
+ 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...
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];
// 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<const DSNode*, DSNode*> &BUNodeMapTy);
+ DSGraph(const DSGraph &DSG, std::map<const DSNode*, DSNode*> &BUNodeMap);
~DSGraph();
bool hasFunction() const { return Func != 0; }
class Type;
class DSGraph;
+class DSNode;
class DSNodeHandle;
class DSCallSite;
class LocalDataStructures; // A collection of local graphs for a program
class TDDataStructures : public Pass {
// DSInfo, one graph for each function
std::map<const Function*, DSGraph*> 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<const DSNode*, DSNodeHandle> BUNodeMapTy;
+ std::map<const Function*, BUNodeMapTy> BUMaps;
public:
~TDDataStructures() { releaseMemory(); }
private:
DSGraph &calculateGraph(Function &F);
- void ResolveCallSite(DSGraph &Graph,
- const DSCallSite &CallSite);
+ void ResolveCallSite(DSGraph &Graph, const DSCallSite &CallSite);
};
#if 0
// 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<DSCallSite> &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,
// our memory... here...
//
void TDDataStructures::releaseMemory() {
+ BUMaps.clear();
for (std::map<const Function*, DSGraph*>::iterator I = DSInfo.begin(),
E = DSInfo.end(); I != E; ++I)
delete I->second;
BUDataStructures &BU = getAnalysis<BUDataStructures>();
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<const DSNode*, DSNode*> 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<DSCallSite> *CallSitesP = BU.getCallSites(F);
if (CallSitesP == 0) {
DEBUG(std::cerr << " [TD] Inlining callers for: " << F.getName() << "\n");
const std::vector<DSCallSite> &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...
//
std::map<Value*, DSNodeHandle> OldValMap;
std::map<const DSNode*, DSNode*> 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!
/*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");