summaryrefslogtreecommitdiffstats
path: root/clang/lib/Basic/Targets/ARM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Basic/Targets/ARM.cpp')
-rw-r--r--clang/lib/Basic/Targets/ARM.cpp889
1 files changed, 753 insertions, 136 deletions
diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp
index ede1eead659..2f828b7f1de 100644
--- a/clang/lib/Basic/Targets/ARM.cpp
+++ b/clang/lib/Basic/Targets/ARM.cpp
@@ -22,72 +22,455 @@
using namespace clang;
using namespace clang::targets;
-bool ARMTargetInfo::setFPMath(StringRef Name) {
- if (Name == "neon") {
- FPMath = FP_Neon;
+void ARMTargetInfo::setABIAAPCS() {
+ IsAAPCS = true;
+
+ DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
+ const llvm::Triple &T = getTriple();
+
+ // size_t is unsigned long on MachO-derived environments, NetBSD, and
+ // OpenBSD.
+ if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD ||
+ T.getOS() == llvm::Triple::OpenBSD)
+ SizeType = UnsignedLong;
+ else
+ SizeType = UnsignedInt;
+
+ switch (T.getOS()) {
+ case llvm::Triple::NetBSD:
+ case llvm::Triple::OpenBSD:
+ WCharType = SignedInt;
+ break;
+ case llvm::Triple::Win32:
+ WCharType = UnsignedShort;
+ break;
+ case llvm::Triple::Linux:
+ default:
+ // AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int.
+ WCharType = UnsignedInt;
+ break;
+ }
+
+ 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-i64:64-v128:64:128-a:0:32-n32-S64"
+ : "e-m:o-p:32:32-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"
+ "-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-i64:64-v128:64:128-a:0:32-n32-S128");
+ } else {
+ resetDataLayout(BigEndian
+ ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+ : "e-m:e-p:32:32-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;
+
+ // size_t is unsigned int on FreeBSD.
+ if (T.getOS() == llvm::Triple::FreeBSD)
+ SizeType = UnsignedInt;
+ else
+ SizeType = UnsignedLong;
+
+ // Revert to using SignedInt on apcs-gnu to comply with existing behaviour.
+ 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-i64:64-a:0:32-n32-S128");
+ } else if (T.isOSBinFormatMachO())
+ resetDataLayout(
+ BigEndian
+ ? "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
+ : "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32");
+ else
+ resetDataLayout(
+ BigEndian
+ ? "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
+ : "e-m:e-p:32:32-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);
+ unsigned AK = llvm::ARM::parseArch(ArchName);
+ if (AK != llvm::ARM::AK_INVALID)
+ ArchKind = AK;
+ setArchInfo(ArchKind);
+}
+
+void ARMTargetInfo::setArchInfo(unsigned 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::IK_ARM && ArchVersion >= 6) ||
+ (ArchISA == llvm::ARM::IK_THUMB && ArchVersion >= 7);
+ // Cortex M does not support 8 byte atomics, while general Thumb2 does.
+ if (ArchProfile == llvm::ARM::PK_M) {
+ MaxAtomicPromoteWidth = 32;
+ if (ShouldUseInlineAtomic)
+ MaxAtomicInlineWidth = 32;
+ } else {
+ MaxAtomicPromoteWidth = 64;
+ if (ShouldUseInlineAtomic)
+ MaxAtomicInlineWidth = 64;
+ }
+}
+
+bool ARMTargetInfo::isThumb() const { return (ArchISA == llvm::ARM::IK_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::AK_ARMV6M:
+ return "6M";
+ case llvm::ARM::AK_ARMV7S:
+ return "7S";
+ case llvm::ARM::AK_ARMV7A:
+ return "7A";
+ case llvm::ARM::AK_ARMV7R:
+ return "7R";
+ case llvm::ARM::AK_ARMV7M:
+ return "7M";
+ case llvm::ARM::AK_ARMV7EM:
+ return "7EM";
+ case llvm::ARM::AK_ARMV7VE:
+ return "7VE";
+ case llvm::ARM::AK_ARMV8A:
+ return "8A";
+ case llvm::ARM::AK_ARMV8_1A:
+ return "8_1A";
+ case llvm::ARM::AK_ARMV8_2A:
+ return "8_2A";
+ case llvm::ARM::AK_ARMV8MBaseline:
+ return "8M_BASE";
+ case llvm::ARM::AK_ARMV8MMainline:
+ return "8M_MAIN";
+ case llvm::ARM::AK_ARMV8R:
+ return "8R";
+ }
+}
+
+StringRef ARMTargetInfo::getCPUProfile() const {
+ switch (ArchProfile) {
+ case llvm::ARM::PK_A:
+ return "A";
+ case llvm::ARM::PK_R:
+ return "R";
+ case llvm::ARM::PK_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) {
+
+ switch (getTriple().getOS()) {
+ case llvm::Triple::NetBSD:
+ case llvm::Triple::OpenBSD:
+ PtrDiffType = SignedLong;
+ break;
+ default:
+ PtrDiffType = SignedInt;
+ break;
+ }
+
+ // 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::PK_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 (Triple.getOS() == llvm::Triple::NetBSD)
+ setABI("apcs-gnu");
+ else if (Triple.getOS() == llvm::Triple::OpenBSD)
+ 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)
+ if (IsAAPCS && (Triple.getEnvironment() != llvm::Triple::Android))
+ 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
+ ? "\01__gnu_mcount_nc"
+ : "\01mcount";
+}
+
+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;
- } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" ||
- Name == "vfp4") {
- FPMath = FP_VFP;
+ }
+ if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") {
+ setABIAAPCS();
return true;
}
return false;
}
-const char *const ARMTargetInfo::GCCRegNames[] = {
- // Integer registers
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
- "r12", "sp", "lr", "pc",
+// 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::vector<StringRef> TargetFeatures;
+ unsigned Arch = llvm::ARM::parseArch(getTriple().getArchName());
+
+ // 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(FeaturesVec);
+ for (auto &Feature : UpdatedFeaturesVec) {
+ if (Feature.compare("+arm") == 0)
+ Feature = "-thumb-mode";
+ else if (Feature.compare("+thumb") == 0)
+ Feature = "+thumb-mode";
+ }
- // 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",
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec);
+}
- // 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"
-};
+bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) {
+ FPU = 0;
+ CRC = 0;
+ Crypto = 0;
+ DSP = 0;
+ Unaligned = 1;
+ SoftFloat = SoftFloatABI = false;
+ HWDiv = 0;
-ArrayRef<const char *> ARMTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
-}
+ // This does not diagnose illegal cases like having both
+ // "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp".
+ uint32_t HW_FP_remove = 0;
+ for (const auto &Feature : Features) {
+ if (Feature == "+soft-float") {
+ SoftFloat = true;
+ } else if (Feature == "+soft-float-abi") {
+ SoftFloatABI = true;
+ } else if (Feature == "+vfp2") {
+ FPU |= VFP2FPU;
+ HW_FP |= HW_FP_SP | HW_FP_DP;
+ } else if (Feature == "+vfp3") {
+ FPU |= VFP3FPU;
+ HW_FP |= HW_FP_SP | HW_FP_DP;
+ } else if (Feature == "+vfp4") {
+ FPU |= VFP4FPU;
+ HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP;
+ } else if (Feature == "+fp-armv8") {
+ FPU |= FPARMV8;
+ HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP;
+ } else if (Feature == "+neon") {
+ FPU |= NeonFPU;
+ HW_FP |= HW_FP_SP | HW_FP_DP;
+ } 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 == "+fp-only-sp") {
+ HW_FP_remove |= HW_FP_DP;
+ } else if (Feature == "+strict-align") {
+ Unaligned = 0;
+ } else if (Feature == "+fp16") {
+ HW_FP |= HW_FP_HP;
+ }
+ }
+ HW_FP &= ~HW_FP_remove;
-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.
-};
+ switch (ArchVersion) {
+ case 6:
+ if (ArchProfile == llvm::ARM::PK_M)
+ LDREX = 0;
+ else if (ArchKind == llvm::ARM::AK_ARMV6K)
+ LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B;
+ else
+ LDREX = LDREX_W;
+ break;
+ case 7:
+ if (ArchProfile == llvm::ARM::PK_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;
+ }
-ArrayRef<TargetInfo::GCCRegAlias> ARMTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
-}
+ if (!(FPU & NeonFPU) && FPMath == FP_Neon) {
+ Diags.Report(diag::err_target_unsupported_fpmath) << "neon";
+ return false;
+ }
-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"
+ if (FPMath == FP_Neon)
+ Features.push_back("+neonfp");
+ else if (FPMath == FP_VFP)
+ Features.push_back("-neonfp");
-#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"
-};
+ // Remove front-end specific options which the backend handles differently.
+ auto Feature = std::find(Features.begin(), Features.end(), "+soft-float-abi");
+ if (Feature != Features.end())
+ Features.erase(Feature);
+
+ return true;
+}
bool ARMTargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
@@ -102,6 +485,45 @@ bool ARMTargetInfo::hasFeature(StringRef Feature) const {
.Default(false);
}
+bool ARMTargetInfo::isValidCPUName(StringRef Name) const {
+ return Name == "generic" ||
+ llvm::ARM::parseCPUArch(Name) != llvm::ARM::AK_INVALID;
+}
+
+bool ARMTargetInfo::setCPU(const std::string &Name) {
+ if (Name != "generic")
+ setArchInfo(llvm::ARM::parseCPUArch(Name));
+
+ if (ArchKind == llvm::ARM::AK_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.
@@ -307,107 +729,197 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
}
}
-bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
- DiagnosticsEngine &Diags) {
- FPU = 0;
- CRC = 0;
- Crypto = 0;
- DSP = 0;
- Unaligned = 1;
- SoftFloat = SoftFloatABI = false;
- HWDiv = 0;
+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"
- // This does not diagnose illegal cases like having both
- // "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp".
- uint32_t HW_FP_remove = 0;
- for (const auto &Feature : Features) {
- if (Feature == "+soft-float") {
- SoftFloat = true;
- } else if (Feature == "+soft-float-abi") {
- SoftFloatABI = true;
- } else if (Feature == "+vfp2") {
- FPU |= VFP2FPU;
- HW_FP |= HW_FP_SP | HW_FP_DP;
- } else if (Feature == "+vfp3") {
- FPU |= VFP3FPU;
- HW_FP |= HW_FP_SP | HW_FP_DP;
- } else if (Feature == "+vfp4") {
- FPU |= VFP4FPU;
- HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP;
- } else if (Feature == "+fp-armv8") {
- FPU |= FPARMV8;
- HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP;
- } else if (Feature == "+neon") {
- FPU |= NeonFPU;
- HW_FP |= HW_FP_SP | HW_FP_DP;
- } 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 == "+fp-only-sp") {
- HW_FP_remove |= HW_FP_DP;
- } else if (Feature == "+strict-align") {
- Unaligned = 0;
- } else if (Feature == "+fp16") {
- HW_FP |= HW_FP_HP;
+#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
+ case 'h': // r8-r15
+ case 't': // VFP Floating point register single precision
+ case 'w': // VFP Floating point register double precision
+ Info.setAllowsRegister();
+ return true;
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ // FIXME
+ return true;
+ case 'Q': // A memory address that is a single base register.
+ Info.setAllowsMemory();
+ return true;
+ 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;
}
}
- HW_FP &= ~HW_FP_remove;
+ return false;
+}
- switch (ArchVersion) {
- case 6:
- if (ArchProfile == llvm::ARM::PK_M)
- LDREX = 0;
- else if (ArchKind == llvm::ARM::AK_ARMV6K)
- LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B;
- else
- LDREX = LDREX_W;
+std::string ARMTargetInfo::convertConstraint(const char *&Constraint) const {
+ std::string R;
+ switch (*Constraint) {
+ case 'U': // Two-character constraint; add "^" hint for later parsing.
+ R = std::string("^") + std::string(Constraint, 2);
+ Constraint++;
break;
- case 7:
- if (ArchProfile == llvm::ARM::PK_M)
- LDREX = LDREX_W | LDREX_H | LDREX_B;
- else
- LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B;
+ case 'p': // 'p' should be translated to 'r' by default.
+ R = std::string("r");
break;
- case 8:
- LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B;
+ default:
+ return std::string(1, *Constraint);
}
+ return R;
+}
- if (!(FPU & NeonFPU) && FPMath == FP_Neon) {
- Diags.Report(diag::err_target_unsupported_fpmath) << "neon";
- return false;
- }
+bool ARMTargetInfo::validateConstraintModifier(
+ StringRef Constraint, char Modifier, unsigned Size,
+ std::string &SuggestedModifier) const {
+ bool isOutput = (Constraint[0] == '=');
+ bool isInOut = (Constraint[0] == '+');
- if (FPMath == FP_Neon)
- Features.push_back("+neonfp");
- else if (FPMath == FP_VFP)
- Features.push_back("-neonfp");
+ // Strip off constraint modifiers.
+ while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
+ Constraint = Constraint.substr(1);
- // Remove front-end specific options which the backend handles differently.
- auto Feature = std::find(Features.begin(), Features.end(), "+soft-float-abi");
- if (Feature != Features.end())
- Features.erase(Feature);
+ 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 "";
+}
-void ARMTargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts,
- MacroBuilder &Builder) const {
- Builder.defineMacro("__ARM_FEATURE_QRDMX", "1");
+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__");
@@ -415,6 +927,13 @@ void ARMbeTargetInfo::getTargetDefines(const LangOptions &Opts,
ARMTargetInfo::getTargetDefines(Opts, Builder);
}
+WindowsARMTargetInfo::WindowsARMTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : WindowsTargetInfo<ARMleTargetInfo>(Triple, Opts), Triple(Triple) {
+ WCharType = UnsignedShort;
+ SizeType = UnsignedInt;
+}
+
void WindowsARMTargetInfo::getVisualStudioDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
WindowsTargetInfo<ARMleTargetInfo>::getVisualStudioDefines(Opts, Builder);
@@ -435,6 +954,61 @@ void WindowsARMTargetInfo::getVisualStudioDefines(const LangOptions &Opts,
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:
+ 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);
@@ -444,6 +1018,15 @@ void MinGWARMTargetInfo::getTargetDefines(const LangOptions &Opts,
addMinGWDefines(Opts, Builder);
}
+CygwinARMTargetInfo::CygwinARMTargetInfo(const llvm::Triple &Triple,
+ const TargetOptions &Opts)
+ : ARMleTargetInfo(Triple, Opts) {
+ TLSSupported = false;
+ WCharType = UnsignedShort;
+ DoubleAlign = LongLongAlign = 64;
+ resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64");
+}
+
void CygwinARMTargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
ARMleTargetInfo::getTargetDefines(Opts, Builder);
@@ -455,13 +1038,47 @@ void CygwinARMTargetInfo::getTargetDefines(const LangOptions &Opts,
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);
+
+ // The 32-bit ABI is silent on what ptrdiff_t should be, but given that
+ // size_t is long, it's a bit weird for it to be int.
+ PtrDiffType = SignedLong;
+
+ // 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);
}
-
-ArrayRef<Builtin::Info> ARMTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::ARM::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
-}
OpenPOWER on IntegriCloud