//===- llvm/Analysis/AliasSetTracker.h - Build Alias Sets -------*- C++ -*-===//
//
// This file defines two classes: AliasSetTracker and AliasSet.  These interface
// are used to classify a collection of pointer references into a maximal number
// of disjoint sets.  Each AliasSet object constructed by the AliasSetTracker
// object refers to memory disjoint from the other sets.
// 
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_ALIASSETTRACKER_H
#define LLVM_ANALYSIS_ALIASSETTRACKER_H

#include "llvm/Support/CallSite.h"
#include "Support/iterator"
#include "Support/hash_map"
#include "Support/ilist"
class AliasAnalysis;
class LoadInst;
class StoreInst;
class AliasSetTracker;
class AliasSet;

class AliasSet {
  friend class AliasSetTracker;

  struct PointerRec;
  typedef std::pair<Value* const, PointerRec> HashNodePair;

  class PointerRec {
    HashNodePair *NextInList;
    AliasSet *AS;
    unsigned Size;
  public:
    PointerRec() : NextInList(0), AS(0), Size(0) {}

    HashNodePair *getNext() const { return NextInList; }
    bool hasAliasSet() const { return AS != 0; }

    void updateSize(unsigned NewSize) {
      if (NewSize > Size) Size = NewSize;
    }

    unsigned getSize() const { return Size; }

    AliasSet *getAliasSet(AliasSetTracker &AST) { 
      assert(AS && "No AliasSet yet!");
      if (AS->Forward) {
        AliasSet *OldAS = AS;
        AS = OldAS->getForwardedTarget(AST);
        if (--OldAS->RefCount == 0)
          OldAS->removeFromTracker(AST);
        AS->RefCount++;
      }
      return AS;
    }

    void setAliasSet(AliasSet *as) {
      assert(AS == 0 && "Already have an alias set!");
      AS = as;
    }
    void setTail(HashNodePair *T) {
      assert(NextInList == 0 && "Already have tail!");
      NextInList = T;
    }
  };

  HashNodePair *PtrListHead, *PtrListTail; // Singly linked list of nodes
  AliasSet *Forward;             // Forwarding pointer
  AliasSet *Next, *Prev;         // Doubly linked list of AliasSets

  std::vector<CallSite> CallSites; // All calls & invokes in this node

  // RefCount - Number of nodes pointing to this AliasSet plus the number of
  // AliasSets forwarding to it.
  unsigned RefCount : 29;

  /// AccessType - Keep track of whether this alias set merely refers to the
  /// locations of memory, whether it modifies the memory, or whether it does
  /// both.  The lattice goes from "NoModRef" to either Refs or Mods, then to
  /// ModRef as neccesary.
  ///
  enum AccessType {
    NoModRef = 0, Refs = 1,         // Ref = bit 1
    Mods     = 2, ModRef = 3        // Mod = bit 2
  };
  unsigned AccessTy : 2;

  /// AliasType - Keep track the relationships between the pointers in the set.
  /// Lattice goes from MustAlias to MayAlias.
  ///
  enum AliasType {
    MustAlias = 0, MayAlias = 1
  };
  unsigned AliasTy : 1;

  friend class ilist_traits<AliasSet>;
  AliasSet *getPrev() const { return Prev; }
  AliasSet *getNext() const { return Next; }
  void setPrev(AliasSet *P) { Prev = P; }
  void setNext(AliasSet *N) { Next = N; }

public:
  /// Accessors...
  bool isRef() const { return AccessTy & Refs; }
  bool isMod() const { return AccessTy & Mods; }
  bool isMustAlias() const { return AliasTy == MustAlias; }
  bool isMayAlias()  const { return AliasTy == MayAlias; }

  /// isForwardingAliasSet - Return true if this alias set should be ignored as
  /// part of the AliasSetTracker object.
  bool isForwardingAliasSet() const { return Forward; }

  /// mergeSetIn - Merge the specified alias set into this alias set...
  ///
  void mergeSetIn(AliasSet &AS);

  // Alias Set iteration - Allow access to all of the pointer which are part of
  // this alias set...
  class iterator;
  iterator begin() const { return iterator(PtrListHead); }
  iterator end()   const { return iterator(); }

  void print(std::ostream &OS) const;
  void dump() const;

  /// Define an iterator for alias sets... this is just a forward iterator.
  class iterator : public forward_iterator<HashNodePair, ptrdiff_t> {
    HashNodePair *CurNode;
  public:
    iterator(HashNodePair *CN = 0) : CurNode(CN) {}
    
    bool operator==(const iterator& x) const {
      return CurNode == x.CurNode;
    }
    bool operator!=(const iterator& x) const { return !operator==(x); }

    const iterator &operator=(const iterator &I) {
      CurNode = I.CurNode;
      return *this;
    }
  
    value_type &operator*() const {
      assert(CurNode && "Dereferencing AliasSet.end()!");
      return *CurNode;
    }
    value_type *operator->() const { return &operator*(); }
  
