xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/ARMTargetDefEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- ARMTargetDefEmitter.cpp - Generate data about ARM Architectures ----===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // This tablegen backend exports information about CPUs, FPUs, architectures,
10*0fca6ea1SDimitry Andric // and features into a common format that can be used by both TargetParser and
11*0fca6ea1SDimitry Andric // the ARM and AArch64 backends.
12*0fca6ea1SDimitry Andric //
13*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
14*0fca6ea1SDimitry Andric 
15*0fca6ea1SDimitry Andric #include "llvm/ADT/StringSet.h"
16*0fca6ea1SDimitry Andric #include "llvm/Support/Format.h"
17*0fca6ea1SDimitry Andric #include "llvm/Support/FormatVariadic.h"
18*0fca6ea1SDimitry Andric #include "llvm/TableGen/Error.h"
19*0fca6ea1SDimitry Andric #include "llvm/TableGen/Record.h"
20*0fca6ea1SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
21*0fca6ea1SDimitry Andric #include <cstdint>
22*0fca6ea1SDimitry Andric #include <string>
23*0fca6ea1SDimitry Andric 
24*0fca6ea1SDimitry Andric using namespace llvm;
25*0fca6ea1SDimitry Andric 
26*0fca6ea1SDimitry Andric static void EmitARMTargetDef(RecordKeeper &RK, raw_ostream &OS) {
27*0fca6ea1SDimitry Andric   OS << "// Autogenerated by ARMTargetDefEmitter.cpp\n\n";
28*0fca6ea1SDimitry Andric 
29*0fca6ea1SDimitry Andric   // Look through all SubtargetFeature defs with the given FieldName, and
30*0fca6ea1SDimitry Andric   // collect the set of all Values that that FieldName is set to.
31*0fca6ea1SDimitry Andric   auto gatherSubtargetFeatureFieldValues = [&RK](StringRef FieldName) {
32*0fca6ea1SDimitry Andric     llvm::StringSet<> Set;
33*0fca6ea1SDimitry Andric     for (const Record *Rec : RK.getAllDerivedDefinitions("SubtargetFeature")) {
34*0fca6ea1SDimitry Andric       if (Rec->getValueAsString("FieldName") == FieldName) {
35*0fca6ea1SDimitry Andric         Set.insert(Rec->getValueAsString("Value"));
36*0fca6ea1SDimitry Andric       }
37*0fca6ea1SDimitry Andric     }
38*0fca6ea1SDimitry Andric     return Set;
39*0fca6ea1SDimitry Andric   };
40*0fca6ea1SDimitry Andric 
41*0fca6ea1SDimitry Andric   // Sort the extensions alphabetically, so they don't appear in tablegen order.
42*0fca6ea1SDimitry Andric   std::vector<Record *> SortedExtensions =
43*0fca6ea1SDimitry Andric       RK.getAllDerivedDefinitions("Extension");
44*0fca6ea1SDimitry Andric   auto Alphabetical = [](Record *A, Record *B) -> bool {
45*0fca6ea1SDimitry Andric     const auto NameA = A->getValueAsString("Name");
46*0fca6ea1SDimitry Andric     const auto NameB = B->getValueAsString("Name");
47*0fca6ea1SDimitry Andric     return NameA.compare(NameB) < 0; // A lexographically less than B
48*0fca6ea1SDimitry Andric   };
49*0fca6ea1SDimitry Andric   std::sort(SortedExtensions.begin(), SortedExtensions.end(), Alphabetical);
50*0fca6ea1SDimitry Andric 
51*0fca6ea1SDimitry Andric   // The ARMProcFamilyEnum values are initialised by SubtargetFeature defs
52*0fca6ea1SDimitry Andric   // which set the ARMProcFamily field. We can generate the enum from these defs
53*0fca6ea1SDimitry Andric   // which look like this:
54*0fca6ea1SDimitry Andric   //
55*0fca6ea1SDimitry Andric   // def ProcA5      : SubtargetFeature<"a5", "ARMProcFamily", "CortexA5",
56*0fca6ea1SDimitry Andric   //                                    "Cortex-A5 ARM processors", []>;
57*0fca6ea1SDimitry Andric   OS << "#ifndef ARM_PROCESSOR_FAMILY\n"
58*0fca6ea1SDimitry Andric      << "#define ARM_PROCESSOR_FAMILY(ENUM)\n"
59*0fca6ea1SDimitry Andric      << "#endif\n\n";
60*0fca6ea1SDimitry Andric   const StringSet<> ARMProcFamilyVals =
61*0fca6ea1SDimitry Andric       gatherSubtargetFeatureFieldValues("ARMProcFamily");
62*0fca6ea1SDimitry Andric   for (const StringRef &Family : ARMProcFamilyVals.keys())
63*0fca6ea1SDimitry Andric     OS << "ARM_PROCESSOR_FAMILY(" << Family << ")\n";
64*0fca6ea1SDimitry Andric   OS << "\n#undef ARM_PROCESSOR_FAMILY\n\n";
65*0fca6ea1SDimitry Andric 
66*0fca6ea1SDimitry Andric   OS << "#ifndef ARM_ARCHITECTURE\n"
67*0fca6ea1SDimitry Andric      << "#define ARM_ARCHITECTURE(ENUM)\n"
68*0fca6ea1SDimitry Andric      << "#endif\n\n";
69*0fca6ea1SDimitry Andric   // This should correspond to instances of the Architecture tablegen class.
70*0fca6ea1SDimitry Andric   const StringSet<> ARMArchVals = gatherSubtargetFeatureFieldValues("ARMArch");
71*0fca6ea1SDimitry Andric   for (const StringRef &Arch : ARMArchVals.keys())
72*0fca6ea1SDimitry Andric     OS << "ARM_ARCHITECTURE(" << Arch << ")\n";
73*0fca6ea1SDimitry Andric   OS << "\n#undef ARM_ARCHITECTURE\n\n";
74*0fca6ea1SDimitry Andric 
75*0fca6ea1SDimitry Andric   // Currently only AArch64 (not ARM) is handled beyond this point.
76*0fca6ea1SDimitry Andric   if (!RK.getClass("Architecture64"))
77*0fca6ea1SDimitry Andric     return;
78*0fca6ea1SDimitry Andric 
79*0fca6ea1SDimitry Andric   // Emit the ArchExtKind enum
80*0fca6ea1SDimitry Andric   OS << "#ifdef EMIT_ARCHEXTKIND_ENUM\n"
81*0fca6ea1SDimitry Andric      << "enum ArchExtKind : unsigned {\n";
82*0fca6ea1SDimitry Andric   for (const Record *Rec : SortedExtensions) {
83*0fca6ea1SDimitry Andric     auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
84*0fca6ea1SDimitry Andric     OS << "  " << AEK << ",\n";
85*0fca6ea1SDimitry Andric   }
86*0fca6ea1SDimitry Andric   OS << "  AEK_NUM_EXTENSIONS\n"
87*0fca6ea1SDimitry Andric      << "};\n"
88*0fca6ea1SDimitry Andric      << "#undef EMIT_ARCHEXTKIND_ENUM\n"
89*0fca6ea1SDimitry Andric      << "#endif // EMIT_ARCHEXTKIND_ENUM\n";
90*0fca6ea1SDimitry Andric 
91*0fca6ea1SDimitry Andric   // Emit information for each defined Extension; used to build ArmExtKind.
92*0fca6ea1SDimitry Andric   OS << "#ifdef EMIT_EXTENSIONS\n"
93*0fca6ea1SDimitry Andric      << "inline constexpr ExtensionInfo Extensions[] = {\n";
94*0fca6ea1SDimitry Andric   for (const Record *Rec : SortedExtensions) {
95*0fca6ea1SDimitry Andric     auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
96*0fca6ea1SDimitry Andric     OS << "  ";
97*0fca6ea1SDimitry Andric     OS << "{\"" << Rec->getValueAsString("UserVisibleName") << "\"";
98*0fca6ea1SDimitry Andric     if (auto Alias = Rec->getValueAsString("UserVisibleAlias"); Alias.empty())
99*0fca6ea1SDimitry Andric       OS << ", {}";
100*0fca6ea1SDimitry Andric     else
101*0fca6ea1SDimitry Andric       OS << ", \"" << Alias << "\"";
102*0fca6ea1SDimitry Andric     OS << ", AArch64::" << AEK;
103*0fca6ea1SDimitry Andric     OS << ", \"" << Rec->getValueAsString("ArchFeatureName") << "\"";
104*0fca6ea1SDimitry Andric     OS << ", \"" << Rec->getValueAsString("Desc") << "\"";
105*0fca6ea1SDimitry Andric     OS << ", \"+" << Rec->getValueAsString("Name") << "\""; // posfeature
106*0fca6ea1SDimitry Andric     OS << ", \"-" << Rec->getValueAsString("Name") << "\""; // negfeature
107*0fca6ea1SDimitry Andric     OS << "},\n";
108*0fca6ea1SDimitry Andric   };
109*0fca6ea1SDimitry Andric   OS << "};\n"
110*0fca6ea1SDimitry Andric      << "#undef EMIT_EXTENSIONS\n"
111*0fca6ea1SDimitry Andric      << "#endif // EMIT_EXTENSIONS\n"
112*0fca6ea1SDimitry Andric      << "\n";
113*0fca6ea1SDimitry Andric 
114*0fca6ea1SDimitry Andric   // Emit FMV information
115*0fca6ea1SDimitry Andric   auto FMVExts = RK.getAllDerivedDefinitionsIfDefined("FMVExtension");
116*0fca6ea1SDimitry Andric   OS << "#ifdef EMIT_FMV_INFO\n"
117*0fca6ea1SDimitry Andric      << "const std::vector<llvm::AArch64::FMVInfo>& "
118*0fca6ea1SDimitry Andric         "llvm::AArch64::getFMVInfo() {\n"
119*0fca6ea1SDimitry Andric      << "  static std::vector<FMVInfo> I;\n"
120*0fca6ea1SDimitry Andric      << "  if(I.size()) return I;\n"
121*0fca6ea1SDimitry Andric      << "  I.reserve(" << FMVExts.size() << ");\n";
122*0fca6ea1SDimitry Andric   for (const Record *Rec : FMVExts) {
123*0fca6ea1SDimitry Andric     OS << "  I.emplace_back(";
124*0fca6ea1SDimitry Andric     OS << "\"" << Rec->getValueAsString("Name") << "\"";
125*0fca6ea1SDimitry Andric     OS << ", " << Rec->getValueAsString("Bit");
126*0fca6ea1SDimitry Andric     OS << ", \"" << Rec->getValueAsString("BackendFeatures") << "\"";
127*0fca6ea1SDimitry Andric     OS << ", " << (uint64_t)Rec->getValueAsInt("Priority");
128*0fca6ea1SDimitry Andric     OS << ");\n";
129*0fca6ea1SDimitry Andric   };
130*0fca6ea1SDimitry Andric   OS << "  return I;\n"
131*0fca6ea1SDimitry Andric      << "}\n"
132*0fca6ea1SDimitry Andric      << "#undef EMIT_FMV_INFO\n"
133*0fca6ea1SDimitry Andric      << "#endif // EMIT_FMV_INFO\n"
134*0fca6ea1SDimitry Andric      << "\n";
135*0fca6ea1SDimitry Andric 
136*0fca6ea1SDimitry Andric   // Emit extension dependencies
137*0fca6ea1SDimitry Andric   OS << "#ifdef EMIT_EXTENSION_DEPENDENCIES\n"
138*0fca6ea1SDimitry Andric      << "inline constexpr ExtensionDependency ExtensionDependencies[] = {\n";
139*0fca6ea1SDimitry Andric   for (const Record *Rec : SortedExtensions) {
140*0fca6ea1SDimitry Andric     auto LaterAEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
141*0fca6ea1SDimitry Andric     for (const Record *I : Rec->getValueAsListOfDefs("Implies"))
142*0fca6ea1SDimitry Andric       if (auto EarlierAEK = I->getValueAsOptionalString("ArchExtKindSpelling"))
143*0fca6ea1SDimitry Andric         OS << "  {" << EarlierAEK->upper() << ", " << LaterAEK << "},\n";
144*0fca6ea1SDimitry Andric   }
145*0fca6ea1SDimitry Andric   // FIXME: Tablegen has the Subtarget Feature FeatureRCPC_IMMO which is implied
146*0fca6ea1SDimitry Andric   // by FeatureRCPC3 and in turn implies FeatureRCPC. The proper fix is to make
147*0fca6ea1SDimitry Andric   // FeatureRCPC_IMMO an Extension but that will expose it to the command line.
148*0fca6ea1SDimitry Andric   OS << "  {AEK_RCPC, AEK_RCPC3},\n";
149*0fca6ea1SDimitry Andric   OS << "};\n"
150*0fca6ea1SDimitry Andric      << "#undef EMIT_EXTENSION_DEPENDENCIES\n"
151*0fca6ea1SDimitry Andric      << "#endif // EMIT_EXTENSION_DEPENDENCIES\n"
152*0fca6ea1SDimitry Andric      << "\n";
153*0fca6ea1SDimitry Andric 
154*0fca6ea1SDimitry Andric   // Emit architecture information
155*0fca6ea1SDimitry Andric   OS << "#ifdef EMIT_ARCHITECTURES\n";
156*0fca6ea1SDimitry Andric 
157*0fca6ea1SDimitry Andric   // Return the C++ name of the of an ArchInfo object
158*0fca6ea1SDimitry Andric   auto ArchInfoName = [](int Major, int Minor,
159*0fca6ea1SDimitry Andric                          StringRef Profile) -> std::string {
160*0fca6ea1SDimitry Andric     return Minor == 0 ? "ARMV" + std::to_string(Major) + Profile.upper()
161*0fca6ea1SDimitry Andric                       : "ARMV" + std::to_string(Major) + "_" +
162*0fca6ea1SDimitry Andric                             std::to_string(Minor) + Profile.upper();
163*0fca6ea1SDimitry Andric   };
164*0fca6ea1SDimitry Andric 
165*0fca6ea1SDimitry Andric   auto Architectures = RK.getAllDerivedDefinitionsIfDefined("Architecture64");
166*0fca6ea1SDimitry Andric   std::vector<std::string> CppSpellings;
167*0fca6ea1SDimitry Andric   for (const Record *Rec : Architectures) {
168*0fca6ea1SDimitry Andric     const int Major = Rec->getValueAsInt("Major");
169*0fca6ea1SDimitry Andric     const int Minor = Rec->getValueAsInt("Minor");
170*0fca6ea1SDimitry Andric     const std::string ProfileLower = Rec->getValueAsString("Profile").str();
171*0fca6ea1SDimitry Andric     const std::string ProfileUpper = Rec->getValueAsString("Profile").upper();
172*0fca6ea1SDimitry Andric 
173*0fca6ea1SDimitry Andric     if (ProfileLower != "a" && ProfileLower != "r")
174*0fca6ea1SDimitry Andric       PrintFatalError(Rec->getLoc(),
175*0fca6ea1SDimitry Andric                       "error: Profile must be one of 'a' or 'r', got '" +
176*0fca6ea1SDimitry Andric                           ProfileLower + "'");
177*0fca6ea1SDimitry Andric 
178*0fca6ea1SDimitry Andric     // Name of the object in C++
179*0fca6ea1SDimitry Andric     const std::string CppSpelling = ArchInfoName(Major, Minor, ProfileUpper);
180*0fca6ea1SDimitry Andric     OS << "inline constexpr ArchInfo " << CppSpelling << " = {\n";
181*0fca6ea1SDimitry Andric     CppSpellings.push_back(CppSpelling);
182*0fca6ea1SDimitry Andric 
183*0fca6ea1SDimitry Andric     OS << llvm::format("  VersionTuple{%d, %d},\n", Major, Minor);
184*0fca6ea1SDimitry Andric     OS << llvm::format("  %sProfile,\n", ProfileUpper.c_str());
185*0fca6ea1SDimitry Andric 
186*0fca6ea1SDimitry Andric     // Name as spelled for -march.
187*0fca6ea1SDimitry Andric     if (Minor == 0)
188*0fca6ea1SDimitry Andric       OS << llvm::format("  \"armv%d-%s\",\n", Major, ProfileLower.c_str());
189*0fca6ea1SDimitry Andric     else
190*0fca6ea1SDimitry Andric       OS << llvm::format("  \"armv%d.%d-%s\",\n", Major, Minor,
191*0fca6ea1SDimitry Andric                          ProfileLower.c_str());
192*0fca6ea1SDimitry Andric 
193*0fca6ea1SDimitry Andric     // SubtargetFeature::Name, used for -target-feature. Here the "+" is added.
194*0fca6ea1SDimitry Andric     const auto TargetFeatureName = Rec->getValueAsString("Name");
195*0fca6ea1SDimitry Andric     OS << "  \"+" << TargetFeatureName << "\",\n";
196*0fca6ea1SDimitry Andric 
197*0fca6ea1SDimitry Andric     // Construct the list of default extensions
198*0fca6ea1SDimitry Andric     OS << "  (AArch64::ExtensionBitset({";
199*0fca6ea1SDimitry Andric     for (auto *E : Rec->getValueAsListOfDefs("DefaultExts")) {
200*0fca6ea1SDimitry Andric       OS << "AArch64::" << E->getValueAsString("ArchExtKindSpelling").upper()
201*0fca6ea1SDimitry Andric          << ", ";
202*0fca6ea1SDimitry Andric     }
203*0fca6ea1SDimitry Andric     OS << "}))\n";
204*0fca6ea1SDimitry Andric 
205*0fca6ea1SDimitry Andric     OS << "};\n";
206*0fca6ea1SDimitry Andric   }
207*0fca6ea1SDimitry Andric 
208*0fca6ea1SDimitry Andric   OS << "\n"
209*0fca6ea1SDimitry Andric      << "/// The set of all architectures\n"
210*0fca6ea1SDimitry Andric      << "static constexpr std::array<const ArchInfo *, " << CppSpellings.size()
211*0fca6ea1SDimitry Andric      << "> ArchInfos = {\n";
212*0fca6ea1SDimitry Andric   for (StringRef CppSpelling : CppSpellings)
213*0fca6ea1SDimitry Andric     OS << "  &" << CppSpelling << ",\n";
214*0fca6ea1SDimitry Andric   OS << "};\n";
215*0fca6ea1SDimitry Andric 
216*0fca6ea1SDimitry Andric   OS << "#undef EMIT_ARCHITECTURES\n"
217*0fca6ea1SDimitry Andric      << "#endif // EMIT_ARCHITECTURES\n"
218*0fca6ea1SDimitry Andric      << "\n";
219*0fca6ea1SDimitry Andric 
220*0fca6ea1SDimitry Andric   // Emit CPU Aliases
221*0fca6ea1SDimitry Andric   OS << "#ifdef EMIT_CPU_ALIAS\n"
222*0fca6ea1SDimitry Andric      << "inline constexpr Alias CpuAliases[] = {\n";
223*0fca6ea1SDimitry Andric 
224*0fca6ea1SDimitry Andric   llvm::StringSet<> Processors;
225*0fca6ea1SDimitry Andric   for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel"))
226*0fca6ea1SDimitry Andric     Processors.insert(Rec->getValueAsString("Name"));
227*0fca6ea1SDimitry Andric 
228*0fca6ea1SDimitry Andric   llvm::StringSet<> Aliases;
229*0fca6ea1SDimitry Andric   for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorAlias")) {
230*0fca6ea1SDimitry Andric     auto Name = Rec->getValueAsString("Name");
231*0fca6ea1SDimitry Andric     auto Alias = Rec->getValueAsString("Alias");
232*0fca6ea1SDimitry Andric     if (!Processors.contains(Alias))
233*0fca6ea1SDimitry Andric       PrintFatalError(
234*0fca6ea1SDimitry Andric           Rec, "Alias '" + Name + "' references a non-existent ProcessorModel '" + Alias + "'");
235*0fca6ea1SDimitry Andric     if (Processors.contains(Name))
236*0fca6ea1SDimitry Andric       PrintFatalError(
237*0fca6ea1SDimitry Andric           Rec, "Alias '" + Name + "' duplicates an existing ProcessorModel");
238*0fca6ea1SDimitry Andric     if (!Aliases.insert(Name).second)
239*0fca6ea1SDimitry Andric       PrintFatalError(
240*0fca6ea1SDimitry Andric           Rec, "Alias '" + Name + "' duplicates an existing ProcessorAlias");
241*0fca6ea1SDimitry Andric 
242*0fca6ea1SDimitry Andric     OS << llvm::formatv(R"(  { "{0}", "{1}" },)", Name, Alias) << '\n';
243*0fca6ea1SDimitry Andric   }
244*0fca6ea1SDimitry Andric 
245*0fca6ea1SDimitry Andric   OS << "};\n"
246*0fca6ea1SDimitry Andric      << "#undef EMIT_CPU_ALIAS\n"
247*0fca6ea1SDimitry Andric      << "#endif // EMIT_CPU_ALIAS\n"
248*0fca6ea1SDimitry Andric      << "\n";
249*0fca6ea1SDimitry Andric 
250*0fca6ea1SDimitry Andric   // Emit CPU information
251*0fca6ea1SDimitry Andric   OS << "#ifdef EMIT_CPU_INFO\n"
252*0fca6ea1SDimitry Andric      << "inline constexpr CpuInfo CpuInfos[] = {\n";
253*0fca6ea1SDimitry Andric 
254*0fca6ea1SDimitry Andric   for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel")) {
255*0fca6ea1SDimitry Andric     auto Name = Rec->getValueAsString("Name");
256*0fca6ea1SDimitry Andric     auto Features = Rec->getValueAsListOfDefs("Features");
257*0fca6ea1SDimitry Andric 
258*0fca6ea1SDimitry Andric     // "apple-latest" is backend-only, should not be accepted by TargetParser.
259*0fca6ea1SDimitry Andric     if (Name == "apple-latest")
260*0fca6ea1SDimitry Andric       continue;
261*0fca6ea1SDimitry Andric 
262*0fca6ea1SDimitry Andric     Record *Arch;
263*0fca6ea1SDimitry Andric     if (Name == "generic") {
264*0fca6ea1SDimitry Andric       // "generic" is an exception. It does not have an architecture, and there
265*0fca6ea1SDimitry Andric       // are tests that depend on e.g. -mattr=-v8.4a meaning HasV8_0aOps==false.
266*0fca6ea1SDimitry Andric       // However, in TargetParser CPUInfo, it is written as 8.0-A.
267*0fca6ea1SDimitry Andric       Arch = RK.getDef("HasV8_0aOps");
268*0fca6ea1SDimitry Andric     } else {
269*0fca6ea1SDimitry Andric       // Search for an Architecture64 in the list of features.
270*0fca6ea1SDimitry Andric       auto IsArch = [](Record *F) { return F->isSubClassOf("Architecture64"); };
271*0fca6ea1SDimitry Andric       auto ArchIter = llvm::find_if(Features, IsArch);
272*0fca6ea1SDimitry Andric       if (ArchIter == Features.end())
273*0fca6ea1SDimitry Andric         PrintFatalError(Rec, "Features must include an Architecture64.");
274*0fca6ea1SDimitry Andric       Arch = *ArchIter;
275*0fca6ea1SDimitry Andric 
276*0fca6ea1SDimitry Andric       // Check there is only one Architecture in the list.
277*0fca6ea1SDimitry Andric       if (llvm::count_if(Features, IsArch) > 1)
278*0fca6ea1SDimitry Andric         PrintFatalError(Rec, "Features has multiple Architecture64 entries");
279*0fca6ea1SDimitry Andric     }
280*0fca6ea1SDimitry Andric 
281*0fca6ea1SDimitry Andric     auto Major = Arch->getValueAsInt("Major");
282*0fca6ea1SDimitry Andric     auto Minor = Arch->getValueAsInt("Minor");
283*0fca6ea1SDimitry Andric     auto Profile = Arch->getValueAsString("Profile");
284*0fca6ea1SDimitry Andric     auto ArchInfo = ArchInfoName(Major, Minor, Profile);
285*0fca6ea1SDimitry Andric 
286*0fca6ea1SDimitry Andric     // The apple-latest alias is backend only, do not expose it to -mcpu.
287*0fca6ea1SDimitry Andric     if (Name == "apple-latest")
288*0fca6ea1SDimitry Andric       continue;
289*0fca6ea1SDimitry Andric 
290*0fca6ea1SDimitry Andric     OS << "  {\n"
291*0fca6ea1SDimitry Andric        << "    \"" << Name << "\",\n"
292*0fca6ea1SDimitry Andric        << "    " << ArchInfo << ",\n"
293*0fca6ea1SDimitry Andric        << "    AArch64::ExtensionBitset({\n";
294*0fca6ea1SDimitry Andric 
295*0fca6ea1SDimitry Andric     // Keep track of extensions we have seen
296*0fca6ea1SDimitry Andric     StringSet<> SeenExts;
297*0fca6ea1SDimitry Andric     for (auto *E : Rec->getValueAsListOfDefs("Features"))
298*0fca6ea1SDimitry Andric       // Only process subclasses of Extension
299*0fca6ea1SDimitry Andric       if (E->isSubClassOf("Extension")) {
300*0fca6ea1SDimitry Andric         const auto AEK = E->getValueAsString("ArchExtKindSpelling").upper();
301*0fca6ea1SDimitry Andric         if (!SeenExts.insert(AEK).second)
302*0fca6ea1SDimitry Andric           PrintFatalError(Rec, "feature already added: " + E->getName());
303*0fca6ea1SDimitry Andric         OS << "      AArch64::" << AEK << ",\n";
304*0fca6ea1SDimitry Andric       }
305*0fca6ea1SDimitry Andric     OS << "    })\n"
306*0fca6ea1SDimitry Andric        << "  },\n";
307*0fca6ea1SDimitry Andric   }
308*0fca6ea1SDimitry Andric   OS << "};\n";
309*0fca6ea1SDimitry Andric 
310*0fca6ea1SDimitry Andric   OS << "#undef EMIT_CPU_INFO\n"
311*0fca6ea1SDimitry Andric      << "#endif // EMIT_CPU_INFO\n"
312*0fca6ea1SDimitry Andric      << "\n";
313*0fca6ea1SDimitry Andric }
314*0fca6ea1SDimitry Andric 
315*0fca6ea1SDimitry Andric static TableGen::Emitter::Opt
316*0fca6ea1SDimitry Andric     X("gen-arm-target-def", EmitARMTargetDef,
317*0fca6ea1SDimitry Andric       "Generate the ARM or AArch64 Architecture information header.");
318