//===-- MSchedGraph.h - Scheduling Graph ------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// A graph class for dependencies
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_MSCHEDGRAPH_H
#define LLVM_MSCHEDGRAPH_H

#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetMachine.h"
#include "Support/GraphTraits.h"
#include "Support/STLExtras.h"
#include "Support/iterator"
#include <vector>

namespace llvm {
  class MSchedGraph;
  class MSchedGraphNode;
  template<class IteratorType, class NodeType>
  class MSchedGraphNodeIterator;


  struct MSchedGraphEdge {
    enum DataDepOrderType {
      TrueDep, AntiDep, OutputDep, NonDataDep
    };
    
    enum MSchedGraphEdgeType {
      MemoryDep, ValueDep, MachineRegister
    };

    MSchedGraphNode *getDest() const { return dest; }
    unsigned getIteDiff() { return iteDiff; }
    unsigned getDepOrderType() { return depOrderType; }

  private:
    friend class MSchedGraphNode;
    MSchedGraphEdge(MSchedGraphNode *destination, MSchedGraphEdgeType type, 
		    unsigned deptype, unsigned diff) 
      : dest(destination), depType(type), depOrderType(deptype), iteDiff(diff) {}
    
    MSchedGraphNode *dest;
    MSchedGraphEdgeType depType;
    unsigned depOrderType;
    unsigned iteDiff;
  };

  class MSchedGraphNode {
   
    const MachineInstr* Inst; //Machine Instruction
    MSchedGraph* Parent; //Graph this node belongs to
    unsigned latency; //Latency of Instruction
    
    std::vector<MSchedGraphNode*> Predecessors; //Predecessor Nodes
    std::vector<MSchedGraphEdge> Successors;

  public:
    MSchedGraphNode(const MachineInstr *inst, MSchedGraph *graph, 
		    unsigned late=0);

    //Iterators
    typedef std::vector<MSchedGraphNode*>::iterator pred_iterator;
    pred_iterator pred_begin() { return Predecessors.begin(); }
    pred_iterator pred_end() { return Predecessors.end(); }
    
    typedef std::vector<MSchedGraphNode*>::const_iterator pred_const_iterator;
    pred_const_iterator pred_begin() const { return Predecessors.begin(); }
    pred_const_iterator pred_end() const { return Predecessors.end(); }

    // Successor iterators.
    typedef MSchedGraphNodeIterator<std::vector<MSchedGraphEdge>::const_iterator,
				    const MSchedGraphNode> succ_const_iterator;
    succ_const_iterator succ_begin() const;
    succ_const_iterator succ_end() const;

    typedef MSchedGraphNodeIterator<std::vector<MSchedGraphEdge>::iterator,
				    MSchedGraphNode> succ_iterator;
    succ_iterator succ_begin();
    succ_iterator succ_end();
    

    void addOutEdge(MSchedGraphNode *destination, 
		    MSchedGraphEdge::MSchedGraphEdgeType type, 
		    unsigned deptype, unsigned diff=0) {
      Successors.push_back(MSchedGraphEdge(destination, type, deptype,diff));
      destination->Predecessors.push_back(this);
    }
    const MachineInstr* getInst() { return Inst; }
    MSchedGraph* getParent() { return Parent; }
    bool hasPredecessors() { return (Predecessors.size() > 0); }
    bool hasSuccessors() { return (Successors.size() > 0); }
    int getLatency() { return latency; }
    MSchedGraphEdge getInEdge(MSchedGraphNode *pred);

    //Debug support
    void print(std::ostream &os) const;

  };

  template<class IteratorType, class NodeType>
  class MSchedGraphNodeIterator : public forward_iterator<NodeType*, ptrdiff_t> {
    IteratorType I;   // std::vector<MSchedGraphEdge>::iterator or const_iterator
  public:
    MSchedGraphNodeIterator(IteratorType i) : I(i) {}

    bool operator==(const MSchedGraphNodeIterator RHS) const { return I == RHS.I; }
    bool operator!=(const MSchedGraphNodeIterator RHS) const { return I != RHS.I; }

    const MSchedGraphNodeIterator &operator=(const MSchedGraphNodeIterator &RHS) {
      I = RHS.I;
      return *this;
    }

    NodeType* operator*() const {
      return I->getDest();
    }
    NodeType* operator->() const { return operator*(); }
    
    MSchedGraphNodeIterator& operator++() {                // Preincrement
      ++I;
      return *this;
    }
    MSchedGraphNodeIterator operator++(int) { // Postincrement
      MSchedGraphNodeIterator tmp = *this; ++*this; return tmp; 
    }

    MSchedGraphEdge &getEdge() {
      return *I;
    }
    const MSchedGraphEdge &getEdge() const {
      return *I;
    }
  };

  inline MSchedGraphNode::succ_const_iterator MSchedGraphNode::succ_begin() const {
    return succ_const_iterator(Successors.begin());
  }
  inline MSchedGraphNode::succ_const_iterator MSchedGraphNode::succ_end() const {
    return succ_const_iterator(Successors.end());
  }
  inline MSchedGraphNode::succ_iterator MSchedGraphNode::succ_begin() {
    return succ_iterator(Successors.begin());
  }
  inline MSchedGraphNode::succ_iterator MSchedGraphNode::succ_end() {
    return succ_iterator(Successors.end());
  }

  // ostream << operator for MSGraphNode class
  inline std::ostream &operator<<(std::ostream &os, 
				  const MSchedGraphNode &node) {
    node.print(os);
    return os;
  }



