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 | |
24 | using namespace llvm; |
25 | |
26 | static 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 | |
32 | const 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 | |
43 | std::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 | |
50 | uint64_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 | |
59 | bool 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 | |
70 | StringRef AArch64::resolveCPUAlias(StringRef Name) { |
71 | for (const auto &A : CpuAliases) |
72 | if (A.AltName == Name) |
73 | return A.Name; |
74 | return Name; |
75 | } |
76 | |
77 | StringRef AArch64::resolveExtAlias(StringRef Name) { |
78 | for (const auto &A : ExtAliases) |
79 | if (A.AltName == Name) |
80 | return A.Name; |
81 | return Name; |
82 | } |
83 | |
84 | StringRef 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 | |
96 | void 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 | |
104 | bool 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". |
110 | const 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 | |
123 | std::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 | |
135 | std::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 | |
147 | void 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 | |
162 | const llvm::AArch64::ExtensionInfo & |
163 | lookupExtensionByID(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 | |
170 | void 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 | |
208 | void 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 | |
232 | void 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 | |
247 | void 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 | |
257 | void 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 | |
266 | bool 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 | |