//===- MemoizationUtils.h - Utils for ADV-MEM-OPT  -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements some utilty functions that are required for ADV-MEM-OPT.
// This is implemented by AOCC
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_UTILS_MEMOIZATIONUTILS_H
#define LLVM_TRANSFORMS_UTILS_MEMOIZATIONUTILS_H

#include "llvm/Analysis/PointerCacheMissAnalysis.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Transforms/Utils/ClassHierarchyUtils.h"
#include "llvm/Transforms/Utils/LoopUtils.h"
#include "llvm/Transforms/Utils/HierarchicalTypeBasedAnalysis.h"
#include "llvm/Analysis/CallSiteAnalysis.h"
#include <set>
#include <unordered_set>
#include <vector>

using llvm::aocc::CSFunctionProperty;
using llvm::aocc::CallSite;

namespace llvm {

bool returnNewMemoryAllocation(
    Function &F, FunctionAnalysisManager &AM,
    std::vector<std::pair<Function *, Value *>> *RetInfo);
bool isDeletingMem(Function &F, FunctionAnalysisManager &AM, set<string> &Check);
std::set<StringRef>
getTypeInfoForChains(Module &M, ModuleAnalysisManager &AM,
                     SmallVector<SmallVector<Instruction *>> Chain,
                     TBAATypeReconstruction *TypeRecon);
bool analyzeArgPointer(Value *Origin, Value *Operand, int f_level,
                       CSFunctionProperty *CS,
                       set<pair<Function *, Value *>> &Func_list,
                       FunctionAnalysisManager &FAM, bool isDes, int &loadlevel,
                       bool isThis);
bool isEscaping(Value *Origin, Value *Operand, CSFunctionProperty *CS,
                FunctionAnalysisManager &FAM,
                TBAATypeReconstruction &TypeRecon);
// This class is the driver for calling various analysis to prove that we can
// memoize certain memory locations given chains of memory locations starting
// for a root location.
// we have to prove that memory locations are repeatedly accesssed. But then
// for every access we need to prove that the intermediate memory locations
// are not changed. This is difficult when memory is accessed in several
// functions and repeated access happens via a loop which happens different
// function dispersed very far in the call graph. We need interprocedural
// analyis esp alias analysis to detect the memory locations are not changing
// and need to lot of methods which make analysis complex and compile time heavy
// and almost result in conservative result saying memory may be modified. If we
// can  need to limit our analysis to few methods in some way then it wont be
// compile time heavy. Also we can do more presice analysis

// One way we can limit our analysis to few methods is when that root location
//  is a private member of CXX method.
//  We then do following analysis to prove the intermediate memory locations are
//  not changing.
// 1. Hierarchical analysis for a CXX class.
//    Checks if the candidate class has properties that
//    gaurantees its data members cannot be accessed outside of its methods.
// 2. Given a private pointer field it calls Memory escape Analysis and
// mod/append
//    analysis on all the memory reachable through the pointer field.
//    we check on all CXX class  methods and functions  they call.
//    We try to prove that memory created inside the methods are
//    are only reachable through the pointer field are not escaping and changing
//    outside these
//     methods.
//    This then helps in Memoization of desired memory locations and avoiding
//    accessing redundant memory locations in the chain.
class CXXMemoizationAnalysis {
private:
  Function *CXXMethodWithIAChains;
  SmallVector<SmallVector<Instruction *>> Chains;
  Module *M;
  ModuleAnalysisManager *AM;
  ClassHierarchyAnalysis *CHA;
  std::vector<Function *> MethodList;
  std::vector<unsigned int> Offsets;
  TBAATypeReconstruction *TypeRecon;

  std::set<StringRef> ChainRootNames;

public:
  CXXMemoizationAnalysis(Module *M, ModuleAnalysisManager *AM,
                         Function *CXXMethodWithIAChains,
                         SmallVector<SmallVector<Instruction *>> Chains,
                         ClassHierarchyAnalysis *CHA)
      : M(M), AM(AM), CXXMethodWithIAChains(CXXMethodWithIAChains),
        Chains(Chains), CHA(CHA){};
  std::map<Instruction *, bool> run();
  bool checkCXXEncapsulationProp();
  bool runEscapeModAppendAnalysis();
  bool validateChainsAndCollectOffsets();
  std::map<unsigned int, bool> offsetAnalysisResultMap ;
  std::map<unsigned int, std::set<Instruction *>> offsetChainEndMap;
  std::set<StringRef> getChainRoots();
  std::vector<Function *> ConstructorFns;
  std::vector<Function *> DestructorFns;

  std::map<unsigned int, bool> getoffsetAnalysisResultMap() {
    return offsetAnalysisResultMap;
  }

  std::map<unsigned int, std::set<Instruction *>> getoffsetChainEndMap() {
    return offsetChainEndMap;
  }
};

void collectEHBlocks(Function *F, std::set<BasicBlock *> &EHBlocks);
bool isSafeForMemoization(Function *F, FunctionAnalysisManager &AM);

bool isEHBlock(BasicBlock *BB);
} // end namespace llvm

#endif // LLVM_TRANSFORMS_UTILS_MEMOIZATIONUTILS_H
