1 //===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements a target parser to recognise AArch64 hardware features
10 // such as FPU/CPU/ARCH and extension names.
12 //===----------------------------------------------------------------------===//
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"
23 #define DEBUG_TYPE "target-parser"
28 #include "llvm/TargetParser/AArch64TargetParserDef.inc"
30 static unsigned checkArchVersion(llvm::StringRef Arch
) {
31 if (Arch
.size() >= 2 && Arch
[0] == 'v' && std::isdigit(Arch
[1]))
32 return (Arch
[1] - 48);
36 const AArch64::ArchInfo
*AArch64::getArchForCpu(StringRef CPU
) {
37 // Note: this now takes cpu aliases into account
38 std::optional
<CpuInfo
> Cpu
= parseCpu(CPU
);
44 std::optional
<AArch64::ArchInfo
> AArch64::ArchInfo::findBySubArch(StringRef SubArch
) {
45 for (const auto *A
: AArch64::ArchInfos
)
46 if (A
->getSubArch() == SubArch
)
51 unsigned AArch64::getFMVPriority(ArrayRef
<StringRef
> Features
) {
52 constexpr unsigned MaxFMVPriority
= 1000;
53 unsigned Priority
= 0;
54 unsigned NumFeatures
= 0;
55 for (StringRef Feature
: Features
) {
56 if (auto Ext
= parseFMVExtension(Feature
)) {
57 Priority
= std::max(Priority
, Ext
->Priority
);
61 return Priority
+ MaxFMVPriority
* NumFeatures
;
64 uint64_t AArch64::getCpuSupportsMask(ArrayRef
<StringRef
> Features
) {
65 // Transitively enable the Arch Extensions which correspond to each feature.
66 ExtensionSet FeatureBits
;
67 for (const StringRef Feature
: Features
)
68 if (std::optional
<FMVInfo
> Info
= parseFMVExtension(Feature
))
70 FeatureBits
.enable(*Info
->ID
);
72 // Construct a bitmask for all the transitively enabled Arch Extensions.
73 uint64_t FeaturesMask
= 0;
74 for (const FMVInfo
&Info
: getFMVInfo())
75 if (Info
.ID
&& FeatureBits
.Enabled
.test(*Info
.ID
))
76 FeaturesMask
|= (1ULL << Info
.Bit
);
81 bool AArch64::getExtensionFeatures(
82 const AArch64::ExtensionBitset
&InputExts
,
83 std::vector
<StringRef
> &Features
) {
84 for (const auto &E
: Extensions
)
85 /* INVALID and NONE have no feature name. */
86 if (InputExts
.test(E
.ID
) && !E
.PosTargetFeature
.empty())
87 Features
.push_back(E
.PosTargetFeature
);
92 StringRef
AArch64::resolveCPUAlias(StringRef Name
) {
93 for (const auto &A
: CpuAliases
)
94 if (A
.AltName
== Name
)
99 StringRef
AArch64::getArchExtFeature(StringRef ArchExt
) {
100 bool IsNegated
= ArchExt
.starts_with("no");
101 StringRef ArchExtBase
= IsNegated
? ArchExt
.drop_front(2) : ArchExt
;
103 if (auto AE
= parseArchExtension(ArchExtBase
)) {
104 assert(!(AE
.has_value() && AE
->NegTargetFeature
.empty()));
105 return IsNegated
? AE
->NegTargetFeature
: AE
->PosTargetFeature
;
111 void AArch64::fillValidCPUArchList(SmallVectorImpl
<StringRef
> &Values
) {
112 for (const auto &C
: CpuInfos
)
113 Values
.push_back(C
.Name
);
115 for (const auto &Alias
: CpuAliases
)
116 // The apple-latest alias is backend only, do not expose it to clang's -mcpu.
117 if (Alias
.AltName
!= "apple-latest")
118 Values
.push_back(Alias
.AltName
);
123 bool AArch64::isX18ReservedByDefault(const Triple
&TT
) {
124 return TT
.isAndroid() || TT
.isOSDarwin() || TT
.isOSFuchsia() ||
125 TT
.isOSWindows() || TT
.isOHOSFamily();
128 // Allows partial match, ex. "v8a" matches "armv8a".
129 const AArch64::ArchInfo
*AArch64::parseArch(StringRef Arch
) {
130 Arch
= llvm::ARM::getCanonicalArchName(Arch
);
131 if (checkArchVersion(Arch
) < 8)
134 StringRef Syn
= llvm::ARM::getArchSynonym(Arch
);
135 for (const auto *A
: ArchInfos
) {
136 if (A
->Name
.ends_with(Syn
))
142 std::optional
<AArch64::ExtensionInfo
>
143 AArch64::parseArchExtension(StringRef ArchExt
) {
146 for (const auto &A
: Extensions
) {
147 if (ArchExt
== A
.UserVisibleName
|| ArchExt
== A
.Alias
)
153 std::optional
<AArch64::FMVInfo
> AArch64::parseFMVExtension(StringRef FMVExt
) {
154 // FIXME introduce general alias functionality, or remove this exception.
155 if (FMVExt
== "rdma")
158 for (const auto &I
: getFMVInfo()) {
159 if (FMVExt
== I
.Name
)
165 std::optional
<AArch64::ExtensionInfo
>
166 AArch64::targetFeatureToExtension(StringRef TargetFeature
) {
167 for (const auto &E
: Extensions
)
168 if (TargetFeature
== E
.PosTargetFeature
)
173 std::optional
<AArch64::CpuInfo
> AArch64::parseCpu(StringRef Name
) {
174 // Resolve aliases first.
175 Name
= resolveCPUAlias(Name
);
177 // Then find the CPU name.
178 for (const auto &C
: CpuInfos
)
185 void AArch64::PrintSupportedExtensions() {
186 outs() << "All available -march extensions for AArch64\n\n"
187 << " " << left_justify("Name", 20)
188 << left_justify("Architecture Feature(s)", 55)
190 for (const auto &Ext
: Extensions
) {
191 // Extensions without a feature cannot be used with -march.
192 if (!Ext
.UserVisibleName
.empty() && !Ext
.PosTargetFeature
.empty()) {
194 << format(Ext
.Description
.empty() ? "%-20s%s\n" : "%-20s%-55s%s\n",
195 Ext
.UserVisibleName
.str().c_str(),
196 Ext
.ArchFeatureName
.str().c_str(),
197 Ext
.Description
.str().c_str());
203 AArch64::printEnabledExtensions(const std::set
<StringRef
> &EnabledFeatureNames
) {
204 outs() << "Extensions enabled for the given AArch64 target\n\n"
205 << " " << left_justify("Architecture Feature(s)", 55)
207 std::vector
<ExtensionInfo
> EnabledExtensionsInfo
;
208 for (const auto &FeatureName
: EnabledFeatureNames
) {
209 std::string PosFeatureName
= '+' + FeatureName
.str();
210 if (auto ExtInfo
= targetFeatureToExtension(PosFeatureName
))
211 EnabledExtensionsInfo
.push_back(*ExtInfo
);
214 std::sort(EnabledExtensionsInfo
.begin(), EnabledExtensionsInfo
.end(),
215 [](const ExtensionInfo
&Lhs
, const ExtensionInfo
&Rhs
) {
216 return Lhs
.ArchFeatureName
< Rhs
.ArchFeatureName
;
219 for (const auto &Ext
: EnabledExtensionsInfo
) {
221 << format("%-55s%s\n",
222 Ext
.ArchFeatureName
.str().c_str(),
223 Ext
.Description
.str().c_str());
227 const llvm::AArch64::ExtensionInfo
&
228 lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID
) {
229 for (const auto &E
: llvm::AArch64::Extensions
)
232 llvm_unreachable("Invalid extension ID");
235 void AArch64::ExtensionSet::enable(ArchExtKind E
) {
239 LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E
).UserVisibleName
<< "\n");
244 // Recursively enable all features that this one depends on. This handles all
245 // of the simple cases, where the behaviour doesn't depend on the base
246 // architecture version.
247 for (auto Dep
: ExtensionDependencies
)
251 // Special cases for dependencies which vary depending on the base
252 // architecture version.
254 // +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+
255 if (E
== AEK_FP16
&& BaseArch
->is_superset(ARMV8_4A
) &&
256 !BaseArch
->is_superset(ARMV9A
))
259 // For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4.
260 if (E
== AEK_CRYPTO
&& BaseArch
->is_superset(ARMV8_4A
)) {
267 void AArch64::ExtensionSet::disable(ArchExtKind E
) {
268 // -crypto always disables aes, sha2, sha3 and sm4, even for architectures
269 // where the latter two would not be enabled by +crypto.
270 if (E
== AEK_CRYPTO
) {
277 // sve2-aes was historically associated with both FEAT_SVE2 and FEAT_SVE_AES,
278 // the latter is now associated with sve-aes and sve2-aes has become shorthand
279 // for +sve2+sve-aes. For backwards compatibility, when we disable sve2-aes we
280 // must also disable sve-aes.
281 if (E
== AEK_SVE2AES
)
284 if (!Enabled
.test(E
))
287 LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E
).UserVisibleName
<< "\n");
292 // Recursively disable all features that depends on this one.
293 for (auto Dep
: ExtensionDependencies
)
294 if (E
== Dep
.Earlier
)
298 void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo
&CPU
) {
299 LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU
.Name
<< ")\n");
300 BaseArch
= &CPU
.Arch
;
302 AArch64::ExtensionBitset CPUExtensions
= CPU
.getImpliedExtensions();
303 for (const auto &E
: Extensions
)
304 if (CPUExtensions
.test(E
.ID
))
308 void AArch64::ExtensionSet::addArchDefaults(const ArchInfo
&Arch
) {
309 LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch
.Name
<< ")\n");
312 for (const auto &E
: Extensions
)
313 if (Arch
.DefaultExts
.test(E
.ID
))
317 bool AArch64::ExtensionSet::parseModifier(StringRef Modifier
,
318 const bool AllowNoDashForm
) {
319 LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier
<< ")\n");
322 // The "no-feat" form is allowed in the target attribute but nowhere else.
323 if (AllowNoDashForm
&& Modifier
.starts_with("no-"))
325 else if (Modifier
.starts_with("no"))
327 bool IsNegated
= NChars
!= 0;
328 StringRef ArchExt
= Modifier
.drop_front(NChars
);
330 if (auto AE
= parseArchExtension(ArchExt
)) {
331 if (AE
->PosTargetFeature
.empty() || AE
->NegTargetFeature
.empty())
342 void AArch64::ExtensionSet::reconstructFromParsedFeatures(
343 const std::vector
<std::string
> &Features
,
344 std::vector
<std::string
> &NonExtensions
) {
345 assert(Touched
.none() && "Bitset already initialized");
346 for (auto &F
: Features
) {
347 bool IsNegated
= F
[0] == '-';
348 if (auto AE
= targetFeatureToExtension(F
)) {
351 Enabled
.reset(AE
->ID
);
356 NonExtensions
.push_back(F
);
360 void AArch64::ExtensionSet::dump() const {
361 std::vector
<StringRef
> Features
;
362 toLLVMFeatureList(Features
);
363 for (StringRef F
: Features
)
364 llvm::outs() << F
<< " ";
365 llvm::outs() << "\n";
368 const AArch64::ExtensionInfo
&
369 AArch64::getExtensionByID(AArch64::ArchExtKind ExtID
) {
370 return lookupExtensionByID(ExtID
);