// BlkExprDeclBitVector.h - Dataflow types for Bitvector Analysis --*- C++ --*--
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides definition of dataflow types used by analyses such
// as LiveVariables and UninitializedValues.  The underlying dataflow values
// are implemented as bitvectors, but the definitions in this file include
// the necessary boilerplate to use with our dataflow framework.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_STMTDECLBVDVAL_H
#define LLVM_CLANG_STMTDECLBVDVAL_H

#include "clang/Analysis/CFG.h"
#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"

namespace clang {

  class Stmt;
  class ASTContext;

struct DeclBitVector_Types {

  class Idx {
    unsigned I;
  public:
    explicit Idx(unsigned i) : I(i) {}
    Idx() : I(~0U) {}

    bool isValid() const {
      return I != ~0U;
    }
    operator unsigned() const {
      assert (isValid());
      return I;
    }
  };

  //===--------------------------------------------------------------------===//
  // AnalysisDataTy - Whole-function meta data.
  //===--------------------------------------------------------------------===//

  class AnalysisDataTy {
  public:
    typedef llvm::DenseMap<const NamedDecl*, unsigned > DMapTy;
    typedef DMapTy::const_iterator decl_iterator;

  protected:
    DMapTy DMap;
    unsigned NDecls;

  public:

    AnalysisDataTy() : NDecls(0) {}
    virtual ~AnalysisDataTy() {}

    bool isTracked(const NamedDecl* SD) { return DMap.find(SD) != DMap.end(); }

    Idx getIdx(const NamedDecl* SD) const {
      DMapTy::const_iterator I = DMap.find(SD);
      return I == DMap.end() ? Idx() : Idx(I->second);
    }

    unsigned getNumDecls() const { return NDecls; }

    void Register(const NamedDecl* SD) {
      if (!isTracked(SD)) DMap[SD] = NDecls++;
    }

    decl_iterator begin_decl() const { return DMap.begin(); }
    decl_iterator end_decl() const { return DMap.end(); }
  };

  //===--------------------------------------------------------------------===//
  // ValTy - Dataflow value.
  //===--------------------------------------------------------------------===//

  class ValTy {
    llvm::BitVector DeclBV;
  public:

    void resetDeclValues(AnalysisDataTy& AD) {
      DeclBV.resize(AD.getNumDecls());
      DeclBV.reset();
    }

    void setDeclValues(AnalysisDataTy& AD) {
      DeclBV.resize(AD.getNumDecls());
      DeclBV.set();
    }

    void resetValues(AnalysisDataTy& AD) {
      resetDeclValues(AD);
    }

    bool operator==(const ValTy& RHS) const {
      assert (sizesEqual(RHS));
      return DeclBV == RHS.DeclBV;
    }

    void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; }

    llvm::BitVector::reference getBit(unsigned i) {
      return DeclBV[i];
    }

    bool getBit(unsigned i) const {
      return DeclBV[i];
    }

    llvm::BitVector::reference
    operator()(const NamedDecl* ND, const AnalysisDataTy& AD) {
      return getBit(AD.getIdx(ND));
    }

    bool operator()(const NamedDecl* ND, const AnalysisDataTy& AD) const {
      return getBit(AD.getIdx(ND));
    }

    llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; }
    const llvm::BitVector::reference getDeclBit(unsigned i) const {
      return const_cast<llvm::BitVector&>(DeclBV)[i];
    }

    ValTy& operator|=(const ValTy& RHS) {
      assert (sizesEqual(RHS));
      DeclBV |= RHS.DeclBV;
      return *this;
    }

    ValTy& operator&=(const ValTy& RHS) {
      assert (sizesEqual(RHS));
      DeclBV &= RHS.DeclBV;
      return *this;
    }

    ValTy& OrDeclBits(const ValTy& RHS) {
      return operator|=(RHS);
    }

    ValTy& AndDeclBits(const ValTy& RHS) {
      return operator&=(RHS);
    }

    bool sizesEqual(const ValTy& RHS) const {
      return DeclBV.size() == RHS.DeclBV.size();
    }
  };

  //===--------------------------------------------------------------------===//
  // Some useful merge operations.
  //===--------------------------------------------------------------------===//

  struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
  struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
};


struct StmtDeclBitVector_Types {

