//===-- TargetParser - Parser for target features ---------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a target parser to recognise hardware features such as
// FPU/CPU/ARCH names as well as specific support such as HDIV, etc.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_TARGETPARSER_H
#define LLVM_SUPPORT_TARGETPARSER_H

// FIXME: vector is used because that's what clang uses for subtarget feature
// lists, but SmallVector would probably be better
#include <vector>

namespace llvm {
class StringRef;

// Target specific information into their own namespaces. These should be
// generated from TableGen because the information is already there, and there
// is where new information about targets will be added.
// FIXME: To TableGen this we need to make some table generated files available
// even if the back-end is not compiled with LLVM, plus we need to create a new
// back-end to TableGen to create these clean tables.
namespace ARM {

// FPU names.
enum FPUKind {
#define ARM_FPU(NAME, KIND, VERSION, NEON_SUPPORT, RESTRICTION) KIND,
#include "ARMTargetParser.def"
  FK_LAST
};

// FPU Version
enum FPUVersion {
  FV_NONE = 0,
  FV_VFPV2,
  FV_VFPV3,
  FV_VFPV3_FP16,
  FV_VFPV4,
  FV_VFPV5
};

// An FPU name implies one of three levels of Neon support:
enum NeonSupportLevel {
  NS_None = 0, ///< No Neon
  NS_Neon,     ///< Neon
  NS_Crypto    ///< Neon with Crypto
};

// An FPU name restricts the FPU in one of three ways:
enum FPURestriction {
  FR_None = 0, ///< No restriction
  FR_D16,      ///< Only 16 D registers
  FR_SP_D16    ///< Only single-precision instructions, with 16 D registers
};

// Arch names.
enum ArchKind {
#define ARM_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) ID,
#include "ARMTargetParser.def"
  AK_LAST
};

// Arch extension modifiers for CPUs.
enum ArchExtKind : unsigned {
  AEK_INVALID = 0x0,
  AEK_NONE = 0x1,
  AEK_CRC = 0x2,
  AEK_CRYPTO = 0x4,
  AEK_FP = 0x8,
  AEK_HWDIV = 0x10,
  AEK_HWDIVARM = 0x20,
  AEK_MP = 0x40,
  AEK_SIMD = 0x80,
  AEK_SEC = 0x100,
  AEK_VIRT = 0x200,
  AEK_DSP = 0x400,
  AEK_FP16 = 0x800,
  AEK_RAS = 0x1000,
  // Unsupported extensions.
  AEK_OS = 0x8000000,
  AEK_IWMMXT = 0x10000000,
  AEK_IWMMXT2 = 0x20000000,
  AEK_MAVERICK = 0x40000000,
  AEK_XSCALE = 0x80000000,
};

// ISA kinds.
enum ISAKind { IK_INVALID = 0, IK_ARM, IK_THUMB, IK_AARCH64 };

// Endianness
// FIXME: BE8 vs. BE32?
enum EndianKind { EK_INVALID = 0, EK_LITTLE, EK_BIG };

// v6/v7/v8 Profile
enum ProfileKind { PK_INVALID = 0, PK_A, PK_R, PK_M };

StringRef getCanonicalArchName(StringRef Arch);

// Information by ID
StringRef getFPUName(unsigned FPUKind);
unsigned getFPUVersion(unsigned FPUKind);
unsigned getFPUNeonSupportLevel(unsigned FPUKind);
unsigned getFPURestriction(unsigned FPUKind);

// FIXME: These should be moved to TargetTuple once it exists
bool getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features);
bool getHWDivFeatures(unsigned HWDivKind, std::vector<StringRef> &Features);
bool getExtensionFeatures(unsigned Extensions,
                          std::vector<StringRef> &Features);

StringRef getArchName(unsigned ArchKind);
unsigned getArchAttr(unsigned ArchKind);
StringRef getCPUAttr(unsigned ArchKind);
StringRef getSubArch(unsigned ArchKind);
StringRef getArchExtName(unsigned ArchExtKind);
StringRef getArchExtFeature(StringRef ArchExt);
StringRef getHWDivName(unsigned HWDivKind);

// Information by Name
unsigned  getDefaultFPU(StringRef CPU, unsigned ArchKind);
unsigned  getDefaultExtensions(StringRef CPU, unsigned ArchKind);
StringRef getDefaultCPU(StringRef Arch);

// Parser
unsigned parseHWDiv(StringRef HWDiv);
unsigned parseFPU(StringRef FPU);
unsigned parseArch(StringRef Arch);
unsigned parseArchExt(StringRef ArchExt);
unsigned parseCPUArch(StringRef CPU);
unsigned parseArchISA(StringRef Arch);
unsigned parseArchEndian(StringRef Arch);
unsigned parseArchProfile(StringRef Arch);
unsigned parseArchVersion(StringRef Arch);

} // namespace ARM

// FIXME:This should be made into class design,to avoid dupplication. 
namespace AArch64 {

// Arch names.
enum class ArchKind {
#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) ID,
#include "AArch64TargetParser.def"
  AK_LAST
};

// Arch extension modifiers for CPUs.
enum ArchExtKind : unsigned {
  AEK_INVALID = 0x0,
  AEK_NONE = 0x1,
  AEK_CRC = 0x2,
  AEK_CRYPTO = 0x4,
  AEK_FP = 0x8,
  AEK_SIMD = 0x10,
  AEK_FP16 = 0x20,
  AEK_PROFILE = 0x40,
  AEK_RAS = 0x80,
  AEK_LSE = 0x100
};

StringRef getCanonicalArchName(StringRef Arch);

// Information by ID
StringRef getFPUName(unsigned FPUKind);
unsigned getFPUVersion(unsigned FPUKind);
unsigned getFPUNeonSupportLevel(unsigned FPUKind);
unsigned getFPURestriction(unsigned FPUKind);

// FIXME: These should be moved to TargetTuple once it exists
bool getFPUFeatures(unsigned FPUKind, std::vector<StringRef> &Features);
bool getExtensionFeatures(unsigned Extensions,
                                   std::vector<StringRef> &Features);
bool getArchFeatures(unsigned ArchKind, std::vector<StringRef> &Features);

StringRef getArchName(unsigned ArchKind);
unsigned getArchAttr(unsigned ArchKind);
StringRef getCPUAttr(unsigned ArchKind);
StringRef getSubArch(unsigned ArchKind);
StringRef getArchExtName(unsigned ArchExtKind);
StringRef getArchExtFeature(StringRef ArchExt);
unsigned checkArchVersion(StringRef Arch);

// Information by Name
unsigned  getDefaultFPU(StringRef CPU, unsigned ArchKind);
unsigned  getDefaultExtensions(StringRef CPU, unsigned ArchKind);
StringRef getDefaultCPU(StringRef Arch);

// Parser
unsigned parseFPU(StringRef FPU);
unsigned parseArch(StringRef Arch);
unsigned parseArchExt(StringRef ArchExt);
unsigned parseCPUArch(StringRef CPU);
unsigned parseArchISA(StringRef Arch);
unsigned parseArchEndian(StringRef Arch);
unsigned parseArchProfile(StringRef Arch);
unsigned parseArchVersion(StringRef Arch);

} // namespace AArch64
} // namespace llvm

#endif
