1 //===- DataStructure.h - Build data structure graphs -------------*- C++ -*--=//
3 // Implement the LLVM data structure analysis library.
5 //===----------------------------------------------------------------------===//
7 #ifndef LLVM_ANALYSIS_DATA_STRUCTURE_H
8 #define LLVM_ANALYSIS_DATA_STRUCTURE_H
10 #include "llvm/Pass.h"
18 class FunctionRepBuilder;
20 class FunctionDSGraph;
25 // FIXME: move this somewhere private
26 unsigned countPointerFields(const Type *Ty);
28 // PointerVal - Represent a pointer to a datastructure. The pointer points to
29 // a node, and can index into it. This is used for getelementptr instructions,
30 // which do not affect which node a pointer points to, but does change the field
35 unsigned Index; // Index into Node->FieldLinks[]
37 PointerVal(DSNode *N, unsigned Idx = 0) : Node(N), Index(Idx) {}
39 DSNode *getNode() const { return Node; }
40 unsigned getIndex() const { return Index; }
42 inline bool operator==(DSNode *N) const { return Node == N; }
43 inline bool operator!=(DSNode *N) const { return Node != N; }
45 // operator< - Allow insertion into a map...
46 bool operator<(const PointerVal &PV) const {
47 return Node < PV.Node || (Node == PV.Node && Index < PV.Index);
50 inline bool operator==(const PointerVal &PV) const {
51 return Node == PV.Node && Index == PV.Index;
53 inline bool operator!=(const PointerVal &PV) const { return !operator==(PV); }
55 void print(std::ostream &O) const;
59 // PointerValSet - This class represents a list of pointer values. The add
60 // method is used to add values to the set, and ensures that duplicates cannot
64 std::vector<PointerVal> Vals;
69 PointerValSet(const PointerValSet &PVS) : Vals(PVS.Vals) { addRefs(); }
70 ~PointerValSet() { dropRefs(); }
71 const PointerValSet &operator=(const PointerValSet &PVS);
73 // operator< - Allow insertion into a map...
74 bool operator<(const PointerValSet &PVS) const;
75 bool operator==(const PointerValSet &PVS) const;
76 bool operator!=(const PointerValSet &PVS) const { return !operator==(PVS); }
78 const PointerVal &operator[](unsigned i) const { return Vals[i]; }
80 unsigned size() const { return Vals.size(); }
81 bool empty() const { return Vals.empty(); }
82 void clear() { dropRefs(); Vals.clear(); }
84 // add - Add the specified pointer, or contents of the specified PVS to this
85 // pointer set. If a 'Pointer' value is provided, notify the underlying data
86 // structure node that the pointer is pointing to it, so that it can be
87 // invalidated if neccesary later. True is returned if the value is new to
90 bool add(const PointerVal &PV, Value *Pointer = 0);
91 bool add(const PointerValSet &PVS, Value *Pointer = 0) {
93 for (unsigned i = 0, e = PVS.size(); i != e; ++i)
94 Changed |= add(PVS[i], Pointer);
98 // removePointerTo - Remove a single pointer val that points to the specified
100 void removePointerTo(DSNode *Node);
102 void print(std::ostream &O) const;
106 //===----------------------------------------------------------------------===//
107 // DSNode - Base class for all data structure nodes...
109 // This class keeps track of its type, the pointer fields in the data structure,
110 // and a list of LLVM values that are pointing to this node.
113 friend class FunctionDSGraph;
115 std::vector<PointerValSet> FieldLinks;
116 std::vector<Value*> Pointers; // Values pointing to me...
117 std::vector<PointerValSet*> Referrers;
119 std::vector<std::pair<const Type *, ShadowDSNode *> > SynthNodes;
121 DSNode(const DSNode &); // DO NOT IMPLEMENT
122 void operator=(const DSNode &); // DO NOT IMPLEMENT
125 NewNode, CallNode, ShadowNode, GlobalNode
128 DSNode(enum NodeTy NT, const Type *T);
131 assert(Referrers.empty() && "Referrers to dead node exist!");
134 typedef DSNodeIterator iterator;
135 inline iterator begin(); // Defined in DataStructureGraph.h
136 inline iterator end();
138 unsigned getNumLinks() const { return FieldLinks.size(); }
139 PointerValSet &getLink(unsigned i) {
140 assert(i < getNumLinks() && "Field links access out of range...");
141 return FieldLinks[i];
143 const PointerValSet &getLink(unsigned i) const {
144 assert(i < getNumLinks() && "Field links access out of range...");
145 return FieldLinks[i];
148 // addReferrer - Keep the referrer set up to date...
149 void addReferrer(PointerValSet *PVS) { Referrers.push_back(PVS); }
150 void removeReferrer(PointerValSet *PVS);
151 const std::vector<PointerValSet*> &getReferrers() const { return Referrers; }
153 // removeAllIncomingEdges - Erase all edges in the graph that point to
155 void removeAllIncomingEdges();
157 void addPointer(Value *V) { Pointers.push_back(V); }
158 const std::vector<Value*> &getPointers() const { return Pointers; }
160 const Type *getType() const { return Ty; }
162 // getNumOutgoingLinks - Return the number of outgoing links, which is usually
163 // the number of normal links, but for call nodes it also includes their
166 virtual unsigned getNumOutgoingLinks() const { return getNumLinks(); }
167 virtual PointerValSet &getOutgoingLink(unsigned Link) {
168 return getLink(Link);
170 virtual const PointerValSet &getOutgoingLink(unsigned Link) const {
171 return getLink(Link);
174 void print(std::ostream &O) const;
177 virtual std::string getCaption() const = 0;
178 virtual const std::vector<PointerValSet> *getAuxLinks() const {
179 return 0; // Default to nothing...
182 // isEquivalentTo - Return true if the nodes should be merged...
183 virtual bool isEquivalentTo(DSNode *Node) const = 0;
184 virtual void mergeInto(DSNode *Node) const {}
186 DSNode *clone() const {
187 DSNode *New = cloneImpl();
188 // Add all of the pointers to the new node...
189 for (unsigned pn = 0, pe = Pointers.size(); pn != pe; ++pn)
190 New->addPointer(Pointers[pn]);
194 // synthesizeNode - Create a new shadow node that is to be linked into this
197 ShadowDSNode *synthesizeNode(const Type *Ty, FunctionRepBuilder *Rep);
199 virtual void dropAllReferences() {
203 static bool classof(const DSNode *N) { return true; }
205 virtual DSNode *cloneImpl() const = 0;
206 virtual void mapNode(std::map<const DSNode*, DSNode*> &NodeMap,
211 // AllocDSNode - Represent all allocation (malloc or alloca) in the program.
213 class AllocDSNode : public DSNode {
214 AllocationInst *Allocation;
215 bool isVarSize; // Allocating variable sized objects
217 AllocDSNode(AllocationInst *V, bool isVarSize = false);
219 virtual std::string getCaption() const;
221 bool isAllocaNode() const;
222 bool isMallocNode() const { return !isAllocaNode(); }
224 AllocationInst *getAllocation() const { return Allocation; }
225 bool isVariableSize() const { return isVarSize; }
227 // isEquivalentTo - Return true if the nodes should be merged...
228 virtual bool isEquivalentTo(DSNode *Node) const;
229 virtual void mergeInto(DSNode *Node) const;
231 // Support type inquiry through isa, cast, and dyn_cast...
232 static bool classof(const AllocDSNode *) { return true; }
233 static bool classof(const DSNode *N) { return N->NodeType == NewNode; }
235 virtual AllocDSNode *cloneImpl() const { return new AllocDSNode(Allocation,
240 // GlobalDSNode - Represent the memory location that a global variable occupies
242 class GlobalDSNode : public DSNode {
245 GlobalDSNode(GlobalValue *V);
247 GlobalValue *getGlobal() const { return Val; }
249 virtual std::string getCaption() const;
251 // isEquivalentTo - Return true if the nodes should be merged...
252 virtual bool isEquivalentTo(DSNode *Node) const;
254 // Support type inquiry through isa, cast, and dyn_cast...
255 static bool classof(const GlobalDSNode *) { return true; }
256 static bool classof(const DSNode *N) { return N->NodeType == GlobalNode; }
258 virtual GlobalDSNode *cloneImpl() const { return new GlobalDSNode(Val); }
262 // CallDSNode - Represent a call instruction in the program...
264 class CallDSNode : public DSNode {
265 friend class FunctionDSGraph;
267 std::vector<PointerValSet> ArgLinks;
269 CallDSNode(CallInst *CI);
274 CallInst *getCall() const { return CI; }
276 const std::vector<PointerValSet> *getAuxLinks() const { return &ArgLinks; }
277 virtual std::string getCaption() const;
279 bool addArgValue(unsigned ArgNo, const PointerValSet &PVS) {
280 return ArgLinks[ArgNo].add(PVS);
283 unsigned getNumArgs() const { return ArgLinks.size(); }
284 const PointerValSet &getArgValues(unsigned ArgNo) const {
285 assert(ArgNo < ArgLinks.size() && "Arg # out of range!");
286 return ArgLinks[ArgNo];
288 PointerValSet &getArgValues(unsigned ArgNo) {
289 assert(ArgNo < ArgLinks.size() && "Arg # out of range!");
290 return ArgLinks[ArgNo];
292 const std::vector<PointerValSet> &getArgs() const { return ArgLinks; }
294 virtual void dropAllReferences() {
295 DSNode::dropAllReferences();
299 // getNumOutgoingLinks - Return the number of outgoing links, which is usually
300 // the number of normal links, but for call nodes it also includes their
303 virtual unsigned getNumOutgoingLinks() const {
304 return getNumLinks() + getNumArgs();
306 virtual PointerValSet &getOutgoingLink(unsigned Link) {
307 if (Link < getNumLinks()) return getLink(Link);
308 return getArgValues(Link-getNumLinks());
310 virtual const PointerValSet &getOutgoingLink(unsigned Link) const {
311 if (Link < getNumLinks()) return getLink(Link);
312 return getArgValues(Link-getNumLinks());
315 // isEquivalentTo - Return true if the nodes should be merged...
316 virtual bool isEquivalentTo(DSNode *Node) const;
318 // Support type inquiry through isa, cast, and dyn_cast...
319 static bool classof(const CallDSNode *) { return true; }
320 static bool classof(const DSNode *N) { return N->NodeType == CallNode; }
322 virtual CallDSNode *cloneImpl() const { return new CallDSNode(CI); }
323 virtual void mapNode(std::map<const DSNode*, DSNode*> &NodeMap,
328 // ShadowDSNode - Represent a chunk of memory that we need to be able to
329 // address. These are generated due to (for example) pointer type method
330 // arguments... if the pointer is dereferenced, we need to have a node to point
331 // to. When functions are integrated into each other, shadow nodes are
334 class ShadowDSNode : public DSNode {
335 friend class FunctionDSGraph;
336 friend class FunctionRepBuilder;
338 DSNode *ShadowParent; // Nonnull if this is a synthesized node...
340 ShadowDSNode(const Type *Ty, Module *M);
341 virtual std::string getCaption() const;
343 // isEquivalentTo - Return true if the nodes should be merged...
344 virtual bool isEquivalentTo(DSNode *Node) const;
346 DSNode *getShadowParent() const { return ShadowParent; }
348 // Support type inquiry through isa, cast, and dyn_cast...
349 static bool classof(const ShadowDSNode *) { return true; }
350 static bool classof(const DSNode *N) { return N->NodeType == ShadowNode; }
353 ShadowDSNode(const Type *Ty, Module *M, DSNode *ShadParent);
355 virtual ShadowDSNode *cloneImpl() const {
357 return new ShadowDSNode(getType(), Mod, ShadowParent);
359 return new ShadowDSNode(getType(), Mod);
364 // FunctionDSGraph - The graph that represents a method.
366 class FunctionDSGraph {
368 std::vector<AllocDSNode*> AllocNodes;
369 std::vector<ShadowDSNode*> ShadowNodes;
370 std::vector<GlobalDSNode*> GlobalNodes;
371 std::vector<CallDSNode*> CallNodes;
372 PointerValSet RetNode; // Node that gets returned...
373 std::map<Value*, PointerValSet> ValueMap;
375 // cloneFunctionIntoSelf - Clone the specified method graph into the current
376 // method graph, returning the Return's set of the graph. If ValueMap is set
377 // to true, the ValueMap of the function is cloned into this function as well
378 // as the data structure graph itself. Regardless, the arguments value sets
379 // of DSG are copied into Args.
381 PointerValSet cloneFunctionIntoSelf(const FunctionDSGraph &G, bool ValueMap,
382 std::vector<PointerValSet> &Args);
384 bool RemoveUnreachableNodes();
385 bool UnlinkUndistinguishableNodes();
386 void MarkEscapeableNodesReachable(std::vector<bool> &RSN,
387 std::vector<bool> &RAN);
390 // Define the interface only accessable to DataStructure
391 friend class DataStructure;
392 FunctionDSGraph(Function *F);
393 FunctionDSGraph(const FunctionDSGraph &DSG);
396 void computeClosure(const DataStructure &DS);
399 Function *getFunction() const { return Func; }
401 // getEscapingAllocations - Add all allocations that escape the current
402 // function to the specified vector.
404 void getEscapingAllocations(std::vector<AllocDSNode*> &Allocs);
406 // getNonEscapingAllocations - Add all allocations that do not escape the
407 // current function to the specified vector.
409 void getNonEscapingAllocations(std::vector<AllocDSNode*> &Allocs);
411 // getValueMap - Get a map that describes what the nodes the scalars in this
412 // function point to...
414 std::map<Value*, PointerValSet> &getValueMap() { return ValueMap; }
415 const std::map<Value*, PointerValSet> &getValueMap() const { return ValueMap;}
417 const PointerValSet &getRetNodes() const { return RetNode; }
419 unsigned getGraphSize() const {
420 return AllocNodes.size() + ShadowNodes.size() +
421 GlobalNodes.size() + CallNodes.size();
424 void printFunction(std::ostream &O, const char *Label) const;
428 // FIXME: This should be a FunctionPass. When the pass framework sees a 'Pass'
429 // that uses the output of a FunctionPass, it should automatically build a map
430 // of output from the method pass that the pass can use.
432 class DataStructure : public Pass {
433 // DSInfo, one intraprocedural and one closed graph for each method...
434 typedef std::map<Function*, std::pair<FunctionDSGraph*,
435 FunctionDSGraph*> > InfoMap;
436 mutable InfoMap DSInfo;
438 static AnalysisID ID; // DataStructure Analysis ID
440 DataStructure(AnalysisID id) { assert(id == ID); }
441 ~DataStructure() { releaseMemory(); }
443 virtual const char *getPassName() const { return "Data Structure Analysis"; }
445 // run - Do nothing, because methods are analyzed lazily
446 virtual bool run(Module &TheModule) { return false; }
448 // getDSGraph - Return the data structure graph for the specified method.
449 // Since method graphs are lazily computed, we may have to create one on the
452 FunctionDSGraph &getDSGraph(Function *F) const {
453 std::pair<FunctionDSGraph*, FunctionDSGraph*> &N = DSInfo[F];
454 if (N.first) return *N.first;
455 return *(N.first = new FunctionDSGraph(F));
458 // getClosedDSGraph - Return the data structure graph for the specified
459 // method. Since method graphs are lazily computed, we may have to create one
460 // on the fly here. This is different than the normal DSGraph for the method
461 // because any function calls that are resolvable will have the data structure
462 // graphs of the called function incorporated into this function as well.
464 FunctionDSGraph &getClosedDSGraph(Function *F) const {
465 std::pair<FunctionDSGraph*, FunctionDSGraph*> &N = DSInfo[F];
466 if (N.second) return *N.second;
467 N.second = new FunctionDSGraph(getDSGraph(F));
468 N.second->computeClosure(*this);
472 // invalidateFunction - Inform this analysis that you changed the specified
473 // function, so the graphs that depend on it are out of date.
475 void invalidateFunction(Function *F) const {
476 // FIXME: THis should invalidate all functions who have inlined the
479 std::pair<FunctionDSGraph*, FunctionDSGraph*> &N = DSInfo[F];
482 N.first = N.second = 0;
485 // print - Print out the analysis results...
486 void print(std::ostream &O, Module *M) const;
488 // If the pass pipeline is done with this pass, we can release our memory...
489 virtual void releaseMemory();
491 // getAnalysisUsage - This obviously provides a call graph
492 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
493 AU.setPreservesAll();