This commit was manufactured by cvs2svn to create branch 'poolalloc'.
llvm-svn: 7751
diff --git a/poolalloc/include/dsa/DSGraph.h b/poolalloc/include/dsa/DSGraph.h
deleted file mode 100644
index 10dca09..0000000
--- a/poolalloc/include/dsa/DSGraph.h
+++ /dev/null
@@ -1,308 +0,0 @@
-//===- DSGraph.h - Represent a collection of data structures ----*- C++ -*-===//
-//
-// This header defines the data structure graph.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_ANALYSIS_DSGRAPH_H
-#define LLVM_ANALYSIS_DSGRAPH_H
-
-#include "llvm/Analysis/DSNode.h"
-class GlobalValue;
-
-//===----------------------------------------------------------------------===//
-/// DSGraph - The graph that represents a function.
-///
-struct DSGraph {
- // Public data-type declarations...
- typedef hash_map<Value*, DSNodeHandle> ScalarMapTy;
- typedef hash_map<Function*, DSNodeHandle> ReturnNodesTy;
- typedef hash_set<const GlobalValue*> GlobalSetTy;
-
- /// NodeMapTy - This data type is used when cloning one graph into another to
- /// keep track of the correspondence between the nodes in the old and new
- /// graphs.
- typedef hash_map<const DSNode*, DSNodeHandle> NodeMapTy;
-private:
- DSGraph *GlobalsGraph; // Pointer to the common graph of global objects
- bool PrintAuxCalls; // Should this graph print the Aux calls vector?
-
- std::vector<DSNode*> Nodes;
- ScalarMapTy ScalarMap;
-
- // ReturnNodes - A return value for every function merged into this graph.
- // Each DSGraph may have multiple functions merged into it at any time, which
- // is used for representing SCCs.
- //
- ReturnNodesTy ReturnNodes;
-
- // FunctionCalls - This vector 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
- // scalar being invoked, and the rest are pointer arguments to the function.
- // This vector is built by the Local graph and is never modified after that.
- //
- std::vector<DSCallSite> FunctionCalls;
-
- // AuxFunctionCalls - This vector contains call sites that have been processed
- // by some mechanism. In pratice, the BU Analysis uses this vector to hold
- // the _unresolved_ call sites, because it cannot modify FunctionCalls.
- //
- std::vector<DSCallSite> AuxFunctionCalls;
-
- // InlinedGlobals - This set records which globals have been inlined from
- // other graphs (callers or callees, depending on the pass) into this one.
- //
- GlobalSetTy InlinedGlobals;
-
- void operator=(const DSGraph &); // DO NOT IMPLEMENT
-
-public:
- // Create a new, empty, DSGraph.
- DSGraph() : GlobalsGraph(0), PrintAuxCalls(false) {}
- DSGraph(Function &F, DSGraph *GlobalsGraph); // Compute the local DSGraph
-
- // Copy ctor - If you want to capture the node mapping between the source and
- // destination graph, you may optionally do this by specifying a map to record
- // this into.
- //
- // Note that a copied graph does not retain the GlobalsGraph pointer of the
- // source. You need to set a new GlobalsGraph with the setGlobalsGraph
- // method.
- //
- DSGraph(const DSGraph &DSG);
- DSGraph(const DSGraph &DSG, NodeMapTy &NodeMap);
- ~DSGraph();
-
- DSGraph *getGlobalsGraph() const { return GlobalsGraph; }
- void setGlobalsGraph(DSGraph *G) { GlobalsGraph = G; }
-
- // setPrintAuxCalls - If you call this method, the auxillary call vector will
- // be printed instead of the standard call vector to the dot file.
- //
- void setPrintAuxCalls() { PrintAuxCalls = true; }
- bool shouldPrintAuxCalls() const { return PrintAuxCalls; }
-
- /// getNodes - Get a vector of all the nodes in the graph
- ///
- const std::vector<DSNode*> &getNodes() const { return Nodes; }
- std::vector<DSNode*> &getNodes() { return Nodes; }
-
- /// getFunctionNames - Return a space separated list of the name of the
- /// functions in this graph (if any)
- std::string getFunctionNames() const;
-
- /// addNode - Add a new node to the graph.
- ///
- void addNode(DSNode *N) { Nodes.push_back(N); }
-
- /// getScalarMap - Get a map that describes what the nodes the scalars in this
- /// function point to...
- ///
- ScalarMapTy &getScalarMap() { return ScalarMap; }
- const ScalarMapTy &getScalarMap() const {return ScalarMap;}
-
- /// getFunctionCalls - Return the list of call sites in the original local
- /// graph...
- ///
- const std::vector<DSCallSite> &getFunctionCalls() const {
- return FunctionCalls;
- }
-
- /// getAuxFunctionCalls - Get the call sites as modified by whatever passes
- /// have been run.
- ///
- std::vector<DSCallSite> &getAuxFunctionCalls() {
- return AuxFunctionCalls;
- }
- const std::vector<DSCallSite> &getAuxFunctionCalls() const {
- return AuxFunctionCalls;
- }
-
- /// getInlinedGlobals - Get the set of globals that are have been inlined
- /// (from callees in BU or from callers in TD) into the current graph.
- ///
- GlobalSetTy& getInlinedGlobals() {
- return InlinedGlobals;
- }
-
- /// getNodeForValue - Given a value that is used or defined in the body of the
- /// current function, return the DSNode that it points to.
- ///
- DSNodeHandle &getNodeForValue(Value *V) { return ScalarMap[V]; }
-
- const DSNodeHandle &getNodeForValue(Value *V) const {
- ScalarMapTy::const_iterator I = ScalarMap.find(V);
- assert(I != ScalarMap.end() &&
- "Use non-const lookup function if node may not be in the map");
- return I->second;
- }
-
- /// getReturnNodes - Return the mapping of functions to their return nodes for
- /// this graph.
- const ReturnNodesTy &getReturnNodes() const { return ReturnNodes; }
- ReturnNodesTy &getReturnNodes() { return ReturnNodes; }
-
- /// getReturnNodeFor - Return the return node for the specified function.
- ///
- DSNodeHandle &getReturnNodeFor(Function &F) {
- ReturnNodesTy::iterator I = ReturnNodes.find(&F);
- assert(I != ReturnNodes.end() && "F not in this DSGraph!");
- return I->second;
- }
-
- const DSNodeHandle &getReturnNodeFor(Function &F) const {
- ReturnNodesTy::const_iterator I = ReturnNodes.find(&F);
- assert(I != ReturnNodes.end() && "F not in this DSGraph!");
- return I->second;
- }
-
- /// getGraphSize - Return the number of nodes in this graph.
- ///
- unsigned getGraphSize() const {
- return Nodes.size();
- }
-
- /// print - Print a dot graph to the specified ostream...
- ///
- void print(std::ostream &O) const;
-
- /// dump - call print(std::cerr), for use from the debugger...
- ///
- void dump() const;
-
- /// viewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
- /// then cleanup. For use from the debugger.
- void viewGraph() const;
-
- void writeGraphToFile(std::ostream &O, const std::string &GraphName) const;
-
- /// maskNodeTypes - Apply a mask to all of the node types in the graph. This
- /// is useful for clearing out markers like Incomplete.
- ///
- void maskNodeTypes(unsigned Mask) {
- for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
- Nodes[i]->maskNodeTypes(Mask);
- }
- void maskIncompleteMarkers() { maskNodeTypes(~DSNode::Incomplete); }
-
- // markIncompleteNodes - Traverse the graph, identifying nodes that may be
- // modified by other functions that have not been resolved yet. This marks
- // nodes that are reachable through three sources of "unknownness":
- // Global Variables, Function Calls, and Incoming Arguments
- //
- // For any node that may have unknown components (because something outside
- // the scope of current analysis may have modified it), the 'Incomplete' flag
- // is added to the NodeType.
- //
- enum MarkIncompleteFlags {
- MarkFormalArgs = 1, IgnoreFormalArgs = 0,
- IgnoreGlobals = 2, MarkGlobalsIncomplete = 0,
- };
- void markIncompleteNodes(unsigned Flags);
-
- // removeDeadNodes - Use a reachability analysis to eliminate subgraphs that
- // are unreachable. This often occurs because the data structure doesn't
- // "escape" into it's caller, and thus should be eliminated from the caller's
- // graph entirely. This is only appropriate to use when inlining graphs.
- //
- enum RemoveDeadNodesFlags {
- RemoveUnreachableGlobals = 1, KeepUnreachableGlobals = 0,
- };
- void removeDeadNodes(unsigned Flags);
-
- /// CloneFlags enum - Bits that may be passed into the cloneInto method to
- /// specify how to clone the function graph.
- enum CloneFlags {
- StripAllocaBit = 1 << 0, KeepAllocaBit = 0,
- DontCloneCallNodes = 1 << 1, CloneCallNodes = 0,
- DontCloneAuxCallNodes = 1 << 2, CloneAuxCallNodes = 0,
- StripModRefBits = 1 << 3, KeepModRefBits = 0,
- StripIncompleteBit = 1 << 4, KeepIncompleteBit = 0,
- };
-
-private:
- void cloneReachableNodes(const DSNode* Node,
- unsigned BitsToClear,
- NodeMapTy& OldNodeMap,
- NodeMapTy& CompletedNodeMap);
-
-public:
- void updateFromGlobalGraph();
-
- void cloneReachableSubgraph(const DSGraph& G,
- const hash_set<const DSNode*>& RootNodes,
- NodeMapTy& OldNodeMap,
- NodeMapTy& CompletedNodeMap,
- unsigned CloneFlags = 0);
-
- /// cloneInto - Clone the specified DSGraph into the current graph. The
- /// translated ScalarMap for the old function is filled into the OldValMap
- /// member, and the translated ReturnNodes map is returned into ReturnNodes.
- ///
- /// The CloneFlags member controls various aspects of the cloning process.
- ///
- void cloneInto(const DSGraph &G, ScalarMapTy &OldValMap,
- ReturnNodesTy &OldReturnNodes, NodeMapTy &OldNodeMap,
- unsigned CloneFlags = 0);
-
- /// mergeInGraph - The method is used for merging graphs together. If the
- /// argument graph is not *this, it makes a clone of the specified graph, then
- /// merges the nodes specified in the call site with the formal arguments in
- /// the graph. If the StripAlloca's argument is 'StripAllocaBit' then Alloca
- /// markers are removed from nodes.
- ///
- void mergeInGraph(const DSCallSite &CS, Function &F, const DSGraph &Graph,
- unsigned CloneFlags);
-
-
- /// getCallSiteForArguments - Get the arguments and return value bindings for
- /// the specified function in the current graph.
- ///
- DSCallSite getCallSiteForArguments(Function &F) const;
-
- // Methods for checking to make sure graphs are well formed...
- void AssertNodeInGraph(const DSNode *N) const {
- assert((!N || find(Nodes.begin(), Nodes.end(), N) != Nodes.end()) &&
- "AssertNodeInGraph: Node is not in graph!");
- }
- void AssertNodeContainsGlobal(const DSNode *N, GlobalValue *GV) const {
- assert(std::find(N->getGlobals().begin(), N->getGlobals().end(), GV) !=
- N->getGlobals().end() && "Global value not in node!");
- }
-
- void AssertCallSiteInGraph(const DSCallSite &CS) const {
- if (CS.isIndirectCall())
- AssertNodeInGraph(CS.getCalleeNode());
- AssertNodeInGraph(CS.getRetVal().getNode());
- for (unsigned j = 0, e = CS.getNumPtrArgs(); j != e; ++j)
- AssertNodeInGraph(CS.getPtrArg(j).getNode());
- }
-
- void AssertCallNodesInGraph() const {
- for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
- AssertCallSiteInGraph(FunctionCalls[i]);
- }
- void AssertAuxCallNodesInGraph() const {
- for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
- AssertCallSiteInGraph(AuxFunctionCalls[i]);
- }
-
- void AssertGraphOK() const;
-
- /// mergeInGlobalsGraph - This method is useful for clients to incorporate the
- /// globals graph into the DS, BU or TD graph for a function. This code
- /// retains all globals, i.e., does not delete unreachable globals after they
- /// are inlined.
- ///
- void mergeInGlobalsGraph();
-
- /// removeTriviallyDeadNodes - After the graph has been constructed, this
- /// method removes all unreachable nodes that are created because they got
- /// merged with other nodes in the graph. This is used as the first step of
- /// removeDeadNodes.
- ///
- void removeTriviallyDeadNodes();
-};
-
-#endif
diff --git a/poolalloc/include/dsa/DSGraphTraits.h b/poolalloc/include/dsa/DSGraphTraits.h
deleted file mode 100644
index 7ea30c0..0000000
--- a/poolalloc/include/dsa/DSGraphTraits.h
+++ /dev/null
@@ -1,142 +0,0 @@
-//===- DSGraphTraits.h - Provide generic graph interface --------*- C++ -*-===//
-//
-// This file provides GraphTraits specializations for the DataStructure graph
-// nodes, allowing datastructure graphs to be processed by generic graph
-// algorithms.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_ANALYSIS_DSGRAPHTRAITS_H
-#define LLVM_ANALYSIS_DSGRAPHTRAITS_H
-
-#include "llvm/Analysis/DSGraph.h"
-#include "Support/GraphTraits.h"
-#include "Support/iterator"
-#include "Support/STLExtras.h"
-
-template<typename NodeTy>
-class DSNodeIterator : public forward_iterator<const DSNode, ptrdiff_t> {
- friend class DSNode;
- NodeTy * const Node;
- unsigned Offset;
-
- typedef DSNodeIterator<NodeTy> _Self;
-
- DSNodeIterator(NodeTy *N) : Node(N), Offset(0) {} // begin iterator
- DSNodeIterator(NodeTy *N, bool) : Node(N) { // Create end iterator
- Offset = N->getNumLinks() << DS::PointerShift;
- if (Offset == 0 && Node->getForwardNode() &&
- Node->isDeadNode()) // Model Forward link
- Offset += DS::PointerSize;
- }
-public:
- DSNodeIterator(const DSNodeHandle &NH)
- : Node(NH.getNode()), Offset(NH.getOffset()) {}
-
- bool operator==(const _Self& x) const {
- return Offset == x.Offset;
- }
- bool operator!=(const _Self& x) const { return !operator==(x); }
-
- const _Self &operator=(const _Self &I) {
- assert(I.Node == Node && "Cannot assign iterators to two different nodes!");
- Offset = I.Offset;
- return *this;
- }
-
- pointer operator*() const {
- if (Node->isDeadNode())
- return Node->getForwardNode();
- else
- return Node->getLink(Offset).getNode();
- }
- pointer operator->() const { return operator*(); }
-
- _Self& operator++() { // Preincrement
- Offset += (1 << DS::PointerShift);
- return *this;
- }
- _Self operator++(int) { // Postincrement
- _Self tmp = *this; ++*this; return tmp;
- }
-
- unsigned getOffset() const { return Offset; }
- const DSNode *getNode() const { return Node; }
-};
-
-// Provide iterators for DSNode...
-inline DSNode::iterator DSNode::begin() {
- return DSNode::iterator(this);
-}
-inline DSNode::iterator DSNode::end() {
- return DSNode::iterator(this, false);
-}
-inline DSNode::const_iterator DSNode::begin() const {
- return DSNode::const_iterator(this);
-}
-inline DSNode::const_iterator DSNode::end() const {
- return DSNode::const_iterator(this, false);
-}
-
-template <> struct GraphTraits<DSNode*> {
- typedef DSNode NodeType;
- typedef DSNode::iterator ChildIteratorType;
-
- static NodeType *getEntryNode(NodeType *N) { return N; }
- static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
- static ChildIteratorType child_end(NodeType *N) { return N->end(); }
-};
-
-template <> struct GraphTraits<const DSNode*> {
- typedef const DSNode NodeType;
- typedef DSNode::const_iterator ChildIteratorType;
-
- static NodeType *getEntryNode(NodeType *N) { return N; }
- static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
- static ChildIteratorType child_end(NodeType *N) { return N->end(); }
-};
-
-static DSNode &dereference ( DSNode *N) { return *N; }
-static const DSNode &dereferenceC(const DSNode *N) { return *N; }
-
-template <> struct GraphTraits<DSGraph*> {
- typedef DSNode NodeType;
- typedef DSNode::iterator ChildIteratorType;
-
- typedef std::pointer_to_unary_function<DSNode *, DSNode&> DerefFun;
-
- // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
- typedef mapped_iterator<std::vector<DSNode*>::iterator,
- DerefFun> nodes_iterator;
- static nodes_iterator nodes_begin(DSGraph *G) {
- return map_iterator(G->getNodes().begin(), DerefFun(dereference));
- }
- static nodes_iterator nodes_end(DSGraph *G) {
- return map_iterator(G->getNodes().end(), DerefFun(dereference));
- }
-
- static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
- static ChildIteratorType child_end(NodeType *N) { return N->end(); }
-};
-
-template <> struct GraphTraits<const DSGraph*> {
- typedef const DSNode NodeType;
- typedef DSNode::const_iterator ChildIteratorType;
-
- typedef std::pointer_to_unary_function<const DSNode *,const DSNode&> DerefFun;
-
- // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
- typedef mapped_iterator<std::vector<DSNode*>::const_iterator,
- DerefFun> nodes_iterator;
- static nodes_iterator nodes_begin(const DSGraph *G) {
- return map_iterator(G->getNodes().begin(), DerefFun(dereferenceC));
- }
- static nodes_iterator nodes_end(const DSGraph *G) {
- return map_iterator(G->getNodes().end(), DerefFun(dereferenceC));
- }
-
- static ChildIteratorType child_begin(const NodeType *N) { return N->begin(); }
- static ChildIteratorType child_end(const NodeType *N) { return N->end(); }
-};
-
-#endif
diff --git a/poolalloc/include/dsa/DSNode.h b/poolalloc/include/dsa/DSNode.h
deleted file mode 100644
index ff1d7d6..0000000
--- a/poolalloc/include/dsa/DSNode.h
+++ /dev/null
@@ -1,372 +0,0 @@
-//===- DSNode.h - Node definition for datastructure graphs ------*- C++ -*-===//
-//
-// Data structure graph nodes and some implementation of DSNodeHandle.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_ANALYSIS_DSNODE_H
-#define LLVM_ANALYSIS_DSNODE_H
-
-#include "llvm/Analysis/DSSupport.h"
-
-template<typename BaseType>
-class DSNodeIterator; // Data structure graph traversal iterator
-
-//===----------------------------------------------------------------------===//
-/// DSNode - Data structure node class
-///
-/// This class represents an untyped memory object of Size bytes. It keeps
-/// track of any pointers that have been stored into the object as well as the
-/// different types represented in this object.
-///
-class DSNode {
- /// NumReferrers - The number of DSNodeHandles pointing to this node... if
- /// this is a forwarding node, then this is the number of node handles which
- /// are still forwarding over us.
- ///
- unsigned NumReferrers;
-
- /// ForwardNH - This NodeHandle contain the node (and offset into the node)
- /// that this node really is. When nodes get folded together, the node to be
- /// eliminated has these fields filled in, otherwise ForwardNH.getNode() is
- /// null.
- DSNodeHandle ForwardNH;
-
- /// Size - The current size of the node. This should be equal to the size of
- /// the current type record.
- ///
- unsigned Size;
-
- /// ParentGraph - The graph this node is currently embedded into.
- ///
- DSGraph *ParentGraph;
-
- /// Ty - Keep track of the current outer most type of this object, in addition
- /// to whether or not it has been indexed like an array or not. If the
- /// isArray bit is set, the node cannot grow.
- ///
- const Type *Ty; // The type itself...
-
- /// Links - Contains one entry for every sizeof(void*) bytes in this memory
- /// object. Note that if the node is not a multiple of size(void*) bytes
- /// large, that there is an extra entry for the "remainder" of the node as
- /// well. For this reason, nodes of 1 byte in size do have one link.
- ///
- std::vector<DSNodeHandle> Links;
-
- /// Globals - The list of global values that are merged into this node.
- ///
- std::vector<GlobalValue*> Globals;
-
- void operator=(const DSNode &); // DO NOT IMPLEMENT
- DSNode(const DSNode &); // DO NOT IMPLEMENT
-public:
- enum NodeTy {
- ShadowNode = 0, // Nothing is known about this node...
- AllocaNode = 1 << 0, // This node was allocated with alloca
- HeapNode = 1 << 1, // This node was allocated with malloc
- GlobalNode = 1 << 2, // This node was allocated by a global var decl
- UnknownNode = 1 << 3, // This node points to unknown allocated memory
- Incomplete = 1 << 4, // This node may not be complete
-
- Modified = 1 << 5, // This node is modified in this context
- Read = 1 << 6, // This node is read in this context
-
- Array = 1 << 7, // This node is treated like an array
- //#ifndef NDEBUG
- DEAD = 1 << 8, // This node is dead and should not be pointed to
- //#endif
-
- Composition = AllocaNode | HeapNode | GlobalNode | UnknownNode,
- };
-
- /// NodeType - A union of the above bits. "Shadow" nodes do not add any flags
- /// to the nodes in the data structure graph, so it is possible to have nodes
- /// with a value of 0 for their NodeType.
- ///
-private:
- unsigned short NodeType;
-public:
-
- DSNode(const Type *T, DSGraph *G);
- DSNode(const DSNode &, DSGraph *G);
-
- ~DSNode() {
- dropAllReferences();
- assert(hasNoReferrers() && "Referrers to dead node exist!");
- }
-
- // Iterator for graph interface... Defined in DSGraphTraits.h
- typedef DSNodeIterator<DSNode> iterator;
- typedef DSNodeIterator<const DSNode> const_iterator;
- inline iterator begin();
- inline iterator end();
- inline const_iterator begin() const;
- inline const_iterator end() const;
-
- //===--------------------------------------------------
- // Accessors
-
- /// getSize - Return the maximum number of bytes occupied by this object...
- ///
- unsigned getSize() const { return Size; }
-
- // getType - Return the node type of this object...
- const Type *getType() const { return Ty; }
- bool isArray() const { return NodeType & Array; }
-
- /// hasNoReferrers - Return true if nothing is pointing to this node at all.
- ///
- bool hasNoReferrers() const { return getNumReferrers() == 0; }
-
- /// getNumReferrers - This method returns the number of referrers to the
- /// current node. Note that if this node is a forwarding node, this will
- /// return the number of nodes forwarding over the node!
- unsigned getNumReferrers() const { return NumReferrers; }
-
- DSGraph *getParentGraph() const { return ParentGraph; }
- void setParentGraph(DSGraph *G) { ParentGraph = G; }
-
- /// getForwardNode - This method returns the node that this node is forwarded
- /// to, if any.
- DSNode *getForwardNode() const { return ForwardNH.getNode(); }
- void stopForwarding() {
- assert(!ForwardNH.isNull() &&
- "Node isn't forwarding, cannot stopForwarding!");
- ForwardNH.setNode(0);
- }
-
- /// hasLink - Return true if this memory object has a link in slot #LinkNo
- ///
- bool hasLink(unsigned Offset) const {
- assert((Offset & ((1 << DS::PointerShift)-1)) == 0 &&
- "Pointer offset not aligned correctly!");
- unsigned Index = Offset >> DS::PointerShift;
- assert(Index < Links.size() && "Link index is out of range!");
- return Links[Index].getNode();
- }
-
- /// getLink - Return the link at the specified offset.
- DSNodeHandle &getLink(unsigned Offset) {
- assert((Offset & ((1 << DS::PointerShift)-1)) == 0 &&
- "Pointer offset not aligned correctly!");
- unsigned Index = Offset >> DS::PointerShift;
- assert(Index < Links.size() && "Link index is out of range!");
- return Links[Index];
- }
- const DSNodeHandle &getLink(unsigned Offset) const {
- assert((Offset & ((1 << DS::PointerShift)-1)) == 0 &&
- "Pointer offset not aligned correctly!");
- unsigned Index = Offset >> DS::PointerShift;
- assert(Index < Links.size() && "Link index is out of range!");
- return Links[Index];
- }
-
- /// getNumLinks - Return the number of links in a node...
- ///
- unsigned getNumLinks() const { return Links.size(); }
-
- /// mergeTypeInfo - This method merges the specified type into the current
- /// node at the specified offset. This may update the current node's type
- /// record if this gives more information to the node, it may do nothing to
- /// the node if this information is already known, or it may merge the node
- /// completely (and return true) if the information is incompatible with what
- /// is already known.
- ///
- /// This method returns true if the node is completely folded, otherwise
- /// false.
- ///
- bool mergeTypeInfo(const Type *Ty, unsigned Offset,
- bool FoldIfIncompatible = true);
-
- /// foldNodeCompletely - If we determine that this node has some funny
- /// behavior happening to it that we cannot represent, we fold it down to a
- /// single, completely pessimistic, node. This node is represented as a
- /// single byte with a single TypeEntry of "void" with isArray = true.
- ///
- void foldNodeCompletely();
-
- /// isNodeCompletelyFolded - Return true if this node has been completely
- /// folded down to something that can never be expanded, effectively losing
- /// all of the field sensitivity that may be present in the node.
- ///
- bool isNodeCompletelyFolded() const;
-
- /// setLink - Set the link at the specified offset to the specified
- /// NodeHandle, replacing what was there. It is uncommon to use this method,
- /// instead one of the higher level methods should be used, below.
- ///
- void setLink(unsigned Offset, const DSNodeHandle &NH) {
- assert((Offset & ((1 << DS::PointerShift)-1)) == 0 &&
- "Pointer offset not aligned correctly!");
- unsigned Index = Offset >> DS::PointerShift;
- assert(Index < Links.size() && "Link index is out of range!");
- Links[Index] = NH;
- }
-
- /// getPointerSize - Return the size of a pointer for the current target.
- ///
- unsigned getPointerSize() const { return DS::PointerSize; }
-
- /// addEdgeTo - Add an edge from the current node to the specified node. This
- /// can cause merging of nodes in the graph.
- ///
- void addEdgeTo(unsigned Offset, const DSNodeHandle &NH);
-
- /// mergeWith - Merge this node and the specified node, moving all links to
- /// and from the argument node into the current node, deleting the node
- /// argument. Offset indicates what offset the specified node is to be merged
- /// into the current node.
- ///
- /// The specified node may be a null pointer (in which case, nothing happens).
- ///
- void mergeWith(const DSNodeHandle &NH, unsigned Offset);
-
- /// addGlobal - Add an entry for a global value to the Globals list. This
- /// also marks the node with the 'G' flag if it does not already have it.
- ///
- void addGlobal(GlobalValue *GV);
- const std::vector<GlobalValue*> &getGlobals() const { return Globals; }
-
- /// maskNodeTypes - Apply a mask to the node types bitfield.
- ///
- void maskNodeTypes(unsigned Mask) {
- NodeType &= Mask;
- }
-
- /// getNodeFlags - Return all of the flags set on the node. If the DEAD flag
- /// is set, hide it from the caller.
- unsigned getNodeFlags() const { return NodeType & ~DEAD; }
-
- bool isAllocaNode() const { return NodeType & AllocaNode; }
- bool isHeapNode() const { return NodeType & HeapNode; }
- bool isGlobalNode() const { return NodeType & GlobalNode; }
- bool isUnknownNode() const { return NodeType & UnknownNode; }
-
- bool isModified() const { return NodeType & Modified; }
- bool isRead() const { return NodeType & Read; }
-
- bool isIncomplete() const { return NodeType & Incomplete; }
- bool isComplete() const { return !isIncomplete(); }
- bool isDeadNode() const { return NodeType & DEAD; }
-
- DSNode *setAllocaNodeMarker() { NodeType |= AllocaNode; return this; }
- DSNode *setHeapNodeMarker() { NodeType |= HeapNode; return this; }
- DSNode *setGlobalNodeMarker() { NodeType |= GlobalNode; return this; }
- DSNode *setUnknownNodeMarker() { NodeType |= UnknownNode; return this; }
-
- DSNode *setIncompleteMarker() { NodeType |= Incomplete; return this; }
- DSNode *setModifiedMarker() { NodeType |= Modified; return this; }
- DSNode *setReadMarker() { NodeType |= Read; return this; }
-
- void makeNodeDead() {
- Globals.clear();
- assert(hasNoReferrers() && "Dead node shouldn't have refs!");
- NodeType = DEAD;
- }
-
- /// forwardNode - Mark this node as being obsolete, and all references to it
- /// should be forwarded to the specified node and offset.
- ///
- void forwardNode(DSNode *To, unsigned Offset);
-
- void print(std::ostream &O, const DSGraph *G) const;
- void dump() const;
-
- void assertOK() const;
-
- void dropAllReferences() {
- Links.clear();
- if (!ForwardNH.isNull())
- ForwardNH.setNode(0);
- }
-
- /// remapLinks - Change all of the Links in the current node according to the
- /// specified mapping.
- void remapLinks(hash_map<const DSNode*, DSNodeHandle> &OldNodeMap);
-
- /// markReachableNodes - This method recursively traverses the specified
- /// DSNodes, marking any nodes which are reachable. All reachable nodes it
- /// adds to the set, which allows it to only traverse visited nodes once.
- ///
- void markReachableNodes(hash_set<DSNode*> &ReachableNodes);
-
-private:
- friend class DSNodeHandle;
-
- // static mergeNodes - Helper for mergeWith()
- static void MergeNodes(DSNodeHandle& CurNodeH, DSNodeHandle& NH);
-};
-
-
-//===----------------------------------------------------------------------===//
-// Define inline DSNodeHandle functions that depend on the definition of DSNode
-//
-inline DSNode *DSNodeHandle::getNode() const {
- assert((!N || Offset < N->Size || (N->Size == 0 && Offset == 0) ||
- !N->ForwardNH.isNull()) && "Node handle offset out of range!");
- if (!N || N->ForwardNH.isNull())
- return N;
-
- return HandleForwarding();
-}
-
-inline void DSNodeHandle::setNode(DSNode *n) {
- assert(!n || !n->getForwardNode() && "Cannot set node to a forwarded node!");
- if (N) N->NumReferrers--;
- N = n;
- if (N) {
- N->NumReferrers++;
- if (Offset >= N->Size) {
- assert((Offset == 0 || N->Size == 1) &&
- "Pointer to non-collapsed node with invalid offset!");
- Offset = 0;
- }
- }
- assert(!N || ((N->NodeType & DSNode::DEAD) == 0));
- assert((!N || Offset < N->Size || (N->Size == 0 && Offset == 0) ||
- !N->ForwardNH.isNull()) && "Node handle offset out of range!");
-}
-
-inline bool DSNodeHandle::hasLink(unsigned Num) const {
- assert(N && "DSNodeHandle does not point to a node yet!");
- return getNode()->hasLink(Num+Offset);
-}
-
-
-/// getLink - Treat this current node pointer as a pointer to a structure of
-/// some sort. This method will return the pointer a mem[this+Num]
-///
-inline const DSNodeHandle &DSNodeHandle::getLink(unsigned Off) const {
- assert(N && "DSNodeHandle does not point to a node yet!");
- return getNode()->getLink(Offset+Off);
-}
-inline DSNodeHandle &DSNodeHandle::getLink(unsigned Off) {
- assert(N && "DSNodeHandle does not point to a node yet!");
- return getNode()->getLink(Off+Offset);
-}
-
-inline void DSNodeHandle::setLink(unsigned Off, const DSNodeHandle &NH) {
- assert(N && "DSNodeHandle does not point to a node yet!");
- getNode()->setLink(Off+Offset, NH);
-}
-
-/// addEdgeTo - Add an edge from the current node to the specified node. This
-/// can cause merging of nodes in the graph.
-///
-inline void DSNodeHandle::addEdgeTo(unsigned Off, const DSNodeHandle &Node) {
- assert(N && "DSNodeHandle does not point to a node yet!");
- getNode()->addEdgeTo(Off+Offset, Node);
-}
-
-/// mergeWith - Merge the logical node pointed to by 'this' with the node
-/// pointed to by 'N'.
-///
-inline void DSNodeHandle::mergeWith(const DSNodeHandle &Node) {
- if (N != 0)
- getNode()->mergeWith(Node, Offset);
- else // No node to merge with, so just point to Node
- *this = Node;
-}
-
-#endif
diff --git a/poolalloc/include/dsa/DSSupport.h b/poolalloc/include/dsa/DSSupport.h
deleted file mode 100644
index aff7abc..0000000
--- a/poolalloc/include/dsa/DSSupport.h
+++ /dev/null
@@ -1,288 +0,0 @@
-//===- DSSupport.h - Support for datastructure graphs -----------*- C++ -*-===//
-//
-// Support for graph nodes, call sites, and types.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_ANALYSIS_DSSUPPORT_H
-#define LLVM_ANALYSIS_DSSUPPORT_H
-
-#include <vector>
-#include <functional>
-#include <string>
-#include <cassert>
-#include "Support/hash_set"
-
-class Function;
-class CallInst;
-class Value;
-class GlobalValue;
-class Type;
-
-class DSNode; // Each node in the graph
-class DSGraph; // A graph for a function
-
-namespace DS { // FIXME: After the paper, this should get cleaned up
- enum { PointerShift = 3, // 64bit ptrs = 3, 32 bit ptrs = 2
- PointerSize = 1 << PointerShift
- };
-
- // isPointerType - Return true if this first class type is big enough to hold
- // a pointer.
- //
- bool isPointerType(const Type *Ty);
-};
-
-//===----------------------------------------------------------------------===//
-/// DSNodeHandle - Implement a "handle" to a data structure node that takes care
-/// of all of the add/un'refing of the node to prevent the backpointers in the
-/// graph from getting out of date. This class represents a "pointer" in the
-/// graph, whose destination is an indexed offset into a node.
-///
-/// Note: some functions that are marked as inline in DSNodeHandle are actually
-/// defined in DSNode.h because they need knowledge of DSNode operation. Putting
-/// them in a CPP file wouldn't help making them inlined and keeping DSNode and
-/// DSNodeHandle (and friends) in one file complicates things.
-///
-class DSNodeHandle {
- mutable DSNode *N;
- mutable unsigned Offset;
- void operator==(const DSNode *N); // DISALLOW, use to promote N to nodehandle
-public:
- // Allow construction, destruction, and assignment...
- DSNodeHandle(DSNode *n = 0, unsigned offs = 0) : N(0), Offset(offs) {
- setNode(n);
- }
- DSNodeHandle(const DSNodeHandle &H) : N(0), Offset(0) {
- setNode(H.getNode());
- Offset = H.Offset; // Must read offset AFTER the getNode()
- }
- ~DSNodeHandle() { setNode((DSNode*)0); }
- DSNodeHandle &operator=(const DSNodeHandle &H) {
- if (&H == this) return *this; // Don't set offset to 0 if self assigning.
- Offset = 0; setNode(H.getNode()); Offset = H.Offset;
- return *this;
- }
-
- bool operator<(const DSNodeHandle &H) const { // Allow sorting
- return getNode() < H.getNode() || (N == H.N && Offset < H.Offset);
- }
- bool operator>(const DSNodeHandle &H) const { return H < *this; }
- bool operator==(const DSNodeHandle &H) const { // Allow comparison
- return getNode() == H.getNode() && Offset == H.Offset;
- }
- bool operator!=(const DSNodeHandle &H) const { return !operator==(H); }
-
- inline void swap(DSNodeHandle &NH) {
- std::swap(Offset, NH.Offset);
- std::swap(N, NH.N);
- }
-
- /// isNull - Check to see if getNode() == 0, without going through the trouble
- /// of checking to see if we are forwarding...
- bool isNull() const { return N == 0; }
-
- // Allow explicit conversion to DSNode...
- inline DSNode *getNode() const; // Defined inline in DSNode.h
- unsigned getOffset() const { return Offset; }
-
- inline void setNode(DSNode *N); // Defined inline in DSNode.h
- void setOffset(unsigned O) {
- //assert((!N || Offset < N->Size || (N->Size == 0 && Offset == 0) ||
- // !N->ForwardNH.isNull()) && "Node handle offset out of range!");
- //assert((!N || O < N->Size || (N->Size == 0 && O == 0) ||
- // !N->ForwardNH.isNull()) && "Node handle offset out of range!");
- Offset = O;
- }
-
- void addEdgeTo(unsigned LinkNo, const DSNodeHandle &N);
- void addEdgeTo(const DSNodeHandle &N) { addEdgeTo(0, N); }
-
- /// mergeWith - Merge the logical node pointed to by 'this' with the node
- /// pointed to by 'N'.
- ///
- void mergeWith(const DSNodeHandle &N);
-
- // hasLink - Return true if there is a link at the specified offset...
- inline bool hasLink(unsigned Num) const;
-
- /// getLink - Treat this current node pointer as a pointer to a structure of
- /// some sort. This method will return the pointer a mem[this+Num]
- ///
- inline const DSNodeHandle &getLink(unsigned Num) const;
- inline DSNodeHandle &getLink(unsigned Num);
-
- inline void setLink(unsigned Num, const DSNodeHandle &NH);
-private:
- DSNode *HandleForwarding() const;
-};
-
-namespace std {
- inline void swap(DSNodeHandle &NH1, DSNodeHandle &NH2) { NH1.swap(NH2); }
-}
-
-//===----------------------------------------------------------------------===//
-/// 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.
-///
-class DSCallSite {
- CallInst *Inst; // Actual call site
- Function *CalleeF; // The function called (direct call)
- DSNodeHandle CalleeN; // The function node called (indirect call)
- DSNodeHandle RetVal; // Returned value
- std::vector<DSNodeHandle> CallArgs;// The pointer arguments
-
- static void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src,
- const hash_map<const DSNode*, DSNode*> &NodeMap) {
- if (DSNode *N = Src.getNode()) {
- hash_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 void InitNH(DSNodeHandle &NH, const DSNodeHandle &Src,
- const hash_map<const DSNode*, DSNodeHandle> &NodeMap) {
- if (DSNode *N = Src.getNode()) {
- hash_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
-public:
- /// Constructor. Note - This ctor destroys the argument vector passed in. On
- /// exit, the argument vector is empty.
- ///
- DSCallSite(CallInst &inst, const DSNodeHandle &rv, DSNode *Callee,
- std::vector<DSNodeHandle> &Args)
- : Inst(&inst), CalleeF(0), CalleeN(Callee), RetVal(rv) {
- assert(Callee && "Null callee node specified for call site!");
- Args.swap(CallArgs);
- }
- DSCallSite(CallInst &inst, const DSNodeHandle &rv, Function *Callee,
- std::vector<DSNodeHandle> &Args)
- : Inst(&inst), CalleeF(Callee), RetVal(rv) {
- assert(Callee && "Null callee function specified for call site!");
- Args.swap(CallArgs);
- }
-
- DSCallSite(const DSCallSite &DSCS) // Simple copy ctor
- : Inst(DSCS.Inst), CalleeF(DSCS.CalleeF), CalleeN(DSCS.CalleeN),
- RetVal(DSCS.RetVal), 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.
- /// This is useful when moving a call site from one graph to another.
- ///
- template<typename MapTy>
- DSCallSite(const DSCallSite &FromCall, const MapTy &NodeMap) {
- Inst = FromCall.Inst;
- InitNH(RetVal, FromCall.RetVal, NodeMap);
- InitNH(CalleeN, FromCall.CalleeN, NodeMap);
- CalleeF = FromCall.CalleeF;
-
- CallArgs.resize(FromCall.CallArgs.size());
- for (unsigned i = 0, e = FromCall.CallArgs.size(); i != e; ++i)
- InitNH(CallArgs[i], FromCall.CallArgs[i], NodeMap);
- }
-
- const DSCallSite &operator=(const DSCallSite &RHS) {
- Inst = RHS.Inst;
- CalleeF = RHS.CalleeF;
- CalleeN = RHS.CalleeN;
- RetVal = RHS.RetVal;
- CallArgs = RHS.CallArgs;
- return *this;
- }
-
- /// isDirectCall - Return true if this call site is a direct call of the
- /// function specified by getCalleeFunc. If not, it is an indirect call to
- /// the node specified by getCalleeNode.
- ///
- bool isDirectCall() const { return CalleeF != 0; }
- bool isIndirectCall() const { return !isDirectCall(); }
-
-
- // Accessor functions...
- Function &getCaller() const;
- CallInst &getCallInst() const { return *Inst; }
- DSNodeHandle &getRetVal() { return RetVal; }
- const DSNodeHandle &getRetVal() const { return RetVal; }
-
- DSNode *getCalleeNode() const {
- assert(!CalleeF && CalleeN.getNode()); return CalleeN.getNode();
- }
- Function *getCalleeFunc() const {
- assert(!CalleeN.getNode() && CalleeF); return CalleeF;
- }
-
- unsigned getNumPtrArgs() const { return CallArgs.size(); }
-
- DSNodeHandle &getPtrArg(unsigned i) {
- assert(i < CallArgs.size() && "Argument to getPtrArgNode is out of range!");
- return CallArgs[i];
- }
- const DSNodeHandle &getPtrArg(unsigned i) const {
- assert(i < CallArgs.size() && "Argument to getPtrArgNode is out of range!");
- return CallArgs[i];
- }
-
- void swap(DSCallSite &CS) {
- if (this != &CS) {
- std::swap(Inst, CS.Inst);
- std::swap(RetVal, CS.RetVal);
- std::swap(CalleeN, CS.CalleeN);
- std::swap(CalleeF, CS.CalleeF);
- std::swap(CallArgs, CS.CallArgs);
- }
- }
-
- // MergeWith - Merge the return value and parameters of the these two call
- // sites.
- void mergeWith(DSCallSite &CS) {
- getRetVal().mergeWith(CS.getRetVal());
- unsigned MinArgs = getNumPtrArgs();
- if (CS.getNumPtrArgs() < MinArgs) MinArgs = CS.getNumPtrArgs();
-
- for (unsigned a = 0; a != MinArgs; ++a)
- getPtrArg(a).mergeWith(CS.getPtrArg(a));
- }
-
- /// markReachableNodes - This method recursively traverses the specified
- /// DSNodes, marking any nodes which are reachable. All reachable nodes it
- /// adds to the set, which allows it to only traverse visited nodes once.
- ///
- void markReachableNodes(hash_set<DSNode*> &Nodes);
-
- bool operator<(const DSCallSite &CS) const {
- if (isDirectCall()) { // This must sort by callee first!
- if (CS.isIndirectCall()) return true;
- if (CalleeF < CS.CalleeF) return true;
- if (CalleeF > CS.CalleeF) return false;
- } else {
- if (CS.isDirectCall()) return false;
- if (CalleeN < CS.CalleeN) return true;
- if (CalleeN > CS.CalleeN) return false;
- }
- if (RetVal < CS.RetVal) return true;
- if (RetVal > CS.RetVal) return false;
- return CallArgs < CS.CallArgs;
- }
-
- bool operator==(const DSCallSite &CS) const {
- return RetVal == CS.RetVal && CalleeN == CS.CalleeN &&
- CalleeF == CS.CalleeF && CallArgs == CS.CallArgs;
- }
-};
-
-namespace std {
- inline void swap(DSCallSite &CS1, DSCallSite &CS2) { CS1.swap(CS2); }
-}
-#endif
diff --git a/poolalloc/include/dsa/DataStructure.h b/poolalloc/include/dsa/DataStructure.h
deleted file mode 100644
index d8f30d2..0000000
--- a/poolalloc/include/dsa/DataStructure.h
+++ /dev/null
@@ -1,176 +0,0 @@
-//===- DataStructure.h - Build data structure graphs ------------*- C++ -*-===//
-//
-// Implement the LLVM data structure analysis library.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_ANALYSIS_DATA_STRUCTURE_H
-#define LLVM_ANALYSIS_DATA_STRUCTURE_H
-
-#include "llvm/Pass.h"
-#include "Support/hash_set"
-
-class Type;
-class CallInst;
-class DSGraph;
-class DSNode;
-class DSCallSite;
-
-// FIXME: move this stuff to a private header
-namespace DataStructureAnalysis {
- // isPointerType - Return true if this first class type is big enough to hold
- // a pointer.
- //
- bool isPointerType(const Type *Ty);
-}
-
-
-// LocalDataStructures - The analysis that computes the local data structure
-// graphs for all of the functions in the program.
-//
-// FIXME: This should be a Function pass that can be USED by a Pass, and would
-// be automatically preserved. Until we can do that, this is a Pass.
-//
-class LocalDataStructures : public Pass {
- // DSInfo, one graph for each function
- hash_map<Function*, DSGraph*> DSInfo;
- DSGraph *GlobalsGraph;
-public:
- ~LocalDataStructures() { releaseMemory(); }
-
- virtual bool run(Module &M);
-
- bool hasGraph(const Function &F) const {
- return DSInfo.find(const_cast<Function*>(&F)) != DSInfo.end();
- }
-
- // getDSGraph - Return the data structure graph for the specified function.
- DSGraph &getDSGraph(const Function &F) const {
- hash_map<Function*, DSGraph*>::const_iterator I =
- DSInfo.find(const_cast<Function*>(&F));
- assert(I != DSInfo.end() && "Function not in module!");
- return *I->second;
- }
-
- DSGraph &getGlobalsGraph() const { return *GlobalsGraph; }
-
- // print - Print out the analysis results...
- void print(std::ostream &O, const Module *M) const;
-
- // If the pass pipeline is done with this pass, we can release our memory...
- virtual void releaseMemory();
-
- // getAnalysisUsage - This obviously provides a data structure graph.
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.setPreservesAll();
- }
-};
-
-
-// BUDataStructures - The analysis that computes the interprocedurally closed
-// data structure graphs for all of the functions in the program. This pass
-// only performs a "Bottom Up" propagation (hence the name).
-//
-class BUDataStructures : public Pass {
- // DSInfo, one graph for each function
- hash_map<Function*, DSGraph*> DSInfo;
- DSGraph *GlobalsGraph;
- hash_multimap<CallInst*, Function*> ActualCallees;
-public:
- ~BUDataStructures() { releaseMemory(); }
-
- virtual bool run(Module &M);
-
- bool hasGraph(const Function &F) const {
- return DSInfo.find(const_cast<Function*>(&F)) != DSInfo.end();
- }
-
- // getDSGraph - Return the data structure graph for the specified function.
- DSGraph &getDSGraph(const Function &F) const {
- hash_map<Function*, DSGraph*>::const_iterator I =
- DSInfo.find(const_cast<Function*>(&F));
- assert(I != DSInfo.end() && "Function not in module!");
- return *I->second;
- }
-
- DSGraph &getGlobalsGraph() const { return *GlobalsGraph; }
-
- // print - Print out the analysis results...
- void print(std::ostream &O, const Module *M) const;
-
- // If the pass pipeline is done with this pass, we can release our memory...
- virtual void releaseMemory();
-
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.setPreservesAll();
- AU.addRequired<LocalDataStructures>();
- }
-
- typedef hash_multimap<CallInst*, Function*> ActualCalleesTy;
- const ActualCalleesTy &getActualCallees() const {
- return ActualCallees;
- }
-
-private:
- void calculateGraph(DSGraph &G);
-
- void calculateReachableGraphs(Function *F);
-
-
- DSGraph &getOrCreateGraph(Function *F);
-
- unsigned calculateGraphs(Function *F, std::vector<Function*> &Stack,
- unsigned &NextID,
- hash_map<Function*, unsigned> &ValMap);
-};
-
-
-// TDDataStructures - Analysis that computes new data structure graphs
-// for each function using the closed graphs for the callers computed
-// by the bottom-up pass.
-//
-class TDDataStructures : public Pass {
- // DSInfo, one graph for each function
- hash_map<Function*, DSGraph*> DSInfo;
- hash_set<Function*> ArgsRemainIncomplete;
- DSGraph *GlobalsGraph;
-public:
- ~TDDataStructures() { releaseMyMemory(); }
-
- virtual bool run(Module &M);
-
- bool hasGraph(const Function &F) const {
- return DSInfo.find(const_cast<Function*>(&F)) != DSInfo.end();
- }
-
- // getDSGraph - Return the data structure graph for the specified function.
- DSGraph &getDSGraph(const Function &F) const {
- hash_map<Function*, DSGraph*>::const_iterator I =
- DSInfo.find(const_cast<Function*>(&F));
- assert(I != DSInfo.end() && "Function not in module!");
- return *I->second;
- }
-
- DSGraph &getGlobalsGraph() const { return *GlobalsGraph; }
-
- // print - Print out the analysis results...
- void print(std::ostream &O, const Module *M) const;
-
- // If the pass pipeline is done with this pass, we can release our memory...
- virtual void releaseMyMemory();
-
- // getAnalysisUsage - This obviously provides a data structure graph.
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.setPreservesAll();
- AU.addRequired<BUDataStructures>();
- }
-
-private:
- void inlineGraphIntoCallees(DSGraph &G);
- DSGraph &getOrCreateDSGraph(Function &F);
- void ComputePostOrder(Function &F, hash_set<DSGraph*> &Visited,
- std::vector<DSGraph*> &PostOrder,
- const BUDataStructures::ActualCalleesTy &ActualCallees);
-};
-
-#endif
diff --git a/poolalloc/include/poolalloc/PoolAllocate.h b/poolalloc/include/poolalloc/PoolAllocate.h
deleted file mode 100644
index b6806c1..0000000
--- a/poolalloc/include/poolalloc/PoolAllocate.h
+++ /dev/null
@@ -1,156 +0,0 @@
-//===-- PoolAllocate.h - Pool allocation pass -------------------*- C++ -*-===//
-//
-// This transform changes programs so that disjoint data structures are
-// allocated out of different pools of memory, increasing locality. This header
-// file exposes information about the pool allocation itself so that follow-on
-// passes may extend or use the pool allocation for analysis.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TRANSFORMS_POOLALLOCATE_H
-#define LLVM_TRANSFORMS_POOLALLOCATE_H
-
-#include "llvm/Pass.h"
-#include "Support/hash_set"
-#include "Support/EquivalenceClasses.h"
-class BUDataStructures;
-class TDDataStructures;
-class DSNode;
-class DSGraph;
-class CallInst;
-
-namespace PA {
- /// FuncInfo - Represent the pool allocation information for one function in
- /// the program. Note that many functions must actually be cloned in order
- /// for pool allocation to add arguments to the function signature. In this
- /// case, the Clone and NewToOldValueMap information identify how the clone
- /// maps to the original function...
- ///
- struct FuncInfo {
- /// MarkedNodes - The set of nodes which are not locally pool allocatable in
- /// the current function.
- ///
- hash_set<DSNode*> MarkedNodes;
-
- /// Clone - The cloned version of the function, if applicable.
- Function *Clone;
-
- /// ArgNodes - The list of DSNodes which have pools passed in as arguments.
- ///
- std::vector<DSNode*> ArgNodes;
-
- /// In order to handle indirect functions, the start and end of the
- /// arguments that are useful to this function.
- /// The pool arguments useful to this function are PoolArgFirst to
- /// PoolArgLast not inclusive.
- int PoolArgFirst, PoolArgLast;
-
- /// PoolDescriptors - The Value* (either an argument or an alloca) which
- /// defines the pool descriptor for this DSNode. Pools are mapped one to
- /// one with nodes in the DSGraph, so this contains a pointer to the node it
- /// corresponds to. In addition, the pool is initialized by calling the
- /// "poolinit" library function with a chunk of memory allocated with an
- /// alloca instruction. This entry contains a pointer to that alloca if the
- /// pool is locally allocated or the argument it is passed in through if
- /// not.
- /// Note: Does not include pool arguments that are passed in because of
- /// indirect function calls that are not used in the function.
- std::map<DSNode*, Value*> PoolDescriptors;
-
- /// NewToOldValueMap - When and if a function needs to be cloned, this map
- /// contains a mapping from all of the values in the new function back to
- /// the values they correspond to in the old function.
- ///
- std::map<Value*, const Value*> NewToOldValueMap;
- };
-}
-
-/// PoolAllocate - The main pool allocation pass
-///
-class PoolAllocate : public Pass {
- Module *CurModule;
- BUDataStructures *BU;
-
- TDDataStructures *TDDS;
-
- hash_set<Function*> InlinedFuncs;
-
- std::map<Function*, PA::FuncInfo> FunctionInfo;
-
- void buildIndirectFunctionSets(Module &M);
-
- void FindFunctionPoolArgs(Function &F);
-
- // Debug function to print the FuncECs
- void printFuncECs();
-
- public:
- Function *PoolInit, *PoolDestroy, *PoolAlloc, *PoolAllocArray, *PoolFree;
-
- // Equivalence class where functions that can potentially be called via
- // the same function pointer are in the same class.
- EquivalenceClasses<Function *> FuncECs;
-
- // Map from an Indirect CallInst to the set of Functions that it can point to
- std::multimap<CallInst *, Function *> CallInstTargets;
-
- // This maps an equivalence class to the last pool argument number for that
- // class. This is used because the pool arguments for all functions within
- // an equivalence class is passed to all the functions in that class.
- // If an equivalence class does not require pool arguments, it is not
- // on this map.
- std::map<Function *, int> EqClass2LastPoolArg;
-
- // Exception flags
- // CollapseFlag set if all data structures are not pool allocated, due to
- // collapsing of nodes in the DS graph
- unsigned CollapseFlag;
-
- public:
- bool run(Module &M);
-
- virtual void getAnalysisUsage(AnalysisUsage &AU) const;
-
- BUDataStructures &getBUDataStructures() const { return *BU; }
-
- PA::FuncInfo *getFuncInfo(Function &F) {
- std::map<Function*, PA::FuncInfo>::iterator I = FunctionInfo.find(&F);
- return I != FunctionInfo.end() ? &I->second : 0;
- }
-
- Module *getCurModule() { return CurModule; }
-
- private:
-
- /// AddPoolPrototypes - Add prototypes for the pool functions to the
- /// specified module and update the Pool* instance variables to point to
- /// them.
- ///
- void AddPoolPrototypes();
-
- /// MakeFunctionClone - If the specified function needs to be modified for
- /// pool allocation support, make a clone of it, adding additional arguments
- /// as neccesary, and return it. If not, just return null.
- ///
- Function *MakeFunctionClone(Function &F);
-
- /// ProcessFunctionBody - Rewrite the body of a transformed function to use
- /// pool allocation where appropriate.
- ///
- void ProcessFunctionBody(Function &Old, Function &New);
-
- /// CreatePools - This creates the pool initialization and destruction code
- /// for the DSNodes specified by the NodesToPA list. This adds an entry to
- /// the PoolDescriptors map for each DSNode.
- ///
- void CreatePools(Function &F, const std::vector<DSNode*> &NodesToPA,
- std::map<DSNode*, Value*> &PoolDescriptors);
-
- void TransformFunctionBody(Function &F, Function &OldF,
- DSGraph &G, PA::FuncInfo &FI);
-
- void InlineIndirectCalls(Function &F, DSGraph &G,
- hash_set<Function*> &visited);
-};
-
-#endif
diff --git a/poolalloc/lib/DSA/BottomUpClosure.cpp b/poolalloc/lib/DSA/BottomUpClosure.cpp
deleted file mode 100644
index dd141f2..0000000
--- a/poolalloc/lib/DSA/BottomUpClosure.cpp
+++ /dev/null
@@ -1,302 +0,0 @@
-//===- BottomUpClosure.cpp - Compute bottom-up interprocedural closure ----===//
-//
-// This file implements the BUDataStructures class, which represents the
-// Bottom-Up Interprocedural closure of the data structure graph over the
-// program. This is useful for applications like pool allocation, but **not**
-// applications like alias analysis.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Module.h"
-#include "Support/Statistic.h"
-#include "Support/Debug.h"
-#include "DSCallSiteIterator.h"
-
-namespace {
- Statistic<> MaxSCC("budatastructure", "Maximum SCC Size in Call Graph");
- Statistic<> NumBUInlines("budatastructures", "Number of graphs inlined");
- Statistic<> NumCallEdges("budatastructures", "Number of 'actual' call edges");
-
- RegisterAnalysis<BUDataStructures>
- X("budatastructure", "Bottom-up Data Structure Analysis");
-}
-
-using namespace DS;
-
-// run - Calculate the bottom up data structure graphs for each function in the
-// program.
-//
-bool BUDataStructures::run(Module &M) {
- LocalDataStructures &LocalDSA = getAnalysis<LocalDataStructures>();
- GlobalsGraph = new DSGraph(LocalDSA.getGlobalsGraph());
- GlobalsGraph->setPrintAuxCalls();
-
- Function *MainFunc = M.getMainFunction();
- if (MainFunc)
- calculateReachableGraphs(MainFunc);
-
- // Calculate the graphs for any functions that are unreachable from main...
- for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
- if (!I->isExternal() && !DSInfo.count(I)) {
-#ifndef NDEBUG
- if (MainFunc)
- std::cerr << "*** Function unreachable from main: "
- << I->getName() << "\n";
-#endif
- calculateReachableGraphs(I); // Calculate all graphs...
- }
-
- NumCallEdges += ActualCallees.size();
- return false;
-}
-
-void BUDataStructures::calculateReachableGraphs(Function *F) {
- std::vector<Function*> Stack;
- hash_map<Function*, unsigned> ValMap;
- unsigned NextID = 1;
- calculateGraphs(F, Stack, NextID, ValMap);
-}
-
-DSGraph &BUDataStructures::getOrCreateGraph(Function *F) {
- // Has the graph already been created?
- DSGraph *&Graph = DSInfo[F];
- if (Graph) return *Graph;
-
- // Copy the local version into DSInfo...
- Graph = new DSGraph(getAnalysis<LocalDataStructures>().getDSGraph(*F));
-
- Graph->setGlobalsGraph(GlobalsGraph);
- Graph->setPrintAuxCalls();
-
- // Start with a copy of the original call sites...
- Graph->getAuxFunctionCalls() = Graph->getFunctionCalls();
- return *Graph;
-}
-
-unsigned BUDataStructures::calculateGraphs(Function *F,
- std::vector<Function*> &Stack,
- unsigned &NextID,
- hash_map<Function*, unsigned> &ValMap) {
- assert(ValMap.find(F) == ValMap.end() && "Shouldn't revisit functions!");
- unsigned Min = NextID++, MyID = Min;
- ValMap[F] = Min;
- Stack.push_back(F);
-
- if (F->isExternal()) { // sprintf, fprintf, sscanf, etc...
- // No callees!
- Stack.pop_back();
- ValMap[F] = ~0;
- return Min;
- }
-
- DSGraph &Graph = getOrCreateGraph(F);
-
- // The edges out of the current node are the call site targets...
- for (DSCallSiteIterator I = DSCallSiteIterator::begin_aux(Graph),
- E = DSCallSiteIterator::end_aux(Graph); I != E; ++I) {
- Function *Callee = *I;
- unsigned M;
- // Have we visited the destination function yet?
- hash_map<Function*, unsigned>::iterator It = ValMap.find(Callee);
- if (It == ValMap.end()) // No, visit it now.
- M = calculateGraphs(Callee, Stack, NextID, ValMap);
- else // Yes, get it's number.
- M = It->second;
- if (M < Min) Min = M;
- }
-
- assert(ValMap[F] == MyID && "SCC construction assumption wrong!");
- if (Min != MyID)
- return Min; // This is part of a larger SCC!
-
- // If this is a new SCC, process it now.
- if (Stack.back() == F) { // Special case the single "SCC" case here.
- DEBUG(std::cerr << "Visiting single node SCC #: " << MyID << " fn: "
- << F->getName() << "\n");
- Stack.pop_back();
- DSGraph &G = getDSGraph(*F);
- DEBUG(std::cerr << " [BU] Calculating graph for: " << F->getName()<< "\n");
- calculateGraph(G);
- DEBUG(std::cerr << " [BU] Done inlining: " << F->getName() << " ["
- << G.getGraphSize() << "+" << G.getAuxFunctionCalls().size()
- << "]\n");
-
- if (MaxSCC < 1) MaxSCC = 1;
-
- // Should we revisit the graph?
- if (DSCallSiteIterator::begin_aux(G) != DSCallSiteIterator::end_aux(G)) {
- ValMap.erase(F);
- return calculateGraphs(F, Stack, NextID, ValMap);
- } else {
- ValMap[F] = ~0U;
- }
- return MyID;
-
- } else {
- // SCCFunctions - Keep track of the functions in the current SCC
- //
- hash_set<Function*> SCCFunctions;
-
- Function *NF;
- std::vector<Function*>::iterator FirstInSCC = Stack.end();
- DSGraph *SCCGraph = 0;
- do {
- NF = *--FirstInSCC;
- ValMap[NF] = ~0U;
- SCCFunctions.insert(NF);
-
- // Figure out which graph is the largest one, in order to speed things up
- // a bit in situations where functions in the SCC have widely different
- // graph sizes.
- DSGraph &NFGraph = getDSGraph(*NF);
- if (!SCCGraph || SCCGraph->getGraphSize() < NFGraph.getGraphSize())
- SCCGraph = &NFGraph;
- } while (NF != F);
-
- std::cerr << "Calculating graph for SCC #: " << MyID << " of size: "
- << SCCFunctions.size() << "\n";
-
- // Compute the Max SCC Size...
- if (MaxSCC < SCCFunctions.size())
- MaxSCC = SCCFunctions.size();
-
- // First thing first, collapse all of the DSGraphs into a single graph for
- // the entire SCC. We computed the largest graph, so clone all of the other
- // (smaller) graphs into it. Discard all of the old graphs.
- //
- for (hash_set<Function*>::iterator I = SCCFunctions.begin(),
- E = SCCFunctions.end(); I != E; ++I) {
- DSGraph &G = getDSGraph(**I);
- if (&G != SCCGraph) {
- DSGraph::NodeMapTy NodeMap;
- SCCGraph->cloneInto(G, SCCGraph->getScalarMap(),
- SCCGraph->getReturnNodes(), NodeMap, 0);
- // Update the DSInfo map and delete the old graph...
- DSInfo[*I] = SCCGraph;
- delete &G;
- }
- }
-
- // Clean up the graph before we start inlining a bunch again...
- SCCGraph->removeTriviallyDeadNodes();
-
- // Now that we have one big happy family, resolve all of the call sites in
- // the graph...
- calculateGraph(*SCCGraph);
- DEBUG(std::cerr << " [BU] Done inlining SCC [" << SCCGraph->getGraphSize()
- << "+" << SCCGraph->getAuxFunctionCalls().size() << "]\n");
-
- std::cerr << "DONE with SCC #: " << MyID << "\n";
-
- // We never have to revisit "SCC" processed functions...
-
- // Drop the stuff we don't need from the end of the stack
- Stack.erase(FirstInSCC, Stack.end());
- return MyID;
- }
-
- return MyID; // == Min
-}
-
-
-// releaseMemory - If the pass pipeline is done with this pass, we can release
-// our memory... here...
-//
-void BUDataStructures::releaseMemory() {
- for (hash_map<Function*, DSGraph*>::iterator I = DSInfo.begin(),
- E = DSInfo.end(); I != E; ++I) {
- I->second->getReturnNodes().erase(I->first);
- if (I->second->getReturnNodes().empty())
- delete I->second;
- }
-
- // Empty map so next time memory is released, data structures are not
- // re-deleted.
- DSInfo.clear();
- delete GlobalsGraph;
- GlobalsGraph = 0;
-}
-
-void BUDataStructures::calculateGraph(DSGraph &Graph) {
- // Move our call site list into TempFCs so that inline call sites go into the
- // new call site list and doesn't invalidate our iterators!
- std::vector<DSCallSite> TempFCs;
- std::vector<DSCallSite> &AuxCallsList = Graph.getAuxFunctionCalls();
- TempFCs.swap(AuxCallsList);
-
- DSGraph::ReturnNodesTy &ReturnNodes = Graph.getReturnNodes();
-
- // Loop over all of the resolvable call sites
- unsigned LastCallSiteIdx = ~0U;
- for (DSCallSiteIterator I = DSCallSiteIterator::begin(TempFCs),
- E = DSCallSiteIterator::end(TempFCs); I != E; ++I) {
- // If we skipped over any call sites, they must be unresolvable, copy them
- // to the real call site list.
- LastCallSiteIdx++;
- for (; LastCallSiteIdx < I.getCallSiteIdx(); ++LastCallSiteIdx)
- AuxCallsList.push_back(TempFCs[LastCallSiteIdx]);
- LastCallSiteIdx = I.getCallSiteIdx();
-
- // Resolve the current call...
- Function *Callee = *I;
- DSCallSite CS = I.getCallSite();
-
- if (Callee->isExternal()) {
- // Ignore this case, simple varargs functions we cannot stub out!
- } else if (ReturnNodes.find(Callee) != ReturnNodes.end()) {
- // Self recursion... simply link up the formal arguments with the
- // actual arguments...
- DEBUG(std::cerr << " Self Inlining: " << Callee->getName() << "\n");
-
- // Handle self recursion by resolving the arguments and return value
- Graph.mergeInGraph(CS, *Callee, Graph, 0);
-
- } else {
- ActualCallees.insert(std::make_pair(&CS.getCallInst(), Callee));
-
- // Get the data structure graph for the called function.
- //
- DSGraph &GI = getDSGraph(*Callee); // Graph to inline
-
- DEBUG(std::cerr << " Inlining graph for " << Callee->getName()
- << "[" << GI.getGraphSize() << "+"
- << GI.getAuxFunctionCalls().size() << "] into '"
- << Graph.getFunctionNames() << "' [" << Graph.getGraphSize() << "+"
- << Graph.getAuxFunctionCalls().size() << "]\n");
-
- // Handle self recursion by resolving the arguments and return value
- Graph.mergeInGraph(CS, *Callee, GI,
- DSGraph::KeepModRefBits |
- DSGraph::StripAllocaBit | DSGraph::DontCloneCallNodes);
- ++NumBUInlines;
-
-#if 0
- Graph.writeGraphToFile(std::cerr, "bu_" + F.getName() + "_after_" +
- Callee->getName());
-#endif
- }
- }
-
- // Make sure to catch any leftover unresolvable calls...
- for (++LastCallSiteIdx; LastCallSiteIdx < TempFCs.size(); ++LastCallSiteIdx)
- AuxCallsList.push_back(TempFCs[LastCallSiteIdx]);
-
- TempFCs.clear();
-
- // Re-materialize nodes from the globals graph.
- // Do not ignore globals inlined from callees -- they are not up-to-date!
- Graph.getInlinedGlobals().clear();
- Graph.updateFromGlobalGraph();
-
- // Recompute the Incomplete markers
- Graph.maskIncompleteMarkers();
- Graph.markIncompleteNodes(DSGraph::MarkFormalArgs);
-
- // Delete dead nodes. Treat globals that are unreachable but that can
- // reach live nodes as live.
- Graph.removeDeadNodes(DSGraph::KeepUnreachableGlobals);
-
- //Graph.writeGraphToFile(std::cerr, "bu_" + F.getName());
-}
-
diff --git a/poolalloc/lib/DSA/DSCallSiteIterator.h b/poolalloc/lib/DSA/DSCallSiteIterator.h
deleted file mode 100644
index acbf808..0000000
--- a/poolalloc/lib/DSA/DSCallSiteIterator.h
+++ /dev/null
@@ -1,126 +0,0 @@
-//===- DSCallSiteIterator.h - Iterator for DSGraph call sites ---*- C++ -*-===//
-//
-// This file implements an iterator for complete call sites in DSGraphs. This
-// code can either iterator over the normal call list or the aux calls list, and
-// is used by the TD and BU passes.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef DSCALLSITEITERATOR_H
-#define DSCALLSITEITERATOR_H
-
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Function.h"
-
-struct DSCallSiteIterator {
- // FCs are the edges out of the current node are the call site targets...
- const std::vector<DSCallSite> *FCs;
- unsigned CallSite;
- unsigned CallSiteEntry;
-
- DSCallSiteIterator(const std::vector<DSCallSite> &CS) : FCs(&CS) {
- CallSite = 0; CallSiteEntry = 0;
- advanceToValidCallee();
- }
-
- // End iterator ctor...
- DSCallSiteIterator(const std::vector<DSCallSite> &CS, bool) : FCs(&CS) {
- CallSite = FCs->size(); CallSiteEntry = 0;
- }
-
- static bool isVAHackFn(const Function *F) {
- return F->getName() == "printf" || F->getName() == "sscanf" ||
- F->getName() == "fprintf" || F->getName() == "open" ||
- F->getName() == "sprintf" || F->getName() == "fputs" ||
- F->getName() == "fscanf" || F->getName() == "bzero" ||
- F->getName() == "memset";
- }
-
- // isUnresolvableFunction - Return true if this is an unresolvable
- // external function. A direct or indirect call to this cannot be resolved.
- //
- static bool isUnresolvableFunc(const Function* callee) {
- return callee->isExternal() && !isVAHackFn(callee);
- }
-
- void advanceToValidCallee() {
- while (CallSite < FCs->size()) {
- if ((*FCs)[CallSite].isDirectCall()) {
- if (CallSiteEntry == 0 && // direct call only has one target...
- ! isUnresolvableFunc((*FCs)[CallSite].getCalleeFunc()))
- return; // and not an unresolvable external func
- } else {
- DSNode *CalleeNode = (*FCs)[CallSite].getCalleeNode();
- if (CallSiteEntry || isCompleteNode(CalleeNode)) {
- const std::vector<GlobalValue*> &Callees = CalleeNode->getGlobals();
- while (CallSiteEntry < Callees.size()) {
- if (isa<Function>(Callees[CallSiteEntry]))
- return;
- ++CallSiteEntry;
- }
- }
- }
- CallSiteEntry = 0;
- ++CallSite;
- }
- }
-
- // isCompleteNode - Return true if we know all of the targets of this node,
- // and if the call sites are not external.
- //
- static inline bool isCompleteNode(DSNode *N) {
- if (N->isIncomplete()) return false;
- const std::vector<GlobalValue*> &Callees = N->getGlobals();
- for (unsigned i = 0, e = Callees.size(); i != e; ++i)
- if (isUnresolvableFunc(cast<Function>(Callees[i])))
- return false; // Unresolvable external function found...
- return true; // otherwise ok
- }
-
-public:
- static DSCallSiteIterator begin_aux(DSGraph &G) {
- return G.getAuxFunctionCalls();
- }
- static DSCallSiteIterator end_aux(DSGraph &G) {
- return DSCallSiteIterator(G.getAuxFunctionCalls(), true);
- }
- static DSCallSiteIterator begin_std(DSGraph &G) {
- return G.getFunctionCalls();
- }
- static DSCallSiteIterator end_std(DSGraph &G) {
- return DSCallSiteIterator(G.getFunctionCalls(), true);
- }
- static DSCallSiteIterator begin(std::vector<DSCallSite> &CSs) { return CSs; }
- static DSCallSiteIterator end(std::vector<DSCallSite> &CSs) {
- return DSCallSiteIterator(CSs, true);
- }
- bool operator==(const DSCallSiteIterator &CSI) const {
- return CallSite == CSI.CallSite && CallSiteEntry == CSI.CallSiteEntry;
- }
- bool operator!=(const DSCallSiteIterator &CSI) const {
- return !operator==(CSI);
- }
-
- unsigned getCallSiteIdx() const { return CallSite; }
- const DSCallSite &getCallSite() const { return (*FCs)[CallSite]; }
-
- Function *operator*() const {
- if ((*FCs)[CallSite].isDirectCall()) {
- return (*FCs)[CallSite].getCalleeFunc();
- } else {
- DSNode *Node = (*FCs)[CallSite].getCalleeNode();
- return cast<Function>(Node->getGlobals()[CallSiteEntry]);
- }
- }
-
- DSCallSiteIterator& operator++() { // Preincrement
- ++CallSiteEntry;
- advanceToValidCallee();
- return *this;
- }
- DSCallSiteIterator operator++(int) { // Postincrement
- DSCallSiteIterator tmp = *this; ++*this; return tmp;
- }
-};
-
-#endif
diff --git a/poolalloc/lib/DSA/DataStructure.cpp b/poolalloc/lib/DSA/DataStructure.cpp
deleted file mode 100644
index 241c2a9..0000000
--- a/poolalloc/lib/DSA/DataStructure.cpp
+++ /dev/null
@@ -1,1612 +0,0 @@
-//===- DataStructure.cpp - Implement the core data structure analysis -----===//
-//
-// This file implements the core data structure functionality.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Function.h"
-#include "llvm/iOther.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Target/TargetData.h"
-#include "llvm/Assembly/Writer.h"
-#include "Support/Debug.h"
-#include "Support/STLExtras.h"
-#include "Support/Statistic.h"
-#include "Support/Timer.h"
-#include <algorithm>
-
-namespace {
- Statistic<> NumFolds ("dsnode", "Number of nodes completely folded");
- Statistic<> NumCallNodesMerged("dsnode", "Number of call nodes merged");
-};
-
-namespace DS { // TODO: FIXME
- extern TargetData TD;
-}
-using namespace DS;
-
-DSNode *DSNodeHandle::HandleForwarding() const {
- assert(!N->ForwardNH.isNull() && "Can only be invoked if forwarding!");
-
- // Handle node forwarding here!
- DSNode *Next = N->ForwardNH.getNode(); // Cause recursive shrinkage
- Offset += N->ForwardNH.getOffset();
-
- if (--N->NumReferrers == 0) {
- // Removing the last referrer to the node, sever the forwarding link
- N->stopForwarding();
- }
-
- N = Next;
- N->NumReferrers++;
- if (N->Size <= Offset) {
- assert(N->Size <= 1 && "Forwarded to shrunk but not collapsed node?");
- Offset = 0;
- }
- return N;
-}
-
-//===----------------------------------------------------------------------===//
-// DSNode Implementation
-//===----------------------------------------------------------------------===//
-
-DSNode::DSNode(const Type *T, DSGraph *G)
- : NumReferrers(0), Size(0), ParentGraph(G), Ty(Type::VoidTy), NodeType(0) {
- // Add the type entry if it is specified...
- if (T) mergeTypeInfo(T, 0);
- G->getNodes().push_back(this);
-}
-
-// DSNode copy constructor... do not copy over the referrers list!
-DSNode::DSNode(const DSNode &N, DSGraph *G)
- : NumReferrers(0), Size(N.Size), ParentGraph(G),
- Ty(N.Ty), Links(N.Links), Globals(N.Globals), NodeType(N.NodeType) {
- G->getNodes().push_back(this);
-}
-
-void DSNode::assertOK() const {
- assert((Ty != Type::VoidTy ||
- Ty == Type::VoidTy && (Size == 0 ||
- (NodeType & DSNode::Array))) &&
- "Node not OK!");
-
- assert(ParentGraph && "Node has no parent?");
- const DSGraph::ScalarMapTy &SM = ParentGraph->getScalarMap();
- for (unsigned i = 0, e = Globals.size(); i != e; ++i) {
- assert(SM.find(Globals[i]) != SM.end());
- assert(SM.find(Globals[i])->second.getNode() == this);
- }
-}
-
-/// forwardNode - Mark this node as being obsolete, and all references to it
-/// should be forwarded to the specified node and offset.
-///
-void DSNode::forwardNode(DSNode *To, unsigned Offset) {
- assert(this != To && "Cannot forward a node to itself!");
- assert(ForwardNH.isNull() && "Already forwarding from this node!");
- if (To->Size <= 1) Offset = 0;
- assert((Offset < To->Size || (Offset == To->Size && Offset == 0)) &&
- "Forwarded offset is wrong!");
- ForwardNH.setNode(To);
- ForwardNH.setOffset(Offset);
- NodeType = DEAD;
- Size = 0;
- Ty = Type::VoidTy;
-}
-
-// addGlobal - Add an entry for a global value to the Globals list. This also
-// marks the node with the 'G' flag if it does not already have it.
-//
-void DSNode::addGlobal(GlobalValue *GV) {
- // Keep the list sorted.
- std::vector<GlobalValue*>::iterator I =
- std::lower_bound(Globals.begin(), Globals.end(), GV);
-
- if (I == Globals.end() || *I != GV) {
- //assert(GV->getType()->getElementType() == Ty);
- Globals.insert(I, GV);
- NodeType |= GlobalNode;
- }
-}
-
-/// foldNodeCompletely - If we determine that this node has some funny
-/// behavior happening to it that we cannot represent, we fold it down to a
-/// single, completely pessimistic, node. This node is represented as a
-/// single byte with a single TypeEntry of "void".
-///
-void DSNode::foldNodeCompletely() {
- if (isNodeCompletelyFolded()) return; // If this node is already folded...
-
- ++NumFolds;
-
- // Create the node we are going to forward to...
- DSNode *DestNode = new DSNode(0, ParentGraph);
- DestNode->NodeType = NodeType|DSNode::Array;
- DestNode->Ty = Type::VoidTy;
- DestNode->Size = 1;
- DestNode->Globals.swap(Globals);
-
- // Start forwarding to the destination node...
- forwardNode(DestNode, 0);
-
- if (Links.size()) {
- DestNode->Links.push_back(Links[0]);
- DSNodeHandle NH(DestNode);
-
- // If we have links, merge all of our outgoing links together...
- for (unsigned i = Links.size()-1; i != 0; --i)
- NH.getNode()->Links[0].mergeWith(Links[i]);
- Links.clear();
- } else {
- DestNode->Links.resize(1);
- }
-}
-
-/// isNodeCompletelyFolded - Return true if this node has been completely
-/// folded down to something that can never be expanded, effectively losing
-/// all of the field sensitivity that may be present in the node.
-///
-bool DSNode::isNodeCompletelyFolded() const {
- return getSize() == 1 && Ty == Type::VoidTy && isArray();
-}
-
-
-namespace {
- /// TypeElementWalker Class - Used for implementation of physical subtyping...
- ///
- class TypeElementWalker {
- struct StackState {
- const Type *Ty;
- unsigned Offset;
- unsigned Idx;
- StackState(const Type *T, unsigned Off = 0)
- : Ty(T), Offset(Off), Idx(0) {}
- };
-
- std::vector<StackState> Stack;
- public:
- TypeElementWalker(const Type *T) {
- Stack.push_back(T);
- StepToLeaf();
- }
-
- bool isDone() const { return Stack.empty(); }
- const Type *getCurrentType() const { return Stack.back().Ty; }
- unsigned getCurrentOffset() const { return Stack.back().Offset; }
-
- void StepToNextType() {
- PopStackAndAdvance();
- StepToLeaf();
- }
-
- private:
- /// PopStackAndAdvance - Pop the current element off of the stack and
- /// advance the underlying element to the next contained member.
- void PopStackAndAdvance() {
- assert(!Stack.empty() && "Cannot pop an empty stack!");
- Stack.pop_back();
- while (!Stack.empty()) {
- StackState &SS = Stack.back();
- if (const StructType *ST = dyn_cast<StructType>(SS.Ty)) {
- ++SS.Idx;
- if (SS.Idx != ST->getElementTypes().size()) {
- const StructLayout *SL = TD.getStructLayout(ST);
- SS.Offset += SL->MemberOffsets[SS.Idx]-SL->MemberOffsets[SS.Idx-1];
- return;
- }
- Stack.pop_back(); // At the end of the structure
- } else {
- const ArrayType *AT = cast<ArrayType>(SS.Ty);
- ++SS.Idx;
- if (SS.Idx != AT->getNumElements()) {
- SS.Offset += TD.getTypeSize(AT->getElementType());
- return;
- }
- Stack.pop_back(); // At the end of the array
- }
- }
- }
-
- /// StepToLeaf - Used by physical subtyping to move to the first leaf node
- /// on the type stack.
- void StepToLeaf() {
- if (Stack.empty()) return;
- while (!Stack.empty() && !Stack.back().Ty->isFirstClassType()) {
- StackState &SS = Stack.back();
- if (const StructType *ST = dyn_cast<StructType>(SS.Ty)) {
- if (ST->getElementTypes().empty()) {
- assert(SS.Idx == 0);
- PopStackAndAdvance();
- } else {
- // Step into the structure...
- assert(SS.Idx < ST->getElementTypes().size());
- const StructLayout *SL = TD.getStructLayout(ST);
- Stack.push_back(StackState(ST->getElementTypes()[SS.Idx],
- SS.Offset+SL->MemberOffsets[SS.Idx]));
- }
- } else {
- const ArrayType *AT = cast<ArrayType>(SS.Ty);
- if (AT->getNumElements() == 0) {
- assert(SS.Idx == 0);
- PopStackAndAdvance();
- } else {
- // Step into the array...
- assert(SS.Idx < AT->getNumElements());
- Stack.push_back(StackState(AT->getElementType(),
- SS.Offset+SS.Idx*
- TD.getTypeSize(AT->getElementType())));
- }
- }
- }
- }
- };
-}
-
-/// ElementTypesAreCompatible - Check to see if the specified types are
-/// "physically" compatible. If so, return true, else return false. We only
-/// have to check the fields in T1: T2 may be larger than T1.
-///
-static bool ElementTypesAreCompatible(const Type *T1, const Type *T2) {
- TypeElementWalker T1W(T1), T2W(T2);
-
- while (!T1W.isDone() && !T2W.isDone()) {
- if (T1W.getCurrentOffset() != T2W.getCurrentOffset())
- return false;
-
- const Type *T1 = T1W.getCurrentType();
- const Type *T2 = T2W.getCurrentType();
- if (T1 != T2 && !T1->isLosslesslyConvertibleTo(T2))
- return false;
-
- T1W.StepToNextType();
- T2W.StepToNextType();
- }
-
- return T1W.isDone();
-}
-
-
-/// mergeTypeInfo - This method merges the specified type into the current node
-/// at the specified offset. This may update the current node's type record if
-/// this gives more information to the node, it may do nothing to the node if
-/// this information is already known, or it may merge the node completely (and
-/// return true) if the information is incompatible with what is already known.
-///
-/// This method returns true if the node is completely folded, otherwise false.
-///
-bool DSNode::mergeTypeInfo(const Type *NewTy, unsigned Offset,
- bool FoldIfIncompatible) {
- // Check to make sure the Size member is up-to-date. Size can be one of the
- // following:
- // Size = 0, Ty = Void: Nothing is known about this node.
- // Size = 0, Ty = FnTy: FunctionPtr doesn't have a size, so we use zero
- // Size = 1, Ty = Void, Array = 1: The node is collapsed
- // Otherwise, sizeof(Ty) = Size
- //
- assert(((Size == 0 && Ty == Type::VoidTy && !isArray()) ||
- (Size == 0 && !Ty->isSized() && !isArray()) ||
- (Size == 1 && Ty == Type::VoidTy && isArray()) ||
- (Size == 0 && !Ty->isSized() && !isArray()) ||
- (TD.getTypeSize(Ty) == Size)) &&
- "Size member of DSNode doesn't match the type structure!");
- assert(NewTy != Type::VoidTy && "Cannot merge void type into DSNode!");
-
- if (Offset == 0 && NewTy == Ty)
- return false; // This should be a common case, handle it efficiently
-
- // Return true immediately if the node is completely folded.
- if (isNodeCompletelyFolded()) return true;
-
- // If this is an array type, eliminate the outside arrays because they won't
- // be used anyway. This greatly reduces the size of large static arrays used
- // as global variables, for example.
- //
- bool WillBeArray = false;
- while (const ArrayType *AT = dyn_cast<ArrayType>(NewTy)) {
- // FIXME: we might want to keep small arrays, but must be careful about
- // things like: [2 x [10000 x int*]]
- NewTy = AT->getElementType();
- WillBeArray = true;
- }
-
- // Figure out how big the new type we're merging in is...
- unsigned NewTySize = NewTy->isSized() ? TD.getTypeSize(NewTy) : 0;
-
- // Otherwise check to see if we can fold this type into the current node. If
- // we can't, we fold the node completely, if we can, we potentially update our
- // internal state.
- //
- if (Ty == Type::VoidTy) {
- // If this is the first type that this node has seen, just accept it without
- // question....
- assert(Offset == 0 && "Cannot have an offset into a void node!");
- assert(!isArray() && "This shouldn't happen!");
- Ty = NewTy;
- NodeType &= ~Array;
- if (WillBeArray) NodeType |= Array;
- Size = NewTySize;
-
- // Calculate the number of outgoing links from this node.
- Links.resize((Size+DS::PointerSize-1) >> DS::PointerShift);
- return false;
- }
-
- // Handle node expansion case here...
- if (Offset+NewTySize > Size) {
- // It is illegal to grow this node if we have treated it as an array of
- // objects...
- if (isArray()) {
- if (FoldIfIncompatible) foldNodeCompletely();
- return true;
- }
-
- if (Offset) { // We could handle this case, but we don't for now...
- std::cerr << "UNIMP: Trying to merge a growth type into "
- << "offset != 0: Collapsing!\n";
- if (FoldIfIncompatible) foldNodeCompletely();
- return true;
- }
-
- // Okay, the situation is nice and simple, we are trying to merge a type in
- // at offset 0 that is bigger than our current type. Implement this by
- // switching to the new type and then merge in the smaller one, which should
- // hit the other code path here. If the other code path decides it's not
- // ok, it will collapse the node as appropriate.
- //
- const Type *OldTy = Ty;
- Ty = NewTy;
- NodeType &= ~Array;
- if (WillBeArray) NodeType |= Array;
- Size = NewTySize;
-
- // Must grow links to be the appropriate size...
- Links.resize((Size+DS::PointerSize-1) >> DS::PointerShift);
-
- // Merge in the old type now... which is guaranteed to be smaller than the
- // "current" type.
- return mergeTypeInfo(OldTy, 0);
- }
-
- assert(Offset <= Size &&
- "Cannot merge something into a part of our type that doesn't exist!");
-
- // Find the section of Ty that NewTy overlaps with... first we find the
- // type that starts at offset Offset.
- //
- unsigned O = 0;
- const Type *SubType = Ty;
- while (O < Offset) {
- assert(Offset-O < TD.getTypeSize(SubType) && "Offset out of range!");
-
- switch (SubType->getPrimitiveID()) {
- case Type::StructTyID: {
- const StructType *STy = cast<StructType>(SubType);
- const StructLayout &SL = *TD.getStructLayout(STy);
-
- unsigned i = 0, e = SL.MemberOffsets.size();
- for (; i+1 < e && SL.MemberOffsets[i+1] <= Offset-O; ++i)
- /* empty */;
-
- // The offset we are looking for must be in the i'th element...
- SubType = STy->getElementTypes()[i];
- O += SL.MemberOffsets[i];
- break;
- }
- case Type::ArrayTyID: {
- SubType = cast<ArrayType>(SubType)->getElementType();
- unsigned ElSize = TD.getTypeSize(SubType);
- unsigned Remainder = (Offset-O) % ElSize;
- O = Offset-Remainder;
- break;
- }
- default:
- if (FoldIfIncompatible) foldNodeCompletely();
- return true;
- }
- }
-
- assert(O == Offset && "Could not achieve the correct offset!");
-
- // If we found our type exactly, early exit
- if (SubType == NewTy) return false;
-
- unsigned SubTypeSize = SubType->isSized() ? TD.getTypeSize(SubType) : 0;
-
- // Ok, we are getting desperate now. Check for physical subtyping, where we
- // just require each element in the node to be compatible.
- if (NewTySize <= SubTypeSize && NewTySize && NewTySize < 256 &&
- SubTypeSize && SubTypeSize < 256 &&
- ElementTypesAreCompatible(NewTy, SubType))
- return false;
-
- // Okay, so we found the leader type at the offset requested. Search the list
- // of types that starts at this offset. If SubType is currently an array or
- // structure, the type desired may actually be the first element of the
- // composite type...
- //
- unsigned PadSize = SubTypeSize; // Size, including pad memory which is ignored
- while (SubType != NewTy) {
- const Type *NextSubType = 0;
- unsigned NextSubTypeSize = 0;
- unsigned NextPadSize = 0;
- switch (SubType->getPrimitiveID()) {
- case Type::StructTyID: {
- const StructType *STy = cast<StructType>(SubType);
- const StructLayout &SL = *TD.getStructLayout(STy);
- if (SL.MemberOffsets.size() > 1)
- NextPadSize = SL.MemberOffsets[1];
- else
- NextPadSize = SubTypeSize;
- NextSubType = STy->getElementTypes()[0];
- NextSubTypeSize = TD.getTypeSize(NextSubType);
- break;
- }
- case Type::ArrayTyID:
- NextSubType = cast<ArrayType>(SubType)->getElementType();
- NextSubTypeSize = TD.getTypeSize(NextSubType);
- NextPadSize = NextSubTypeSize;
- break;
- default: ;
- // fall out
- }
-
- if (NextSubType == 0)
- break; // In the default case, break out of the loop
-
- if (NextPadSize < NewTySize)
- break; // Don't allow shrinking to a smaller type than NewTySize
- SubType = NextSubType;
- SubTypeSize = NextSubTypeSize;
- PadSize = NextPadSize;
- }
-
- // If we found the type exactly, return it...
- if (SubType == NewTy)
- return false;
-
- // Check to see if we have a compatible, but different type...
- if (NewTySize == SubTypeSize) {
- // Check to see if this type is obviously convertible... int -> uint f.e.
- if (NewTy->isLosslesslyConvertibleTo(SubType))
- return false;
-
- // Check to see if we have a pointer & integer mismatch going on here,
- // loading a pointer as a long, for example.
- //
- if (SubType->isInteger() && isa<PointerType>(NewTy) ||
- NewTy->isInteger() && isa<PointerType>(SubType))
- return false;
- } else if (NewTySize > SubTypeSize && NewTySize <= PadSize) {
- // We are accessing the field, plus some structure padding. Ignore the
- // structure padding.
- return false;
- }
-
- Module *M = 0;
- if (getParentGraph()->getReturnNodes().size())
- M = getParentGraph()->getReturnNodes().begin()->first->getParent();
- DEBUG(std::cerr << "MergeTypeInfo Folding OrigTy: ";
- WriteTypeSymbolic(std::cerr, Ty, M) << "\n due to:";
- WriteTypeSymbolic(std::cerr, NewTy, M) << " @ " << Offset << "!\n"
- << "SubType: ";
- WriteTypeSymbolic(std::cerr, SubType, M) << "\n\n");
-
- if (FoldIfIncompatible) foldNodeCompletely();
- return true;
-}
-
-
-
-// addEdgeTo - Add an edge from the current node to the specified node. This
-// can cause merging of nodes in the graph.
-//
-void DSNode::addEdgeTo(unsigned Offset, const DSNodeHandle &NH) {
- if (NH.getNode() == 0) return; // Nothing to do
-
- DSNodeHandle &ExistingEdge = getLink(Offset);
- if (ExistingEdge.getNode()) {
- // Merge the two nodes...
- ExistingEdge.mergeWith(NH);
- } else { // No merging to perform...
- setLink(Offset, NH); // Just force a link in there...
- }
-}
-
-
-// MergeSortedVectors - Efficiently merge a vector into another vector where
-// duplicates are not allowed and both are sorted. This assumes that 'T's are
-// efficiently copyable and have sane comparison semantics.
-//
-static void MergeSortedVectors(std::vector<GlobalValue*> &Dest,
- const std::vector<GlobalValue*> &Src) {
- // By far, the most common cases will be the simple ones. In these cases,
- // avoid having to allocate a temporary vector...
- //
- if (Src.empty()) { // Nothing to merge in...
- return;
- } else if (Dest.empty()) { // Just copy the result in...
- Dest = Src;
- } else if (Src.size() == 1) { // Insert a single element...
- const GlobalValue *V = Src[0];
- std::vector<GlobalValue*>::iterator I =
- std::lower_bound(Dest.begin(), Dest.end(), V);
- if (I == Dest.end() || *I != Src[0]) // If not already contained...
- Dest.insert(I, Src[0]);
- } else if (Dest.size() == 1) {
- GlobalValue *Tmp = Dest[0]; // Save value in temporary...
- Dest = Src; // Copy over list...
- std::vector<GlobalValue*>::iterator I =
- std::lower_bound(Dest.begin(), Dest.end(), Tmp);
- if (I == Dest.end() || *I != Tmp) // If not already contained...
- Dest.insert(I, Tmp);
-
- } else {
- // Make a copy to the side of Dest...
- std::vector<GlobalValue*> Old(Dest);
-
- // Make space for all of the type entries now...
- Dest.resize(Dest.size()+Src.size());
-
- // Merge the two sorted ranges together... into Dest.
- std::merge(Old.begin(), Old.end(), Src.begin(), Src.end(), Dest.begin());
-
- // Now erase any duplicate entries that may have accumulated into the
- // vectors (because they were in both of the input sets)
- Dest.erase(std::unique(Dest.begin(), Dest.end()), Dest.end());
- }
-}
-
-
-// MergeNodes() - Helper function for DSNode::mergeWith().
-// This function does the hard work of merging two nodes, CurNodeH
-// and NH after filtering out trivial cases and making sure that
-// CurNodeH.offset >= NH.offset.
-//
-// ***WARNING***
-// Since merging may cause either node to go away, we must always
-// use the node-handles to refer to the nodes. These node handles are
-// automatically updated during merging, so will always provide access
-// to the correct node after a merge.
-//
-void DSNode::MergeNodes(DSNodeHandle& CurNodeH, DSNodeHandle& NH) {
- assert(CurNodeH.getOffset() >= NH.getOffset() &&
- "This should have been enforced in the caller.");
-
- // Now we know that Offset >= NH.Offset, so convert it so our "Offset" (with
- // respect to NH.Offset) is now zero. NOffset is the distance from the base
- // of our object that N starts from.
- //
- unsigned NOffset = CurNodeH.getOffset()-NH.getOffset();
- unsigned NSize = NH.getNode()->getSize();
-
- // If the two nodes are of different size, and the smaller node has the array
- // bit set, collapse!
- if (NSize != CurNodeH.getNode()->getSize()) {
- if (NSize < CurNodeH.getNode()->getSize()) {
- if (NH.getNode()->isArray())
- NH.getNode()->foldNodeCompletely();
- } else if (CurNodeH.getNode()->isArray()) {
- NH.getNode()->foldNodeCompletely();
- }
- }
-
- // Merge the type entries of the two nodes together...
- if (NH.getNode()->Ty != Type::VoidTy)
- CurNodeH.getNode()->mergeTypeInfo(NH.getNode()->Ty, NOffset);
- assert(!CurNodeH.getNode()->isDeadNode());
-
- // If we are merging a node with a completely folded node, then both nodes are
- // now completely folded.
- //
- if (CurNodeH.getNode()->isNodeCompletelyFolded()) {
- if (!NH.getNode()->isNodeCompletelyFolded()) {
- NH.getNode()->foldNodeCompletely();
- assert(NH.getNode() && NH.getOffset() == 0 &&
- "folding did not make offset 0?");
- NOffset = NH.getOffset();
- NSize = NH.getNode()->getSize();
- assert(NOffset == 0 && NSize == 1);
- }
- } else if (NH.getNode()->isNodeCompletelyFolded()) {
- CurNodeH.getNode()->foldNodeCompletely();
- assert(CurNodeH.getNode() && CurNodeH.getOffset() == 0 &&
- "folding did not make offset 0?");
- NOffset = NH.getOffset();
- NSize = NH.getNode()->getSize();
- assert(NOffset == 0 && NSize == 1);
- }
-
- DSNode *N = NH.getNode();
- if (CurNodeH.getNode() == N || N == 0) return;
- assert(!CurNodeH.getNode()->isDeadNode());
-
- // Merge the NodeType information...
- CurNodeH.getNode()->NodeType |= N->NodeType;
-
- // Start forwarding to the new node!
- N->forwardNode(CurNodeH.getNode(), NOffset);
- assert(!CurNodeH.getNode()->isDeadNode());
-
- // Make all of the outgoing links of N now be outgoing links of CurNodeH.
- //
- for (unsigned i = 0; i < N->getNumLinks(); ++i) {
- DSNodeHandle &Link = N->getLink(i << DS::PointerShift);
- if (Link.getNode()) {
- // Compute the offset into the current node at which to
- // merge this link. In the common case, this is a linear
- // relation to the offset in the original node (with
- // wrapping), but if the current node gets collapsed due to
- // recursive merging, we must make sure to merge in all remaining
- // links at offset zero.
- unsigned MergeOffset = 0;
- DSNode *CN = CurNodeH.getNode();
- if (CN->Size != 1)
- MergeOffset = ((i << DS::PointerShift)+NOffset) % CN->getSize();
- CN->addEdgeTo(MergeOffset, Link);
- }
- }
-
- // Now that there are no outgoing edges, all of the Links are dead.
- N->Links.clear();
-
- // Merge the globals list...
- if (!N->Globals.empty()) {
- MergeSortedVectors(CurNodeH.getNode()->Globals, N->Globals);
-
- // Delete the globals from the old node...
- std::vector<GlobalValue*>().swap(N->Globals);
- }
-}
-
-
-// mergeWith - Merge this node and the specified node, moving all links to and
-// from the argument node into the current node, deleting the node argument.
-// Offset indicates what offset the specified node is to be merged into the
-// current node.
-//
-// The specified node may be a null pointer (in which case, nothing happens).
-//
-void DSNode::mergeWith(const DSNodeHandle &NH, unsigned Offset) {
- DSNode *N = NH.getNode();
- if (N == 0 || (N == this && NH.getOffset() == Offset))
- return; // Noop
-
- assert(!N->isDeadNode() && !isDeadNode());
- assert(!hasNoReferrers() && "Should not try to fold a useless node!");
-
- if (N == this) {
- // We cannot merge two pieces of the same node together, collapse the node
- // completely.
- DEBUG(std::cerr << "Attempting to merge two chunks of"
- << " the same node together!\n");
- foldNodeCompletely();
- return;
- }
-
- // If both nodes are not at offset 0, make sure that we are merging the node
- // at an later offset into the node with the zero offset.
- //
- if (Offset < NH.getOffset()) {
- N->mergeWith(DSNodeHandle(this, Offset), NH.getOffset());
- return;
- } else if (Offset == NH.getOffset() && getSize() < N->getSize()) {
- // If the offsets are the same, merge the smaller node into the bigger node
- N->mergeWith(DSNodeHandle(this, Offset), NH.getOffset());
- return;
- }
-
- // Ok, now we can merge the two nodes. Use a static helper that works with
- // two node handles, since "this" may get merged away at intermediate steps.
- DSNodeHandle CurNodeH(this, Offset);
- DSNodeHandle NHCopy(NH);
- DSNode::MergeNodes(CurNodeH, NHCopy);
-}
-
-//===----------------------------------------------------------------------===//
-// DSCallSite Implementation
-//===----------------------------------------------------------------------===//
-
-// Define here to avoid including iOther.h and BasicBlock.h in DSGraph.h
-Function &DSCallSite::getCaller() const {
- return *Inst->getParent()->getParent();
-}
-
-
-//===----------------------------------------------------------------------===//
-// DSGraph Implementation
-//===----------------------------------------------------------------------===//
-
-/// getFunctionNames - Return a space separated list of the name of the
-/// functions in this graph (if any)
-std::string DSGraph::getFunctionNames() const {
- switch (getReturnNodes().size()) {
- case 0: return "Globals graph";
- case 1: return getReturnNodes().begin()->first->getName();
- default:
- std::string Return;
- for (DSGraph::ReturnNodesTy::const_iterator I = getReturnNodes().begin();
- I != getReturnNodes().end(); ++I)
- Return += I->first->getName() + " ";
- Return.erase(Return.end()-1, Return.end()); // Remove last space character
- return Return;
- }
-}
-
-
-DSGraph::DSGraph(const DSGraph &G) : GlobalsGraph(0) {
- PrintAuxCalls = false;
- NodeMapTy NodeMap;
- cloneInto(G, ScalarMap, ReturnNodes, NodeMap);
- InlinedGlobals.clear(); // clear set of "up-to-date" globals
-}
-
-DSGraph::DSGraph(const DSGraph &G, NodeMapTy &NodeMap)
- : GlobalsGraph(0) {
- PrintAuxCalls = false;
- cloneInto(G, ScalarMap, ReturnNodes, NodeMap);
- InlinedGlobals.clear(); // clear set of "up-to-date" globals
-}
-
-DSGraph::~DSGraph() {
- FunctionCalls.clear();
- AuxFunctionCalls.clear();
- InlinedGlobals.clear();
- ScalarMap.clear();
- ReturnNodes.clear();
-
- // Drop all intra-node references, so that assertions don't fail...
- std::for_each(Nodes.begin(), Nodes.end(),
- std::mem_fun(&DSNode::dropAllReferences));
-
- // Delete all of the nodes themselves...
- std::for_each(Nodes.begin(), Nodes.end(), deleter<DSNode>);
-}
-
-// dump - Allow inspection of graph in a debugger.
-void DSGraph::dump() const { print(std::cerr); }
-
-
-/// remapLinks - Change all of the Links in the current node according to the
-/// specified mapping.
-///
-void DSNode::remapLinks(DSGraph::NodeMapTy &OldNodeMap) {
- for (unsigned i = 0, e = Links.size(); i != e; ++i) {
- DSNodeHandle &H = OldNodeMap[Links[i].getNode()];
- Links[i].setNode(H.getNode());
- Links[i].setOffset(Links[i].getOffset()+H.getOffset());
- }
-}
-
-
-/// cloneReachableNodes - Clone all reachable nodes from *Node into the
-/// current graph. This is a recursive function. The map OldNodeMap is a
-/// map from the original nodes to their clones.
-///
-void DSGraph::cloneReachableNodes(const DSNode* Node,
- unsigned BitsToClear,
- NodeMapTy& OldNodeMap,
- NodeMapTy& CompletedNodeMap) {
- if (CompletedNodeMap.find(Node) != CompletedNodeMap.end())
- return;
-
- DSNodeHandle& NH = OldNodeMap[Node];
- if (NH.getNode() != NULL)
- return;
-
- // else Node has not yet been cloned: clone it and clear the specified bits
- NH = new DSNode(*Node, this); // enters in OldNodeMap
- NH.getNode()->maskNodeTypes(~BitsToClear);
-
- // now recursively clone nodes pointed to by this node
- for (unsigned i = 0, e = Node->getNumLinks(); i != e; ++i) {
- const DSNodeHandle &Link = Node->getLink(i << DS::PointerShift);
- if (const DSNode* nextNode = Link.getNode())
- cloneReachableNodes(nextNode, BitsToClear, OldNodeMap, CompletedNodeMap);
- }
-}
-
-void DSGraph::cloneReachableSubgraph(const DSGraph& G,
- const hash_set<const DSNode*>& RootNodes,
- NodeMapTy& OldNodeMap,
- NodeMapTy& CompletedNodeMap,
- unsigned CloneFlags) {
- if (RootNodes.empty())
- return;
-
- assert(OldNodeMap.empty() && "Returned OldNodeMap should be empty!");
- assert(&G != this && "Cannot clone graph into itself!");
- assert((*RootNodes.begin())->getParentGraph() == &G &&
- "Root nodes do not belong to this graph!");
-
- // Remove alloca or mod/ref bits as specified...
- unsigned BitsToClear = ((CloneFlags & StripAllocaBit)? DSNode::AllocaNode : 0)
- | ((CloneFlags & StripModRefBits)? (DSNode::Modified | DSNode::Read) : 0)
- | ((CloneFlags & StripIncompleteBit)? DSNode::Incomplete : 0);
- BitsToClear |= DSNode::DEAD; // Clear dead flag...
-
- // Clone all nodes reachable from each root node, using a recursive helper
- for (hash_set<const DSNode*>::const_iterator I = RootNodes.begin(),
- E = RootNodes.end(); I != E; ++I)
- cloneReachableNodes(*I, BitsToClear, OldNodeMap, CompletedNodeMap);
-
- // Merge the map entries in OldNodeMap and CompletedNodeMap to remap links
- NodeMapTy MergedMap(OldNodeMap);
- MergedMap.insert(CompletedNodeMap.begin(), CompletedNodeMap.end());
-
- // Rewrite the links in the newly created nodes (the nodes in OldNodeMap)
- // to point into the current graph. MergedMap gives the full mapping.
- for (NodeMapTy::iterator I=OldNodeMap.begin(), E=OldNodeMap.end(); I!= E; ++I)
- I->second.getNode()->remapLinks(MergedMap);
-
- // Now merge cloned global nodes with their copies in the current graph
- // Just look through OldNodeMap to find such nodes!
- for (NodeMapTy::iterator I=OldNodeMap.begin(), E=OldNodeMap.end(); I!= E; ++I)
- if (I->first->isGlobalNode()) {
- DSNodeHandle &GClone = I->second;
- assert(GClone.getNode() != NULL && "NULL node in OldNodeMap?");
- const std::vector<GlobalValue*> &Globals = I->first->getGlobals();
- for (unsigned gi = 0, ge = Globals.size(); gi != ge; ++gi) {
- DSNodeHandle &GH = ScalarMap[Globals[gi]];
- GH.mergeWith(GClone);
- }
- }
-}
-
-
-/// updateFromGlobalGraph - This function rematerializes global nodes and
-/// nodes reachable from them from the globals graph into the current graph.
-/// It invokes cloneReachableSubgraph, using the globals in the current graph
-/// as the roots. It also uses the vector InlinedGlobals to avoid cloning and
-/// merging globals that are already up-to-date in the current graph. In
-/// practice, in the TD pass, this is likely to be a large fraction of the
-/// live global nodes in each function (since most live nodes are likely to
-/// have been brought up-to-date in at _some_ caller or callee).
-///
-void DSGraph::updateFromGlobalGraph() {
-
- // Use a map to keep track of the mapping between nodes in the globals graph
- // and this graph for up-to-date global nodes, which do not need to be cloned.
- NodeMapTy CompletedMap;
-
- // Put the live, non-up-to-date global nodes into a set and the up-to-date
- // ones in the map above, mapping node in GlobalsGraph to the up-to-date node.
- hash_set<const DSNode*> GlobalNodeSet;
- for (ScalarMapTy::const_iterator I = getScalarMap().begin(),
- E = getScalarMap().end(); I != E; ++I)
- if (GlobalValue* GV = dyn_cast<GlobalValue>(I->first)) {
- DSNode* GNode = I->second.getNode();
- assert(GNode && "No node for live global in current Graph?");
- if (const DSNode* GGNode = GlobalsGraph->ScalarMap[GV].getNode())
- if (InlinedGlobals.count(GV) == 0) // GNode is not up-to-date
- GlobalNodeSet.insert(GGNode);
- else { // GNode is up-to-date
- CompletedMap[GGNode] = I->second;
- assert(GGNode->getNumLinks() == GNode->getNumLinks() &&
- "Links dont match in a node that is supposed to be up-to-date?"
- "\nremapLinks() will not work if the links don't match!");
- }
- }
-
- // Clone the subgraph reachable from the vector of nodes in GlobalNodes
- // and merge the cloned global nodes with the corresponding ones, if any.
- NodeMapTy OldNodeMap;
- cloneReachableSubgraph(*GlobalsGraph, GlobalNodeSet, OldNodeMap,CompletedMap);
-
- // Merging global nodes leaves behind unused nodes: get rid of them now.
- OldNodeMap.clear(); // remove references before dead node cleanup
- CompletedMap.clear(); // remove references before dead node cleanup
- removeTriviallyDeadNodes();
-}
-
-/// cloneInto - Clone the specified DSGraph into the current graph. The
-/// translated ScalarMap for the old function is filled into the OldValMap
-/// member, and the translated ReturnNodes map is returned into ReturnNodes.
-///
-/// The CloneFlags member controls various aspects of the cloning process.
-///
-void DSGraph::cloneInto(const DSGraph &G, ScalarMapTy &OldValMap,
- ReturnNodesTy &OldReturnNodes, NodeMapTy &OldNodeMap,
- unsigned CloneFlags) {
- assert(OldNodeMap.empty() && "Returned OldNodeMap should be empty!");
- assert(&G != this && "Cannot clone graph into itself!");
-
- unsigned FN = Nodes.size(); // First new node...
-
- // Duplicate all of the nodes, populating the node map...
- Nodes.reserve(FN+G.Nodes.size());
-
- // Remove alloca or mod/ref bits as specified...
- unsigned BitsToClear = ((CloneFlags & StripAllocaBit)? DSNode::AllocaNode : 0)
- | ((CloneFlags & StripModRefBits)? (DSNode::Modified | DSNode::Read) : 0)
- | ((CloneFlags & StripIncompleteBit)? DSNode::Incomplete : 0);
- BitsToClear |= DSNode::DEAD; // Clear dead flag...
- for (unsigned i = 0, e = G.Nodes.size(); i != e; ++i) {
- DSNode *Old = G.Nodes[i];
- DSNode *New = new DSNode(*Old, this);
- New->maskNodeTypes(~BitsToClear);
- OldNodeMap[Old] = New;
- }
-
-#ifndef NDEBUG
- Timer::addPeakMemoryMeasurement();
-#endif
-
- // Rewrite the links in the new nodes to point into the current graph now.
- for (unsigned i = FN, e = Nodes.size(); i != e; ++i)
- Nodes[i]->remapLinks(OldNodeMap);
-
- // Copy the scalar map... merging all of the global nodes...
- for (ScalarMapTy::const_iterator I = G.ScalarMap.begin(),
- E = G.ScalarMap.end(); I != E; ++I) {
- DSNodeHandle &MappedNode = OldNodeMap[I->second.getNode()];
- DSNodeHandle &H = OldValMap[I->first];
- H.mergeWith(DSNodeHandle(MappedNode.getNode(),
- I->second.getOffset()+MappedNode.getOffset()));
-
- // If this is a global, add the global to this fn or merge if already exists
- if (GlobalValue* GV = dyn_cast<GlobalValue>(I->first)) {
- ScalarMap[GV].mergeWith(H);
- InlinedGlobals.insert(GV);
- }
- }
-
- if (!(CloneFlags & DontCloneCallNodes)) {
- // Copy the function calls list...
- unsigned FC = FunctionCalls.size(); // FirstCall
- FunctionCalls.reserve(FC+G.FunctionCalls.size());
- for (unsigned i = 0, ei = G.FunctionCalls.size(); i != ei; ++i)
- FunctionCalls.push_back(DSCallSite(G.FunctionCalls[i], OldNodeMap));
- }
-
- if (!(CloneFlags & DontCloneAuxCallNodes)) {
- // Copy the auxillary function calls list...
- unsigned FC = AuxFunctionCalls.size(); // FirstCall
- AuxFunctionCalls.reserve(FC+G.AuxFunctionCalls.size());
- for (unsigned i = 0, ei = G.AuxFunctionCalls.size(); i != ei; ++i)
- AuxFunctionCalls.push_back(DSCallSite(G.AuxFunctionCalls[i], OldNodeMap));
- }
-
- // Map the return node pointers over...
- for (ReturnNodesTy::const_iterator I = G.getReturnNodes().begin(),
- E = G.getReturnNodes().end(); I != E; ++I) {
- const DSNodeHandle &Ret = I->second;
- DSNodeHandle &MappedRet = OldNodeMap[Ret.getNode()];
- OldReturnNodes.insert(std::make_pair(I->first,
- DSNodeHandle(MappedRet.getNode(),
- MappedRet.getOffset()+Ret.getOffset())));
- }
-}
-
-/// mergeInGraph - The method is used for merging graphs together. If the
-/// argument graph is not *this, it makes a clone of the specified graph, then
-/// merges the nodes specified in the call site with the formal arguments in the
-/// graph.
-///
-void DSGraph::mergeInGraph(const DSCallSite &CS, Function &F,
- const DSGraph &Graph, unsigned CloneFlags) {
- ScalarMapTy OldValMap, *ScalarMap;
- DSNodeHandle RetVal;
-
- // If this is not a recursive call, clone the graph into this graph...
- if (&Graph != this) {
- // 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.
- NodeMapTy OldNodeMap;
-
- // The clone call may invalidate any of the vectors in the data
- // structure graph. Strip locals and don't copy the list of callers
- ReturnNodesTy OldRetNodes;
- cloneInto(Graph, OldValMap, OldRetNodes, OldNodeMap, CloneFlags);
-
- // We need to map the arguments for the function to the cloned nodes old
- // argument values. Do this now.
- RetVal = OldRetNodes[&F];
- ScalarMap = &OldValMap;
- } else {
- RetVal = getReturnNodeFor(F);
- ScalarMap = &getScalarMap();
- }
-
- // Merge the return value with the return value of the context...
- RetVal.mergeWith(CS.getRetVal());
-
- // Resolve all of the function arguments...
- Function::aiterator AI = F.abegin();
-
- for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i, ++AI) {
- // Advance the argument iterator to the first pointer argument...
- while (AI != F.aend() && !isPointerType(AI->getType())) {
- ++AI;
-#ifndef NDEBUG
- if (AI == F.aend())
- std::cerr << "Bad call to Function: " << F.getName() << "\n";
-#endif
- }
- if (AI == F.aend()) break;
-
- // Add the link from the argument scalar to the provided value
- assert(ScalarMap->count(AI) && "Argument not in scalar map?");
- DSNodeHandle &NH = (*ScalarMap)[AI];
- assert(NH.getNode() && "Pointer argument without scalarmap entry?");
- NH.mergeWith(CS.getPtrArg(i));
- }
-}
-
-/// getCallSiteForArguments - Get the arguments and return value bindings for
-/// the specified function in the current graph.
-///
-DSCallSite DSGraph::getCallSiteForArguments(Function &F) const {
- std::vector<DSNodeHandle> Args;
-
- for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I)
- if (isPointerType(I->getType()))
- Args.push_back(getScalarMap().find(I)->second);
-
- return DSCallSite(*(CallInst*)0, getReturnNodeFor(F), &F, Args);
-}
-
-
-
-// markIncompleteNodes - Mark the specified node as having contents that are not
-// known with the current analysis we have performed. Because a node makes all
-// of the nodes it can reach incomplete if the node itself is incomplete, we
-// must recursively traverse the data structure graph, marking all reachable
-// nodes as incomplete.
-//
-static void markIncompleteNode(DSNode *N) {
- // Stop recursion if no node, or if node already marked...
- if (N == 0 || N->isIncomplete()) return;
-
- // Actually mark the node
- N->setIncompleteMarker();
-
- // Recusively process children...
- for (unsigned i = 0, e = N->getSize(); i < e; i += DS::PointerSize)
- if (DSNode *DSN = N->getLink(i).getNode())
- markIncompleteNode(DSN);
-}
-
-static void markIncomplete(DSCallSite &Call) {
- // Then the return value is certainly incomplete!
- markIncompleteNode(Call.getRetVal().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());
-}
-
-// markIncompleteNodes - Traverse the graph, identifying nodes that may be
-// modified by other functions that have not been resolved yet. This marks
-// nodes that are reachable through three sources of "unknownness":
-//
-// Global Variables, Function Calls, and Incoming Arguments
-//
-// For any node that may have unknown components (because something outside the
-// scope of current analysis may have modified it), the 'Incomplete' flag is
-// added to the NodeType.
-//
-void DSGraph::markIncompleteNodes(unsigned Flags) {
- // Mark any incoming arguments as incomplete...
- if (Flags & DSGraph::MarkFormalArgs)
- for (ReturnNodesTy::iterator FI = ReturnNodes.begin(), E =ReturnNodes.end();
- FI != E; ++FI) {
- Function &F = *FI->first;
- if (F.getName() != "main")
- for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I)
- if (isPointerType(I->getType()) &&
- ScalarMap.find(I) != ScalarMap.end())
- markIncompleteNode(ScalarMap[I].getNode());
- }
-
- // Mark stuff passed into functions calls as being incomplete...
- if (!shouldPrintAuxCalls())
- for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
- markIncomplete(FunctionCalls[i]);
- else
- for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
- markIncomplete(AuxFunctionCalls[i]);
-
-
- // Mark all global nodes as incomplete...
- if ((Flags & DSGraph::IgnoreGlobals) == 0)
- for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
- if (Nodes[i]->isGlobalNode() && Nodes[i]->getNumLinks())
- markIncompleteNode(Nodes[i]);
-}
-
-static inline void killIfUselessEdge(DSNodeHandle &Edge) {
- if (DSNode *N = Edge.getNode()) // Is there an edge?
- if (N->getNumReferrers() == 1) // Does it point to a lonely node?
- // No interesting info?
- if ((N->getNodeFlags() & ~DSNode::Incomplete) == 0 &&
- N->getType() == Type::VoidTy && !N->isNodeCompletelyFolded())
- Edge.setNode(0); // Kill the edge!
-}
-
-static inline bool nodeContainsExternalFunction(const DSNode *N) {
- const std::vector<GlobalValue*> &Globals = N->getGlobals();
- for (unsigned i = 0, e = Globals.size(); i != e; ++i)
- if (Globals[i]->isExternal())
- return true;
- return false;
-}
-
-static void removeIdenticalCalls(std::vector<DSCallSite> &Calls) {
-
- // Remove trivially identical function calls
- unsigned NumFns = Calls.size();
- std::sort(Calls.begin(), Calls.end()); // Sort by callee as primary key!
-
- // Scan the call list cleaning it up as necessary...
- DSNode *LastCalleeNode = 0;
- Function *LastCalleeFunc = 0;
- unsigned NumDuplicateCalls = 0;
- bool LastCalleeContainsExternalFunction = false;
- for (unsigned i = 0; i != Calls.size(); ++i) {
- DSCallSite &CS = Calls[i];
-
- // If the Callee is a useless edge, this must be an unreachable call site,
- // eliminate it.
- if (CS.isIndirectCall() && CS.getCalleeNode()->getNumReferrers() == 1 &&
- CS.getCalleeNode()->getNodeFlags() == 0) { // No useful info?
- std::cerr << "WARNING: Useless call site found??\n";
- CS.swap(Calls.back());
- Calls.pop_back();
- --i;
- } else {
- // If the return value or any arguments point to a void node with no
- // information at all in it, and the call node is the only node to point
- // to it, remove the edge to the node (killing the node).
- //
- killIfUselessEdge(CS.getRetVal());
- for (unsigned a = 0, e = CS.getNumPtrArgs(); a != e; ++a)
- killIfUselessEdge(CS.getPtrArg(a));
-
- // If this call site calls the same function as the last call site, and if
- // the function pointer contains an external function, this node will
- // never be resolved. Merge the arguments of the call node because no
- // information will be lost.
- //
- if ((CS.isDirectCall() && CS.getCalleeFunc() == LastCalleeFunc) ||
- (CS.isIndirectCall() && CS.getCalleeNode() == LastCalleeNode)) {
- ++NumDuplicateCalls;
- if (NumDuplicateCalls == 1) {
- if (LastCalleeNode)
- LastCalleeContainsExternalFunction =
- nodeContainsExternalFunction(LastCalleeNode);
- else
- LastCalleeContainsExternalFunction = LastCalleeFunc->isExternal();
- }
-
-#if 1
- if (LastCalleeContainsExternalFunction ||
- // This should be more than enough context sensitivity!
- // FIXME: Evaluate how many times this is tripped!
- NumDuplicateCalls > 20) {
- DSCallSite &OCS = Calls[i-1];
- OCS.mergeWith(CS);
-
- // The node will now be eliminated as a duplicate!
- if (CS.getNumPtrArgs() < OCS.getNumPtrArgs())
- CS = OCS;
- else if (CS.getNumPtrArgs() > OCS.getNumPtrArgs())
- OCS = CS;
- }
-#endif
- } else {
- if (CS.isDirectCall()) {
- LastCalleeFunc = CS.getCalleeFunc();
- LastCalleeNode = 0;
- } else {
- LastCalleeNode = CS.getCalleeNode();
- LastCalleeFunc = 0;
- }
- NumDuplicateCalls = 0;
- }
- }
- }
-
- Calls.erase(std::unique(Calls.begin(), Calls.end()),
- Calls.end());
-
- // Track the number of call nodes merged away...
- NumCallNodesMerged += NumFns-Calls.size();
-
- DEBUG(if (NumFns != Calls.size())
- std::cerr << "Merged " << (NumFns-Calls.size()) << " call nodes.\n";);
-}
-
-
-// removeTriviallyDeadNodes - After the graph has been constructed, this method
-// removes all unreachable nodes that are created because they got merged with
-// other nodes in the graph. These nodes will all be trivially unreachable, so
-// we don't have to perform any non-trivial analysis here.
-//
-void DSGraph::removeTriviallyDeadNodes() {
- removeIdenticalCalls(FunctionCalls);
- removeIdenticalCalls(AuxFunctionCalls);
-
- bool isGlobalsGraph = !GlobalsGraph;
-
- for (unsigned i = 0; i != Nodes.size(); ++i) {
- DSNode *Node = Nodes[i];
-
- // Do not remove *any* global nodes in the globals graph.
- // This is a special case because such nodes may not have I, M, R flags set.
- if (Node->isGlobalNode() && isGlobalsGraph)
- continue;
-
- if (Node->isComplete() && !Node->isModified() && !Node->isRead()) {
- // This is a useless node if it has no mod/ref info (checked above),
- // outgoing edges (which it cannot, as it is not modified in this
- // context), and it has no incoming edges. If it is a global node it may
- // have all of these properties and still have incoming edges, due to the
- // scalar map, so we check those now.
- //
- if (Node->getNumReferrers() == Node->getGlobals().size()) {
- const std::vector<GlobalValue*> &Globals = Node->getGlobals();
-
- // Loop through and make sure all of the globals are referring directly
- // to the node...
- for (unsigned j = 0, e = Globals.size(); j != e; ++j) {
- DSNode *N = ScalarMap.find(Globals[j])->second.getNode();
- assert(N == Node && "ScalarMap doesn't match globals list!");
- }
-
- // Make sure NumReferrers still agrees, if so, the node is truly dead.
- if (Node->getNumReferrers() == Globals.size()) {
- for (unsigned j = 0, e = Globals.size(); j != e; ++j)
- ScalarMap.erase(Globals[j]);
- Node->makeNodeDead();
- }
- }
-
-#ifdef SANER_CODE_FOR_CHECKING_IF_ALL_REFERRERS_ARE_FROM_SCALARMAP
- //
- // *** It seems to me that we should be able to simply check if
- // *** there are fewer or equal #referrers as #globals and make
- // *** sure that all those referrers are in the scalar map?
- //
- if (Node->getNumReferrers() <= Node->getGlobals().size()) {
- const std::vector<GlobalValue*> &Globals = Node->getGlobals();
-
-#ifndef NDEBUG
- // Loop through and make sure all of the globals are referring directly
- // to the node...
- for (unsigned j = 0, e = Globals.size(); j != e; ++j) {
- DSNode *N = ScalarMap.find(Globals[j])->second.getNode();
- assert(N == Node && "ScalarMap doesn't match globals list!");
- }
-#endif
-
- // Make sure NumReferrers still agrees. The node is truly dead.
- assert(Node->getNumReferrers() == Globals.size());
- for (unsigned j = 0, e = Globals.size(); j != e; ++j)
- ScalarMap.erase(Globals[j]);
- Node->makeNodeDead();
- }
-#endif
- }
-
- if (Node->getNodeFlags() == 0 && Node->hasNoReferrers()) {
- // This node is dead!
- delete Node; // Free memory...
- Nodes[i--] = Nodes.back();
- Nodes.pop_back(); // Remove from node list...
- }
- }
-}
-
-
-/// markReachableNodes - This method recursively traverses the specified
-/// DSNodes, marking any nodes which are reachable. All reachable nodes it adds
-/// to the set, which allows it to only traverse visited nodes once.
-///
-void DSNode::markReachableNodes(hash_set<DSNode*> &ReachableNodes) {
- if (this == 0) return;
- assert(getForwardNode() == 0 && "Cannot mark a forwarded node!");
- if (ReachableNodes.count(this)) return; // Already marked reachable
- ReachableNodes.insert(this); // Is reachable now
-
- for (unsigned i = 0, e = getSize(); i < e; i += DS::PointerSize)
- getLink(i).getNode()->markReachableNodes(ReachableNodes);
-}
-
-void DSCallSite::markReachableNodes(hash_set<DSNode*> &Nodes) {
- getRetVal().getNode()->markReachableNodes(Nodes);
- if (isIndirectCall()) getCalleeNode()->markReachableNodes(Nodes);
-
- for (unsigned i = 0, e = getNumPtrArgs(); i != e; ++i)
- getPtrArg(i).getNode()->markReachableNodes(Nodes);
-}
-
-// CanReachAliveNodes - Simple graph walker that recursively traverses the graph
-// looking for a node that is marked alive. If an alive node is found, return
-// true, otherwise return false. If an alive node is reachable, this node is
-// marked as alive...
-//
-static bool CanReachAliveNodes(DSNode *N, hash_set<DSNode*> &Alive,
- hash_set<DSNode*> &Visited,
- bool IgnoreGlobals) {
- if (N == 0) return false;
- assert(N->getForwardNode() == 0 && "Cannot mark a forwarded node!");
-
- // If this is a global node, it will end up in the globals graph anyway, so we
- // don't need to worry about it.
- if (IgnoreGlobals && N->isGlobalNode()) return false;
-
- // If we know that this node is alive, return so!
- if (Alive.count(N)) return true;
-
- // Otherwise, we don't think the node is alive yet, check for infinite
- // recursion.
- if (Visited.count(N)) return false; // Found a cycle
- Visited.insert(N); // No recursion, insert into Visited...
-
- for (unsigned i = 0, e = N->getSize(); i < e; i += DS::PointerSize)
- if (CanReachAliveNodes(N->getLink(i).getNode(), Alive, Visited,
- IgnoreGlobals)) {
- N->markReachableNodes(Alive);
- return true;
- }
- return false;
-}
-
-// CallSiteUsesAliveArgs - Return true if the specified call site can reach any
-// alive nodes.
-//
-static bool CallSiteUsesAliveArgs(DSCallSite &CS, hash_set<DSNode*> &Alive,
- hash_set<DSNode*> &Visited,
- bool IgnoreGlobals) {
- if (CanReachAliveNodes(CS.getRetVal().getNode(), Alive, Visited,
- IgnoreGlobals))
- return true;
- if (CS.isIndirectCall() &&
- CanReachAliveNodes(CS.getCalleeNode(), Alive, Visited, IgnoreGlobals))
- return true;
- for (unsigned i = 0, e = CS.getNumPtrArgs(); i != e; ++i)
- if (CanReachAliveNodes(CS.getPtrArg(i).getNode(), Alive, Visited,
- IgnoreGlobals))
- return true;
- return false;
-}
-
-// removeDeadNodes - Use a more powerful reachability analysis to eliminate
-// subgraphs that are unreachable. This often occurs because the data
-// structure doesn't "escape" into it's caller, and thus should be eliminated
-// from the caller's graph entirely. This is only appropriate to use when
-// inlining graphs.
-//
-void DSGraph::removeDeadNodes(unsigned Flags) {
- DEBUG(AssertGraphOK(); GlobalsGraph->AssertGraphOK());
-
- // Reduce the amount of work we have to do... remove dummy nodes left over by
- // merging...
- removeTriviallyDeadNodes();
-
- // FIXME: Merge nontrivially identical call nodes...
-
- // Alive - a set that holds all nodes found to be reachable/alive.
- hash_set<DSNode*> Alive;
- std::vector<std::pair<Value*, DSNode*> > GlobalNodes;
-
- // Mark all nodes reachable by (non-global) scalar nodes as alive...
- for (ScalarMapTy::iterator I = ScalarMap.begin(), E = ScalarMap.end(); I !=E;)
- if (isa<GlobalValue>(I->first)) { // Keep track of global nodes
- assert(I->second.getNode() && "Null global node?");
- assert(I->second.getNode()->isGlobalNode() && "Should be a global node!");
- GlobalNodes.push_back(std::make_pair(I->first, I->second.getNode()));
- ++I;
- } else {
- // Check to see if this is a worthless node generated for non-pointer
- // values, such as integers. Consider an addition of long types: A+B.
- // Assuming we can track all uses of the value in this context, and it is
- // NOT used as a pointer, we can delete the node. We will be able to
- // detect this situation if the node pointed to ONLY has Unknown bit set
- // in the node. In this case, the node is not incomplete, does not point
- // to any other nodes (no mod/ref bits set), and is therefore
- // uninteresting for data structure analysis. If we run across one of
- // these, prune the scalar pointing to it.
- //
- DSNode *N = I->second.getNode();
- if (N->getNodeFlags() == DSNode::UnknownNode && !isa<Argument>(I->first)){
- ScalarMap.erase(I++);
- } else {
- I->second.getNode()->markReachableNodes(Alive);
- ++I;
- }
- }
-
- // The return value is alive as well...
- for (ReturnNodesTy::iterator I = ReturnNodes.begin(), E = ReturnNodes.end();
- I != E; ++I)
- I->second.getNode()->markReachableNodes(Alive);
-
- // Mark any nodes reachable by primary calls as alive...
- for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i)
- FunctionCalls[i].markReachableNodes(Alive);
-
- // Copy and merge all information about globals to the GlobalsGraph
- // if this is not a final pass (where unreachable globals are removed)
- NodeMapTy GlobalNodeMap;
- hash_set<const DSNode*> GlobalNodeSet;
-
- for (std::vector<std::pair<Value*, DSNode*> >::const_iterator
- I = GlobalNodes.begin(), E = GlobalNodes.end(); I != E; ++I)
- GlobalNodeSet.insert(I->second); // put global nodes into a set
-
- // Now find globals and aux call nodes that are already live or reach a live
- // value (which makes them live in turn), and continue till no more are found.
- //
- bool Iterate;
- hash_set<DSNode*> Visited;
- std::vector<unsigned char> AuxFCallsAlive(AuxFunctionCalls.size());
- do {
- Visited.clear();
- // If any global node points to a non-global that is "alive", the global is
- // "alive" as well... Remove it from the GlobalNodes list so we only have
- // unreachable globals in the list.
- //
- Iterate = false;
- if (!(Flags & DSGraph::RemoveUnreachableGlobals))
- for (unsigned i = 0; i != GlobalNodes.size(); ++i)
- if (CanReachAliveNodes(GlobalNodes[i].second, Alive, Visited,
- Flags & DSGraph::RemoveUnreachableGlobals)) {
- std::swap(GlobalNodes[i--], GlobalNodes.back()); // Move to end to...
- GlobalNodes.pop_back(); // erase efficiently
- Iterate = true;
- }
-
- // Mark only unresolvable call nodes for moving to the GlobalsGraph since
- // call nodes that get resolved will be difficult to remove from that graph.
- // The final unresolved call nodes must be handled specially at the end of
- // the BU pass (i.e., in main or other roots of the call graph).
- for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
- if (!AuxFCallsAlive[i] &&
- (AuxFunctionCalls[i].isIndirectCall()
- || CallSiteUsesAliveArgs(AuxFunctionCalls[i], Alive, Visited,
- Flags & DSGraph::RemoveUnreachableGlobals))) {
- AuxFunctionCalls[i].markReachableNodes(Alive);
- AuxFCallsAlive[i] = true;
- Iterate = true;
- }
- } while (Iterate);
-
- // Move dead aux function calls to the end of the list
- unsigned CurIdx = 0;
- for (unsigned i = 0, e = AuxFunctionCalls.size(); i != e; ++i)
- if (AuxFCallsAlive[i])
- AuxFunctionCalls[CurIdx++].swap(AuxFunctionCalls[i]);
-
- // Copy and merge all global nodes and dead aux call nodes into the
- // GlobalsGraph, and all nodes reachable from those nodes
- //
- if (!(Flags & DSGraph::RemoveUnreachableGlobals)) {
-
- // First, add the dead aux call nodes to the set of root nodes for cloning
- // -- return value at this call site, if any
- // -- actual arguments passed at this call site
- // -- callee node at this call site, if this is an indirect call
- for (unsigned i = CurIdx, e = AuxFunctionCalls.size(); i != e; ++i) {
- if (const DSNode* RetNode = AuxFunctionCalls[i].getRetVal().getNode())
- GlobalNodeSet.insert(RetNode);
- for (unsigned j=0, N=AuxFunctionCalls[i].getNumPtrArgs(); j < N; ++j)
- if (const DSNode* ArgTarget=AuxFunctionCalls[i].getPtrArg(j).getNode())
- GlobalNodeSet.insert(ArgTarget);
- if (AuxFunctionCalls[i].isIndirectCall())
- GlobalNodeSet.insert(AuxFunctionCalls[i].getCalleeNode());
- }
-
- // There are no "pre-completed" nodes so use any empty map for those.
- // Strip all alloca bits since the current function is only for the BU pass.
- // Strip all incomplete bits since they are short-lived properties and they
- // will be correctly computed when rematerializing nodes into the functions.
- //
- NodeMapTy CompletedMap;
- GlobalsGraph->cloneReachableSubgraph(*this, GlobalNodeSet,
- GlobalNodeMap, CompletedMap,
- (DSGraph::StripAllocaBit |
- DSGraph::StripIncompleteBit));
- }
-
- // Remove all dead aux function calls...
- if (!(Flags & DSGraph::RemoveUnreachableGlobals)) {
- assert(GlobalsGraph && "No globals graph available??");
-
- // Copy the unreachable call nodes to the globals graph, updating
- // their target pointers using the GlobalNodeMap
- for (unsigned i = CurIdx, e = AuxFunctionCalls.size(); i != e; ++i)
- GlobalsGraph->AuxFunctionCalls.push_back(DSCallSite(AuxFunctionCalls[i],
- GlobalNodeMap));
- }
- // Crop all the useless ones out...
- AuxFunctionCalls.erase(AuxFunctionCalls.begin()+CurIdx,
- AuxFunctionCalls.end());
-
- // We are finally done with the GlobalNodeMap so we can clear it and
- // then get rid of unused nodes in the GlobalsGraph produced by merging.
- GlobalNodeMap.clear();
- GlobalsGraph->removeTriviallyDeadNodes();
-
- // At this point, any nodes which are visited, but not alive, are nodes
- // which can be removed. Loop over all nodes, eliminating completely
- // unreachable nodes.
- //
- std::vector<DSNode*> DeadNodes;
- DeadNodes.reserve(Nodes.size());
- for (unsigned i = 0; i != Nodes.size(); ++i)
- if (!Alive.count(Nodes[i])) {
- DSNode *N = Nodes[i];
- Nodes[i--] = Nodes.back(); // move node to end of vector
- Nodes.pop_back(); // Erase node from alive list.
- DeadNodes.push_back(N);
- N->dropAllReferences();
- } else {
- assert(Nodes[i]->getForwardNode() == 0 && "Alive forwarded node?");
- }
-
- // Remove all unreachable globals from the ScalarMap.
- // If flag RemoveUnreachableGlobals is set, GlobalNodes has only dead nodes.
- // In either case, the dead nodes will not be in the set Alive.
- for (unsigned i = 0, e = GlobalNodes.size(); i != e; ++i) {
- assert(((Flags & DSGraph::RemoveUnreachableGlobals) ||
- !Alive.count(GlobalNodes[i].second)) && "huh? non-dead global");
- if (!Alive.count(GlobalNodes[i].second))
- ScalarMap.erase(GlobalNodes[i].first);
- }
-
- // Delete all dead nodes now since their referrer counts are zero.
- for (unsigned i = 0, e = DeadNodes.size(); i != e; ++i)
- delete DeadNodes[i];
-
- DEBUG(AssertGraphOK(); GlobalsGraph->AssertGraphOK());
-}
-
-void DSGraph::AssertGraphOK() const {
- for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
- Nodes[i]->assertOK();
-
- for (ScalarMapTy::const_iterator I = ScalarMap.begin(),
- E = ScalarMap.end(); I != E; ++I) {
- assert(I->second.getNode() && "Null node in scalarmap!");
- AssertNodeInGraph(I->second.getNode());
- if (GlobalValue *GV = dyn_cast<GlobalValue>(I->first)) {
- assert(I->second.getNode()->isGlobalNode() &&
- "Global points to node, but node isn't global?");
- AssertNodeContainsGlobal(I->second.getNode(), GV);
- }
- }
- AssertCallNodesInGraph();
- AssertAuxCallNodesInGraph();
-}
-
-/// mergeInGlobalsGraph - This method is useful for clients to incorporate the
-/// globals graph into the DS, BU or TD graph for a function. This code retains
-/// all globals, i.e., does not delete unreachable globals after they are
-/// inlined.
-///
-void DSGraph::mergeInGlobalsGraph() {
- NodeMapTy GlobalNodeMap;
- ScalarMapTy OldValMap;
- ReturnNodesTy OldRetNodes;
- cloneInto(*GlobalsGraph, OldValMap, OldRetNodes, GlobalNodeMap,
- DSGraph::KeepAllocaBit | DSGraph::DontCloneCallNodes |
- DSGraph::DontCloneAuxCallNodes);
-
- // Now merge existing global nodes in the GlobalsGraph with their copies
- for (ScalarMapTy::iterator I = ScalarMap.begin(), E = ScalarMap.end();
- I != E; ++I)
- if (isa<GlobalValue>(I->first)) { // Found a global node
- DSNodeHandle &GH = I->second;
- DSNodeHandle &GGNodeH = GlobalsGraph->getScalarMap()[I->first];
- GH.mergeWith(GlobalNodeMap[GGNodeH.getNode()]);
- }
-
- // Merging leaves behind unused nodes: get rid of them now.
- GlobalNodeMap.clear();
- OldValMap.clear();
- OldRetNodes.clear();
- removeTriviallyDeadNodes();
-}
diff --git a/poolalloc/lib/DSA/DataStructureAA.cpp b/poolalloc/lib/DSA/DataStructureAA.cpp
deleted file mode 100644
index e7e963a..0000000
--- a/poolalloc/lib/DSA/DataStructureAA.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-//===- DataStructureAA.cpp - Data Structure Based Alias Analysis ----------===//
-//
-// This pass uses the top-down data structure graphs to implement a simple
-// context sensitive alias analysis.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Analysis/AliasAnalysis.h"
-#include "llvm/Module.h"
-
-namespace {
- class DSAA : public Pass, public AliasAnalysis {
- TDDataStructures *TD;
- public:
- DSAA() : TD(0) {}
-
- //------------------------------------------------
- // Implement the Pass API
- //
-
- // run - Build up the result graph, representing the pointer graph for the
- // program.
- //
- bool run(Module &M) {
- InitializeAliasAnalysis(this);
- TD = &getAnalysis<TDDataStructures>();
- return false;
- }
-
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- AliasAnalysis::getAnalysisUsage(AU);
- AU.setPreservesAll(); // Does not transform code...
- AU.addRequired<TDDataStructures>(); // Uses TD Datastructures
- AU.addRequired<AliasAnalysis>(); // Chains to another AA impl...
- }
-
- //------------------------------------------------
- // Implement the AliasAnalysis API
- //
-
- AliasResult alias(const Value *V1, unsigned V1Size,
- const Value *V2, unsigned V2Size);
-
- void getMustAliases(Value *P, std::vector<Value*> &RetVals);
-
- private:
- DSGraph *getGraphForValue(const Value *V);
- };
-
- // Register the pass...
- RegisterOpt<DSAA> X("ds-aa", "Data Structure Graph Based Alias Analysis");
-
- // Register as an implementation of AliasAnalysis
- RegisterAnalysisGroup<AliasAnalysis, DSAA> Y;
-}
-
-// getGraphForValue - Return the DSGraph to use for queries about the specified
-// value...
-//
-DSGraph *DSAA::getGraphForValue(const Value *V) {
- if (const Instruction *I = dyn_cast<Instruction>(V))
- return &TD->getDSGraph(*I->getParent()->getParent());
- else if (const Argument *A = dyn_cast<Argument>(V))
- return &TD->getDSGraph(*A->getParent());
- else if (const BasicBlock *BB = dyn_cast<BasicBlock>(V))
- return &TD->getDSGraph(*BB->getParent());
- return 0;
-}
-
-// isSinglePhysicalObject - For now, the only case that we know that there is
-// only one memory object in the node is when there is a single global in the
-// node, and the only composition bit set is Global.
-//
-static bool isSinglePhysicalObject(DSNode *N) {
- assert(N->isComplete() && "Can only tell if this is a complete object!");
- return N->isGlobalNode() && N->getGlobals().size() == 1 &&
- !N->isHeapNode() && !N->isAllocaNode() && !N->isUnknownNode();
-}
-
-// alias - This is the only method here that does anything interesting...
-AliasAnalysis::AliasResult DSAA::alias(const Value *V1, unsigned V1Size,
- const Value *V2, unsigned V2Size) {
- if (V1 == V2) return MustAlias;
-
- DSGraph *G1 = getGraphForValue(V1);
- DSGraph *G2 = getGraphForValue(V2);
- assert((!G1 || !G2 || G1 == G2) && "Alias query for 2 different functions?");
-
- // Get the graph to use...
- DSGraph &G = *(G1 ? G1 : (G2 ? G2 : &TD->getGlobalsGraph()));
-
- const DSGraph::ScalarMapTy &GSM = G.getScalarMap();
- DSGraph::ScalarMapTy::const_iterator I = GSM.find((Value*)V1);
- if (I != GSM.end()) {
- assert(I->second.getNode() && "Scalar map points to null node?");
- DSGraph::ScalarMapTy::const_iterator J = GSM.find((Value*)V2);
- if (J != GSM.end()) {
- assert(J->second.getNode() && "Scalar map points to null node?");
-
- DSNode *N1 = I->second.getNode(), *N2 = J->second.getNode();
- unsigned O1 = I->second.getOffset(), O2 = J->second.getOffset();
-
- // We can only make a judgement of one of the nodes is complete...
- if (N1->isComplete() || N2->isComplete()) {
- if (N1 != N2)
- return NoAlias; // Completely different nodes.
-
-#if 0 // This does not correctly handle arrays!
- // Both point to the same node and same offset, and there is only one
- // physical memory object represented in the node, return must alias.
- //
- // FIXME: This isn't correct because we do not handle array indexing
- // correctly.
-
- if (O1 == O2 && isSinglePhysicalObject(N1))
- return MustAlias; // Exactly the same object & offset
-#endif
-
- // See if they point to different offsets... if so, we may be able to
- // determine that they do not alias...
- if (O1 != O2) {
- if (O2 < O1) { // Ensure that O1 <= O2
- std::swap(V1, V2);
- std::swap(O1, O2);
- std::swap(V1Size, V2Size);
- }
-
- // FIXME: This is not correct because we do not handle array
- // indexing correctly with this check!
- //if (O1+V1Size <= O2) return NoAlias;
- }
- }
- }
- }
-
- // FIXME: we could improve on this by checking the globals graph for aliased
- // global queries...
- return getAnalysis<AliasAnalysis>().alias(V1, V1Size, V2, V2Size);
-}
-
-
-/// getMustAliases - If there are any pointers known that must alias this
-/// pointer, return them now. This allows alias-set based alias analyses to
-/// perform a form a value numbering (which is exposed by load-vn). If an alias
-/// analysis supports this, it should ADD any must aliased pointers to the
-/// specified vector.
-///
-void DSAA::getMustAliases(Value *P, std::vector<Value*> &RetVals) {
-#if 0 // This does not correctly handle arrays!
- // Currently the only must alias information we can provide is to say that
- // something is equal to a global value. If we already have a global value,
- // don't get worked up about it.
- if (!isa<GlobalValue>(P)) {
- DSGraph *G = getGraphForValue(P);
- if (!G) G = &TD->getGlobalsGraph();
-
- // The only must alias information we can currently determine occurs when
- // the node for P is a global node with only one entry.
- const DSGraph::ScalarMapTy &GSM = G->getScalarMap();
- DSGraph::ScalarMapTy::const_iterator I = GSM.find(P);
- if (I != GSM.end()) {
- DSNode *N = I->second.getNode();
- if (N->isComplete() && isSinglePhysicalObject(N))
- RetVals.push_back(N->getGlobals()[0]);
- }
- }
-#endif
- return getAnalysis<AliasAnalysis>().getMustAliases(P, RetVals);
-}
diff --git a/poolalloc/lib/DSA/DataStructureOpt.cpp b/poolalloc/lib/DSA/DataStructureOpt.cpp
deleted file mode 100644
index 297979a..0000000
--- a/poolalloc/lib/DSA/DataStructureOpt.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-//===- DataStructureOpt.cpp - Data Structure Analysis Based Optimizations -===//
-//
-// This pass uses DSA to a series of simple optimizations, like marking
-// unwritten global variables 'constant'.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Module.h"
-#include "llvm/Constant.h"
-#include "Support/Statistic.h"
-
-namespace {
- Statistic<>
- NumGlobalsConstanted("ds-opt", "Number of globals marked constant");
- Statistic<>
- NumGlobalsIsolated("ds-opt", "Number of globals with references dropped");
-
- class DSOpt : public Pass {
- TDDataStructures *TD;
- public:
- bool run(Module &M) {
- TD = &getAnalysis<TDDataStructures>();
- bool Changed = OptimizeGlobals(M);
- return Changed;
- }
-
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<TDDataStructures>(); // Uses TD Datastructures
- AU.addPreserved<LocalDataStructures>(); // Preserves local...
- AU.addPreserved<TDDataStructures>(); // Preserves bu...
- AU.addPreserved<BUDataStructures>(); // Preserves td...
- }
-
- private:
- bool OptimizeGlobals(Module &M);
- };
-
- RegisterOpt<DSOpt> X("ds-opt", "DSA-based simple optimizations");
-}
-
-
-/// OptimizeGlobals - This method uses information taken from DSA to optimize
-/// global variables.
-///
-bool DSOpt::OptimizeGlobals(Module &M) {
- DSGraph &GG = TD->getGlobalsGraph();
- const DSGraph::ScalarMapTy &SM = GG.getScalarMap();
- bool Changed = false;
-
- for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I)
- if (!I->isExternal()) { // Loop over all of the non-external globals...
- // Look up the node corresponding to this global, if it exists.
- DSNode *GNode = 0;
- DSGraph::ScalarMapTy::const_iterator SMI = SM.find(I);
- if (SMI != SM.end()) GNode = SMI->second.getNode();
-
- if (GNode == 0 && I->hasInternalLinkage()) {
- // If there is no entry in the scalar map for this global, it was never
- // referenced in the program. If it has internal linkage, that means we
- // can delete it. We don't ACTUALLY want to delete the global, just
- // remove anything that references the global: later passes will take
- // care of nuking it.
- if (!I->use_empty()) {
- I->replaceAllUsesWith(Constant::getNullValue((Type*)I->getType()));
- ++NumGlobalsIsolated;
- }
- } else if (GNode && GNode->isComplete()) {
-
- // If the node has not been read or written, and it is not externally
- // visible, kill any references to it so it can be DCE'd.
- if (!GNode->isModified() && !GNode->isRead() &&I->hasInternalLinkage()){
- if (!I->use_empty()) {
- I->replaceAllUsesWith(Constant::getNullValue((Type*)I->getType()));
- ++NumGlobalsIsolated;
- }
- }
-
- // We expect that there will almost always be a node for this global.
- // If there is, and the node doesn't have the M bit set, we can set the
- // 'constant' bit on the global.
- if (!GNode->isModified() && !I->isConstant()) {
- I->setConstant(true);
- ++NumGlobalsConstanted;
- Changed = true;
- }
- }
- }
- return Changed;
-}
diff --git a/poolalloc/lib/DSA/DataStructureStats.cpp b/poolalloc/lib/DSA/DataStructureStats.cpp
deleted file mode 100644
index c2ca7ea..0000000
--- a/poolalloc/lib/DSA/DataStructureStats.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-//===- DSGraphStats.cpp - Various statistics for DS Graphs -----*- C++ -*--===//
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Function.h"
-#include "llvm/iOther.h"
-#include "llvm/Pass.h"
-#include "Support/Statistic.h"
-#include <vector>
-
-namespace {
- Statistic<> TotalNumCallees("totalcallees",
- "Total number of callee functions at all indirect call sites");
- Statistic<> NumIndirectCalls("numindirect",
- "Total number of indirect call sites in the program");
- Statistic<> NumPoolNodes("numpools",
- "Number of allocation nodes that could be pool allocated");
-
- class DSGraphStats: public FunctionPass {
- void countCallees(const Function& F, const DSGraph& tdGraph);
-
- public:
- /// Driver functions to compute the Load/Store Dep. Graph per function.
- bool runOnFunction(Function& F);
-
- /// getAnalysisUsage - This modify nothing, and uses the Top-Down Graph.
- void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.setPreservesAll();
- AU.addRequired<TDDataStructures>();
- }
-
- /// Debugging support methods
- void print(std::ostream &O) const { }
- void dump() const;
- };
-
- static RegisterAnalysis<DSGraphStats> Z("dsstats", "DS Graph Statistics");
-}
-
-static bool isIndirectCallee(Value *V) {
- if (isa<Function>(V)) return false;
-
- if (CastInst *CI = dyn_cast<CastInst>(V))
- return isIndirectCallee(CI->getOperand(0));
- return true;
-}
-
-
-void DSGraphStats::countCallees(const Function& F, const DSGraph& tdGraph) {
- unsigned numIndirectCalls = 0, totalNumCallees = 0;
-
- const std::vector<DSCallSite>& callSites = tdGraph.getFunctionCalls();
- for (unsigned i=0, N = callSites.size(); i < N; ++i)
- if (isIndirectCallee(callSites[i].getCallInst().getCalledValue()))
- { // This is an indirect function call
- std::vector<GlobalValue*> Callees =
- callSites[i].getCalleeNode()->getGlobals();
- if (Callees.size() > 0) {
- totalNumCallees += Callees.size();
- ++numIndirectCalls;
- }
-#ifndef NDEBUG
- else
- std::cerr << "WARNING: No callee in Function " << F.getName()
- << "at call:\n" << callSites[i].getCallInst();
-#endif
- }
-
- TotalNumCallees += totalNumCallees;
- NumIndirectCalls += numIndirectCalls;
-
- if (numIndirectCalls)
- std::cout << " In function " << F.getName() << ": "
- << (totalNumCallees / (double) numIndirectCalls)
- << " average callees per indirect call\n";
-}
-
-
-bool DSGraphStats::runOnFunction(Function& F) {
- const DSGraph& tdGraph = getAnalysis<TDDataStructures>().getDSGraph(F);
- countCallees(F, tdGraph);
- return true;
-}
-
-void DSGraphStats::dump() const
-{
- this->print(std::cerr);
-}
diff --git a/poolalloc/lib/DSA/GraphChecker.cpp b/poolalloc/lib/DSA/GraphChecker.cpp
deleted file mode 100644
index 4c690b1..0000000
--- a/poolalloc/lib/DSA/GraphChecker.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-//===- GraphChecker.cpp - Assert that various graph properties hold -------===//
-//
-// This pass is used to test DSA with regression tests. It can be used to check
-// that certain graph properties hold, such as two nodes being disjoint, whether
-// or not a node is collapsed, etc. These are the command line arguments that
-// it supports:
-//
-// --dsgc-dsapass={local,bu,td} - Specify what flavor of graph to check
-// --dsgc-abort-if-any-collapsed - Abort if any collapsed nodes are found
-// --dsgc-abort-if-collapsed=<list> - Abort if a node pointed to by an SSA
-// value with name in <list> is collapsed
-// --dsgc-check-flags=<list> - Abort if the specified nodes have flags
-// that are not specified.
-// --dsgc-abort-if-merged=<list> - Abort if any of the named SSA values
-// point to the same node.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "Support/CommandLine.h"
-#include "llvm/Value.h"
-#include <set>
-
-namespace {
- enum DSPass { local, bu, td };
- cl::opt<DSPass>
- DSPass("dsgc-dspass", cl::Hidden,
- cl::desc("Specify which DSA pass the -datastructure-gc pass should use"),
- cl::values(clEnumVal(local, "Local pass"),
- clEnumVal(bu, "Bottom-up pass"),
- clEnumVal(td, "Top-down pass"), 0), cl::init(local));
-
- cl::opt<bool>
- AbortIfAnyCollapsed("dsgc-abort-if-any-collapsed", cl::Hidden,
- cl::desc("Abort if any collapsed nodes are found"));
- cl::list<std::string>
- AbortIfCollapsed("dsgc-abort-if-collapsed", cl::Hidden, cl::CommaSeparated,
- cl::desc("Abort if any of the named symbols is collapsed"));
- cl::list<std::string>
- CheckFlags("dsgc-check-flags", cl::Hidden, cl::CommaSeparated,
- cl::desc("Check that flags are specified for nodes"));
- cl::list<std::string>
- AbortIfMerged("dsgc-abort-if-merged", cl::Hidden, cl::CommaSeparated,
- cl::desc("Abort if any of the named symbols are merged together"));
-
- struct DSGC : public FunctionPass {
- DSGC();
- bool doFinalization(Module &M);
- bool runOnFunction(Function &F);
-
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- switch (DSPass) {
- case local: AU.addRequired<LocalDataStructures>(); break;
- case bu: AU.addRequired<BUDataStructures>(); break;
- case td: AU.addRequired<TDDataStructures>(); break;
- }
- AU.setPreservesAll();
- }
- void print(std::ostream &O, const Module *M) const {}
-
- private:
- void verify(const DSGraph &G);
- };
-
- RegisterAnalysis<DSGC> X("datastructure-gc", "DSA Graph Checking Pass");
-}
-
-DSGC::DSGC() {
- if (!AbortIfAnyCollapsed && AbortIfCollapsed.empty() &&
- CheckFlags.empty() && AbortIfMerged.empty()) {
- std::cerr << "The -datastructure-gc is useless if you don't specify any"
- " -dsgc-* options. See the -help-hidden output for a list.\n";
- abort();
- }
-}
-
-
-/// doFinalization - Verify that the globals graph is in good shape...
-///
-bool DSGC::doFinalization(Module &M) {
- switch (DSPass) {
- case local:verify(getAnalysis<LocalDataStructures>().getGlobalsGraph());break;
- case bu: verify(getAnalysis<BUDataStructures>().getGlobalsGraph()); break;
- case td: verify(getAnalysis<TDDataStructures>().getGlobalsGraph()); break;
- }
- return false;
-}
-
-/// runOnFunction - Get the DSGraph for this function and verify that it is ok.
-///
-bool DSGC::runOnFunction(Function &F) {
- switch (DSPass) {
- case local: verify(getAnalysis<LocalDataStructures>().getDSGraph(F)); break;
- case bu: verify(getAnalysis<BUDataStructures>().getDSGraph(F)); break;
- case td: verify(getAnalysis<TDDataStructures>().getDSGraph(F)); break;
- }
-
- return false;
-}
-
-/// verify - This is the function which checks to make sure that all of the
-/// invariants established on the command line are true.
-///
-void DSGC::verify(const DSGraph &G) {
- // Loop over all of the nodes, checking to see if any are collapsed...
- if (AbortIfAnyCollapsed) {
- const std::vector<DSNode*> &Nodes = G.getNodes();
- for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
- if (Nodes[i]->isNodeCompletelyFolded()) {
- std::cerr << "Node is collapsed: ";
- Nodes[i]->print(std::cerr, &G);
- abort();
- }
- }
-
- if (!AbortIfCollapsed.empty() || !CheckFlags.empty() ||
- !AbortIfMerged.empty()) {
- // Convert from a list to a set, because we don't have cl::set's yet. FIXME
- std::set<std::string> AbortIfCollapsedS(AbortIfCollapsed.begin(),
- AbortIfCollapsed.end());
- std::set<std::string> AbortIfMergedS(AbortIfMerged.begin(),
- AbortIfMerged.end());
- std::map<std::string, unsigned> CheckFlagsM;
-
- for (cl::list<std::string>::iterator I = CheckFlags.begin(),
- E = CheckFlags.end(); I != E; ++I) {
- unsigned ColonPos = I->rfind(':');
- if (ColonPos == std::string::npos) {
- std::cerr << "Error: '" << *I
- << "' is an invalid value for the --dsgc-check-flags option!\n";
- abort();
- }
-
- unsigned Flags = 0;
- for (unsigned C = ColonPos+1; C != I->size(); ++C)
- switch ((*I)[C]) {
- case 'S': Flags |= DSNode::AllocaNode; break;
- case 'H': Flags |= DSNode::HeapNode; break;
- case 'G': Flags |= DSNode::GlobalNode; break;
- case 'U': Flags |= DSNode::UnknownNode; break;
- case 'I': Flags |= DSNode::Incomplete; break;
- case 'M': Flags |= DSNode::Modified; break;
- case 'R': Flags |= DSNode::Read; break;
- case 'A': Flags |= DSNode::Array; break;
- default: std::cerr << "Invalid DSNode flag!\n"; abort();
- }
- CheckFlagsM[std::string(I->begin(), I->begin()+ColonPos)] = Flags;
- }
-
- // Now we loop over all of the scalars, checking to see if any are collapsed
- // that are not supposed to be, or if any are merged together.
- const DSGraph::ScalarMapTy &SM = G.getScalarMap();
- std::map<DSNode*, std::string> AbortIfMergedNodes;
-
- for (DSGraph::ScalarMapTy::const_iterator I = SM.begin(), E = SM.end();
- I != E; ++I)
- if (I->first->hasName() && I->second.getNode()) {
- const std::string &Name = I->first->getName();
- DSNode *N = I->second.getNode();
-
- // Verify it is not collapsed if it is not supposed to be...
- if (N->isNodeCompletelyFolded() && AbortIfCollapsedS.count(Name)) {
- std::cerr << "Node for value '%" << Name << "' is collapsed: ";
- N->print(std::cerr, &G);
- abort();
- }
-
- if (CheckFlagsM.count(Name) && CheckFlagsM[Name] != N->getNodeFlags()) {
- std::cerr << "Node flags are not as expected for node: " << Name
- << "\n";
- N->print(std::cerr, &G);
- abort();
- }
-
- // Verify that it is not merged if it is not supposed to be...
- if (AbortIfMergedS.count(Name)) {
- if (AbortIfMergedNodes.count(N)) {
- std::cerr << "Nodes for values '%" << Name << "' and '%"
- << AbortIfMergedNodes[N] << "' is merged: ";
- N->print(std::cerr, &G);
- abort();
- }
- AbortIfMergedNodes[N] = Name;
- }
- }
- }
-}
diff --git a/poolalloc/lib/DSA/IPModRef.cpp b/poolalloc/lib/DSA/IPModRef.cpp
deleted file mode 100644
index 86bddc8..0000000
--- a/poolalloc/lib/DSA/IPModRef.cpp
+++ /dev/null
@@ -1,439 +0,0 @@
-//===- IPModRef.cpp - Compute IP Mod/Ref information ------------*- C++ -*-===//
-//
-// See high-level comments in include/llvm/Analysis/IPModRef.h
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/IPModRef.h"
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Module.h"
-#include "llvm/Function.h"
-#include "llvm/iMemory.h"
-#include "llvm/iOther.h"
-#include "Support/Statistic.h"
-#include "Support/STLExtras.h"
-#include "Support/StringExtras.h"
-#include <vector>
-
-//----------------------------------------------------------------------------
-// Private constants and data
-//----------------------------------------------------------------------------
-
-static RegisterAnalysis<IPModRef>
-Z("ipmodref", "Interprocedural mod/ref analysis");
-
-
-//----------------------------------------------------------------------------
-// class ModRefInfo
-//----------------------------------------------------------------------------
-
-void ModRefInfo::print(std::ostream &O,
- const std::string& sprefix) const
-{
- O << sprefix << "Modified nodes = " << modNodeSet;
- O << sprefix << "Referenced nodes = " << refNodeSet;
-}
-
-void ModRefInfo::dump() const
-{
- print(std::cerr);
-}
-
-//----------------------------------------------------------------------------
-// class FunctionModRefInfo
-//----------------------------------------------------------------------------
-
-
-// This constructor computes a node numbering for the TD graph.
-//
-FunctionModRefInfo::FunctionModRefInfo(const Function& func,
- IPModRef& ipmro,
- DSGraph* tdgClone)
- : F(func), IPModRefObj(ipmro),
- funcTDGraph(tdgClone),
- funcModRefInfo(tdgClone->getGraphSize())
-{
- for (unsigned i=0, N = funcTDGraph->getGraphSize(); i < N; ++i)
- NodeIds[funcTDGraph->getNodes()[i]] = i;
-}
-
-
-FunctionModRefInfo::~FunctionModRefInfo()
-{
- for(std::map<const CallInst*, ModRefInfo*>::iterator
- I=callSiteModRefInfo.begin(), E=callSiteModRefInfo.end(); I != E; ++I)
- delete(I->second);
-
- // Empty map just to make problems easier to track down
- callSiteModRefInfo.clear();
-
- delete funcTDGraph;
-}
-
-unsigned FunctionModRefInfo::getNodeId(const Value* value) const {
- return getNodeId(funcTDGraph->getNodeForValue(const_cast<Value*>(value))
- .getNode());
-}
-
-
-
-// Compute Mod/Ref bit vectors for the entire function.
-// These are simply copies of the Read/Write flags from the nodes of
-// the top-down DS graph.
-//
-void FunctionModRefInfo::computeModRef(const Function &func)
-{
- // Mark all nodes in the graph that are marked MOD as being mod
- // and all those marked REF as being ref.
- for (unsigned i = 0, N = funcTDGraph->getGraphSize(); i < N; ++i)
- {
- if (funcTDGraph->getNodes()[i]->isModified())
- funcModRefInfo.setNodeIsMod(i);
- if (funcTDGraph->getNodes()[i]->isRead())
- funcModRefInfo.setNodeIsRef(i);
- }
-
- // Compute the Mod/Ref info for all call sites within the function.
- // The call sites are recorded in the TD graph.
- const std::vector<DSCallSite>& callSites = funcTDGraph->getFunctionCalls();
- for (unsigned i = 0, N = callSites.size(); i < N; ++i)
- computeModRef(callSites[i].getCallInst());
-}
-
-
-// ResolveCallSiteModRefInfo - This method performs the following actions:
-//
-// 1. It clones the top-down graph for the current function
-// 2. It clears all of the mod/ref bits in the cloned graph
-// 3. It then merges the bottom-up graph(s) for the specified call-site into
-// the clone (bringing new mod/ref bits).
-// 4. It returns the clone, and a mapping of nodes from the original TDGraph to
-// the cloned graph with Mod/Ref info for the callsite.
-//
-// NOTE: Because this clones a dsgraph and returns it, the caller is responsible
-// for deleting the returned graph!
-// NOTE: This method may return a null pointer if it is unable to determine the
-// requested information (because the call site calls an external
-// function or we cannot determine the complete set of functions invoked).
-//
-DSGraph* FunctionModRefInfo::ResolveCallSiteModRefInfo(CallInst &CI,
- hash_map<const DSNode*, DSNodeHandle> &NodeMap)
-{
- // Step #0: Quick check if we are going to fail anyway: avoid
- // all the graph cloning and map copying in steps #1 and #2.
- //
- if (const Function *F = CI.getCalledFunction())
- {
- if (F->isExternal())
- return 0; // We cannot compute Mod/Ref info for this callsite...
- }
- else
- {
- // Eventually, should check here if any callee is external.
- // For now we are not handling this case anyway.
- std::cerr << "IP Mod/Ref indirect call not implemented yet: "
- << "Being conservative\n";
- return 0; // We cannot compute Mod/Ref info for this callsite...
- }
-
- // Step #1: Clone the top-down graph...
- DSGraph *Result = new DSGraph(*funcTDGraph, NodeMap);
-
- // Step #2: Clear Mod/Ref information...
- Result->maskNodeTypes(~(DSNode::Modified | DSNode::Read));
-
- // Step #3: clone the bottom up graphs for the callees into the caller graph
- if (Function *F = CI.getCalledFunction())
- {
- assert(!F->isExternal());
-
- // Build up a DSCallSite for our invocation point here...
-
- // If the call returns a value, make sure to merge the nodes...
- DSNodeHandle RetVal;
- if (DS::isPointerType(CI.getType()))
- RetVal = Result->getNodeForValue(&CI);
-
- // Populate the arguments list...
- std::vector<DSNodeHandle> Args;
- for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i)
- if (DS::isPointerType(CI.getOperand(i)->getType()))
- Args.push_back(Result->getNodeForValue(CI.getOperand(i)));
-
- // Build the call site...
- DSCallSite CS(CI, RetVal, F, Args);
-
- // Perform the merging now of the graph for the callee, which will
- // come with mod/ref bits set...
- Result->mergeInGraph(CS, *F, IPModRefObj.getBUDSGraph(*F),
- DSGraph::StripAllocaBit
- | DSGraph::DontCloneCallNodes
- | DSGraph::DontCloneAuxCallNodes);
- }
- else
- assert(0 && "See error message");
-
- // Remove dead nodes aggressively to match the caller's original graph.
- Result->removeDeadNodes(DSGraph::KeepUnreachableGlobals);
-
- // Step #4: Return the clone + the mapping (by ref)
- return Result;
-}
-
-// Compute Mod/Ref bit vectors for a single call site.
-// These are copies of the Read/Write flags from the nodes of
-// the graph produced by clearing all flags in teh caller's TD graph
-// and then inlining the callee's BU graph into the caller's TD graph.
-//
-void
-FunctionModRefInfo::computeModRef(const CallInst& callInst)
-{
- // Allocate the mod/ref info for the call site. Bits automatically cleared.
- ModRefInfo* callModRefInfo = new ModRefInfo(funcTDGraph->getGraphSize());
- callSiteModRefInfo[&callInst] = callModRefInfo;
-
- // Get a copy of the graph for the callee with the callee inlined
- hash_map<const DSNode*, DSNodeHandle> NodeMap;
- DSGraph* csgp = ResolveCallSiteModRefInfo(const_cast<CallInst&>(callInst),
- NodeMap);
- if (!csgp)
- { // Callee's side effects are unknown: mark all nodes Mod and Ref.
- // Eventually this should only mark nodes visible to the callee, i.e.,
- // exclude stack variables not reachable from any outgoing argument
- // or any global.
- callModRefInfo->getModSet().set();
- callModRefInfo->getRefSet().set();
- return;
- }
-
- // For all nodes in the graph, extract the mod/ref information
- const std::vector<DSNode*>& csgNodes = csgp->getNodes();
- const std::vector<DSNode*>& origNodes = funcTDGraph->getNodes();
- assert(csgNodes.size() == origNodes.size());
- for (unsigned i=0, N = origNodes.size(); i < N; ++i)
- {
- DSNode* csgNode = NodeMap[origNodes[i]].getNode();
- assert(csgNode && "Inlined and original graphs do not correspond!");
- if (csgNode->isModified())
- callModRefInfo->setNodeIsMod(getNodeId(origNodes[i]));
- if (csgNode->isRead())
- callModRefInfo->setNodeIsRef(getNodeId(origNodes[i]));
- }
-
- // Drop nodemap before we delete the graph...
- NodeMap.clear();
- delete csgp;
-}
-
-
-class DSGraphPrintHelper {
- const DSGraph& tdGraph;
- std::vector<std::vector<const Value*> > knownValues; // identifiable objects
-
-public:
- /*ctor*/ DSGraphPrintHelper(const FunctionModRefInfo& fmrInfo)
- : tdGraph(fmrInfo.getFuncGraph())
- {
- knownValues.resize(tdGraph.getGraphSize());
-
- // For every identifiable value, save Value pointer in knownValues[i]
- for (hash_map<Value*, DSNodeHandle>::const_iterator
- I = tdGraph.getScalarMap().begin(),
- E = tdGraph.getScalarMap().end(); I != E; ++I)
- if (isa<GlobalValue>(I->first) ||
- isa<Argument>(I->first) ||
- isa<LoadInst>(I->first) ||
- isa<AllocaInst>(I->first) ||
- isa<MallocInst>(I->first))
- {
- unsigned nodeId = fmrInfo.getNodeId(I->second.getNode());
- knownValues[nodeId].push_back(I->first);
- }
- }
-
- void printValuesInBitVec(std::ostream &O, const BitSetVector& bv) const
- {
- assert(bv.size() == knownValues.size());
-
- if (bv.none())
- { // No bits are set: just say so and return
- O << "\tNONE.\n";
- return;
- }
-
- if (bv.all())
- { // All bits are set: just say so and return
- O << "\tALL GRAPH NODES.\n";
- return;
- }
-
- for (unsigned i=0, N=bv.size(); i < N; ++i)
- if (bv.test(i))
- {
- O << "\tNode# " << i << " : ";
- if (! knownValues[i].empty())
- for (unsigned j=0, NV=knownValues[i].size(); j < NV; j++)
- {
- const Value* V = knownValues[i][j];
-
- if (isa<GlobalValue>(V)) O << "(Global) ";
- else if (isa<Argument>(V)) O << "(Target of FormalParm) ";
- else if (isa<LoadInst>(V)) O << "(Target of LoadInst ) ";
- else if (isa<AllocaInst>(V)) O << "(Target of AllocaInst) ";
- else if (isa<MallocInst>(V)) O << "(Target of MallocInst) ";
-
- if (V->hasName()) O << V->getName();
- else if (isa<Instruction>(V)) O << *V;
- else O << "(Value*) 0x" << (void*) V;
-
- O << std::string((j < NV-1)? "; " : "\n");
- }
- else
- tdGraph.getNodes()[i]->print(O, /*graph*/ NULL);
- }
- }
-};
-
-
-// Print the results of the pass.
-// Currently this just prints bit-vectors and is not very readable.
-//
-void FunctionModRefInfo::print(std::ostream &O) const
-{
- DSGraphPrintHelper DPH(*this);
-
- O << "========== Mod/ref information for function "
- << F.getName() << "========== \n\n";
-
- // First: Print Globals and Locals modified anywhere in the function.
- //
- O << " -----Mod/Ref in the body of function " << F.getName()<< ":\n";
-
- O << " --Objects modified in the function body:\n";
- DPH.printValuesInBitVec(O, funcModRefInfo.getModSet());
-
- O << " --Objects referenced in the function body:\n";
- DPH.printValuesInBitVec(O, funcModRefInfo.getRefSet());
-
- O << " --Mod and Ref vectors for the nodes listed above:\n";
- funcModRefInfo.print(O, "\t");
-
- O << "\n";
-
- // Second: Print Globals and Locals modified at each call site in function
- //
- for (std::map<const CallInst*, ModRefInfo*>::const_iterator
- CI = callSiteModRefInfo.begin(), CE = callSiteModRefInfo.end();
- CI != CE; ++CI)
- {
- O << " ----Mod/Ref information for call site\n" << CI->first;
-
- O << " --Objects modified at call site:\n";
- DPH.printValuesInBitVec(O, CI->second->getModSet());
-
- O << " --Objects referenced at call site:\n";
- DPH.printValuesInBitVec(O, CI->second->getRefSet());
-
- O << " --Mod and Ref vectors for the nodes listed above:\n";
- CI->second->print(O, "\t");
-
- O << "\n";
- }
-
- O << "\n";
-}
-
-void FunctionModRefInfo::dump() const
-{
- print(std::cerr);
-}
-
-
-//----------------------------------------------------------------------------
-// class IPModRef: An interprocedural pass that computes IP Mod/Ref info.
-//----------------------------------------------------------------------------
-
-// Free the FunctionModRefInfo objects cached in funcToModRefInfoMap.
-//
-void IPModRef::releaseMemory()
-{
- for(std::map<const Function*, FunctionModRefInfo*>::iterator
- I=funcToModRefInfoMap.begin(), E=funcToModRefInfoMap.end(); I != E; ++I)
- delete(I->second);
-
- // Clear map so memory is not re-released if we are called again
- funcToModRefInfoMap.clear();
-}
-
-// Run the "interprocedural" pass on each function. This needs to do
-// NO real interprocedural work because all that has been done the
-// data structure analysis.
-//
-bool IPModRef::run(Module &theModule)
-{
- M = &theModule;
-
- for (Module::const_iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI)
- if (! FI->isExternal())
- getFuncInfo(*FI, /*computeIfMissing*/ true);
- return true;
-}
-
-
-FunctionModRefInfo& IPModRef::getFuncInfo(const Function& func,
- bool computeIfMissing)
-{
- FunctionModRefInfo*& funcInfo = funcToModRefInfoMap[&func];
- assert (funcInfo != NULL || computeIfMissing);
- if (funcInfo == NULL)
- { // Create a new FunctionModRefInfo object.
- // Clone the top-down graph and remove any dead nodes first, because
- // otherwise original and merged graphs will not match.
- // The memory for this graph clone will be freed by FunctionModRefInfo.
- DSGraph* funcTDGraph =
- new DSGraph(getAnalysis<TDDataStructures>().getDSGraph(func));
- funcTDGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals);
-
- funcInfo = new FunctionModRefInfo(func, *this, funcTDGraph); //auto-insert
- funcInfo->computeModRef(func); // computes the mod/ref info
- }
- return *funcInfo;
-}
-
-/// getBUDSGraph - This method returns the BU data structure graph for F through
-/// the use of the BUDataStructures object.
-///
-const DSGraph &IPModRef::getBUDSGraph(const Function &F) {
- return getAnalysis<BUDataStructures>().getDSGraph(F);
-}
-
-
-// getAnalysisUsage - This pass requires top-down data structure graphs.
-// It modifies nothing.
-//
-void IPModRef::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.setPreservesAll();
- AU.addRequired<LocalDataStructures>();
- AU.addRequired<BUDataStructures>();
- AU.addRequired<TDDataStructures>();
-}
-
-
-void IPModRef::print(std::ostream &O) const
-{
- O << "\nRESULTS OF INTERPROCEDURAL MOD/REF ANALYSIS:\n\n";
-
- for (std::map<const Function*, FunctionModRefInfo*>::const_iterator
- mapI = funcToModRefInfoMap.begin(), mapE = funcToModRefInfoMap.end();
- mapI != mapE; ++mapI)
- mapI->second->print(O);
-
- O << "\n";
-}
-
-
-void IPModRef::dump() const
-{
- print(std::cerr);
-}
diff --git a/poolalloc/lib/DSA/Local.cpp b/poolalloc/lib/DSA/Local.cpp
deleted file mode 100644
index a03354d..0000000
--- a/poolalloc/lib/DSA/Local.cpp
+++ /dev/null
@@ -1,503 +0,0 @@
-//===- Local.cpp - Compute a local data structure graph for a function ----===//
-//
-// Compute the local version of the data structure graph for a function. The
-// external interface to this file is the DSGraph constructor.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/iMemory.h"
-#include "llvm/iTerminators.h"
-#include "llvm/iPHINode.h"
-#include "llvm/iOther.h"
-#include "llvm/Constants.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Function.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/Support/InstVisitor.h"
-#include "llvm/Target/TargetData.h"
-#include "Support/CommandLine.h"
-#include "Support/Debug.h"
-#include "Support/Timer.h"
-
-// FIXME: This should eventually be a FunctionPass that is automatically
-// aggregated into a Pass.
-//
-#include "llvm/Module.h"
-
-static RegisterAnalysis<LocalDataStructures>
-X("datastructure", "Local Data Structure Analysis");
-
-namespace DS {
- // FIXME: Do something smarter with target data!
- TargetData TD("temp-td");
-
- // isPointerType - Return true if this type is big enough to hold a pointer.
- bool isPointerType(const Type *Ty) {
- if (isa<PointerType>(Ty))
- return true;
- else if (Ty->isPrimitiveType() && Ty->isInteger())
- return Ty->getPrimitiveSize() >= PointerSize;
- return false;
- }
-}
-using namespace DS;
-
-
-namespace {
- cl::opt<bool>
- DisableDirectCallOpt("disable-direct-call-dsopt", cl::Hidden,
- cl::desc("Disable direct call optimization in "
- "DSGraph construction"));
- cl::opt<bool>
- DisableFieldSensitivity("disable-ds-field-sensitivity", cl::Hidden,
- cl::desc("Disable field sensitivity in DSGraphs"));
-
- //===--------------------------------------------------------------------===//
- // GraphBuilder Class
- //===--------------------------------------------------------------------===//
- //
- /// This class is the builder class that constructs the local data structure
- /// graph by performing a single pass over the function in question.
- ///
- class GraphBuilder : InstVisitor<GraphBuilder> {
- Function &F;
- DSGraph &G;
- DSNodeHandle &RetNode; // Node that gets returned...
- DSGraph::ScalarMapTy &ScalarMap;
- std::vector<DSCallSite> &FunctionCalls;
-
- public:
- GraphBuilder(Function &f, DSGraph &g, DSNodeHandle &retNode,
- DSGraph::ScalarMapTy &SM, std::vector<DSCallSite> &fc)
- : F(f), G(g), RetNode(retNode), ScalarMap(SM),
- FunctionCalls(fc) {
-
- // Create scalar nodes for all pointer arguments...
- for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I)
- if (isPointerType(I->getType()))
- getValueDest(*I);
-
- visit(F); // Single pass over the function
- }
-
- private:
- // Visitor functions, used to handle each instruction type we encounter...
- friend class InstVisitor<GraphBuilder>;
- void visitMallocInst(MallocInst &MI) { handleAlloc(MI, true); }
- void visitAllocaInst(AllocaInst &AI) { handleAlloc(AI, false); }
- void handleAlloc(AllocationInst &AI, bool isHeap);
-
- void visitPHINode(PHINode &PN);
-
- void visitGetElementPtrInst(User &GEP);
- void visitReturnInst(ReturnInst &RI);
- void visitLoadInst(LoadInst &LI);
- void visitStoreInst(StoreInst &SI);
- void visitCallInst(CallInst &CI);
- void visitSetCondInst(SetCondInst &SCI) {} // SetEQ & friends are ignored
- void visitFreeInst(FreeInst &FI);
- void visitCastInst(CastInst &CI);
- void visitInstruction(Instruction &I);
-
- private:
- // Helper functions used to implement the visitation functions...
-
- /// createNode - Create a new DSNode, ensuring that it is properly added to
- /// the graph.
- ///
- DSNode *createNode(const Type *Ty = 0) {
- DSNode *N = new DSNode(Ty, &G); // Create the node
- if (DisableFieldSensitivity) {
- N->foldNodeCompletely();
- if (DSNode *FN = N->getForwardNode())
- N = FN;
- }
- return N;
- }
-
- /// setDestTo - Set the ScalarMap 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 setDestTo(Value &V, const DSNodeHandle &NH);
-
- /// getValueDest - Return the DSNode that the actual value points to.
- ///
- 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
- /// null), then we create a new node, link it, then return it.
- ///
- DSNodeHandle &getLink(const DSNodeHandle &Node, unsigned Link = 0);
- };
-}
-
-//===----------------------------------------------------------------------===//
-// DSGraph constructor - Simply use the GraphBuilder to construct the local
-// graph.
-DSGraph::DSGraph(Function &F, DSGraph *GG) : GlobalsGraph(GG) {
- PrintAuxCalls = false;
-
- DEBUG(std::cerr << " [Loc] Calculating graph for: " << F.getName() << "\n");
-
- // Use the graph builder to construct the local version of the graph
- GraphBuilder B(F, *this, ReturnNodes[&F], ScalarMap, FunctionCalls);
-#ifndef NDEBUG
- Timer::addPeakMemoryMeasurement();
-#endif
-
- // Remove all integral constants from the scalarmap!
- for (ScalarMapTy::iterator I = ScalarMap.begin(); I != ScalarMap.end();)
- if (isa<ConstantIntegral>(I->first)) {
- ScalarMapTy::iterator J = I++;
- ScalarMap.erase(J);
- } else
- ++I;
-
- markIncompleteNodes(DSGraph::MarkFormalArgs);
-
- // Remove any nodes made dead due to merging...
- removeDeadNodes(DSGraph::KeepUnreachableGlobals);
-}
-
-
-//===----------------------------------------------------------------------===//
-// Helper method implementations...
-//
-
-/// getValueDest - Return the DSNode that the actual value points to.
-///
-DSNodeHandle GraphBuilder::getValueDest(Value &Val) {
- Value *V = &Val;
- if (V == Constant::getNullValue(V->getType()))
- return 0; // Null doesn't point to anything, don't add to ScalarMap!
-
- DSNodeHandle &NH = ScalarMap[V];
- if (NH.getNode())
- return NH; // Already have a node? Just return it...
-
- // Otherwise we need to create a new node to point to.
- // Check first for constant expressions that must be traversed to
- // extract the actual value.
- if (Constant *C = dyn_cast<Constant>(V))
- if (ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(C)) {
- return NH = getValueDest(*CPR->getValue());
- } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
- if (CE->getOpcode() == Instruction::Cast)
- NH = getValueDest(*CE->getOperand(0));
- else if (CE->getOpcode() == Instruction::GetElementPtr) {
- visitGetElementPtrInst(*CE);
- DSGraph::ScalarMapTy::iterator I = ScalarMap.find(CE);
- assert(I != ScalarMap.end() && "GEP didn't get processed right?");
- NH = I->second;
- } else {
- // This returns a conservative unknown node for any unhandled ConstExpr
- return NH = createNode()->setUnknownNodeMarker();
- }
- if (NH.getNode() == 0) { // (getelementptr null, X) returns null
- ScalarMap.erase(V);
- return 0;
- }
- return NH;
-
- } else if (ConstantIntegral *CI = dyn_cast<ConstantIntegral>(C)) {
- // Random constants are unknown mem
- return NH = createNode()->setUnknownNodeMarker();
- } else {
- assert(0 && "Unknown constant type!");
- }
-
- // 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(GV->getType()->getElementType());
- N->addGlobal(GV);
- } else {
- // Otherwise just create a shadow node
- N = createNode();
- }
-
- NH.setNode(N); // Remember that we are pointing to it...
- NH.setOffset(0);
- return NH;
-}
-
-
-/// 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
-/// null), then we create a new node, link it, then return it. We must
-/// specify the type of the Node field we are accessing so that we know what
-/// type should be linked to if we need to create a new node.
-///
-DSNodeHandle &GraphBuilder::getLink(const DSNodeHandle &node, unsigned LinkNo) {
- DSNodeHandle &Node = const_cast<DSNodeHandle&>(node);
- DSNodeHandle &Link = Node.getLink(LinkNo);
- if (!Link.getNode()) {
- // If the link hasn't been created yet, make and return a new shadow node
- Link = createNode();
- }
- return Link;
-}
-
-
-/// setDestTo - Set the ScalarMap 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 = ScalarMap[&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...
-//
-
-/// Alloca & Malloc instruction implementation - Simply create a new memory
-/// object, pointing the scalar to it.
-///
-void GraphBuilder::handleAlloc(AllocationInst &AI, bool isHeap) {
- DSNode *N = createNode();
- if (isHeap)
- N->setHeapNodeMarker();
- else
- N->setAllocaNodeMarker();
- setDestTo(AI, N);
-}
-
-// PHINode - Make the scalar for the PHI node point to all of the things the
-// incoming values point to... which effectively causes them to be merged.
-//
-void GraphBuilder::visitPHINode(PHINode &PN) {
- if (!isPointerType(PN.getType())) return; // Only pointer PHIs
-
- DSNodeHandle &PNDest = ScalarMap[&PN];
- for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i)
- PNDest.mergeWith(getValueDest(*PN.getIncomingValue(i)));
-}
-
-void GraphBuilder::visitGetElementPtrInst(User &GEP) {
- DSNodeHandle Value = getValueDest(*GEP.getOperand(0));
- if (Value.getNode() == 0) return;
-
- unsigned Offset = 0;
- const PointerType *PTy = cast<PointerType>(GEP.getOperand(0)->getType());
- const Type *CurTy = PTy->getElementType();
-
- if (Value.getNode()->mergeTypeInfo(CurTy, Value.getOffset())) {
- // If the node had to be folded... exit quickly
- setDestTo(GEP, Value); // GEP result points to folded node
- return;
- }
-
-#if 0
- // Handle the pointer index specially...
- if (GEP.getNumOperands() > 1 &&
- GEP.getOperand(1) != ConstantSInt::getNullValue(Type::LongTy)) {
-
- // If we already know this is an array being accessed, don't do anything...
- if (!TopTypeRec.isArray) {
- TopTypeRec.isArray = true;
-
- // If we are treating some inner field pointer as an array, fold the node
- // up because we cannot handle it right. This can come because of
- // something like this: &((&Pt->X)[1]) == &Pt->Y
- //
- if (Value.getOffset()) {
- // Value is now the pointer we want to GEP to be...
- Value.getNode()->foldNodeCompletely();
- 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
- // are pointing to the outter most type in the node.
- // FIXME: We need to check one more case here...
- }
- }
- }
-#endif
-
- // All of these subscripts are indexing INTO the elements we have...
- for (unsigned i = 2, e = GEP.getNumOperands(); i < e; ++i)
- if (GEP.getOperand(i)->getType() == Type::LongTy) {
- // Get the type indexing into...
- const SequentialType *STy = cast<SequentialType>(CurTy);
- CurTy = STy->getElementType();
-#if 0
- if (ConstantSInt *CS = dyn_cast<ConstantSInt>(GEP.getOperand(i))) {
- Offset += CS->getValue()*TD.getTypeSize(CurTy);
- } else {
- // Variable index into a node. We must merge all of the elements of the
- // sequential type here.
- if (isa<PointerType>(STy))
- std::cerr << "Pointer indexing not handled yet!\n";
- else {
- const ArrayType *ATy = cast<ArrayType>(STy);
- unsigned ElSize = TD.getTypeSize(CurTy);
- DSNode *N = Value.getNode();
- assert(N && "Value must have a node!");
- unsigned RawOffset = Offset+Value.getOffset();
-
- // Loop over all of the elements of the array, merging them into the
- // zero'th element.
- for (unsigned i = 1, e = ATy->getNumElements(); i != e; ++i)
- // Merge all of the byte components of this array element
- for (unsigned j = 0; j != ElSize; ++j)
- N->mergeIndexes(RawOffset+j, RawOffset+i*ElSize+j);
- }
- }
-#endif
- } else if (GEP.getOperand(i)->getType() == Type::UByteTy) {
- unsigned FieldNo = cast<ConstantUInt>(GEP.getOperand(i))->getValue();
- const StructType *STy = cast<StructType>(CurTy);
- Offset += TD.getStructLayout(STy)->MemberOffsets[FieldNo];
- CurTy = STy->getContainedType(FieldNo);
- }
-
- // Add in the offset calculated...
- Value.setOffset(Value.getOffset()+Offset);
-
- // Value is now the pointer we want to GEP to be...
- setDestTo(GEP, Value);
-}
-
-void GraphBuilder::visitLoadInst(LoadInst &LI) {
- DSNodeHandle Ptr = getValueDest(*LI.getOperand(0));
- if (Ptr.getNode() == 0) return;
-
- // Make that the node is read from...
- Ptr.getNode()->setReadMarker();
-
- // Ensure a typerecord exists...
- Ptr.getNode()->mergeTypeInfo(LI.getType(), Ptr.getOffset(), false);
-
- if (isPointerType(LI.getType()))
- setDestTo(LI, getLink(Ptr));
-}
-
-void GraphBuilder::visitStoreInst(StoreInst &SI) {
- const Type *StoredTy = SI.getOperand(0)->getType();
- DSNodeHandle Dest = getValueDest(*SI.getOperand(1));
- if (Dest.getNode() == 0) return;
-
- // Mark that the node is written to...
- Dest.getNode()->setModifiedMarker();
-
- // Ensure a typerecord exists...
- Dest.getNode()->mergeTypeInfo(StoredTy, Dest.getOffset());
-
- // Avoid adding edges from null, or processing non-"pointer" stores
- if (isPointerType(StoredTy))
- Dest.addEdgeTo(getValueDest(*SI.getOperand(0)));
-}
-
-void GraphBuilder::visitReturnInst(ReturnInst &RI) {
- 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 = getValueDest(CI);
-
- DSNode *Callee = 0;
- if (DisableDirectCallOpt || !isa<Function>(CI.getOperand(0)))
- Callee = getValueDest(*CI.getOperand(0)).getNode();
-
- std::vector<DSNodeHandle> Args;
- Args.reserve(CI.getNumOperands()-1);
-
- // Calculate the arguments vector...
- for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i)
- if (isPointerType(CI.getOperand(i)->getType()))
- Args.push_back(getValueDest(*CI.getOperand(i)));
-
- // Add a new function call entry...
- if (Callee)
- FunctionCalls.push_back(DSCallSite(CI, RetVal, Callee, Args));
- else
- FunctionCalls.push_back(DSCallSite(CI, RetVal,
- cast<Function>(CI.getOperand(0)), Args));
-}
-
-void GraphBuilder::visitFreeInst(FreeInst &FI) {
- // Mark that the node is written to...
- DSNode *N = getValueDest(*FI.getOperand(0)).getNode();
- N->setModifiedMarker();
- N->setHeapNodeMarker();
-}
-
-/// Handle casts...
-void GraphBuilder::visitCastInst(CastInst &CI) {
- if (isPointerType(CI.getType()))
- if (isPointerType(CI.getOperand(0)->getType())) {
- // Cast one pointer to the other, just act like a copy instruction
- setDestTo(CI, getValueDest(*CI.getOperand(0)));
- } else {
- // Cast something (floating point, small integer) to a pointer. We need
- // to track the fact that the node points to SOMETHING, just something we
- // don't know about. Make an "Unknown" node.
- //
- setDestTo(CI, createNode()->setUnknownNodeMarker());
- }
-}
-
-
-// visitInstruction - For all other instruction types, if we have any arguments
-// that are of pointer type, make them have unknown composition bits, and merge
-// the nodes together.
-void GraphBuilder::visitInstruction(Instruction &Inst) {
- DSNodeHandle CurNode;
- if (isPointerType(Inst.getType()))
- CurNode = getValueDest(Inst);
- for (User::op_iterator I = Inst.op_begin(), E = Inst.op_end(); I != E; ++I)
- if (isPointerType((*I)->getType()))
- CurNode.mergeWith(getValueDest(**I));
-
- if (CurNode.getNode())
- CurNode.getNode()->setUnknownNodeMarker();
-}
-
-
-
-//===----------------------------------------------------------------------===//
-// LocalDataStructures Implementation
-//===----------------------------------------------------------------------===//
-
-bool LocalDataStructures::run(Module &M) {
- GlobalsGraph = new DSGraph();
-
- // Calculate all of the graphs...
- for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
- if (!I->isExternal())
- DSInfo.insert(std::make_pair(I, new DSGraph(*I, GlobalsGraph)));
- return false;
-}
-
-// releaseMemory - If the pass pipeline is done with this pass, we can release
-// our memory... here...
-//
-void LocalDataStructures::releaseMemory() {
- for (hash_map<Function*, DSGraph*>::iterator I = DSInfo.begin(),
- E = DSInfo.end(); I != E; ++I) {
- I->second->getReturnNodes().erase(I->first);
- if (I->second->getReturnNodes().empty())
- delete I->second;
- }
-
- // Empty map so next time memory is released, data structures are not
- // re-deleted.
- DSInfo.clear();
- delete GlobalsGraph;
- GlobalsGraph = 0;
-}
diff --git a/poolalloc/lib/DSA/Makefile b/poolalloc/lib/DSA/Makefile
deleted file mode 100644
index 3c4c7e2..0000000
--- a/poolalloc/lib/DSA/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-LEVEL = ../../..
-LIBRARYNAME = datastructure
-BUILD_ARCHIVE = 1
-
-include $(LEVEL)/Makefile.common
-
diff --git a/poolalloc/lib/DSA/MemoryDepAnalysis.cpp b/poolalloc/lib/DSA/MemoryDepAnalysis.cpp
deleted file mode 100644
index 598bff9..0000000
--- a/poolalloc/lib/DSA/MemoryDepAnalysis.cpp
+++ /dev/null
@@ -1,491 +0,0 @@
-//===- MemoryDepAnalysis.cpp - Compute dep graph for memory ops --*-C++-*--===//
-//
-// This file implements a pass (MemoryDepAnalysis) that computes memory-based
-// data dependences between instructions for each function in a module.
-// Memory-based dependences occur due to load and store operations, but
-// also the side-effects of call instructions.
-//
-// The result of this pass is a DependenceGraph for each function
-// representing the memory-based data dependences between instructions.
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/MemoryDepAnalysis.h"
-#include "llvm/Analysis/IPModRef.h"
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Module.h"
-#include "llvm/Function.h"
-#include "llvm/iMemory.h"
-#include "llvm/iOther.h"
-#include "llvm/Support/InstVisitor.h"
-#include "llvm/Support/CFG.h"
-#include "Support/TarjanSCCIterator.h"
-#include "Support/Statistic.h"
-#include "Support/STLExtras.h"
-#include "Support/hash_map"
-#include "Support/hash_set"
-#include <iostream>
-
-
-///--------------------------------------------------------------------------
-/// struct ModRefTable:
-///
-/// A data structure that tracks ModRefInfo for instructions:
-/// -- modRefMap is a map of Instruction* -> ModRefInfo for the instr.
-/// -- definers is a vector of instructions that define any node
-/// -- users is a vector of instructions that reference any node
-/// -- numUsersBeforeDef is a vector indicating that the number of users
-/// seen before definers[i] is numUsersBeforeDef[i].
-///
-/// numUsersBeforeDef[] effectively tells us the exact interleaving of
-/// definers and users within the ModRefTable.
-/// This is only maintained when constructing the table for one SCC, and
-/// not copied over from one table to another since it is no longer useful.
-///--------------------------------------------------------------------------
-
-struct ModRefTable
-{
- typedef hash_map<Instruction*, ModRefInfo> ModRefMap;
- typedef ModRefMap::const_iterator const_map_iterator;
- typedef ModRefMap:: iterator map_iterator;
- typedef std::vector<Instruction*>::const_iterator const_ref_iterator;
- typedef std::vector<Instruction*>:: iterator ref_iterator;
-
- ModRefMap modRefMap;
- std::vector<Instruction*> definers;
- std::vector<Instruction*> users;
- std::vector<unsigned> numUsersBeforeDef;
-
- // Iterators to enumerate all the defining instructions
- const_ref_iterator defsBegin() const { return definers.begin(); }
- ref_iterator defsBegin() { return definers.begin(); }
- const_ref_iterator defsEnd() const { return definers.end(); }
- ref_iterator defsEnd() { return definers.end(); }
-
- // Iterators to enumerate all the user instructions
- const_ref_iterator usersBegin() const { return users.begin(); }
- ref_iterator usersBegin() { return users.begin(); }
- const_ref_iterator usersEnd() const { return users.end(); }
- ref_iterator usersEnd() { return users.end(); }
-
- // Iterator identifying the last user that was seen *before* a
- // specified def. In particular, all users in the half-closed range
- // [ usersBegin(), usersBeforeDef_End(defPtr) )
- // were seen *before* the specified def. All users in the half-closed range
- // [ usersBeforeDef_End(defPtr), usersEnd() )
- // were seen *after* the specified def.
- //
- ref_iterator usersBeforeDef_End(const_ref_iterator defPtr) {
- unsigned defIndex = (unsigned) (defPtr - defsBegin());
- assert(defIndex < numUsersBeforeDef.size());
- assert(usersBegin() + numUsersBeforeDef[defIndex] <= usersEnd());
- return usersBegin() + numUsersBeforeDef[defIndex];
- }
- const_ref_iterator usersBeforeDef_End(const_ref_iterator defPtr) const {
- return const_cast<ModRefTable*>(this)->usersBeforeDef_End(defPtr);
- }
-
- //
- // Modifier methods
- //
- void AddDef(Instruction* D) {
- definers.push_back(D);
- numUsersBeforeDef.push_back(users.size());
- }
- void AddUse(Instruction* U) {
- users.push_back(U);
- }
- void Insert(const ModRefTable& fromTable) {
- modRefMap.insert(fromTable.modRefMap.begin(), fromTable.modRefMap.end());
- definers.insert(definers.end(),
- fromTable.definers.begin(), fromTable.definers.end());
- users.insert(users.end(),
- fromTable.users.begin(), fromTable.users.end());
- numUsersBeforeDef.clear(); /* fromTable.numUsersBeforeDef is ignored */
- }
-};
-
-
-///--------------------------------------------------------------------------
-/// class ModRefInfoBuilder:
-///
-/// A simple InstVisitor<> class that retrieves the Mod/Ref info for
-/// Load/Store/Call instructions and inserts this information in
-/// a ModRefTable. It also records all instructions that Mod any node
-/// and all that use any node.
-///--------------------------------------------------------------------------
-
-class ModRefInfoBuilder : public InstVisitor<ModRefInfoBuilder> {
- const DSGraph& funcGraph;
- const FunctionModRefInfo& funcModRef;
- ModRefTable& modRefTable;
-
- ModRefInfoBuilder(); // DO NOT IMPLEMENT
- ModRefInfoBuilder(const ModRefInfoBuilder&); // DO NOT IMPLEMENT
- void operator=(const ModRefInfoBuilder&); // DO NOT IMPLEMENT
-
-public:
- /*ctor*/ ModRefInfoBuilder(const DSGraph& _funcGraph,
- const FunctionModRefInfo& _funcModRef,
- ModRefTable& _modRefTable)
- : funcGraph(_funcGraph), funcModRef(_funcModRef), modRefTable(_modRefTable)
- {
- }
-
- // At a call instruction, retrieve the ModRefInfo using IPModRef results.
- // Add the call to the defs list if it modifies any nodes and to the uses
- // list if it refs any nodes.
- //
- void visitCallInst (CallInst& callInst) {
- ModRefInfo safeModRef(funcGraph.getGraphSize());
- const ModRefInfo* callModRef = funcModRef.getModRefInfo(callInst);
- if (callModRef == NULL)
- { // call to external/unknown function: mark all nodes as Mod and Ref
- safeModRef.getModSet().set();
- safeModRef.getRefSet().set();
- callModRef = &safeModRef;
- }
-
- modRefTable.modRefMap.insert(std::make_pair(&callInst,
- ModRefInfo(*callModRef)));
- if (callModRef->getModSet().any())
- modRefTable.AddDef(&callInst);
- if (callModRef->getRefSet().any())
- modRefTable.AddUse(&callInst);
- }
-
- // At a store instruction, add to the mod set the single node pointed to
- // by the pointer argument of the store. Interestingly, if there is no
- // such node, that would be a null pointer reference!
- void visitStoreInst (StoreInst& storeInst) {
- const DSNodeHandle& ptrNode =
- funcGraph.getNodeForValue(storeInst.getPointerOperand());
- if (const DSNode* target = ptrNode.getNode())
- {
- unsigned nodeId = funcModRef.getNodeId(target);
- ModRefInfo& minfo =
- modRefTable.modRefMap.insert(
- std::make_pair(&storeInst,
- ModRefInfo(funcGraph.getGraphSize()))).first->second;
- minfo.setNodeIsMod(nodeId);
- modRefTable.AddDef(&storeInst);
- }
- else
- std::cerr << "Warning: Uninitialized pointer reference!\n";
- }
-
- // At a load instruction, add to the ref set the single node pointed to
- // by the pointer argument of the load. Interestingly, if there is no
- // such node, that would be a null pointer reference!
- void visitLoadInst (LoadInst& loadInst) {
- const DSNodeHandle& ptrNode =
- funcGraph.getNodeForValue(loadInst.getPointerOperand());
- if (const DSNode* target = ptrNode.getNode())
- {
- unsigned nodeId = funcModRef.getNodeId(target);
- ModRefInfo& minfo =
- modRefTable.modRefMap.insert(
- std::make_pair(&loadInst,
- ModRefInfo(funcGraph.getGraphSize()))).first->second;
- minfo.setNodeIsRef(nodeId);
- modRefTable.AddUse(&loadInst);
- }
- else
- std::cerr << "Warning: Uninitialized pointer reference!\n";
- }
-};
-
-
-//----------------------------------------------------------------------------
-// class MemoryDepAnalysis: A dep. graph for load/store/call instructions
-//----------------------------------------------------------------------------
-
-/// Basic dependence gathering algorithm, using TarjanSCCIterator on CFG:
-///
-/// for every SCC S in the CFG in PostOrder on the SCC DAG
-/// {
-/// for every basic block BB in S in *postorder*
-/// for every instruction I in BB in reverse
-/// Add (I, ModRef[I]) to ModRefCurrent
-/// if (Mod[I] != NULL)
-/// Add I to DefSetCurrent: { I \in S : Mod[I] != NULL }
-/// if (Ref[I] != NULL)
-/// Add I to UseSetCurrent: { I : Ref[I] != NULL }
-///
-/// for every def D in DefSetCurrent
-///
-/// // NOTE: D comes after itself iff S contains a loop
-/// if (HasLoop(S) && D & D)
-/// Add output-dep: D -> D2
-///
-/// for every def D2 *after* D in DefSetCurrent
-/// // NOTE: D2 comes before D in execution order
-/// if (D & D2)
-/// Add output-dep: D2 -> D
-/// if (HasLoop(S))
-/// Add output-dep: D -> D2
-///
-/// for every use U in UseSetCurrent that was seen *before* D
-/// // NOTE: U comes after D in execution order
-/// if (U & D)
-/// if (U != D || HasLoop(S))
-/// Add true-dep: D -> U
-/// if (HasLoop(S))
-/// Add anti-dep: U -> D
-///
-/// for every use U in UseSetCurrent that was seen *after* D
-/// // NOTE: U comes before D in execution order
-/// if (U & D)
-/// if (U != D || HasLoop(S))
-/// Add anti-dep: U -> D
-/// if (HasLoop(S))
-/// Add true-dep: D -> U
-///
-/// for every def Dnext in DefSetAfter
-/// // NOTE: Dnext comes after D in execution order
-/// if (Dnext & D)
-/// Add output-dep: D -> Dnext
-///
-/// for every use Unext in UseSetAfter
-/// // NOTE: Unext comes after D in execution order
-/// if (Unext & D)
-/// Add true-dep: D -> Unext
-///
-/// for every use U in UseSetCurrent
-/// for every def Dnext in DefSetAfter
-/// // NOTE: Dnext comes after U in execution order
-/// if (Dnext & D)
-/// Add anti-dep: U -> Dnext
-///
-/// Add ModRefCurrent to ModRefAfter: { (I, ModRef[I] ) }
-/// Add DefSetCurrent to DefSetAfter: { I : Mod[I] != NULL }
-/// Add UseSetCurrent to UseSetAfter: { I : Ref[I] != NULL }
-/// }
-///
-///
-
-void MemoryDepAnalysis::ProcessSCC(SCC<Function*>& S,
- ModRefTable& ModRefAfter)
-{
- ModRefTable ModRefCurrent;
- ModRefTable::ModRefMap& mapCurrent = ModRefCurrent.modRefMap;
- ModRefTable::ModRefMap& mapAfter = ModRefAfter.modRefMap;
-
- bool hasLoop = S.HasLoop();
-
- // Builder class fills out a ModRefTable one instruction at a time.
- // To use it, we just invoke it's visit function for each basic block:
- //
- // for each basic block BB in the SCC in *postorder*
- // for each instruction I in BB in *reverse*
- // ModRefInfoBuilder::visit(I)
- // : Add (I, ModRef[I]) to ModRefCurrent.modRefMap
- // : Add I to ModRefCurrent.definers if it defines any node
- // : Add I to ModRefCurrent.users if it uses any node
- //
- ModRefInfoBuilder builder(*funcGraph, *funcModRef, ModRefCurrent);
- for (SCC<Function*>::iterator BI=S.begin(), BE=S.end(); BI != BE; ++BI)
- // Note: BBs in the SCC<> created by TarjanSCCIterator are in postorder.
- for (BasicBlock::reverse_iterator II=(*BI)->rbegin(), IE=(*BI)->rend();
- II != IE; ++II)
- builder.visit(*II);
-
- /// for every def D in DefSetCurrent
- ///
- for (ModRefTable::ref_iterator II=ModRefCurrent.defsBegin(),
- IE=ModRefCurrent.defsEnd(); II != IE; ++II)
- {
- /// // NOTE: D comes after itself iff S contains a loop
- /// if (HasLoop(S))
- /// Add output-dep: D -> D2
- if (hasLoop)
- funcDepGraph->AddSimpleDependence(**II, **II, OutputDependence);
-
- /// for every def D2 *after* D in DefSetCurrent
- /// // NOTE: D2 comes before D in execution order
- /// if (D2 & D)
- /// Add output-dep: D2 -> D
- /// if (HasLoop(S))
- /// Add output-dep: D -> D2
- for (ModRefTable::ref_iterator JI=II+1; JI != IE; ++JI)
- if (!Disjoint(mapCurrent.find(*II)->second.getModSet(),
- mapCurrent.find(*JI)->second.getModSet()))
- {
- funcDepGraph->AddSimpleDependence(**JI, **II, OutputDependence);
- if (hasLoop)
- funcDepGraph->AddSimpleDependence(**II, **JI, OutputDependence);
- }
-
- /// for every use U in UseSetCurrent that was seen *before* D
- /// // NOTE: U comes after D in execution order
- /// if (U & D)
- /// if (U != D || HasLoop(S))
- /// Add true-dep: U -> D
- /// if (HasLoop(S))
- /// Add anti-dep: D -> U
- ModRefTable::ref_iterator JI=ModRefCurrent.usersBegin();
- ModRefTable::ref_iterator JE = ModRefCurrent.usersBeforeDef_End(II);
- for ( ; JI != JE; ++JI)
- if (!Disjoint(mapCurrent.find(*II)->second.getModSet(),
- mapCurrent.find(*JI)->second.getRefSet()))
- {
- if (*II != *JI || hasLoop)
- funcDepGraph->AddSimpleDependence(**II, **JI, TrueDependence);
- if (hasLoop)
- funcDepGraph->AddSimpleDependence(**JI, **II, AntiDependence);
- }
-
- /// for every use U in UseSetCurrent that was seen *after* D
- /// // NOTE: U comes before D in execution order
- /// if (U & D)
- /// if (U != D || HasLoop(S))
- /// Add anti-dep: U -> D
- /// if (HasLoop(S))
- /// Add true-dep: D -> U
- for (/*continue JI*/ JE = ModRefCurrent.usersEnd(); JI != JE; ++JI)
- if (!Disjoint(mapCurrent.find(*II)->second.getModSet(),
- mapCurrent.find(*JI)->second.getRefSet()))
- {
- if (*II != *JI || hasLoop)
- funcDepGraph->AddSimpleDependence(**JI, **II, AntiDependence);
- if (hasLoop)
- funcDepGraph->AddSimpleDependence(**II, **JI, TrueDependence);
- }
-
- /// for every def Dnext in DefSetPrev
- /// // NOTE: Dnext comes after D in execution order
- /// if (Dnext & D)
- /// Add output-dep: D -> Dnext
- for (ModRefTable::ref_iterator JI=ModRefAfter.defsBegin(),
- JE=ModRefAfter.defsEnd(); JI != JE; ++JI)
- if (!Disjoint(mapCurrent.find(*II)->second.getModSet(),
- mapAfter.find(*JI)->second.getModSet()))
- funcDepGraph->AddSimpleDependence(**II, **JI, OutputDependence);
-
- /// for every use Unext in UseSetAfter
- /// // NOTE: Unext comes after D in execution order
- /// if (Unext & D)
- /// Add true-dep: D -> Unext
- for (ModRefTable::ref_iterator JI=ModRefAfter.usersBegin(),
- JE=ModRefAfter.usersEnd(); JI != JE; ++JI)
- if (!Disjoint(mapCurrent.find(*II)->second.getModSet(),
- mapAfter.find(*JI)->second.getRefSet()))
- funcDepGraph->AddSimpleDependence(**II, **JI, TrueDependence);
- }
-
- ///
- /// for every use U in UseSetCurrent
- /// for every def Dnext in DefSetAfter
- /// // NOTE: Dnext comes after U in execution order
- /// if (Dnext & D)
- /// Add anti-dep: U -> Dnext
- for (ModRefTable::ref_iterator II=ModRefCurrent.usersBegin(),
- IE=ModRefCurrent.usersEnd(); II != IE; ++II)
- for (ModRefTable::ref_iterator JI=ModRefAfter.defsBegin(),
- JE=ModRefAfter.defsEnd(); JI != JE; ++JI)
- if (!Disjoint(mapCurrent.find(*II)->second.getRefSet(),
- mapAfter.find(*JI)->second.getModSet()))
- funcDepGraph->AddSimpleDependence(**II, **JI, AntiDependence);
-
- /// Add ModRefCurrent to ModRefAfter: { (I, ModRef[I] ) }
- /// Add DefSetCurrent to DefSetAfter: { I : Mod[I] != NULL }
- /// Add UseSetCurrent to UseSetAfter: { I : Ref[I] != NULL }
- ModRefAfter.Insert(ModRefCurrent);
-}
-
-
-/// Debugging support methods
-///
-void MemoryDepAnalysis::print(std::ostream &O) const
-{
- // TEMPORARY LOOP
- for (hash_map<Function*, DependenceGraph*>::const_iterator
- I = funcMap.begin(), E = funcMap.end(); I != E; ++I)
- {
- Function* func = I->first;
- DependenceGraph* depGraph = I->second;
-
- O << "\n================================================================\n";
- O << "DEPENDENCE GRAPH FOR MEMORY OPERATIONS IN FUNCTION " << func->getName();
- O << "\n================================================================\n\n";
- depGraph->print(*func, O);
-
- }
-}
-
-
-///
-/// Run the pass on a function
-///
-bool MemoryDepAnalysis::runOnFunction(Function& func)
-{
- assert(! func.isExternal());
-
- // Get the FunctionModRefInfo holding IPModRef results for this function.
- // Use the TD graph recorded within the FunctionModRefInfo object, which
- // may not be the same as the original TD graph computed by DS analysis.
- //
- funcModRef = &getAnalysis<IPModRef>().getFunctionModRefInfo(func);
- funcGraph = &funcModRef->getFuncGraph();
-
- // TEMPORARY: ptr to depGraph (later just becomes "this").
- assert(funcMap.find(&func) == funcMap.end() && "Analyzing function twice?");
- funcDepGraph = funcMap[&func] = new DependenceGraph();
-
- ModRefTable ModRefAfter;
-
- SCC<Function*>* nextSCC;
- for (TarjanSCC_iterator<Function*> tarjSCCiter = tarj_begin(&func);
- (nextSCC = *tarjSCCiter) != NULL; ++tarjSCCiter)
- ProcessSCC(*nextSCC, ModRefAfter);
-
- return true;
-}
-
-
-//-------------------------------------------------------------------------
-// TEMPORARY FUNCTIONS TO MAKE THIS A MODULE PASS ---
-// These functions will go away once this class becomes a FunctionPass.
-//
-
-// Driver function to compute dependence graphs for every function.
-// This is temporary and will go away once this is a FunctionPass.
-//
-bool MemoryDepAnalysis::run(Module& M)
-{
- for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI)
- if (! FI->isExternal())
- runOnFunction(*FI); // automatically inserts each depGraph into funcMap
- return true;
-}
-
-// Release all the dependence graphs in the map.
-void MemoryDepAnalysis::releaseMemory()
-{
- for (hash_map<Function*, DependenceGraph*>::const_iterator
- I = funcMap.begin(), E = funcMap.end(); I != E; ++I)
- delete I->second;
- funcMap.clear();
-
- // Clear pointers because the pass constructor will not be invoked again.
- funcDepGraph = NULL;
- funcGraph = NULL;
- funcModRef = NULL;
-}
-
-MemoryDepAnalysis::~MemoryDepAnalysis()
-{
- releaseMemory();
-}
-
-//----END TEMPORARY FUNCTIONS----------------------------------------------
-
-
-void MemoryDepAnalysis::dump() const
-{
- this->print(std::cerr);
-}
-
-static RegisterAnalysis<MemoryDepAnalysis>
-Z("memdep", "Memory Dependence Analysis");
-
diff --git a/poolalloc/lib/DSA/Parallelize.cpp b/poolalloc/lib/DSA/Parallelize.cpp
deleted file mode 100644
index 81a5252..0000000
--- a/poolalloc/lib/DSA/Parallelize.cpp
+++ /dev/null
@@ -1,548 +0,0 @@
-//===- Parallelize.cpp - Auto parallelization using DS Graphs ---*- C++ -*-===//
-//
-// This file implements a pass that automatically parallelizes a program,
-// using the Cilk multi-threaded runtime system to execute parallel code.
-//
-// The pass uses the Program Dependence Graph (class PDGIterator) to
-// identify parallelizable function calls, i.e., calls whose instances
-// can be executed in parallel with instances of other function calls.
-// (In the future, this should also execute different instances of the same
-// function call in parallel, but that requires parallelizing across
-// loop iterations.)
-//
-// The output of the pass is LLVM code with:
-// (1) all parallelizable functions renamed to flag them as parallelizable;
-// (2) calls to a sync() function introduced at synchronization points.
-// The CWriter recognizes these functions and inserts the appropriate Cilk
-// keywords when writing out C code. This C code must be compiled with cilk2c.
-//
-// Current algorithmic limitations:
-// -- no array dependence analysis
-// -- no parallelization for function calls in different loop iterations
-// (except in unlikely trivial cases)
-//
-// Limitations of using Cilk:
-// -- No parallelism within a function body, e.g., in a loop;
-// -- Simplistic synchronization model requiring all parallel threads
-// created within a function to block at a sync().
-// -- Excessive overhead at "spawned" function calls, which has no benefit
-// once all threads are busy (especially common when the degree of
-// parallelism is low).
-//===----------------------------------------------------------------------===//
-
-
-#include "llvm/Transforms/Parallelize.h"
-#include "llvm/Transforms/Utils/DemoteRegToStack.h"
-#include "llvm/Analysis/PgmDependenceGraph.h"
-#include "llvm/Analysis/Dominators.h"
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Module.h"
-#include "llvm/Function.h"
-#include "llvm/iOther.h"
-#include "llvm/iPHINode.h"
-#include "llvm/iTerminators.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Support/InstVisitor.h"
-#include "llvm/Support/Cilkifier.h"
-#include "Support/Statistic.h"
-#include "Support/STLExtras.h"
-#include "Support/hash_set"
-#include "Support/hash_map"
-#include <vector>
-#include <stack>
-#include <functional>
-#include <algorithm>
-
-
-
-#if 0
-void AddToDomSet(vector<BasicBlock*>& domSet, BasicBlock* bb,
- const DominatorTree& domTree)
-{
- DominatorTreeBase::Node* bbNode = domTree.getNode(bb);
- const std::vector<Node*>& domKids = bbNode.getChildren();
- domSet.insert(domSet.end(), domKids.begin(), domKids.end());
- for (unsigned i = 0; i < domKids.size(); ++i)
- AddToDomSet(domSet, domKids[i]->getNode(), domTree);
-}
-
-bool CheckDominance(Function& func,
- const CallInst& callInst1,
- const CallInst& callInst2)
-{
- if (callInst1 == callInst2) // makes sense if this is in a loop but
- return false; // we're not handling loops yet
-
- // Check first if one call dominates the other
- DominatorSet& domSet = getAnalysis<DominatorSet>(func);
- if (domSet.dominates(callInst2, callInst1))
- { // swap callInst1 and callInst2
- const CallInst& tmp = callInst2; callInst2 = callInst1; callInst1 = tmp;
- }
- else if (! domSet.dominates(callInst1, callInst2))
- return false; // neither dominates the other:
-
- //
- if (! AreIndependent(func, callInst1, callInst2))
- return false;
-}
-
-#endif
-
-
-//----------------------------------------------------------------------------
-// class Cilkifier
-//
-// Code generation pass that transforms code to identify where Cilk keywords
-// should be inserted. This relies on dis -c to print out the keywords.
-//----------------------------------------------------------------------------
-
-
-class Cilkifier: public InstVisitor<Cilkifier>
-{
- Function* DummySyncFunc;
-
- // Data used when transforming each function.
- hash_set<const Instruction*> stmtsVisited; // Flags for recursive DFS
- hash_map<const CallInst*, hash_set<CallInst*> > spawnToSyncsMap;
-
- // Input data for the transformation.
- const hash_set<Function*>* cilkFunctions; // Set of parallel functions
- PgmDependenceGraph* depGraph;
-
- void DFSVisitInstr (Instruction* I,
- Instruction* root,
- hash_set<const Instruction*>& depsOfRoot);
-
-public:
- /*ctor*/ Cilkifier (Module& M);
-
- // Transform a single function including its name, its call sites, and syncs
- //
- void TransformFunc (Function* F,
- const hash_set<Function*>& cilkFunctions,
- PgmDependenceGraph& _depGraph);
-
- // The visitor function that does most of the hard work, via DFSVisitInstr
- //
- void visitCallInst(CallInst& CI);
-};
-
-
-Cilkifier::Cilkifier(Module& M)
-{
- // create the dummy Sync function and add it to the Module
- DummySyncFunc = new Function(FunctionType::get( Type::VoidTy,
- std::vector<const Type*>(),
- /*isVararg*/ false),
- GlobalValue::ExternalLinkage, DummySyncFuncName,
- &M);
-}
-
-void Cilkifier::TransformFunc(Function* F,
- const hash_set<Function*>& _cilkFunctions,
- PgmDependenceGraph& _depGraph)
-{
- // Memoize the information for this function
- cilkFunctions = &_cilkFunctions;
- depGraph = &_depGraph;
-
- // Add the marker suffix to the Function name
- // This should automatically mark all calls to the function also!
- F->setName(F->getName() + CilkSuffix);
-
- // Insert sync operations for each separate spawn
- visit(*F);
-
- // Now traverse the CFG in rPostorder and eliminate redundant syncs, i.e.,
- // two consecutive sync's on a straight-line path with no intervening spawn.
-
-}
-
-
-void Cilkifier::DFSVisitInstr(Instruction* I,
- Instruction* root,
- hash_set<const Instruction*>& depsOfRoot)
-{
- assert(stmtsVisited.find(I) == stmtsVisited.end());
- stmtsVisited.insert(I);
-
- // If there is a dependence from root to I, insert Sync and return
- if (depsOfRoot.find(I) != depsOfRoot.end())
- { // Insert a sync before I and stop searching along this path.
- // If I is a Phi instruction, the dependence can only be an SSA dep.
- // and we need to insert the sync in the predecessor on the appropriate
- // incoming edge!
- CallInst* syncI = 0;
- if (PHINode* phiI = dyn_cast<PHINode>(I))
- { // check all operands of the Phi and insert before each one
- for (unsigned i = 0, N = phiI->getNumIncomingValues(); i < N; ++i)
- if (phiI->getIncomingValue(i) == root)
- syncI = new CallInst(DummySyncFunc, std::vector<Value*>(), "",
- phiI->getIncomingBlock(i)->getTerminator());
- }
- else
- syncI = new CallInst(DummySyncFunc, std::vector<Value*>(), "", I);
-
- // Remember the sync for each spawn to eliminate rendundant ones later
- spawnToSyncsMap[cast<CallInst>(root)].insert(syncI);
-
- return;
- }
-
- // else visit unvisited successors
- if (BranchInst* brI = dyn_cast<BranchInst>(I))
- { // visit first instruction in each successor BB
- for (unsigned i = 0, N = brI->getNumSuccessors(); i < N; ++i)
- if (stmtsVisited.find(&brI->getSuccessor(i)->front())
- == stmtsVisited.end())
- DFSVisitInstr(&brI->getSuccessor(i)->front(), root, depsOfRoot);
- }
- else
- if (Instruction* nextI = I->getNext())
- if (stmtsVisited.find(nextI) == stmtsVisited.end())
- DFSVisitInstr(nextI, root, depsOfRoot);
-}
-
-
-void Cilkifier::visitCallInst(CallInst& CI)
-{
- assert(CI.getCalledFunction() != 0 && "Only direct calls can be spawned.");
- if (cilkFunctions->find(CI.getCalledFunction()) == cilkFunctions->end())
- return; // not a spawn
-
- // Find all the outgoing memory dependences.
- hash_set<const Instruction*> depsOfRoot;
- for (PgmDependenceGraph::iterator DI =
- depGraph->outDepBegin(CI, MemoryDeps); ! DI.fini(); ++DI)
- depsOfRoot.insert(&DI->getSink()->getInstr());
-
- // Now find all outgoing SSA dependences to the eventual non-Phi users of
- // the call value (i.e., direct users that are not phis, and for any
- // user that is a Phi, direct non-Phi users of that Phi, and recursively).
- std::stack<const PHINode*> phiUsers;
- hash_set<const PHINode*> phisSeen; // ensures we don't visit a phi twice
- for (Value::use_iterator UI=CI.use_begin(), UE=CI.use_end(); UI != UE; ++UI)
- if (const PHINode* phiUser = dyn_cast<PHINode>(*UI))
- {
- if (phisSeen.find(phiUser) == phisSeen.end())
- {
- phiUsers.push(phiUser);
- phisSeen.insert(phiUser);
- }
- }
- else
- depsOfRoot.insert(cast<Instruction>(*UI));
-
- // Now we've found the non-Phi users and immediate phi users.
- // Recursively walk the phi users and add their non-phi users.
- for (const PHINode* phiUser; !phiUsers.empty(); phiUsers.pop())
- {
- phiUser = phiUsers.top();
- for (Value::use_const_iterator UI=phiUser->use_begin(),
- UE=phiUser->use_end(); UI != UE; ++UI)
- if (const PHINode* pn = dyn_cast<PHINode>(*UI))
- {
- if (phisSeen.find(pn) == phisSeen.end())
- {
- phiUsers.push(pn);
- phisSeen.insert(pn);
- }
- }
- else
- depsOfRoot.insert(cast<Instruction>(*UI));
- }
-
- // Walk paths of the CFG starting at the call instruction and insert
- // one sync before the first dependence on each path, if any.
- if (! depsOfRoot.empty())
- {
- stmtsVisited.clear(); // start a new DFS for this CallInst
- assert(CI.getNext() && "Call instruction cannot be a terminator!");
- DFSVisitInstr(CI.getNext(), &CI, depsOfRoot);
- }
-
- // Now, eliminate all users of the SSA value of the CallInst, i.e.,
- // if the call instruction returns a value, delete the return value
- // register and replace it by a stack slot.
- if (CI.getType() != Type::VoidTy)
- DemoteRegToStack(CI);
-}
-
-
-//----------------------------------------------------------------------------
-// class FindParallelCalls
-//
-// Find all CallInst instructions that have at least one other CallInst
-// that is independent. These are the instructions that can produce
-// useful parallelism.
-//----------------------------------------------------------------------------
-
-class FindParallelCalls : public InstVisitor<FindParallelCalls> {
- typedef hash_set<CallInst*> DependentsSet;
- typedef DependentsSet::iterator Dependents_iterator;
- typedef DependentsSet::const_iterator Dependents_const_iterator;
-
- PgmDependenceGraph& depGraph; // dependence graph for the function
- hash_set<Instruction*> stmtsVisited; // flags for DFS walk of depGraph
- hash_map<CallInst*, bool > completed; // flags marking if a CI is done
- hash_map<CallInst*, DependentsSet> dependents; // dependent CIs for each CI
-
- void VisitOutEdges(Instruction* I,
- CallInst* root,
- DependentsSet& depsOfRoot);
-
- FindParallelCalls(const FindParallelCalls &); // DO NOT IMPLEMENT
- void operator=(const FindParallelCalls&); // DO NOT IMPLEMENT
-public:
- std::vector<CallInst*> parallelCalls;
-
-public:
- /*ctor*/ FindParallelCalls (Function& F, PgmDependenceGraph& DG);
- void visitCallInst (CallInst& CI);
-};
-
-
-FindParallelCalls::FindParallelCalls(Function& F,
- PgmDependenceGraph& DG)
- : depGraph(DG)
-{
- // Find all CallInsts reachable from each CallInst using a recursive DFS
- visit(F);
-
- // Now we've found all CallInsts reachable from each CallInst.
- // Find those CallInsts that are parallel with at least one other CallInst
- // by counting total inEdges and outEdges.
- //
- unsigned long totalNumCalls = completed.size();
-
- if (totalNumCalls == 1)
- { // Check first for the special case of a single call instruction not
- // in any loop. It is not parallel, even if it has no dependences
- // (this is why it is a special case).
- //
- // FIXME:
- // THIS CASE IS NOT HANDLED RIGHT NOW, I.E., THERE IS NO
- // PARALLELISM FOR CALLS IN DIFFERENT ITERATIONS OF A LOOP.
- //
- return;
- }
-
- hash_map<CallInst*, unsigned long> numDeps;
- for (hash_map<CallInst*, DependentsSet>::iterator II = dependents.begin(),
- IE = dependents.end(); II != IE; ++II)
- {
- CallInst* fromCI = II->first;
- numDeps[fromCI] += II->second.size();
- for (Dependents_iterator DI = II->second.begin(), DE = II->second.end();
- DI != DE; ++DI)
- numDeps[*DI]++; // *DI can be reached from II->first
- }
-
- for (hash_map<CallInst*, DependentsSet>::iterator
- II = dependents.begin(), IE = dependents.end(); II != IE; ++II)
-
- // FIXME: Remove "- 1" when considering parallelism in loops
- if (numDeps[II->first] < totalNumCalls - 1)
- parallelCalls.push_back(II->first);
-}
-
-
-void FindParallelCalls::VisitOutEdges(Instruction* I,
- CallInst* root,
- DependentsSet& depsOfRoot)
-{
- assert(stmtsVisited.find(I) == stmtsVisited.end() && "Stmt visited twice?");
- stmtsVisited.insert(I);
-
- if (CallInst* CI = dyn_cast<CallInst>(I))
-
- // FIXME: Ignoring parallelism in a loop. Here we're actually *ignoring*
- // a self-dependence in order to get the count comparison right above.
- // When we include loop parallelism, self-dependences should be included.
- //
- if (CI != root)
-
- { // CallInst root has a path to CallInst I and any calls reachable from I
- depsOfRoot.insert(CI);
- if (completed[CI])
- { // We have already visited I so we know all nodes it can reach!
- DependentsSet& depsOfI = dependents[CI];
- depsOfRoot.insert(depsOfI.begin(), depsOfI.end());
- return;
- }
- }
-
- // If we reach here, we need to visit all children of I
- for (PgmDependenceGraph::iterator DI = depGraph.outDepBegin(*I);
- ! DI.fini(); ++DI)
- {
- Instruction* sink = &DI->getSink()->getInstr();
- if (stmtsVisited.find(sink) == stmtsVisited.end())
- VisitOutEdges(sink, root, depsOfRoot);
- }
-}
-
-
-void FindParallelCalls::visitCallInst(CallInst& CI)
-{
- if (completed[&CI])
- return;
- stmtsVisited.clear(); // clear flags to do a fresh DFS
-
- // Visit all children of CI using a recursive walk through dep graph
- DependentsSet& depsOfRoot = dependents[&CI];
- for (PgmDependenceGraph::iterator DI = depGraph.outDepBegin(CI);
- ! DI.fini(); ++DI)
- {
- Instruction* sink = &DI->getSink()->getInstr();
- if (stmtsVisited.find(sink) == stmtsVisited.end())
- VisitOutEdges(sink, &CI, depsOfRoot);
- }
-
- completed[&CI] = true;
-}
-
-
-//----------------------------------------------------------------------------
-// class Parallelize
-//
-// (1) Find candidate parallel functions: any function F s.t.
-// there is a call C1 to the function F that is followed or preceded
-// by at least one other call C2 that is independent of this one
-// (i.e., there is no dependence path from C1 to C2 or C2 to C1)
-// (2) Label such a function F as a cilk function.
-// (3) Convert every call to F to a spawn
-// (4) For every function X, insert sync statements so that
-// every spawn is postdominated by a sync before any statements
-// with a data dependence to/from the call site for the spawn
-//
-//----------------------------------------------------------------------------
-
-namespace {
- class Parallelize: public Pass
- {
- public:
- /// Driver functions to transform a program
- ///
- bool run(Module& M);
-
- /// getAnalysisUsage - Modifies extensively so preserve nothing.
- /// Uses the DependenceGraph and the Top-down DS Graph (only to find
- /// all functions called via an indirect call).
- ///
- void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<TDDataStructures>();
- AU.addRequired<MemoryDepAnalysis>(); // force this not to be released
- AU.addRequired<PgmDependenceGraph>(); // because it is needed by this
- }
- };
-
- RegisterOpt<Parallelize> X("parallel", "Parallelize program using Cilk");
-}
-
-
-static Function* FindMain(Module& M)
-{
- for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI)
- if (FI->getName() == std::string("main"))
- return FI;
- return NULL;
-}
-
-
-bool Parallelize::run(Module& M)
-{
- hash_set<Function*> parallelFunctions;
- hash_set<Function*> safeParallelFunctions;
- hash_set<const GlobalValue*> indirectlyCalled;
-
- // If there is no main (i.e., for an incomplete program), we can do nothing.
- // If there is a main, mark main as a parallel function.
- //
- Function* mainFunc = FindMain(M);
- if (!mainFunc)
- return false;
-
- // (1) Find candidate parallel functions and mark them as Cilk functions
- //
- for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI)
- if (! FI->isExternal())
- {
- Function* F = FI;
- DSGraph& tdg = getAnalysis<TDDataStructures>().getDSGraph(*F);
-
- // All the hard analysis work gets done here!
- //
- FindParallelCalls finder(*F,
- getAnalysis<PgmDependenceGraph>().getGraph(*F));
- /* getAnalysis<MemoryDepAnalysis>().getGraph(*F)); */
-
- // Now we know which call instructions are useful to parallelize.
- // Remember those callee functions.
- //
- for (std::vector<CallInst*>::iterator
- CII = finder.parallelCalls.begin(),
- CIE = finder.parallelCalls.end(); CII != CIE; ++CII)
- {
- // Check if this is a direct call...
- if ((*CII)->getCalledFunction() != NULL)
- { // direct call: if this is to a non-external function,
- // mark it as a parallelizable function
- if (! (*CII)->getCalledFunction()->isExternal())
- parallelFunctions.insert((*CII)->getCalledFunction());
- }
- else
- { // Indirect call: mark all potential callees as bad
- std::vector<GlobalValue*> callees =
- tdg.getNodeForValue((*CII)->getCalledValue())
- .getNode()->getGlobals();
- indirectlyCalled.insert(callees.begin(), callees.end());
- }
- }
- }
-
- // Remove all indirectly called functions from the list of Cilk functions.
- //
- for (hash_set<Function*>::iterator PFI = parallelFunctions.begin(),
- PFE = parallelFunctions.end(); PFI != PFE; ++PFI)
- if (indirectlyCalled.count(*PFI) == 0)
- safeParallelFunctions.insert(*PFI);
-
-#undef CAN_USE_BIND1ST_ON_REFERENCE_TYPE_ARGS
-#ifdef CAN_USE_BIND1ST_ON_REFERENCE_TYPE_ARGS
- // Use this undecipherable STLese because erase invalidates iterators.
- // Otherwise we have to copy sets as above.
- hash_set<Function*>::iterator extrasBegin =
- std::remove_if(parallelFunctions.begin(), parallelFunctions.end(),
- compose1(std::bind2nd(std::greater<int>(), 0),
- bind_obj(&indirectlyCalled,
- &hash_set<const GlobalValue*>::count)));
- parallelFunctions.erase(extrasBegin, parallelFunctions.end());
-#endif
-
- // If there are no parallel functions, we can just give up.
- if (safeParallelFunctions.empty())
- return false;
-
- // Add main as a parallel function since Cilk requires this.
- safeParallelFunctions.insert(mainFunc);
-
- // (2,3) Transform each Cilk function and all its calls simply by
- // adding a unique suffix to the function name.
- // This should identify both functions and calls to such functions
- // to the code generator.
- // (4) Also, insert calls to sync at appropriate points.
- //
- Cilkifier cilkifier(M);
- for (hash_set<Function*>::iterator CFI = safeParallelFunctions.begin(),
- CFE = safeParallelFunctions.end(); CFI != CFE; ++CFI)
- {
- cilkifier.TransformFunc(*CFI, safeParallelFunctions,
- getAnalysis<PgmDependenceGraph>().getGraph(**CFI));
- /* getAnalysis<MemoryDepAnalysis>().getGraph(**CFI)); */
- }
-
- return true;
-}
diff --git a/poolalloc/lib/DSA/PgmDependenceGraph.cpp b/poolalloc/lib/DSA/PgmDependenceGraph.cpp
deleted file mode 100644
index 705a944..0000000
--- a/poolalloc/lib/DSA/PgmDependenceGraph.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-//===- PgmDependenceGraph.cpp - Enumerate PDG for a function ----*- C++ -*-===//
-//
-// The Program Dependence Graph (PDG) for a single function represents all
-// data and control dependences for the function. This file provides an
-// iterator to enumerate all these dependences. In particular, it enumerates:
-//
-// -- Data dependences on memory locations, computed using the
-// MemoryDepAnalysis pass;
-// -- Data dependences on SSA registers, directly from Def-Use edges of Values;
-// -- Control dependences, computed using postdominance frontiers
-// (NOT YET IMPLEMENTED).
-//
-// Note that this file does not create an explicit dependence graph --
-// it only provides an iterator to traverse the PDG conceptually.
-// The MemoryDepAnalysis does build an explicit graph, which is used internally
-// here. That graph could be augmented with the other dependences above if
-// desired, but for most uses there will be little need to do that.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/PgmDependenceGraph.h"
-#include "llvm/Analysis/MemoryDepAnalysis.h"
-#include "llvm/Analysis/PostDominators.h"
-#include "llvm/Function.h"
-
-
-//----------------------------------------------------------------------------
-// class DepIterState
-//----------------------------------------------------------------------------
-
-const DepIterState::IterStateFlags DepIterState::NoFlag = 0x0;
-const DepIterState::IterStateFlags DepIterState::MemDone = 0x1;
-const DepIterState::IterStateFlags DepIterState::SSADone = 0x2;
-const DepIterState::IterStateFlags DepIterState::AllDone = 0x4;
-const DepIterState::IterStateFlags DepIterState::FirstTimeFlag= 0x8;
-
-// Find the first memory dependence for the current Mem In/Out iterators.
-// Find the first memory dependence for the current Mem In/Out iterators.
-// Sets dep to that dependence and returns true if one is found.
-//
-bool DepIterState::SetFirstMemoryDep()
-{
- if (! (depFlags & MemoryDeps))
- return false;
-
- bool doIncomingDeps = dep.getDepType() & IncomingFlag;
-
- if (( doIncomingDeps && memDepIter == memDepGraph->inDepEnd( *depNode)) ||
- (!doIncomingDeps && memDepIter == memDepGraph->outDepEnd(*depNode)))
- {
- iterFlags |= MemDone;
- return false;
- }
-
- dep = *memDepIter; // simple copy from dependence in memory DepGraph
-
- return true;
-}
-
-
-// Find the first valid data dependence for the current SSA In/Out iterators.
-// A valid data dependence is one that is to/from an Instruction.
-// E.g., an SSA edge from a formal parameter is not a valid dependence.
-// Sets dep to that dependence and returns true if a valid one is found.
-// Returns false and leaves dep unchanged otherwise.
-//
-bool DepIterState::SetFirstSSADep()
-{
- if (! (depFlags & SSADeps))
- return false;
-
- bool doIncomingDeps = dep.getDepType() & IncomingFlag;
- Instruction* firstTarget = NULL;
-
- // Increment the In or Out iterator till it runs out or we find a valid dep
- if (doIncomingDeps)
- for (Instruction::op_iterator E = depNode->getInstr().op_end();
- ssaInEdgeIter != E &&
- (firstTarget = dyn_cast<Instruction>(ssaInEdgeIter))== NULL; )
- ++ssaInEdgeIter;
- else
- for (Value::use_iterator E = depNode->getInstr().use_end();
- ssaOutEdgeIter != E &&
- (firstTarget = dyn_cast<Instruction>(*ssaOutEdgeIter)) == NULL; )
- ++ssaOutEdgeIter;
-
- // If the iterator ran out before we found a valid dep, there isn't one.
- if (!firstTarget)
- {
- iterFlags |= SSADone;
- return false;
- }
-
- // Create a simple dependence object to represent this SSA dependence.
- dep = Dependence(memDepGraph->getNode(*firstTarget, /*create*/ true),
- TrueDependence, doIncomingDeps);
-
- return true;
-}
-
-
-DepIterState::DepIterState(DependenceGraph* _memDepGraph,
- Instruction& I,
- bool incomingDeps,
- PDGIteratorFlags whichDeps)
- : memDepGraph(_memDepGraph),
- depFlags(whichDeps),
- iterFlags(NoFlag)
-{
- depNode = memDepGraph->getNode(I, /*create*/ true);
-
- if (incomingDeps)
- {
- if (whichDeps & MemoryDeps) memDepIter= memDepGraph->inDepBegin(*depNode);
- if (whichDeps & SSADeps) ssaInEdgeIter = I.op_begin();
- /* Initialize control dependence iterator here. */
- }
- else
- {
- if (whichDeps & MemoryDeps) memDepIter=memDepGraph->outDepBegin(*depNode);
- if (whichDeps & SSADeps) ssaOutEdgeIter = I.use_begin();
- /* Initialize control dependence iterator here. */
- }
-
- // Set the dependence to the first of a memory dep or an SSA dep
- // and set the done flag if either is found. Otherwise, set the
- // init flag to indicate that the iterators have just been initialized.
- //
- if (!SetFirstMemoryDep() && !SetFirstSSADep())
- iterFlags |= AllDone;
- else
- iterFlags |= FirstTimeFlag;
-}
-
-
-// Helper function for ++ operator that bumps iterator by 1 (to next
-// dependence) and resets the dep field to represent the new dependence.
-//
-void DepIterState::Next()
-{
- // firstMemDone and firstSsaDone are used to indicate when the memory or
- // SSA iterators just ran out, or when this is the very first increment.
- // In either case, the next iterator (if any) should not be incremented.
- //
- bool firstMemDone = iterFlags & FirstTimeFlag;
- bool firstSsaDone = iterFlags & FirstTimeFlag;
- bool doIncomingDeps = dep.getDepType() & IncomingFlag;
-
- if (depFlags & MemoryDeps && ! (iterFlags & MemDone))
- {
- iterFlags &= ~FirstTimeFlag; // clear "firstTime" flag
- ++memDepIter;
- if (SetFirstMemoryDep())
- return;
- firstMemDone = true; // flags that we _just_ rolled over
- }
-
- if (depFlags & SSADeps && ! (iterFlags & SSADone))
- {
- // Don't increment the SSA iterator if we either just rolled over from
- // the memory dep iterator, or if the SSA iterator is already done.
- iterFlags &= ~FirstTimeFlag; // clear "firstTime" flag
- if (! firstMemDone)
- if (doIncomingDeps) ++ssaInEdgeIter;
- else ++ssaOutEdgeIter;
- if (SetFirstSSADep())
- return;
- firstSsaDone = true; // flags if we just rolled over
- }
-
- if (depFlags & ControlDeps != 0)
- {
- assert(0 && "Cannot handle control deps");
- // iterFlags &= ~FirstTimeFlag; // clear "firstTime" flag
- }
-
- // This iterator is now complete.
- iterFlags |= AllDone;
-}
-
-
-//----------------------------------------------------------------------------
-// class PgmDependenceGraph
-//----------------------------------------------------------------------------
-
-
-// MakeIterator -- Create and initialize an iterator as specified.
-//
-PDGIterator PgmDependenceGraph::MakeIterator(Instruction& I,
- bool incomingDeps,
- PDGIteratorFlags whichDeps)
-{
- assert(memDepGraph && "Function not initialized!");
- return PDGIterator(new DepIterState(memDepGraph, I, incomingDeps, whichDeps));
-}
-
-
-void PgmDependenceGraph::printOutgoingSSADeps(Instruction& I,
- std::ostream &O)
-{
- iterator SI = this->outDepBegin(I, SSADeps);
- iterator SE = this->outDepEnd(I, SSADeps);
- if (SI == SE)
- return;
-
- O << "\n Outgoing SSA dependences:\n";
- for ( ; SI != SE; ++SI)
- {
- O << "\t";
- SI->print(O);
- O << " to instruction:";
- O << SI->getSink()->getInstr();
- }
-}
-
-
-void PgmDependenceGraph::print(std::ostream &O) const
-{
- MemoryDepAnalysis& graphSet = getAnalysis<MemoryDepAnalysis>();
-
- // TEMPORARY LOOP
- for (hash_map<Function*, DependenceGraph*>::iterator
- I = graphSet.funcMap.begin(), E = graphSet.funcMap.end();
- I != E; ++I)
- {
- Function* func = I->first;
- DependenceGraph* depGraph = I->second;
- const_cast<PgmDependenceGraph*>(this)->runOnFunction(*func);
-
- O << "DEPENDENCE GRAPH FOR FUNCTION " << func->getName() << ":\n";
- for (Function::iterator BB=func->begin(), FE=func->end(); BB != FE; ++BB)
- for (BasicBlock::iterator II=BB->begin(), IE=BB->end(); II !=IE; ++II)
- {
- DepGraphNode* dgNode = depGraph->getNode(*II, /*create*/ true);
- dgNode->print(O);
- const_cast<PgmDependenceGraph*>(this)->printOutgoingSSADeps(*II, O);
- }
- } // END TEMPORARY LOOP
-}
-
-
-void PgmDependenceGraph::dump() const
-{
- this->print(std::cerr);
-}
-
-static RegisterAnalysis<PgmDependenceGraph>
-Z("pgmdep", "Enumerate Program Dependence Graph (data and control)");
diff --git a/poolalloc/lib/DSA/Printer.cpp b/poolalloc/lib/DSA/Printer.cpp
deleted file mode 100644
index 87fc1f7..0000000
--- a/poolalloc/lib/DSA/Printer.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-//===- Printer.cpp - Code for printing data structure graphs nicely -------===//
-//
-// This file implements the 'dot' graph printer.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Analysis/DSGraphTraits.h"
-#include "llvm/Module.h"
-#include "llvm/Constants.h"
-#include "llvm/Assembly/Writer.h"
-#include "Support/CommandLine.h"
-#include "Support/GraphWriter.h"
-#include "Support/Statistic.h"
-#include <fstream>
-#include <sstream>
-
-// OnlyPrintMain - The DataStructure printer exposes this option to allow
-// printing of only the graph for "main".
-//
-namespace {
- cl::opt<bool> OnlyPrintMain("only-print-main-ds", cl::ReallyHidden);
- Statistic<> MaxGraphSize ("dsnode", "Maximum graph size");
- Statistic<> NumFoldedNodes ("dsnode", "Number of folded nodes (in final graph)");
-}
-
-
-void DSNode::dump() const { print(std::cerr, 0); }
-
-static std::string getCaption(const DSNode *N, const DSGraph *G) {
- std::stringstream OS;
- Module *M = 0;
- // Get the module from ONE of the functions in the graph it is available.
- if (G && !G->getReturnNodes().empty())
- M = G->getReturnNodes().begin()->first->getParent();
-
- if (N->isNodeCompletelyFolded())
- OS << "COLLAPSED";
- else {
- WriteTypeSymbolic(OS, N->getType(), M);
- if (N->isArray())
- OS << " array";
- }
- if (unsigned NodeType = N->getNodeFlags()) {
- OS << ": ";
- if (NodeType & DSNode::AllocaNode ) OS << "S";
- if (NodeType & DSNode::HeapNode ) OS << "H";
- if (NodeType & DSNode::GlobalNode ) OS << "G";
- if (NodeType & DSNode::UnknownNode) OS << "U";
- if (NodeType & DSNode::Incomplete ) OS << "I";
- if (NodeType & DSNode::Modified ) OS << "M";
- if (NodeType & DSNode::Read ) OS << "R";
-#ifndef NDEBUG
- if (NodeType & DSNode::DEAD ) OS << "<dead>";
-#endif
- OS << "\n";
- }
-
- for (unsigned i = 0, e = N->getGlobals().size(); i != e; ++i) {
- WriteAsOperand(OS, N->getGlobals()[i], false, true, M);
- OS << "\n";
- }
-
- return OS.str();
-}
-
-template<>
-struct DOTGraphTraits<const DSGraph*> : public DefaultDOTGraphTraits {
- static std::string getGraphName(const DSGraph *G) {
- switch (G->getReturnNodes().size()) {
- case 0: return G->getFunctionNames();
- case 1: return "Function " + G->getFunctionNames();
- default: return "Functions: " + G->getFunctionNames();
- }
- }
-
- static const char *getGraphProperties(const DSGraph *G) {
- return "\tsize=\"10,7.5\";\n"
- "\trotate=\"90\";\n";
- }
-
- static std::string getNodeLabel(const DSNode *Node, const DSGraph *Graph) {
- return getCaption(Node, Graph);
- }
-
- static std::string getNodeAttributes(const DSNode *N) {
- return "shape=Mrecord";//fontname=Courier";
- }
-
- /// addCustomGraphFeatures - Use this graph writing hook to emit call nodes
- /// and the return node.
- ///
- static void addCustomGraphFeatures(const DSGraph *G,
- GraphWriter<const DSGraph*> &GW) {
- Module *CurMod = 0;
- if (!G->getReturnNodes().empty())
- CurMod = G->getReturnNodes().begin()->first->getParent();
-
- // Add scalar nodes to the graph...
- const DSGraph::ScalarMapTy &VM = G->getScalarMap();
- for (DSGraph::ScalarMapTy::const_iterator I = VM.begin(); I != VM.end();++I)
- if (!isa<GlobalValue>(I->first) && !isa<ConstantPointerRef>(I->first)) {
- std::stringstream OS;
- WriteAsOperand(OS, I->first, false, true, CurMod);
- GW.emitSimpleNode(I->first, "", OS.str());
-
- // Add edge from return node to real destination
- int EdgeDest = I->second.getOffset() >> DS::PointerShift;
- if (EdgeDest == 0) EdgeDest = -1;
- GW.emitEdge(I->first, -1, I->second.getNode(),
- EdgeDest, "arrowtail=tee,color=gray63");
- }
-
-
- // Output the returned value pointer...
- const DSGraph::ReturnNodesTy &RetNodes = G->getReturnNodes();
- for (DSGraph::ReturnNodesTy::const_iterator I = RetNodes.begin(),
- E = RetNodes.end(); I != E; ++I)
- if (I->second.getNode()) {
- std::string Label;
- if (RetNodes.size() == 1)
- Label = "returning";
- else
- Label = I->first->getName() + " ret node";
- // Output the return node...
- GW.emitSimpleNode((void*)1, "plaintext=circle", Label);
-
- // Add edge from return node to real destination
- int RetEdgeDest = I->second.getOffset() >> DS::PointerShift;;
- if (RetEdgeDest == 0) RetEdgeDest = -1;
- GW.emitEdge((void*)1, -1, I->second.getNode(),
- RetEdgeDest, "arrowtail=tee,color=gray63");
- }
-
- // Output all of the call nodes...
- const std::vector<DSCallSite> &FCs =
- G->shouldPrintAuxCalls() ? G->getAuxFunctionCalls()
- : G->getFunctionCalls();
- for (unsigned i = 0, e = FCs.size(); i != e; ++i) {
- const DSCallSite &Call = FCs[i];
- std::vector<std::string> EdgeSourceCaptions(Call.getNumPtrArgs()+2);
- EdgeSourceCaptions[0] = "r";
- if (Call.isDirectCall())
- EdgeSourceCaptions[1] = Call.getCalleeFunc()->getName();
- else
- EdgeSourceCaptions[1] = "f";
-
- GW.emitSimpleNode(&Call, "shape=record", "call", Call.getNumPtrArgs()+2,
- &EdgeSourceCaptions);
-
- if (DSNode *N = Call.getRetVal().getNode()) {
- int EdgeDest = Call.getRetVal().getOffset() >> DS::PointerShift;
- if (EdgeDest == 0) EdgeDest = -1;
- GW.emitEdge(&Call, 0, N, EdgeDest, "color=gray63,tailclip=false");
- }
-
- // Print out the callee...
- if (Call.isIndirectCall()) {
- DSNode *N = Call.getCalleeNode();
- assert(N && "Null call site callee node!");
- GW.emitEdge(&Call, 1, N, -1, "color=gray63,tailclip=false");
- }
-
- for (unsigned j = 0, e = Call.getNumPtrArgs(); j != e; ++j)
- if (DSNode *N = Call.getPtrArg(j).getNode()) {
- int EdgeDest = Call.getPtrArg(j).getOffset() >> DS::PointerShift;
- if (EdgeDest == 0) EdgeDest = -1;
- GW.emitEdge(&Call, j+2, N, EdgeDest, "color=gray63,tailclip=false");
- }
- }
- }
-};
-
-void DSNode::print(std::ostream &O, const DSGraph *G) const {
- GraphWriter<const DSGraph *> W(O, G);
- W.writeNode(this);
-}
-
-void DSGraph::print(std::ostream &O) const {
- WriteGraph(O, this, "DataStructures");
-}
-
-void DSGraph::writeGraphToFile(std::ostream &O,
- const std::string &GraphName) const {
- std::string Filename = GraphName + ".dot";
- O << "Writing '" << Filename << "'...";
- std::ofstream F(Filename.c_str());
-
- if (F.good()) {
- print(F);
- unsigned NumCalls = shouldPrintAuxCalls() ?
- getAuxFunctionCalls().size() : getFunctionCalls().size();
- O << " [" << getGraphSize() << "+" << NumCalls << "]\n";
- } else {
- O << " error opening file for writing!\n";
- }
-}
-
-/// viewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
-/// then cleanup. For use from the debugger.
-///
-void DSGraph::viewGraph() const {
- std::ofstream F("/tmp/tempgraph.dot");
- if (!F.good()) {
- std::cerr << "Error opening '/tmp/tempgraph.dot' for temporary graph!\n";
- return;
- }
- print(F);
- F.close();
- if (system("dot -Tps /tmp/tempgraph.dot > /tmp/tempgraph.ps"))
- std::cerr << "Error running dot: 'dot' not in path?\n";
- system("gv /tmp/tempgraph.ps");
- system("rm /tmp/tempgraph.dot /tmp/tempgraph.ps");
-}
-
-
-template <typename Collection>
-static void printCollection(const Collection &C, std::ostream &O,
- const Module *M, const std::string &Prefix) {
- if (M == 0) {
- O << "Null Module pointer, cannot continue!\n";
- return;
- }
-
- unsigned TotalNumNodes = 0, TotalCallNodes = 0;
- for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
- if (C.hasGraph(*I)) {
- DSGraph &Gr = C.getDSGraph((Function&)*I);
- TotalNumNodes += Gr.getGraphSize();
- unsigned NumCalls = Gr.shouldPrintAuxCalls() ?
- Gr.getAuxFunctionCalls().size() : Gr.getFunctionCalls().size();
-
- TotalCallNodes += NumCalls;
- if (I->getName() == "main" || !OnlyPrintMain)
- Gr.writeGraphToFile(O, Prefix+I->getName());
- else {
- O << "Skipped Writing '" << Prefix+I->getName() << ".dot'... ["
- << Gr.getGraphSize() << "+" << NumCalls << "]\n";
- }
-
- if (MaxGraphSize < Gr.getNodes().size())
- MaxGraphSize = Gr.getNodes().size();
- for (unsigned i = 0, e = Gr.getNodes().size(); i != e; ++i)
- if (Gr.getNodes()[i]->isNodeCompletelyFolded())
- ++NumFoldedNodes;
- }
-
- DSGraph &GG = C.getGlobalsGraph();
- TotalNumNodes += GG.getGraphSize();
- TotalCallNodes += GG.getFunctionCalls().size();
- if (!OnlyPrintMain) {
- GG.writeGraphToFile(O, Prefix+"GlobalsGraph");
- } else {
- O << "Skipped Writing '" << Prefix << "GlobalsGraph.dot'... ["
- << GG.getGraphSize() << "+" << GG.getFunctionCalls().size() << "]\n";
- }
-
- O << "\nGraphs contain [" << TotalNumNodes << "+" << TotalCallNodes
- << "] nodes total" << std::endl;
-}
-
-
-// print - Print out the analysis results...
-void LocalDataStructures::print(std::ostream &O, const Module *M) const {
- printCollection(*this, O, M, "ds.");
-}
-
-void BUDataStructures::print(std::ostream &O, const Module *M) const {
- printCollection(*this, O, M, "bu.");
-}
-
-void TDDataStructures::print(std::ostream &O, const Module *M) const {
- printCollection(*this, O, M, "td.");
-}
diff --git a/poolalloc/lib/DSA/Steensgaard.cpp b/poolalloc/lib/DSA/Steensgaard.cpp
deleted file mode 100644
index a3034dd..0000000
--- a/poolalloc/lib/DSA/Steensgaard.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-//===- Steensgaard.cpp - Context Insensitive Alias Analysis ---------------===//
-//
-// This pass uses the data structure graphs to implement a simple context
-// insensitive alias analysis. It does this by computing the local analysis
-// graphs for all of the functions, then merging them together into a single big
-// graph without cloning.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Analysis/AliasAnalysis.h"
-#include "llvm/Module.h"
-#include "Support/Debug.h"
-
-namespace {
- class Steens : public Pass, public AliasAnalysis {
- DSGraph *ResultGraph;
- DSGraph *GlobalsGraph; // FIXME: Eliminate globals graph stuff from DNE
- public:
- Steens() : ResultGraph(0), GlobalsGraph(0) {}
- ~Steens() {
- releaseMyMemory();
- assert(ResultGraph == 0 && "releaseMemory not called?");
- }
-
- //------------------------------------------------
- // Implement the Pass API
- //
-
- // run - Build up the result graph, representing the pointer graph for the
- // program.
- //
- bool run(Module &M);
-
- virtual void releaseMyMemory() { delete ResultGraph; ResultGraph = 0; }
-
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- AliasAnalysis::getAnalysisUsage(AU);
- AU.setPreservesAll(); // Does not transform code...
- AU.addRequired<LocalDataStructures>(); // Uses local dsgraph
- AU.addRequired<AliasAnalysis>(); // Chains to another AA impl...
- }
-
- // print - Implement the Pass::print method...
- void print(std::ostream &O, const Module *M) const {
- assert(ResultGraph && "Result graph has not yet been computed!");
- ResultGraph->writeGraphToFile(O, "steensgaards");
- }
-
- //------------------------------------------------
- // Implement the AliasAnalysis API
- //
-
- // alias - This is the only method here that does anything interesting...
- AliasResult alias(const Value *V1, unsigned V1Size,
- const Value *V2, unsigned V2Size);
-
- private:
- void ResolveFunctionCall(Function *F, const DSCallSite &Call,
- DSNodeHandle &RetVal);
- };
-
- // Register the pass...
- RegisterOpt<Steens> X("steens-aa",
- "Steensgaard's alias analysis (DSGraph based)");
-
- // Register as an implementation of AliasAnalysis
- RegisterAnalysisGroup<AliasAnalysis, Steens> Y;
-}
-
-
-/// ResolveFunctionCall - Resolve the actual arguments of a call to function F
-/// with the specified call site descriptor. This function links the arguments
-/// and the return value for the call site context-insensitively.
-///
-void Steens::ResolveFunctionCall(Function *F, const DSCallSite &Call,
- DSNodeHandle &RetVal) {
- assert(ResultGraph != 0 && "Result graph not allocated!");
- DSGraph::ScalarMapTy &ValMap = ResultGraph->getScalarMap();
-
- // Handle the return value of the function...
- if (Call.getRetVal().getNode() && RetVal.getNode())
- RetVal.mergeWith(Call.getRetVal());
-
- // Loop over all pointer arguments, resolving them to their provided pointers
- unsigned PtrArgIdx = 0;
- for (Function::aiterator AI = F->abegin(), AE = F->aend();
- AI != AE && PtrArgIdx < Call.getNumPtrArgs(); ++AI) {
- DSGraph::ScalarMapTy::iterator I = ValMap.find(AI);
- if (I != ValMap.end()) // If its a pointer argument...
- I->second.mergeWith(Call.getPtrArg(PtrArgIdx++));
- }
-}
-
-
-/// run - Build up the result graph, representing the pointer graph for the
-/// program.
-///
-bool Steens::run(Module &M) {
- InitializeAliasAnalysis(this);
- assert(ResultGraph == 0 && "Result graph already allocated!");
- LocalDataStructures &LDS = getAnalysis<LocalDataStructures>();
-
- // Create a new, empty, graph...
- ResultGraph = new DSGraph();
- GlobalsGraph = new DSGraph();
- ResultGraph->setGlobalsGraph(GlobalsGraph);
- ResultGraph->setPrintAuxCalls();
-
- // RetValMap - Keep track of the return values for all functions that return
- // valid pointers.
- //
- DSGraph::ReturnNodesTy RetValMap;
-
- // Loop over the rest of the module, merging graphs for non-external functions
- // into this graph.
- //
- unsigned Count = 0;
- for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
- if (!I->isExternal()) {
- DSGraph::ScalarMapTy ValMap;
- { // Scope to free NodeMap memory ASAP
- DSGraph::NodeMapTy NodeMap;
- const DSGraph &FDSG = LDS.getDSGraph(*I);
- ResultGraph->cloneInto(FDSG, ValMap, RetValMap, NodeMap);
- }
-
- // Incorporate the inlined Function's ScalarMap into the global
- // ScalarMap...
- DSGraph::ScalarMapTy &GVM = ResultGraph->getScalarMap();
- for (DSGraph::ScalarMapTy::iterator I = ValMap.begin(),
- E = ValMap.end(); I != E; ++I)
- GVM[I->first].mergeWith(I->second);
-
- if ((++Count & 1) == 0) // Prune nodes out every other time...
- ResultGraph->removeTriviallyDeadNodes();
- }
-
- // FIXME: Must recalculate and use the Incomplete markers!!
-
- // Now that we have all of the graphs inlined, we can go about eliminating
- // call nodes...
- //
- std::vector<DSCallSite> &Calls =
- ResultGraph->getAuxFunctionCalls();
- assert(Calls.empty() && "Aux call list is already in use??");
-
- // Start with a copy of the original call sites...
- Calls = ResultGraph->getFunctionCalls();
-
- for (unsigned i = 0; i != Calls.size(); ) {
- DSCallSite &CurCall = Calls[i];
-
- // Loop over the called functions, eliminating as many as possible...
- std::vector<GlobalValue*> CallTargets;
- if (CurCall.isDirectCall())
- CallTargets.push_back(CurCall.getCalleeFunc());
- else
- CallTargets = CurCall.getCalleeNode()->getGlobals();
-
- for (unsigned c = 0; c != CallTargets.size(); ) {
- // If we can eliminate this function call, do so!
- bool Eliminated = false;
- if (Function *F = dyn_cast<Function>(CallTargets[c]))
- if (!F->isExternal()) {
- ResolveFunctionCall(F, CurCall, RetValMap[F]);
- Eliminated = true;
- }
- if (Eliminated) {
- CallTargets[c] = CallTargets.back();
- CallTargets.pop_back();
- } else
- ++c; // Cannot eliminate this call, skip over it...
- }
-
- if (CallTargets.empty()) { // Eliminated all calls?
- CurCall = Calls.back(); // Remove entry
- Calls.pop_back();
- } else
- ++i; // Skip this call site...
- }
-
- RetValMap.clear();
-
- // Update the "incomplete" markers on the nodes, ignoring unknownness due to
- // incoming arguments...
- ResultGraph->maskIncompleteMarkers();
- ResultGraph->markIncompleteNodes(DSGraph::IgnoreFormalArgs);
-
- // Remove any nodes that are dead after all of the merging we have done...
- // FIXME: We should be able to disable the globals graph for steens!
- ResultGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals);
-
- DEBUG(print(std::cerr, &M));
- return false;
-}
-
-// alias - This is the only method here that does anything interesting...
-AliasAnalysis::AliasResult Steens::alias(const Value *V1, unsigned V1Size,
- const Value *V2, unsigned V2Size) {
- // FIXME: HANDLE Size argument!
- assert(ResultGraph && "Result graph has not been computed yet!");
-
- DSGraph::ScalarMapTy &GSM = ResultGraph->getScalarMap();
-
- DSGraph::ScalarMapTy::iterator I = GSM.find(const_cast<Value*>(V1));
- if (I != GSM.end() && I->second.getNode()) {
- DSNodeHandle &V1H = I->second;
- DSGraph::ScalarMapTy::iterator J=GSM.find(const_cast<Value*>(V2));
- if (J != GSM.end() && J->second.getNode()) {
- DSNodeHandle &V2H = J->second;
- // If the two pointers point to different data structure graph nodes, they
- // cannot alias!
- if (V1H.getNode() != V2H.getNode()) // FIXME: Handle incompleteness!
- return NoAlias;
-
- // FIXME: If the two pointers point to the same node, and the offsets are
- // different, and the LinkIndex vector doesn't alias the section, then the
- // two pointers do not alias. We need access size information for the two
- // accesses though!
- //
- }
- }
-
- // If we cannot determine alias properties based on our graph, fall back on
- // some other AA implementation.
- //
- return getAnalysis<AliasAnalysis>().alias(V1, V1Size, V2, V2Size);
-}
diff --git a/poolalloc/lib/DSA/TopDownClosure.cpp b/poolalloc/lib/DSA/TopDownClosure.cpp
deleted file mode 100644
index 92a03ee..0000000
--- a/poolalloc/lib/DSA/TopDownClosure.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-//===- TopDownClosure.cpp - Compute the top-down interprocedure closure ---===//
-//
-// This file implements the TDDataStructures class, which represents the
-// Top-down Interprocedural closure of the data structure graph over the
-// program. This is useful (but not strictly necessary?) for applications
-// like pointer analysis.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Module.h"
-#include "llvm/DerivedTypes.h"
-#include "Support/Debug.h"
-#include "Support/Statistic.h"
-#include "DSCallSiteIterator.h"
-
-namespace {
- RegisterAnalysis<TDDataStructures> // Register the pass
- Y("tddatastructure", "Top-down Data Structure Analysis");
-
- Statistic<> NumTDInlines("tddatastructures", "Number of graphs inlined");
-}
-
-/// FunctionHasCompleteArguments - This function returns true if it is safe not
-/// to mark arguments to the function complete.
-///
-/// FIXME: Need to check if all callers have been found, or rather if a
-/// funcpointer escapes!
-///
-static bool FunctionHasCompleteArguments(Function &F) {
- return F.hasInternalLinkage();
-}
-
-// run - Calculate the top down data structure graphs for each function in the
-// program.
-//
-bool TDDataStructures::run(Module &M) {
- BUDataStructures &BU = getAnalysis<BUDataStructures>();
- GlobalsGraph = new DSGraph(BU.getGlobalsGraph());
-
- // Figure out which functions must not mark their arguments complete because
- // they are accessible outside this compilation unit.
- for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
- if (!FunctionHasCompleteArguments(*I))
- ArgsRemainIncomplete.insert(I);
-
- // We want to traverse the call graph in reverse post-order. To do this, we
- // calculate a post-order traversal, then reverse it.
- hash_set<DSGraph*> VisitedGraph;
- std::vector<DSGraph*> PostOrder;
- const BUDataStructures::ActualCalleesTy &ActualCallees =
- getAnalysis<BUDataStructures>().getActualCallees();
-
- // Calculate top-down from main...
- if (Function *F = M.getMainFunction())
- ComputePostOrder(*F, VisitedGraph, PostOrder, ActualCallees);
-
- // Next calculate the graphs for each unreachable function...
- for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
- ComputePostOrder(*I, VisitedGraph, PostOrder, ActualCallees);
-
- VisitedGraph.clear(); // Release memory!
-
- // Visit each of the graphs in reverse post-order now!
- while (!PostOrder.empty()) {
- inlineGraphIntoCallees(*PostOrder.back());
- PostOrder.pop_back();
- }
-
- ArgsRemainIncomplete.clear();
- return false;
-}
-
-
-DSGraph &TDDataStructures::getOrCreateDSGraph(Function &F) {
- DSGraph *&G = DSInfo[&F];
- if (G == 0) { // Not created yet? Clone BU graph...
- G = new DSGraph(getAnalysis<BUDataStructures>().getDSGraph(F));
- G->getAuxFunctionCalls().clear();
- G->setPrintAuxCalls();
- G->setGlobalsGraph(GlobalsGraph);
- }
- return *G;
-}
-
-
-void TDDataStructures::ComputePostOrder(Function &F,hash_set<DSGraph*> &Visited,
- std::vector<DSGraph*> &PostOrder,
- const BUDataStructures::ActualCalleesTy &ActualCallees) {
- if (F.isExternal()) return;
- DSGraph &G = getOrCreateDSGraph(F);
- if (Visited.count(&G)) return;
- Visited.insert(&G);
-
- // Recursively traverse all of the callee graphs.
- const std::vector<DSCallSite> &FunctionCalls = G.getFunctionCalls();
-
- for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i) {
- std::pair<BUDataStructures::ActualCalleesTy::const_iterator,
- BUDataStructures::ActualCalleesTy::const_iterator>
- IP = ActualCallees.equal_range(&FunctionCalls[i].getCallInst());
-
- for (BUDataStructures::ActualCalleesTy::const_iterator I = IP.first;
- I != IP.second; ++I)
- ComputePostOrder(*I->second, Visited, PostOrder, ActualCallees);
- }
-
- PostOrder.push_back(&G);
-}
-
-
-
-
-
-// releaseMemory - If the pass pipeline is done with this pass, we can release
-// our memory... here...
-//
-// FIXME: This should be releaseMemory and will work fine, except that LoadVN
-// has no way to extend the lifetime of the pass, which screws up ds-aa.
-//
-void TDDataStructures::releaseMyMemory() {
- for (hash_map<Function*, DSGraph*>::iterator I = DSInfo.begin(),
- E = DSInfo.end(); I != E; ++I) {
- I->second->getReturnNodes().erase(I->first);
- if (I->second->getReturnNodes().empty())
- delete I->second;
- }
-
- // Empty map so next time memory is released, data structures are not
- // re-deleted.
- DSInfo.clear();
- delete GlobalsGraph;
- GlobalsGraph = 0;
-}
-
-void TDDataStructures::inlineGraphIntoCallees(DSGraph &Graph) {
- // Recompute the Incomplete markers and eliminate unreachable nodes.
- Graph.removeTriviallyDeadNodes();
- Graph.maskIncompleteMarkers();
-
- // If any of the functions has incomplete incoming arguments, don't mark any
- // of them as complete.
- bool HasIncompleteArgs = false;
- const DSGraph::ReturnNodesTy &GraphReturnNodes = Graph.getReturnNodes();
- for (DSGraph::ReturnNodesTy::const_iterator I = GraphReturnNodes.begin(),
- E = GraphReturnNodes.end(); I != E; ++I)
- if (ArgsRemainIncomplete.count(I->first)) {
- HasIncompleteArgs = true;
- break;
- }
-
- // Now fold in the necessary globals from the GlobalsGraph. A global G
- // must be folded in if it exists in the current graph (i.e., is not dead)
- // and it was not inlined from any of my callers. If it was inlined from
- // a caller, it would have been fully consistent with the GlobalsGraph
- // in the caller so folding in is not necessary. Otherwise, this node came
- // solely from this function's BU graph and so has to be made consistent.
- //
- Graph.updateFromGlobalGraph();
-
- // Recompute the Incomplete markers. Depends on whether args are complete
- unsigned Flags
- = HasIncompleteArgs ? DSGraph::MarkFormalArgs : DSGraph::IgnoreFormalArgs;
- Graph.markIncompleteNodes(Flags | DSGraph::IgnoreGlobals);
-
- // Delete dead nodes. Treat globals that are unreachable as dead also.
- Graph.removeDeadNodes(DSGraph::RemoveUnreachableGlobals);
-
- // We are done with computing the current TD Graph! Now move on to
- // inlining the current graph into the graphs for its callees, if any.
- //
- const std::vector<DSCallSite> &FunctionCalls = Graph.getFunctionCalls();
- if (FunctionCalls.empty()) {
- DEBUG(std::cerr << " [TD] No callees for: " << Graph.getFunctionNames()
- << "\n");
- return;
- }
-
- // Now that we have information about all of the callees, propagate the
- // current graph into the callees. Clone only the reachable subgraph at
- // each call-site, not the entire graph (even though the entire graph
- // would be cloned only once, this should still be better on average).
- //
- DEBUG(std::cerr << " [TD] Inlining '" << Graph.getFunctionNames() <<"' into "
- << FunctionCalls.size() << " call nodes.\n");
-
- const BUDataStructures::ActualCalleesTy &ActualCallees =
- getAnalysis<BUDataStructures>().getActualCallees();
-
- // Loop over all the call sites and all the callees at each call site.
- // Clone and merge the reachable subgraph from the call into callee's graph.
- //
- for (unsigned i = 0, e = FunctionCalls.size(); i != e; ++i) {
- // For each function in the invoked function list at this call site...
- std::pair<BUDataStructures::ActualCalleesTy::const_iterator,
- BUDataStructures::ActualCalleesTy::const_iterator>
- IP = ActualCallees.equal_range(&FunctionCalls[i].getCallInst());
-
- // Multiple callees may have the same graph, so try to inline and merge
- // only once for each <callSite,calleeGraph> pair, not once for each
- // <callSite,calleeFunction> pair; the latter will be correct but slower.
- hash_set<DSGraph*> GraphsSeen;
-
- // Loop over each actual callee at this call site
- for (BUDataStructures::ActualCalleesTy::const_iterator I = IP.first;
- I != IP.second; ++I) {
- DSGraph& CalleeGraph = getDSGraph(*I->second);
- assert(&CalleeGraph != &Graph && "TD need not inline graph into self!");
-
- // if this callee graph is already done at this site, skip this callee
- if (GraphsSeen.find(&CalleeGraph) != GraphsSeen.end())
- continue;
- GraphsSeen.insert(&CalleeGraph);
-
- // Get the root nodes for cloning the reachable subgraph into each callee:
- // -- all global nodes that appear in both the caller and the callee
- // -- return value at this call site, if any
- // -- actual arguments passed at this call site
- // -- callee node at this call site, if this is an indirect call (this may
- // not be needed for merging, but allows us to create CS and therefore
- // simplify the merging below).
- hash_set<const DSNode*> RootNodeSet;
- for (DSGraph::ScalarMapTy::const_iterator
- SI = CalleeGraph.getScalarMap().begin(),
- SE = CalleeGraph.getScalarMap().end(); SI != SE; ++SI)
- if (GlobalValue* GV = dyn_cast<GlobalValue>(SI->first)) {
- DSGraph::ScalarMapTy::const_iterator GI=Graph.getScalarMap().find(GV);
- if (GI != Graph.getScalarMap().end())
- RootNodeSet.insert(GI->second.getNode());
- }
-
- if (const DSNode* RetNode = FunctionCalls[i].getRetVal().getNode())
- RootNodeSet.insert(RetNode);
-
- for (unsigned j=0, N=FunctionCalls[i].getNumPtrArgs(); j < N; ++j)
- if (const DSNode* ArgTarget = FunctionCalls[i].getPtrArg(j).getNode())
- RootNodeSet.insert(ArgTarget);
-
- if (FunctionCalls[i].isIndirectCall())
- RootNodeSet.insert(FunctionCalls[i].getCalleeNode());
-
- DEBUG(std::cerr << " [TD] Resolving arguments for callee graph '"
- << CalleeGraph.getFunctionNames()
- << "': " << I->second->getFunctionType()->getNumParams()
- << " args\n at call site (DSCallSite*) 0x"
- << &FunctionCalls[i] << "\n");
-
- DSGraph::NodeMapTy NodeMapInCallee; // map from nodes to clones in callee
- DSGraph::NodeMapTy CompletedMap; // unused map for nodes not to do
- CalleeGraph.cloneReachableSubgraph(Graph, RootNodeSet,
- NodeMapInCallee, CompletedMap,
- DSGraph::StripModRefBits |
- DSGraph::KeepAllocaBit);
-
- // Transform our call site info into the cloned version for CalleeGraph
- DSCallSite CS(FunctionCalls[i], NodeMapInCallee);
-
- // Get the formal argument and return nodes for the called function
- // and merge them with the cloned subgraph. Global nodes were merged
- // already by cloneReachableSubgraph() above.
- CalleeGraph.getCallSiteForArguments(*I->second).mergeWith(CS);
-
- ++NumTDInlines;
- }
- }
-
- DEBUG(std::cerr << " [TD] Done inlining into callees for: "
- << Graph.getFunctionNames() << " [" << Graph.getGraphSize() << "+"
- << Graph.getFunctionCalls().size() << "]\n");
-}
-
diff --git a/poolalloc/lib/PoolAllocate/PoolAllocate.cpp b/poolalloc/lib/PoolAllocate/PoolAllocate.cpp
deleted file mode 100644
index 685071f..0000000
--- a/poolalloc/lib/PoolAllocate/PoolAllocate.cpp
+++ /dev/null
@@ -1,1191 +0,0 @@
-//===-- PoolAllocate.cpp - Pool Allocation Pass ---------------------------===//
-//
-// This transform changes programs so that disjoint data structures are
-// allocated out of different pools of memory, increasing locality.
-//
-//===----------------------------------------------------------------------===//
-
-#define DEBUG_TYPE "PoolAllocation"
-#include "llvm/Transforms/PoolAllocate.h"
-#include "llvm/Transforms/Utils/Cloning.h"
-#include "llvm/Analysis/DataStructure.h"
-#include "llvm/Analysis/DSGraph.h"
-#include "llvm/Module.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Constants.h"
-#include "llvm/Instructions.h"
-#include "llvm/Target/TargetData.h"
-#include "llvm/Support/InstVisitor.h"
-#include "Support/Debug.h"
-#include "Support/VectorExtras.h"
-using namespace PA;
-
-namespace {
- const Type *VoidPtrTy = PointerType::get(Type::SByteTy);
-
- // The type to allocate for a pool descriptor: { sbyte*, uint, uint }
- // void *Data (the data)
- // unsigned NodeSize (size of an allocated node)
- // unsigned FreeablePool (are slabs in the pool freeable upon calls to
- // poolfree?)
- const Type *PoolDescType =
- StructType::get(make_vector<const Type*>(VoidPtrTy, Type::UIntTy,
- Type::UIntTy, 0));
-
- const PointerType *PoolDescPtr = PointerType::get(PoolDescType);
-
- RegisterOpt<PoolAllocate>
- X("poolalloc", "Pool allocate disjoint data structures");
-}
-
-void PoolAllocate::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<BUDataStructures>();
- AU.addRequired<TDDataStructures>();
- AU.addRequired<TargetData>();
-}
-
-// Prints out the functions mapped to the leader of the equivalence class they
-// belong to.
-void PoolAllocate::printFuncECs() {
- std::map<Function*, Function*> &leaderMap = FuncECs.getLeaderMap();
- std::cerr << "Indirect Function Map \n";
- for (std::map<Function*, Function*>::iterator LI = leaderMap.begin(),
- LE = leaderMap.end(); LI != LE; ++LI) {
- std::cerr << LI->first->getName() << ": leader is "
- << LI->second->getName() << "\n";
- }
-}
-
-static void printNTOMap(std::map<Value*, const Value*> &NTOM) {
- std::cerr << "NTOM MAP\n";
- for (std::map<Value*, const Value *>::iterator I = NTOM.begin(),
- E = NTOM.end(); I != E; ++I) {
- if (!isa<Function>(I->first) && !isa<BasicBlock>(I->first))
- std::cerr << *I->first << " to " << *I->second << "\n";
- }
-}
-
-void PoolAllocate::buildIndirectFunctionSets(Module &M) {
- // Iterate over the module looking for indirect calls to functions
-
- // Get top down DSGraph for the functions
- TDDS = &getAnalysis<TDDataStructures>();
-
- for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
-
- DEBUG(std::cerr << "Processing indirect calls function:" << MI->getName() << "\n");
-
- if (MI->isExternal())
- continue;
-
- DSGraph &TDG = TDDS->getDSGraph(*MI);
-
- std::vector<DSCallSite> callSites = TDG.getFunctionCalls();
-
- // For each call site in the function
- // All the functions that can be called at the call site are put in the
- // same equivalence class.
- for (std::vector<DSCallSite>::iterator CSI = callSites.begin(),
- CSE = callSites.end(); CSI != CSE ; ++CSI) {
- if (CSI->isIndirectCall()) {
- DSNode *DSN = CSI->getCalleeNode();
- if (DSN->isIncomplete())
- std::cerr << "Incomplete node " << CSI->getCallInst();
- // assert(DSN->isGlobalNode());
- const std::vector<GlobalValue*> &Callees = DSN->getGlobals();
- if (Callees.size() > 0) {
- Function *firstCalledF = dyn_cast<Function>(*Callees.begin());
- FuncECs.addElement(firstCalledF);
- CallInstTargets.insert(std::pair<CallInst*,Function*>
- (&CSI->getCallInst(),
- firstCalledF));
- if (Callees.size() > 1) {
- for (std::vector<GlobalValue*>::const_iterator CalleesI =
- Callees.begin()+1, CalleesE = Callees.end();
- CalleesI != CalleesE; ++CalleesI) {
- Function *calledF = dyn_cast<Function>(*CalleesI);
- FuncECs.unionSetsWith(firstCalledF, calledF);
- CallInstTargets.insert(std::pair<CallInst*,Function*>
- (&CSI->getCallInst(), calledF));
- }
- }
- } else {
- std::cerr << "No targets " << CSI->getCallInst();
- }
- }
- }
- }
-
- // Print the equivalence classes
- DEBUG(printFuncECs());
-}
-
-bool PoolAllocate::run(Module &M) {
- if (M.begin() == M.end()) return false;
- CurModule = &M;
-
- AddPoolPrototypes();
- BU = &getAnalysis<BUDataStructures>();
-
- buildIndirectFunctionSets(M);
-
- std::map<Function*, Function*> FuncMap;
-
- // Loop over the functions in the original program finding the pool desc.
- // arguments necessary for each function that is indirectly callable.
- // For each equivalence class, make a list of pool arguments and update
- // the PoolArgFirst and PoolArgLast values for each function.
- Module::iterator LastOrigFunction = --M.end();
- for (Module::iterator I = M.begin(); ; ++I) {
- if (!I->isExternal())
- FindFunctionPoolArgs(*I);
- if (I == LastOrigFunction) break;
- }
-
- // Now clone a function using the pool arg list obtained in the previous
- // pass over the modules.
- // Loop over only the function initially in the program, don't traverse newly
- // added ones. If the function uses memory, make its clone.
- for (Module::iterator I = M.begin(); ; ++I) {
- if (!I->isExternal())
- if (Function *R = MakeFunctionClone(*I))
- FuncMap[I] = R;
- if (I == LastOrigFunction) break;
- }
-
- ++LastOrigFunction;
-
- // Now that all call targets are available, rewrite the function bodies of the
- // clones.
- for (Module::iterator I = M.begin(); I != LastOrigFunction; ++I)
- if (!I->isExternal()) {
- std::map<Function*, Function*>::iterator FI = FuncMap.find(I);
- ProcessFunctionBody(*I, FI != FuncMap.end() ? *FI->second : *I);
- }
-
- if (CollapseFlag)
- std::cerr << "Pool Allocation successful! However all data structures may not be pool allocated\n";
-
- return true;
-}
-
-
-// AddPoolPrototypes - Add prototypes for the pool functions to the specified
-// module and update the Pool* instance variables to point to them.
-//
-void PoolAllocate::AddPoolPrototypes() {
- CurModule->addTypeName("PoolDescriptor", PoolDescType);
-
- // Get poolinit function...
- FunctionType *PoolInitTy =
- FunctionType::get(Type::VoidTy,
- make_vector<const Type*>(PoolDescPtr, Type::UIntTy, 0),
- false);
- PoolInit = CurModule->getOrInsertFunction("poolinit", PoolInitTy);
-
- // Get pooldestroy function...
- std::vector<const Type*> PDArgs(1, PoolDescPtr);
- FunctionType *PoolDestroyTy =
- FunctionType::get(Type::VoidTy, PDArgs, false);
- PoolDestroy = CurModule->getOrInsertFunction("pooldestroy", PoolDestroyTy);
-
- // Get the poolalloc function...
- FunctionType *PoolAllocTy = FunctionType::get(VoidPtrTy, PDArgs, false);
- PoolAlloc = CurModule->getOrInsertFunction("poolalloc", PoolAllocTy);
-
- // Get the poolfree function...
- PDArgs.push_back(VoidPtrTy); // Pointer to free
- FunctionType *PoolFreeTy = FunctionType::get(Type::VoidTy, PDArgs, false);
- PoolFree = CurModule->getOrInsertFunction("poolfree", PoolFreeTy);
-
- // The poolallocarray function
- FunctionType *PoolAllocArrayTy =
- FunctionType::get(VoidPtrTy,
- make_vector<const Type*>(PoolDescPtr, Type::UIntTy, 0),
- false);
- PoolAllocArray = CurModule->getOrInsertFunction("poolallocarray",
- PoolAllocArrayTy);
-
-}
-
-// Inline the DSGraphs of functions corresponding to the potential targets at
-// indirect call sites into the DS Graph of the callee.
-// This is required to know what pools to create/pass at the call site in the
-// caller
-//
-void PoolAllocate::InlineIndirectCalls(Function &F, DSGraph &G,
- hash_set<Function*> &visited) {
- std::vector<DSCallSite> callSites = G.getFunctionCalls();
-
- visited.insert(&F);
-
- // For each indirect call site in the function, inline all the potential
- // targets
- for (std::vector<DSCallSite>::iterator CSI = callSites.begin(),
- CSE = callSites.end(); CSI != CSE; ++CSI) {
- if (CSI->isIndirectCall()) {
- CallInst &CI = CSI->getCallInst();
- std::pair<std::multimap<CallInst*, Function*>::iterator,
- std::multimap<CallInst*, Function*>::iterator> Targets =
- CallInstTargets.equal_range(&CI);
- for (std::multimap<CallInst*, Function*>::iterator TFI = Targets.first,
- TFE = Targets.second; TFI != TFE; ++TFI) {
- DSGraph &TargetG = BU->getDSGraph(*TFI->second);
- // Call the function recursively if the callee is not yet inlined
- // and if it hasn't been visited in this sequence of calls
- // The latter is dependent on the fact that the graphs of all functions
- // in an SCC are actually the same
- if (InlinedFuncs.find(TFI->second) == InlinedFuncs.end() &&
- visited.find(TFI->second) == visited.end()) {
- InlineIndirectCalls(*TFI->second, TargetG, visited);
- }
- G.mergeInGraph(*CSI, *TFI->second, TargetG, DSGraph::KeepModRefBits |
- DSGraph::KeepAllocaBit | DSGraph::DontCloneCallNodes |
- DSGraph::DontCloneAuxCallNodes);
- }
- }
- }
-
- // Mark this function as one whose graph is inlined with its indirect
- // function targets' DS Graphs. This ensures that every function is inlined
- // exactly once
- InlinedFuncs.insert(&F);
-}
-
-void PoolAllocate::FindFunctionPoolArgs(Function &F) {
-
- // The DSGraph is merged with the globals graph.
- DSGraph &G = BU->getDSGraph(F);
- G.mergeInGlobalsGraph();
-
- // Inline the potential targets of indirect calls
- hash_set<Function*> visitedFuncs;
- InlineIndirectCalls(F, G, visitedFuncs);
-
- // At this point the DS Graphs have been modified in place including
- // information about globals as well as indirect calls, making it useful
- // for pool allocation
- std::vector<DSNode*> &Nodes = G.getNodes();
- if (Nodes.empty()) return ; // No memory activity, nothing is required
-
- FuncInfo &FI = FunctionInfo[&F]; // Create a new entry for F
-
- FI.Clone = 0;
-
- // Initialize the PoolArgFirst and PoolArgLast for the function depending
- // on whether there have been other functions in the equivalence class
- // that have pool arguments so far in the analysis.
- if (!FuncECs.findClass(&F)) {
- FI.PoolArgFirst = FI.PoolArgLast = 0;
- } else {
- if (EqClass2LastPoolArg.find(FuncECs.findClass(&F)) !=
- EqClass2LastPoolArg.end())
- FI.PoolArgFirst = FI.PoolArgLast =
- EqClass2LastPoolArg[FuncECs.findClass(&F)] + 1;
- else
- FI.PoolArgFirst = FI.PoolArgLast = 0;
- }
-
- // Find DataStructure nodes which are allocated in pools non-local to the
- // current function. This set will contain all of the DSNodes which require
- // pools to be passed in from outside of the function.
- hash_set<DSNode*> &MarkedNodes = FI.MarkedNodes;
-
- // Mark globals and incomplete nodes as live... (this handles arguments)
- if (F.getName() != "main")
- for (unsigned i = 0, e = Nodes.size(); i != e; ++i) {
- if (Nodes[i]->isGlobalNode() && !Nodes[i]->isIncomplete())
- DEBUG(std::cerr << "Global node is not Incomplete\n");
- if ((Nodes[i]->isIncomplete() || Nodes[i]->isGlobalNode()) &&
- Nodes[i]->isHeapNode())
- Nodes[i]->markReachableNodes(MarkedNodes);
- }
-
- // Marked the returned node as alive...
- if (DSNode *RetNode = G.getReturnNodeFor(F).getNode())
- if (RetNode->isHeapNode())
- RetNode->markReachableNodes(MarkedNodes);
-
- if (MarkedNodes.empty()) // We don't need to clone the function if there
- return; // are no incoming arguments to be added.
-
- // Erase any marked node that is not a heap node
-
- for (hash_set<DSNode*>::iterator I = MarkedNodes.begin(),
- E = MarkedNodes.end(); I != E; ) {
- // erase invalidates hash_set iterators if the iterator points to the
- // element being erased
- if (!(*I)->isHeapNode())
- MarkedNodes.erase(I++);
- else
- ++I;
- }
-
- FI.PoolArgLast += MarkedNodes.size();
-
-
- if (FuncECs.findClass(&F)) {
- // Update the equivalence class last pool argument information
- // only if there actually were pool arguments to the function.
- // Also, there is no entry for the Eq. class in EqClass2LastPoolArg
- // if there are no functions in the equivalence class with pool arguments.
- if (FI.PoolArgLast != FI.PoolArgFirst)
- EqClass2LastPoolArg[FuncECs.findClass(&F)] = FI.PoolArgLast - 1;
- }
-
-}
-
-// MakeFunctionClone - If the specified function needs to be modified for pool
-// allocation support, make a clone of it, adding additional arguments as
-// neccesary, and return it. If not, just return null.
-//
-Function *PoolAllocate::MakeFunctionClone(Function &F) {
-
- DSGraph &G = BU->getDSGraph(F);
-
- std::vector<DSNode*> &Nodes = G.getNodes();
- if (Nodes.empty())
- return 0;
-
- FuncInfo &FI = FunctionInfo[&F];
-
- hash_set<DSNode*> &MarkedNodes = FI.MarkedNodes;
-
- if (!FuncECs.findClass(&F)) {
- // Not in any equivalence class
- if (MarkedNodes.empty())
- return 0;
- } else {
- // No need to clone if there are no pool arguments in any function in the
- // equivalence class
- if (!EqClass2LastPoolArg.count(FuncECs.findClass(&F)))
- return 0;
- }
-
- // Figure out what the arguments are to be for the new version of the function
- const FunctionType *OldFuncTy = F.getFunctionType();
- std::vector<const Type*> ArgTys;
- if (!FuncECs.findClass(&F)) {
- ArgTys.reserve(OldFuncTy->getParamTypes().size() + MarkedNodes.size());
- FI.ArgNodes.reserve(MarkedNodes.size());
- for (hash_set<DSNode*>::iterator I = MarkedNodes.begin(),
- E = MarkedNodes.end(); I != E; ++I) {
- ArgTys.push_back(PoolDescPtr); // Add the appropriate # of pool descs
- FI.ArgNodes.push_back(*I);
- }
- if (FI.ArgNodes.empty()) return 0; // No nodes to be pool allocated!
-
- }
- else {
- // This function is a member of an equivalence class and needs to be cloned
- ArgTys.reserve(OldFuncTy->getParamTypes().size() +
- EqClass2LastPoolArg[FuncECs.findClass(&F)] + 1);
- FI.ArgNodes.reserve(EqClass2LastPoolArg[FuncECs.findClass(&F)] + 1);
-
- for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i) {
- ArgTys.push_back(PoolDescPtr); // Add the appropriate # of pool
- // descs
- }
-
- for (hash_set<DSNode*>::iterator I = MarkedNodes.begin(),
- E = MarkedNodes.end(); I != E; ++I) {
- FI.ArgNodes.push_back(*I);
- }
-
- assert ((FI.ArgNodes.size() == (unsigned) (FI.PoolArgLast -
- FI.PoolArgFirst)) &&
- "Number of ArgNodes equal to the number of pool arguments used by this function");
-
- if (FI.ArgNodes.empty()) return 0;
- }
-
-
- ArgTys.insert(ArgTys.end(), OldFuncTy->getParamTypes().begin(),
- OldFuncTy->getParamTypes().end());
-
-
- // Create the new function prototype
- FunctionType *FuncTy = FunctionType::get(OldFuncTy->getReturnType(), ArgTys,
- OldFuncTy->isVarArg());
- // Create the new function...
- Function *New = new Function(FuncTy, GlobalValue::InternalLinkage,
- F.getName(), F.getParent());
-
- // Set the rest of the new arguments names to be PDa<n> and add entries to the
- // pool descriptors map
- std::map<DSNode*, Value*> &PoolDescriptors = FI.PoolDescriptors;
- Function::aiterator NI = New->abegin();
-
- if (FuncECs.findClass(&F)) {
- // If the function belongs to an equivalence class
- for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i,
- ++NI)
- NI->setName("PDa");
-
- NI = New->abegin();
- if (FI.PoolArgFirst > 0)
- for (int i = 0; i < FI.PoolArgFirst; ++NI, ++i)
- ;
-
- for (unsigned i = 0, e = FI.ArgNodes.size(); i != e; ++i, ++NI)
- PoolDescriptors.insert(std::make_pair(FI.ArgNodes[i], NI));
-
- NI = New->abegin();
- if (EqClass2LastPoolArg.count(FuncECs.findClass(&F)))
- for (int i = 0; i <= EqClass2LastPoolArg[FuncECs.findClass(&F)]; ++i, ++NI)
- ;
- } else {
- // If the function does not belong to an equivalence class
- if (FI.ArgNodes.size())
- for (unsigned i = 0, e = FI.ArgNodes.size(); i != e; ++i, ++NI) {
- NI->setName("PDa"); // Add pd entry
- PoolDescriptors.insert(std::make_pair(FI.ArgNodes[i], NI));
- }
- NI = New->abegin();
- if (FI.ArgNodes.size())
- for (unsigned i = 0; i < FI.ArgNodes.size(); ++NI, ++i)
- ;
- }
-
- // Map the existing arguments of the old function to the corresponding
- // arguments of the new function.
- std::map<const Value*, Value*> ValueMap;
- if (NI != New->aend())
- for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I, ++NI) {
- ValueMap[I] = NI;
- NI->setName(I->getName());
- }
-
- // Populate the value map with all of the globals in the program.
- // FIXME: This should be unneccesary!
- Module &M = *F.getParent();
- for (Module::iterator I = M.begin(), E=M.end(); I!=E; ++I) ValueMap[I] = I;
- for (Module::giterator I = M.gbegin(), E=M.gend(); I!=E; ++I) ValueMap[I] = I;
-
- // Perform the cloning.
- std::vector<ReturnInst*> Returns;
- CloneFunctionInto(New, &F, ValueMap, Returns);
-
- // Invert the ValueMap into the NewToOldValueMap
- std::map<Value*, const Value*> &NewToOldValueMap = FI.NewToOldValueMap;
- for (std::map<const Value*, Value*>::iterator I = ValueMap.begin(),
- E = ValueMap.end(); I != E; ++I)
- NewToOldValueMap.insert(std::make_pair(I->second, I->first));
-
- return FI.Clone = New;
-}
-
-
-// processFunction - Pool allocate any data structures which are contained in
-// the specified function...
-//
-void PoolAllocate::ProcessFunctionBody(Function &F, Function &NewF) {
- DSGraph &G = BU->getDSGraph(F);
-
- std::vector<DSNode*> &Nodes = G.getNodes();
- if (Nodes.empty()) return; // Quick exit if nothing to do...
-
- FuncInfo &FI = FunctionInfo[&F]; // Get FuncInfo for F
- hash_set<DSNode*> &MarkedNodes = FI.MarkedNodes;
-
- DEBUG(std::cerr << "[" << F.getName() << "] Pool Allocate: ");
-
- // Loop over all of the nodes which are non-escaping, adding pool-allocatable
- // ones to the NodesToPA vector.
- std::vector<DSNode*> NodesToPA;
- for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
- if (Nodes[i]->isHeapNode() && // Pick nodes with heap elems
- !MarkedNodes.count(Nodes[i])) // Can't be marked
- NodesToPA.push_back(Nodes[i]);
-
- DEBUG(std::cerr << NodesToPA.size() << " nodes to pool allocate\n");
- if (!NodesToPA.empty()) {
- // Create pool construction/destruction code
- std::map<DSNode*, Value*> &PoolDescriptors = FI.PoolDescriptors;
- CreatePools(NewF, NodesToPA, PoolDescriptors);
- }
-
- // Transform the body of the function now...
- TransformFunctionBody(NewF, F, G, FI);
-}
-
-
-// CreatePools - This creates the pool initialization and destruction code for
-// the DSNodes specified by the NodesToPA list. This adds an entry to the
-// PoolDescriptors map for each DSNode.
-//
-void PoolAllocate::CreatePools(Function &F,
- const std::vector<DSNode*> &NodesToPA,
- std::map<DSNode*, Value*> &PoolDescriptors) {
- // Find all of the return nodes in the CFG...
- std::vector<BasicBlock*> ReturnNodes;
- for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
- if (isa<ReturnInst>(I->getTerminator()))
- ReturnNodes.push_back(I);
-
- TargetData &TD = getAnalysis<TargetData>();
-
- // Loop over all of the pools, inserting code into the entry block of the
- // function for the initialization and code in the exit blocks for
- // destruction.
- //
- Instruction *InsertPoint = F.front().begin();
- for (unsigned i = 0, e = NodesToPA.size(); i != e; ++i) {
- DSNode *Node = NodesToPA[i];
-
- // Create a new alloca instruction for the pool...
- Value *AI = new AllocaInst(PoolDescType, 0, "PD", InsertPoint);
-
- Value *ElSize;
-
- // Void types in DS graph are never used
- if (Node->getType() != Type::VoidTy)
- ElSize = ConstantUInt::get(Type::UIntTy, TD.getTypeSize(Node->getType()));
- else {
- DEBUG(std::cerr << "Potential node collapsing in " << F.getName()
- << ". All Data Structures may not be pool allocated\n");
- ElSize = ConstantUInt::get(Type::UIntTy, 0);
- }
-
- // Insert the call to initialize the pool...
- new CallInst(PoolInit, make_vector(AI, ElSize, 0), "", InsertPoint);
-
- // Update the PoolDescriptors map
- PoolDescriptors.insert(std::make_pair(Node, AI));
-
- // Insert a call to pool destroy before each return inst in the function
- for (unsigned r = 0, e = ReturnNodes.size(); r != e; ++r)
- new CallInst(PoolDestroy, make_vector(AI, 0), "",
- ReturnNodes[r]->getTerminator());
- }
-}
-
-
-namespace {
- /// FuncTransform - This class implements transformation required of pool
- /// allocated functions.
- struct FuncTransform : public InstVisitor<FuncTransform> {
- PoolAllocate &PAInfo;
- DSGraph &G; // The Bottom-up DS Graph
- DSGraph &TDG; // The Top-down DS Graph
- FuncInfo &FI;
-
- FuncTransform(PoolAllocate &P, DSGraph &g, DSGraph &tdg, FuncInfo &fi)
- : PAInfo(P), G(g), TDG(tdg), FI(fi) {
- }
-
- void visitMallocInst(MallocInst &MI);
- void visitFreeInst(FreeInst &FI);
- void visitCallInst(CallInst &CI);
-
- // The following instructions are never modified by pool allocation
- void visitBranchInst(BranchInst &I) { }
- void visitBinaryOperator(Instruction &I) { }
- void visitShiftInst (ShiftInst &I) { }
- void visitSwitchInst (SwitchInst &I) { }
- void visitCastInst (CastInst &I) { }
- void visitAllocaInst(AllocaInst &I) { }
- void visitLoadInst(LoadInst &I) { }
- void visitGetElementPtrInst (GetElementPtrInst &I) { }
-
- void visitReturnInst(ReturnInst &I);
- void visitStoreInst (StoreInst &I);
- void visitPHINode(PHINode &I);
-
- void visitInstruction(Instruction &I) {
- std::cerr << "PoolAllocate does not recognize this instruction\n";
- abort();
- }
-
- private:
- DSNodeHandle& getDSNodeHFor(Value *V) {
- // if (isa<Constant>(V))
- // return DSNodeHandle();
-
- if (!FI.NewToOldValueMap.empty()) {
- // If the NewToOldValueMap is in effect, use it.
- std::map<Value*,const Value*>::iterator I = FI.NewToOldValueMap.find(V);
- if (I != FI.NewToOldValueMap.end())
- V = (Value*)I->second;
- }
-
- return G.getScalarMap()[V];
- }
-
- DSNodeHandle& getTDDSNodeHFor(Value *V) {
- if (!FI.NewToOldValueMap.empty()) {
- // If the NewToOldValueMap is in effect, use it.
- std::map<Value*,const Value*>::iterator I = FI.NewToOldValueMap.find(V);
- if (I != FI.NewToOldValueMap.end())
- V = (Value*)I->second;
- }
-
- return TDG.getScalarMap()[V];
- }
-
- Value *getPoolHandle(Value *V) {
- DSNode *Node = getDSNodeHFor(V).getNode();
- // Get the pool handle for this DSNode...
- std::map<DSNode*, Value*>::iterator I = FI.PoolDescriptors.find(Node);
-
- if (I != FI.PoolDescriptors.end()) {
- // Check that the node pointed to by V in the TD DS graph is not
- // collapsed
- DSNode *TDNode = getTDDSNodeHFor(V).getNode();
- if (TDNode->getType() != Type::VoidTy)
- return I->second;
- else {
- PAInfo.CollapseFlag = 1;
- return 0;
- }
- }
- else
- return 0;
-
- }
-
- bool isFuncPtr(Value *V);
-
- Function* getFuncClass(Value *V);
-
- Value* retCloneIfFunc(Value *V);
- };
-}
-
-void PoolAllocate::TransformFunctionBody(Function &F, Function &OldF,
- DSGraph &G, FuncInfo &FI) {
- FuncTransform(*this, G, TDDS->getDSGraph(OldF), FI).visit(F);
-}
-
-// Returns true if V is a function pointer
-bool FuncTransform::isFuncPtr(Value *V) {
- if (const PointerType *PTy = dyn_cast<PointerType>(V->getType()))
- return isa<FunctionType>(PTy->getElementType());
- return false;
-}
-
-// Given a function pointer, return the function eq. class if one exists
-Function* FuncTransform::getFuncClass(Value *V) {
- // Look at DSGraph and see if the set of of functions it could point to
- // are pool allocated.
-
- if (!isFuncPtr(V))
- return 0;
-
- // Two cases:
- // if V is a constant
- if (Function *theFunc = dyn_cast<Function>(V)) {
- if (!PAInfo.FuncECs.findClass(theFunc))
- // If this function does not belong to any equivalence class
- return 0;
- if (PAInfo.EqClass2LastPoolArg.count(PAInfo.FuncECs.findClass(theFunc)))
- return PAInfo.FuncECs.findClass(theFunc);
- else
- return 0;
- }
-
- // if V is not a constant
- DSNode *DSN = TDG.getNodeForValue(V).getNode();
- if (!DSN) {
- return 0;
- }
- const std::vector<GlobalValue*> &Callees = DSN->getGlobals();
- if (Callees.size() > 0) {
- Function *calledF = dyn_cast<Function>(*Callees.begin());
- assert(PAInfo.FuncECs.findClass(calledF) && "should exist in some eq. class");
- if (PAInfo.EqClass2LastPoolArg.count(PAInfo.FuncECs.findClass(calledF)))
- return PAInfo.FuncECs.findClass(calledF);
- }
-
- return 0;
-}
-
-// Returns the clone if V is a static function (not a pointer) and belongs
-// to an equivalence class i.e. is pool allocated
-Value* FuncTransform::retCloneIfFunc(Value *V) {
- if (Function *fixedFunc = dyn_cast<Function>(V))
- if (getFuncClass(V))
- return PAInfo.getFuncInfo(*fixedFunc)->Clone;
-
- return 0;
-}
-
-void FuncTransform::visitReturnInst (ReturnInst &RI) {
- if (RI.getNumOperands())
- if (Value *clonedFunc = retCloneIfFunc(RI.getOperand(0))) {
- // Cast the clone of RI.getOperand(0) to the non-pool-allocated type
- CastInst *CastI = new CastInst(clonedFunc, RI.getOperand(0)->getType(),
- "tmp", &RI);
- // Insert return instruction that returns the casted value
- ReturnInst *RetI = new ReturnInst(CastI, &RI);
-
- // Remove original return instruction
- RI.getParent()->getInstList().erase(&RI);
-
- if (!FI.NewToOldValueMap.empty()) {
- std::map<Value*,const Value*>::iterator II =
- FI.NewToOldValueMap.find(&RI);
- assert(II != FI.NewToOldValueMap.end() &&
- "RI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(RetI, II->second));
- FI.NewToOldValueMap.erase(II);
- }
- }
-}
-
-void FuncTransform::visitStoreInst (StoreInst &SI) {
- // Check if a constant function is being stored
- if (Value *clonedFunc = retCloneIfFunc(SI.getOperand(0))) {
- CastInst *CastI = new CastInst(clonedFunc, SI.getOperand(0)->getType(),
- "tmp", &SI);
- StoreInst *StoreI = new StoreInst(CastI, SI.getOperand(1), &SI);
- SI.getParent()->getInstList().erase(&SI);
-
- // Update the NewToOldValueMap if this is a clone
- if (!FI.NewToOldValueMap.empty()) {
- std::map<Value*,const Value*>::iterator II =
- FI.NewToOldValueMap.find(&SI);
- assert(II != FI.NewToOldValueMap.end() &&
- "SI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(StoreI, II->second));
- FI.NewToOldValueMap.erase(II);
- }
- }
-}
-
-void FuncTransform::visitPHINode(PHINode &PI) {
- // If any of the operands of the PHI node is a constant function pointer
- // that is cloned, the cast instruction has to be inserted at the end of the
- // previous basic block
-
- if (isFuncPtr(&PI)) {
- PHINode *V = new PHINode(PI.getType(), PI.getName(), &PI);
- for (unsigned i = 0 ; i < PI.getNumIncomingValues(); ++i) {
- if (Value *clonedFunc = retCloneIfFunc(PI.getIncomingValue(i))) {
- // Insert CastInst at the end of PI.getIncomingBlock(i)
- BasicBlock::iterator BBI = --PI.getIncomingBlock(i)->end();
- // BBI now points to the terminator instruction of the basic block.
- CastInst *CastI = new CastInst(clonedFunc, PI.getType(), "tmp", BBI);
- V->addIncoming(CastI, PI.getIncomingBlock(i));
- } else {
- V->addIncoming(PI.getIncomingValue(i), PI.getIncomingBlock(i));
- }
-
- }
- PI.replaceAllUsesWith(V);
- PI.getParent()->getInstList().erase(&PI);
-
- DSGraph::ScalarMapTy &SM = G.getScalarMap();
- DSGraph::ScalarMapTy::iterator PII = SM.find(&PI);
-
- // Update Scalar map of DSGraph if this is one of the original functions
- // Otherwise update the NewToOldValueMap
- if (PII != SM.end()) {
- SM.insert(std::make_pair(V, PII->second));
- SM.erase(PII); // Destroy the PHINode
- } else {
- std::map<Value*,const Value*>::iterator II =
- FI.NewToOldValueMap.find(&PI);
- assert(II != FI.NewToOldValueMap.end() &&
- "PhiI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(V, II->second));
- FI.NewToOldValueMap.erase(II);
- }
- }
-}
-
-void FuncTransform::visitMallocInst(MallocInst &MI) {
- // Get the pool handle for the node that this contributes to...
- Value *PH = getPoolHandle(&MI);
-
- // NB: PH is zero even if the node is collapsed
- if (PH == 0) return;
-
- // Insert a call to poolalloc
- Value *V;
- if (MI.isArrayAllocation())
- V = new CallInst(PAInfo.PoolAllocArray,
- make_vector(PH, MI.getOperand(0), 0),
- MI.getName(), &MI);
- else
- V = new CallInst(PAInfo.PoolAlloc, make_vector(PH, 0),
- MI.getName(), &MI);
-
- MI.setName(""); // Nuke MIs name
-
- Value *Casted = V;
-
- // Cast to the appropriate type if necessary
- if (V->getType() != MI.getType()) {
- Casted = new CastInst(V, MI.getType(), V->getName(), &MI);
- }
-
- // Update def-use info
- MI.replaceAllUsesWith(Casted);
-
- // Remove old malloc instruction
- MI.getParent()->getInstList().erase(&MI);
-
- DSGraph::ScalarMapTy &SM = G.getScalarMap();
- DSGraph::ScalarMapTy::iterator MII = SM.find(&MI);
-
- // If we are modifying the original function, update the DSGraph...
- if (MII != SM.end()) {
- // V and Casted now point to whatever the original malloc did...
- SM.insert(std::make_pair(V, MII->second));
- if (V != Casted)
- SM.insert(std::make_pair(Casted, MII->second));
- SM.erase(MII); // The malloc is now destroyed
- } else { // Otherwise, update the NewToOldValueMap
- std::map<Value*,const Value*>::iterator MII =
- FI.NewToOldValueMap.find(&MI);
- assert(MII != FI.NewToOldValueMap.end() && "MI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(V, MII->second));
- if (V != Casted)
- FI.NewToOldValueMap.insert(std::make_pair(Casted, MII->second));
- FI.NewToOldValueMap.erase(MII);
- }
-}
-
-void FuncTransform::visitFreeInst(FreeInst &FrI) {
- Value *Arg = FrI.getOperand(0);
- Value *PH = getPoolHandle(Arg); // Get the pool handle for this DSNode...
- if (PH == 0) return;
- // Insert a cast and a call to poolfree...
- Value *Casted = Arg;
- if (Arg->getType() != PointerType::get(Type::SByteTy))
- Casted = new CastInst(Arg, PointerType::get(Type::SByteTy),
- Arg->getName()+".casted", &FrI);
-
- CallInst *FreeI = new CallInst(PAInfo.PoolFree, make_vector(PH, Casted, 0),
- "", &FrI);
- // Delete the now obsolete free instruction...
- FrI.getParent()->getInstList().erase(&FrI);
-
- // Update the NewToOldValueMap if this is a clone
- if (!FI.NewToOldValueMap.empty()) {
- std::map<Value*,const Value*>::iterator II =
- FI.NewToOldValueMap.find(&FrI);
- assert(II != FI.NewToOldValueMap.end() &&
- "FrI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(FreeI, II->second));
- FI.NewToOldValueMap.erase(II);
- }
-}
-
-static void CalcNodeMapping(DSNodeHandle& Caller, DSNodeHandle& Callee,
- std::map<DSNode*, DSNode*> &NodeMapping) {
- DSNode *CalleeNode = Callee.getNode();
- DSNode *CallerNode = Caller.getNode();
-
- unsigned CalleeOffset = Callee.getOffset();
- unsigned CallerOffset = Caller.getOffset();
-
- if (CalleeNode == 0) return;
-
- // If callee has a node and caller doesn't, then a constant argument was
- // passed by the caller
- if (CallerNode == 0) {
- NodeMapping.insert(NodeMapping.end(), std::make_pair(CalleeNode,
- (DSNode *) 0));
- }
-
- // Map the callee node to the caller node.
- // NB: The callee node could be of a different type. Eg. if it points to the
- // field of a struct that the caller points to
- std::map<DSNode*, DSNode*>::iterator I = NodeMapping.find(CalleeNode);
- if (I != NodeMapping.end()) { // Node already in map...
- assert(I->second == CallerNode &&
- "Node maps to different nodes on paths?");
- } else {
- NodeMapping.insert(I, std::make_pair(CalleeNode, CallerNode));
-
- if (CalleeNode->getType() != CallerNode->getType() && CallerOffset == 0)
- DEBUG(std::cerr << "NB: Mapping of nodes between different types\n");
-
- // Recursively map the callee links to the caller links starting from the
- // offset in the node into which they are mapped.
- // Being a BU Graph, the callee ought to have smaller number of links unless
- // there is collapsing in the caller
- unsigned numCallerLinks = CallerNode->getNumLinks() - CallerOffset;
- unsigned numCalleeLinks = CalleeNode->getNumLinks() - CalleeOffset;
-
- if (numCallerLinks > 0) {
- if (numCallerLinks < numCalleeLinks) {
- DEBUG(std::cerr << "Potential node collapsing in caller\n");
- for (unsigned i = 0, e = numCalleeLinks; i != e; ++i)
- CalcNodeMapping(CallerNode->getLink(((i%numCallerLinks) << DS::PointerShift) + CallerOffset), CalleeNode->getLink((i << DS::PointerShift) + CalleeOffset), NodeMapping);
- } else {
- for (unsigned i = 0, e = numCalleeLinks; i != e; ++i)
- CalcNodeMapping(CallerNode->getLink((i << DS::PointerShift) + CallerOffset), CalleeNode->getLink((i << DS::PointerShift) + CalleeOffset), NodeMapping);
- }
- } else if (numCalleeLinks > 0) {
- DEBUG(std::cerr <<
- "Caller has unexpanded node, due to indirect call perhaps!\n");
- }
- }
-}
-
-void FuncTransform::visitCallInst(CallInst &CI) {
- Function *CF = CI.getCalledFunction();
-
- // optimization for function pointers that are basically gotten from a cast
- // with only one use and constant expressions with casts in them
- if (!CF) {
- if (CastInst* CastI = dyn_cast<CastInst>(CI.getCalledValue())) {
- if (isa<Function>(CastI->getOperand(0)) &&
- CastI->getOperand(0)->getType() == CastI->getType())
- CF = dyn_cast<Function>(CastI->getOperand(0));
- } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(CI.getOperand(0))) {
- if (CE->getOpcode() == Instruction::Cast) {
- if (isa<ConstantPointerRef>(CE->getOperand(0)))
- return;
- else
- assert(0 && "Function pointer cast not handled as called function\n");
- }
- }
-
- }
-
- DSGraph &CallerG = G;
-
- std::vector<Value*> Args;
- if (!CF) { // Indirect call
- DEBUG(std::cerr << " Handling call: " << CI);
-
- std::map<unsigned, Value*> PoolArgs;
- Function *FuncClass;
-
- std::pair<std::multimap<CallInst*, Function*>::iterator,
- std::multimap<CallInst*, Function*>::iterator> Targets =
- PAInfo.CallInstTargets.equal_range(&CI);
- for (std::multimap<CallInst*, Function*>::iterator TFI = Targets.first,
- TFE = Targets.second; TFI != TFE; ++TFI) {
- if (TFI == Targets.first) {
- FuncClass = PAInfo.FuncECs.findClass(TFI->second);
- // Nothing to transform if there are no pool arguments in this
- // equivalence class of functions.
- if (!PAInfo.EqClass2LastPoolArg.count(FuncClass))
- return;
- }
-
- FuncInfo *CFI = PAInfo.getFuncInfo(*TFI->second);
-
- if (!CFI->ArgNodes.size()) continue; // Nothing to transform...
-
- DSGraph &CG = PAInfo.getBUDataStructures().getDSGraph(*TFI->second);
- std::map<DSNode*, DSNode*> NodeMapping;
-
- Function::aiterator AI = TFI->second->abegin(), AE = TFI->second->aend();
- unsigned OpNum = 1;
- for ( ; AI != AE; ++AI, ++OpNum) {
- if (!isa<Constant>(CI.getOperand(OpNum)))
- CalcNodeMapping(getDSNodeHFor(CI.getOperand(OpNum)),
- CG.getScalarMap()[AI], NodeMapping);
- }
- assert(OpNum == CI.getNumOperands() && "Varargs calls not handled yet!");
-
- if (CI.getType() != Type::VoidTy)
- CalcNodeMapping(getDSNodeHFor(&CI),
- CG.getReturnNodeFor(*TFI->second), NodeMapping);
-
- // Map the nodes that are pointed to by globals.
- // For all globals map getDSNodeForGlobal(g)->CG.getDSNodeForGlobal(g)
- for (DSGraph::ScalarMapTy::iterator SMI = G.getScalarMap().begin(),
- SME = G.getScalarMap().end(); SMI != SME; ++SMI)
- if (isa<GlobalValue>(SMI->first)) {
- CalcNodeMapping(SMI->second,
- CG.getScalarMap()[SMI->first], NodeMapping);
- }
-
- unsigned idx = CFI->PoolArgFirst;
-
- // The following loop determines the pool pointers corresponding to
- // CFI.
- for (unsigned i = 0, e = CFI->ArgNodes.size(); i != e; ++i, ++idx) {
- if (NodeMapping.count(CFI->ArgNodes[i])) {
- assert(NodeMapping.count(CFI->ArgNodes[i]) && "Node not in mapping!");
- DSNode *LocalNode = NodeMapping.find(CFI->ArgNodes[i])->second;
- if (LocalNode) {
- assert(FI.PoolDescriptors.count(LocalNode) &&
- "Node not pool allocated?");
- PoolArgs[idx] = FI.PoolDescriptors.find(LocalNode)->second;
- }
- else
- // LocalNode is null when a constant is passed in as a parameter
- PoolArgs[idx] = Constant::getNullValue(PoolDescPtr);
- } else {
- PoolArgs[idx] = Constant::getNullValue(PoolDescPtr);
- }
- }
- }
-
- // Push the pool arguments into Args.
- if (PAInfo.EqClass2LastPoolArg.count(FuncClass)) {
- for (int i = 0; i <= PAInfo.EqClass2LastPoolArg[FuncClass]; ++i) {
- if (PoolArgs.find(i) != PoolArgs.end())
- Args.push_back(PoolArgs[i]);
- else
- Args.push_back(Constant::getNullValue(PoolDescPtr));
- }
-
- assert(Args.size()== (unsigned) PAInfo.EqClass2LastPoolArg[FuncClass] + 1
- && "Call has same number of pool args as the called function");
- }
-
- // Add the rest of the arguments (the original arguments of the function)...
- Args.insert(Args.end(), CI.op_begin()+1, CI.op_end());
-
- std::string Name = CI.getName();
-
- Value *NewCall;
- if (Args.size() > CI.getNumOperands() - 1) {
- // If there are any pool arguments
- CastInst *CastI =
- new CastInst(CI.getOperand(0),
- PAInfo.getFuncInfo(*FuncClass)->Clone->getType(), "tmp",
- &CI);
- NewCall = new CallInst(CastI, Args, Name, &CI);
- } else {
- NewCall = new CallInst(CI.getOperand(0), Args, Name, &CI);
- }
-
- CI.replaceAllUsesWith(NewCall);
- DEBUG(std::cerr << " Result Call: " << *NewCall);
-
- if (CI.getType() != Type::VoidTy) {
- // If we are modifying the original function, update the DSGraph...
- DSGraph::ScalarMapTy &SM = G.getScalarMap();
- DSGraph::ScalarMapTy::iterator CII = SM.find(&CI);
- if (CII != SM.end()) {
- SM.insert(std::make_pair(NewCall, CII->second));
- SM.erase(CII); // Destroy the CallInst
- } else {
- // Otherwise update the NewToOldValueMap with the new CI return value
- std::map<Value*,const Value*>::iterator CII =
- FI.NewToOldValueMap.find(&CI);
- assert(CII != FI.NewToOldValueMap.end() && "CI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(NewCall, CII->second));
- FI.NewToOldValueMap.erase(CII);
- }
- } else if (!FI.NewToOldValueMap.empty()) {
- std::map<Value*,const Value*>::iterator II =
- FI.NewToOldValueMap.find(&CI);
- assert(II != FI.NewToOldValueMap.end() &&
- "CI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(NewCall, II->second));
- FI.NewToOldValueMap.erase(II);
- }
- }
- else {
-
- FuncInfo *CFI = PAInfo.getFuncInfo(*CF);
-
- if (CFI == 0 || CFI->Clone == 0) return; // Nothing to transform...
-
- DEBUG(std::cerr << " Handling call: " << CI);
-
- DSGraph &CG = PAInfo.getBUDataStructures().getDSGraph(*CF); // Callee graph
-
- // We need to figure out which local pool descriptors correspond to the pool
- // descriptor arguments passed into the function call. Calculate a mapping
- // from callee DSNodes to caller DSNodes. We construct a partial isomophism
- // between the graphs to figure out which pool descriptors need to be passed
- // in. The roots of this mapping is found from arguments and return values.
- //
- std::map<DSNode*, DSNode*> NodeMapping;
-
- Function::aiterator AI = CF->abegin(), AE = CF->aend();
- unsigned OpNum = 1;
- for (; AI != AE; ++AI, ++OpNum) {
- Value *callOp = CI.getOperand(OpNum);
- if (!isa<Constant>(callOp))
- CalcNodeMapping(getDSNodeHFor(callOp), CG.getScalarMap()[AI],
- NodeMapping);
- }
- assert(OpNum == CI.getNumOperands() && "Varargs calls not handled yet!");
-
- // Map the return value as well...
- if (CI.getType() != Type::VoidTy)
- CalcNodeMapping(getDSNodeHFor(&CI), CG.getReturnNodeFor(*CF),
- NodeMapping);
-
- // Map the nodes that are pointed to by globals.
- // For all globals map getDSNodeForGlobal(g)->CG.getDSNodeForGlobal(g)
- for (DSGraph::ScalarMapTy::iterator SMI = G.getScalarMap().begin(),
- SME = G.getScalarMap().end(); SMI != SME; ++SMI)
- if (isa<GlobalValue>(SMI->first)) {
- CalcNodeMapping(SMI->second,
- CG.getScalarMap()[SMI->first], NodeMapping);
- }
-
- // Okay, now that we have established our mapping, we can figure out which
- // pool descriptors to pass in...
-
- // Add an argument for each pool which must be passed in...
- if (CFI->PoolArgFirst != 0) {
- for (int i = 0; i < CFI->PoolArgFirst; ++i)
- Args.push_back(Constant::getNullValue(PoolDescPtr));
- }
-
- for (unsigned i = 0, e = CFI->ArgNodes.size(); i != e; ++i) {
- if (NodeMapping.count(CFI->ArgNodes[i])) {
-
- DSNode *LocalNode = NodeMapping.find(CFI->ArgNodes[i])->second;
- if (LocalNode) {
- assert(FI.PoolDescriptors.count(LocalNode) &&
- "Node not pool allocated?");
- Args.push_back(FI.PoolDescriptors.find(LocalNode)->second);
- } else
- Args.push_back(Constant::getNullValue(PoolDescPtr));
- } else {
- Args.push_back(Constant::getNullValue(PoolDescPtr));
- }
- }
-
- Function *FuncClass = PAInfo.FuncECs.findClass(CF);
-
- if (PAInfo.EqClass2LastPoolArg.count(FuncClass))
- for (int i = CFI->PoolArgLast;
- i <= PAInfo.EqClass2LastPoolArg[FuncClass]; ++i)
- Args.push_back(Constant::getNullValue(PoolDescPtr));
-
- // Add the rest of the arguments...
- Args.insert(Args.end(), CI.op_begin()+1, CI.op_end());
-
- std::string Name = CI.getName();
-
- std::map<Value*,const Value*>::iterator CNewII;
-
- Value *NewCall = new CallInst(CFI->Clone, Args, Name, &CI);
-
- CI.replaceAllUsesWith(NewCall);
- DEBUG(std::cerr << " Result Call: " << *NewCall);
-
- if (CI.getType() != Type::VoidTy) {
- // If we are modifying the original function, update the DSGraph...
- DSGraph::ScalarMapTy &SM = G.getScalarMap();
- DSGraph::ScalarMapTy::iterator CII = SM.find(&CI);
- if (CII != SM.end()) {
- SM.insert(std::make_pair(NewCall, CII->second));
- SM.erase(CII); // Destroy the CallInst
- } else {
- // Otherwise update the NewToOldValueMap with the new CI return value
- std::map<Value*,const Value*>::iterator CNII =
- FI.NewToOldValueMap.find(&CI);
- assert(CNII != FI.NewToOldValueMap.end() && CNII->second &&
- "CI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(NewCall, CNII->second));
- FI.NewToOldValueMap.erase(CNII);
- }
- } else if (!FI.NewToOldValueMap.empty()) {
- std::map<Value*,const Value*>::iterator II =
- FI.NewToOldValueMap.find(&CI);
- assert(II != FI.NewToOldValueMap.end() && "CI not found in clone?");
- FI.NewToOldValueMap.insert(std::make_pair(NewCall, II->second));
- FI.NewToOldValueMap.erase(II);
- }
- }
-
- CI.getParent()->getInstList().erase(&CI);
-}
diff --git a/poolalloc/lib/PoolAllocate/PoolAllocate.h b/poolalloc/lib/PoolAllocate/PoolAllocate.h
deleted file mode 100644
index b6806c1..0000000
--- a/poolalloc/lib/PoolAllocate/PoolAllocate.h
+++ /dev/null
@@ -1,156 +0,0 @@
-//===-- PoolAllocate.h - Pool allocation pass -------------------*- C++ -*-===//
-//
-// This transform changes programs so that disjoint data structures are
-// allocated out of different pools of memory, increasing locality. This header
-// file exposes information about the pool allocation itself so that follow-on
-// passes may extend or use the pool allocation for analysis.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TRANSFORMS_POOLALLOCATE_H
-#define LLVM_TRANSFORMS_POOLALLOCATE_H
-
-#include "llvm/Pass.h"
-#include "Support/hash_set"
-#include "Support/EquivalenceClasses.h"
-class BUDataStructures;
-class TDDataStructures;
-class DSNode;
-class DSGraph;
-class CallInst;
-
-namespace PA {
- /// FuncInfo - Represent the pool allocation information for one function in
- /// the program. Note that many functions must actually be cloned in order
- /// for pool allocation to add arguments to the function signature. In this
- /// case, the Clone and NewToOldValueMap information identify how the clone
- /// maps to the original function...
- ///
- struct FuncInfo {
- /// MarkedNodes - The set of nodes which are not locally pool allocatable in
- /// the current function.
- ///
- hash_set<DSNode*> MarkedNodes;
-
- /// Clone - The cloned version of the function, if applicable.
- Function *Clone;
-
- /// ArgNodes - The list of DSNodes which have pools passed in as arguments.
- ///
- std::vector<DSNode*> ArgNodes;
-
- /// In order to handle indirect functions, the start and end of the
- /// arguments that are useful to this function.
- /// The pool arguments useful to this function are PoolArgFirst to
- /// PoolArgLast not inclusive.
- int PoolArgFirst, PoolArgLast;
-
- /// PoolDescriptors - The Value* (either an argument or an alloca) which
- /// defines the pool descriptor for this DSNode. Pools are mapped one to
- /// one with nodes in the DSGraph, so this contains a pointer to the node it
- /// corresponds to. In addition, the pool is initialized by calling the
- /// "poolinit" library function with a chunk of memory allocated with an
- /// alloca instruction. This entry contains a pointer to that alloca if the
- /// pool is locally allocated or the argument it is passed in through if
- /// not.
- /// Note: Does not include pool arguments that are passed in because of
- /// indirect function calls that are not used in the function.
- std::map<DSNode*, Value*> PoolDescriptors;
-
- /// NewToOldValueMap - When and if a function needs to be cloned, this map
- /// contains a mapping from all of the values in the new function back to
- /// the values they correspond to in the old function.
- ///
- std::map<Value*, const Value*> NewToOldValueMap;
- };
-}
-
-/// PoolAllocate - The main pool allocation pass
-///
-class PoolAllocate : public Pass {
- Module *CurModule;
- BUDataStructures *BU;
-
- TDDataStructures *TDDS;
-
- hash_set<Function*> InlinedFuncs;
-
- std::map<Function*, PA::FuncInfo> FunctionInfo;
-
- void buildIndirectFunctionSets(Module &M);
-
- void FindFunctionPoolArgs(Function &F);
-
- // Debug function to print the FuncECs
- void printFuncECs();
-
- public:
- Function *PoolInit, *PoolDestroy, *PoolAlloc, *PoolAllocArray, *PoolFree;
-
- // Equivalence class where functions that can potentially be called via
- // the same function pointer are in the same class.
- EquivalenceClasses<Function *> FuncECs;
-
- // Map from an Indirect CallInst to the set of Functions that it can point to
- std::multimap<CallInst *, Function *> CallInstTargets;
-
- // This maps an equivalence class to the last pool argument number for that
- // class. This is used because the pool arguments for all functions within
- // an equivalence class is passed to all the functions in that class.
- // If an equivalence class does not require pool arguments, it is not
- // on this map.
- std::map<Function *, int> EqClass2LastPoolArg;
-
- // Exception flags
- // CollapseFlag set if all data structures are not pool allocated, due to
- // collapsing of nodes in the DS graph
- unsigned CollapseFlag;
-
- public:
- bool run(Module &M);
-
- virtual void getAnalysisUsage(AnalysisUsage &AU) const;
-
- BUDataStructures &getBUDataStructures() const { return *BU; }
-
- PA::FuncInfo *getFuncInfo(Function &F) {
- std::map<Function*, PA::FuncInfo>::iterator I = FunctionInfo.find(&F);
- return I != FunctionInfo.end() ? &I->second : 0;
- }
-
- Module *getCurModule() { return CurModule; }
-
- private:
-
- /// AddPoolPrototypes - Add prototypes for the pool functions to the
- /// specified module and update the Pool* instance variables to point to
- /// them.
- ///
- void AddPoolPrototypes();
-
- /// MakeFunctionClone - If the specified function needs to be modified for
- /// pool allocation support, make a clone of it, adding additional arguments
- /// as neccesary, and return it. If not, just return null.
- ///
- Function *MakeFunctionClone(Function &F);
-
- /// ProcessFunctionBody - Rewrite the body of a transformed function to use
- /// pool allocation where appropriate.
- ///
- void ProcessFunctionBody(Function &Old, Function &New);
-
- /// CreatePools - This creates the pool initialization and destruction code
- /// for the DSNodes specified by the NodesToPA list. This adds an entry to
- /// the PoolDescriptors map for each DSNode.
- ///
- void CreatePools(Function &F, const std::vector<DSNode*> &NodesToPA,
- std::map<DSNode*, Value*> &PoolDescriptors);
-
- void TransformFunctionBody(Function &F, Function &OldF,
- DSGraph &G, PA::FuncInfo &FI);
-
- void InlineIndirectCalls(Function &F, DSGraph &G,
- hash_set<Function*> &visited);
-};
-
-#endif
diff --git a/poolalloc/runtime/PoolAllocator/PoolAllocatorBitMask.cpp b/poolalloc/runtime/PoolAllocator/PoolAllocatorBitMask.cpp
deleted file mode 100644
index b3a715f..0000000
--- a/poolalloc/runtime/PoolAllocator/PoolAllocatorBitMask.cpp
+++ /dev/null
@@ -1,460 +0,0 @@
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#undef assert
-#define assert(X)
-
-
-/* In the current implementation, each slab in the pool has NODES_PER_SLAB
- * nodes unless the isSingleArray flag is set in which case it contains a
- * single array of size ArraySize. Small arrays (size <= NODES_PER_SLAB) are
- * still allocated in the slabs of size NODES_PER_SLAB
- */
-#define NODES_PER_SLAB 512
-
-typedef struct PoolTy {
- void *Data;
- unsigned NodeSize;
- unsigned FreeablePool; /* Set to false if the memory from this pool cannot be
- freed before destroy*/
-
-} PoolTy;
-
-/* PoolSlab Structure - Hold NODES_PER_SLAB objects of the current node type.
- * Invariants: FirstUnused <= LastUsed+1
- */
-typedef struct PoolSlab {
- unsigned FirstUnused; /* First empty node in slab */
- int LastUsed; /* Last allocated node in slab */
- struct PoolSlab *Next;
- unsigned char AllocatedBitVector[NODES_PER_SLAB/8];
- unsigned char StartOfAllocation[NODES_PER_SLAB/8];
-
- unsigned isSingleArray; /* If this slab is used for exactly one array */
- /* The array is allocated from the start to the end of the slab */
- unsigned ArraySize; /* The size of the array allocated */
-
- char Data[1]; /* Buffer to hold data in this slab... variable sized */
-
-} PoolSlab;
-
-#define NODE_ALLOCATED(POOLSLAB, NODENUM) \
- ((POOLSLAB)->AllocatedBitVector[(NODENUM) >> 3] & (1 << ((NODENUM) & 7)))
-#define MARK_NODE_ALLOCATED(POOLSLAB, NODENUM) \
- (POOLSLAB)->AllocatedBitVector[(NODENUM) >> 3] |= 1 << ((NODENUM) & 7)
-#define MARK_NODE_FREE(POOLSLAB, NODENUM) \
- (POOLSLAB)->AllocatedBitVector[(NODENUM) >> 3] &= ~(1 << ((NODENUM) & 7))
-#define ALLOCATION_BEGINS(POOLSLAB, NODENUM) \
- ((POOLSLAB)->StartOfAllocation[(NODENUM) >> 3] & (1 << ((NODENUM) & 7)))
-#define SET_START_BIT(POOLSLAB, NODENUM) \
- (POOLSLAB)->StartOfAllocation[(NODENUM) >> 3] |= 1 << ((NODENUM) & 7)
-#define CLEAR_START_BIT(POOLSLAB, NODENUM) \
- (POOLSLAB)->StartOfAllocation[(NODENUM) >> 3] &= ~(1 << ((NODENUM) & 7))
-
-
-/* poolinit - Initialize a pool descriptor to empty
- */
-void poolinit(PoolTy *Pool, unsigned NodeSize) {
- if (!Pool) {
- printf("Null pool pointer passed into poolinit!\n");
- exit(1);
- }
-
- Pool->NodeSize = NodeSize;
- Pool->Data = 0;
-
- Pool->FreeablePool = 1;
-
-}
-
-void poolmakeunfreeable(PoolTy *Pool) {
- if (!Pool) {
- printf("Null pool pointer passed in to poolmakeunfreeable!\n");
- exit(1);
- }
-
- Pool->FreeablePool = 0;
-}
-
-/* pooldestroy - Release all memory allocated for a pool
- */
-void pooldestroy(PoolTy *Pool) {
- PoolSlab *PS;
- if (!Pool) {
- printf("Null pool pointer passed in to pooldestroy!\n");
- exit(1);
- }
-
- PS = (PoolSlab*)Pool->Data;
- while (PS) {
- PoolSlab *Next = PS->Next;
- free(PS);
- PS = Next;
- }
-}
-
-static void *FindSlabEntry(PoolSlab *PS, unsigned NodeSize) {
- /* Loop through all of the slabs looking for one with an opening */
- for (; PS; PS = PS->Next) {
-
- /* If the slab is a single array, go on to the next slab */
- /* Don't allocate single nodes in a SingleArray slab */
- if (PS->isSingleArray)
- continue;
-
- /* Check to see if there are empty entries at the end of the slab... */
- if (PS->LastUsed < NODES_PER_SLAB-1) {
- /* Mark the returned entry used */
- MARK_NODE_ALLOCATED(PS, PS->LastUsed+1);
- SET_START_BIT(PS, PS->LastUsed+1);
-
- /* If we are allocating out the first unused field, bump its index also */
- if (PS->FirstUnused == PS->LastUsed+1)
- PS->FirstUnused++;
-
- /* Return the entry, increment LastUsed field. */
- return &PS->Data[0] + ++PS->LastUsed * NodeSize;
- }
-
- /* If not, check to see if this node has a declared "FirstUnused" value that
- * is less than the number of nodes allocated...
- */
- if (PS->FirstUnused < NODES_PER_SLAB) {
- /* Successfully allocate out the first unused node */
- unsigned Idx = PS->FirstUnused;
-
- MARK_NODE_ALLOCATED(PS, Idx);
- SET_START_BIT(PS, Idx);
-
- /* Increment FirstUnused to point to the new first unused value... */
- do {
- ++PS->FirstUnused;
- } while (PS->FirstUnused < NODES_PER_SLAB &&
- NODE_ALLOCATED(PS, PS->FirstUnused));
-
- return &PS->Data[0] + Idx*NodeSize;
- }
- }
-
- /* No empty nodes available, must grow # slabs! */
- return 0;
-}
-
-char *poolalloc(PoolTy *Pool) {
- unsigned NodeSize;
- PoolSlab *PS;
- void *Result;
-
- if (!Pool) {
- printf("Null pool pointer passed in to poolalloc!\n");
- exit(1);
- }
-
- NodeSize = Pool->NodeSize;
- // Return if this pool has size 0
- if (NodeSize == 0)
- return 0;
-
- PS = (PoolSlab*)Pool->Data;
-
- if ((Result = FindSlabEntry(PS, NodeSize)))
- return Result;
-
- /* Otherwise we must allocate a new slab and add it to the list */
- PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*NODES_PER_SLAB-1);
-
- if (!PS) {
- printf("poolalloc: Could not allocate memory!");
- exit(1);
- }
-
- /* Initialize the slab to indicate that the first element is allocated */
- PS->FirstUnused = 1;
- PS->LastUsed = 0;
- /* This is not a single array */
- PS->isSingleArray = 0;
- PS->ArraySize = 0;
-
- MARK_NODE_ALLOCATED(PS, 0);
- SET_START_BIT(PS, 0);
-
- /* Add the slab to the list... */
- PS->Next = (PoolSlab*)Pool->Data;
- Pool->Data = PS;
- return &PS->Data[0];
-}
-
-void poolfree(PoolTy *Pool, char *Node) {
- unsigned NodeSize, Idx;
- PoolSlab *PS;
- PoolSlab **PPS;
- unsigned idxiter;
-
- if (!Pool) {
- printf("Null pool pointer passed in to poolfree!\n");
- exit(1);
- }
-
- NodeSize = Pool->NodeSize;
-
- // Return if this pool has size 0
- if (NodeSize == 0)
- return;
-
- PS = (PoolSlab*)Pool->Data;
- PPS = (PoolSlab**)&Pool->Data;
-
- /* Search for the slab that contains this node... */
- while (&PS->Data[0] > Node || &PS->Data[NodeSize*NODES_PER_SLAB-1] < Node) {
- if (!PS) {
- printf("poolfree: node being free'd not found in allocation pool specified!\n");
- exit(1);
- }
-
- PPS = &PS->Next;
- PS = PS->Next;
- }
-
- /* PS now points to the slab where Node is */
-
- Idx = (Node-&PS->Data[0])/NodeSize;
- assert(Idx < NODES_PER_SLAB && "Pool slab searching loop broken!");
-
- if (PS->isSingleArray) {
-
- /* If this slab is a SingleArray */
-
- if (Idx != 0) {
- printf("poolfree: Attempt to free middle of allocated array\n");
- exit(1);
- }
- if (!NODE_ALLOCATED(PS,0)) {
- printf("poolfree: Attempt to free node that is already freed\n");
- exit(1);
- }
- /* Mark this SingleArray slab as being free by just marking the first
- entry as free*/
- MARK_NODE_FREE(PS, 0);
- } else {
-
- /* If this slab is not a SingleArray */
-
- if (!ALLOCATION_BEGINS(PS, Idx)) {
- printf("poolfree: Attempt to free middle of allocated array\n");
- }
-
- /* Free the first node */
- if (!NODE_ALLOCATED(PS, Idx)) {
- printf("poolfree: Attempt to free node that is already freed\n");
- exit(1);
- }
- CLEAR_START_BIT(PS, Idx);
- MARK_NODE_FREE(PS, Idx);
-
- // Free all nodes
- idxiter = Idx + 1;
- while (idxiter < NODES_PER_SLAB && (!ALLOCATION_BEGINS(PS,idxiter)) &&
- (NODE_ALLOCATED(PS, idxiter))) {
- MARK_NODE_FREE(PS, idxiter);
- ++idxiter;
- }
-
- /* Update the first free field if this node is below the free node line */
- if (Idx < PS->FirstUnused) PS->FirstUnused = Idx;
-
- /* If we are not freeing the last element in a slab... */
- if (idxiter - 1 != PS->LastUsed) {
- return;
- }
-
- /* Otherwise we are freeing the last element in a slab... shrink the
- * LastUsed marker down to last used node.
- */
- PS->LastUsed = Idx;
- do {
- --PS->LastUsed;
- /* Fixme, this should scan the allocated array an entire byte at a time
- * for performance!
- */
- } while (PS->LastUsed >= 0 && (!NODE_ALLOCATED(PS, PS->LastUsed)));
-
- assert(PS->FirstUnused <= PS->LastUsed+1 &&
- "FirstUnused field was out of date!");
- }
-
- /* Ok, if this slab is empty, we unlink it from the of slabs and either move
- * it to the head of the list, or free it, depending on whether or not there
- * is already an empty slab at the head of the list.
- */
- /* Do this only if the pool is freeable */
- if (Pool->FreeablePool) {
- if (PS->isSingleArray) {
- /* If it is a SingleArray, just free it */
- *PPS = PS->Next;
- free(PS);
- } else if (PS->LastUsed == -1) { /* Empty slab? */
- PoolSlab *HeadSlab;
- *PPS = PS->Next; /* Unlink from the list of slabs... */
-
- HeadSlab = (PoolSlab*)Pool->Data;
- if (HeadSlab && HeadSlab->LastUsed == -1){/*List already has empty slab?*/
- free(PS); /*Free memory for slab */
- } else {
- PS->Next = HeadSlab; /*No empty slab yet, add this*/
- Pool->Data = PS; /*one to the head of the list */
- }
- }
- } else {
- /* Pool is not freeable for safety reasons */
- /* Leave it in the list of PoolSlabs as an empty PoolSlab */
- if (!PS->isSingleArray)
- if (PS->LastUsed == -1) {
- PS->FirstUnused = 0;
-
- /* Do not free the pool, but move it to the head of the list if there is
- no empty slab there already */
- PoolSlab *HeadSlab;
- HeadSlab = (PoolSlab*)Pool->Data;
- if (HeadSlab && HeadSlab->LastUsed != -1) {
- PS->Next = HeadSlab;
- Pool->Data = PS;
- }
- }
- }
-}
-
-/* The poolallocarray version of FindSlabEntry */
-static void *FindSlabEntryArray(PoolSlab *PS, unsigned NodeSize,
- unsigned Size) {
- unsigned i;
-
- /* Loop through all of the slabs looking for one with an opening */
- for (; PS; PS = PS->Next) {
-
- /* For large array allocation */
- if (Size > NODES_PER_SLAB) {
- /* If this slab is a SingleArray that is free with size > Size, use it */
- if (PS->isSingleArray && !NODE_ALLOCATED(PS,0) && PS->ArraySize >= Size) {
- /* Allocate the array in this slab */
- MARK_NODE_ALLOCATED(PS,0); /* In a single array, only the first node
- needs to be marked */
- return &PS->Data[0];
- } else
- continue;
- } else if (PS->isSingleArray)
- continue; /* Do not allocate small arrays in SingleArray slabs */
-
- /* For small array allocation */
- /* Check to see if there are empty entries at the end of the slab... */
- if (PS->LastUsed < NODES_PER_SLAB-Size) {
- /* Mark the returned entry used and set the start bit*/
- SET_START_BIT(PS, PS->LastUsed + 1);
- for (i = PS->LastUsed + 1; i <= PS->LastUsed + Size; ++i)
- MARK_NODE_ALLOCATED(PS, i);
-
- /* If we are allocating out the first unused field, bump its index also */
- if (PS->FirstUnused == PS->LastUsed+1)
- PS->FirstUnused += Size;
-
- /* Increment LastUsed */
- PS->LastUsed += Size;
-
- /* Return the entry */
- return &PS->Data[0] + (PS->LastUsed - Size + 1) * NodeSize;
- }
-
- /* If not, check to see if this node has a declared "FirstUnused" value
- * starting which Size nodes can be allocated
- */
- if (PS->FirstUnused < NODES_PER_SLAB - Size + 1 &&
- (PS->LastUsed < PS->FirstUnused ||
- PS->LastUsed - PS->FirstUnused >= Size)) {
- unsigned Idx = PS->FirstUnused, foundArray;
-
- /* Check if there is a continuous array of Size nodes starting
- FirstUnused */
- foundArray = 1;
- for (i = Idx; (i < Idx + Size) && foundArray; ++i)
- if (NODE_ALLOCATED(PS, i))
- foundArray = 0;
-
- if (foundArray) {
- /* Successfully allocate starting from the first unused node */
- SET_START_BIT(PS, Idx);
- for (i = Idx; i < Idx + Size; ++i)
- MARK_NODE_ALLOCATED(PS, i);
-
- PS->FirstUnused += Size;
- while (PS->FirstUnused < NODES_PER_SLAB &&
- NODE_ALLOCATED(PS, PS->FirstUnused)) {
- ++PS->FirstUnused;
- }
- return &PS->Data[0] + Idx*NodeSize;
- }
-
- }
- }
-
- /* No empty nodes available, must grow # slabs! */
- return 0;
-}
-
-char* poolallocarray(PoolTy* Pool, unsigned Size) {
- unsigned NodeSize;
- PoolSlab *PS;
- void *Result;
- unsigned i;
-
- if (!Pool) {
- printf("Null pool pointer passed to poolallocarray!\n");
- exit(1);
- }
-
- NodeSize = Pool->NodeSize;
-
- // Return if this pool has size 0
- if (NodeSize == 0)
- return 0;
-
- PS = (PoolSlab*)Pool->Data;
-
- if ((Result = FindSlabEntryArray(PS, NodeSize,Size)))
- return Result;
-
- /* Otherwise we must allocate a new slab and add it to the list */
- if (Size > NODES_PER_SLAB) {
- /* Allocate a new slab of size Size */
- PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*Size-1);
- if (!PS) {
- printf("poolallocarray: Could not allocate memory!\n");
- exit(1);
- }
- PS->isSingleArray = 1;
- PS->ArraySize = Size;
- MARK_NODE_ALLOCATED(PS, 0);
- } else {
- PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*NODES_PER_SLAB-1);
- if (!PS) {
- printf("poolallocarray: Could not allocate memory!\n");
- exit(1);
- }
-
- /* Initialize the slab to indicate that the first element is allocated */
- PS->FirstUnused = Size;
- PS->LastUsed = Size - 1;
-
- PS->isSingleArray = 0;
- PS->ArraySize = 0;
-
- SET_START_BIT(PS, 0);
- for (i = 0; i < Size; ++i) {
- MARK_NODE_ALLOCATED(PS, i);
- }
- }
-
- /* Add the slab to the list... */
- PS->Next = (PoolSlab*)Pool->Data;
- Pool->Data = PS;
- return &PS->Data[0];
-}