10b57cec5SDimitry Andric //===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements a target parser to recognise AArch64 hardware features
100b57cec5SDimitry Andric // such as FPU/CPU/ARCH and extension names.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "llvm/Support/AArch64TargetParser.h"
150b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
165ffd83dbSDimitry Andric #include "llvm/ADT/Triple.h"
170b57cec5SDimitry Andric #include <cctype>
180b57cec5SDimitry Andric
190b57cec5SDimitry Andric using namespace llvm;
200b57cec5SDimitry Andric
checkArchVersion(llvm::StringRef Arch)210b57cec5SDimitry Andric static unsigned checkArchVersion(llvm::StringRef Arch) {
220b57cec5SDimitry Andric if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1]))
230b57cec5SDimitry Andric return (Arch[1] - 48);
240b57cec5SDimitry Andric return 0;
250b57cec5SDimitry Andric }
260b57cec5SDimitry Andric
getDefaultFPU(StringRef CPU,AArch64::ArchKind AK)270b57cec5SDimitry Andric unsigned AArch64::getDefaultFPU(StringRef CPU, AArch64::ArchKind AK) {
280b57cec5SDimitry Andric if (CPU == "generic")
290b57cec5SDimitry Andric return AArch64ARCHNames[static_cast<unsigned>(AK)].DefaultFPU;
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric return StringSwitch<unsigned>(CPU)
320b57cec5SDimitry Andric #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \
330b57cec5SDimitry Andric .Case(NAME, ARM::DEFAULT_FPU)
340b57cec5SDimitry Andric #include "../../include/llvm/Support/AArch64TargetParser.def"
350b57cec5SDimitry Andric .Default(ARM::FK_INVALID);
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric
getDefaultExtensions(StringRef CPU,AArch64::ArchKind AK)38af732203SDimitry Andric uint64_t AArch64::getDefaultExtensions(StringRef CPU, AArch64::ArchKind AK) {
390b57cec5SDimitry Andric if (CPU == "generic")
400b57cec5SDimitry Andric return AArch64ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions;
410b57cec5SDimitry Andric
42af732203SDimitry Andric return StringSwitch<uint64_t>(CPU)
430b57cec5SDimitry Andric #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \
440b57cec5SDimitry Andric .Case(NAME, AArch64ARCHNames[static_cast<unsigned>(ArchKind::ID)] \
450b57cec5SDimitry Andric .ArchBaseExtensions | \
460b57cec5SDimitry Andric DEFAULT_EXT)
470b57cec5SDimitry Andric #include "../../include/llvm/Support/AArch64TargetParser.def"
480b57cec5SDimitry Andric .Default(AArch64::AEK_INVALID);
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric
getCPUArchKind(StringRef CPU)510b57cec5SDimitry Andric AArch64::ArchKind AArch64::getCPUArchKind(StringRef CPU) {
520b57cec5SDimitry Andric if (CPU == "generic")
530b57cec5SDimitry Andric return ArchKind::ARMV8A;
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric return StringSwitch<AArch64::ArchKind>(CPU)
560b57cec5SDimitry Andric #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) \
570b57cec5SDimitry Andric .Case(NAME, ArchKind::ID)
580b57cec5SDimitry Andric #include "../../include/llvm/Support/AArch64TargetParser.def"
590b57cec5SDimitry Andric .Default(ArchKind::INVALID);
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric
getExtensionFeatures(uint64_t Extensions,std::vector<StringRef> & Features)62af732203SDimitry Andric bool AArch64::getExtensionFeatures(uint64_t Extensions,
630b57cec5SDimitry Andric std::vector<StringRef> &Features) {
640b57cec5SDimitry Andric if (Extensions == AArch64::AEK_INVALID)
650b57cec5SDimitry Andric return false;
660b57cec5SDimitry Andric
670b57cec5SDimitry Andric if (Extensions & AEK_FP)
680b57cec5SDimitry Andric Features.push_back("+fp-armv8");
690b57cec5SDimitry Andric if (Extensions & AEK_SIMD)
700b57cec5SDimitry Andric Features.push_back("+neon");
710b57cec5SDimitry Andric if (Extensions & AEK_CRC)
720b57cec5SDimitry Andric Features.push_back("+crc");
730b57cec5SDimitry Andric if (Extensions & AEK_CRYPTO)
740b57cec5SDimitry Andric Features.push_back("+crypto");
750b57cec5SDimitry Andric if (Extensions & AEK_DOTPROD)
760b57cec5SDimitry Andric Features.push_back("+dotprod");
770b57cec5SDimitry Andric if (Extensions & AEK_FP16FML)
780b57cec5SDimitry Andric Features.push_back("+fp16fml");
790b57cec5SDimitry Andric if (Extensions & AEK_FP16)
800b57cec5SDimitry Andric Features.push_back("+fullfp16");
810b57cec5SDimitry Andric if (Extensions & AEK_PROFILE)
820b57cec5SDimitry Andric Features.push_back("+spe");
830b57cec5SDimitry Andric if (Extensions & AEK_RAS)
840b57cec5SDimitry Andric Features.push_back("+ras");
850b57cec5SDimitry Andric if (Extensions & AEK_LSE)
860b57cec5SDimitry Andric Features.push_back("+lse");
870b57cec5SDimitry Andric if (Extensions & AEK_RDM)
880b57cec5SDimitry Andric Features.push_back("+rdm");
890b57cec5SDimitry Andric if (Extensions & AEK_SVE)
900b57cec5SDimitry Andric Features.push_back("+sve");
910b57cec5SDimitry Andric if (Extensions & AEK_SVE2)
920b57cec5SDimitry Andric Features.push_back("+sve2");
930b57cec5SDimitry Andric if (Extensions & AEK_SVE2AES)
940b57cec5SDimitry Andric Features.push_back("+sve2-aes");
950b57cec5SDimitry Andric if (Extensions & AEK_SVE2SM4)
960b57cec5SDimitry Andric Features.push_back("+sve2-sm4");
970b57cec5SDimitry Andric if (Extensions & AEK_SVE2SHA3)
980b57cec5SDimitry Andric Features.push_back("+sve2-sha3");
990b57cec5SDimitry Andric if (Extensions & AEK_SVE2BITPERM)
1000b57cec5SDimitry Andric Features.push_back("+sve2-bitperm");
1010b57cec5SDimitry Andric if (Extensions & AEK_RCPC)
1020b57cec5SDimitry Andric Features.push_back("+rcpc");
103af732203SDimitry Andric if (Extensions & AEK_BRBE)
104af732203SDimitry Andric Features.push_back("+brbe");
105af732203SDimitry Andric if (Extensions & AEK_PAUTH)
106af732203SDimitry Andric Features.push_back("+pauth");
107af732203SDimitry Andric if (Extensions & AEK_FLAGM)
108af732203SDimitry Andric Features.push_back("+flagm");
109*5f7ddb14SDimitry Andric if (Extensions & AArch64::AEK_SME)
110*5f7ddb14SDimitry Andric Features.push_back("+sme");
111*5f7ddb14SDimitry Andric if (Extensions & AArch64::AEK_SMEF64)
112*5f7ddb14SDimitry Andric Features.push_back("+sme-f64");
113*5f7ddb14SDimitry Andric if (Extensions & AArch64::AEK_SMEI64)
114*5f7ddb14SDimitry Andric Features.push_back("+sme-i64");
1150b57cec5SDimitry Andric
1160b57cec5SDimitry Andric return true;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric
getArchFeatures(AArch64::ArchKind AK,std::vector<StringRef> & Features)1190b57cec5SDimitry Andric bool AArch64::getArchFeatures(AArch64::ArchKind AK,
1200b57cec5SDimitry Andric std::vector<StringRef> &Features) {
1210b57cec5SDimitry Andric if (AK == ArchKind::ARMV8_1A)
1220b57cec5SDimitry Andric Features.push_back("+v8.1a");
1230b57cec5SDimitry Andric if (AK == ArchKind::ARMV8_2A)
1240b57cec5SDimitry Andric Features.push_back("+v8.2a");
1250b57cec5SDimitry Andric if (AK == ArchKind::ARMV8_3A)
1260b57cec5SDimitry Andric Features.push_back("+v8.3a");
1270b57cec5SDimitry Andric if (AK == ArchKind::ARMV8_4A)
1280b57cec5SDimitry Andric Features.push_back("+v8.4a");
1290b57cec5SDimitry Andric if (AK == ArchKind::ARMV8_5A)
1300b57cec5SDimitry Andric Features.push_back("+v8.5a");
1315ffd83dbSDimitry Andric if (AK == AArch64::ArchKind::ARMV8_6A)
1325ffd83dbSDimitry Andric Features.push_back("+v8.6a");
133af732203SDimitry Andric if (AK == AArch64::ArchKind::ARMV8_7A)
134af732203SDimitry Andric Features.push_back("+v8.7a");
135af732203SDimitry Andric if(AK == AArch64::ArchKind::ARMV8R)
136af732203SDimitry Andric Features.push_back("+v8r");
1370b57cec5SDimitry Andric
1380b57cec5SDimitry Andric return AK != ArchKind::INVALID;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
getArchName(AArch64::ArchKind AK)1410b57cec5SDimitry Andric StringRef AArch64::getArchName(AArch64::ArchKind AK) {
1420b57cec5SDimitry Andric return AArch64ARCHNames[static_cast<unsigned>(AK)].getName();
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric
getCPUAttr(AArch64::ArchKind AK)1450b57cec5SDimitry Andric StringRef AArch64::getCPUAttr(AArch64::ArchKind AK) {
1460b57cec5SDimitry Andric return AArch64ARCHNames[static_cast<unsigned>(AK)].getCPUAttr();
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric
getSubArch(AArch64::ArchKind AK)1490b57cec5SDimitry Andric StringRef AArch64::getSubArch(AArch64::ArchKind AK) {
1500b57cec5SDimitry Andric return AArch64ARCHNames[static_cast<unsigned>(AK)].getSubArch();
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric
getArchAttr(AArch64::ArchKind AK)1530b57cec5SDimitry Andric unsigned AArch64::getArchAttr(AArch64::ArchKind AK) {
1540b57cec5SDimitry Andric return AArch64ARCHNames[static_cast<unsigned>(AK)].ArchAttr;
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric
getArchExtName(unsigned ArchExtKind)1570b57cec5SDimitry Andric StringRef AArch64::getArchExtName(unsigned ArchExtKind) {
1580b57cec5SDimitry Andric for (const auto &AE : AArch64ARCHExtNames)
1590b57cec5SDimitry Andric if (ArchExtKind == AE.ID)
1600b57cec5SDimitry Andric return AE.getName();
1610b57cec5SDimitry Andric return StringRef();
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric
getArchExtFeature(StringRef ArchExt)1640b57cec5SDimitry Andric StringRef AArch64::getArchExtFeature(StringRef ArchExt) {
1650b57cec5SDimitry Andric if (ArchExt.startswith("no")) {
1660b57cec5SDimitry Andric StringRef ArchExtBase(ArchExt.substr(2));
1670b57cec5SDimitry Andric for (const auto &AE : AArch64ARCHExtNames) {
1680b57cec5SDimitry Andric if (AE.NegFeature && ArchExtBase == AE.getName())
1690b57cec5SDimitry Andric return StringRef(AE.NegFeature);
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric
1730b57cec5SDimitry Andric for (const auto &AE : AArch64ARCHExtNames)
1740b57cec5SDimitry Andric if (AE.Feature && ArchExt == AE.getName())
1750b57cec5SDimitry Andric return StringRef(AE.Feature);
1760b57cec5SDimitry Andric return StringRef();
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric
getDefaultCPU(StringRef Arch)1790b57cec5SDimitry Andric StringRef AArch64::getDefaultCPU(StringRef Arch) {
1800b57cec5SDimitry Andric ArchKind AK = parseArch(Arch);
1810b57cec5SDimitry Andric if (AK == ArchKind::INVALID)
1820b57cec5SDimitry Andric return StringRef();
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric // Look for multiple AKs to find the default for pair AK+Name.
1850b57cec5SDimitry Andric for (const auto &CPU : AArch64CPUNames)
1860b57cec5SDimitry Andric if (CPU.ArchID == AK && CPU.Default)
1870b57cec5SDimitry Andric return CPU.getName();
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric // If we can't find a default then target the architecture instead
1900b57cec5SDimitry Andric return "generic";
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric
fillValidCPUArchList(SmallVectorImpl<StringRef> & Values)1930b57cec5SDimitry Andric void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
1940b57cec5SDimitry Andric for (const auto &Arch : AArch64CPUNames) {
1950b57cec5SDimitry Andric if (Arch.ArchID != ArchKind::INVALID)
1960b57cec5SDimitry Andric Values.push_back(Arch.getName());
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric
isX18ReservedByDefault(const Triple & TT)2000b57cec5SDimitry Andric bool AArch64::isX18ReservedByDefault(const Triple &TT) {
2010b57cec5SDimitry Andric return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() ||
2020b57cec5SDimitry Andric TT.isOSWindows();
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric
2050b57cec5SDimitry Andric // Allows partial match, ex. "v8a" matches "armv8a".
parseArch(StringRef Arch)2060b57cec5SDimitry Andric AArch64::ArchKind AArch64::parseArch(StringRef Arch) {
2070b57cec5SDimitry Andric Arch = ARM::getCanonicalArchName(Arch);
2080b57cec5SDimitry Andric if (checkArchVersion(Arch) < 8)
2090b57cec5SDimitry Andric return ArchKind::INVALID;
2100b57cec5SDimitry Andric
2110b57cec5SDimitry Andric StringRef Syn = ARM::getArchSynonym(Arch);
2125ffd83dbSDimitry Andric for (const auto &A : AArch64ARCHNames) {
2130b57cec5SDimitry Andric if (A.getName().endswith(Syn))
2140b57cec5SDimitry Andric return A.ID;
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric return ArchKind::INVALID;
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric
parseArchExt(StringRef ArchExt)2190b57cec5SDimitry Andric AArch64::ArchExtKind AArch64::parseArchExt(StringRef ArchExt) {
2205ffd83dbSDimitry Andric for (const auto &A : AArch64ARCHExtNames) {
2210b57cec5SDimitry Andric if (ArchExt == A.getName())
2220b57cec5SDimitry Andric return static_cast<ArchExtKind>(A.ID);
2230b57cec5SDimitry Andric }
2240b57cec5SDimitry Andric return AArch64::AEK_INVALID;
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric
parseCPUArch(StringRef CPU)2270b57cec5SDimitry Andric AArch64::ArchKind AArch64::parseCPUArch(StringRef CPU) {
2285ffd83dbSDimitry Andric for (const auto &C : AArch64CPUNames) {
2290b57cec5SDimitry Andric if (CPU == C.getName())
2300b57cec5SDimitry Andric return C.ArchID;
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric return ArchKind::INVALID;
2330b57cec5SDimitry Andric }
234480093f4SDimitry Andric
235480093f4SDimitry Andric // Parse a branch protection specification, which has the form
236480093f4SDimitry Andric // standard | none | [bti,pac-ret[+b-key,+leaf]*]
237480093f4SDimitry Andric // Returns true on success, with individual elements of the specification
238480093f4SDimitry Andric // returned in `PBP`. Returns false in error, with `Err` containing
239480093f4SDimitry Andric // an erroneous part of the spec.
parseBranchProtection(StringRef Spec,ParsedBranchProtection & PBP,StringRef & Err)240480093f4SDimitry Andric bool AArch64::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP,
241480093f4SDimitry Andric StringRef &Err) {
242480093f4SDimitry Andric PBP = {"none", "a_key", false};
243480093f4SDimitry Andric if (Spec == "none")
244480093f4SDimitry Andric return true; // defaults are ok
245480093f4SDimitry Andric
246480093f4SDimitry Andric if (Spec == "standard") {
247480093f4SDimitry Andric PBP.Scope = "non-leaf";
248480093f4SDimitry Andric PBP.BranchTargetEnforcement = true;
249480093f4SDimitry Andric return true;
250480093f4SDimitry Andric }
251480093f4SDimitry Andric
252480093f4SDimitry Andric SmallVector<StringRef, 4> Opts;
253480093f4SDimitry Andric Spec.split(Opts, "+");
254480093f4SDimitry Andric for (int I = 0, E = Opts.size(); I != E; ++I) {
255480093f4SDimitry Andric StringRef Opt = Opts[I].trim();
256480093f4SDimitry Andric if (Opt == "bti") {
257480093f4SDimitry Andric PBP.BranchTargetEnforcement = true;
258480093f4SDimitry Andric continue;
259480093f4SDimitry Andric }
260480093f4SDimitry Andric if (Opt == "pac-ret") {
261480093f4SDimitry Andric PBP.Scope = "non-leaf";
262480093f4SDimitry Andric for (; I + 1 != E; ++I) {
263480093f4SDimitry Andric StringRef PACOpt = Opts[I + 1].trim();
264480093f4SDimitry Andric if (PACOpt == "leaf")
265480093f4SDimitry Andric PBP.Scope = "all";
266480093f4SDimitry Andric else if (PACOpt == "b-key")
267480093f4SDimitry Andric PBP.Key = "b_key";
268480093f4SDimitry Andric else
269480093f4SDimitry Andric break;
270480093f4SDimitry Andric }
271480093f4SDimitry Andric continue;
272480093f4SDimitry Andric }
273480093f4SDimitry Andric if (Opt == "")
274480093f4SDimitry Andric Err = "<empty>";
275480093f4SDimitry Andric else
276480093f4SDimitry Andric Err = Opt;
277480093f4SDimitry Andric return false;
278480093f4SDimitry Andric }
279480093f4SDimitry Andric
280480093f4SDimitry Andric return true;
281480093f4SDimitry Andric }
282