//===- 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/Pass.h"
#include <iterator>

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<Dependence, ptrdiff_t>
{
  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 Dependence> 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<MemoryDepAnalysis>().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<MemoryDepAnalysis>();
    /* AU.addRequired<PostDominanceFrontier>(); */
  }

  /// Debugging support methods
  /// 
  void print(std::ostream &O) const;
  void dump() const;
};


//===----------------------------------------------------------------------===//

#endif