  class MSchedGraph {
    
    const MachineBasicBlock *BB; //Machine basic block
    const TargetMachine &Target; //Target Machine
        
    //Nodes
    std::map<const MachineInstr*, MSchedGraphNode*> GraphMap;

    //Add Nodes and Edges to this graph for our BB
    typedef std::pair<int, MSchedGraphNode*> OpIndexNodePair;
    void buildNodesAndEdges();
    void addValueEdges(std::vector<OpIndexNodePair> &NodesInMap, 
		       MSchedGraphNode *node,
		       bool nodeIsUse, bool nodeIsDef, int diff=0);
    void addMachRegEdges(std::map<int, 
			 std::vector<OpIndexNodePair> >& regNumtoNodeMap);
    void addMemEdges(const std::vector<MSchedGraphNode*>& memInst);

  public:
    MSchedGraph(const MachineBasicBlock *bb, const TargetMachine &targ);
    ~MSchedGraph();
    
    //Add Nodes to the Graph
    void addNode(const MachineInstr* MI, MSchedGraphNode *node);
    
    //iterators 
    typedef std::map<const MachineInstr*, MSchedGraphNode*>::iterator iterator;
    typedef std::map<const MachineInstr*, MSchedGraphNode*>::const_iterator const_iterator;
    typedef std::map<const MachineInstr*, MSchedGraphNode*>::reverse_iterator reverse_iterator;
    iterator find(const MachineInstr* I) { return GraphMap.find(I); }
    iterator end() { return GraphMap.end(); }
    iterator begin() { return GraphMap.begin(); }
    reverse_iterator rbegin() { return GraphMap.rbegin(); }
    reverse_iterator rend() { return GraphMap.rend(); }
    
  };

  
  static MSchedGraphNode& getSecond(std::pair<const MachineInstr* const,
					 MSchedGraphNode*> &Pair) {
    return *Pair.second;
  }



  // Provide specializations of GraphTraits to be able to use graph
  // iterators on the scheduling graph!
  //
  template <> struct GraphTraits<MSchedGraph*> {
    typedef MSchedGraphNode NodeType;
    typedef MSchedGraphNode::succ_iterator ChildIteratorType;
    
    static inline ChildIteratorType child_begin(NodeType *N) { 
      return N->succ_begin(); 
    }
    static inline ChildIteratorType child_end(NodeType *N) { 
      return N->succ_end();
    }

    typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
           MSchedGraphNode*>&, MSchedGraphNode&> DerefFun;

    typedef mapped_iterator<MSchedGraph::iterator, DerefFun> nodes_iterator;
    static nodes_iterator nodes_begin(MSchedGraph *G) {
      return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond));
    }
    static nodes_iterator nodes_end(MSchedGraph *G) {
      return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond));
    }
    

  };
  
  template <> struct GraphTraits<const MSchedGraph*> {
    typedef const MSchedGraphNode NodeType;
    typedef MSchedGraphNode::succ_const_iterator ChildIteratorType;
    
    static inline ChildIteratorType child_begin(NodeType *N) { 
      return N->succ_begin(); 
    }
    static inline ChildIteratorType child_end(NodeType *N) { 
      return N->succ_end();
    }
    typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
						     MSchedGraphNode*>&, MSchedGraphNode&> DerefFun;
    
    typedef mapped_iterator<MSchedGraph::iterator, DerefFun> nodes_iterator;
    static nodes_iterator nodes_begin(MSchedGraph *G) {
      return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond));
    }
    static nodes_iterator nodes_end(MSchedGraph *G) {
      return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond));
    }
  };
  
  template <> struct GraphTraits<Inverse<MSchedGraph*> > {
    typedef MSchedGraphNode NodeType;
    typedef MSchedGraphNode::pred_iterator ChildIteratorType;
    
    static inline ChildIteratorType child_begin(NodeType *N) { 
      return N->pred_begin();
    }
    static inline ChildIteratorType child_end(NodeType *N) { 
      return N->pred_end();
    }
    typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
           MSchedGraphNode*>&, MSchedGraphNode&> DerefFun;

    typedef mapped_iterator<MSchedGraph::iterator, DerefFun> nodes_iterator;
    static nodes_iterator nodes_begin(MSchedGraph *G) {
      return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond));
    }
    static nodes_iterator nodes_end(MSchedGraph *G) {
      return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond));
    }
  };
  
  template <> struct GraphTraits<Inverse<const MSchedGraph*> > {
    typedef const MSchedGraphNode NodeType;
    typedef MSchedGraphNode::pred_const_iterator ChildIteratorType;
    
    static inline ChildIteratorType child_begin(NodeType *N) { 
      return N->pred_begin();
    }
    static inline ChildIteratorType child_end(NodeType *N) { 
      return N->pred_end();
    }

    typedef std::pointer_to_unary_function<std::pair<const MachineInstr* const,
						     MSchedGraphNode*>&, MSchedGraphNode&> DerefFun;
    
    typedef mapped_iterator<MSchedGraph::iterator, DerefFun> nodes_iterator;
    static nodes_iterator nodes_begin(MSchedGraph *G) {
      return map_iterator(((MSchedGraph*)G)->begin(), DerefFun(getSecond));
    }
    static nodes_iterator nodes_end(MSchedGraph *G) {
      return map_iterator(((MSchedGraph*)G)->end(), DerefFun(getSecond));
    }
  };




}

#endif
