//===- PrefixSuffix.h - Part of Dynamic Dispatch mechanism ----------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// Modifications Copyright (c) 2021 Advanced Micro Devices, Inc. All rights
// reserved. Notified per clause 4(b) of the license.
//
//===----------------------------------------------------------------------===//
//
// Passes for performing Dynamic Dispatch of functions
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_DYNAMICDISPATCH_PASSES_H
#define LLVM_TRANSFORMS_DYNAMICDISPATCH_PASSES_H

#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"
#include <functional>
#include <unordered_map>

extern cl::opt<std::string> ISAs;

namespace llvm {
// This struct contains function with its feature mask.
// Used to sort clones so that the functions with higher feature
// mask are given the priority in resolver.
struct FunctionFeatureMask {
  Function *Func;
  int FeatPriority;
  FunctionFeatureMask(Function *F, int Priority);
};

using LoopInfoCallbackTy = std::function<LoopInfo &(Function &F)>;
using OptimizationRemarkEmitterCallbackTy =
    std::function<OptimizationRemarkEmitter &(Function &F)>;

struct ISAData {
  std::string MangledName;
  std::string Features;
};

enum DynDispatchFnMetadataType {
  UnanalyzedClone = 0,
  AnalyzedClone = 1,
  ValidClone = 2,
  FalseClone = 255
};

extern std::unordered_map<std::string, ISAData> ISAInfos;

std::string getFunctionTopISA(Function &F);
int getFunctionFeaturePriority(Function &F);
uint64_t getFunctionCpuSupportsMask(Function &F);
// Function to sort cloned functions according to higher feature priority
bool clonedFunctionSorter(const FunctionFeatureMask &A,
                          const FunctionFeatureMask &B);

namespace X86 {
enum ProcessorFeatures {
#define X86_FEATURE(ENUM, STRING) FEATURE_##ENUM,
#include "llvm/TargetParser/X86TargetParser.def"
  CPU_FEATURE_MAX
};
} // namespace X86
// Different from X86::getCpuSupportsMask - this variant adds code to
// skip the feature flag with a '-' sign
uint64_t getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs);
uint64_t hasCpuSupportsMask(ArrayRef<StringRef> FeatureStrs,
                            const uint64_t &Mask);

/// Clones a function with vectorizable loop to be processed later on.
/// The clone will have vectorization disabled.
struct DynDispatchPrefixPass : public PassInfoMixin<DynDispatchPrefixPass> {
public:
  DynDispatchPrefixPass();

  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);

  // Shim for old PM.
  bool runImpl(Function &F);
};

/// If vectorization succeeds on original, this pass clones the original clone
/// (from DynDispatchPrefixPass) for all required ISAs along with the specific
/// features. The vectorizer is called again after this pass to vectorize the
/// newly created functions.
struct DynDispatchSuffixPass : public PassInfoMixin<DynDispatchSuffixPass> {
public:
  DynDispatchSuffixPass();

  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);

  // Shim for old PM.
  bool runImpl(Function &F, LoopInfoCallbackTy LICB,
               OptimizationRemarkEmitterCallbackTy ORECB);
};

/// This is a module pass that deletes the clones that have not been vectorized
/// (Metadata is false for the cloned functions that are not vectorized).
/// Will also possibly create the resolver function for the clones.
struct DynDispatchGenResolverPass
    : public PassInfoMixin<DynDispatchGenResolverPass> {
  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);

  // Shim for old PM.
  bool runImpl(Module &M);
};
} // end namespace llvm

#endif // LLVM_TRANSFORMS_DYNAMICDISPATCH_PASSES_H
