diff options
Diffstat (limited to 'clang/lib/Basic/Targets/ARM.cpp')
| -rw-r--r-- | clang/lib/Basic/Targets/ARM.cpp | 1255 | 
1 files changed, 1255 insertions, 0 deletions
| diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp new file mode 100644 index 000000000000..437a77afdc99 --- /dev/null +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -0,0 +1,1255 @@ +//===--- ARM.cpp - Implement ARM target feature support -------------------===// +// +// 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 implements ARM TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "ARM.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +void ARMTargetInfo::setABIAAPCS() { +  IsAAPCS = true; + +  DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; +  const llvm::Triple &T = getTriple(); + +  bool IsNetBSD = T.isOSNetBSD(); +  bool IsOpenBSD = T.isOSOpenBSD(); +  if (!T.isOSWindows() && !IsNetBSD && !IsOpenBSD) +    WCharType = UnsignedInt; + +  UseBitFieldTypeAlignment = true; + +  ZeroLengthBitfieldBoundary = 0; + +  // Thumb1 add sp, #imm requires the immediate value be multiple of 4, +  // so set preferred for small types to 32. +  if (T.isOSBinFormatMachO()) { +    resetDataLayout(BigEndian +                        ? "E-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" +                        : "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"); +  } else if (T.isOSWindows()) { +    assert(!BigEndian && "Windows on ARM does not support big endian"); +    resetDataLayout("e" +                    "-m:w" +                    "-p:32:32" +                    "-Fi8" +                    "-i64:64" +                    "-v128:64:128" +                    "-a:0:32" +                    "-n32" +                    "-S64"); +  } else if (T.isOSNaCl()) { +    assert(!BigEndian && "NaCl on ARM does not support big endian"); +    resetDataLayout("e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S128"); +  } else { +    resetDataLayout(BigEndian +                        ? "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" +                        : "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"); +  } + +  // FIXME: Enumerated types are variable width in straight AAPCS. +} + +void ARMTargetInfo::setABIAPCS(bool IsAAPCS16) { +  const llvm::Triple &T = getTriple(); + +  IsAAPCS = false; + +  if (IsAAPCS16) +    DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; +  else +    DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32; + +  WCharType = SignedInt; + +  // Do not respect the alignment of bit-field types when laying out +  // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. +  UseBitFieldTypeAlignment = false; + +  /// gcc forces the alignment to 4 bytes, regardless of the type of the +  /// zero length bitfield.  This corresponds to EMPTY_FIELD_BOUNDARY in +  /// gcc. +  ZeroLengthBitfieldBoundary = 32; + +  if (T.isOSBinFormatMachO() && IsAAPCS16) { +    assert(!BigEndian && "AAPCS16 does not support big-endian"); +    resetDataLayout("e-m:o-p:32:32-Fi8-i64:64-a:0:32-n32-S128"); +  } else if (T.isOSBinFormatMachO()) +    resetDataLayout( +        BigEndian +            ? "E-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" +            : "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"); +  else +    resetDataLayout( +        BigEndian +            ? "E-m:e-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" +            : "e-m:e-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"); + +  // FIXME: Override "preferred align" for double and long long. +} + +void ARMTargetInfo::setArchInfo() { +  StringRef ArchName = getTriple().getArchName(); + +  ArchISA = llvm::ARM::parseArchISA(ArchName); +  CPU = llvm::ARM::getDefaultCPU(ArchName); +  llvm::ARM::ArchKind AK = llvm::ARM::parseArch(ArchName); +  if (AK != llvm::ARM::ArchKind::INVALID) +    ArchKind = AK; +  setArchInfo(ArchKind); +} + +void ARMTargetInfo::setArchInfo(llvm::ARM::ArchKind Kind) { +  StringRef SubArch; + +  // cache TargetParser info +  ArchKind = Kind; +  SubArch = llvm::ARM::getSubArch(ArchKind); +  ArchProfile = llvm::ARM::parseArchProfile(SubArch); +  ArchVersion = llvm::ARM::parseArchVersion(SubArch); + +  // cache CPU related strings +  CPUAttr = getCPUAttr(); +  CPUProfile = getCPUProfile(); +} + +void ARMTargetInfo::setAtomic() { +  // when triple does not specify a sub arch, +  // then we are not using inline atomics +  bool ShouldUseInlineAtomic = +      (ArchISA == llvm::ARM::ISAKind::ARM && ArchVersion >= 6) || +      (ArchISA == llvm::ARM::ISAKind::THUMB && ArchVersion >= 7); +  // Cortex M does not support 8 byte atomics, while general Thumb2 does. +  if (ArchProfile == llvm::ARM::ProfileKind::M) { +    MaxAtomicPromoteWidth = 32; +    if (ShouldUseInlineAtomic) +      MaxAtomicInlineWidth = 32; +  } else { +    MaxAtomicPromoteWidth = 64; +    if (ShouldUseInlineAtomic) +      MaxAtomicInlineWidth = 64; +  } +} + +bool ARMTargetInfo::hasMVE() const { +  return ArchKind == llvm::ARM::ArchKind::ARMV8_1MMainline && MVE != 0; +} + +bool ARMTargetInfo::hasMVEFloat() const { +  return hasMVE() && (MVE & MVE_FP); +} + +bool ARMTargetInfo::isThumb() const { +  return ArchISA == llvm::ARM::ISAKind::THUMB; +} + +bool ARMTargetInfo::supportsThumb() const { +  return CPUAttr.count('T') || ArchVersion >= 6; +} + +bool ARMTargetInfo::supportsThumb2() const { +  return CPUAttr.equals("6T2") || +         (ArchVersion >= 7 && !CPUAttr.equals("8M_BASE")); +} + +StringRef ARMTargetInfo::getCPUAttr() const { +  // For most sub-arches, the build attribute CPU name is enough. +  // For Cortex variants, it's slightly different. +  switch (ArchKind) { +  default: +    return llvm::ARM::getCPUAttr(ArchKind); +  case llvm::ARM::ArchKind::ARMV6M: +    return "6M"; +  case llvm::ARM::ArchKind::ARMV7S: +    return "7S"; +  case llvm::ARM::ArchKind::ARMV7A: +    return "7A"; +  case llvm::ARM::ArchKind::ARMV7R: +    return "7R"; +  case llvm::ARM::ArchKind::ARMV7M: +    return "7M"; +  case llvm::ARM::ArchKind::ARMV7EM: +    return "7EM"; +  case llvm::ARM::ArchKind::ARMV7VE: +    return "7VE"; +  case llvm::ARM::ArchKind::ARMV8A: +    return "8A"; +  case llvm::ARM::ArchKind::ARMV8_1A: +    return "8_1A"; +  case llvm::ARM::ArchKind::ARMV8_2A: +    return "8_2A"; +  case llvm::ARM::ArchKind::ARMV8_3A: +    return "8_3A"; +  case llvm::ARM::ArchKind::ARMV8_4A: +    return "8_4A"; +  case llvm::ARM::ArchKind::ARMV8_5A: +    return "8_5A"; +  case llvm::ARM::ArchKind::ARMV8MBaseline: +    return "8M_BASE"; +  case llvm::ARM::ArchKind::ARMV8MMainline: +    return "8M_MAIN"; +  case llvm::ARM::ArchKind::ARMV8R: +    return "8R"; +  case llvm::ARM::ArchKind::ARMV8_1MMainline: +    return "8_1M_MAIN"; +  } +} + +StringRef ARMTargetInfo::getCPUProfile() const { +  switch (ArchProfile) { +  case llvm::ARM::ProfileKind::A: +    return "A"; +  case llvm::ARM::ProfileKind::R: +    return "R"; +  case llvm::ARM::ProfileKind::M: +    return "M"; +  default: +    return ""; +  } +} + +ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple, +                             const TargetOptions &Opts) +    : TargetInfo(Triple), FPMath(FP_Default), IsAAPCS(true), LDREX(0), +      HW_FP(0) { +  bool IsOpenBSD = Triple.isOSOpenBSD(); +  bool IsNetBSD = Triple.isOSNetBSD(); + +  // FIXME: the isOSBinFormatMachO is a workaround for identifying a Darwin-like +  // environment where size_t is `unsigned long` rather than `unsigned int` + +  PtrDiffType = IntPtrType = +      (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD || +       IsNetBSD) +          ? SignedLong +          : SignedInt; + +  SizeType = (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD || +              IsNetBSD) +                 ? UnsignedLong +                 : UnsignedInt; + +  // ptrdiff_t is inconsistent on Darwin +  if ((Triple.isOSDarwin() || Triple.isOSBinFormatMachO()) && +      !Triple.isWatchABI()) +    PtrDiffType = SignedInt; + +  // Cache arch related info. +  setArchInfo(); + +  // {} in inline assembly are neon specifiers, not assembly variant +  // specifiers. +  NoAsmVariants = true; + +  // FIXME: This duplicates code from the driver that sets the -target-abi +  // option - this code is used if -target-abi isn't passed and should +  // be unified in some way. +  if (Triple.isOSBinFormatMachO()) { +    // The backend is hardwired to assume AAPCS for M-class processors, ensure +    // the frontend matches that. +    if (Triple.getEnvironment() == llvm::Triple::EABI || +        Triple.getOS() == llvm::Triple::UnknownOS || +        ArchProfile == llvm::ARM::ProfileKind::M) { +      setABI("aapcs"); +    } else if (Triple.isWatchABI()) { +      setABI("aapcs16"); +    } else { +      setABI("apcs-gnu"); +    } +  } else if (Triple.isOSWindows()) { +    // FIXME: this is invalid for WindowsCE +    setABI("aapcs"); +  } else { +    // Select the default based on the platform. +    switch (Triple.getEnvironment()) { +    case llvm::Triple::Android: +    case llvm::Triple::GNUEABI: +    case llvm::Triple::GNUEABIHF: +    case llvm::Triple::MuslEABI: +    case llvm::Triple::MuslEABIHF: +      setABI("aapcs-linux"); +      break; +    case llvm::Triple::EABIHF: +    case llvm::Triple::EABI: +      setABI("aapcs"); +      break; +    case llvm::Triple::GNU: +      setABI("apcs-gnu"); +      break; +    default: +      if (IsNetBSD) +        setABI("apcs-gnu"); +      else if (IsOpenBSD) +        setABI("aapcs-linux"); +      else +        setABI("aapcs"); +      break; +    } +  } + +  // ARM targets default to using the ARM C++ ABI. +  TheCXXABI.set(TargetCXXABI::GenericARM); + +  // ARM has atomics up to 8 bytes +  setAtomic(); + +  // Maximum alignment for ARM NEON data types should be 64-bits (AAPCS) +  // as well the default alignment +  if (IsAAPCS && (Triple.getEnvironment() != llvm::Triple::Android)) +    DefaultAlignForAttributeAligned = MaxVectorAlign = 64; + +  // Do force alignment of members that follow zero length bitfields.  If +  // the alignment of the zero-length bitfield is greater than the member +  // that follows it, `bar', `bar' will be aligned as the  type of the +  // zero length bitfield. +  UseZeroLengthBitfieldAlignment = true; + +  if (Triple.getOS() == llvm::Triple::Linux || +      Triple.getOS() == llvm::Triple::UnknownOS) +    this->MCountName = Opts.EABIVersion == llvm::EABI::GNU +                           ? "llvm.arm.gnu.eabi.mcount" +                           : "\01mcount"; + +  SoftFloatABI = llvm::is_contained(Opts.FeaturesAsWritten, "+soft-float-abi"); +} + +StringRef ARMTargetInfo::getABI() const { return ABI; } + +bool ARMTargetInfo::setABI(const std::string &Name) { +  ABI = Name; + +  // The defaults (above) are for AAPCS, check if we need to change them. +  // +  // FIXME: We need support for -meabi... we could just mangle it into the +  // name. +  if (Name == "apcs-gnu" || Name == "aapcs16") { +    setABIAPCS(Name == "aapcs16"); +    return true; +  } +  if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") { +    setABIAAPCS(); +    return true; +  } +  return false; +} + +// FIXME: This should be based on Arch attributes, not CPU names. +bool ARMTargetInfo::initFeatureMap( +    llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, +    const std::vector<std::string> &FeaturesVec) const { + +  std::string ArchFeature; +  std::vector<StringRef> TargetFeatures; +  llvm::ARM::ArchKind Arch = llvm::ARM::parseArch(getTriple().getArchName()); + +  // Map the base architecture to an appropriate target feature, so we don't +  // rely on the target triple. +  llvm::ARM::ArchKind CPUArch = llvm::ARM::parseCPUArch(CPU); +  if (CPUArch == llvm::ARM::ArchKind::INVALID) +    CPUArch = Arch; +  if (CPUArch != llvm::ARM::ArchKind::INVALID) { +    ArchFeature = ("+" + llvm::ARM::getArchName(CPUArch)).str(); +    TargetFeatures.push_back(ArchFeature); +  } + +  // get default FPU features +  unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch); +  llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures); + +  // get default Extension features +  unsigned Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch); +  llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures); + +  for (auto Feature : TargetFeatures) +    if (Feature[0] == '+') +      Features[Feature.drop_front(1)] = true; + +  // Enable or disable thumb-mode explicitly per function to enable mixed +  // ARM and Thumb code generation. +  if (isThumb()) +    Features["thumb-mode"] = true; +  else +    Features["thumb-mode"] = false; + +  // Convert user-provided arm and thumb GNU target attributes to +  // [-|+]thumb-mode target features respectively. +  std::vector<std::string> UpdatedFeaturesVec; +  for (const auto &Feature : FeaturesVec) { +    // Skip soft-float-abi; it's something we only use to initialize a bit of +    // class state, and is otherwise unrecognized. +    if (Feature == "+soft-float-abi") +      continue; + +    StringRef FixedFeature; +    if (Feature == "+arm") +      FixedFeature = "-thumb-mode"; +    else if (Feature == "+thumb") +      FixedFeature = "+thumb-mode"; +    else +      FixedFeature = Feature; +    UpdatedFeaturesVec.push_back(FixedFeature.str()); +  } + +  return TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec); +} + + +bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, +                                         DiagnosticsEngine &Diags) { +  FPU = 0; +  MVE = 0; +  CRC = 0; +  Crypto = 0; +  DSP = 0; +  Unaligned = 1; +  SoftFloat = false; +  // Note that SoftFloatABI is initialized in our constructor. +  HWDiv = 0; +  DotProd = 0; +  HasFloat16 = true; + +  // This does not diagnose illegal cases like having both +  // "+vfpv2" and "+vfpv3" or having "+neon" and "-fp64". +  for (const auto &Feature : Features) { +    if (Feature == "+soft-float") { +      SoftFloat = true; +    } else if (Feature == "+vfp2sp" || Feature == "+vfp2") { +      FPU |= VFP2FPU; +      HW_FP |= HW_FP_SP; +      if (Feature == "+vfp2") +          HW_FP |= HW_FP_DP; +    } else if (Feature == "+vfp3sp" || Feature == "+vfp3d16sp" || +               Feature == "+vfp3" || Feature == "+vfp3d16") { +      FPU |= VFP3FPU; +      HW_FP |= HW_FP_SP; +      if (Feature == "+vfp3" || Feature == "+vfp3d16") +          HW_FP |= HW_FP_DP; +    } else if (Feature == "+vfp4sp" || Feature == "+vfp4d16sp" || +               Feature == "+vfp4" || Feature == "+vfp4d16") { +      FPU |= VFP4FPU; +      HW_FP |= HW_FP_SP | HW_FP_HP; +      if (Feature == "+vfp4" || Feature == "+vfp4d16") +          HW_FP |= HW_FP_DP; +    } else if (Feature == "+fp-armv8sp" || Feature == "+fp-armv8d16sp" || +               Feature == "+fp-armv8" || Feature == "+fp-armv8d16") { +      FPU |= FPARMV8; +      HW_FP |= HW_FP_SP | HW_FP_HP; +      if (Feature == "+fp-armv8" || Feature == "+fp-armv8d16") +          HW_FP |= HW_FP_DP; +    } else if (Feature == "+neon") { +      FPU |= NeonFPU; +      HW_FP |= HW_FP_SP; +    } else if (Feature == "+hwdiv") { +      HWDiv |= HWDivThumb; +    } else if (Feature == "+hwdiv-arm") { +      HWDiv |= HWDivARM; +    } else if (Feature == "+crc") { +      CRC = 1; +    } else if (Feature == "+crypto") { +      Crypto = 1; +    } else if (Feature == "+dsp") { +      DSP = 1; +    } else if (Feature == "+fp64") { +      HW_FP |= HW_FP_DP; +    } else if (Feature == "+8msecext") { +      if (CPUProfile != "M" || ArchVersion != 8) { +        Diags.Report(diag::err_target_unsupported_mcmse) << CPU; +        return false; +      } +    } else if (Feature == "+strict-align") { +      Unaligned = 0; +    } else if (Feature == "+fp16") { +      HW_FP |= HW_FP_HP; +    } else if (Feature == "+fullfp16") { +      HasLegalHalfType = true; +    } else if (Feature == "+dotprod") { +      DotProd = true; +    } else if (Feature == "+mve") { +      DSP = 1; +      MVE |= MVE_INT; +    } else if (Feature == "+mve.fp") { +      DSP = 1; +      HasLegalHalfType = true; +      FPU |= FPARMV8; +      MVE |= MVE_INT | MVE_FP; +      HW_FP |= HW_FP_SP | HW_FP_HP; +    } +  } + +  switch (ArchVersion) { +  case 6: +    if (ArchProfile == llvm::ARM::ProfileKind::M) +      LDREX = 0; +    else if (ArchKind == llvm::ARM::ArchKind::ARMV6K) +      LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; +    else +      LDREX = LDREX_W; +    break; +  case 7: +    if (ArchProfile == llvm::ARM::ProfileKind::M) +      LDREX = LDREX_W | LDREX_H | LDREX_B; +    else +      LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; +    break; +  case 8: +    LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; +  } + +  if (!(FPU & NeonFPU) && FPMath == FP_Neon) { +    Diags.Report(diag::err_target_unsupported_fpmath) << "neon"; +    return false; +  } + +  if (FPMath == FP_Neon) +    Features.push_back("+neonfp"); +  else if (FPMath == FP_VFP) +    Features.push_back("-neonfp"); + +  return true; +} + +bool ARMTargetInfo::hasFeature(StringRef Feature) const { +  return llvm::StringSwitch<bool>(Feature) +      .Case("arm", true) +      .Case("aarch32", true) +      .Case("softfloat", SoftFloat) +      .Case("thumb", isThumb()) +      .Case("neon", (FPU & NeonFPU) && !SoftFloat) +      .Case("vfp", FPU && !SoftFloat) +      .Case("hwdiv", HWDiv & HWDivThumb) +      .Case("hwdiv-arm", HWDiv & HWDivARM) +      .Case("mve", hasMVE()) +      .Default(false); +} + +bool ARMTargetInfo::isValidCPUName(StringRef Name) const { +  return Name == "generic" || +         llvm::ARM::parseCPUArch(Name) != llvm::ARM::ArchKind::INVALID; +} + +void ARMTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { +  llvm::ARM::fillValidCPUArchList(Values); +} + +bool ARMTargetInfo::setCPU(const std::string &Name) { +  if (Name != "generic") +    setArchInfo(llvm::ARM::parseCPUArch(Name)); + +  if (ArchKind == llvm::ARM::ArchKind::INVALID) +    return false; +  setAtomic(); +  CPU = Name; +  return true; +} + +bool ARMTargetInfo::setFPMath(StringRef Name) { +  if (Name == "neon") { +    FPMath = FP_Neon; +    return true; +  } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" || +             Name == "vfp4") { +    FPMath = FP_VFP; +    return true; +  } +  return false; +} + +void ARMTargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts, +                                            MacroBuilder &Builder) const { +  Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); +} + +void ARMTargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts, +                                            MacroBuilder &Builder) const { +  // Also include the ARMv8.1-A defines +  getTargetDefinesARMV81A(Opts, Builder); +} + +void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, +                                     MacroBuilder &Builder) const { +  // Target identification. +  Builder.defineMacro("__arm"); +  Builder.defineMacro("__arm__"); +  // For bare-metal none-eabi. +  if (getTriple().getOS() == llvm::Triple::UnknownOS && +      (getTriple().getEnvironment() == llvm::Triple::EABI || +       getTriple().getEnvironment() == llvm::Triple::EABIHF)) +    Builder.defineMacro("__ELF__"); + +  // Target properties. +  Builder.defineMacro("__REGISTER_PREFIX__", ""); + +  // Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU +  // happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__. +  if (getTriple().isWatchABI()) +    Builder.defineMacro("__ARM_ARCH_7K__", "2"); + +  if (!CPUAttr.empty()) +    Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__"); + +  // ACLE 6.4.1 ARM/Thumb instruction set architecture +  // __ARM_ARCH is defined as an integer value indicating the current ARM ISA +  Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion)); + +  if (ArchVersion >= 8) { +    // ACLE 6.5.7 Crypto Extension +    if (Crypto) +      Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); +    // ACLE 6.5.8 CRC32 Extension +    if (CRC) +      Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); +    // ACLE 6.5.10 Numeric Maximum and Minimum +    Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); +    // ACLE 6.5.9 Directed Rounding +    Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); +  } + +  // __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA.  It +  // is not defined for the M-profile. +  // NOTE that the default profile is assumed to be 'A' +  if (CPUProfile.empty() || ArchProfile != llvm::ARM::ProfileKind::M) +    Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1"); + +  // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supports the original +  // Thumb ISA (including v6-M and v8-M Baseline).  It is set to 2 if the +  // core supports the Thumb-2 ISA as found in the v6T2 architecture and all +  // v7 and v8 architectures excluding v8-M Baseline. +  if (supportsThumb2()) +    Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2"); +  else if (supportsThumb()) +    Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1"); + +  // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit +  // instruction set such as ARM or Thumb. +  Builder.defineMacro("__ARM_32BIT_STATE", "1"); + +  // ACLE 6.4.2 Architectural Profile (A, R, M or pre-Cortex) + +  // __ARM_ARCH_PROFILE is defined as 'A', 'R', 'M' or 'S', or unset. +  if (!CPUProfile.empty()) +    Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'"); + +  // ACLE 6.4.3 Unaligned access supported in hardware +  if (Unaligned) +    Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); + +  // ACLE 6.4.4 LDREX/STREX +  if (LDREX) +    Builder.defineMacro("__ARM_FEATURE_LDREX", "0x" + Twine::utohexstr(LDREX)); + +  // ACLE 6.4.5 CLZ +  if (ArchVersion == 5 || (ArchVersion == 6 && CPUProfile != "M") || +      ArchVersion > 6) +    Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); + +  // ACLE 6.5.1 Hardware Floating Point +  if (HW_FP) +    Builder.defineMacro("__ARM_FP", "0x" + Twine::utohexstr(HW_FP)); + +  // ACLE predefines. +  Builder.defineMacro("__ARM_ACLE", "200"); + +  // FP16 support (we currently only support IEEE format). +  Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); +  Builder.defineMacro("__ARM_FP16_ARGS", "1"); + +  // ACLE 6.5.3 Fused multiply-accumulate (FMA) +  if (ArchVersion >= 7 && (FPU & VFP4FPU)) +    Builder.defineMacro("__ARM_FEATURE_FMA", "1"); + +  // Subtarget options. + +  // FIXME: It's more complicated than this and we don't really support +  // interworking. +  // Windows on ARM does not "support" interworking +  if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows()) +    Builder.defineMacro("__THUMB_INTERWORK__"); + +  if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") { +    // Embedded targets on Darwin follow AAPCS, but not EABI. +    // Windows on ARM follows AAPCS VFP, but does not conform to EABI. +    if (!getTriple().isOSBinFormatMachO() && !getTriple().isOSWindows()) +      Builder.defineMacro("__ARM_EABI__"); +    Builder.defineMacro("__ARM_PCS", "1"); +  } + +  if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp" || ABI == "aapcs16") +    Builder.defineMacro("__ARM_PCS_VFP", "1"); + +  if (SoftFloat) +    Builder.defineMacro("__SOFTFP__"); + +  // ACLE position independent code macros. +  if (Opts.ROPI) +    Builder.defineMacro("__ARM_ROPI", "1"); +  if (Opts.RWPI) +    Builder.defineMacro("__ARM_RWPI", "1"); + +  if (ArchKind == llvm::ARM::ArchKind::XSCALE) +    Builder.defineMacro("__XSCALE__"); + +  if (isThumb()) { +    Builder.defineMacro("__THUMBEL__"); +    Builder.defineMacro("__thumb__"); +    if (supportsThumb2()) +      Builder.defineMacro("__thumb2__"); +  } + +  // ACLE 6.4.9 32-bit SIMD instructions +  if ((CPUProfile != "M" && ArchVersion >= 6) || (CPUProfile == "M" && DSP)) +    Builder.defineMacro("__ARM_FEATURE_SIMD32", "1"); + +  // ACLE 6.4.10 Hardware Integer Divide +  if (((HWDiv & HWDivThumb) && isThumb()) || +      ((HWDiv & HWDivARM) && !isThumb())) { +    Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); +    Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1"); +  } + +  // Note, this is always on in gcc, even though it doesn't make sense. +  Builder.defineMacro("__APCS_32__"); + +  if (FPUModeIsVFP((FPUMode)FPU)) { +    Builder.defineMacro("__VFP_FP__"); +    if (FPU & VFP2FPU) +      Builder.defineMacro("__ARM_VFPV2__"); +    if (FPU & VFP3FPU) +      Builder.defineMacro("__ARM_VFPV3__"); +    if (FPU & VFP4FPU) +      Builder.defineMacro("__ARM_VFPV4__"); +    if (FPU & FPARMV8) +      Builder.defineMacro("__ARM_FPV5__"); +  } + +  // This only gets set when Neon instructions are actually available, unlike +  // the VFP define, hence the soft float and arch check. This is subtly +  // different from gcc, we follow the intent which was that it should be set +  // when Neon instructions are actually available. +  if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) { +    Builder.defineMacro("__ARM_NEON", "1"); +    Builder.defineMacro("__ARM_NEON__"); +    // current AArch32 NEON implementations do not support double-precision +    // floating-point even when it is present in VFP. +    Builder.defineMacro("__ARM_NEON_FP", +                        "0x" + Twine::utohexstr(HW_FP & ~HW_FP_DP)); +  } + +  if (hasMVE()) { +    Builder.defineMacro("__ARM_FEATURE_MVE", hasMVEFloat() ? "3" : "1"); +  } + +  Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", +                      Twine(Opts.WCharSize ? Opts.WCharSize : 4)); + +  Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); + +  // CMSE +  if (ArchVersion == 8 && ArchProfile == llvm::ARM::ProfileKind::M) +    Builder.defineMacro("__ARM_FEATURE_CMSE", Opts.Cmse ? "3" : "1"); + +  if (ArchVersion >= 6 && CPUAttr != "6M" && CPUAttr != "8M_BASE") { +    Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); +    Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); +    Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); +    Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); +  } + +  // ACLE 6.4.7 DSP instructions +  if (DSP) { +    Builder.defineMacro("__ARM_FEATURE_DSP", "1"); +  } + +  // ACLE 6.4.8 Saturation instructions +  bool SAT = false; +  if ((ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6) { +    Builder.defineMacro("__ARM_FEATURE_SAT", "1"); +    SAT = true; +  } + +  // ACLE 6.4.6 Q (saturation) flag +  if (DSP || SAT) +    Builder.defineMacro("__ARM_FEATURE_QBIT", "1"); + +  if (Opts.UnsafeFPMath) +    Builder.defineMacro("__ARM_FP_FAST", "1"); + +  // Armv8.2-A FP16 vector intrinsic +  if ((FPU & NeonFPU) && HasLegalHalfType) +    Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1"); + +  // Armv8.2-A FP16 scalar intrinsics +  if (HasLegalHalfType) +    Builder.defineMacro("__ARM_FEATURE_FP16_SCALAR_ARITHMETIC", "1"); + +  // Armv8.2-A dot product intrinsics +  if (DotProd) +    Builder.defineMacro("__ARM_FEATURE_DOTPROD", "1"); + +  switch (ArchKind) { +  default: +    break; +  case llvm::ARM::ArchKind::ARMV8_1A: +    getTargetDefinesARMV81A(Opts, Builder); +    break; +  case llvm::ARM::ArchKind::ARMV8_2A: +    getTargetDefinesARMV82A(Opts, Builder); +    break; +  } +} + +const Builtin::Info ARMTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS)                                               \ +  {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER)                                    \ +  {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsNEON.def" + +#define BUILTIN(ID, TYPE, ATTRS)                                               \ +  {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANG)                                     \ +  {#ID, TYPE, ATTRS, nullptr, LANG, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER)                                    \ +  {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE)         \ +  {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE}, +#include "clang/Basic/BuiltinsARM.def" +}; + +ArrayRef<Builtin::Info> ARMTargetInfo::getTargetBuiltins() const { +  return llvm::makeArrayRef(BuiltinInfo, clang::ARM::LastTSBuiltin - +                                             Builtin::FirstTSBuiltin); +} + +bool ARMTargetInfo::isCLZForZeroUndef() const { return false; } +TargetInfo::BuiltinVaListKind ARMTargetInfo::getBuiltinVaListKind() const { +  return IsAAPCS +             ? AAPCSABIBuiltinVaList +             : (getTriple().isWatchABI() ? TargetInfo::CharPtrBuiltinVaList +                                         : TargetInfo::VoidPtrBuiltinVaList); +} + +const char *const ARMTargetInfo::GCCRegNames[] = { +    // Integer registers +    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", +    "r12", "sp", "lr", "pc", + +    // Float registers +    "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", +    "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", +    "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + +    // Double registers +    "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", +    "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", +    "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", + +    // Quad registers +    "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11", +    "q12", "q13", "q14", "q15"}; + +ArrayRef<const char *> ARMTargetInfo::getGCCRegNames() const { +  return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { +    {{"a1"}, "r0"},  {{"a2"}, "r1"},        {{"a3"}, "r2"},  {{"a4"}, "r3"}, +    {{"v1"}, "r4"},  {{"v2"}, "r5"},        {{"v3"}, "r6"},  {{"v4"}, "r7"}, +    {{"v5"}, "r8"},  {{"v6", "rfp"}, "r9"}, {{"sl"}, "r10"}, {{"fp"}, "r11"}, +    {{"ip"}, "r12"}, {{"r13"}, "sp"},       {{"r14"}, "lr"}, {{"r15"}, "pc"}, +    // The S, D and Q registers overlap, but aren't really aliases; we +    // don't want to substitute one of these for a different-sized one. +}; + +ArrayRef<TargetInfo::GCCRegAlias> ARMTargetInfo::getGCCRegAliases() const { +  return llvm::makeArrayRef(GCCRegAliases); +} + +bool ARMTargetInfo::validateAsmConstraint( +    const char *&Name, TargetInfo::ConstraintInfo &Info) const { +  switch (*Name) { +  default: +    break; +  case 'l': // r0-r7 if thumb, r0-r15 if ARM +    Info.setAllowsRegister(); +    return true; +  case 'h': // r8-r15, thumb only +    if (isThumb()) { +      Info.setAllowsRegister(); +      return true; +    } +    break; +  case 's': // An integer constant, but allowing only relocatable values. +    return true; +  case 't': // s0-s31, d0-d31, or q0-q15 +  case 'w': // s0-s15, d0-d7, or q0-q3 +  case 'x': // s0-s31, d0-d15, or q0-q7 +    Info.setAllowsRegister(); +    return true; +  case 'j': // An immediate integer between 0 and 65535 (valid for MOVW) +    // only available in ARMv6T2 and above +    if (CPUAttr.equals("6T2") || ArchVersion >= 7) { +      Info.setRequiresImmediate(0, 65535); +      return true; +    } +    break; +  case 'I': +    if (isThumb()) { +      if (!supportsThumb2()) +        Info.setRequiresImmediate(0, 255); +      else +        // FIXME: should check if immediate value would be valid for a Thumb2 +        // data-processing instruction +        Info.setRequiresImmediate(); +    } else +      // FIXME: should check if immediate value would be valid for an ARM +      // data-processing instruction +      Info.setRequiresImmediate(); +    return true; +  case 'J': +    if (isThumb() && !supportsThumb2()) +      Info.setRequiresImmediate(-255, -1); +    else +      Info.setRequiresImmediate(-4095, 4095); +    return true; +  case 'K': +    if (isThumb()) { +      if (!supportsThumb2()) +        // FIXME: should check if immediate value can be obtained from shifting +        // a value between 0 and 255 left by any amount +        Info.setRequiresImmediate(); +      else +        // FIXME: should check if immediate value would be valid for a Thumb2 +        // data-processing instruction when inverted +        Info.setRequiresImmediate(); +    } else +      // FIXME: should check if immediate value would be valid for an ARM +      // data-processing instruction when inverted +      Info.setRequiresImmediate(); +    return true; +  case 'L': +    if (isThumb()) { +      if (!supportsThumb2()) +        Info.setRequiresImmediate(-7, 7); +      else +        // FIXME: should check if immediate value would be valid for a Thumb2 +        // data-processing instruction when negated +        Info.setRequiresImmediate(); +    } else +      // FIXME: should check if immediate value  would be valid for an ARM +      // data-processing instruction when negated +      Info.setRequiresImmediate(); +    return true; +  case 'M': +    if (isThumb() && !supportsThumb2()) +      // FIXME: should check if immediate value is a multiple of 4 between 0 and +      // 1020 +      Info.setRequiresImmediate(); +    else +      // FIXME: should check if immediate value is a power of two or a integer +      // between 0 and 32 +      Info.setRequiresImmediate(); +    return true; +  case 'N': +    // Thumb1 only +    if (isThumb() && !supportsThumb2()) { +      Info.setRequiresImmediate(0, 31); +      return true; +    } +    break; +  case 'O': +    // Thumb1 only +    if (isThumb() && !supportsThumb2()) { +      // FIXME: should check if immediate value is a multiple of 4 between -508 +      // and 508 +      Info.setRequiresImmediate(); +      return true; +    } +    break; +  case 'Q': // A memory address that is a single base register. +    Info.setAllowsMemory(); +    return true; +  case 'T': +    switch (Name[1]) { +    default: +      break; +    case 'e': // Even general-purpose register +    case 'o': // Odd general-purpose register +      Info.setAllowsRegister(); +      Name++; +      return true; +    } +    break; +  case 'U': // a memory reference... +    switch (Name[1]) { +    case 'q': // ...ARMV4 ldrsb +    case 'v': // ...VFP load/store (reg+constant offset) +    case 'y': // ...iWMMXt load/store +    case 't': // address valid for load/store opaque types wider +              // than 128-bits +    case 'n': // valid address for Neon doubleword vector load/store +    case 'm': // valid address for Neon element and structure load/store +    case 's': // valid address for non-offset loads/stores of quad-word +              // values in four ARM registers +      Info.setAllowsMemory(); +      Name++; +      return true; +    } +    break; +  } +  return false; +} + +std::string ARMTargetInfo::convertConstraint(const char *&Constraint) const { +  std::string R; +  switch (*Constraint) { +  case 'U': // Two-character constraint; add "^" hint for later parsing. +  case 'T': +    R = std::string("^") + std::string(Constraint, 2); +    Constraint++; +    break; +  case 'p': // 'p' should be translated to 'r' by default. +    R = std::string("r"); +    break; +  default: +    return std::string(1, *Constraint); +  } +  return R; +} + +bool ARMTargetInfo::validateConstraintModifier( +    StringRef Constraint, char Modifier, unsigned Size, +    std::string &SuggestedModifier) const { +  bool isOutput = (Constraint[0] == '='); +  bool isInOut = (Constraint[0] == '+'); + +  // Strip off constraint modifiers. +  while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') +    Constraint = Constraint.substr(1); + +  switch (Constraint[0]) { +  default: +    break; +  case 'r': { +    switch (Modifier) { +    default: +      return (isInOut || isOutput || Size <= 64); +    case 'q': +      // A register of size 32 cannot fit a vector type. +      return false; +    } +  } +  } + +  return true; +} +const char *ARMTargetInfo::getClobbers() const { +  // FIXME: Is this really right? +  return ""; +} + +TargetInfo::CallingConvCheckResult +ARMTargetInfo::checkCallingConvention(CallingConv CC) const { +  switch (CC) { +  case CC_AAPCS: +  case CC_AAPCS_VFP: +  case CC_Swift: +  case CC_OpenCLKernel: +    return CCCR_OK; +  default: +    return CCCR_Warning; +  } +} + +int ARMTargetInfo::getEHDataRegisterNumber(unsigned RegNo) const { +  if (RegNo == 0) +    return 0; +  if (RegNo == 1) +    return 1; +  return -1; +} + +bool ARMTargetInfo::hasSjLjLowering() const { return true; } + +ARMleTargetInfo::ARMleTargetInfo(const llvm::Triple &Triple, +                                 const TargetOptions &Opts) +    : ARMTargetInfo(Triple, Opts) {} + +void ARMleTargetInfo::getTargetDefines(const LangOptions &Opts, +                                       MacroBuilder &Builder) const { +  Builder.defineMacro("__ARMEL__"); +  ARMTargetInfo::getTargetDefines(Opts, Builder); +} + +ARMbeTargetInfo::ARMbeTargetInfo(const llvm::Triple &Triple, +                                 const TargetOptions &Opts) +    : ARMTargetInfo(Triple, Opts) {} + +void ARMbeTargetInfo::getTargetDefines(const LangOptions &Opts, +                                       MacroBuilder &Builder) const { +  Builder.defineMacro("__ARMEB__"); +  Builder.defineMacro("__ARM_BIG_ENDIAN"); +  ARMTargetInfo::getTargetDefines(Opts, Builder); +} + +WindowsARMTargetInfo::WindowsARMTargetInfo(const llvm::Triple &Triple, +                                           const TargetOptions &Opts) +    : WindowsTargetInfo<ARMleTargetInfo>(Triple, Opts), Triple(Triple) { +} + +void WindowsARMTargetInfo::getVisualStudioDefines(const LangOptions &Opts, +                                                  MacroBuilder &Builder) const { +  // FIXME: this is invalid for WindowsCE +  Builder.defineMacro("_M_ARM_NT", "1"); +  Builder.defineMacro("_M_ARMT", "_M_ARM"); +  Builder.defineMacro("_M_THUMB", "_M_ARM"); + +  assert((Triple.getArch() == llvm::Triple::arm || +          Triple.getArch() == llvm::Triple::thumb) && +         "invalid architecture for Windows ARM target info"); +  unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; +  Builder.defineMacro("_M_ARM", Triple.getArchName().substr(Offset)); + +  // TODO map the complete set of values +  // 31: VFPv3 40: VFPv4 +  Builder.defineMacro("_M_ARM_FP", "31"); +} + +TargetInfo::BuiltinVaListKind +WindowsARMTargetInfo::getBuiltinVaListKind() const { +  return TargetInfo::CharPtrBuiltinVaList; +} + +TargetInfo::CallingConvCheckResult +WindowsARMTargetInfo::checkCallingConvention(CallingConv CC) const { +  switch (CC) { +  case CC_X86StdCall: +  case CC_X86ThisCall: +  case CC_X86FastCall: +  case CC_X86VectorCall: +    return CCCR_Ignore; +  case CC_C: +  case CC_OpenCLKernel: +  case CC_PreserveMost: +  case CC_PreserveAll: +  case CC_Swift: +    return CCCR_OK; +  default: +    return CCCR_Warning; +  } +} + +// Windows ARM + Itanium C++ ABI Target +ItaniumWindowsARMleTargetInfo::ItaniumWindowsARMleTargetInfo( +    const llvm::Triple &Triple, const TargetOptions &Opts) +    : WindowsARMTargetInfo(Triple, Opts) { +  TheCXXABI.set(TargetCXXABI::GenericARM); +} + +void ItaniumWindowsARMleTargetInfo::getTargetDefines( +    const LangOptions &Opts, MacroBuilder &Builder) const { +  WindowsARMTargetInfo::getTargetDefines(Opts, Builder); + +  if (Opts.MSVCCompat) +    WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); +} + +// Windows ARM, MS (C++) ABI +MicrosoftARMleTargetInfo::MicrosoftARMleTargetInfo(const llvm::Triple &Triple, +                                                   const TargetOptions &Opts) +    : WindowsARMTargetInfo(Triple, Opts) { +  TheCXXABI.set(TargetCXXABI::Microsoft); +} + +void MicrosoftARMleTargetInfo::getTargetDefines(const LangOptions &Opts, +                                                MacroBuilder &Builder) const { +  WindowsARMTargetInfo::getTargetDefines(Opts, Builder); +  WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); +} + +MinGWARMTargetInfo::MinGWARMTargetInfo(const llvm::Triple &Triple, +                                       const TargetOptions &Opts) +    : WindowsARMTargetInfo(Triple, Opts) { +  TheCXXABI.set(TargetCXXABI::GenericARM); +} + +void MinGWARMTargetInfo::getTargetDefines(const LangOptions &Opts, +                                          MacroBuilder &Builder) const { +  WindowsARMTargetInfo::getTargetDefines(Opts, Builder); +  Builder.defineMacro("_ARM_"); +} + +CygwinARMTargetInfo::CygwinARMTargetInfo(const llvm::Triple &Triple, +                                         const TargetOptions &Opts) +    : ARMleTargetInfo(Triple, Opts) { +  this->WCharType = TargetInfo::UnsignedShort; +  TLSSupported = false; +  DoubleAlign = LongLongAlign = 64; +  resetDataLayout("e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"); +} + +void CygwinARMTargetInfo::getTargetDefines(const LangOptions &Opts, +                                           MacroBuilder &Builder) const { +  ARMleTargetInfo::getTargetDefines(Opts, Builder); +  Builder.defineMacro("_ARM_"); +  Builder.defineMacro("__CYGWIN__"); +  Builder.defineMacro("__CYGWIN32__"); +  DefineStd(Builder, "unix", Opts); +  if (Opts.CPlusPlus) +    Builder.defineMacro("_GNU_SOURCE"); +} + +DarwinARMTargetInfo::DarwinARMTargetInfo(const llvm::Triple &Triple, +                                         const TargetOptions &Opts) +    : DarwinTargetInfo<ARMleTargetInfo>(Triple, Opts) { +  HasAlignMac68kSupport = true; +  // iOS always has 64-bit atomic instructions. +  // FIXME: This should be based off of the target features in +  // ARMleTargetInfo. +  MaxAtomicInlineWidth = 64; + +  if (Triple.isWatchABI()) { +    // Darwin on iOS uses a variant of the ARM C++ ABI. +    TheCXXABI.set(TargetCXXABI::WatchOS); + +    // BOOL should be a real boolean on the new ABI +    UseSignedCharForObjCBool = false; +  } else +    TheCXXABI.set(TargetCXXABI::iOS); +} + +void DarwinARMTargetInfo::getOSDefines(const LangOptions &Opts, +                                       const llvm::Triple &Triple, +                                       MacroBuilder &Builder) const { +  getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); +} + +RenderScript32TargetInfo::RenderScript32TargetInfo(const llvm::Triple &Triple, +                                                   const TargetOptions &Opts) +    : ARMleTargetInfo(llvm::Triple("armv7", Triple.getVendorName(), +                                   Triple.getOSName(), +                                   Triple.getEnvironmentName()), +                      Opts) { +  IsRenderScriptTarget = true; +  LongWidth = LongAlign = 64; +} + +void RenderScript32TargetInfo::getTargetDefines(const LangOptions &Opts, +                                                MacroBuilder &Builder) const { +  Builder.defineMacro("__RENDERSCRIPT__"); +  ARMleTargetInfo::getTargetDefines(Opts, Builder); +} | 
