//===- llvm/Analysis/LoopReuseAnalysis.h -------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the interface for the loop reuse analysis.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_LOOPREUSEANALYSIS_H
#define LLVM_ANALYSIS_LOOPREUSEANALYSIS_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Transforms/Utils/LoopUtils.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"

using namespace llvm;
using namespace std;

namespace llvm {

class OptimizationRemarkEmitter;
class TargetTransformInfo;

// This class checks for loop reuse and can be used to query its properties.
struct LoopReuse {

  // Metrics that we get by checking the loops
  unsigned NumberOfInstructions;
  unsigned NumberOfBlocks;
  unsigned NumberOfCalls;
  unsigned NumberOfVectorInsts;
  unsigned NumberOfRets;
  unsigned NumberOfReuses;
  unsigned NumberOfMemAccess;

  Loop *Loop1, *Loop2;

  // The accessess that are to be analyzed for reuses
  SmallVector<Instruction *, 2> Loop1Accesses;
  SmallVector<Instruction *, 2> Loop2Accesses; 
  void getAccesses(SmallVector<Instruction *, 2> &LoopAccesses, Loop *L);
  void initLoops(Loop *L1, Loop *L2);

  AssumptionCache *AC = nullptr;
  OptimizationRemarkEmitter *ORE = nullptr;
  AliasAnalysis *AA;
  const TargetTransformInfo *TTI;
  ScalarEvolution *SE = nullptr;

  LoopReuse (AssumptionCache *AC, OptimizationRemarkEmitter *ORE,
             TargetTransformInfo *TTI, AliasAnalysis *AA,
             ScalarEvolution *SE):
             AC(AC), ORE(ORE), TTI(TTI), AA(AA), SE(SE){}
  LoopReuse(){}
   
  // Construct two loops to check Reuse across them
  bool initInfo(Loop *Loop1, Loop *Loop2);

  // Get number of reuses
  unsigned getNumberOfReuses(ScalarEvolution *SE);

  // Legality check routines
  bool checkSubscripts(Instruction *Inst1, Loop *Loop1, 
                       Instruction *Inst2, Loop *Loop2);
  bool checkLoopsStructure(Loop *Loop1, Loop *Loop2);
  bool isTripCountsIdentical(Loop *L1, Loop *L2) ;

  bool getCLI(Loop *Loop1, Loop *Loop2);
  void getCombinedLoopsInfo(Loop *Loop1, Loop *Loop2);
  bool runOnFunction(Function &F){}
};

/// The legacy pass manager's analysis pass 
class LoopReuseLegacyAnalysis : public FunctionPass {
private:
  LoopReuse LR;
  AssumptionCache *AC = nullptr;
  ScalarEvolution *SE = nullptr;
  OptimizationRemarkEmitter *ORE = nullptr;
  AliasAnalysis *AA = nullptr;
  TargetTransformInfo *TTI = nullptr;

public:
  static char ID; // Pass identification, replacement for typeid

  LoopReuseLegacyAnalysis();

  bool runOnFunction(Function &F) override;

//  void print(raw_ostream &O, const Module *M = nullptr) const override;

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.addRequired<AssumptionCacheTracker>();
    AU.addRequired<TargetTransformInfoWrapperPass>();
    AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
    AU.addRequired<AAResultsWrapperPass>();    
    AU.addRequired<ScalarEvolutionWrapperPass>();

    AU.setPreservesAll();
  }

  LoopReuse & getInfo();

};

class LoopReuseAnalysis
    : public AnalysisInfoMixin<LoopReuseAnalysis> {
  friend AnalysisInfoMixin<LoopReuseAnalysis>;
  static AnalysisKey Key;

public:
  typedef LoopReuse Result;
  Result run(Function &F, FunctionAnalysisManager &AM);
};

} // namespace llvm

#endif // LLVM_ANALYSIS_LOOPREUSEANALYSIS_H
