1e01718cdSDavid Spickett //===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===//
2e01718cdSDavid Spickett //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e01718cdSDavid Spickett //
7e01718cdSDavid Spickett //===----------------------------------------------------------------------===//
8e01718cdSDavid Spickett //
9e01718cdSDavid Spickett // This file implements a target parser to recognise AArch64 hardware features
10e01718cdSDavid Spickett // such as FPU/CPU/ARCH and extension names.
11e01718cdSDavid Spickett //
12e01718cdSDavid Spickett //===----------------------------------------------------------------------===//
13e01718cdSDavid Spickett 
14e01718cdSDavid Spickett #include "llvm/Support/AArch64TargetParser.h"
15e01718cdSDavid Spickett #include "llvm/ADT/StringSwitch.h"
16ffd9cfa7SSimon Pilgrim #include "llvm/ADT/Triple.h"
17e01718cdSDavid Spickett #include <cctype>
18e01718cdSDavid Spickett 
19e01718cdSDavid Spickett using namespace llvm;
20e01718cdSDavid Spickett 
checkArchVersion(llvm::StringRef Arch)21e01718cdSDavid Spickett static unsigned checkArchVersion(llvm::StringRef Arch) {
22e01718cdSDavid Spickett   if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1]))
23e01718cdSDavid Spickett     return (Arch[1] - 48);
24e01718cdSDavid Spickett   return 0;
25e01718cdSDavid Spickett }
26e01718cdSDavid Spickett 
getDefaultFPU(StringRef CPU,AArch64::ArchKind AK)27e01718cdSDavid Spickett unsigned AArch64::getDefaultFPU(StringRef CPU, AArch64::ArchKind AK) {
28e01718cdSDavid Spickett   if (CPU == "generic")
29e01718cdSDavid Spickett     return AArch64ARCHNames[static_cast<unsigned>(AK)].DefaultFPU;
30e01718cdSDavid Spickett 
31e01718cdSDavid Spickett   return StringSwitch<unsigned>(CPU)
32e01718cdSDavid Spickett #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)       \
33e01718cdSDavid Spickett   .Case(NAME, ARM::DEFAULT_FPU)
34e01718cdSDavid Spickett #include "../../include/llvm/Support/AArch64TargetParser.def"
35e01718cdSDavid Spickett   .Default(ARM::FK_INVALID);
36e01718cdSDavid Spickett }
37e01718cdSDavid Spickett 
getDefaultExtensions(StringRef CPU,AArch64::ArchKind AK)38c145a1caSJon Roelofs uint64_t AArch64::getDefaultExtensions(StringRef CPU, AArch64::ArchKind AK) {
39e01718cdSDavid Spickett   if (CPU == "generic")
40e01718cdSDavid Spickett     return AArch64ARCHNames[static_cast<unsigned>(AK)].ArchBaseExtensions;
41e01718cdSDavid Spickett 
42c145a1caSJon Roelofs   return StringSwitch<uint64_t>(CPU)
43e01718cdSDavid Spickett #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)       \
44e01718cdSDavid Spickett   .Case(NAME, AArch64ARCHNames[static_cast<unsigned>(ArchKind::ID)]            \
45e01718cdSDavid Spickett                       .ArchBaseExtensions |                                    \
46e01718cdSDavid Spickett                   DEFAULT_EXT)
47e01718cdSDavid Spickett #include "../../include/llvm/Support/AArch64TargetParser.def"
48e01718cdSDavid Spickett   .Default(AArch64::AEK_INVALID);
49e01718cdSDavid Spickett }
50e01718cdSDavid Spickett 
getCPUArchKind(StringRef CPU)51e01718cdSDavid Spickett AArch64::ArchKind AArch64::getCPUArchKind(StringRef CPU) {
52e01718cdSDavid Spickett   if (CPU == "generic")
53e01718cdSDavid Spickett     return ArchKind::ARMV8A;
54e01718cdSDavid Spickett 
55e01718cdSDavid Spickett   return StringSwitch<AArch64::ArchKind>(CPU)
56e01718cdSDavid Spickett #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT)       \
57e01718cdSDavid Spickett   .Case(NAME, ArchKind::ID)
58e01718cdSDavid Spickett #include "../../include/llvm/Support/AArch64TargetParser.def"
59e01718cdSDavid Spickett   .Default(ArchKind::INVALID);
60e01718cdSDavid Spickett }
61e01718cdSDavid Spickett 
getExtensionFeatures(uint64_t Extensions,std::vector<StringRef> & Features)62c145a1caSJon Roelofs bool AArch64::getExtensionFeatures(uint64_t Extensions,
63e01718cdSDavid Spickett                                    std::vector<StringRef> &Features) {
64e01718cdSDavid Spickett   if (Extensions == AArch64::AEK_INVALID)
65e01718cdSDavid Spickett     return false;
66e01718cdSDavid Spickett 
67*55b6a318SDavid Spickett #define AARCH64_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE)                   \
68*55b6a318SDavid Spickett   if (Extensions & ID) {                                                       \
69*55b6a318SDavid Spickett     const char *feature = FEATURE;                                             \
70*55b6a318SDavid Spickett     /* INVALID and NONE have no feature name. */                               \
71*55b6a318SDavid Spickett     if (feature)                                                               \
72*55b6a318SDavid Spickett       Features.push_back(feature);                                             \
73*55b6a318SDavid Spickett   }
74*55b6a318SDavid Spickett #include "../../include/llvm/Support/AArch64TargetParser.def"
75e01718cdSDavid Spickett 
76e01718cdSDavid Spickett   return true;
77e01718cdSDavid Spickett }
78e01718cdSDavid Spickett 
getArchFeatures(AArch64::ArchKind AK,std::vector<StringRef> & Features)79e01718cdSDavid Spickett bool AArch64::getArchFeatures(AArch64::ArchKind AK,
80e01718cdSDavid Spickett                               std::vector<StringRef> &Features) {
818689f5e6SAlexandros Lamprineas   if (AK == ArchKind::ARMV8A)
828689f5e6SAlexandros Lamprineas     Features.push_back("+v8a");
83e01718cdSDavid Spickett   if (AK == ArchKind::ARMV8_1A)
84e01718cdSDavid Spickett     Features.push_back("+v8.1a");
85e01718cdSDavid Spickett   if (AK == ArchKind::ARMV8_2A)
86e01718cdSDavid Spickett     Features.push_back("+v8.2a");
87e01718cdSDavid Spickett   if (AK == ArchKind::ARMV8_3A)
88e01718cdSDavid Spickett     Features.push_back("+v8.3a");
89e01718cdSDavid Spickett   if (AK == ArchKind::ARMV8_4A)
90e01718cdSDavid Spickett     Features.push_back("+v8.4a");
91e01718cdSDavid Spickett   if (AK == ArchKind::ARMV8_5A)
92e01718cdSDavid Spickett     Features.push_back("+v8.5a");
9371ae267dSTies Stuij   if (AK == AArch64::ArchKind::ARMV8_6A)
9471ae267dSTies Stuij     Features.push_back("+v8.6a");
95c4d851b0SLucas Prates   if (AK == AArch64::ArchKind::ARMV8_7A)
96c4d851b0SLucas Prates     Features.push_back("+v8.7a");
97d50072f7SSimon Tatham   if (AK == AArch64::ArchKind::ARMV8_8A)
98d50072f7SSimon Tatham     Features.push_back("+v8.8a");
993550e242SVictor Campos   if (AK == AArch64::ArchKind::ARMV9A)
1003550e242SVictor Campos     Features.push_back("+v9a");
1013550e242SVictor Campos   if (AK == AArch64::ArchKind::ARMV9_1A)
1023550e242SVictor Campos     Features.push_back("+v9.1a");
1033550e242SVictor Campos   if (AK == AArch64::ArchKind::ARMV9_2A)
1043550e242SVictor Campos     Features.push_back("+v9.2a");
105cd7f621aSLucas Prates   if (AK == AArch64::ArchKind::ARMV9_3A)
106cd7f621aSLucas Prates     Features.push_back("+v9.3a");
1078825fec3SSjoerd Meijer   if(AK == AArch64::ArchKind::ARMV8R)
1088825fec3SSjoerd Meijer     Features.push_back("+v8r");
109e01718cdSDavid Spickett 
110e01718cdSDavid Spickett   return AK != ArchKind::INVALID;
111e01718cdSDavid Spickett }
112e01718cdSDavid Spickett 
getArchName(AArch64::ArchKind AK)113e01718cdSDavid Spickett StringRef AArch64::getArchName(AArch64::ArchKind AK) {
114e01718cdSDavid Spickett   return AArch64ARCHNames[static_cast<unsigned>(AK)].getName();
115e01718cdSDavid Spickett }
116e01718cdSDavid Spickett 
getCPUAttr(AArch64::ArchKind AK)117e01718cdSDavid Spickett StringRef AArch64::getCPUAttr(AArch64::ArchKind AK) {
118e01718cdSDavid Spickett   return AArch64ARCHNames[static_cast<unsigned>(AK)].getCPUAttr();
119e01718cdSDavid Spickett }
120e01718cdSDavid Spickett 
getSubArch(AArch64::ArchKind AK)121e01718cdSDavid Spickett StringRef AArch64::getSubArch(AArch64::ArchKind AK) {
122e01718cdSDavid Spickett   return AArch64ARCHNames[static_cast<unsigned>(AK)].getSubArch();
123e01718cdSDavid Spickett }
124e01718cdSDavid Spickett 
getArchAttr(AArch64::ArchKind AK)125e01718cdSDavid Spickett unsigned AArch64::getArchAttr(AArch64::ArchKind AK) {
126e01718cdSDavid Spickett   return AArch64ARCHNames[static_cast<unsigned>(AK)].ArchAttr;
127e01718cdSDavid Spickett }
128e01718cdSDavid Spickett 
getArchExtName(unsigned ArchExtKind)129e01718cdSDavid Spickett StringRef AArch64::getArchExtName(unsigned ArchExtKind) {
130e01718cdSDavid Spickett   for (const auto &AE : AArch64ARCHExtNames)
131e01718cdSDavid Spickett     if (ArchExtKind == AE.ID)
132e01718cdSDavid Spickett       return AE.getName();
133e01718cdSDavid Spickett   return StringRef();
134e01718cdSDavid Spickett }
135e01718cdSDavid Spickett 
getArchExtFeature(StringRef ArchExt)136e01718cdSDavid Spickett StringRef AArch64::getArchExtFeature(StringRef ArchExt) {
137e01718cdSDavid Spickett   if (ArchExt.startswith("no")) {
138e01718cdSDavid Spickett     StringRef ArchExtBase(ArchExt.substr(2));
139e01718cdSDavid Spickett     for (const auto &AE : AArch64ARCHExtNames) {
140e01718cdSDavid Spickett       if (AE.NegFeature && ArchExtBase == AE.getName())
141e01718cdSDavid Spickett         return StringRef(AE.NegFeature);
142e01718cdSDavid Spickett     }
143e01718cdSDavid Spickett   }
144e01718cdSDavid Spickett 
145e01718cdSDavid Spickett   for (const auto &AE : AArch64ARCHExtNames)
146e01718cdSDavid Spickett     if (AE.Feature && ArchExt == AE.getName())
147e01718cdSDavid Spickett       return StringRef(AE.Feature);
148e01718cdSDavid Spickett   return StringRef();
149e01718cdSDavid Spickett }
150e01718cdSDavid Spickett 
getDefaultCPU(StringRef Arch)151e01718cdSDavid Spickett StringRef AArch64::getDefaultCPU(StringRef Arch) {
152e01718cdSDavid Spickett   ArchKind AK = parseArch(Arch);
153e01718cdSDavid Spickett   if (AK == ArchKind::INVALID)
154e01718cdSDavid Spickett     return StringRef();
155e01718cdSDavid Spickett 
156e01718cdSDavid Spickett   // Look for multiple AKs to find the default for pair AK+Name.
157e01718cdSDavid Spickett   for (const auto &CPU : AArch64CPUNames)
158e01718cdSDavid Spickett     if (CPU.ArchID == AK && CPU.Default)
159e01718cdSDavid Spickett       return CPU.getName();
160e01718cdSDavid Spickett 
161e01718cdSDavid Spickett   // If we can't find a default then target the architecture instead
162e01718cdSDavid Spickett   return "generic";
163e01718cdSDavid Spickett }
164e01718cdSDavid Spickett 
fillValidCPUArchList(SmallVectorImpl<StringRef> & Values)165e01718cdSDavid Spickett void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
166e01718cdSDavid Spickett   for (const auto &Arch : AArch64CPUNames) {
167e01718cdSDavid Spickett     if (Arch.ArchID != ArchKind::INVALID)
168e01718cdSDavid Spickett       Values.push_back(Arch.getName());
169e01718cdSDavid Spickett   }
170e01718cdSDavid Spickett }
171e01718cdSDavid Spickett 
isX18ReservedByDefault(const Triple & TT)172e01718cdSDavid Spickett bool AArch64::isX18ReservedByDefault(const Triple &TT) {
173e01718cdSDavid Spickett   return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() ||
174e01718cdSDavid Spickett          TT.isOSWindows();
175e01718cdSDavid Spickett }
176e01718cdSDavid Spickett 
177e01718cdSDavid Spickett // Allows partial match, ex. "v8a" matches "armv8a".
parseArch(StringRef Arch)178e01718cdSDavid Spickett AArch64::ArchKind AArch64::parseArch(StringRef Arch) {
179e01718cdSDavid Spickett   Arch = ARM::getCanonicalArchName(Arch);
180e01718cdSDavid Spickett   if (checkArchVersion(Arch) < 8)
181e01718cdSDavid Spickett     return ArchKind::INVALID;
182e01718cdSDavid Spickett 
183e01718cdSDavid Spickett   StringRef Syn = ARM::getArchSynonym(Arch);
184f3bacd07SReid Kleckner   for (const auto &A : AArch64ARCHNames) {
185e01718cdSDavid Spickett     if (A.getName().endswith(Syn))
186e01718cdSDavid Spickett       return A.ID;
187e01718cdSDavid Spickett   }
188e01718cdSDavid Spickett   return ArchKind::INVALID;
189e01718cdSDavid Spickett }
190e01718cdSDavid Spickett 
parseArchExt(StringRef ArchExt)191e01718cdSDavid Spickett AArch64::ArchExtKind AArch64::parseArchExt(StringRef ArchExt) {
192f3bacd07SReid Kleckner   for (const auto &A : AArch64ARCHExtNames) {
193e01718cdSDavid Spickett     if (ArchExt == A.getName())
194e01718cdSDavid Spickett       return static_cast<ArchExtKind>(A.ID);
195e01718cdSDavid Spickett   }
196e01718cdSDavid Spickett   return AArch64::AEK_INVALID;
197e01718cdSDavid Spickett }
198e01718cdSDavid Spickett 
parseCPUArch(StringRef CPU)199e01718cdSDavid Spickett AArch64::ArchKind AArch64::parseCPUArch(StringRef CPU) {
200f3bacd07SReid Kleckner   for (const auto &C : AArch64CPUNames) {
201e01718cdSDavid Spickett     if (CPU == C.getName())
202e01718cdSDavid Spickett       return C.ArchID;
203e01718cdSDavid Spickett   }
204e01718cdSDavid Spickett   return ArchKind::INVALID;
205e01718cdSDavid Spickett }
206