#ifndef LLVM_LIB_TARGET_MIPS_MIPSSUBTARGET_H
#define LLVM_LIB_TARGET_MIPS_MIPSSUBTARGET_H
#include "MCTargetDesc/MipsABIInfo.h"
#include "MipsFrameLowering.h"
#include "MipsISelLowering.h"
#include "MipsInstrInfo.h"
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/CodeGen/RegisterBankInfo.h"
#include "llvm/CodeGen/SelectionDAGTargetInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/MC/MCInstrItineraries.h"
#include "llvm/Support/ErrorHandling.h"
#include <string>
#define GET_SUBTARGETINFO_HEADER
#include "MipsGenSubtargetInfo.inc"
namespace llvm {
class StringRef;
class MipsTargetMachine;
class MipsSubtarget : public MipsGenSubtargetInfo {
  virtual void anchor();
  enum MipsArchEnum {
    MipsDefault,
    Mips1, Mips2, Mips32, Mips32r2, Mips32r3, Mips32r5, Mips32r6, Mips32Max,
    Mips3, Mips4, Mips5, Mips64, Mips64r2, Mips64r3, Mips64r5, Mips64r6
  };
  enum class CPU { P5600 };
    static bool DspWarningPrinted;
    static bool MSAWarningPrinted;
    static bool CRCWarningPrinted;
    static bool GINVWarningPrinted;
    static bool MIPS1WarningPrinted;
    static bool VirtWarningPrinted;
    MipsArchEnum MipsArchVersion;
      CPU ProcImpl;
    bool IsLittle;
    bool IsSoftFloat;
        bool IsSingleFloat;
    bool IsFPXX;
    bool NoABICalls;
    bool Abs2008;
    bool IsFP64bit;
      bool UseOddSPReg;
    bool IsNaN2008bit;
    bool IsGP64bit;
    bool IsPTR64bit;
    bool HasVFPU;
    bool HasCnMips;
    bool HasCnMipsP;
    bool IsLinux;
    bool UseSmallSection;
  
