1//===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements a target parser to recognise AArch64 hardware features
10// such as FPU/CPU/ARCH and extension names.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/TargetParser/AArch64TargetParser.h"
15#include "llvm/Support/Debug.h"
16#include "llvm/Support/Format.h"
17#include "llvm/Support/raw_ostream.h"
18#include "llvm/TargetParser/ARMTargetParserCommon.h"
19#include "llvm/TargetParser/Triple.h"
20#include <cctype>
21
22#define DEBUG_TYPE "target-parser"
23
24using namespace llvm;
25
26static unsigned checkArchVersion(llvm::StringRef Arch) {
27 if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1]))
28 return (Arch[1] - 48);
29 return 0;
30}
31
32const AArch64::ArchInfo *AArch64::getArchForCpu(StringRef CPU) {
33 if (CPU == "generic")
34 return &ARMV8A;
35
36 // Note: this now takes cpu aliases into account
37 std::optional<CpuInfo> Cpu = parseCpu(Name: CPU);
38 if (!Cpu)
39 return nullptr;
40 return &Cpu->Arch;
41}
42
43std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubArch) {
44 for (const auto *A : AArch64::ArchInfos)
45 if (A->getSubArch() == SubArch)
46 return *A;
47 return {};
48}
49
50uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
51 uint64_t FeaturesMask = 0;
52 for (const StringRef &FeatureStr : FeatureStrs) {
53 if (auto Ext = parseArchExtension(Extension: FeatureStr))
54 FeaturesMask |= (1ULL << Ext->CPUFeature);
55 }
56 return FeaturesMask;
57}
58
59bool AArch64::getExtensionFeatures(
60 const AArch64::ExtensionBitset &InputExts,
61 std::vector<StringRef> &Features) {
62 for (const auto &E : Extensions)
63 /* INVALID and NONE have no feature name. */
64 if (InputExts.test(I: E.ID) && !E.Feature.empty())
65 Features.push_back(x: E.Feature);
66
67 return true;
68}
69
70StringRef AArch64::resolveCPUAlias(StringRef Name) {
71 for (const auto &A : CpuAliases)
72 if (A.AltName == Name)
73 return A.Name;
74 return Name;
75}
76
77StringRef AArch64::resolveExtAlias(StringRef Name) {
78 for (const auto &A : ExtAliases)
79 if (A.AltName == Name)
80 return A.Name;
81 return Name;
82}
83
84StringRef AArch64::getArchExtFeature(StringRef ArchExt) {
85 bool IsNegated = ArchExt.starts_with(Prefix: "no");
86 StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(N: 2) : ArchExt;
87
88 if (auto AE = parseArchExtension(Extension: ArchExtBase)) {
89 // Note: the returned string can be empty.
90 return IsNegated ? AE->NegFeature : AE->Feature;
91 }
92
93 return StringRef();
94}
95
96void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
97 for (const auto &C : CpuInfos)
98 Values.push_back(Elt: C.Name);
99
100 for (const auto &Alias : CpuAliases)
101 Values.push_back(Elt: Alias.AltName);
102}
103
104bool AArch64::isX18ReservedByDefault(const Triple &TT) {
105 return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() ||
106 TT.isOSWindows() || TT.isOHOSFamily();
107}
108
109// Allows partial match, ex. "v8a" matches "armv8a".
110const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) {
111 Arch = llvm::ARM::getCanonicalArchName(Arch);
112 if (checkArchVersion(Arch) < 8)
113 return {};
114
115 StringRef Syn = llvm::ARM::getArchSynonym(Arch);
116 for (const auto *A : ArchInfos) {
117 if (A->Name.ends_with(Suffix: Syn))
118 return A;
119 }
120 return {};
121}
122
123std::optional<AArch64::ExtensionInfo> AArch64::parseArchExtension(StringRef ArchExt) {
124 // Resolve aliases first.
125 ArchExt = resolveExtAlias(Name: ArchExt);
126
127 // Then find the Extension name.
128 for (const auto &A : Extensions) {
129 if (ArchExt == A.Name)
130 return A;
131 }
132 return {};
133}
134
135std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) {
136 // Resolve aliases first.
137 Name = resolveCPUAlias(Name);
138
139 // Then find the CPU name.
140 for (const auto &C : CpuInfos)
141 if (Name == C.Name)
142 return C;
143
144 return {};
145}
146
147void AArch64::PrintSupportedExtensions(StringMap<StringRef> DescMap) {
148 outs() << "All available -march extensions for AArch64\n\n"
149 << " " << left_justify(Str: "Name", Width: 20)
150 << (DescMap.empty() ? "\n" : "Description\n");
151 for (const auto &Ext : Extensions) {
152 // Extensions without a feature cannot be used with -march.
153 if (!Ext.Feature.empty()) {
154 std::string Description = DescMap[Ext.Name].str();
155 outs() << " "
156 << format(Fmt: Description.empty() ? "%s\n" : "%-20s%s\n",
157 Vals: Ext.Name.str().c_str(), Vals: Description.c_str());
158 }
159 }
160}
161
162const llvm::AArch64::ExtensionInfo &
163lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) {
164 for (const auto &E : llvm::AArch64::Extensions)
165 if (E.ID == ExtID)
166 return E;
167 llvm_unreachable("Invalid extension ID");
168}
169
170void AArch64::ExtensionSet::enable(ArchExtKind E) {
171 if (Enabled.test(I: E))
172 return;
173
174 LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).Name << "\n");
175
176 Touched.set(E);
177 Enabled.set(E);
178
179 // Recursively enable all features that this one depends on. This handles all
180 // of the simple cases, where the behaviour doesn't depend on the base
181 // architecture version.
182 for (auto Dep : ExtensionDependencies)
183 if (E == Dep.Later)
184 enable(E: Dep.Earlier);
185
186 // Special cases for dependencies which vary depending on the base
187 // architecture version.
188 if (BaseArch) {
189 // +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+
190 if (E == AEK_FP16 && BaseArch->is_superset(Other: ARMV8_4A) &&
191 !BaseArch->is_superset(Other: ARMV9A))
192 enable(E: AEK_FP16FML);
193
194 // For all architectures, +crypto enables +aes and +sha2.
195 if (E == AEK_CRYPTO) {
196 enable(E: AEK_AES);
197 enable(E: AEK_SHA2);
198 }
199
200 // For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4.
201 if (E == AEK_CRYPTO && BaseArch->is_superset(Other: ARMV8_4A)) {
202 enable(E: AEK_SHA3);
203 enable(E: AEK_SM4);
204 }
205 }
206}
207
208void AArch64::ExtensionSet::disable(ArchExtKind E) {
209 // -crypto always disables aes, sha2, sha3 and sm4, even for architectures
210 // where the latter two would not be enabled by +crypto.
211 if (E == AEK_CRYPTO) {
212 disable(E: AEK_AES);
213 disable(E: AEK_SHA2);
214 disable(E: AEK_SHA3);
215 disable(E: AEK_SM4);
216 }
217
218 if (!Enabled.test(I: E))
219 return;
220
221 LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).Name << "\n");
222
223 Touched.set(E);
224 Enabled.reset(I: E);
225
226 // Recursively disable all features that depends on this one.
227 for (auto Dep : ExtensionDependencies)
228 if (E == Dep.Earlier)
229 disable(E: Dep.Later);
230}
231
232void AArch64::ExtensionSet::toLLVMFeatureList(
233 std::vector<StringRef> &Features) const {
234 if (BaseArch && !BaseArch->ArchFeature.empty())
235 Features.push_back(x: BaseArch->ArchFeature);
236
237 for (const auto &E : Extensions) {
238 if (E.Feature.empty() || !Touched.test(I: E.ID))
239 continue;
240 if (Enabled.test(I: E.ID))
241 Features.push_back(x: E.Feature);
242 else
243 Features.push_back(x: E.NegFeature);
244 }
245}
246
247void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo &CPU) {
248 LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU.Name << ")\n");
249 BaseArch = &CPU.Arch;
250
251 AArch64::ExtensionBitset CPUExtensions = CPU.getImpliedExtensions();
252 for (const auto &E : Extensions)
253 if (CPUExtensions.test(I: E.ID))
254 enable(E: E.ID);
255}
256
257void AArch64::ExtensionSet::addArchDefaults(const ArchInfo &Arch) {
258 LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch.Name << ")\n");
259 BaseArch = &Arch;
260
261 for (const auto &E : Extensions)
262 if (Arch.DefaultExts.test(I: E.ID))
263 enable(E: E.ID);
264}
265
266bool AArch64::ExtensionSet::parseModifier(StringRef Modifier) {
267 LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier << ")\n");
268
269 bool IsNegated = Modifier.starts_with(Prefix: "no");
270 StringRef ArchExt = IsNegated ? Modifier.drop_front(N: 2) : Modifier;
271
272 if (auto AE = parseArchExtension(ArchExt)) {
273 if (AE->Feature.empty() || AE->NegFeature.empty())
274 return false;
275 if (IsNegated)
276 disable(E: AE->ID);
277 else
278 enable(E: AE->ID);
279 return true;
280 }
281 return false;
282}
283

source code of llvm/lib/TargetParser/AArch64TargetParser.cpp