From 96b21c1054832f6e11a1a91e4df95d65016c9039 Mon Sep 17 00:00:00 2001 From: "Vikram S. Adve" Date: Sun, 8 Dec 2002 13:26:29 +0000 Subject: [PATCH] An explicit representation of dependence graphs, and a pass that computes a dependence graph for data dependences on memory locations using interprocedural Mod/Ref information. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@4957 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/DependenceGraph.h | 250 +++++++++ include/llvm/Analysis/MemoryDepAnalysis.h | 115 ++++ .../DataStructure/MemoryDepAnalysis.cpp | 492 ++++++++++++++++++ lib/Analysis/IPA/DependenceGraph.cpp | 79 +++ lib/Analysis/IPA/MemoryDepAnalysis.cpp | 492 ++++++++++++++++++ 5 files changed, 1428 insertions(+) create mode 100644 include/llvm/Analysis/DependenceGraph.h create mode 100644 include/llvm/Analysis/MemoryDepAnalysis.h create mode 100644 lib/Analysis/DataStructure/MemoryDepAnalysis.cpp create mode 100644 lib/Analysis/IPA/DependenceGraph.cpp create mode 100644 lib/Analysis/IPA/MemoryDepAnalysis.cpp diff --git a/include/llvm/Analysis/DependenceGraph.h b/include/llvm/Analysis/DependenceGraph.h new file mode 100644 index 00000000000..9c803f0a119 --- /dev/null +++ b/include/llvm/Analysis/DependenceGraph.h @@ -0,0 +1,250 @@ +//===- DependenceGraph.h - Dependence graph for a function ------*- C++ -*-===// +// +// This file provides an explicit representation for the dependence graph +// of a function, with one node per instruction and one edge per dependence. +// Dependences include both data and control dependences. +// +// Each dep. graph node (class DepGraphNode) keeps lists of incoming and +// outgoing dependence edges. +// +// Each dep. graph edge (class Dependence) keeps a pointer to one end-point +// of the dependence. This saves space and is important because dep. graphs +// can grow quickly. It works just fine because the standard idiom is to +// start with a known node and enumerate the dependences to or from that node. +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_ANALYSIS_DEPENDENCEGRAPH_H +#define LLVM_ANALYSIS_DEPENDENCEGRAPH_H + + +#include +#include +#include +#include +#include + +class Instruction; +class Function; +class Dependence; +class DepGraphNode; +class DependenceGraph; + + +//---------------------------------------------------------------------------- +// enum DependenceType: The standard data dependence types. +//---------------------------------------------------------------------------- + +enum DependenceType { + NoDependence = 0x0, + TrueDependence = 0x1, + AntiDependence = 0x2, + OutputDependence = 0x4, + ControlDependence = 0x8, // from a terminator to some other instr. + IncomingFlag = 0x10 // is this an incoming or outgoing dep? +}; + +#undef SUPPORTING_LOOP_DEPENDENCES +#ifdef SUPPORTING_LOOP_DEPENDENCES +typedef int DependenceDistance; // negative means unknown distance +typedef short DependenceLevel; // 0 means global level outside loops +#endif + + +//---------------------------------------------------------------------------- +// class Dependence: +// +// A representation of a simple (non-loop-related) dependence. +//---------------------------------------------------------------------------- + +class Dependence { + DepGraphNode* toOrFromNode; + DependenceType depType:8; + +public: + /*ctor*/ Dependence (DepGraphNode* toOrFromN, + DependenceType type, + bool isIncoming) + : toOrFromNode(toOrFromN), + depType(type | (isIncoming? IncomingFlag : 0x0)) { } + + /* copy ctor*/ Dependence (const Dependence& D) + : toOrFromNode(D.toOrFromNode), + depType(D.depType) { } + + bool operator==(const Dependence& D) { + return toOrFromNode == D.toOrFromNode && depType == D.depType; + } + + /// Get information about the type of dependence. + /// + DependenceType getDepType() { + return depType; + } + + /// Get source or sink depending on what type of node this is! + /// + DepGraphNode* getSrc() { + assert(depType & IncomingFlag); return toOrFromNode; + } + const DepGraphNode* getSrc() const { + assert(depType & IncomingFlag); return toOrFromNode; + } + + DepGraphNode* getSink() { + assert(! (depType & IncomingFlag)); return toOrFromNode; + } + const DepGraphNode* getSink() const { + assert(! (depType & IncomingFlag)); return toOrFromNode; + } + + /// Debugging support methods + /// + void print(std::ostream &O) const; + + // Default constructor: Do not use directly except for graph builder code + // + /*ctor*/ Dependence() : toOrFromNode(NULL), depType(NoDependence) { } +}; + + +#ifdef SUPPORTING_LOOP_DEPENDENCES +struct LoopDependence: public Dependence { + DependenceDirection dir; + DependenceDistance distance; + DependenceLevel level; + LoopInfo* enclosingLoop; +}; +#endif + + +//---------------------------------------------------------------------------- +// class DepGraphNode: +// +// A representation of a single node in a dependence graph, corresponding +// to a single instruction. +//---------------------------------------------------------------------------- + +class DepGraphNode { + Instruction* instr; + std::vector inDeps; + std::vector outDeps; + friend class DependenceGraph; + + typedef std::vector:: iterator iterator; + typedef std::vector::const_iterator const_iterator; + + iterator inDepBegin() { return inDeps.begin(); } + const_iterator inDepBegin() const { return inDeps.begin(); } + iterator inDepEnd() { return inDeps.end(); } + const_iterator inDepEnd() const { return inDeps.end(); } + + iterator outDepBegin() { return outDeps.begin(); } + const_iterator outDepBegin() const { return outDeps.begin(); } + iterator outDepEnd() { return outDeps.end(); } + const_iterator outDepEnd() const { return outDeps.end(); } + +public: + + DepGraphNode(Instruction& I) : instr(&I) { } + + Instruction& getInstr() { return *instr; } + const Instruction& getInstr() const { return *instr; } + + /// Debugging support methods + /// + void print(std::ostream &O) const; +}; + + +//---------------------------------------------------------------------------- +// class DependenceGraph: +// +// A representation of a dependence graph for a procedure. +// The primary query operation here is to look up a DepGraphNode for +// a particular instruction, and then use the in/out dependence iterators +// for the node. +//---------------------------------------------------------------------------- + +class DependenceGraph: public NonCopyable { + typedef hash_map DepNodeMapType; + typedef DepNodeMapType:: iterator map_iterator; + typedef DepNodeMapType::const_iterator const_map_iterator; + + DepNodeMapType depNodeMap; + + inline DepGraphNode* getNodeInternal(Instruction& inst, + bool createIfMissing = false) { + map_iterator I = depNodeMap.find(&inst); + if (I == depNodeMap.end()) + return (!createIfMissing)? NULL : + depNodeMap.insert( + std::make_pair(&inst, new DepGraphNode(inst))).first->second; + else + return I->second; + } + +public: + typedef std::vector:: iterator iterator; + typedef std::vector::const_iterator const_iterator; + +public: + DependenceGraph() { } + ~DependenceGraph(); + + /// Get the graph node for an instruction. There will be one if and + /// only if there are any dependences incident on this instruction. + /// If there is none, these methods will return NULL. + /// + DepGraphNode* getNode(Instruction& inst, bool createIfMissing = false) { + return getNodeInternal(inst, createIfMissing); + } + const DepGraphNode* getNode(const Instruction& inst) const { + return const_cast(this) + ->getNodeInternal(const_cast(inst)); + } + + iterator inDepBegin ( DepGraphNode& T) { return T.inDeps.begin(); } + const_iterator inDepBegin (const DepGraphNode& T) const { return T.inDeps.begin(); } + + iterator inDepEnd ( DepGraphNode& T) { return T.inDeps.end(); } + const_iterator inDepEnd (const DepGraphNode& T) const { return T.inDeps.end(); } + + iterator outDepBegin( DepGraphNode& F) { return F.outDeps.begin();} + const_iterator outDepBegin(const DepGraphNode& F) const { return F.outDeps.begin();} + + iterator outDepEnd ( DepGraphNode& F) { return F.outDeps.end(); } + const_iterator outDepEnd (const DepGraphNode& F) const { return F.outDeps.end(); } + + /// Debugging support methods + /// + void print(const Function& func, std::ostream &O) const; + +public: + /// Functions for adding and modifying the dependence graph. + /// These should to be used only by dependence analysis implementations. + void AddSimpleDependence(Instruction& fromI, + Instruction& toI, + DependenceType depType) { + DepGraphNode* fromNode = getNodeInternal(fromI, /*create*/ true); + DepGraphNode* toNode = getNodeInternal(toI, /*create*/ true); + fromNode->outDeps.push_back(Dependence(toNode, depType, false)); + toNode-> inDeps. push_back(Dependence(fromNode, depType, true)); + } + +#ifdef SUPPORTING_LOOP_DEPENDENCES + /// This interface is a placeholder to show what information is needed. + /// It will probably change when it starts being used. + void AddLoopDependence(Instruction& fromI, + Instruction& toI, + DependenceType depType, + DependenceDirection dir, + DependenceDistance distance, + DependenceLevel level, + LoopInfo* enclosingLoop); +#endif // SUPPORTING_LOOP_DEPENDENCES +}; + +//===----------------------------------------------------------------------===// + +#endif diff --git a/include/llvm/Analysis/MemoryDepAnalysis.h b/include/llvm/Analysis/MemoryDepAnalysis.h new file mode 100644 index 00000000000..965a2f42a18 --- /dev/null +++ b/include/llvm/Analysis/MemoryDepAnalysis.h @@ -0,0 +1,115 @@ +//===- MemoryDepAnalysis.h - Compute dep graph for memory ops ---*- C++ -*-===// +// +// This file provides 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. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_MEMORYDEPANALYSIS_H +#define LLVM_ANALYSIS_MEMORYDEPANALYSIS_H + +#include "llvm/Analysis/DependenceGraph.h" +#include "llvm/Analysis/IPModRef.h" +#include "llvm/Analysis/DataStructure.h" +#include "llvm/Pass.h" +#include "Support/TarjanSCCIterator.h" +#include "Support/NonCopyable.h" +#include "Support/hash_map" + + +class Instruction; +class Function; +class DSGraph; +class ModRefTable; + + +///--------------------------------------------------------------------------- +/// class MemoryDepGraph: +/// Dependence analysis for load/store/call instructions using IPModRef info +/// computed at the granularity of individual DSGraph nodes. +/// +/// This pass computes memory dependences for each function in a module. +/// It can be made a FunctionPass once a Pass (such as Parallelize) is +/// allowed to use a FunctionPass such as this one. +///--------------------------------------------------------------------------- + +class MemoryDepAnalysis: /* Use if FunctionPass: public DependenceGraph, */ + public Pass { + /// The following map and depGraph pointer are temporary until this class + /// becomes a FunctionPass instead of a module Pass. */ + hash_map funcMap; + DependenceGraph* funcDepGraph; + + /// Information about one function being analyzed. + const DSGraph* funcGraph; + const FunctionModRefInfo* funcModRef; + + /// Internal routine that processes each SCC of the CFG. + void MemoryDepAnalysis::ProcessSCC(SCC& S, + ModRefTable& ModRefAfter); + + friend class PgmDependenceGraph; + +public: + MemoryDepAnalysis() + : /*DependenceGraph(),*/ funcDepGraph(NULL), + funcGraph(NULL), funcModRef(NULL) { } + ~MemoryDepAnalysis(); + + ///------------------------------------------------------------------------ + /// 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. + bool run(Module& M); + + /// getGraph() -- Retrieve the dependence graph for a function. + /// This is temporary and will go away once this is a FunctionPass. + /// At that point, this class should directly inherit from DependenceGraph. + /// + DependenceGraph& getGraph(Function& F) { + hash_map::iterator I = funcMap.find(&F); + assert(I != funcMap.end()); + return *I->second; + } + const DependenceGraph& getGraph(Function& F) const { + hash_map::const_iterator + I = funcMap.find(&F); + assert(I != funcMap.end()); + return *I->second; + } + + /// Release depGraphs held in the Function -> DepGraph map. + /// + virtual void releaseMemory(); + + ///----END TEMPORARY FUNCTIONS--------------------------------------------- + + + /// Driver functions to compute the Load/Store Dep. Graph per function. + /// + bool runOnFunction(Function& _func); + + /// getAnalysisUsage - This does not modify anything. + /// It uses the Top-Down DS Graph and IPModRef. + /// + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); + AU.addRequired(); + } + + /// Debugging support methods + /// + void print(std::ostream &O) const; + void dump() const; +}; + + +//===----------------------------------------------------------------------===// + +#endif diff --git a/lib/Analysis/DataStructure/MemoryDepAnalysis.cpp b/lib/Analysis/DataStructure/MemoryDepAnalysis.cpp new file mode 100644 index 00000000000..ef08a5ceb67 --- /dev/null +++ b/lib/Analysis/DataStructure/MemoryDepAnalysis.cpp @@ -0,0 +1,492 @@ +//===- 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/NonCopyable.h" +#include "Support/STLExtras.h" +#include "Support/hash_map" +#include "Support/hash_set" +#include + + +///-------------------------------------------------------------------------- +/// 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 ModRefMap; + typedef ModRefMap::const_iterator const_map_iterator; + typedef ModRefMap:: iterator map_iterator; + typedef std::vector::const_iterator const_ref_iterator; + typedef std::vector:: iterator ref_iterator; + + ModRefMap modRefMap; + std::vector definers; + std::vector users; + std::vector 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(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, + public NonCopyable +{ + const DSGraph& funcGraph; + const FunctionModRefInfo& funcModRef; + ModRefTable& modRefTable; + + 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& 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::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::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().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* nextSCC; + for (TarjanSCC_iterator 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::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 +Z("memdep", "Memory Dependence Analysis"); + diff --git a/lib/Analysis/IPA/DependenceGraph.cpp b/lib/Analysis/IPA/DependenceGraph.cpp new file mode 100644 index 00000000000..fa8f7b00041 --- /dev/null +++ b/lib/Analysis/IPA/DependenceGraph.cpp @@ -0,0 +1,79 @@ +//===- DependenceGraph.cpp - Dependence graph for a function ----*- C++ -*-===// +// +// This file implments an explicit representation for the dependence graph +// of a function, with one node per instruction and one edge per dependence. +// Dependences include both data and control dependences. +// +// Each dep. graph node (class DepGraphNode) keeps lists of incoming and +// outgoing dependence edges. +// +// Each dep. graph edge (class Dependence) keeps a pointer to one end-point +// of the dependence. This saves space and is important because dep. graphs +// can grow quickly. It works just fine because the standard idiom is to +// start with a known node and enumerate the dependences to or from that node. +//===----------------------------------------------------------------------===// + + +#include "llvm/Analysis/DependenceGraph.h" +#include "llvm/Function.h" +#include "llvm/BasicBlock.h" +#include "llvm/Instruction.h" + + +//---------------------------------------------------------------------------- +// class Dependence: +// +// A representation of a simple (non-loop-related) dependence +//---------------------------------------------------------------------------- + +void Dependence::print(std::ostream &O) const +{ + assert(depType != NoDependence && "This dependence should never be created!"); + switch (depType) { + case TrueDependence: O << "TRUE dependence"; break; + case AntiDependence: O << "ANTI dependence"; break; + case OutputDependence: O << "OUTPUT dependence"; break; + case ControlDependence: O << "CONTROL dependence"; break; + default: assert(0 && "Invalid dependence type"); break; + } +} + + +//---------------------------------------------------------------------------- +// class DepGraphNode +//---------------------------------------------------------------------------- + +void DepGraphNode::print(std::ostream &O) const +{ + const_iterator DI = outDepBegin(), DE = outDepEnd(); + + O << "\nDeps. from instr:" << getInstr(); + + for ( ; DI != DE; ++DI) + { + O << "\t"; + DI->print(O); + O << " to instruction:"; + O << DI->getSink()->getInstr(); + } +} + +//---------------------------------------------------------------------------- +// class DependenceGraph +//---------------------------------------------------------------------------- + +DependenceGraph::~DependenceGraph() +{ + // Free all DepGraphNode objects created for this graph + for (map_iterator I = depNodeMap.begin(), E = depNodeMap.end(); I != E; ++I) + delete I->second; +} + +void DependenceGraph::print(const Function& func, std::ostream &O) const +{ + O << "DEPENDENCE GRAPH FOR FUNCTION " << func.getName() << ":\n"; + for (Function::const_iterator BB=func.begin(), FE=func.end(); BB != FE; ++BB) + for (BasicBlock::const_iterator II=BB->begin(), IE=BB->end(); II !=IE; ++II) + if (const DepGraphNode* dgNode = this->getNode(*II)) + dgNode->print(O); +} diff --git a/lib/Analysis/IPA/MemoryDepAnalysis.cpp b/lib/Analysis/IPA/MemoryDepAnalysis.cpp new file mode 100644 index 00000000000..ef08a5ceb67 --- /dev/null +++ b/lib/Analysis/IPA/MemoryDepAnalysis.cpp @@ -0,0 +1,492 @@ +//===- 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/NonCopyable.h" +#include "Support/STLExtras.h" +#include "Support/hash_map" +#include "Support/hash_set" +#include + + +///-------------------------------------------------------------------------- +/// 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 ModRefMap; + typedef ModRefMap::const_iterator const_map_iterator; + typedef ModRefMap:: iterator map_iterator; + typedef std::vector::const_iterator const_ref_iterator; + typedef std::vector:: iterator ref_iterator; + + ModRefMap modRefMap; + std::vector definers; + std::vector users; + std::vector 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(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, + public NonCopyable +{ + const DSGraph& funcGraph; + const FunctionModRefInfo& funcModRef; + ModRefTable& modRefTable; + + 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& 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::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::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().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* nextSCC; + for (TarjanSCC_iterator 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::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 +Z("memdep", "Memory Dependence Analysis"); +