//=- GlobSTyConstProp.h - Conatant propogation for Global Struct fields   --==//
//
//===----------------------------------------------------------------------===//
//                     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.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/Analysis/LoopAccessAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/Debug.h"


using namespace llvm;
namespace llvm {

    typedef DenseMap<Instruction*, int> InsPresenceMap;


    struct VulnerableStrCpyNode {
        Instruction* StrcpyCI;
        int LenToCheck;
    };


class GlobSTyConstProp {
public:

    explicit GlobSTyConstProp(Module* thisM,
        function_ref<LoopInfo * (Function&)> LookupLoopInfo,
        function_ref<DominatorTree * (Function&)> LookupDominatorTree)
        : thisM(thisM), LookupLoopInfo(LookupLoopInfo), LookupDominatorTree(LookupDominatorTree) {}

    explicit GlobSTyConstProp() {}

    bool runOnModule();
    function_ref<LoopInfo * (Function&)> LookupLoopInfo;
    function_ref<DominatorTree * (Function&)> LookupDominatorTree;

    /// This Module
    Module* thisM;
  
  void InitCommonData(Module &M);

  ~GlobSTyConstProp() {
      ReleaseAllResources();
  }

  void InitCommonlyReqData(Module& M);
  GlobSTyConstProp *PerformVirtualGlobalConstantProp(Module& M);
  VulnerableStrCpyNode* GetSingleVulnerableStrcpy(void);
  unsigned int GetNumVulnerableStrcpy(void);
  void ReleaseAllResources(void);
  Constant* GetVirtConstVal(LoadInst* LI);
  

private:

    LLVMContext* Cntx;
    bool M64;
    Type* LTy;
    Type* I8Ty;
    Type* I8PtrTy;
    Type* I32Ty;
    const DataLayout* DL;

    typedef DenseMap<LoadInst*, Constant*> ConsPropMap;
    ConsPropMap GlobalConsPropMap;


    std::list<VulnerableStrCpyNode*> VulnerableStrCpy;

    bool isValidPeelTyGSCP(StructType* STy);
    bool AllAccessesGepBased(StructType* STy, GlobalVariable* GV,
        std::list<GEPOperator*>& AllGepsOfGV,
        std::list<CallInst*>& AllMemSetCI,
        std::list<std::list<Instruction*>*> AllStoreOfGV,
        std::list<std::list<Instruction*>*> AllLoadsOfGV);
    bool isAStdLibSafeFunc(CallInst* CI);
    bool isMemSetCallLegal(StructType* STy, CallInst* CI,
        std::list<CallInst*>& AllMemSetCI,
        GlobalVariable* GV);
    bool ConstPropagateGV(StructType* STy, GlobalVariable* GV,
        std::list<GEPOperator*>& AllGepsOfGV,
        std::list<CallInst*>& AllMemSetCI,
        std::list<std::list<Instruction*>*> AllStoreOfGV,
        std::list<std::list<Instruction*>*> AllLoadsOfGV);
    std::list<Instruction*>* GetNthElement(
        std::list<std::list<Instruction*>*> InsListList, int N);
    bool MapLoadsToConst(DominatorTree* DT,
        StoreInst* SI, std::list<Instruction*> AllLoadsOfGV,
        Constant* COp);
    bool PreceedsAllLoadsAndStores(Instruction* I, GlobalVariable* GV);
    void GetAllPredInst(Instruction* I,
        InsPresenceMap& AllPredInstMap);
    int GetNumSucc(BasicBlock* BB);
    bool SearchVulnerableStrCpy(Instruction* CI);
    bool InsPreceeds(Instruction* Src, Instruction* Dest);
    bool isUnusedParameter(Instruction* CI, Value* Param);
};



class GlobSTyConstPropLegacyPass :public ModulePass {
public:
    /// AnalysisUsage
    virtual void getAnalysisUsage(AnalysisUsage& AU) const {
        AU.addRequired<DominatorTreeWrapperPass>();
        AU.addRequired<LoopInfoWrapperPass>();
        AU.setPreservesAll();
    }
public:
    static char ID;

	GlobSTyConstProp *Impl;
    /// Constructor
    GlobSTyConstPropLegacyPass() : ModulePass(ID) {
        initializeGlobSTyConstPropLegacyPassPass(*PassRegistry::getPassRegistry());
    }

    virtual bool runOnModule(Module& M);

};



struct GlobSTyConstPropPass : public PassInfoMixin<GlobSTyConstPropPass> {
public:
    PreservedAnalyses run(Module& M, ModuleAnalysisManager& AM);
};

/// Analysis pass that exposes the \c LoopInfo for a function.
class GlobSTyConstPropAnalysis : public AnalysisInfoMixin<GlobSTyConstPropAnalysis> {
    friend AnalysisInfoMixin<GlobSTyConstPropAnalysis>;
    static AnalysisKey Key;
    
public:
    typedef GlobSTyConstProp Result;
    Result run(Module& M, ModuleAnalysisManager& AM);
};

} // namespace llvm
