|  | //===--- 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); | 
|  | } |