//===- PgmDependenceGraph.h - Enumerate the 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. // // Key Classes: // // enum PDGIteratorFlags -- Specify which dependences to enumerate. // // class PDGIterator -- The PDG iterator. This is essentially like a // pointer to class Dependence, but doesn't explicitly // construct a Dependence object for each dependence. // // class PgmDependenceGraph -- Interface to obtain PDGIterators for each // instruction. //===----------------------------------------------------------------------===// #ifndef LLVM_ANALYSIS_PGMDEPENDENCEGRAPH_H #define LLVM_ANALYSIS_PGMDEPENDENCEGRAPH_H #include "llvm/Analysis/DependenceGraph.h" #include "llvm/Analysis/MemoryDepAnalysis.h" /* #include "llvm/Analysis/PostDominators.h" -- see below */ #include "llvm/Instruction.h" #include "llvm/Value.h" #include "llvm/Pass.h" #include "Support/NonCopyable.h" #include class Instruction; class Function; class DSGraph; class DependenceGraph; class PgmDependenceGraph; ///--------------------------------------------------------------------------- /// enum PDGIteratorFlags /// /// These bit flags specify which dependences incident on a statement are to be /// enumerated: Memory deps, SSA deps, Control deps, or any combination thereof. ///--------------------------------------------------------------------------- enum PDGIteratorFlags { MemoryDeps = 0x1, // load/store/call deps SSADeps = 0x2, // SSA deps (true) ControlDeps = /* 0x4*/ 0x0, // control dependences AllDataDeps = MemoryDeps | SSADeps, // shorthand for data deps AllDeps = MemoryDeps | SSADeps | ControlDeps // shorthand for all three }; ///--------------------------------------------------------------------------- /// struct DepIterState /// /// This data type is primarily an internal implementation detail. /// It are exposed here only to give inlinable access to field dep, /// which is the representation for the current dependence pointed to by /// a PgmDependenceGraph::iterator. ///--------------------------------------------------------------------------- class DepIterState { private: typedef char IterStateFlags; static const IterStateFlags NoFlag, MemDone, SSADone, AllDone, FirstTimeFlag; public: DepGraphNode* depNode; // the node being enumerated DependenceGraph::iterator memDepIter; // pointer to current memory dep Instruction::op_iterator ssaInEdgeIter; // pointer to current SSA in-dep Value::use_iterator ssaOutEdgeIter; // pointer to current SSA out-dep DependenceGraph* memDepGraph; // the core dependence graph Dependence dep; // the "current" dependence PDGIteratorFlags depFlags:8; // which deps are we enumerating? IterStateFlags iterFlags:8; // marking where the iter stands /*ctor*/ DepIterState (DependenceGraph* _memDepGraph, Instruction& I, bool incomingDeps, PDGIteratorFlags whichDeps); bool operator==(const DepIterState& S) { assert(memDepGraph == S.memDepGraph && "Incompatible iterators! This is a probable sign of something BAD."); return (iterFlags == S.iterFlags && dep == S.dep && depFlags == S.depFlags && depNode == S.depNode && memDepIter == S.memDepIter && ssaInEdgeIter == S.ssaInEdgeIter && ssaOutEdgeIter == S.ssaOutEdgeIter); } // Is the iteration completely done? // bool done () const { return iterFlags & AllDone; } // Bump this iterator logically by 1 (to next dependence) and reset the // dep field to represent the new dependence if there is one. // Set done = true otherwise. // void Next (); // Find the first memory dependence for the current Mem In/Out iterators. // Sets dep to that dependence and returns true if one is found. // Returns false and leaves dep unchanged otherwise. // bool SetFirstMemoryDep(); // Find the next 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 SetFirstSSADep (); }; ///--------------------------------------------------------------------------- /// The dependence iterator class. This class represents a pointer to /// a single dependence in the program dependence graph. It is essentially /// like a pointer to an object of class Dependence but it is much more /// efficient to retrieve information about the dependence directly rather /// than constructing the equivalent Dependence object (since that object /// is normally not constructed for SSA def-use dependences). ///--------------------------------------------------------------------------- class PDGIterator: public forward_iterator { DepIterState* istate; #if 0 /*copy*/ PDGIterator (const PDGIterator& I); // do not implement! PDGIterator& operator= (const PDGIterator& I); // do not implement! /*copy*/ PDGIterator (PDGIterator& I) : istate(I.istate) { I.istate = NULL; // ensure this is not deleted twice. } #endif friend class PgmDependenceGraph; public: typedef PDGIterator _Self; /*ctor*/ PDGIterator (DepIterState* _istate) : istate(_istate) { } /*dtor*/ ~PDGIterator () { delete istate; } /*copy*/ PDGIterator (const PDGIterator& I) : istate(new DepIterState(*I.istate)) { } PDGIterator& operator= (const PDGIterator& I) { if (istate) delete istate; istate = new DepIterState(*I.istate); return *this; } // Check if the iteration is complete // bool fini() const { return !istate || istate->done(); } // Retrieve the underlying Dependence. Returns NULL if fini(). // Dependence* operator*() const { return fini() ? NULL : &istate->dep; } Dependence* operator->() const { assert(!fini()); return &istate->dep; } // Increment the iterator // _Self& operator++() { if (!fini()) istate->Next(); return *this;} _Self& operator++(int); // do not implement! // Equality comparison: a "null" state should compare equal to done // This is efficient for comparing with "end" or with itself, but could // be quite inefficient for other cases. // bool operator==(const PDGIterator& I) const { if (I.istate == NULL) // most common case: iter == end() return (istate == NULL || istate->done()); if (istate == NULL) return (I.istate == NULL || I.istate->done()); return (*istate == *I.istate); } bool operator!=(const PDGIterator& I) const { return ! (*this == I); } }; ///--------------------------------------------------------------------------- /// class PgmDependenceGraph: /// /// This pass enumerates dependences incident on each instruction in a function. /// It can be made a FunctionPass once a Pass (such as Parallelize) is /// allowed to use a FunctionPass such as this one. ///--------------------------------------------------------------------------- class PgmDependenceGraph: public Pass { /// Information about the function being analyzed. /// DependenceGraph* memDepGraph; // print helper function. void printOutgoingSSADeps(Instruction& I, std::ostream &O); // MakeIterator -- // The first version creates and initializes an iterator as specified. // The second version creates a null iterator representing end-of-iteration. // PDGIterator MakeIterator (Instruction& I, bool incomingDeps, PDGIteratorFlags whichDeps); PDGIterator MakeIterator () { return PDGIterator(NULL); } friend class PDGIterator; friend class DepIterState; public: typedef PDGIterator iterator; /* typedef PDGIterator const iterator; */ public: PgmDependenceGraph() : memDepGraph(NULL) { } ~PgmDependenceGraph() { } /// Iterators to enumerate the program dependence graph for a function. /// Note that this does not provide "end" iterators to check for completion. /// Instead, just use iterator::fini() or iterator::operator*() == NULL // iterator inDepBegin(Instruction& I, PDGIteratorFlags whichDeps = AllDeps) { return MakeIterator(I, /*inDeps*/ true, whichDeps); } iterator inDepEnd (Instruction& I, PDGIteratorFlags whichDeps = AllDeps) { return MakeIterator(); } iterator outDepBegin(Instruction& I, PDGIteratorFlags whichDeps = AllDeps) { return MakeIterator(I, /*inDeps*/ false, whichDeps); } iterator outDepEnd (Instruction& I, PDGIteratorFlags whichDeps = AllDeps) { return MakeIterator(); } ///------------------------------------------------------------------------ /// 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) { return true; } /// getGraph() -- Retrieve the pgm dependence graph for a function. /// This is temporary and will go away once this is a FunctionPass. /// At that point, this class itself will be the PgmDependenceGraph you want. /// PgmDependenceGraph& getGraph(Function& F) { Visiting(F); return *this; } private: void Visiting(Function& F) { memDepGraph = &getAnalysis().getGraph(F); } public: ///----END TEMPORARY FUNCTIONS--------------------------------------------- /// This initializes the program dependence graph iterator for a function. /// bool runOnFunction(Function& func) { Visiting(func); return true; } /// getAnalysisUsage - This does not modify anything. /// It uses the Memory Dependence Analysis pass. /// It needs to use the PostDominanceFrontier pass, but cannot because /// that is a FunctionPass. This means control dependence are not emumerated. /// void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); /* AU.addRequired(); */ } /// Debugging support methods /// void print(std::ostream &O) const; void dump() const; }; //===----------------------------------------------------------------------===// #endif