    bool HasMips3_32;
    bool HasMips3_32r2;
    bool HasMips4_32;
    bool HasMips4_32r2;
    bool HasMips5_32r2;
    bool InMips16Mode;
    bool InMips16HardFloat;
    bool InMicroMipsMode;
    bool HasDSP, HasDSPR2, HasDSPR3;
    bool Has3D;
    bool AllowMixed16_32;
        bool Os16;
    bool HasMSA;
    bool UseTCCInDIV;
    bool HasSym32;
    bool HasEVA;
      bool DisableMadd4;
    bool HasMT;
    bool HasCRC;
    bool HasVirt;
    bool HasGINV;
      bool UseIndirectJumpsHazard;
    bool UseLongCalls = false;
    bool UseXGOT = false;
      Align stackAlignment;
    MaybeAlign StackAlignOverride;
  InstrItineraryData InstrItins;
      enum {NoOverride, Mips16Override, NoMips16Override} OverrideMode;
  const MipsTargetMachine &TM;
  Triple TargetTriple;
  const SelectionDAGTargetInfo TSInfo;
  std::unique_ptr<const MipsInstrInfo> InstrInfo;
  std::unique_ptr<const MipsFrameLowering> FrameLowering;
  std::unique_ptr<const MipsTargetLowering> TLInfo;
public:
  bool isPositionIndependent() const;
    bool enablePostRAScheduler() const override;
  void getCriticalPathRCs(RegClassVector &CriticalPathRCs) const override;
  CodeGenOpt::Level getOptLevelToEnablePostRAScheduler() const override;
  bool isABI_N64() const;
  bool isABI_N32() const;
  bool isABI_O32() const;
  const MipsABIInfo &getABI() const;
  bool isABI_FPXX() const { return isABI_O32() && IsFPXX; }
      MipsSubtarget(const Triple &TT, StringRef CPU, StringRef FS, bool little,
                const MipsTargetMachine &TM, MaybeAlign StackAlignOverride);
      void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS);
  bool hasMips1() const { return MipsArchVersion >= Mips1; }
  bool hasMips2() const { return MipsArchVersion >= Mips2; }
  bool hasMips3() const { return MipsArchVersion >= Mips3; }
  bool hasMips4() const { return MipsArchVersion >= Mips4; }
  bool hasMips5() const { return MipsArchVersion >= Mips5; }
  bool hasMips4_32() const { return HasMips4_32; }
  bool hasMips4_32r2() const { return HasMips4_32r2; }
  bool hasMips32() const {
    return (MipsArchVersion >= Mips32 && MipsArchVersion < Mips32Max) ||
           hasMips64();
  }
  bool hasMips32r2() const {
    return (MipsArchVersion >= Mips32r2 && MipsArchVersion < Mips32Max) ||
           hasMips64r2();
  }
  bool hasMips32r3() const {
    return (MipsArchVersion >= Mips32r3 && MipsArchVersion < Mips32Max) ||
           hasMips64r2();
  }
  bool hasMips32r5() const {
    return (MipsArchVersion >= Mips32r5 && MipsArchVersion < Mips32Max) ||
           hasMips64r5();
  }
  bool hasMips32r6() const {
    return (MipsArchVersion >= Mips32r6 && MipsArchVersion < Mips32Max) ||
           hasMips64r6();
  }
  bool hasMips64() const { return MipsArchVersion >= Mips64; }
  bool hasMips64r2() const { return MipsArchVersion >= Mips64r2; }
  bool hasMips64r3() const { return MipsArchVersion >= Mips64r3; }
  bool hasMips64r5() const { return MipsArchVersion >= Mips64r5; }
  bool hasMips64r6() const { return MipsArchVersion >= Mips64r6; }
  bool hasCnMips() const { return HasCnMips; }
  bool hasCnMipsP() const { return HasCnMipsP; }
  bool isLittle() const { return IsLittle; }
  bool isABICalls() const { return !NoABICalls; }
  bool isFPXX() const { return IsFPXX; }
  bool isFP64bit() const { return IsFP64bit; }
  bool useOddSPReg() const { return UseOddSPReg; }
  bool noOddSPReg() const { return !UseOddSPReg; }
  bool isNaN2008() const { return IsNaN2008bit; }
  bool inAbs2008Mode() const { return Abs2008; }
  bool isGP64bit() const { return IsGP64bit; }
  bool isGP32bit() const { return !IsGP64bit; }
  unsigned getGPRSizeInBytes() const { return isGP64bit() ? 8 : 4; }
  bool isPTR64bit() const { return IsPTR64bit; }
  bool isPTR32bit() const { return !IsPTR64bit; }
  bool hasSym32() const {
    return (HasSym32 && isABI_N64()) || isABI_N32() || isABI_O32();
  }
  bool isSingleFloat() const { return IsSingleFloat; }
  bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
  bool hasVFPU() const { return HasVFPU; }
  bool inMips16Mode() const { return InMips16Mode; }
  bool inMips16ModeDefault() const {
    return InMips16Mode;
  }
          bool inMips16HardFloat() const {
    return inMips16Mode() && InMips16HardFloat;
  }
  bool inMicroMipsMode() const { return InMicroMipsMode && !InMips16Mode; }
  bool inMicroMips32r6Mode() const {
    return inMicroMipsMode() && hasMips32r6();
  }
  bool hasDSP() const { return HasDSP; }
  bool hasDSPR2() const { return HasDSPR2; }
  bool hasDSPR3() const { return HasDSPR3; }
  bool has3D() const { return Has3D; }
  bool hasMSA() const { return HasMSA; }
  bool disableMadd4() const { return DisableMadd4; }
  bool hasEVA() const { return HasEVA; }
  bool hasMT() const { return HasMT; }
  bool hasCRC() const { return HasCRC; }
  bool hasVirt() const { return HasVirt; }
  bool hasGINV() const { return HasGINV; }
  bool useIndirectJumpsHazard() const {
    return UseIndirectJumpsHazard && hasMips32r2();
  }
  bool useSmallSection() const { return UseSmallSection; }
  bool hasStandardEncoding() const { return !InMips16Mode && !InMicroMipsMode; }
  bool useSoftFloat() const { return IsSoftFloat; }
  bool useLongCalls() const { return UseLongCalls; }
  bool useXGOT() const { return UseXGOT; }
  bool enableLongBranchPass() const {
    return hasStandardEncoding() || inMicroMipsMode() || allowMixed16_32();
  }
    bool hasExtractInsert() const { return !inMips16Mode() && hasMips32r2(); }
  bool hasMTHC1() const { return hasMips32r2(); }
  bool allowMixed16_32() const { return inMips16ModeDefault() |
                                        AllowMixed16_32; }
  bool os16() const { return Os16; }
  bool isTargetNaCl() const { return TargetTriple.isOSNaCl(); }
  bool isXRaySupported() const override { return true; }
      static bool useConstantIslands();
  Align getStackAlignment() const { return stackAlignment; }
    Reloc::Model getRelocationModel() const;
  MipsSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS,
                                                 const TargetMachine &TM);
            bool systemSupportsUnalignedAccess() const { return hasMips32r6(); }
    void setHelperClassesMips16();
  void setHelperClassesMipsSE();
  const SelectionDAGTargetInfo *getSelectionDAGInfo() const override {
    return &TSInfo;
  }
  const MipsInstrInfo *getInstrInfo() const override { return InstrInfo.get(); }
  const TargetFrameLowering *getFrameLowering() const override {
    return FrameLowering.get();
  }
  const MipsRegisterInfo *getRegisterInfo() const override {
    return &InstrInfo->getRegisterInfo();
  }
  const MipsTargetLowering *getTargetLowering() const override {
    return TLInfo.get();
  }
  const InstrItineraryData *getInstrItineraryData() const override {
    return &InstrItins;
  }
protected:
    std::unique_ptr<CallLowering> CallLoweringInfo;
  std::unique_ptr<LegalizerInfo> Legalizer;
  std::unique_ptr<RegisterBankInfo> RegBankInfo;
  std::unique_ptr<InstructionSelector> InstSelector;
public:
  const CallLowering *getCallLowering() const override;
  const LegalizerInfo *getLegalizerInfo() const override;
  const RegisterBankInfo *getRegBankInfo() const override;
  InstructionSelector *getInstructionSelector() const override;
};
} 
#endif