//===============       - AnalyzeInterProceduralLoopRegions.h -
//===============//
//
// Utility: Input is a list of loop regions and a list of interested class
// types. For a loop region, this utily traverses all the basic blocks and
// collects stores originating from the methods of the intersted classes. We use
// the meta data propagated from clang in the store instrucions. In the loop
// regions when we enocunter a function call we will include the function's
// basic block and continue searching.  Bascially it searches all the basic
// blocks rechable from the loop region interprocedurally. The stores seen are
// then filtered based on the class and member field we are interested. If we
// can't filter the stores due to lack of information from clang, we mark the
// basic block of the stores as unsafe.  Also we collect unsafe regions like the
// landing pads of exception handling code while seraching the basic blocks of
// the loop region.
//===----------------------------------------------------------------------===//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Copyright (c) 2015 Advanced Micro Devices, Inc.  All rights reserved.
// Developed by: Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimers.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimers in the documentation
// and/or other materials provided with the distribution.
// Neither the names of Advanced Micro Devices, Inc., nor the names of its
// contributors may be used to endorse or promote products derived from this
// Software without specific prior written permission.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_UTILS_ANALYZEINTERPROCEDURALLOOPREGIONS_H
#define LLVM_TRANSFORMS_UTILS_ANALYZEINTERPROCEDURALLOOPREGIONS_H
#include "llvm/Analysis/TBAATypeReconstruction.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/raw_ostream.h"
#include <vector>

namespace llvm {
class AnalyzeInterProceduralLoopRegions {
private:
  FunctionAnalysisManager *FM;

public:
  std::vector<Loop *> LoopRegions;
  std::vector<GlobalVariable *> ClassList;
  std::vector<BasicBlock *> Visited;
  std::set<BasicBlock *> UnsafeList;
  std::set<BasicBlock *> UnsafeCallList;
  std::set<Instruction *> UnsafeInsnList;
  std::vector<StoreInst *> CandidateStores;
  std::map<CallBase *, std::set<Function *>> callInstToFunctionMap;
  /// TODO: update it as and when new safe function is identified
  /// Set of safe lib calls
  std::set<StringRef> SafeLibFuncs;
  // Add intrinsics to this set
  std::set<Intrinsic::ID> SafeIntrinsics;

  std::set<StringRef> ChainRoots;
  TBAATypeReconstruction *TypeRecon;

  void setTypeInfo(TBAATypeReconstruction *TR, std::set<StringRef> Roots) {
    ChainRoots.insert(Roots.begin(),Roots.end());
    TypeRecon = TR;
  }


  AnalyzeInterProceduralLoopRegions(
      std::vector<Loop *> LoopRegions, std::vector<GlobalVariable *> ClassList,
      std::map<CallBase *, std::set<Function *>> callInstToFunctionMap,
      FunctionAnalysisManager *FM)
      : LoopRegions(LoopRegions), ClassList(ClassList),
        callInstToFunctionMap(callInstToFunctionMap), FM(FM) {}
  bool scanLoopRegionBBs();
  bool scanFunctionBBs(Function *F);
  bool evaluateStoresinBBs(BasicBlock *BB);
  bool collectCandidateStores(StoreInst *St);
  void markDominatedBlocksAsVisited(BasicBlock *BB);
  void buildSafeLibFuncs() {
    // Below are not safe.
    //  SafeIntrinsics.insert(Intrinsic::memcpy);
    //  SafeIntrinsics.insert(Intrinsic::memmove);
    //  SafeIntrinsics.insert(Intrinsic::memset);
    // SafeIntrinsics.insert(Intrinsic::masked_store);

    // Below calls need to double check if they are safe
    SafeLibFuncs.insert("_Znam");
    SafeLibFuncs.insert("_Znwm");
    SafeLibFuncs.insert("fopen");
    SafeLibFuncs.insert("fclose");
    SafeLibFuncs.insert("fwrite");
    SafeLibFuncs.insert("_ZdaPv");
    SafeLibFuncs.insert("_ZdlPv");

    // Safe list to ignore
    SafeIntrinsics.insert(Intrinsic::lifetime_start);
    SafeIntrinsics.insert(Intrinsic::lifetime_end);
    SafeIntrinsics.insert(Intrinsic::experimental_noalias_scope_decl);
    SafeIntrinsics.insert(Intrinsic::assume);
    SafeLibFuncs.insert("__cxa_atexit");
    SafeLibFuncs.insert("_ZSt9terminatev");
    SafeLibFuncs.insert("exit");
    SafeLibFuncs.insert("_ZNSo5writeEPKcl");
    SafeLibFuncs.insert("_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_"
                        "ostreamIT_T0_ES6_PKS3_l");
    SafeLibFuncs.insert("mbstowcs");
    SafeLibFuncs.insert("strtol");
    SafeLibFuncs.insert("strtoul");
    SafeLibFuncs.insert("fflush");
    SafeLibFuncs.insert("sprintf");
    SafeLibFuncs.insert("_ZNSo5flushEv");
    SafeLibFuncs.insert("__ctype_get_mb_cur_max");
    SafeLibFuncs.insert("mblen");
    SafeLibFuncs.insert("printf");
    SafeLibFuncs.insert("llvm.trap");
    SafeLibFuncs.insert("realpath");
    SafeLibFuncs.insert("fprintf");
    SafeLibFuncs.insert("localeconv");
    SafeLibFuncs.insert("strtod");
    SafeLibFuncs.insert("towupper");
    SafeLibFuncs.insert("towlower");
    SafeLibFuncs.insert("fread");
    SafeLibFuncs.insert("wcstombs");
    SafeLibFuncs.insert("_ZNSi4readEPcl");
    SafeLibFuncs.insert("__cxa_allocate_exception");
    SafeLibFuncs.insert("__cxa_begin_catch");
    SafeLibFuncs.insert("__cxa_end_catch");
    SafeLibFuncs.insert("__cxa_free_exception");
    SafeLibFuncs.insert("__cxa_pure_virtual");
    SafeLibFuncs.insert("__cxa_rethrow");
    SafeLibFuncs.insert("__cxa_throw");
  }
  std::set<BasicBlock *> getUnsafeBlockList() { return UnsafeList; }
  std::set<BasicBlock *> getUnsafeCallBlockList() { return UnsafeCallList; }
  std::vector<StoreInst *> getCandidateStoreList() { return CandidateStores; }
};
} // namespace llvm
#endif