    iterator& operator++() {                // Preincrement
      assert(CurNode && "Advancing past AliasSet.end()!");
      CurNode = CurNode->second.getNext();
      return *this;
    }
    iterator operator++(int) { // Postincrement
      iterator tmp = *this; ++*this; return tmp; 
    }
  };

private:
  // Can only be created by AliasSetTracker
  AliasSet() : PtrListHead(0), PtrListTail(0), Forward(0), RefCount(0),
               AccessTy(NoModRef), AliasTy(MustAlias) {
  }
  HashNodePair *getSomePointer() const {
    return PtrListHead ? PtrListHead : 0;
  }

  /// getForwardedTarget - Return the real alias set this represents.  If this
  /// has been merged with another set and is forwarding, return the ultimate
  /// destination set.  This also implements the union-find collapsing as well.
  AliasSet *getForwardedTarget(AliasSetTracker &AST) {
    if (!Forward) return this;

    AliasSet *Dest = Forward->getForwardedTarget(AST);
    if (Dest != Forward) {
      Dest->RefCount++;
      if (--Forward->RefCount == 0)
        Forward->removeFromTracker(AST);
      Forward = Dest;
    }
    return Dest;
  }

  void removeFromTracker(AliasSetTracker &AST);

  void addPointer(AliasSetTracker &AST, HashNodePair &Entry, unsigned Size);
  void addCallSite(CallSite CS);

  /// aliasesPointer - Return true if the specified pointer "may" (or must)
  /// alias one of the members in the set.
  ///
  bool aliasesPointer(const Value *Ptr, unsigned Size, AliasAnalysis &AA) const;
  bool aliasesCallSite(CallSite CS, AliasAnalysis &AA) const;
};

inline std::ostream& operator<<(std::ostream &OS, const AliasSet &AS) {
  AS.print(OS);
  return OS;
}


class AliasSetTracker {
  AliasAnalysis &AA;
  ilist<AliasSet> AliasSets;

  // Map from pointers to their node
  hash_map<Value*, AliasSet::PointerRec> PointerMap;
public:
  /// AliasSetTracker ctor - Create an empty collection of AliasSets, and use
  /// the specified alias analysis object to disambiguate load and store
  /// addresses.
  AliasSetTracker(AliasAnalysis &aa) : AA(aa) {}

  /// add methods - These methods are used to add different types of
  /// instructions to the alias sets.  Adding a new instruction can result in
  /// one of three actions happening:
  ///
  ///   1. If the instruction doesn't alias any other sets, create a new set.
  ///   2. If the instruction aliases exactly one set, add it to the set
  ///   3. If the instruction aliases multiple sets, merge the sets, and add
  ///      the instruction to the result.
  ///
  void add(LoadInst *LI);
  void add(StoreInst *SI);
  void add(CallSite CS);          // Call/Invoke instructions
  void add(CallInst *CI)   { add(CallSite(CI)); }
  void add(InvokeInst *II) { add(CallSite(II)); }
  void add(Instruction *I);       // Dispatch to one of the other add methods...
  void add(BasicBlock &BB);       // Add all instructions in basic block
  void add(const AliasSetTracker &AST); // Add alias relations from another AST

  /// getAliasSets - Return the alias sets that are active.
  const ilist<AliasSet> &getAliasSets() const { return AliasSets; }

  /// getAliasSetForPointer - Return the alias set that the specified pointer
  /// lives in...
  AliasSet &getAliasSetForPointer(Value *P, unsigned Size);

  /// getAliasAnalysis - Return the underlying alias analysis object used by
  /// this tracker.
  AliasAnalysis &getAliasAnalysis() const { return AA; }

  typedef ilist<AliasSet>::iterator iterator;
  typedef ilist<AliasSet>::const_iterator const_iterator;

  const_iterator begin() const { return AliasSets.begin(); }
  const_iterator end()   const { return AliasSets.end(); }

  iterator begin() { return AliasSets.begin(); }
  iterator end()   { return AliasSets.end(); }

  void print(std::ostream &OS) const;
  void dump() const;

private:
  friend class AliasSet;
  void removeAliasSet(AliasSet *AS);

  AliasSet::HashNodePair &getEntryFor(Value *V) {
    // Standard operator[], except that it returns the whole pair, not just
    // ->second.
    return *PointerMap.insert(AliasSet::HashNodePair(V,
                                            AliasSet::PointerRec())).first;
  }

  void addPointer(Value *P, unsigned Size, AliasSet::AccessType E) {
    AliasSet &AS = getAliasSetForPointer(P, Size);
    AS.AccessTy |= E;
  }
  AliasSet *findAliasSetForPointer(const Value *Ptr, unsigned Size);

  AliasSet *findAliasSetForCallSite(CallSite CS);
};

inline std::ostream& operator<<(std::ostream &OS, const AliasSetTracker &AST) {
  AST.print(OS);
  return OS;
}

#endif
