[llvm-commits] [poolalloc] r106474 - in /poolalloc/trunk: include/dsa/DSGraph.h include/dsa/DSNode.h include/dsa/DSSupport.h lib/DSA/BottomUpClosure.cpp lib/DSA/DSGraph.cpp lib/DSA/DataStructure.cpp lib/DSA/Local.cpp lib/DSA/Makefile lib/DSA/Printer.cpp lib/DSA/TopDownClosure.cpp
Will Dietz
wdietz2 at illinois.edu
Mon Jun 21 13:52:30 PDT 2010
Author: wdietz2
Date: Mon Jun 21 15:52:30 2010
New Revision: 106474
URL: http://llvm.org/viewvc/llvm-project?rev=106474&view=rev
Log:
Improve var-arg support in DSA
Modified:
poolalloc/trunk/include/dsa/DSGraph.h
poolalloc/trunk/include/dsa/DSNode.h
poolalloc/trunk/include/dsa/DSSupport.h
poolalloc/trunk/lib/DSA/BottomUpClosure.cpp
poolalloc/trunk/lib/DSA/DSGraph.cpp
poolalloc/trunk/lib/DSA/DataStructure.cpp
poolalloc/trunk/lib/DSA/Local.cpp
poolalloc/trunk/lib/DSA/Makefile
poolalloc/trunk/lib/DSA/Printer.cpp
poolalloc/trunk/lib/DSA/TopDownClosure.cpp
Modified: poolalloc/trunk/include/dsa/DSGraph.h
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSGraph.h?rev=106474&r1=106473&r2=106474&view=diff
==============================================================================
--- poolalloc/trunk/include/dsa/DSGraph.h (original)
+++ poolalloc/trunk/include/dsa/DSGraph.h Mon Jun 21 15:52:30 2010
@@ -18,6 +18,7 @@
#include "dsa/DSNode.h"
#include "dsa/DSCallGraph.h"
#include "llvm/ADT/EquivalenceClasses.h"
+#include "llvm/Function.h"
#include <list>
#include <map>
@@ -195,6 +196,7 @@
// Public data-type declarations...
typedef DSScalarMap ScalarMapTy;
typedef std::map<const Function*, DSNodeHandle> ReturnNodesTy;
+ typedef std::map<const Function*, DSNodeHandle> VANodesTy;
typedef ilist<DSNode> NodeListTy;
/// NodeMapTy - This data type is used when cloning one graph into another to
@@ -218,6 +220,10 @@
//
ReturnNodesTy ReturnNodes;
+ // VANodes - Special "Variable Argument" Node for each function
+ //
+ VANodesTy VANodes;
+
// FunctionCalls - This list maintains a single entry for each call
// instruction in the current graph. The first entry in the vector is the
// scalar that holds the return value for the call, the second is the function
@@ -377,6 +383,10 @@
typedef ReturnNodesTy::const_iterator retnodes_iterator;
retnodes_iterator retnodes_begin() const { return ReturnNodes.begin(); }
retnodes_iterator retnodes_end() const { return ReturnNodes.end(); }
+
+ typedef VANodesTy::const_iterator vanodes_iterator;
+ vanodes_iterator vanodes_begin() const { return VANodes.begin(); }
+ vanodes_iterator vanodes_end() const { return VANodes.end(); }
/// getReturnNodes - Return the mapping of functions to their return nodes for
@@ -399,10 +409,28 @@
return I->second;
}
+ /// getVANodeFor - Return the var-arg node for the specified function.
+ ///
+ DSNodeHandle &getVANodeFor(const Function &F) {
+ VANodesTy::iterator I = VANodes.find(&F);
+ assert(I != VANodes.end() && "Var-arg info for F not in this graph!");
+ return I->second;
+ }
+
+ const DSNodeHandle &getVANodeFor(const Function &F) const {
+ VANodesTy::const_iterator I = VANodes.find(&F);
+ assert(I != VANodes.end() && "Var-arg info for F not in this graph!");
+ return I->second;
+ }
+
DSNodeHandle& getOrCreateReturnNodeFor(const Function& F) {
return ReturnNodes[&F];
}
+ DSNodeHandle& getOrCreateVANodeFor(const Function& F) {
+ return VANodes[&F];
+ }
+
/// containsFunction - Return true if this DSGraph contains information for
/// the specified function.
bool containsFunction(const Function *F) const {
Modified: poolalloc/trunk/include/dsa/DSNode.h
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSNode.h?rev=106474&r1=106473&r2=106474&view=diff
==============================================================================
--- poolalloc/trunk/include/dsa/DSNode.h (original)
+++ poolalloc/trunk/include/dsa/DSNode.h Mon Jun 21 15:52:30 2010
@@ -103,7 +103,7 @@
ExternalNode = 1 << 11, // This node comes from an external source
IntToPtrNode = 1 << 12, // This node comes from an int cast
PtrToIntNode = 1 << 13, // This node excapes to an int cast
- VAStartNode = 1 << 14, // This node excapes to an int cast
+ VAStartNode = 1 << 14, // This node is from a vastart call
//#ifndef NDEBUG
DeadNode = 1 << 15, // This node is dead and should not be pointed to
Modified: poolalloc/trunk/include/dsa/DSSupport.h
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSSupport.h?rev=106474&r1=106473&r2=106474&view=diff
==============================================================================
--- poolalloc/trunk/include/dsa/DSSupport.h (original)
+++ poolalloc/trunk/include/dsa/DSSupport.h Mon Jun 21 15:52:30 2010
@@ -25,6 +25,7 @@
namespace llvm {
class Function;
+class FunctionType;
class CallInst;
class Value;
class GlobalValue;
@@ -158,6 +159,7 @@
const Function *CalleeF; // The function called (direct call)
DSNodeHandle CalleeN; // The function node called (indirect call)
DSNodeHandle RetVal; // Returned value
+ DSNodeHandle VarArgVal; // Merged var-arg val
std::vector<DSNodeHandle> CallArgs; // The pointer arguments
static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src,
@@ -189,22 +191,23 @@
/// Constructor. Note - This ctor destroys the argument vector passed in. On
/// exit, the argument vector is empty.
///
- DSCallSite(CallSite CS, const DSNodeHandle &rv, DSNode *Callee,
- std::vector<DSNodeHandle> &Args)
- : Site(CS), CalleeF(0), CalleeN(Callee), RetVal(rv) {
+ DSCallSite(CallSite CS, const DSNodeHandle &rv, const DSNodeHandle &va,
+ DSNode *Callee, std::vector<DSNodeHandle> &Args)
+ : Site(CS), CalleeF(0), CalleeN(Callee), RetVal(rv), VarArgVal(va) {
assert(Callee && "Null callee node specified for call site!");
Args.swap(CallArgs);
}
- DSCallSite(CallSite CS, const DSNodeHandle &rv, const Function *Callee,
- std::vector<DSNodeHandle> &Args)
- : Site(CS), CalleeF(Callee), RetVal(rv) {
+ DSCallSite(CallSite CS, const DSNodeHandle &rv, const DSNodeHandle &va,
+ const Function *Callee, std::vector<DSNodeHandle> &Args)
+ : Site(CS), CalleeF(Callee), RetVal(rv), VarArgVal(va) {
assert(Callee && "Null callee function specified for call site!");
Args.swap(CallArgs);
}
DSCallSite(const DSCallSite &DSCS) // Simple copy ctor
: Site(DSCS.Site), CalleeF(DSCS.CalleeF), CalleeN(DSCS.CalleeN),
- RetVal(DSCS.RetVal), CallArgs(DSCS.CallArgs) {}
+ RetVal(DSCS.RetVal), VarArgVal(DSCS.VarArgVal),
+ CallArgs(DSCS.CallArgs) {}
/// Mapping copy constructor - This constructor takes a preexisting call site
/// to copy plus a map that specifies how the links should be transformed.
@@ -215,6 +218,7 @@
Site = FromCall.Site;
InitNH(RetVal, FromCall.RetVal, NodeMap);
InitNH(CalleeN, FromCall.CalleeN, NodeMap);
+ InitNH(VarArgVal, FromCall.VarArgVal, NodeMap);
CalleeF = FromCall.CalleeF;
CallArgs.resize(FromCall.CallArgs.size());
@@ -227,6 +231,7 @@
CalleeF = RHS.CalleeF;
CalleeN = RHS.CalleeN;
RetVal = RHS.RetVal;
+ VarArgVal = RHS.VarArgVal;
CallArgs = RHS.CallArgs;
return *this;
}
@@ -244,6 +249,8 @@
CallSite getCallSite() const { return Site; }
DSNodeHandle &getRetVal() { return RetVal; }
const DSNodeHandle &getRetVal() const { return RetVal; }
+ DSNodeHandle &getVAVal() { return VarArgVal; }
+ const DSNodeHandle &getVAVal() const { return VarArgVal; }
DSNode *getCalleeNode() const {
assert(!CalleeF && CalleeN.getNode()); return CalleeN.getNode();
@@ -271,6 +278,7 @@
if (this != &CS) {
std::swap(Site, CS.Site);
std::swap(RetVal, CS.RetVal);
+ std::swap(VarArgVal, CS.VarArgVal);
std::swap(CalleeN, CS.CalleeN);
std::swap(CalleeF, CS.CalleeF);
std::swap(CallArgs, CS.CallArgs);
@@ -282,6 +290,7 @@
///
void mergeWith(DSCallSite &CS) {
getRetVal().mergeWith(CS.getRetVal());
+ getVAVal().mergeWith(CS.getVAVal());
unsigned MinArgs = getNumPtrArgs();
if (CS.getNumPtrArgs() < MinArgs) MinArgs = CS.getNumPtrArgs();
@@ -310,13 +319,26 @@
}
if (RetVal < CS.RetVal) return true;
if (RetVal > CS.RetVal) return false;
+ if (VarArgVal < CS.VarArgVal) return true;
+ if (VarArgVal > CS.VarArgVal) return false;
return CallArgs < CS.CallArgs;
}
bool operator==(const DSCallSite &CS) const {
return CalleeF == CS.CalleeF && CalleeN == CS.CalleeN &&
- RetVal == CS.RetVal && CallArgs == CS.CallArgs;
+ RetVal == CS.RetVal && CallArgs == CS.CallArgs &&
+ VarArgVal == CS.VarArgVal;
}
+
+ /// FunctionTypeOfCallSite - Helper method to extract the signature of a function
+ /// that is called a given CallSite
+ ///
+ static const FunctionType *FunctionTypeOfCallSite(const CallSite & Site);
+
+ /// isVarArg - Determines if the call this represents is to a variable argument
+ /// function
+ ///
+ bool isVarArg() const;
};
} // End llvm namespace
Modified: poolalloc/trunk/lib/DSA/BottomUpClosure.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/BottomUpClosure.cpp?rev=106474&r1=106473&r2=106474&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/BottomUpClosure.cpp (original)
+++ poolalloc/trunk/lib/DSA/BottomUpClosure.cpp Mon Jun 21 15:52:30 2010
@@ -58,8 +58,10 @@
// entry-points correctly. As a bonus, we can be more aggressive at propagating
// information upwards, as long as we don't remove unresolved call sites.
bool BUDataStructures::runOnModuleInternal(Module& M) {
+#if 0
llvm::errs() << "BU is currently being worked in in very invasive ways.\n"
<< "It is probably broken right now\n";
+#endif
//Find SCCs and make SCC call graph
callgraph.buildSCCs();
@@ -248,6 +250,7 @@
for (std::set<DSCallSite>::iterator ii = BadCalls.begin(),
ee = BadCalls.end(); ii != ee; ++ii) {
ii->getRetVal().getNode()->markReachableNodes(reachable);
+ ii->getVAVal().getNode()->markReachableNodes(reachable);
for (unsigned x = 0; x < ii->getNumPtrArgs(); ++x)
ii->getPtrArg(x).getNode()->markReachableNodes(reachable);
}
@@ -339,7 +342,7 @@
// Fast path for noop calls. Note that we don't care about merging globals
// in the callee with nodes in the caller here.
- if (CS.getRetVal().isNull() && CS.getNumPtrArgs() == 0) {
+ if (CS.getRetVal().isNull() && CS.getNumPtrArgs() == 0 && !CS.isVarArg()) {
TempFCs.erase(TempFCs.begin());
continue;
}
Modified: poolalloc/trunk/lib/DSA/DSGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/DSGraph.cpp?rev=106474&r1=106473&r2=106474&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/DSGraph.cpp (original)
+++ poolalloc/trunk/lib/DSA/DSGraph.cpp Mon Jun 21 15:52:30 2010
@@ -84,6 +84,7 @@
AuxFunctionCalls.clear();
ScalarMap.clear();
ReturnNodes.clear();
+ VANodes.clear();
// Drop all intra-node references, so that assertions don't fail...
for (node_iterator NI = node_begin(), E = node_end(); NI != E; ++NI)
@@ -137,8 +138,8 @@
/// cloneInto - Clone the specified DSGraph into the current graph. The
/// translated ScalarMap for the old function is filled into the ScalarMap
-/// for the graph, and the translated ReturnNodes map is returned into
-/// ReturnNodes.
+/// for the graph, the translated ReturnNodes map is returned into
+/// ReturnNodes, and the translated VANodes map is return into VANodes.
///
/// The CloneFlags member controls various aspects of the cloning process.
///
@@ -208,6 +209,17 @@
DSNodeHandle(MappedRetN,
MappedRet.getOffset()+Ret.getOffset())));
}
+
+ // Map the VA node pointers over...
+ for (vanodes_iterator I = G->vanodes_begin(),
+ E = G->vanodes_end(); I != E; ++I) {
+ const DSNodeHandle &VarArg = I->second;
+ DSNodeHandle &MappedVarArg = OldNodeMap[VarArg.getNode()];
+ DSNode *MappedVarArgN = MappedVarArg.getNode();
+ VANodes.insert(std::make_pair(I->first,
+ DSNodeHandle(MappedVarArgN,
+ MappedVarArg.getOffset()+VarArg.getOffset())));
+ }
}
/// spliceFrom - Logically perform the operation of cloning the RHS graph into
@@ -235,6 +247,14 @@
RHS->ReturnNodes.clear();
}
+ // Same for the VA nodes
+ if (VANodes.empty()) {
+ VANodes.swap(RHS->VANodes);
+ } else {
+ VANodes.insert(RHS->VANodes.begin(), RHS->VANodes.end());
+ RHS->VANodes.clear();
+ }
+
// Merge the scalar map in.
ScalarMap.spliceFrom(RHS->ScalarMap);
}
@@ -242,11 +262,12 @@
/// getFunctionArgumentsForCall - Given a function that is currently in this
/// graph, return the DSNodeHandles that correspond to the pointer-compatible
/// function arguments. The vector is filled in with the return value (or
-/// null if it is not pointer compatible), followed by all of the
-/// pointer-compatible arguments.
+/// null if it is not pointer compatible), a vararg node (null if not
+/// applicable) followed by all of the pointer-compatible arguments.
void DSGraph::getFunctionArgumentsForCall(const Function *F,
std::vector<DSNodeHandle> &Args) const {
Args.push_back(getReturnNodeFor(*F));
+ Args.push_back(getVANodeFor(*F));
for (Function::const_arg_iterator AI = F->arg_begin(), E = F->arg_end();
AI != E; ++AI)
if (isa<PointerType>(AI->getType())) {
@@ -287,6 +308,8 @@
for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i)
if (PathExistsToClonedNode(CS.getPtrArg(i).getNode()))
return true;
+ if (PathExistsToClonedNode(CS.getVAVal().getNode()))
+ return true;
return false;
}
};
@@ -378,13 +401,16 @@
// Merge the return value with the return value of the context.
Args[0].mergeWith(CS.getRetVal());
+ // Merge var-arg node
+ Args[1].mergeWith(CS.getVAVal());
+
// Resolve all of the function arguments.
for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i) {
- if (i == Args.size()-1)
+ if (i == Args.size()-2)
break;
// Add the link from the argument scalar to the provided value.
- Args[i+1].mergeWith(CS.getPtrArg(i));
+ Args[i+2].mergeWith(CS.getPtrArg(i));
}
return;
}
@@ -398,13 +424,17 @@
if (!CS.getRetVal().isNull())
RC.merge(CS.getRetVal(), Args[0]);
+ // Map the variable arguments
+ if (!CS.getVAVal().isNull())
+ RC.merge(CS.getVAVal(), Args[1]);
+
// Map over all of the arguments.
for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i) {
- if (i == Args.size()-1)
+ if (i == Args.size()-2)
break;
// Add the link from the argument scalar to the provided value.
- RC.merge(CS.getPtrArg(i), Args[i+1]);
+ RC.merge(CS.getPtrArg(i), Args[i+2]);
}
// We generally don't want to copy global nodes or aux calls from the callee
@@ -479,34 +509,42 @@
if (isa<PointerType>(I->getType()))
Args.push_back(getNodeForValue(I));
- return DSCallSite(CallSite(), getReturnNodeFor(F), &F, Args);
+ return DSCallSite(CallSite(), getReturnNodeFor(F), getVANodeFor(F), &F, Args);
}
/// getDSCallSiteForCallSite - Given an LLVM CallSite object that is live in
/// the context of this graph, return the DSCallSite for it.
DSCallSite DSGraph::getDSCallSiteForCallSite(CallSite CS) const {
- DSNodeHandle RetVal;
+ DSNodeHandle RetVal, VarArg;
Instruction *I = CS.getInstruction();
if (isa<PointerType>(I->getType()))
RetVal = getNodeForValue(I);
+ //FIXME: Here we trust the signature of the callsite to determine which arguments
+ //are var-arg and which are fixed. Apparently we can't assume this, but I'm not sure
+ //of a better way. For now, this assumption is known limitation.
+ const FunctionType *CalleeFuncType = DSCallSite::FunctionTypeOfCallSite(CS);
+ unsigned NumFixedArgs = CalleeFuncType->getNumParams();
+
std::vector<DSNodeHandle> Args;
Args.reserve(CS.arg_end()-CS.arg_begin());
// Calculate the arguments vector...
for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); I != E; ++I)
if (isa<PointerType>((*I)->getType())) {
- if (isa<ConstantPointerNull>(*I))
- Args.push_back(DSNodeHandle());
- else
- Args.push_back(getNodeForValue(*I));
+ const DSNodeHandle ArgNode = getNodeForValue(*I);
+ if (I - CS.arg_begin() < NumFixedArgs) {
+ Args.push_back(ArgNode);
+ } else {
+ VarArg.mergeWith(ArgNode);
+ }
}
// Add a new function call entry...
if (Function *F = CS.getCalledFunction())
- return DSCallSite(CS, RetVal, F, Args);
+ return DSCallSite(CS, RetVal, VarArg, F, Args);
else
- return DSCallSite(CS, RetVal,
+ return DSCallSite(CS, RetVal, VarArg,
getNodeForValue(CS.getCalledValue()).getNode(), Args);
}
@@ -535,6 +573,8 @@
// Then the return value is certainly incomplete!
markIncompleteNode(Call.getRetVal().getNode());
+ markIncompleteNode(Call.getVAVal().getNode());
+
// All objects pointed to by function arguments are incomplete!
for (unsigned i = 0, e = Call.getNumPtrArgs(); i != e; ++i)
markIncompleteNode(Call.getPtrArg(i).getNode());
@@ -552,7 +592,7 @@
//
void DSGraph::markIncompleteNodes(unsigned Flags) {
// Mark any incoming arguments as incomplete.
- if (Flags & DSGraph::MarkFormalArgs)
+ if (Flags & DSGraph::MarkFormalArgs) {
for (ReturnNodesTy::iterator FI = ReturnNodes.begin(), E =ReturnNodes.end();
FI != E; ++FI) {
const Function &F = *FI->first;
@@ -562,6 +602,11 @@
markIncompleteNode(getNodeForValue(I).getNode());
markIncompleteNode(FI->second.getNode());
}
+ // Mark all vanodes as incomplete (they are also arguments)
+ for (vanodes_iterator I = vanodes_begin(), E = vanodes_end();
+ I != E; ++I)
+ markIncompleteNode(I->second.getNode());
+ }
// Mark stuff passed into functions calls as being incomplete.
if (!shouldPrintAuxCalls())
@@ -667,6 +712,7 @@
// to it, remove the edge to the node (killing the node).
//
killIfUselessEdge(CS.getRetVal());
+ killIfUselessEdge(CS.getVAVal());
for (unsigned a = 0, e = CS.getNumPtrArgs(); a != e; ++a)
killIfUselessEdge(CS.getPtrArg(a));
@@ -883,6 +929,8 @@
if (CanReachAliveNodes(CS.getRetVal().getNode(), Alive, Visited,
IgnoreGlobals))
return true;
+ if (CanReachAliveNodes(CS.getVAVal().getNode(), Alive, Visited, IgnoreGlobals))
+ return true;
if (CS.isIndirectCall() &&
CanReachAliveNodes(CS.getCalleeNode(), Alive, Visited, IgnoreGlobals))
return true;
@@ -1059,6 +1107,7 @@
#endif
}
AssertNodeInGraph(CS.getRetVal().getNode());
+ AssertNodeInGraph(CS.getVAVal().getNode());
for (unsigned j = 0, e = CS.getNumPtrArgs(); j != e; ++j)
AssertNodeInGraph(CS.getPtrArg(j).getNode());
}
@@ -1099,6 +1148,9 @@
if (isa<PointerType>(AI->getType()))
assert(!getNodeForValue(AI).isNull() &&
"Pointer argument must be in the scalar map!");
+ if (F.isVarArg())
+ assert(VANodes.find(&F) != VANodes.end() &&
+ "VarArg function missing VANode!");
}
}
@@ -1186,6 +1238,7 @@
CalleeGraph.getCallSiteForArguments(const_cast<Function&>(Callee));
computeNodeMapping(CalleeArgs.getRetVal(), CS.getRetVal(), NodeMap);
+ computeNodeMapping(CalleeArgs.getVAVal(), CS.getVAVal(), NodeMap);
unsigned NumArgs = CS.getNumPtrArgs();
if (NumArgs > CalleeArgs.getNumPtrArgs())
Modified: poolalloc/trunk/lib/DSA/DataStructure.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/DataStructure.cpp?rev=106474&r1=106473&r2=106474&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/DataStructure.cpp (original)
+++ poolalloc/trunk/lib/DSA/DataStructure.cpp Mon Jun 21 15:52:30 2010
@@ -813,6 +813,7 @@
void ReachabilityCloner::mergeCallSite(DSCallSite &DestCS,
const DSCallSite &SrcCS) {
merge(DestCS.getRetVal(), SrcCS.getRetVal());
+ merge(DestCS.getVAVal(), SrcCS.getVAVal());
unsigned MinArgs = DestCS.getNumPtrArgs();
if (SrcCS.getNumPtrArgs() < MinArgs) MinArgs = SrcCS.getNumPtrArgs();
@@ -830,11 +831,13 @@
if (SrcCS.isDirectCall())
return DSCallSite(SrcCS.getCallSite(),
getClonedNH(SrcCS.getRetVal()),
+ getClonedNH(SrcCS.getVAVal()),
SrcCS.getCalleeFunc(),
Args);
else
return DSCallSite(SrcCS.getCallSite(),
getClonedNH(SrcCS.getRetVal()),
+ getClonedNH(SrcCS.getVAVal()),
getClonedNH(SrcCS.getCalleeNode()).getNode(),
Args);
}
@@ -853,6 +856,39 @@
NH = RC.getClonedNH(Src);
}
+/// FunctionTypeOfCallSite - Helper method to extract the signature of a function
+/// that is called a given CallSite
+///
+const FunctionType *DSCallSite::FunctionTypeOfCallSite(const CallSite & Site) {
+ Value *Callee = Site.getCalledValue();
+
+ // Direct call, simple
+ if (Function *F = dyn_cast<Function>(Callee))
+ return F->getFunctionType();
+
+ // Indirect call, extract the type
+ const FunctionType *CalleeFuncType = NULL;
+
+ const PointerType *CalleeType = dyn_cast<PointerType>(Callee->getType());
+ if (!CalleeType) {
+ assert(0 && "Call through a non-pointer type?");
+ } else {
+ CalleeFuncType = dyn_cast<FunctionType>(CalleeType->getElementType());
+ assert(CalleeFuncType &&
+ "Call through pointer to non-function?");
+ }
+
+ return CalleeFuncType;
+}
+
+/// isVarArg - Determines if the call this represents is to a variable argument
+/// function
+///
+bool DSCallSite::isVarArg() const {
+ const FunctionType *FT = FunctionTypeOfCallSite(Site);
+ return FT->isVarArg();
+}
+
/// remapLinks - Change all of the Links in the current node according to the
/// specified mapping.
///
@@ -897,6 +933,8 @@
return true;
if (CS.isDirectCall() || PathExistsToClonedNode(CS.getCalleeNode()))
return true;
+ if (PathExistsToClonedNode(CS.getVAVal().getNode()))
+ return true;
for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i)
if (PathExistsToClonedNode(CS.getPtrArg(i).getNode()))
return true;
@@ -990,6 +1028,7 @@
void DSCallSite::markReachableNodes(DenseSet<const DSNode*> &Nodes) const {
getRetVal().getNode()->markReachableNodes(Nodes);
+ getVAVal().getNode()->markReachableNodes(Nodes);
if (isIndirectCall()) getCalleeNode()->markReachableNodes(Nodes);
for (unsigned i = 0, e = getNumPtrArgs(); i != e; ++i)
Modified: poolalloc/trunk/lib/DSA/Local.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/Local.cpp?rev=106474&r1=106473&r2=106474&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/Local.cpp (original)
+++ poolalloc/trunk/lib/DSA/Local.cpp Mon Jun 21 15:52:30 2010
@@ -29,6 +29,7 @@
#include "llvm/Support/Timer.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Triple.h"
#include <fstream>
@@ -148,6 +149,8 @@
bool visitIntrinsic(CallSite CS, Function* F);
void visitCallSite(CallSite CS);
+ void visitVAStartInst(CallSite CS);
+ void visitVAStartNode(DSNode* N);
public:
GraphBuilder(Function &f, DSGraph &g, DataStructures& DSi)
@@ -168,6 +171,9 @@
// the graph
g.getOrCreateReturnNodeFor(f);
+ // Create a node to handle information about variable arguments
+ g.getOrCreateVANodeFor(f);
+
visit(f); // Single pass over the function
// If there are any constant globals referenced in this function, merge
@@ -391,6 +397,7 @@
}
void GraphBuilder::visitVAArgInst(VAArgInst &I) {
+ assert(0 && "What frontend generates this?");
//FIXME: also updates the argument
DSNodeHandle Ptr = getValueDest(I.getOperand(0));
if (Ptr.isNull()) return;
@@ -604,45 +611,105 @@
visitCallSite(&II);
}
+void GraphBuilder::visitVAStartInst(CallSite CS) {
+ // Build out DSNodes for the va_list depending on the target arch
+ // And assosiate the right node with the VANode for this function
+ // so it can be merged with the right arguments from callsites
+
+ DSNodeHandle RetNH = getValueDest(*CS.arg_begin());
+
+ if (DSNode *N = RetNH.getNode())
+ visitVAStartNode(N);
+ else
+ {
+ //
+ // Sometimes the argument to the vastart is casted and has no DSNode.
+ // Peer past the cast.
+ //
+ Value * Operand = CS.getInstruction()->getOperand(1);
+ if (CastInst * CI = dyn_cast<CastInst>(Operand))
+ Operand = CI->getOperand (0);
+ const DSNodeHandle & CastNH = getValueDest(Operand);
+ visitVAStartNode(CastNH.getNode());
+ //We assert out here because it's not clear when this happens
+ assert(0 && "When does this happen?");
+ }
+}
+
+void GraphBuilder::visitVAStartNode(DSNode* N) {
+ assert(FB && "No function for this graph?");
+ Module *M = FB->getParent();
+ assert(M && "No module for function");
+ Triple TargetTriple(M->getTargetTriple());
+ Triple::ArchType Arch = TargetTriple.getArch();
+
+ // Fetch the VANode associated with the func containing the call to va_start
+ DSNodeHandle & VANH = G.getVANodeFor(*FB);
+ // Make sure this NodeHandle has a node to go with it
+ if (VANH.isNull()) VANH.mergeWith(createNode());
+
+ // Create a dsnode for an array of pointers to the VAInfo for this func
+ DSNode * VAArray = createNode();
+ VAArray->setArrayMarker();
+ VAArray->foldNodeCompletely();
+ VAArray->setLink(0,VANH);
+
+ //VAStart modifies its argument
+ N->setModifiedMarker();
+
+ // For the architectures we support, build dsnodes that match
+ // how we know va_list is used.
+ switch (Arch) {
+ case Triple::x86:
+ // On x86, we have:
+ // va_list as a pointer to an array of pointers to the variable arguments
+ N->growSize(1);
+ N->setLink(0, VAArray);
+ break;
+ case Triple::x86_64:
+ // On x86_64, we have va_list as a struct {i32, i32, i8*, i8* }
+ // The first i8* is where arguments generally go, but the second i8* can be used
+ // also to pass arguments by register.
+ // We model this by having both the i8*'s point to an array of pointers to the arguments.
+ N->growSize(24); //sizeof the va_list struct mentioned above
+ N->setLink(8,VAArray); //first i8*
+ N->setLink(16,VAArray); //second i8*
+ break;
+ default:
+ // FIXME: For now we abort if we don't know how to handle this arch
+ // Either add support for other architectures, or at least mark the
+ // nodes unknown/incomplete or whichever results in the correct
+ // conservative behavior in the general case
+ assert(0 && "VAstart not supported on this architecture!");
+ //XXX: This might be good enough in those cases that we don't know
+ //what the arch does
+ N->setIncompleteMarker()->setUnknownMarker()->foldNodeCompletely();
+ }
+
+ //XXX: We used to set the alloca marker for the DSNode passed to va_start.
+ //Seems to me that you could allocate the va_list on the heap, so ignoring for now.
+ N->setModifiedMarker()->setVAStartMarker();
+}
+
/// returns true if the intrinsic is handled
bool GraphBuilder::visitIntrinsic(CallSite CS, Function *F) {
++NumIntrinsicCall;
switch (F->getIntrinsicID()) {
case Intrinsic::vastart: {
- // Mark the memory written by the vastart intrinsic as incomplete
- DSNodeHandle RetNH = getValueDest(*CS.arg_begin());
- if (DSNode *N = RetNH.getNode()) {
- N->setModifiedMarker()->setAllocaMarker()->setIncompleteMarker()
- ->setVAStartMarker()->setUnknownMarker()->foldNodeCompletely();
- }
-
- if (RetNH.hasLink(0)) {
- DSNodeHandle Link = RetNH.getLink(0);
- if (DSNode *N = Link.getNode()) {
- N->setModifiedMarker()->setAllocaMarker()->setIncompleteMarker()
- ->setVAStartMarker()->setUnknownMarker()->foldNodeCompletely();
- }
- } else {
- //
- // Sometimes the argument to the vastart is casted and has no DSNode.
- // Peer past the cast.
- //
- Value * Operand = CS.getInstruction()->getOperand(1);
- if (CastInst * CI = dyn_cast<CastInst>(Operand))
- Operand = CI->getOperand (0);
- RetNH = getValueDest(Operand);
- if (DSNode *N = RetNH.getNode()) {
- N->setModifiedMarker()->setAllocaMarker()->setIncompleteMarker()
- ->setVAStartMarker()->setUnknownMarker()->foldNodeCompletely();
- }
- }
-
+ visitVAStartInst(CS);
return true;
}
- case Intrinsic::vacopy:
- getValueDest(CS.getInstruction()).
- mergeWith(getValueDest(*(CS.arg_begin())));
+ case Intrinsic::vacopy: {
+ // Simply merge the two arguments to va_copy.
+ // This results in loss of precision on the temporaries used to manipulate
+ // the va_list, and so isn't a big deal. In theory we would build a
+ // separate graph for this (like the one created in visitVAStartNode)
+ // and only merge the node containing the variable arguments themselves.
+ DSNodeHandle destNH = getValueDest(CS.getArgument(0));
+ DSNodeHandle srcNH = getValueDest(CS.getArgument(1));
+ destNH.mergeWith(srcNH);
return true;
+ }
case Intrinsic::stacksave: {
DSNode * Node = createNode();
Node->setAllocaMarker()->setIncompleteMarker()->setUnknownMarker();
@@ -813,23 +880,64 @@
}
}
+ //NOTE: This code is identical to 'DSGraph::getDSCallSiteForCallSite',
+ //the reason it's duplicated apparently is so we can increment the
+ //stats 'NumIndirectCall' and 'NumDirectCall'.
+ //FIXME: refactor so we don't have this duplication
+
+ //Get the FunctionType for the called function
+ const FunctionType *CalleeFuncType = DSCallSite::FunctionTypeOfCallSite(CS);
+ unsigned NumFixedArgs = CalleeFuncType->getNumParams();
+
+ // Sanity check--this really, really shouldn't happen
+ if (!CalleeFuncType->isVarArg())
+ assert(CS.arg_size() == NumFixedArgs &&
+ "Too many arguments/incorrect function signature!");
+
std::vector<DSNodeHandle> Args;
Args.reserve(CS.arg_end()-CS.arg_begin());
+ DSNodeHandle VarArgNH;
// Calculate the arguments vector...
- for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); I != E; ++I)
- if (isa<PointerType>((*I)->getType()))
- Args.push_back(getValueDest(*I));
+ if (!CalleeFuncType->isVarArg()) {
+ // Add all pointer arguments
+ for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
+ I != E; ++I) {
+ if (isa<PointerType>((*I)->getType()))
+ Args.push_back(getValueDest(*I));
+ if (I - CS.arg_begin() >= NumFixedArgs) {
+ errs() << "WARNING: Call contains too many arguments:\n";
+ CS.getInstruction()->dump();
+ assert(0 && "Failing for now");
+ }
+ }
+ } else {
+ // Add all fixed pointer arguments, then merge the rest together
+ for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end();
+ I != E; ++I)
+ if (isa<PointerType>((*I)->getType())) {
+ DSNodeHandle ArgNode = getValueDest(*I);
+ if (I - CS.arg_begin() < NumFixedArgs) {
+ Args.push_back(ArgNode);
+ } else {
+ VarArgNH.mergeWith(ArgNode);
+ }
+ }
+ }
// Add a new function call entry...
if (CalleeNode) {
++NumIndirectCall;
- G.getFunctionCalls().push_back(DSCallSite(CS, RetVal, CalleeNode, Args));
+ G.getFunctionCalls().push_back(DSCallSite(CS, RetVal, VarArgNH, CalleeNode,
+ Args));
} else {
++NumDirectCall;
- G.getFunctionCalls().push_back(DSCallSite(CS, RetVal, cast<Function>(Callee),
+ G.getFunctionCalls().push_back(DSCallSite(CS, RetVal, VarArgNH,
+ cast<Function>(Callee),
Args));
}
+
+
}
// visitInstruction - For all other instruction types, if we have any arguments
Modified: poolalloc/trunk/lib/DSA/Makefile
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/Makefile?rev=106474&r1=106473&r2=106474&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/Makefile (original)
+++ poolalloc/trunk/lib/DSA/Makefile Mon Jun 21 15:52:30 2010
@@ -17,6 +17,13 @@
endif
endif
+#Bah. Confirmed on llvm-dev, there's no good way for us to do this.
+#Essentially we're tasked with linking in the pieces that our plugin
+#makes use of--but /not/ the tool we're using does /not/ make use of.
+#It's dirty, but apparently what we're stuck with since we're a plugin
+LDFLAGS = $(LLVM_OBJ_ROOT)/lib/Support/$(BuildMode)/Triple.o
+
include $(LEVEL)/Makefile.common
CFlags += -Wno-deprecated
+
Modified: poolalloc/trunk/lib/DSA/Printer.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/Printer.cpp?rev=106474&r1=106473&r2=106474&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/Printer.cpp (original)
+++ poolalloc/trunk/lib/DSA/Printer.cpp Mon Jun 21 15:52:30 2010
@@ -91,6 +91,7 @@
if (NodeType & DSNode::ExternalNode ) OS << "E";
if (NodeType & DSNode::IntToPtrNode ) OS << "P";
if (NodeType & DSNode::PtrToIntNode ) OS << "2";
+ if (NodeType & DSNode::VAStartNode ) OS << "V";
#ifndef NDEBUG
if (NodeType & DSNode::DeadNode ) OS << "<dead>";
@@ -98,6 +99,15 @@
OS << "\n";
}
+ //Indicate if this is a VANode for some function
+ for (DSGraph::vanodes_iterator I = G->vanodes_begin(), E = G->vanodes_end();
+ I != E; ++I) {
+ DSNodeHandle VANode = I->second;
+ if (N == VANode.getNode()) {
+ OS << "(VANode for " << I->first->getNameStr() << ")\n";
+ }
+ }
+
EquivalenceClasses<const GlobalValue*> *GlobalECs = 0;
if (G) GlobalECs = &G->getGlobalECs();
@@ -257,6 +267,8 @@
GW.emitEdge(&Call, 0, N, EdgeDest, "color=gray63,tailclip=false");
}
+ // FIXME: visualize the VANode?
+
// Print out the callee...
if (Call.isIndirectCall()) {
DSNode *N = Call.getCalleeNode();
Modified: poolalloc/trunk/lib/DSA/TopDownClosure.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/TopDownClosure.cpp?rev=106474&r1=106473&r2=106474&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/TopDownClosure.cpp (original)
+++ poolalloc/trunk/lib/DSA/TopDownClosure.cpp Mon Jun 21 15:52:30 2010
@@ -355,8 +355,8 @@
// merged into it. The actual callee function doesn't matter here, so we
// just pass it something to keep the ctor happy.
std::vector<DSNodeHandle> ArgDummyVec;
- DSCallSite DummyCS(CI->getCallSite(), DSNodeHandle(), Callees[0]/*dummy*/,
- ArgDummyVec);
+ DSCallSite DummyCS(CI->getCallSite(), DSNodeHandle(), DSNodeHandle(),
+ Callees[0]/*dummy*/, ArgDummyVec);
IndCallGraph->getFunctionCalls().push_back(DummyCS);
IndCallRecI = IndCallMap.insert(IndCallRecI,
More information about the llvm-commits
mailing list