text: //===--- X86.h - Declare X86 target feature support -------------*- 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
  //
  //===----------------------------------------------------------------------===//
  //
  // This file declares X86 TargetInfo objects.
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef LLVM_CLANG_LIB_BASIC_TARGETS_X86_H
  #define LLVM_CLANG_LIB_BASIC_TARGETS_X86_H
  
  #include "OSTargets.h"
  #include "clang/Basic/TargetInfo.h"
  #include "clang/Basic/TargetOptions.h"
  #include "llvm/ADT/Triple.h"
  #include "llvm/Support/Compiler.h"
  #include "llvm/Support/X86TargetParser.h"
  
  namespace clang {
  namespace targets {
  
  static const unsigned X86AddrSpaceMap[] = {
      0,   // Default
      0,   // opencl_global
      0,   // opencl_local
      0,   // opencl_constant
      0,   // opencl_private
      0,   // opencl_generic
      0,   // opencl_global_device
      0,   // opencl_global_host
      0,   // cuda_device
      0,   // cuda_constant
      0,   // cuda_shared
      0,   // sycl_global
      0,   // sycl_global_device
      0,   // sycl_global_host
      0,   // sycl_local
      0,   // sycl_private
      270, // ptr32_sptr
      271, // ptr32_uptr
      272  // ptr64
  };
  
  // X86 target abstract base class; x86-32 and x86-64 are very close, so
  // most of the implementation can be shared.
  class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
  
    enum X86SSEEnum {
      NoSSE,
      SSE1,
      SSE2,
      SSE3,
      SSSE3,
      SSE41,
      SSE42,
      AVX,
      AVX2,
      AVX512F
    } SSELevel = NoSSE;
    enum MMX3DNowEnum {
      NoMMX3DNow,
      MMX,
      AMD3DNow,
      AMD3DNowAthlon
    } MMX3DNowLevel = NoMMX3DNow;
    enum XOPEnum { NoXOP, SSE4A, FMA4, XOP } XOPLevel = NoXOP;
    enum AddrSpace { ptr32_sptr = 270, ptr32_uptr = 271, ptr64 = 272 };
  
    bool HasAES = false;
    bool HasVAES = false;
    bool HasPCLMUL = false;
    bool HasVPCLMULQDQ = false;
    bool HasGFNI = false;
    bool HasLZCNT = false;
    bool HasRDRND = false;
    bool HasFSGSBASE = false;
    bool HasBMI = false;
    bool HasBMI2 = false;
    bool HasPOPCNT = false;
    bool HasRTM = false;
    bool HasPRFCHW = false;
    bool HasRDSEED = false;
    bool HasADX = false;
    bool HasTBM = false;
    bool HasLWP = false;
    bool HasFMA = false;
    bool HasF16C = false;
    bool HasAVX512CD = false;
    bool HasAVX512VPOPCNTDQ = false;
    bool HasAVX512VNNI = false;
    bool HasAVX512FP16 = false;
    bool HasAVX512BF16 = false;
    bool HasAVX512ER = false;
    bool HasAVX512PF = false;
    bool HasAVX512DQ = false;
    bool HasAVX512BITALG = false;
    bool HasAVX512BW = false;
    bool HasAVX512VL = false;
    bool HasAVX512VBMI = false;
    bool HasAVX512VBMI2 = false;
    bool HasAVX512IFMA = false;
    bool HasAVX512VP2INTERSECT = false;
    bool HasSHA = false;
    bool HasSHSTK = false;
    bool HasSGX = false;
    bool HasCX8 = false;
    bool HasCX16 = false;
    bool HasFXSR = false;
    bool HasXSAVE = false;
    bool HasXSAVEOPT = false;
    bool HasXSAVEC = false;
    bool HasXSAVES = false;
    bool HasMWAITX = false;
    bool HasCLZERO = false;
    bool HasCLDEMOTE = false;
    bool HasPCONFIG = false;
    bool HasPKU = false;
    bool HasCLFLUSHOPT = false;
    bool HasCLWB = false;
    bool HasMOVBE = false;
    bool HasPREFETCHWT1 = false;
    bool HasRDPID = false;
    bool HasRetpolineExternalThunk = false;
    bool HasLAHFSAHF = false;
    bool HasWBNOINVD = false;
    bool HasWAITPKG = false;
    bool HasMOVDIRI = false;
    bool HasMOVDIR64B = false;
    bool HasPTWRITE = false;
    bool HasINVPCID = false;
    bool HasENQCMD = false;
    bool HasKL = false;      // For key locker
    bool HasWIDEKL = false; // For wide key locker
    bool HasHRESET = false;
    bool HasAVXVNNI = false;
    bool HasAMXTILE = false;
    bool HasAMXINT8 = false;
    bool HasAMXBF16 = false;
    bool HasSERIALIZE = false;
    bool HasTSXLDTRK = false;
    bool HasUINTR = false;
    bool HasCRC32 = false;
    bool HasX87 = false;
  
  protected:
    llvm::X86::CPUKind CPU = llvm::X86::CK_None;
  
    enum FPMathKind { FP_Default, FP_SSE, FP_387 } FPMath = FP_Default;
  
  public:
    X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
        : TargetInfo(Triple) {
      LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
      AddrSpaceMap = &X86AddrSpaceMap;
      HasStrictFP = true;
  
      bool IsWinCOFF =
          getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
      if (IsWinCOFF)
        MaxVectorAlign = MaxTLSAlign = 8192u * getCharWidth();
    }
  
    const char *getLongDoubleMangling() const override {
      return LongDoubleFormat == &llvm::APFloat::IEEEquad() ? "g" : "e";
    }
  
    unsigned getFloatEvalMethod() const override {
      // X87 evaluates with 80 bits "long double" precision.
      return SSELevel == NoSSE ? 2 : 0;
    }
  
    ArrayRef<const char *> getGCCRegNames() const override;
  
    ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
      return None;
    }
  
    ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override;
  
    bool isSPRegName(StringRef RegName) const override {
      return RegName.equals("esp") || RegName.equals("rsp");
    }
  
    bool validateCpuSupports(StringRef Name) const override;
  
    bool validateCpuIs(StringRef Name) const override;
  
    bool validateCPUSpecificCPUDispatch(StringRef Name) const override;
  
    char CPUSpecificManglingCharacter(StringRef Name) const override;
  
    void getCPUSpecificCPUDispatchFeatures(
        StringRef Name,
        llvm::SmallVectorImpl<StringRef> &Features) const override;
  
    Optional<unsigned> getCPUCacheLineSize() const override;
  
    bool validateAsmConstraint(const char *&Name,
                               TargetInfo::ConstraintInfo &info) const override;
  
    bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize,
                                        bool &HasSizeMismatch) const override {
      // esp and ebp are the only 32-bit registers the x86 backend can currently
      // handle.
      if (RegName.equals("esp") || RegName.equals("ebp")) {
        // Check that the register size is 32-bit.
        HasSizeMismatch = RegSize != 32;
        return true;
      }
  
      return false;
    }
  
    bool validateOutputSize(const llvm::StringMap<bool> &FeatureMap,
                            StringRef Constraint, unsigned Size) const override;
  
    bool validateInputSize(const llvm::StringMap<bool> &FeatureMap,
                           StringRef Constraint, unsigned Size) const override;
  
    virtual bool
    checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override {
      return true;
    };
  
    virtual bool
    checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const override {
      return true;
    };
  
    virtual bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap,
                                     StringRef Constraint, unsigned Size) const;
  
    std::string convertConstraint(const char *&Constraint) const override;
    const char *getClobbers() const override {
      return "~{dirflag},~{fpsr},~{flags}";
    }
  
    StringRef getConstraintRegister(StringRef Constraint,
                                    StringRef Expression) const override {
      StringRef::iterator I, E;
      for (I = Constraint.begin(), E = Constraint.end(); I != E; ++I) {
        if (isalpha(*I) || *I == '@')
          break;
      }
      if (I == E)
        return "";
      switch (*I) {
      // For the register constraints, return the matching register name
      case 'a':
        return "ax";
      case 'b':
        return "bx";
      case 'c':
        return "cx";
      case 'd':
        return "dx";
      case 'S':
        return "si";
      case 'D':
        return "di";
      // In case the constraint is 'r' we need to return Expression
      case 'r':
        return Expression;
      // Double letters Y<x> constraints
      case 'Y':
        if ((++I != E) && ((*I == '0') || (*I == 'z')))
          return "xmm0";
        break;
      default:
        break;
      }
      return "";
    }
  
    bool useFP16ConversionIntrinsics() const override {
      return false;
    }
  
    void getTargetDefines(const LangOptions &Opts,
                          MacroBuilder &Builder) const override;
  
    void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name,
                           bool Enabled) const final;
  
    bool
    initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
                   StringRef CPU,
                   const std::vector<std::string> &FeaturesVec) const override;
  
    bool isValidFeatureName(StringRef Name) const override;
  
    bool hasFeature(StringRef Feature) const final;
  
    bool handleTargetFeatures(std::vector<std::string> &Features,
                              DiagnosticsEngine &Diags) override;
  
    StringRef getABI() const override {
      if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX512F)
        return "avx512";
      if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
        return "avx";
      if (getTriple().getArch() == llvm::Triple::x86 &&
          MMX3DNowLevel == NoMMX3DNow)
        return "no-mmx";
      return "";
    }
  
    bool supportsTargetAttributeTune() const override {
      return true;
    }
  
    bool isValidCPUName(StringRef Name) const override {
      bool Only64Bit = getTriple().getArch() != llvm::Triple::x86;
      return llvm::X86::parseArchX86(Name, Only64Bit) != llvm::X86::CK_None;
    }
  
    bool isValidTuneCPUName(StringRef Name) const override {
      if (Name == "generic")
        return true;
  
      // Allow 32-bit only CPUs regardless of 64-bit mode unlike isValidCPUName.
      // NOTE: gcc rejects 32-bit mtune CPUs in 64-bit mode. But being lenient
      // since mtune was ignored by clang for so long.
      return llvm::X86::parseTuneCPU(Name) != llvm::X86::CK_None;
    }
  
    void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
    void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
  
    bool setCPU(const std::string &Name) override {
      bool Only64Bit = getTriple().getArch() != llvm::Triple::x86;
      CPU = llvm::X86::parseArchX86(Name, Only64Bit);
      return CPU != llvm::X86::CK_None;
    }
  
    unsigned multiVersionSortPriority(StringRef Name) const override;
  
    bool setFPMath(StringRef Name) override;
  
    bool supportsExtendIntArgs() const override {
      return getTriple().getArch() != llvm::Triple::x86;
    }
  
    CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
      // Most of the non-ARM calling conventions are i386 conventions.
      switch (CC) {
      case CC_X86ThisCall:
      case CC_X86FastCall:
      case CC_X86StdCall:
      case CC_X86VectorCall:
      case CC_X86RegCall:
      case CC_C:
      case CC_PreserveMost:
      case CC_Swift:
      case CC_X86Pascal:
      case CC_IntelOclBicc:
      case CC_OpenCLKernel:
        return CCCR_OK;
      case CC_SwiftAsync:
        return CCCR_Error;
      default:
        return CCCR_Warning;
      }
    }
  
    bool checkArithmeticFenceSupported() const override { return true; }
  
    CallingConv getDefaultCallingConv() const override {
      return CC_C;
    }
  
    bool hasSjLjLowering() const override { return true; }
  
    void setSupportedOpenCLOpts() override { supportAllOpenCLOpts(); }
  
    uint64_t getPointerWidthV(unsigned AddrSpace) const override {
      if (AddrSpace == ptr32_sptr || AddrSpace == ptr32_uptr)
        return 32;
      if (AddrSpace == ptr64)
        return 64;
      return PointerWidth;
    }
  
    uint64_t getPointerAlignV(unsigned AddrSpace) const override {
      return getPointerWidthV(AddrSpace);
    }
  };
  
  // X86-32 generic target
  class LLVM_LIBRARY_VISIBILITY X86_32TargetInfo : public X86TargetInfo {
  public:
    X86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : X86TargetInfo(Triple, Opts) {
      DoubleAlign = LongLongAlign = 32;
      LongDoubleWidth = 96;
      LongDoubleAlign = 32;
      SuitableAlign = 128;
      resetDataLayout(
          Triple.isOSBinFormatMachO()
              ? "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-"
                "f80:32-n8:16:32-S128"
              : "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-"
                "f80:32-n8:16:32-S128",
          Triple.isOSBinFormatMachO() ? "_" : "");
      SizeType = UnsignedInt;
      PtrDiffType = SignedInt;
      IntPtrType = SignedInt;
      RegParmMax = 3;
  
      // Use fpret for all types.
      RealTypeUsesObjCFPRet =
          ((1 << (int)FloatModeKind::Float) | (1 << (int)FloatModeKind::Double) |
           (1 << (int)FloatModeKind::LongDouble));
  
      // x86-32 has atomics up to 8 bytes
      MaxAtomicPromoteWidth = 64;
      MaxAtomicInlineWidth = 32;
    }
  
    BuiltinVaListKind getBuiltinVaListKind() const override {
      return TargetInfo::CharPtrBuiltinVaList;
    }
  
    int getEHDataRegisterNumber(unsigned RegNo) const override {
      if (RegNo == 0)
        return 0;
      if (RegNo == 1)
        return 2;
      return -1;
    }
  
    bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap,
                             StringRef Constraint, unsigned Size) const override {
      switch (Constraint[0]) {
      default:
        break;
      case 'R':
      case 'q':
      case 'Q':
      case 'a':
      case 'b':
      case 'c':
      case 'd':
      case 'S':
      case 'D':
        return Size <= 32;
      case 'A':
        return Size <= 64;
      }
  
      return X86TargetInfo::validateOperandSize(FeatureMap, Constraint, Size);
    }
  
    void setMaxAtomicWidth() override {
      if (hasFeature("cx8"))
        MaxAtomicInlineWidth = 64;
    }
  
    ArrayRef<Builtin::Info> getTargetBuiltins() const override;
  
    bool hasBitIntType() const override { return true; }
  };
  
  class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo
      : public NetBSDTargetInfo<X86_32TargetInfo> {
  public:
    NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {}
  
    unsigned getFloatEvalMethod() const override {
      VersionTuple OsVersion = getTriple().getOSVersion();
      // New NetBSD uses the default rounding mode.
      if (OsVersion >= VersionTuple(6, 99, 26) || OsVersion.getMajor() == 0)
        return X86_32TargetInfo::getFloatEvalMethod();
      // NetBSD before 6.99.26 defaults to "double" rounding.
      return 1;
    }
  };
  
  class LLVM_LIBRARY_VISIBILITY OpenBSDI386TargetInfo
      : public OpenBSDTargetInfo<X86_32TargetInfo> {
  public:
    OpenBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : OpenBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {
      SizeType = UnsignedLong;
      IntPtrType = SignedLong;
      PtrDiffType = SignedLong;
    }
  };
  
  class LLVM_LIBRARY_VISIBILITY DarwinI386TargetInfo
      : public DarwinTargetInfo<X86_32TargetInfo> {
  public:
    DarwinI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : DarwinTargetInfo<X86_32TargetInfo>(Triple, Opts) {
      LongDoubleWidth = 128;
      LongDoubleAlign = 128;
      SuitableAlign = 128;
      MaxVectorAlign = 256;
      // The watchOS simulator uses the builtin bool type for Objective-C.
      llvm::Triple T = llvm::Triple(Triple);
      if (T.isWatchOS())
        UseSignedCharForObjCBool = false;
      SizeType = UnsignedLong;
      IntPtrType = SignedLong;
      resetDataLayout("e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-"
                      "f80:128-n8:16:32-S128", "_");
      HasAlignMac68kSupport = true;
    }
  
    bool handleTargetFeatures(std::vector<std::string> &Features,
                              DiagnosticsEngine &Diags) override {
      if (!DarwinTargetInfo<X86_32TargetInfo>::handleTargetFeatures(Features,
                                                                    Diags))
        return false;
      // We now know the features we have: we can decide how to align vectors.
      MaxVectorAlign =
          hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128;
      return true;
    }
  };
  
  // x86-32 Windows target
  class LLVM_LIBRARY_VISIBILITY WindowsX86_32TargetInfo
      : public WindowsTargetInfo<X86_32TargetInfo> {
  public:
    WindowsX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : WindowsTargetInfo<X86_32TargetInfo>(Triple, Opts) {
      DoubleAlign = LongLongAlign = 64;
      bool IsWinCOFF =
          getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
      bool IsMSVC = getTriple().isWindowsMSVCEnvironment();
      std::string Layout = IsWinCOFF ? "e-m:x" : "e-m:e";
      Layout += "-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-";
      Layout += IsMSVC ? "f80:128" : "f80:32";
      Layout += "-n8:16:32-a:0:32-S32";
      resetDataLayout(Layout, IsWinCOFF ? "_" : "");
    }
  };
  
  // x86-32 Windows Visual Studio target
  class LLVM_LIBRARY_VISIBILITY MicrosoftX86_32TargetInfo
      : public WindowsX86_32TargetInfo {
  public:
    MicrosoftX86_32TargetInfo(const llvm::Triple &Triple,
                              const TargetOptions &Opts)
        : WindowsX86_32TargetInfo(Triple, Opts) {
      LongDoubleWidth = LongDoubleAlign = 64;
      LongDoubleFormat = &llvm::APFloat::IEEEdouble();
    }
  
    void getTargetDefines(const LangOptions &Opts,
                          MacroBuilder &Builder) const override {
      WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
      // The value of the following reflects processor type.
      // 300=386, 400=486, 500=Pentium, 600=Blend (default)
      // We lost the original triple, so we use the default.
      Builder.defineMacro("_M_IX86", "600");
    }
  };
  
  // x86-32 MinGW target
  class LLVM_LIBRARY_VISIBILITY MinGWX86_32TargetInfo
      : public WindowsX86_32TargetInfo {
  public:
    MinGWX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : WindowsX86_32TargetInfo(Triple, Opts) {
      HasFloat128 = true;
    }
  
    void getTargetDefines(const LangOptions &Opts,
                          MacroBuilder &Builder) const override {
      WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
      Builder.defineMacro("_X86_");
    }
  };
  
  // x86-32 Cygwin target
  class LLVM_LIBRARY_VISIBILITY CygwinX86_32TargetInfo : public X86_32TargetInfo {
  public:
    CygwinX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : X86_32TargetInfo(Triple, Opts) {
      this->WCharType = TargetInfo::UnsignedShort;
      DoubleAlign = LongLongAlign = 64;
      resetDataLayout("e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:"
                      "32-n8:16:32-a:0:32-S32",
                      "_");
    }
  
    void getTargetDefines(const LangOptions &Opts,
                          MacroBuilder &Builder) const override {
      X86_32TargetInfo::getTargetDefines(Opts, Builder);
      Builder.defineMacro("_X86_");
      Builder.defineMacro("__CYGWIN__");
      Builder.defineMacro("__CYGWIN32__");
      addCygMingDefines(Opts, Builder);
      DefineStd(Builder, "unix", Opts);
      if (Opts.CPlusPlus)
        Builder.defineMacro("_GNU_SOURCE");
    }
  };
  
  // x86-32 Haiku target
  class LLVM_LIBRARY_VISIBILITY HaikuX86_32TargetInfo
      : public HaikuTargetInfo<X86_32TargetInfo> {
  public:
    HaikuX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : HaikuTargetInfo<X86_32TargetInfo>(Triple, Opts) {}
  
    void getTargetDefines(const LangOptions &Opts,
                          MacroBuilder &Builder) const override {
      HaikuTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder);
      Builder.defineMacro("__INTEL__");
    }
  };
  
  // X86-32 MCU target
  class LLVM_LIBRARY_VISIBILITY MCUX86_32TargetInfo : public X86_32TargetInfo {
  public:
    MCUX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : X86_32TargetInfo(Triple, Opts) {
      LongDoubleWidth = 64;
      LongDoubleFormat = &llvm::APFloat::IEEEdouble();
      resetDataLayout("e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:32-f64:"
                      "32-f128:32-n8:16:32-a:0:32-S32");
      WIntType = UnsignedInt;
    }
  
    CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
      // On MCU we support only C calling convention.
      return CC == CC_C ? CCCR_OK : CCCR_Warning;
    }
  
    void getTargetDefines(const LangOptions &Opts,
                          MacroBuilder &Builder) const override {
      X86_32TargetInfo::getTargetDefines(Opts, Builder);
      Builder.defineMacro("__iamcu");
      Builder.defineMacro("__iamcu__");
    }
  
    bool allowsLargerPreferedTypeAlignment() const override { return false; }
  };
  
  // x86-32 RTEMS target
  class LLVM_LIBRARY_VISIBILITY RTEMSX86_32TargetInfo : public X86_32TargetInfo {
  public:
    RTEMSX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : X86_32TargetInfo(Triple, Opts) {
      SizeType = UnsignedLong;
      IntPtrType = SignedLong;
      PtrDiffType = SignedLong;
    }
  
    void getTargetDefines(const LangOptions &Opts,
                          MacroBuilder &Builder) const override {
      X86_32TargetInfo::getTargetDefines(Opts, Builder);
      Builder.defineMacro("__INTEL__");
      Builder.defineMacro("__rtems__");
    }
  };
  
  // x86-64 generic target
  class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo {
  public:
    X86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : X86TargetInfo(Triple, Opts) {
      const bool IsX32 = getTriple().isX32();
      bool IsWinCOFF =
          getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
      LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64;
      LongDoubleWidth = 128;
      LongDoubleAlign = 128;
      LargeArrayMinWidth = 128;
      LargeArrayAlign = 128;
      SuitableAlign = 128;
      SizeType = IsX32 ? UnsignedInt : UnsignedLong;
      PtrDiffType = IsX32 ? SignedInt : SignedLong;
      IntPtrType = IsX32 ? SignedInt : SignedLong;
      IntMaxType = IsX32 ? SignedLongLong : SignedLong;
      Int64Type = IsX32 ? SignedLongLong : SignedLong;
      RegParmMax = 6;
  
      // Pointers are 32-bit in x32.
      resetDataLayout(IsX32 ? "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-"
                              "i64:64-f80:128-n8:16:32:64-S128"
                            : IsWinCOFF ? "e-m:w-p270:32:32-p271:32:32-p272:64:"
                                          "64-i64:64-f80:128-n8:16:32:64-S128"
                                        : "e-m:e-p270:32:32-p271:32:32-p272:64:"
                                          "64-i64:64-f80:128-n8:16:32:64-S128");
  
      // Use fpret only for long double.
      RealTypeUsesObjCFPRet = (1 << (int)FloatModeKind::LongDouble);
  
      // Use fp2ret for _Complex long double.
      ComplexLongDoubleUsesFP2Ret = true;
  
      // Make __builtin_ms_va_list available.
      HasBuiltinMSVaList = true;
  
      // x86-64 has atomics up to 16 bytes.
      MaxAtomicPromoteWidth = 128;
      MaxAtomicInlineWidth = 64;
    }
  
    BuiltinVaListKind getBuiltinVaListKind() const override {
      return TargetInfo::X86_64ABIBuiltinVaList;
    }
  
    int getEHDataRegisterNumber(unsigned RegNo) const override {
      if (RegNo == 0)
        return 0;
      if (RegNo == 1)
        return 1;
      return -1;
    }
  
    CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
      switch (CC) {
      case CC_C:
      case CC_Swift:
      case CC_SwiftAsync:
      case CC_X86VectorCall:
      case CC_IntelOclBicc:
      case CC_Win64:
      case CC_PreserveMost:
      case CC_PreserveAll:
      case CC_X86RegCall:
      case CC_OpenCLKernel:
        return CCCR_OK;
      default:
        return CCCR_Warning;
      }
    }
  
    CallingConv getDefaultCallingConv() const override {
      return CC_C;
    }
  
    // for x32 we need it here explicitly
    bool hasInt128Type() const override { return true; }
  
    unsigned getUnwindWordWidth() const override { return 64; }
  
    unsigned getRegisterWidth() const override { return 64; }
  
    bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize,
                                        bool &HasSizeMismatch) const override {
      // rsp and rbp are the only 64-bit registers the x86 backend can currently
      // handle.
      if (RegName.equals("rsp") || RegName.equals("rbp")) {
        // Check that the register size is 64-bit.
        HasSizeMismatch = RegSize != 64;
        return true;
      }
  
      // Check if the register is a 32-bit register the backend can handle.
      return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize,
                                                           HasSizeMismatch);
    }
  
    void setMaxAtomicWidth() override {
      if (hasFeature("cx16"))
        MaxAtomicInlineWidth = 128;
    }
  
    ArrayRef<Builtin::Info> getTargetBuiltins() const override;
  
    bool hasBitIntType() const override { return true; }
  };
  
  // x86-64 Windows target
  class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo
      : public WindowsTargetInfo<X86_64TargetInfo> {
  public:
    WindowsX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : WindowsTargetInfo<X86_64TargetInfo>(Triple, Opts) {
      LongWidth = LongAlign = 32;
      DoubleAlign = LongLongAlign = 64;
      IntMaxType = SignedLongLong;
      Int64Type = SignedLongLong;
      SizeType = UnsignedLongLong;
      PtrDiffType = SignedLongLong;
      IntPtrType = SignedLongLong;
    }
  
    BuiltinVaListKind getBuiltinVaListKind() const override {
      return TargetInfo::CharPtrBuiltinVaList;
    }
  
    CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
      switch (CC) {
      case CC_X86StdCall:
      case CC_X86ThisCall:
      case CC_X86FastCall:
        return CCCR_Ignore;
      case CC_C:
      case CC_X86VectorCall:
      case CC_IntelOclBicc:
      case CC_PreserveMost:
      case CC_PreserveAll:
      case CC_X86_64SysV:
      case CC_Swift:
      case CC_SwiftAsync:
      case CC_X86RegCall:
      case CC_OpenCLKernel:
        return CCCR_OK;
      default:
        return CCCR_Warning;
      }
    }
  };
  
  // x86-64 Windows Visual Studio target
  class LLVM_LIBRARY_VISIBILITY MicrosoftX86_64TargetInfo
      : public WindowsX86_64TargetInfo {
  public:
    MicrosoftX86_64TargetInfo(const llvm::Triple &Triple,
                              const TargetOptions &Opts)
        : WindowsX86_64TargetInfo(Triple, Opts) {
      LongDoubleWidth = LongDoubleAlign = 64;
      LongDoubleFormat = &llvm::APFloat::IEEEdouble();
    }
  
    void getTargetDefines(const LangOptions &Opts,
                          MacroBuilder &Builder) const override {
      WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
      Builder.defineMacro("_M_X64", "100");
      Builder.defineMacro("_M_AMD64", "100");
    }
  
    TargetInfo::CallingConvKind
    getCallingConvKind(bool ClangABICompat4) const override {
      return CCK_MicrosoftWin64;
    }
  };
  
  // x86-64 MinGW target
  class LLVM_LIBRARY_VISIBILITY MinGWX86_64TargetInfo
      : public WindowsX86_64TargetInfo {
  public:
    MinGWX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : WindowsX86_64TargetInfo(Triple, Opts) {
      // Mingw64 rounds long double size and alignment up to 16 bytes, but sticks
      // with x86 FP ops. Weird.
      LongDoubleWidth = LongDoubleAlign = 128;
      LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
      HasFloat128 = true;
    }
  };
  
  // x86-64 Cygwin target
  class LLVM_LIBRARY_VISIBILITY CygwinX86_64TargetInfo : public X86_64TargetInfo {
  public:
    CygwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : X86_64TargetInfo(Triple, Opts) {
      this->WCharType = TargetInfo::UnsignedShort;
      TLSSupported = false;
    }
  
    void getTargetDefines(const LangOptions &Opts,
                          MacroBuilder &Builder) const override {
      X86_64TargetInfo::getTargetDefines(Opts, Builder);
      Builder.defineMacro("__x86_64__");
      Builder.defineMacro("__CYGWIN__");
      Builder.defineMacro("__CYGWIN64__");
      addCygMingDefines(Opts, Builder);
      DefineStd(Builder, "unix", Opts);
      if (Opts.CPlusPlus)
        Builder.defineMacro("_GNU_SOURCE");
    }
  };
  
  class LLVM_LIBRARY_VISIBILITY DarwinX86_64TargetInfo
      : public DarwinTargetInfo<X86_64TargetInfo> {
  public:
    DarwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : DarwinTargetInfo<X86_64TargetInfo>(Triple, Opts) {
      Int64Type = SignedLongLong;
      // The 64-bit iOS simulator uses the builtin bool type for Objective-C.
      llvm::Triple T = llvm::Triple(Triple);
      if (T.isiOS())
        UseSignedCharForObjCBool = false;
      resetDataLayout("e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:"
                      "16:32:64-S128", "_");
    }
  
    bool handleTargetFeatures(std::vector<std::string> &Features,
                              DiagnosticsEngine &Diags) override {
      if (!DarwinTargetInfo<X86_64TargetInfo>::handleTargetFeatures(Features,
                                                                    Diags))
        return false;
      // We now know the features we have: we can decide how to align vectors.
      MaxVectorAlign =
          hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128;
      return true;
    }
  };
  
  class LLVM_LIBRARY_VISIBILITY OpenBSDX86_64TargetInfo
      : public OpenBSDTargetInfo<X86_64TargetInfo> {
  public:
    OpenBSDX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : OpenBSDTargetInfo<X86_64TargetInfo>(Triple, Opts) {
      IntMaxType = SignedLongLong;
      Int64Type = SignedLongLong;
    }
  };
  
  // x86_32 Android target
  class LLVM_LIBRARY_VISIBILITY AndroidX86_32TargetInfo
      : public LinuxTargetInfo<X86_32TargetInfo> {
  public:
    AndroidX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : LinuxTargetInfo<X86_32TargetInfo>(Triple, Opts) {
      SuitableAlign = 32;
      LongDoubleWidth = 64;
      LongDoubleFormat = &llvm::APFloat::IEEEdouble();
    }
  };
  
  // x86_64 Android target
  class LLVM_LIBRARY_VISIBILITY AndroidX86_64TargetInfo
      : public LinuxTargetInfo<X86_64TargetInfo> {
  public:
    AndroidX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
        : LinuxTargetInfo<X86_64TargetInfo>(Triple, Opts) {
      LongDoubleFormat = &llvm::APFloat::IEEEquad();
    }
  };
  } // namespace targets
  } // namespace clang
  #endif // LLVM_CLANG_LIB_BASIC_TARGETS_X86_H
  