  //===--------------------------------------------------------------------===//
  // AnalysisDataTy - Whole-function meta data.
  //===--------------------------------------------------------------------===//

  class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy {
    ASTContext* ctx;
    CFG* cfg;
  public:
    AnalysisDataTy() : ctx(0), cfg(0) {}
    virtual ~AnalysisDataTy() {}

    void setContext(ASTContext& c) { ctx = &c; }
    ASTContext& getContext() {
      assert(ctx && "ASTContext should not be NULL.");
      return *ctx;
    }

    void setCFG(CFG& c) { cfg = &c; }
    CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; }

    bool isTracked(const Stmt* S) { return cfg->isBlkExpr(S); }
    using DeclBitVector_Types::AnalysisDataTy::isTracked;

    unsigned getIdx(const Stmt* S) const {
      CFG::BlkExprNumTy I = cfg->getBlkExprNum(S);
      assert(I && "Stmtession not tracked for bitvector.");
      return I;
    }
    using DeclBitVector_Types::AnalysisDataTy::getIdx;

    unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); }
  };

  //===--------------------------------------------------------------------===//
  // ValTy - Dataflow value.
  //===--------------------------------------------------------------------===//

  class ValTy : public DeclBitVector_Types::ValTy {
    llvm::BitVector BlkExprBV;
    typedef DeclBitVector_Types::ValTy ParentTy;

    static inline ParentTy& ParentRef(ValTy& X) {
      return static_cast<ParentTy&>(X);
    }

    static inline const ParentTy& ParentRef(const ValTy& X) {
      return static_cast<const ParentTy&>(X);
    }

  public:

    void resetBlkExprValues(AnalysisDataTy& AD) {
      BlkExprBV.resize(AD.getNumBlkExprs());
      BlkExprBV.reset();
    }

    void setBlkExprValues(AnalysisDataTy& AD) {
      BlkExprBV.resize(AD.getNumBlkExprs());
      BlkExprBV.set();
    }

    void resetValues(AnalysisDataTy& AD) {
      resetDeclValues(AD);
      resetBlkExprValues(AD);
    }

    void setValues(AnalysisDataTy& AD) {
      setDeclValues(AD);
      setBlkExprValues(AD);
    }

    bool operator==(const ValTy& RHS) const {
      return ParentRef(*this) == ParentRef(RHS)
          && BlkExprBV == RHS.BlkExprBV;
    }

    void copyValues(const ValTy& RHS) {
      ParentRef(*this).copyValues(ParentRef(RHS));
      BlkExprBV = RHS.BlkExprBV;
    }

    llvm::BitVector::reference
    operator()(const Stmt* S, const AnalysisDataTy& AD) {
      return BlkExprBV[AD.getIdx(S)];
    }
    const llvm::BitVector::reference
    operator()(const Stmt* S, const AnalysisDataTy& AD) const {
      return const_cast<ValTy&>(*this)(S,AD);
    }

    using DeclBitVector_Types::ValTy::operator();


    llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; }
    const llvm::BitVector::reference getStmtBit(unsigned i) const {
      return const_cast<llvm::BitVector&>(BlkExprBV)[i];
    }

    ValTy& OrBlkExprBits(const ValTy& RHS) {
      BlkExprBV |= RHS.BlkExprBV;
      return *this;
    }

    ValTy& AndBlkExprBits(const ValTy& RHS) {
      BlkExprBV &= RHS.BlkExprBV;
      return *this;
    }

    ValTy& operator|=(const ValTy& RHS) {
      assert (sizesEqual(RHS));
      ParentRef(*this) |= ParentRef(RHS);
      BlkExprBV |= RHS.BlkExprBV;
      return *this;
    }

    ValTy& operator&=(const ValTy& RHS) {
      assert (sizesEqual(RHS));
      ParentRef(*this) &= ParentRef(RHS);
      BlkExprBV &= RHS.BlkExprBV;
      return *this;
    }

    bool sizesEqual(const ValTy& RHS) const {
      return ParentRef(*this).sizesEqual(ParentRef(RHS))
          && BlkExprBV.size() == RHS.BlkExprBV.size();
    }
  };

  //===--------------------------------------------------------------------===//
  // Some useful merge operations.
  //===--------------------------------------------------------------------===//

  struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
  struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };

};
} // end namespace clang

#endif
