1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 19:52:54 +01:00

Stop representing scalars as explicit nodes in the graph. Now the only

nodes in the graph are memory objects, which is very nice.  This also greatly
reduces the size and memory footprint for DSGraphs.  For example, the local
DSGraph for llu went from 65 to 13 nodes with this change.  As a side bonus,
dot seems to lay out the graphs slightly better too.  :)

llvm-svn: 4488
This commit is contained in:
Chris Lattner 2002-11-02 00:13:20 +00:00
parent f76aa218db
commit 226c503f31
4 changed files with 141 additions and 178 deletions

View File

@ -16,8 +16,7 @@ using std::map;
static RegisterAnalysis<BUDataStructures>
X("budatastructure", "Bottom-up Data Structure Analysis Closure");
// TODO: FIXME
namespace DataStructureAnalysis {
namespace DataStructureAnalysis { // TODO: FIXME: Eliminate
// isPointerType - Return true if this first class type is big enough to hold
// a pointer.
//
@ -60,14 +59,12 @@ static void ResolveArguments(DSCallSite &Call, Function &F,
map<Value*, DSNodeHandle> &ValueMap) {
// Resolve all of the function arguments...
Function::aiterator AI = F.abegin();
for (unsigned i = 0, e = Call.getNumPtrArgs(); i != e; ++i) {
for (unsigned i = 0, e = Call.getNumPtrArgs(); i != e; ++i, ++AI) {
// Advance the argument iterator to the first pointer argument...
while (!isPointerType(AI->getType())) ++AI;
// Add the link from the argument scalar to the provided value
DSNodeHandle &NN = ValueMap[AI];
NN.addEdgeTo(Call.getPtrArg(i));
++AI;
ValueMap[AI].mergeWith(Call.getPtrArg(i));
}
}
@ -118,8 +115,7 @@ DSGraph &BUDataStructures::calculateGraph(Function &F) {
DEBUG(std::cerr << "\t[BU] Self Inlining: " << F.getName() << "\n");
// Handle the return value if present...
if (Call.getRetVal().getNode())
Graph->getRetNode().mergeWith(Call.getRetVal());
Graph->getRetNode().mergeWith(Call.getRetVal());
// Resolve the arguments in the call to the actual values...
ResolveArguments(Call, F, Graph->getValueMap());
@ -143,11 +139,12 @@ 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.
#if 1 /// FIXME: Reenable
std::vector<DSCallSite> &CallSitesForFunc = CallSites[&FI];
CallSitesForFunc.push_back(Call);
CallSitesForFunc.back().setResolvingCaller(&F);
CallSitesForFunc.back().setCallee(0);
#endif
// Clone the callee's graph into the current graph, keeping
// track of where scalars in the old graph _used_ to point,
// and of the new nodes matching nodes of the old graph.
@ -163,8 +160,8 @@ DSGraph &BUDataStructures::calculateGraph(Function &F) {
// Resolve the arguments in the call to the actual values...
ResolveArguments(Call, FI, OldValMap);
if (Call.getRetVal().getNode())// Handle the return value if present
RetVal.mergeWith(Call.getRetVal());
// Handle the return value if present...
RetVal.mergeWith(Call.getRetVal());
// Erase the entry in the Callees vector
Callees.erase(Callees.begin()+c--);
@ -172,9 +169,10 @@ DSGraph &BUDataStructures::calculateGraph(Function &F) {
} else if (FI.getName() == "printf" || FI.getName() == "sscanf" ||
FI.getName() == "fprintf" || FI.getName() == "open" ||
FI.getName() == "sprintf") {
// FIXME: These special cases should go away when we can define
// functions that take a variable number of arguments.
// FIXME: These special cases (eg printf) should go away when we can
// define functions that take a variable number of arguments.
// FIXME: at the very least, this should update mod/ref info
// Erase the entry in the globals vector
Callees.erase(Callees.begin()+c--);
}

View File

@ -16,8 +16,7 @@
using std::vector;
// TODO: FIXME
namespace DataStructureAnalysis {
namespace DataStructureAnalysis { // TODO: FIXME
// isPointerType - Return true if this first class type is big enough to hold
// a pointer.
//
@ -538,14 +537,15 @@ void DSNode::remapLinks(std::map<const DSNode*, DSNode*> &OldNodeMap) {
// cloneInto - Clone the specified DSGraph into the current graph, returning the
// Return node of the graph. The translated ValueMap for the old function is
// filled into the OldValMap member. If StripLocals is set to true, Scalar and
// Alloca markers are removed from the graph, as the graph is being cloned into
// a calling function's graph.
// filled into the OldValMap member. If StripAllocas is set to true, Alloca
// markers are removed from the graph, as the graph is being cloned into a
// calling function's graph.
//
DSNodeHandle DSGraph::cloneInto(const DSGraph &G,
std::map<Value*, DSNodeHandle> &OldValMap,
std::map<const DSNode*, DSNode*> &OldNodeMap,
bool StripScalars, bool StripAllocas) {
bool StripScalars, // FIXME: Kill StripScalars
bool StripAllocas) {
assert(OldNodeMap.empty() && "Returned OldNodeMap should be empty!");
unsigned FN = Nodes.size(); // First new node...
@ -564,8 +564,7 @@ DSNodeHandle DSGraph::cloneInto(const DSGraph &G,
Nodes[i]->remapLinks(OldNodeMap);
// Remove local markers as specified
unsigned char StripBits = (StripScalars ? DSNode::ScalarNode : 0) |
(StripAllocas ? DSNode::AllocaNode : 0);
unsigned char StripBits = StripAllocas ? DSNode::AllocaNode : 0;
if (StripBits)
for (unsigned i = FN, e = Nodes.size(); i != e; ++i)
Nodes[i]->NodeType &= ~StripBits;
@ -574,7 +573,8 @@ DSNodeHandle DSGraph::cloneInto(const DSGraph &G,
for (std::map<Value*, DSNodeHandle>::const_iterator I = G.ValueMap.begin(),
E = G.ValueMap.end(); I != E; ++I) {
DSNodeHandle &H = OldValMap[I->first];
H = DSNodeHandle(OldNodeMap[I->second.getNode()], I->second.getOffset());
H.setNode(OldNodeMap[I->second.getNode()]);
H.setOffset(I->second.getOffset());
if (isa<GlobalValue>(I->first)) { // Is this a global?
std::map<Value*, DSNodeHandle>::iterator GVI = ValueMap.find(I->first);
@ -655,11 +655,8 @@ void DSGraph::markIncompleteNodes(bool markFormalArgs) {
// Mark any incoming arguments as incomplete...
if (markFormalArgs && Func)
for (Function::aiterator I = Func->abegin(), E = Func->aend(); I != E; ++I)
if (isPointerType(I->getType()) && ValueMap.find(I) != ValueMap.end()) {
DSNodeHandle &INH = ValueMap[I];
if (INH.getNode() && INH.hasLink(0))
markIncompleteNode(ValueMap[I].getLink(0)->getNode());
}
if (isPointerType(I->getType()) && ValueMap.find(I) != ValueMap.end())
markIncompleteNode(ValueMap[I].getNode());
// Mark stuff passed into functions calls as being incomplete...
for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i) {
@ -667,17 +664,16 @@ void DSGraph::markIncompleteNodes(bool markFormalArgs) {
// Then the return value is certainly incomplete!
markIncompleteNode(Call.getRetVal().getNode());
// The call does not make the function argument incomplete...
// All arguments to the function call are incomplete though!
// All objects pointed to by function arguments are incomplete though!
for (unsigned i = 0, e = Call.getNumPtrArgs(); i != e; ++i)
markIncompleteNode(Call.getPtrArg(i).getNode());
}
// Mark all of the nodes pointed to by global or cast nodes as incomplete...
// Mark all of the nodes pointed to by global nodes as incomplete...
for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
if (Nodes[i]->NodeType & DSNode::GlobalNode) {
DSNode *N = Nodes[i];
// FIXME: Make more efficient by looking over Links directly
for (unsigned i = 0, e = N->getSize(); i != e; ++i)
if (DSNodeHandle *DSNH = N->getLink(i))
markIncompleteNode(DSNH->getNode());
@ -706,9 +702,7 @@ bool DSGraph::isNodeDead(DSNode *N) {
return true;
// Is it a function node or some other trivially unused global?
if (N->NodeType != 0 &&
(N->NodeType & ~DSNode::GlobalNode) == 0 &&
N->getSize() == 0 &&
if ((N->NodeType & ~DSNode::GlobalNode) == 0 && N->getSize() == 0 &&
N->getReferrers().size() == N->getGlobals().size()) {
// Remove the globals from the ValueMap, so that the referrer count will go
@ -758,6 +752,7 @@ static void markAlive(DSNode *N, std::set<DSNode*> &Alive) {
if (N == 0) return;
Alive.insert(N);
// FIXME: Make more efficient by looking over Links directly
for (unsigned i = 0, e = N->getSize(); i != e; ++i)
if (DSNodeHandle *DSNH = N->getLink(i))
if (!Alive.count(DSNH->getNode()))
@ -887,7 +882,7 @@ static void markGlobalsAlive(DSGraph &G, std::set<DSNode*> &Alive,
markGlobalsIteration(GlobalNodes, Calls, Alive, FilterCalls);
// Free up references to dead globals from the ValueMap
std::set<DSNode*>::iterator I=GlobalNodes.begin(), E=GlobalNodes.end();
std::set<DSNode*>::iterator I = GlobalNodes.begin(), E = GlobalNodes.end();
for( ; I != E; ++I)
if (Alive.count(*I) == 0)
removeRefsToGlobal(*I, G.getValueMap());
@ -931,19 +926,20 @@ void DSGraph::removeDeadNodes(bool KeepAllGlobals, bool KeepCalls) {
markAlive(FunctionCalls[i].getCallee().getNode(), Alive);
}
#if 0
for (unsigned i = 0, e = OrigFunctionCalls.size(); i != e; ++i)
for (unsigned j = 0, e = OrigFunctionCalls[i].size(); j != e; ++j)
markAlive(OrigFunctionCalls[i][j].getNode(), Alive);
#endif
// Mark all nodes reachable by scalar nodes as alive...
for (std::map<Value*, DSNodeHandle>::iterator I = ValueMap.begin(),
E = ValueMap.end(); I != E; ++I)
markAlive(I->second.getNode(), Alive);
// Mark all nodes reachable by scalar nodes (and global nodes, if
// keeping them was specified) as alive...
unsigned char keepBits = DSNode::ScalarNode |
(KeepAllGlobals ? DSNode::GlobalNode : 0);
for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
if (Nodes[i]->NodeType & keepBits)
markAlive(Nodes[i], Alive);
#if 0
// Marge all nodes reachable by global nodes, as alive. Isn't this covered by
// the ValueMap?
//
if (KeepAllGlobals)
for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
if (Nodes[i]->NodeType & DSNode::GlobalNode)
markAlive(Nodes[i], Alive);
#endif
// The return value is alive as well...
markAlive(RetNode.getNode(), Alive);
@ -952,7 +948,7 @@ void DSGraph::removeDeadNodes(bool KeepAllGlobals, bool KeepCalls) {
// This also marks all nodes reachable from such nodes as alive.
// Of course, if KeepAllGlobals is specified, they would be live already.
if (!KeepAllGlobals)
markGlobalsAlive(*this, Alive, ! KeepCalls);
markGlobalsAlive(*this, Alive, !KeepCalls);
// Loop over all unreachable nodes, dropping their references...
vector<DSNode*> DeadNodes;

View File

@ -61,7 +61,6 @@ namespace {
vector<DSNode*> &Nodes;
DSNodeHandle &RetNode; // Node that gets returned...
map<Value*, DSNodeHandle> &ValueMap;
map<GlobalValue*, DSNodeHandle> GlobalScalarValueMap;
vector<DSCallSite> &FunctionCalls;
public:
@ -107,23 +106,21 @@ namespace {
/// createNode - Create a new DSNode, ensuring that it is properly added to
/// the graph.
///
DSNode *createNode(DSNode::NodeTy NodeType, const Type *Ty);
DSNode *createNode(DSNode::NodeTy NodeType, const Type *Ty = 0) {
DSNode *N = new DSNode(NodeType, Ty); // Create the node
Nodes.push_back(N); // Add node to nodes list
return N;
}
/// getValueNode - Return a DSNode that corresponds the the specified LLVM
/// value. This either returns the already existing node, or creates a new
/// one and adds it to the graph, if none exists.
/// setDestTo - Set the ValueMap entry for the specified value to point to
/// the specified destination. If the Value already points to a node, make
/// sure to merge the two destinations together.
///
DSNodeHandle &getValueNode(Value &V);
void setDestTo(Value &V, const DSNodeHandle &NH);
/// getValueDest - Return the DSNode that the actual value points to. This
/// is the same thing as: getLink(getValueNode(V))
/// getValueDest - Return the DSNode that the actual value points to.
///
DSNodeHandle &getValueDest(Value &V);
/// getGlobalNode - Just like getValueNode, except the global node itself is
/// returned, not a scalar node pointing to a global.
///
DSNodeHandle &getGlobalNode(GlobalValue &V);
DSNodeHandle getValueDest(Value &V);
/// getLink - This method is used to return the specified link in the
/// specified node if one exists. If a link does not already exist (it's
@ -148,78 +145,34 @@ DSGraph::DSGraph(Function &F) : Func(&F) {
//
// createNode - Create a new DSNode, ensuring that it is properly added to the
// graph.
//
DSNode *GraphBuilder::createNode(DSNode::NodeTy NodeType, const Type *Ty) {
DSNode *N = new DSNode(NodeType, Ty);
Nodes.push_back(N);
return N;
}
// getGlobalNode - Just like getValueNode, except the global node itself is
// returned, not a scalar node pointing to a global.
//
DSNodeHandle &GraphBuilder::getGlobalNode(GlobalValue &V) {
DSNodeHandle &NH = ValueMap[&V];
if (NH.getNode()) return NH; // Already have a node? Just return it...
// Create a new global node for this global variable...
DSNode *G = createNode(DSNode::GlobalNode, V.getType()->getElementType());
G->addGlobal(&V);
// If this node has outgoing edges, make sure to recycle the same node for
// each use. For functions and other global variables, this is unneccesary,
// so avoid excessive merging by cloning these nodes on demand.
//
NH.setNode(G);
return NH;
}
// getValueNode - Return a DSNode that corresponds the the specified LLVM value.
// This either returns the already existing node, or creates a new one and adds
// it to the graph, if none exists.
//
DSNodeHandle &GraphBuilder::getValueNode(Value &V) {
assert(isPointerType(V.getType()) && "Should only use pointer scalars!");
if (GlobalValue *GV = dyn_cast<GlobalValue>(&V)) {
// The GlobalScalarValueMap keeps track of the scalar nodes that point to
// global values... The ValueMap contains pointers to the global memory
// object itself, not the scalar constant that points to the memory.
//
DSNodeHandle &NH = GlobalScalarValueMap[GV];
if (NH.getNode()) return NH;
// If this is a global value, create the global pointed to.
DSNode *N = createNode(DSNode::ScalarNode, V.getType());
NH.setOffset(0);
NH.setNode(N);
N->addEdgeTo(0, getGlobalNode(*GV));
return NH;
} else {
DSNodeHandle &NH = ValueMap[&V];
if (NH.getNode())
return NH; // Already have a node? Just return it...
// Otherwise we need to create a new scalar node...
DSNode *N = createNode(DSNode::ScalarNode, V.getType());
NH.setOffset(0);
NH.setNode(N);
return NH;
}
}
/// getValueDest - Return the DSNode that the actual value points to. This is
/// the same thing as: getLink(getValueNode(V), 0)
/// getValueDest - Return the DSNode that the actual value points to.
///
DSNodeHandle &GraphBuilder::getValueDest(Value &V) {
return getLink(getValueNode(V));
DSNodeHandle GraphBuilder::getValueDest(Value &V) {
if (Constant *C = dyn_cast<Constant>(&V)) {
// FIXME: Return null NH for constants like 10 or null
// FIXME: Handle constant exprs here.
return 0; // Constant doesn't point to anything.
}
DSNodeHandle &NH = ValueMap[&V];
if (NH.getNode())
return NH; // Already have a node? Just return it...
// Otherwise we need to create a new node to point to...
DSNode *N;
if (GlobalValue *GV = dyn_cast<GlobalValue>(&V)) {
// Create a new global node for this global variable...
N = createNode(DSNode::GlobalNode, GV->getType()->getElementType());
N->addGlobal(GV);
} else {
// Otherwise just create a shadow node
N = createNode(DSNode::ShadowNode);
}
NH.setNode(N); // Remember that we are pointing to it...
NH.setOffset(0);
return NH;
}
@ -235,12 +188,25 @@ DSNodeHandle &GraphBuilder::getLink(const DSNodeHandle &node, unsigned LinkNo) {
if (Link) return *Link;
// If the link hasn't been created yet, make and return a new shadow node
DSNode *N = createNode(DSNode::ShadowNode, 0);
DSNode *N = createNode(DSNode::ShadowNode);
Node.setLink(LinkNo, N);
return *Node.getLink(LinkNo);
}
/// setDestTo - Set the ValueMap entry for the specified value to point to the
/// specified destination. If the Value already points to a node, make sure to
/// merge the two destinations together.
///
void GraphBuilder::setDestTo(Value &V, const DSNodeHandle &NH) {
DSNodeHandle &AINH = ValueMap[&V];
if (AINH.getNode() == 0) // Not pointing to anything yet?
AINH = NH; // Just point directly to NH
else
AINH.mergeWith(NH);
}
//===----------------------------------------------------------------------===//
// Specific instruction type handler implementations...
//
@ -249,10 +215,7 @@ DSNodeHandle &GraphBuilder::getLink(const DSNodeHandle &node, unsigned LinkNo) {
/// object, pointing the scalar to it.
///
void GraphBuilder::handleAlloc(AllocationInst &AI, DSNode::NodeTy NodeType) {
DSNode *New = createNode(NodeType, 0);
// Make the scalar point to the new node...
getValueNode(AI).addEdgeTo(New);
setDestTo(AI, createNode(NodeType));
}
// PHINode - Make the scalar for the PHI node point to all of the things the
@ -261,14 +224,14 @@ void GraphBuilder::handleAlloc(AllocationInst &AI, DSNode::NodeTy NodeType) {
void GraphBuilder::visitPHINode(PHINode &PN) {
if (!isPointerType(PN.getType())) return; // Only pointer PHIs
DSNodeHandle &ScalarDest = getValueDest(PN);
DSNodeHandle &PNDest = ValueMap[&PN];
for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i)
if (!isa<ConstantPointerNull>(PN.getIncomingValue(i)))
ScalarDest.mergeWith(getValueDest(*PN.getIncomingValue(i)));
PNDest.mergeWith(getValueDest(*PN.getIncomingValue(i)));
}
void GraphBuilder::visitGetElementPtrInst(GetElementPtrInst &GEP) {
DSNodeHandle Value = getValueDest(*GEP.getOperand(0));
if (Value.getNode() == 0) return;
unsigned Offset = 0;
const PointerType *PTy = cast<PointerType>(GEP.getOperand(0)->getType());
@ -278,7 +241,7 @@ void GraphBuilder::visitGetElementPtrInst(GetElementPtrInst &GEP) {
// If the node had to be folded... exit quickly
if (TopTypeRec.Ty == Type::VoidTy) {
getValueNode(GEP).addEdgeTo(Value); // GEP result points to folded node
setDestTo(GEP, Value); // GEP result points to folded node
return;
}
@ -297,7 +260,7 @@ void GraphBuilder::visitGetElementPtrInst(GetElementPtrInst &GEP) {
if (Value.getOffset()) {
// Value is now the pointer we want to GEP to be...
Value.getNode()->foldNodeCompletely();
getValueNode(GEP).addEdgeTo(Value); // GEP result points to folded node
setDestTo(GEP, Value); // GEP result points to folded node
return;
} else {
// This is a pointer to the first byte of the node. Make sure that we
@ -346,56 +309,51 @@ void GraphBuilder::visitGetElementPtrInst(GetElementPtrInst &GEP) {
Value.setOffset(Value.getOffset()+Offset);
// Value is now the pointer we want to GEP to be...
getValueNode(GEP).addEdgeTo(Value);
setDestTo(GEP, Value);
}
void GraphBuilder::visitLoadInst(LoadInst &LI) {
DSNodeHandle &Ptr = getValueDest(*LI.getOperand(0));
DSNodeHandle Ptr = getValueDest(*LI.getOperand(0));
if (Ptr.getNode() == 0) return;
// Make that the node is read from...
Ptr.getNode()->NodeType |= DSNode::Read;
// Ensure a typerecord exists...
Ptr.getNode()->getTypeRec(LI.getType(), Ptr.getOffset());
if (isPointerType(LI.getType()))
getValueNode(LI).addEdgeTo(getLink(Ptr));
setDestTo(LI, getLink(Ptr));
}
void GraphBuilder::visitStoreInst(StoreInst &SI) {
DSNodeHandle &Dest = getValueDest(*SI.getOperand(1));
Dest.getNode()->NodeType |= DSNode::Modified;
const Type *StoredTy = SI.getOperand(0)->getType();
DSNodeHandle Dest = getValueDest(*SI.getOperand(1));
if (Dest.getNode() == 0) return;
// Make that the node is written to...
Dest.getNode()->NodeType |= DSNode::Modified;
// Ensure a typerecord exists...
Dest.getNode()->getTypeRec(StoredTy, Dest.getOffset());
// Avoid adding edges from null, or processing non-"pointer" stores
if (isPointerType(StoredTy) &&
!isa<ConstantPointerNull>(SI.getOperand(0))) {
if (isPointerType(StoredTy))
Dest.addEdgeTo(getValueDest(*SI.getOperand(0)));
}
}
void GraphBuilder::visitReturnInst(ReturnInst &RI) {
if (RI.getNumOperands() && isPointerType(RI.getOperand(0)->getType()) &&
!isa<ConstantPointerNull>(RI.getOperand(0))) {
DSNodeHandle &Value = getValueDest(*RI.getOperand(0));
Value.mergeWith(RetNode);
RetNode = Value;
}
if (RI.getNumOperands() && isPointerType(RI.getOperand(0)->getType()))
RetNode.mergeWith(getValueDest(*RI.getOperand(0)));
}
void GraphBuilder::visitCallInst(CallInst &CI) {
// Set up the return value...
DSNodeHandle RetVal;
if (isPointerType(CI.getType()))
RetVal = getLink(getValueNode(CI));
RetVal = getValueDest(CI);
DSNodeHandle Callee;
// Special case for a direct call, avoid creating spurious scalar node...
if (GlobalValue *GV = dyn_cast<GlobalValue>(CI.getOperand(0)))
Callee = getGlobalNode(*GV);
else
Callee = getLink(getValueNode(*CI.getOperand(0)));
DSNodeHandle Callee = getValueDest(*CI.getOperand(0));
std::vector<DSNodeHandle> Args;
Args.reserve(CI.getNumOperands()-1);
@ -403,7 +361,7 @@ void GraphBuilder::visitCallInst(CallInst &CI) {
// Calculate the arguments vector...
for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i)
if (isPointerType(CI.getOperand(i)->getType()))
Args.push_back(getLink(getValueNode(*CI.getOperand(i))));
Args.push_back(getValueDest(*CI.getOperand(i)));
// Add a new function call entry...
FunctionCalls.push_back(DSCallSite(CI, RetVal, Callee, Args));
@ -411,8 +369,12 @@ void GraphBuilder::visitCallInst(CallInst &CI) {
/// Handle casts...
void GraphBuilder::visitCastInst(CastInst &CI) {
if (isPointerType(CI.getType()) && isPointerType(CI.getOperand(0)->getType()))
getValueNode(CI).addEdgeTo(getLink(getValueNode(*CI.getOperand(0))));
if (isPointerType(CI.getType())) {
if (isPointerType(CI.getOperand(0)->getType()))
setDestTo(CI, getValueDest(*CI.getOperand(0)));
else
; // FIXME: "Other" node
}
}

View File

@ -36,7 +36,6 @@ static string getCaption(const DSNode *N, const DSGraph *G) {
OS << "\n";
}
if (N->NodeType & DSNode::ScalarNode) OS << "S";
if (N->NodeType & DSNode::AllocaNode) OS << "A";
if (N->NodeType & DSNode::NewNode ) OS << "N";
if (N->NodeType & DSNode::GlobalNode) OS << "G";
@ -49,15 +48,6 @@ static string getCaption(const DSNode *N, const DSGraph *G) {
OS << "\n";
}
if ((N->NodeType & DSNode::ScalarNode) && G) {
const std::map<Value*, DSNodeHandle> &VM = G->getValueMap();
for (std::map<Value*, DSNodeHandle>::const_iterator I = VM.begin(),
E = VM.end(); I != E; ++I)
if (I->second.getNode() == N) {
WriteAsOperand(OS, I->first, false, true, M);
OS << "\n";
}
}
return OS.str();
}
@ -94,6 +84,23 @@ struct DOTGraphTraits<const DSGraph*> : public DefaultDOTGraphTraits {
///
static void addCustomGraphFeatures(const DSGraph *G,
GraphWriter<const DSGraph*> &GW) {
// Add scalar nodes to the graph...
const std::map<Value*, DSNodeHandle> &VM = G->getValueMap();
for (std::map<Value*, DSNodeHandle>::const_iterator I = VM.begin();
I != VM.end(); ++I)
if (!isa<GlobalValue>(I->first)) {
std::stringstream OS;
WriteAsOperand(OS, I->first, false, true, G->getFunction().getParent());
GW.emitSimpleNode(I->first, "plaintext=circle", OS.str());
// Add edge from return node to real destination
int EdgeDest = I->second.getOffset();
if (EdgeDest == 0) EdgeDest = -1;
GW.emitEdge(I->first, -1, I->second.getNode(),
EdgeDest, "arrowtail=tee,color=gray63");
}
// Output the returned value pointer...
if (G->getRetNode().getNode() != 0) {
// Output the return node...