#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;
BFloat16Width = BFloat16Align = 16;
BFloat16Format = &llvm::APFloat::BFloat();
const llvm::Triple &T = getTriple();
bool IsNetBSD = T.isOSNetBSD();
bool IsOpenBSD = T.isOSOpenBSD();
if (!T.isOSWindows() && !IsNetBSD && !IsOpenBSD)
WCharType = UnsignedInt;
UseBitFieldTypeAlignment = true;
ZeroLengthBitfieldBoundary = 0;
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");
}
}
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;
BFloat16Width = BFloat16Align = 16;
BFloat16Format = &llvm::APFloat::BFloat();
WCharType = SignedInt;
UseBitFieldTypeAlignment = false;
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");
}
void ARMTargetInfo::setArchInfo() {
StringRef ArchName = getTriple().getArchName();
ArchISA = llvm::ARM::parseArchISA(ArchName);
CPU = std::string(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;
ArchKind = Kind;
SubArch = llvm::ARM::getSubArch(ArchKind);
ArchProfile = llvm::ARM::parseArchProfile(SubArch);
ArchVersion = llvm::ARM::parseArchVersion(SubArch);
CPUAttr = getCPUAttr();
CPUProfile = getCPUProfile();
}
void ARMTargetInfo::setAtomic() {
bool ShouldUseInlineAtomic =
(ArchISA == llvm::ARM::ISAKind::ARM && ArchVersion >= 6) ||
(ArchISA == llvm::ARM::ISAKind::THUMB && ArchVersion >= 7);
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::hasCDE() const { return getARMCDECoprocMask() != 0; }
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 {
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::ARMV8_6A:
return "8_6A";
case llvm::ARM::ArchKind::ARMV8_7A:
return "8_7A";
case llvm::ARM::ArchKind::ARMV8_8A:
return "8_8A";
case llvm::ARM::ArchKind::ARMV9A:
return "9A";
case llvm::ARM::ArchKind::ARMV9_1A:
return "9_1A";
case llvm::ARM::ArchKind::ARMV9_2A:
return "9_2A";
case llvm::ARM::ArchKind::ARMV9_3A:
return "9_3A";
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();
PtrDiffType = IntPtrType =
(Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD ||
IsNetBSD)
? SignedLong
: SignedInt;
SizeType = (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD ||
IsNetBSD)
? UnsignedLong
: UnsignedInt;
if ((Triple.isOSDarwin() || Triple.isOSBinFormatMachO()) &&
!Triple.isWatchABI())
PtrDiffType = SignedInt;
setArchInfo();
NoAsmVariants = true;
if (Triple.isOSBinFormatMachO()) {
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()) {
setABI("aapcs");
} else {
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;
}
}
TheCXXABI.set(TargetCXXABI::GenericARM);
setAtomic();
if (IsAAPCS && !Triple.isAndroid())
DefaultAlignForAttributeAligned = MaxVectorAlign = 64;
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;
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;
}
bool ARMTargetInfo::isBranchProtectionSupportedArch(StringRef Arch) const {
llvm::ARM::ArchKind CPUArch = llvm::ARM::parseCPUArch(Arch);
if (CPUArch == llvm::ARM::ArchKind::INVALID)
CPUArch = llvm::ARM::parseArch(getTriple().getArchName());
if (CPUArch == llvm::ARM::ArchKind::INVALID)
return false;
StringRef ArchFeature = llvm::ARM::getArchName(CPUArch);
auto a =
llvm::Triple(ArchFeature, getTriple().getVendorName(),
getTriple().getOSName(), getTriple().getEnvironmentName());
StringRef SubArch = llvm::ARM::getSubArch(CPUArch);
llvm::ARM::ProfileKind Profile = llvm::ARM::parseArchProfile(SubArch);
return a.isArmT32() && (Profile == llvm::ARM::ProfileKind::M);
}
bool ARMTargetInfo::validateBranchProtection(StringRef Spec, StringRef Arch,
BranchProtectionInfo &BPI,
StringRef &Err) const {
llvm::ARM::ParsedBranchProtection PBP;
if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err))
return false;
if (!isBranchProtectionSupportedArch(Arch))
return false;
BPI.SignReturnAddr =
llvm::StringSwitch<LangOptions::SignReturnAddressScopeKind>(PBP.Scope)
.Case("non-leaf", LangOptions::SignReturnAddressScopeKind::NonLeaf)
.Case("all", LangOptions::SignReturnAddressScopeKind::All)
.Default(LangOptions::SignReturnAddressScopeKind::None);
if (PBP.Key == "b_key")
Err = "b-key";
BPI.SignKey = LangOptions::SignReturnAddressKeyKind::AKey;
BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement;
return true;
}
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());
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);
}
unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch);
llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures);
uint64_t Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch);
llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures);
for (auto Feature : TargetFeatures)
if (Feature[0] == '+')
Features[Feature.drop_front(1)] = true;
if (isThumb())
Features["thumb-mode"] = true;
else
Features["thumb-mode"] = false;
std::vector<std::string> UpdatedFeaturesVec;
for (const auto &Feature : FeaturesVec) {
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;
SHA2 = 0;
AES = 0;
DSP = 0;
Unaligned = 1;
SoftFloat = false;
HWDiv = 0;
DotProd = 0;
HasMatMul = 0;
HasPAC = 0;
HasBTI = 0;
HasFloat16 = true;
ARMCDECoprocMask = 0;
HasBFloat16 = false;
FPRegsDisabled = false;
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 == "+sha2") {
SHA2 = 1;
} else if (Feature == "+aes") {
AES = 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") {
MVE |= MVE_INT;
} else if (Feature == "+mve.fp") {
HasLegalHalfType = true;
FPU |= FPARMV8;
MVE |= MVE_INT | MVE_FP;
HW_FP |= HW_FP_SP | HW_FP_HP;
} else if (Feature == "+i8mm") {
HasMatMul = 1;
} else if (Feature.size() == strlen("+cdecp0") && Feature >= "+cdecp0" &&
Feature <= "+cdecp7") {
unsigned Coproc = Feature.back() - '0';
ARMCDECoprocMask |= (1U << Coproc);
} else if (Feature == "+bf16") {
HasBFloat16 = true;
} else if (Feature == "-fpregs") {
FPRegsDisabled = true;
} else if (Feature == "+pacbti") {
HasPAC = 1;
HasBTI = 1;
}
}
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:
case 9:
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::hasBFloat16Type() const {
return HasBFloat16 && !SoftFloat;
}
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 {
getTargetDefinesARMV81A(Opts, Builder);
}
void ARMTargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__ARM_FEATURE_COMPLEX", "1");
getTargetDefinesARMV82A(Opts, Builder);
}
void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__arm");
Builder.defineMacro("__arm__");
if (getTriple().getOS() == llvm::Triple::UnknownOS &&
(getTriple().getEnvironment() == llvm::Triple::EABI ||
getTriple().getEnvironment() == llvm::Triple::EABIHF))
Builder.defineMacro("__ELF__");
Builder.defineMacro("__REGISTER_PREFIX__", "");
if (getTriple().isWatchABI())
Builder.defineMacro("__ARM_ARCH_7K__", "2");
if (!CPUAttr.empty())
Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__");
Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion));
if (ArchVersion >= 8) {
if (SHA2 && AES)
Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1");
if (SHA2)
Builder.defineMacro("__ARM_FEATURE_SHA2", "1");
if (AES)
Builder.defineMacro("__ARM_FEATURE_AES", "1");
if (CRC)
Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1");
Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1");
}
if (CPUProfile.empty() || ArchProfile != llvm::ARM::ProfileKind::M)
Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1");
if (supportsThumb2())
Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2");
else if (supportsThumb())
Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1");
Builder.defineMacro("__ARM_32BIT_STATE", "1");
if (!CPUProfile.empty())
Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'");
if (Unaligned)
Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
if (LDREX)
Builder.defineMacro("__ARM_FEATURE_LDREX", "0x" + Twine::utohexstr(LDREX));
if (ArchVersion == 5 || (ArchVersion == 6 && CPUProfile != "M") ||
ArchVersion > 6)
Builder.defineMacro("__ARM_FEATURE_CLZ", "1");
if (HW_FP)
Builder.defineMacro("__ARM_FP", "0x" + Twine::utohexstr(HW_FP));
Builder.defineMacro("__ARM_ACLE", "200");
Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1");
Builder.defineMacro("__ARM_FP16_ARGS", "1");
if (ArchVersion >= 7 && (FPU & VFP4FPU))
Builder.defineMacro("__ARM_FEATURE_FMA", "1");
if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows())
Builder.defineMacro("__THUMB_INTERWORK__");
if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") {
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__");
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__");
}
if ((CPUProfile != "M" && ArchVersion >= 6) || (CPUProfile == "M" && DSP))
Builder.defineMacro("__ARM_FEATURE_SIMD32", "1");
if (((HWDiv & HWDivThumb) && isThumb()) ||
((HWDiv & HWDivARM) && !isThumb())) {
Builder.defineMacro("__ARM_FEATURE_IDIV", "1");
Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1");
}
Builder.defineMacro("__APCS_32__");
Builder.defineMacro("__VFP_FP__");
if (FPUModeIsVFP((FPUMode)FPU)) {
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__");
}
if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) {
Builder.defineMacro("__ARM_NEON", "1");
Builder.defineMacro("__ARM_NEON__");
Builder.defineMacro("__ARM_NEON_FP",
"0x" + Twine::utohexstr(HW_FP & ~HW_FP_DP));
}
if (hasMVE()) {
Builder.defineMacro("__ARM_FEATURE_MVE", hasMVEFloat() ? "3" : "1");
}
if (hasCDE()) {
Builder.defineMacro("__ARM_FEATURE_CDE", "1");
Builder.defineMacro("__ARM_FEATURE_CDE_COPROC",
"0x" + Twine::utohexstr(getARMCDECoprocMask()));
}
Builder.defineMacro("__ARM_SIZEOF_WCHAR_T",
Twine(Opts.WCharSize ? Opts.WCharSize : 4));
Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4");
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");
}
if (DSP) {
Builder.defineMacro("__ARM_FEATURE_DSP", "1");
}
bool SAT = false;
if ((ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6) {
Builder.defineMacro("__ARM_FEATURE_SAT", "1");
SAT = true;
}
if (DSP || SAT)
Builder.defineMacro("__ARM_FEATURE_QBIT", "1");
if (Opts.UnsafeFPMath)
Builder.defineMacro("__ARM_FP_FAST", "1");
if ((FPU & NeonFPU) && HasLegalHalfType)
Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1");
if (HasLegalHalfType)
Builder.defineMacro("__ARM_FEATURE_FP16_SCALAR_ARITHMETIC", "1");
if (DotProd)
Builder.defineMacro("__ARM_FEATURE_DOTPROD", "1");
if (HasMatMul)
Builder.defineMacro("__ARM_FEATURE_MATMUL_INT8", "1");
if (HasPAC)
Builder.defineMacro("__ARM_FEATURE_PAUTH", "1");
if (HasBTI)
Builder.defineMacro("__ARM_FEATURE_BTI", "1");
if (HasBFloat16) {
Builder.defineMacro("__ARM_FEATURE_BF16", "1");
Builder.defineMacro("__ARM_FEATURE_BF16_VECTOR_ARITHMETIC", "1");
Builder.defineMacro("__ARM_BF16_FORMAT_ALTERNATIVE", "1");
}
if (Opts.BranchTargetEnforcement)
Builder.defineMacro("__ARM_FEATURE_BTI_DEFAULT", "1");
if (Opts.hasSignReturnAddress()) {
unsigned Value = 1;
if (Opts.isSignReturnAddressScopeAll())
Value |= 1 << 2;
Builder.defineMacro("__ARM_FEATURE_PAC_DEFAULT", Twine(Value));
}
switch (ArchKind) {
default:
break;
case llvm::ARM::ArchKind::ARMV8_1A:
getTargetDefinesARMV81A(Opts, Builder);
break;
case llvm::ARM::ArchKind::ARMV8_2A:
getTargetDefinesARMV82A(Opts, Builder);
break;
case llvm::ARM::ArchKind::ARMV8_3A:
case llvm::ARM::ArchKind::ARMV8_4A:
case llvm::ARM::ArchKind::ARMV8_5A:
case llvm::ARM::ArchKind::ARMV8_6A:
case llvm::ARM::ArchKind::ARMV8_7A:
case llvm::ARM::ArchKind::ARMV8_8A:
case llvm::ARM::ArchKind::ARMV9A:
case llvm::ARM::ArchKind::ARMV9_1A:
case llvm::ARM::ArchKind::ARMV9_2A:
case llvm::ARM::ArchKind::ARMV9_3A:
getTargetDefinesARMV83A(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[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
"r12", "sp", "lr", "pc",
"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",
"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",
"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"},
};
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': Info.setAllowsRegister();
return true;
case 'h': if (isThumb()) {
Info.setAllowsRegister();
return true;
}
break;
case 's': return true;
case 't': case 'w': case 'x': if (FPRegsDisabled)
return false;
Info.setAllowsRegister();
return true;
case 'j': if (CPUAttr.equals("6T2") || ArchVersion >= 7) {
Info.setRequiresImmediate(0, 65535);
return true;
}
break;
case 'I':
if (isThumb()) {
if (!supportsThumb2())
Info.setRequiresImmediate(0, 255);
else
Info.setRequiresImmediate();
} else
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())
Info.setRequiresImmediate();
else
Info.setRequiresImmediate();
} else
Info.setRequiresImmediate();
return true;
case 'L':
if (isThumb()) {
if (!supportsThumb2())
Info.setRequiresImmediate(-7, 7);
else
Info.setRequiresImmediate();
} else
Info.setRequiresImmediate();
return true;
case 'M':
if (isThumb() && !supportsThumb2())
Info.setRequiresImmediate();
else
Info.setRequiresImmediate();
return true;
case 'N':
if (isThumb() && !supportsThumb2()) {
Info.setRequiresImmediate(0, 31);
return true;
}
break;
case 'O':
if (isThumb() && !supportsThumb2()) {
Info.setRequiresImmediate();
return true;
}
break;
case 'Q': Info.setAllowsMemory();
return true;
case 'T':
switch (Name[1]) {
default:
break;
case 'e': case 'o': Info.setAllowsRegister();
Name++;
return true;
}
break;
case 'U': switch (Name[1]) {
case 'q': case 'v': case 'y': case 't': case 'n': case 'm': case 's': Info.setAllowsMemory();
Name++;
return true;
}
break;
}
return false;
}
std::string ARMTargetInfo::convertConstraint(const char *&Constraint) const {
std::string R;
switch (*Constraint) {
case 'U': case 'T':
R = std::string("^") + std::string(Constraint, 2);
Constraint++;
break;
case 'p': 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] == '+');
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':
return false;
}
}
}
return true;
}
const char *ARMTargetInfo::getClobbers() const {
return "";
}
TargetInfo::CallingConvCheckResult
ARMTargetInfo::checkCallingConvention(CallingConv CC) const {
switch (CC) {
case CC_AAPCS:
case CC_AAPCS_VFP:
case CC_Swift:
case CC_SwiftAsync:
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 {
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));
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:
case CC_SwiftAsync:
return CCCR_OK;
default:
return CCCR_Warning;
}
}
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);
}
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;
MaxAtomicInlineWidth = 64;
if (Triple.isWatchABI()) {
TheCXXABI.set(TargetCXXABI::WatchOS);
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);
}