#ifndef STRUCT__ARRAY__MEMBER__ANALYSIS__HPP
#define STRUCT__ARRAY__MEMBER__ANALYSIS__HPP

#include "llvm/Pass.h"

#include <boost/functional/hash.hpp>
#include <tr1/unordered_map>

namespace llvm
{
  class GetElementPtrInst;
  class Type;
}

/*!
  This is a simple preprocessing pass to check the entire module
  for trivial uses of struct members in array contexts.

  It does not perform any alias analysis or any flow/context
  sensitive operations; it is very dumb but effective.
 */
struct StructArrayMember : public llvm::ModulePass
{
  static char ID;
  StructArrayMember();

  // ModulePass
  virtual bool runOnModule(llvm::Module &M);
  virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const;

  // Will return -1 if this is not an array assignment destination
  short getStructArrayDepth(const llvm::GetElementPtrInst* GEP) const;
  
private:
  void analyzeFunction(llvm::Function* F);
  void analyzeGEP(llvm::GetElementPtrInst* GEP);
  
private:
  // Map of (StructType,Index) pairs to array depths (the array depth of that
  // struct member)
  typedef std::pair<const llvm::Type*,short> array_depth_key;
  typedef std::tr1::unordered_map<array_depth_key, short, boost::hash<array_depth_key> > array_depth_map;
  array_depth_map _arrayDepths;
};
#endif // STRUCT__ARRAY__MEMBER__ANALYSIS__HPP
