#ifndef LLVM_TRANSFORMS_SCALAR_RUNTIMEEXCEPTIONCHECKSGENERATOR_H
#define LLVM_TRANSFORMS_SCALAR_RUNTIMEEXCEPTIONCHECKSGENERATOR_H

#include "llvm/IR/PassManager.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Transforms/Utils/HierarchicalTypeBasedAnalysis.h"
#include "llvm/Analysis/TBAATypeReconstruction.h"
#include "llvm/Analysis/ClassHierarchyAnalysis.h"
#include "llvm/Transforms/Utils/ClassHierarchyUtils.h"

namespace llvm {
class CXXFieldEvaluator;
bool genChecksForInst(Instruction&, FunctionAnalysisManager&,
                aocc::CSFunctionProperty&, std::vector<Function*>&, 
                CXXFieldEvaluator &, std::set<Instruction*>, Function*);
bool mayThrow(const Instruction&);
bool mayThrow(const BasicBlock&);
bool mayThrow(const Function&);
bool isTypeCheckLoad(Value*);

class SCEVCollectUnknownTerms {
  std::vector<Value*> &Terms;

public:
  SCEVCollectUnknownTerms(std::vector<Value*> &T);
  bool follow(const SCEV *S);
  bool isDone() const;
};

class CXXFieldEvaluator{
aocc::CSFunctionProperty * CS;
FunctionAnalysisManager  * FAM;
TBAATypeReconstruction *TypeRecon;
ClassHierarchyAnalysis * CHA;
std::set<Instruction *> accessTypeInsns;
std::set<Instruction *> baseTypeInsns;
bool track_unsafe_uses_GEP(Value *V, Function *CurrFn, TBAATypeReconstruction::TypeInfo *Ty, std::set<Value*> &Visited); 

public:
CXXFieldEvaluator(aocc::CSFunctionProperty * CS, FunctionAnalysisManager  * FAM):
                  CS(CS), FAM(FAM){}
bool allowUnconditionalLoadToFieldOfCXXClass(GetElementPtrInst * Inst);
bool checkLoadToFieldOfCXXClass(LoadInst* Ld,  GetElementPtrInst ** candGEP);
bool getMemoryEffectingInsnFromHierachicalType(GetElementPtrInst * GEP);
bool getMemoryEffectingInsnFromBaseType(GetElementPtrInst * GEP);
bool areEqualType(TBAATypeReconstruction::TypeInfo *A,
                  TBAATypeReconstruction::TypeInfo *B);
bool trackUsesofAccessTypes();
bool trackRecursiveLdUsesInCalls(LoadInst *L, std::set<std::tuple<Function*, unsigned int>>& CalledFunctions, std::set<std::tuple<Function*, unsigned int>> &CheckFun);
bool isFunctionArgument(Value *V,
                         Function *Function);
bool track_unsafe_uses_GEP(Value *V, Function *CurrFn, TBAATypeReconstruction::TypeInfo *Ty); 
bool AnalyzeBaseTypeUses();
};

}

#endif
