xref: /freebsd-src/contrib/llvm-project/llvm/lib/TargetParser/AArch64TargetParser.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1bdd1243dSDimitry Andric //===-- AArch64TargetParser - Parser for AArch64 features -------*- C++ -*-===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric //
9bdd1243dSDimitry Andric // This file implements a target parser to recognise AArch64 hardware features
10bdd1243dSDimitry Andric // such as FPU/CPU/ARCH and extension names.
11bdd1243dSDimitry Andric //
12bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
13bdd1243dSDimitry Andric 
14bdd1243dSDimitry Andric #include "llvm/TargetParser/AArch64TargetParser.h"
157a6dacacSDimitry Andric #include "llvm/Support/Debug.h"
165f757f3fSDimitry Andric #include "llvm/Support/Format.h"
175f757f3fSDimitry Andric #include "llvm/Support/raw_ostream.h"
18bdd1243dSDimitry Andric #include "llvm/TargetParser/ARMTargetParserCommon.h"
19bdd1243dSDimitry Andric #include "llvm/TargetParser/Triple.h"
20bdd1243dSDimitry Andric #include <cctype>
21*0fca6ea1SDimitry Andric #include <vector>
22bdd1243dSDimitry Andric 
237a6dacacSDimitry Andric #define DEBUG_TYPE "target-parser"
247a6dacacSDimitry Andric 
25bdd1243dSDimitry Andric using namespace llvm;
26bdd1243dSDimitry Andric 
27*0fca6ea1SDimitry Andric #define EMIT_FMV_INFO
28*0fca6ea1SDimitry Andric #include "llvm/TargetParser/AArch64TargetParserDef.inc"
29*0fca6ea1SDimitry Andric 
30bdd1243dSDimitry Andric static unsigned checkArchVersion(llvm::StringRef Arch) {
31bdd1243dSDimitry Andric   if (Arch.size() >= 2 && Arch[0] == 'v' && std::isdigit(Arch[1]))
32bdd1243dSDimitry Andric     return (Arch[1] - 48);
33bdd1243dSDimitry Andric   return 0;
34bdd1243dSDimitry Andric }
35bdd1243dSDimitry Andric 
367a6dacacSDimitry Andric const AArch64::ArchInfo *AArch64::getArchForCpu(StringRef CPU) {
37bdd1243dSDimitry Andric   // Note: this now takes cpu aliases into account
3806c3fb27SDimitry Andric   std::optional<CpuInfo> Cpu = parseCpu(CPU);
3906c3fb27SDimitry Andric   if (!Cpu)
407a6dacacSDimitry Andric     return nullptr;
417a6dacacSDimitry Andric   return &Cpu->Arch;
42bdd1243dSDimitry Andric }
43bdd1243dSDimitry Andric 
4406c3fb27SDimitry Andric std::optional<AArch64::ArchInfo> AArch64::ArchInfo::findBySubArch(StringRef SubArch) {
45bdd1243dSDimitry Andric   for (const auto *A : AArch64::ArchInfos)
46bdd1243dSDimitry Andric     if (A->getSubArch() == SubArch)
47bdd1243dSDimitry Andric       return *A;
4806c3fb27SDimitry Andric   return {};
49bdd1243dSDimitry Andric }
50bdd1243dSDimitry Andric 
51bdd1243dSDimitry Andric uint64_t AArch64::getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs) {
52bdd1243dSDimitry Andric   uint64_t FeaturesMask = 0;
53bdd1243dSDimitry Andric   for (const StringRef &FeatureStr : FeatureStrs) {
54*0fca6ea1SDimitry Andric     if (auto Ext = parseFMVExtension(FeatureStr))
55*0fca6ea1SDimitry Andric       FeaturesMask |= (1ULL << Ext->Bit);
56bdd1243dSDimitry Andric   }
57bdd1243dSDimitry Andric   return FeaturesMask;
58bdd1243dSDimitry Andric }
59bdd1243dSDimitry Andric 
605f757f3fSDimitry Andric bool AArch64::getExtensionFeatures(
615f757f3fSDimitry Andric     const AArch64::ExtensionBitset &InputExts,
62bdd1243dSDimitry Andric     std::vector<StringRef> &Features) {
63bdd1243dSDimitry Andric   for (const auto &E : Extensions)
64bdd1243dSDimitry Andric     /* INVALID and NONE have no feature name. */
65*0fca6ea1SDimitry Andric     if (InputExts.test(E.ID) && !E.PosTargetFeature.empty())
66*0fca6ea1SDimitry Andric       Features.push_back(E.PosTargetFeature);
67bdd1243dSDimitry Andric 
68bdd1243dSDimitry Andric   return true;
69bdd1243dSDimitry Andric }
70bdd1243dSDimitry Andric 
71bdd1243dSDimitry Andric StringRef AArch64::resolveCPUAlias(StringRef Name) {
72bdd1243dSDimitry Andric   for (const auto &A : CpuAliases)
73*0fca6ea1SDimitry Andric     if (A.AltName == Name)
74bdd1243dSDimitry Andric       return A.Name;
75bdd1243dSDimitry Andric   return Name;
76bdd1243dSDimitry Andric }
77bdd1243dSDimitry Andric 
78bdd1243dSDimitry Andric StringRef AArch64::getArchExtFeature(StringRef ArchExt) {
797a6dacacSDimitry Andric   bool IsNegated = ArchExt.starts_with("no");
807a6dacacSDimitry Andric   StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(2) : ArchExt;
817a6dacacSDimitry Andric 
827a6dacacSDimitry Andric   if (auto AE = parseArchExtension(ArchExtBase)) {
83*0fca6ea1SDimitry Andric     assert(!(AE.has_value() && AE->NegTargetFeature.empty()));
84*0fca6ea1SDimitry Andric     return IsNegated ? AE->NegTargetFeature : AE->PosTargetFeature;
85bdd1243dSDimitry Andric   }
86bdd1243dSDimitry Andric 
87bdd1243dSDimitry Andric   return StringRef();
88bdd1243dSDimitry Andric }
89bdd1243dSDimitry Andric 
90bdd1243dSDimitry Andric void AArch64::fillValidCPUArchList(SmallVectorImpl<StringRef> &Values) {
91bdd1243dSDimitry Andric   for (const auto &C : CpuInfos)
92bdd1243dSDimitry Andric     Values.push_back(C.Name);
93bdd1243dSDimitry Andric 
94bdd1243dSDimitry Andric   for (const auto &Alias : CpuAliases)
95*0fca6ea1SDimitry Andric     // The apple-latest alias is backend only, do not expose it to clang's -mcpu.
96*0fca6ea1SDimitry Andric     if (Alias.AltName != "apple-latest")
97*0fca6ea1SDimitry Andric       Values.push_back(Alias.AltName);
98*0fca6ea1SDimitry Andric 
99*0fca6ea1SDimitry Andric   llvm::sort(Values);
100bdd1243dSDimitry Andric }
101bdd1243dSDimitry Andric 
102bdd1243dSDimitry Andric bool AArch64::isX18ReservedByDefault(const Triple &TT) {
103bdd1243dSDimitry Andric   return TT.isAndroid() || TT.isOSDarwin() || TT.isOSFuchsia() ||
10406c3fb27SDimitry Andric          TT.isOSWindows() || TT.isOHOSFamily();
105bdd1243dSDimitry Andric }
106bdd1243dSDimitry Andric 
107bdd1243dSDimitry Andric // Allows partial match, ex. "v8a" matches "armv8a".
1087a6dacacSDimitry Andric const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) {
109bdd1243dSDimitry Andric   Arch = llvm::ARM::getCanonicalArchName(Arch);
110bdd1243dSDimitry Andric   if (checkArchVersion(Arch) < 8)
11106c3fb27SDimitry Andric     return {};
112bdd1243dSDimitry Andric 
113bdd1243dSDimitry Andric   StringRef Syn = llvm::ARM::getArchSynonym(Arch);
114bdd1243dSDimitry Andric   for (const auto *A : ArchInfos) {
1155f757f3fSDimitry Andric     if (A->Name.ends_with(Syn))
1167a6dacacSDimitry Andric       return A;
117bdd1243dSDimitry Andric   }
11806c3fb27SDimitry Andric   return {};
119bdd1243dSDimitry Andric }
120bdd1243dSDimitry Andric 
121*0fca6ea1SDimitry Andric std::optional<AArch64::ExtensionInfo>
122*0fca6ea1SDimitry Andric AArch64::parseArchExtension(StringRef ArchExt) {
123*0fca6ea1SDimitry Andric   if (ArchExt.empty())
124*0fca6ea1SDimitry Andric     return {};
125bdd1243dSDimitry Andric   for (const auto &A : Extensions) {
126*0fca6ea1SDimitry Andric     if (ArchExt == A.UserVisibleName || ArchExt == A.Alias)
12706c3fb27SDimitry Andric       return A;
128bdd1243dSDimitry Andric   }
12906c3fb27SDimitry Andric   return {};
130bdd1243dSDimitry Andric }
131bdd1243dSDimitry Andric 
132*0fca6ea1SDimitry Andric std::optional<AArch64::FMVInfo> AArch64::parseFMVExtension(StringRef FMVExt) {
133*0fca6ea1SDimitry Andric   // FIXME introduce general alias functionality, or remove this exception.
134*0fca6ea1SDimitry Andric   if (FMVExt == "rdma")
135*0fca6ea1SDimitry Andric     FMVExt = "rdm";
136*0fca6ea1SDimitry Andric 
137*0fca6ea1SDimitry Andric   for (const auto &I : getFMVInfo()) {
138*0fca6ea1SDimitry Andric     if (FMVExt == I.Name)
139*0fca6ea1SDimitry Andric       return I;
140*0fca6ea1SDimitry Andric   }
141*0fca6ea1SDimitry Andric   return {};
142*0fca6ea1SDimitry Andric }
143*0fca6ea1SDimitry Andric 
144*0fca6ea1SDimitry Andric std::optional<AArch64::ExtensionInfo>
145*0fca6ea1SDimitry Andric AArch64::targetFeatureToExtension(StringRef TargetFeature) {
146*0fca6ea1SDimitry Andric   for (const auto &E : Extensions)
147*0fca6ea1SDimitry Andric     if (TargetFeature == E.PosTargetFeature)
148*0fca6ea1SDimitry Andric       return E;
149*0fca6ea1SDimitry Andric   return {};
150*0fca6ea1SDimitry Andric }
151*0fca6ea1SDimitry Andric 
15206c3fb27SDimitry Andric std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) {
153bdd1243dSDimitry Andric   // Resolve aliases first.
154bdd1243dSDimitry Andric   Name = resolveCPUAlias(Name);
155bdd1243dSDimitry Andric 
156bdd1243dSDimitry Andric   // Then find the CPU name.
157bdd1243dSDimitry Andric   for (const auto &C : CpuInfos)
158bdd1243dSDimitry Andric     if (Name == C.Name)
159bdd1243dSDimitry Andric       return C;
160bdd1243dSDimitry Andric 
16106c3fb27SDimitry Andric   return {};
162bdd1243dSDimitry Andric }
1635f757f3fSDimitry Andric 
164*0fca6ea1SDimitry Andric void AArch64::PrintSupportedExtensions() {
1655f757f3fSDimitry Andric   outs() << "All available -march extensions for AArch64\n\n"
1665f757f3fSDimitry Andric          << "    " << left_justify("Name", 20)
167*0fca6ea1SDimitry Andric          << left_justify("Architecture Feature(s)", 55)
168*0fca6ea1SDimitry Andric          << "Description\n";
1695f757f3fSDimitry Andric   for (const auto &Ext : Extensions) {
1705f757f3fSDimitry Andric     // Extensions without a feature cannot be used with -march.
171*0fca6ea1SDimitry Andric     if (!Ext.UserVisibleName.empty() && !Ext.PosTargetFeature.empty()) {
1725f757f3fSDimitry Andric       outs() << "    "
173*0fca6ea1SDimitry Andric              << format(Ext.Description.empty() ? "%-20s%s\n" : "%-20s%-55s%s\n",
174*0fca6ea1SDimitry Andric                        Ext.UserVisibleName.str().c_str(),
175*0fca6ea1SDimitry Andric                        Ext.ArchFeatureName.str().c_str(),
176*0fca6ea1SDimitry Andric                        Ext.Description.str().c_str());
1775f757f3fSDimitry Andric     }
1785f757f3fSDimitry Andric   }
1795f757f3fSDimitry Andric }
1807a6dacacSDimitry Andric 
181*0fca6ea1SDimitry Andric void
182*0fca6ea1SDimitry Andric AArch64::printEnabledExtensions(const std::set<StringRef> &EnabledFeatureNames) {
183*0fca6ea1SDimitry Andric   outs() << "Extensions enabled for the given AArch64 target\n\n"
184*0fca6ea1SDimitry Andric          << "    " << left_justify("Architecture Feature(s)", 55)
185*0fca6ea1SDimitry Andric          << "Description\n";
186*0fca6ea1SDimitry Andric   std::vector<ExtensionInfo> EnabledExtensionsInfo;
187*0fca6ea1SDimitry Andric   for (const auto &FeatureName : EnabledFeatureNames) {
188*0fca6ea1SDimitry Andric     std::string PosFeatureName = '+' + FeatureName.str();
189*0fca6ea1SDimitry Andric     if (auto ExtInfo = targetFeatureToExtension(PosFeatureName))
190*0fca6ea1SDimitry Andric       EnabledExtensionsInfo.push_back(*ExtInfo);
191*0fca6ea1SDimitry Andric   }
192*0fca6ea1SDimitry Andric 
193*0fca6ea1SDimitry Andric   std::sort(EnabledExtensionsInfo.begin(), EnabledExtensionsInfo.end(),
194*0fca6ea1SDimitry Andric             [](const ExtensionInfo &Lhs, const ExtensionInfo &Rhs) {
195*0fca6ea1SDimitry Andric               return Lhs.ArchFeatureName < Rhs.ArchFeatureName;
196*0fca6ea1SDimitry Andric             });
197*0fca6ea1SDimitry Andric 
198*0fca6ea1SDimitry Andric   for (const auto &Ext : EnabledExtensionsInfo) {
199*0fca6ea1SDimitry Andric     outs() << "    "
200*0fca6ea1SDimitry Andric            << format("%-55s%s\n",
201*0fca6ea1SDimitry Andric                      Ext.ArchFeatureName.str().c_str(),
202*0fca6ea1SDimitry Andric                      Ext.Description.str().c_str());
203*0fca6ea1SDimitry Andric   }
204*0fca6ea1SDimitry Andric }
205*0fca6ea1SDimitry Andric 
2067a6dacacSDimitry Andric const llvm::AArch64::ExtensionInfo &
2077a6dacacSDimitry Andric lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) {
2087a6dacacSDimitry Andric   for (const auto &E : llvm::AArch64::Extensions)
2097a6dacacSDimitry Andric     if (E.ID == ExtID)
2107a6dacacSDimitry Andric       return E;
2117a6dacacSDimitry Andric   llvm_unreachable("Invalid extension ID");
2127a6dacacSDimitry Andric }
2137a6dacacSDimitry Andric 
2147a6dacacSDimitry Andric void AArch64::ExtensionSet::enable(ArchExtKind E) {
2157a6dacacSDimitry Andric   if (Enabled.test(E))
2167a6dacacSDimitry Andric     return;
2177a6dacacSDimitry Andric 
218*0fca6ea1SDimitry Andric   LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).UserVisibleName << "\n");
2197a6dacacSDimitry Andric 
2207a6dacacSDimitry Andric   Touched.set(E);
2217a6dacacSDimitry Andric   Enabled.set(E);
2227a6dacacSDimitry Andric 
2237a6dacacSDimitry Andric   // Recursively enable all features that this one depends on. This handles all
2247a6dacacSDimitry Andric   // of the simple cases, where the behaviour doesn't depend on the base
2257a6dacacSDimitry Andric   // architecture version.
2267a6dacacSDimitry Andric   for (auto Dep : ExtensionDependencies)
2277a6dacacSDimitry Andric     if (E == Dep.Later)
2287a6dacacSDimitry Andric       enable(Dep.Earlier);
2297a6dacacSDimitry Andric 
2307a6dacacSDimitry Andric   // Special cases for dependencies which vary depending on the base
2317a6dacacSDimitry Andric   // architecture version.
2327a6dacacSDimitry Andric   if (BaseArch) {
2337a6dacacSDimitry Andric     // +fp16 implies +fp16fml for v8.4A+, but not v9.0-A+
2347a6dacacSDimitry Andric     if (E == AEK_FP16 && BaseArch->is_superset(ARMV8_4A) &&
2357a6dacacSDimitry Andric         !BaseArch->is_superset(ARMV9A))
2367a6dacacSDimitry Andric       enable(AEK_FP16FML);
2377a6dacacSDimitry Andric 
2387a6dacacSDimitry Andric     // For v8.4A+ and v9.0A+, +crypto also enables +sha3 and +sm4.
2397a6dacacSDimitry Andric     if (E == AEK_CRYPTO && BaseArch->is_superset(ARMV8_4A)) {
2407a6dacacSDimitry Andric       enable(AEK_SHA3);
2417a6dacacSDimitry Andric       enable(AEK_SM4);
2427a6dacacSDimitry Andric     }
2437a6dacacSDimitry Andric   }
2447a6dacacSDimitry Andric }
2457a6dacacSDimitry Andric 
2467a6dacacSDimitry Andric void AArch64::ExtensionSet::disable(ArchExtKind E) {
2477a6dacacSDimitry Andric   // -crypto always disables aes, sha2, sha3 and sm4, even for architectures
2487a6dacacSDimitry Andric   // where the latter two would not be enabled by +crypto.
2497a6dacacSDimitry Andric   if (E == AEK_CRYPTO) {
2507a6dacacSDimitry Andric     disable(AEK_AES);
2517a6dacacSDimitry Andric     disable(AEK_SHA2);
2527a6dacacSDimitry Andric     disable(AEK_SHA3);
2537a6dacacSDimitry Andric     disable(AEK_SM4);
2547a6dacacSDimitry Andric   }
2557a6dacacSDimitry Andric 
2567a6dacacSDimitry Andric   if (!Enabled.test(E))
2577a6dacacSDimitry Andric     return;
2587a6dacacSDimitry Andric 
259*0fca6ea1SDimitry Andric   LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).UserVisibleName << "\n");
2607a6dacacSDimitry Andric 
2617a6dacacSDimitry Andric   Touched.set(E);
2627a6dacacSDimitry Andric   Enabled.reset(E);
2637a6dacacSDimitry Andric 
2647a6dacacSDimitry Andric   // Recursively disable all features that depends on this one.
2657a6dacacSDimitry Andric   for (auto Dep : ExtensionDependencies)
2667a6dacacSDimitry Andric     if (E == Dep.Earlier)
2677a6dacacSDimitry Andric       disable(Dep.Later);
2687a6dacacSDimitry Andric }
2697a6dacacSDimitry Andric 
2707a6dacacSDimitry Andric void AArch64::ExtensionSet::addCPUDefaults(const CpuInfo &CPU) {
2717a6dacacSDimitry Andric   LLVM_DEBUG(llvm::dbgs() << "addCPUDefaults(" << CPU.Name << ")\n");
2727a6dacacSDimitry Andric   BaseArch = &CPU.Arch;
2737a6dacacSDimitry Andric 
2747a6dacacSDimitry Andric   AArch64::ExtensionBitset CPUExtensions = CPU.getImpliedExtensions();
2757a6dacacSDimitry Andric   for (const auto &E : Extensions)
2767a6dacacSDimitry Andric     if (CPUExtensions.test(E.ID))
2777a6dacacSDimitry Andric       enable(E.ID);
2787a6dacacSDimitry Andric }
2797a6dacacSDimitry Andric 
2807a6dacacSDimitry Andric void AArch64::ExtensionSet::addArchDefaults(const ArchInfo &Arch) {
2817a6dacacSDimitry Andric   LLVM_DEBUG(llvm::dbgs() << "addArchDefaults(" << Arch.Name << ")\n");
2827a6dacacSDimitry Andric   BaseArch = &Arch;
2837a6dacacSDimitry Andric 
2847a6dacacSDimitry Andric   for (const auto &E : Extensions)
2857a6dacacSDimitry Andric     if (Arch.DefaultExts.test(E.ID))
2867a6dacacSDimitry Andric       enable(E.ID);
2877a6dacacSDimitry Andric }
2887a6dacacSDimitry Andric 
289*0fca6ea1SDimitry Andric bool AArch64::ExtensionSet::parseModifier(StringRef Modifier,
290*0fca6ea1SDimitry Andric                                           const bool AllowNoDashForm) {
2917a6dacacSDimitry Andric   LLVM_DEBUG(llvm::dbgs() << "parseModifier(" << Modifier << ")\n");
2927a6dacacSDimitry Andric 
293*0fca6ea1SDimitry Andric   size_t NChars = 0;
294*0fca6ea1SDimitry Andric   // The "no-feat" form is allowed in the target attribute but nowhere else.
295*0fca6ea1SDimitry Andric   if (AllowNoDashForm && Modifier.starts_with("no-"))
296*0fca6ea1SDimitry Andric     NChars = 3;
297*0fca6ea1SDimitry Andric   else if (Modifier.starts_with("no"))
298*0fca6ea1SDimitry Andric     NChars = 2;
299*0fca6ea1SDimitry Andric   bool IsNegated = NChars != 0;
300*0fca6ea1SDimitry Andric   StringRef ArchExt = Modifier.drop_front(NChars);
3017a6dacacSDimitry Andric 
302*0fca6ea1SDimitry Andric   if (auto AE = parseArchExtension(ArchExt)) {
303*0fca6ea1SDimitry Andric     if (AE->PosTargetFeature.empty() || AE->NegTargetFeature.empty())
3047a6dacacSDimitry Andric       return false;
305*0fca6ea1SDimitry Andric     if (IsNegated)
306*0fca6ea1SDimitry Andric       disable(AE->ID);
307*0fca6ea1SDimitry Andric     else
308*0fca6ea1SDimitry Andric       enable(AE->ID);
309*0fca6ea1SDimitry Andric     return true;
310*0fca6ea1SDimitry Andric   }
311*0fca6ea1SDimitry Andric   return false;
312*0fca6ea1SDimitry Andric }
313*0fca6ea1SDimitry Andric 
314*0fca6ea1SDimitry Andric void AArch64::ExtensionSet::reconstructFromParsedFeatures(
315*0fca6ea1SDimitry Andric     const std::vector<std::string> &Features,
316*0fca6ea1SDimitry Andric     std::vector<std::string> &NonExtensions) {
317*0fca6ea1SDimitry Andric   assert(Touched.none() && "Bitset already initialized");
318*0fca6ea1SDimitry Andric   for (auto &F : Features) {
319*0fca6ea1SDimitry Andric     bool IsNegated = F[0] == '-';
320*0fca6ea1SDimitry Andric     if (auto AE = targetFeatureToExtension(F)) {
321*0fca6ea1SDimitry Andric       Touched.set(AE->ID);
322*0fca6ea1SDimitry Andric       if (IsNegated)
323*0fca6ea1SDimitry Andric         Enabled.reset(AE->ID);
324*0fca6ea1SDimitry Andric       else
325*0fca6ea1SDimitry Andric         Enabled.set(AE->ID);
326*0fca6ea1SDimitry Andric       continue;
327*0fca6ea1SDimitry Andric     }
328*0fca6ea1SDimitry Andric     NonExtensions.push_back(F);
329*0fca6ea1SDimitry Andric   }
330*0fca6ea1SDimitry Andric }
331*0fca6ea1SDimitry Andric 
332*0fca6ea1SDimitry Andric void AArch64::ExtensionSet::dump() const {
333*0fca6ea1SDimitry Andric   std::vector<StringRef> Features;
334*0fca6ea1SDimitry Andric   toLLVMFeatureList(Features);
335*0fca6ea1SDimitry Andric   for (StringRef F : Features)
336*0fca6ea1SDimitry Andric     llvm::outs() << F << " ";
337*0fca6ea1SDimitry Andric   llvm::outs() << "\n";
338*0fca6ea1SDimitry Andric }
339*0fca6ea1SDimitry Andric 
340*0fca6ea1SDimitry Andric const AArch64::ExtensionInfo &
341*0fca6ea1SDimitry Andric AArch64::getExtensionByID(AArch64::ArchExtKind ExtID) {
342*0fca6ea1SDimitry Andric   return lookupExtensionByID(ExtID);
3437a6dacacSDimitry Andric }
344