xref: /freebsd-src/contrib/llvm-project/llvm/utils/TableGen/ARMTargetDefEmitter.cpp (revision 62987288060ff68c817b7056815aa9fb8ba8ecd7)
10fca6ea1SDimitry Andric //===- ARMTargetDefEmitter.cpp - Generate data about ARM Architectures ----===//
20fca6ea1SDimitry Andric //
30fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60fca6ea1SDimitry Andric //
70fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
80fca6ea1SDimitry Andric //
90fca6ea1SDimitry Andric // This tablegen backend exports information about CPUs, FPUs, architectures,
100fca6ea1SDimitry Andric // and features into a common format that can be used by both TargetParser and
110fca6ea1SDimitry Andric // the ARM and AArch64 backends.
120fca6ea1SDimitry Andric //
130fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
140fca6ea1SDimitry Andric 
150fca6ea1SDimitry Andric #include "llvm/ADT/StringSet.h"
160fca6ea1SDimitry Andric #include "llvm/Support/Format.h"
170fca6ea1SDimitry Andric #include "llvm/Support/FormatVariadic.h"
180fca6ea1SDimitry Andric #include "llvm/TableGen/Error.h"
190fca6ea1SDimitry Andric #include "llvm/TableGen/Record.h"
200fca6ea1SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
210fca6ea1SDimitry Andric #include <cstdint>
22*62987288SDimitry Andric #include <set>
230fca6ea1SDimitry Andric #include <string>
240fca6ea1SDimitry Andric 
250fca6ea1SDimitry Andric using namespace llvm;
260fca6ea1SDimitry Andric 
27*62987288SDimitry Andric /// Collect the full set of implied features for a SubtargetFeature.
28*62987288SDimitry Andric static void CollectImpliedFeatures(std::set<Record *> &SeenFeats, Record *Rec) {
29*62987288SDimitry Andric   assert(Rec->isSubClassOf("SubtargetFeature") &&
30*62987288SDimitry Andric          "Rec is not a SubtargetFeature");
31*62987288SDimitry Andric 
32*62987288SDimitry Andric   SeenFeats.insert(Rec);
33*62987288SDimitry Andric   for (Record *Implied : Rec->getValueAsListOfDefs("Implies"))
34*62987288SDimitry Andric     CollectImpliedFeatures(SeenFeats, Implied);
35*62987288SDimitry Andric }
36*62987288SDimitry Andric 
37*62987288SDimitry Andric static void CheckFeatureTree(Record *Root) {
38*62987288SDimitry Andric   std::set<Record *> SeenFeats;
39*62987288SDimitry Andric   CollectImpliedFeatures(SeenFeats, Root);
40*62987288SDimitry Andric 
41*62987288SDimitry Andric   // Check that each of the mandatory (implied) features which is an
42*62987288SDimitry Andric   // ExtensionWithMArch is also enabled by default.
43*62987288SDimitry Andric   auto DefaultExtsVec = Root->getValueAsListOfDefs("DefaultExts");
44*62987288SDimitry Andric   std::set<Record *> DefaultExts{DefaultExtsVec.begin(), DefaultExtsVec.end()};
45*62987288SDimitry Andric   for (auto *Feat : SeenFeats) {
46*62987288SDimitry Andric     if (Feat->isSubClassOf("ExtensionWithMArch") && !DefaultExts.count(Feat))
47*62987288SDimitry Andric       PrintFatalError(Root->getLoc(),
48*62987288SDimitry Andric                       "ExtensionWithMArch " + Feat->getName() +
49*62987288SDimitry Andric                           " is implied (mandatory) as a SubtargetFeature, but "
50*62987288SDimitry Andric                           "is not present in DefaultExts");
51*62987288SDimitry Andric   }
52*62987288SDimitry Andric }
53*62987288SDimitry Andric 
540fca6ea1SDimitry Andric static void EmitARMTargetDef(RecordKeeper &RK, raw_ostream &OS) {
550fca6ea1SDimitry Andric   OS << "// Autogenerated by ARMTargetDefEmitter.cpp\n\n";
560fca6ea1SDimitry Andric 
570fca6ea1SDimitry Andric   // Look through all SubtargetFeature defs with the given FieldName, and
580fca6ea1SDimitry Andric   // collect the set of all Values that that FieldName is set to.
590fca6ea1SDimitry Andric   auto gatherSubtargetFeatureFieldValues = [&RK](StringRef FieldName) {
600fca6ea1SDimitry Andric     llvm::StringSet<> Set;
610fca6ea1SDimitry Andric     for (const Record *Rec : RK.getAllDerivedDefinitions("SubtargetFeature")) {
620fca6ea1SDimitry Andric       if (Rec->getValueAsString("FieldName") == FieldName) {
630fca6ea1SDimitry Andric         Set.insert(Rec->getValueAsString("Value"));
640fca6ea1SDimitry Andric       }
650fca6ea1SDimitry Andric     }
660fca6ea1SDimitry Andric     return Set;
670fca6ea1SDimitry Andric   };
680fca6ea1SDimitry Andric 
690fca6ea1SDimitry Andric   // Sort the extensions alphabetically, so they don't appear in tablegen order.
700fca6ea1SDimitry Andric   std::vector<Record *> SortedExtensions =
710fca6ea1SDimitry Andric       RK.getAllDerivedDefinitions("Extension");
720fca6ea1SDimitry Andric   auto Alphabetical = [](Record *A, Record *B) -> bool {
730fca6ea1SDimitry Andric     const auto NameA = A->getValueAsString("Name");
740fca6ea1SDimitry Andric     const auto NameB = B->getValueAsString("Name");
750fca6ea1SDimitry Andric     return NameA.compare(NameB) < 0; // A lexographically less than B
760fca6ea1SDimitry Andric   };
770fca6ea1SDimitry Andric   std::sort(SortedExtensions.begin(), SortedExtensions.end(), Alphabetical);
780fca6ea1SDimitry Andric 
790fca6ea1SDimitry Andric   // The ARMProcFamilyEnum values are initialised by SubtargetFeature defs
800fca6ea1SDimitry Andric   // which set the ARMProcFamily field. We can generate the enum from these defs
810fca6ea1SDimitry Andric   // which look like this:
820fca6ea1SDimitry Andric   //
830fca6ea1SDimitry Andric   // def ProcA5      : SubtargetFeature<"a5", "ARMProcFamily", "CortexA5",
840fca6ea1SDimitry Andric   //                                    "Cortex-A5 ARM processors", []>;
850fca6ea1SDimitry Andric   OS << "#ifndef ARM_PROCESSOR_FAMILY\n"
860fca6ea1SDimitry Andric      << "#define ARM_PROCESSOR_FAMILY(ENUM)\n"
870fca6ea1SDimitry Andric      << "#endif\n\n";
880fca6ea1SDimitry Andric   const StringSet<> ARMProcFamilyVals =
890fca6ea1SDimitry Andric       gatherSubtargetFeatureFieldValues("ARMProcFamily");
900fca6ea1SDimitry Andric   for (const StringRef &Family : ARMProcFamilyVals.keys())
910fca6ea1SDimitry Andric     OS << "ARM_PROCESSOR_FAMILY(" << Family << ")\n";
920fca6ea1SDimitry Andric   OS << "\n#undef ARM_PROCESSOR_FAMILY\n\n";
930fca6ea1SDimitry Andric 
940fca6ea1SDimitry Andric   OS << "#ifndef ARM_ARCHITECTURE\n"
950fca6ea1SDimitry Andric      << "#define ARM_ARCHITECTURE(ENUM)\n"
960fca6ea1SDimitry Andric      << "#endif\n\n";
970fca6ea1SDimitry Andric   // This should correspond to instances of the Architecture tablegen class.
980fca6ea1SDimitry Andric   const StringSet<> ARMArchVals = gatherSubtargetFeatureFieldValues("ARMArch");
990fca6ea1SDimitry Andric   for (const StringRef &Arch : ARMArchVals.keys())
1000fca6ea1SDimitry Andric     OS << "ARM_ARCHITECTURE(" << Arch << ")\n";
1010fca6ea1SDimitry Andric   OS << "\n#undef ARM_ARCHITECTURE\n\n";
1020fca6ea1SDimitry Andric 
1030fca6ea1SDimitry Andric   // Currently only AArch64 (not ARM) is handled beyond this point.
1040fca6ea1SDimitry Andric   if (!RK.getClass("Architecture64"))
1050fca6ea1SDimitry Andric     return;
1060fca6ea1SDimitry Andric 
1070fca6ea1SDimitry Andric   // Emit the ArchExtKind enum
1080fca6ea1SDimitry Andric   OS << "#ifdef EMIT_ARCHEXTKIND_ENUM\n"
1090fca6ea1SDimitry Andric      << "enum ArchExtKind : unsigned {\n";
1100fca6ea1SDimitry Andric   for (const Record *Rec : SortedExtensions) {
1110fca6ea1SDimitry Andric     auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
1120fca6ea1SDimitry Andric     OS << "  " << AEK << ",\n";
1130fca6ea1SDimitry Andric   }
1140fca6ea1SDimitry Andric   OS << "  AEK_NUM_EXTENSIONS\n"
1150fca6ea1SDimitry Andric      << "};\n"
1160fca6ea1SDimitry Andric      << "#undef EMIT_ARCHEXTKIND_ENUM\n"
1170fca6ea1SDimitry Andric      << "#endif // EMIT_ARCHEXTKIND_ENUM\n";
1180fca6ea1SDimitry Andric 
1190fca6ea1SDimitry Andric   // Emit information for each defined Extension; used to build ArmExtKind.
1200fca6ea1SDimitry Andric   OS << "#ifdef EMIT_EXTENSIONS\n"
1210fca6ea1SDimitry Andric      << "inline constexpr ExtensionInfo Extensions[] = {\n";
1220fca6ea1SDimitry Andric   for (const Record *Rec : SortedExtensions) {
1230fca6ea1SDimitry Andric     auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
1240fca6ea1SDimitry Andric     OS << "  ";
1250fca6ea1SDimitry Andric     OS << "{\"" << Rec->getValueAsString("UserVisibleName") << "\"";
1260fca6ea1SDimitry Andric     if (auto Alias = Rec->getValueAsString("UserVisibleAlias"); Alias.empty())
1270fca6ea1SDimitry Andric       OS << ", {}";
1280fca6ea1SDimitry Andric     else
1290fca6ea1SDimitry Andric       OS << ", \"" << Alias << "\"";
1300fca6ea1SDimitry Andric     OS << ", AArch64::" << AEK;
1310fca6ea1SDimitry Andric     OS << ", \"" << Rec->getValueAsString("ArchFeatureName") << "\"";
1320fca6ea1SDimitry Andric     OS << ", \"" << Rec->getValueAsString("Desc") << "\"";
1330fca6ea1SDimitry Andric     OS << ", \"+" << Rec->getValueAsString("Name") << "\""; // posfeature
1340fca6ea1SDimitry Andric     OS << ", \"-" << Rec->getValueAsString("Name") << "\""; // negfeature
1350fca6ea1SDimitry Andric     OS << "},\n";
1360fca6ea1SDimitry Andric   };
1370fca6ea1SDimitry Andric   OS << "};\n"
1380fca6ea1SDimitry Andric      << "#undef EMIT_EXTENSIONS\n"
1390fca6ea1SDimitry Andric      << "#endif // EMIT_EXTENSIONS\n"
1400fca6ea1SDimitry Andric      << "\n";
1410fca6ea1SDimitry Andric 
1420fca6ea1SDimitry Andric   // Emit FMV information
1430fca6ea1SDimitry Andric   auto FMVExts = RK.getAllDerivedDefinitionsIfDefined("FMVExtension");
1440fca6ea1SDimitry Andric   OS << "#ifdef EMIT_FMV_INFO\n"
1450fca6ea1SDimitry Andric      << "const std::vector<llvm::AArch64::FMVInfo>& "
1460fca6ea1SDimitry Andric         "llvm::AArch64::getFMVInfo() {\n"
1470fca6ea1SDimitry Andric      << "  static std::vector<FMVInfo> I;\n"
1480fca6ea1SDimitry Andric      << "  if(I.size()) return I;\n"
1490fca6ea1SDimitry Andric      << "  I.reserve(" << FMVExts.size() << ");\n";
1500fca6ea1SDimitry Andric   for (const Record *Rec : FMVExts) {
1510fca6ea1SDimitry Andric     OS << "  I.emplace_back(";
1520fca6ea1SDimitry Andric     OS << "\"" << Rec->getValueAsString("Name") << "\"";
1530fca6ea1SDimitry Andric     OS << ", " << Rec->getValueAsString("Bit");
1540fca6ea1SDimitry Andric     OS << ", \"" << Rec->getValueAsString("BackendFeatures") << "\"";
1550fca6ea1SDimitry Andric     OS << ", " << (uint64_t)Rec->getValueAsInt("Priority");
1560fca6ea1SDimitry Andric     OS << ");\n";
1570fca6ea1SDimitry Andric   };
1580fca6ea1SDimitry Andric   OS << "  return I;\n"
1590fca6ea1SDimitry Andric      << "}\n"
1600fca6ea1SDimitry Andric      << "#undef EMIT_FMV_INFO\n"
1610fca6ea1SDimitry Andric      << "#endif // EMIT_FMV_INFO\n"
1620fca6ea1SDimitry Andric      << "\n";
1630fca6ea1SDimitry Andric 
1640fca6ea1SDimitry Andric   // Emit extension dependencies
1650fca6ea1SDimitry Andric   OS << "#ifdef EMIT_EXTENSION_DEPENDENCIES\n"
1660fca6ea1SDimitry Andric      << "inline constexpr ExtensionDependency ExtensionDependencies[] = {\n";
1670fca6ea1SDimitry Andric   for (const Record *Rec : SortedExtensions) {
1680fca6ea1SDimitry Andric     auto LaterAEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
1690fca6ea1SDimitry Andric     for (const Record *I : Rec->getValueAsListOfDefs("Implies"))
1700fca6ea1SDimitry Andric       if (auto EarlierAEK = I->getValueAsOptionalString("ArchExtKindSpelling"))
1710fca6ea1SDimitry Andric         OS << "  {" << EarlierAEK->upper() << ", " << LaterAEK << "},\n";
1720fca6ea1SDimitry Andric   }
1730fca6ea1SDimitry Andric   // FIXME: Tablegen has the Subtarget Feature FeatureRCPC_IMMO which is implied
1740fca6ea1SDimitry Andric   // by FeatureRCPC3 and in turn implies FeatureRCPC. The proper fix is to make
1750fca6ea1SDimitry Andric   // FeatureRCPC_IMMO an Extension but that will expose it to the command line.
1760fca6ea1SDimitry Andric   OS << "  {AEK_RCPC, AEK_RCPC3},\n";
1770fca6ea1SDimitry Andric   OS << "};\n"
1780fca6ea1SDimitry Andric      << "#undef EMIT_EXTENSION_DEPENDENCIES\n"
1790fca6ea1SDimitry Andric      << "#endif // EMIT_EXTENSION_DEPENDENCIES\n"
1800fca6ea1SDimitry Andric      << "\n";
1810fca6ea1SDimitry Andric 
1820fca6ea1SDimitry Andric   // Emit architecture information
1830fca6ea1SDimitry Andric   OS << "#ifdef EMIT_ARCHITECTURES\n";
1840fca6ea1SDimitry Andric 
1850fca6ea1SDimitry Andric   // Return the C++ name of the of an ArchInfo object
1860fca6ea1SDimitry Andric   auto ArchInfoName = [](int Major, int Minor,
1870fca6ea1SDimitry Andric                          StringRef Profile) -> std::string {
1880fca6ea1SDimitry Andric     return Minor == 0 ? "ARMV" + std::to_string(Major) + Profile.upper()
1890fca6ea1SDimitry Andric                       : "ARMV" + std::to_string(Major) + "_" +
1900fca6ea1SDimitry Andric                             std::to_string(Minor) + Profile.upper();
1910fca6ea1SDimitry Andric   };
1920fca6ea1SDimitry Andric 
1930fca6ea1SDimitry Andric   auto Architectures = RK.getAllDerivedDefinitionsIfDefined("Architecture64");
1940fca6ea1SDimitry Andric   std::vector<std::string> CppSpellings;
1950fca6ea1SDimitry Andric   for (const Record *Rec : Architectures) {
1960fca6ea1SDimitry Andric     const int Major = Rec->getValueAsInt("Major");
1970fca6ea1SDimitry Andric     const int Minor = Rec->getValueAsInt("Minor");
1980fca6ea1SDimitry Andric     const std::string ProfileLower = Rec->getValueAsString("Profile").str();
1990fca6ea1SDimitry Andric     const std::string ProfileUpper = Rec->getValueAsString("Profile").upper();
2000fca6ea1SDimitry Andric 
2010fca6ea1SDimitry Andric     if (ProfileLower != "a" && ProfileLower != "r")
2020fca6ea1SDimitry Andric       PrintFatalError(Rec->getLoc(),
2030fca6ea1SDimitry Andric                       "error: Profile must be one of 'a' or 'r', got '" +
2040fca6ea1SDimitry Andric                           ProfileLower + "'");
2050fca6ea1SDimitry Andric 
2060fca6ea1SDimitry Andric     // Name of the object in C++
2070fca6ea1SDimitry Andric     const std::string CppSpelling = ArchInfoName(Major, Minor, ProfileUpper);
2080fca6ea1SDimitry Andric     OS << "inline constexpr ArchInfo " << CppSpelling << " = {\n";
2090fca6ea1SDimitry Andric     CppSpellings.push_back(CppSpelling);
2100fca6ea1SDimitry Andric 
2110fca6ea1SDimitry Andric     OS << llvm::format("  VersionTuple{%d, %d},\n", Major, Minor);
2120fca6ea1SDimitry Andric     OS << llvm::format("  %sProfile,\n", ProfileUpper.c_str());
2130fca6ea1SDimitry Andric 
2140fca6ea1SDimitry Andric     // Name as spelled for -march.
2150fca6ea1SDimitry Andric     if (Minor == 0)
2160fca6ea1SDimitry Andric       OS << llvm::format("  \"armv%d-%s\",\n", Major, ProfileLower.c_str());
2170fca6ea1SDimitry Andric     else
2180fca6ea1SDimitry Andric       OS << llvm::format("  \"armv%d.%d-%s\",\n", Major, Minor,
2190fca6ea1SDimitry Andric                          ProfileLower.c_str());
2200fca6ea1SDimitry Andric 
2210fca6ea1SDimitry Andric     // SubtargetFeature::Name, used for -target-feature. Here the "+" is added.
2220fca6ea1SDimitry Andric     const auto TargetFeatureName = Rec->getValueAsString("Name");
2230fca6ea1SDimitry Andric     OS << "  \"+" << TargetFeatureName << "\",\n";
2240fca6ea1SDimitry Andric 
2250fca6ea1SDimitry Andric     // Construct the list of default extensions
2260fca6ea1SDimitry Andric     OS << "  (AArch64::ExtensionBitset({";
2270fca6ea1SDimitry Andric     for (auto *E : Rec->getValueAsListOfDefs("DefaultExts")) {
2280fca6ea1SDimitry Andric       OS << "AArch64::" << E->getValueAsString("ArchExtKindSpelling").upper()
2290fca6ea1SDimitry Andric          << ", ";
2300fca6ea1SDimitry Andric     }
2310fca6ea1SDimitry Andric     OS << "}))\n";
2320fca6ea1SDimitry Andric 
2330fca6ea1SDimitry Andric     OS << "};\n";
2340fca6ea1SDimitry Andric   }
2350fca6ea1SDimitry Andric 
2360fca6ea1SDimitry Andric   OS << "\n"
2370fca6ea1SDimitry Andric      << "/// The set of all architectures\n"
2380fca6ea1SDimitry Andric      << "static constexpr std::array<const ArchInfo *, " << CppSpellings.size()
2390fca6ea1SDimitry Andric      << "> ArchInfos = {\n";
2400fca6ea1SDimitry Andric   for (StringRef CppSpelling : CppSpellings)
2410fca6ea1SDimitry Andric     OS << "  &" << CppSpelling << ",\n";
2420fca6ea1SDimitry Andric   OS << "};\n";
2430fca6ea1SDimitry Andric 
2440fca6ea1SDimitry Andric   OS << "#undef EMIT_ARCHITECTURES\n"
2450fca6ea1SDimitry Andric      << "#endif // EMIT_ARCHITECTURES\n"
2460fca6ea1SDimitry Andric      << "\n";
2470fca6ea1SDimitry Andric 
2480fca6ea1SDimitry Andric   // Emit CPU Aliases
2490fca6ea1SDimitry Andric   OS << "#ifdef EMIT_CPU_ALIAS\n"
2500fca6ea1SDimitry Andric      << "inline constexpr Alias CpuAliases[] = {\n";
2510fca6ea1SDimitry Andric 
2520fca6ea1SDimitry Andric   llvm::StringSet<> Processors;
2530fca6ea1SDimitry Andric   for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel"))
2540fca6ea1SDimitry Andric     Processors.insert(Rec->getValueAsString("Name"));
2550fca6ea1SDimitry Andric 
2560fca6ea1SDimitry Andric   llvm::StringSet<> Aliases;
2570fca6ea1SDimitry Andric   for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorAlias")) {
2580fca6ea1SDimitry Andric     auto Name = Rec->getValueAsString("Name");
2590fca6ea1SDimitry Andric     auto Alias = Rec->getValueAsString("Alias");
2600fca6ea1SDimitry Andric     if (!Processors.contains(Alias))
2610fca6ea1SDimitry Andric       PrintFatalError(
2620fca6ea1SDimitry Andric           Rec, "Alias '" + Name + "' references a non-existent ProcessorModel '" + Alias + "'");
2630fca6ea1SDimitry Andric     if (Processors.contains(Name))
2640fca6ea1SDimitry Andric       PrintFatalError(
2650fca6ea1SDimitry Andric           Rec, "Alias '" + Name + "' duplicates an existing ProcessorModel");
2660fca6ea1SDimitry Andric     if (!Aliases.insert(Name).second)
2670fca6ea1SDimitry Andric       PrintFatalError(
2680fca6ea1SDimitry Andric           Rec, "Alias '" + Name + "' duplicates an existing ProcessorAlias");
2690fca6ea1SDimitry Andric 
2700fca6ea1SDimitry Andric     OS << llvm::formatv(R"(  { "{0}", "{1}" },)", Name, Alias) << '\n';
2710fca6ea1SDimitry Andric   }
2720fca6ea1SDimitry Andric 
2730fca6ea1SDimitry Andric   OS << "};\n"
2740fca6ea1SDimitry Andric      << "#undef EMIT_CPU_ALIAS\n"
2750fca6ea1SDimitry Andric      << "#endif // EMIT_CPU_ALIAS\n"
2760fca6ea1SDimitry Andric      << "\n";
2770fca6ea1SDimitry Andric 
2780fca6ea1SDimitry Andric   // Emit CPU information
2790fca6ea1SDimitry Andric   OS << "#ifdef EMIT_CPU_INFO\n"
2800fca6ea1SDimitry Andric      << "inline constexpr CpuInfo CpuInfos[] = {\n";
2810fca6ea1SDimitry Andric 
2820fca6ea1SDimitry Andric   for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel")) {
2830fca6ea1SDimitry Andric     auto Name = Rec->getValueAsString("Name");
2840fca6ea1SDimitry Andric     auto Features = Rec->getValueAsListOfDefs("Features");
2850fca6ea1SDimitry Andric 
2860fca6ea1SDimitry Andric     // "apple-latest" is backend-only, should not be accepted by TargetParser.
2870fca6ea1SDimitry Andric     if (Name == "apple-latest")
2880fca6ea1SDimitry Andric       continue;
2890fca6ea1SDimitry Andric 
2900fca6ea1SDimitry Andric     Record *Arch;
2910fca6ea1SDimitry Andric     if (Name == "generic") {
2920fca6ea1SDimitry Andric       // "generic" is an exception. It does not have an architecture, and there
2930fca6ea1SDimitry Andric       // are tests that depend on e.g. -mattr=-v8.4a meaning HasV8_0aOps==false.
2940fca6ea1SDimitry Andric       // However, in TargetParser CPUInfo, it is written as 8.0-A.
2950fca6ea1SDimitry Andric       Arch = RK.getDef("HasV8_0aOps");
2960fca6ea1SDimitry Andric     } else {
2970fca6ea1SDimitry Andric       // Search for an Architecture64 in the list of features.
2980fca6ea1SDimitry Andric       auto IsArch = [](Record *F) { return F->isSubClassOf("Architecture64"); };
2990fca6ea1SDimitry Andric       auto ArchIter = llvm::find_if(Features, IsArch);
3000fca6ea1SDimitry Andric       if (ArchIter == Features.end())
3010fca6ea1SDimitry Andric         PrintFatalError(Rec, "Features must include an Architecture64.");
3020fca6ea1SDimitry Andric       Arch = *ArchIter;
3030fca6ea1SDimitry Andric 
3040fca6ea1SDimitry Andric       // Check there is only one Architecture in the list.
3050fca6ea1SDimitry Andric       if (llvm::count_if(Features, IsArch) > 1)
3060fca6ea1SDimitry Andric         PrintFatalError(Rec, "Features has multiple Architecture64 entries");
3070fca6ea1SDimitry Andric     }
3080fca6ea1SDimitry Andric 
3090fca6ea1SDimitry Andric     auto Major = Arch->getValueAsInt("Major");
3100fca6ea1SDimitry Andric     auto Minor = Arch->getValueAsInt("Minor");
3110fca6ea1SDimitry Andric     auto Profile = Arch->getValueAsString("Profile");
3120fca6ea1SDimitry Andric     auto ArchInfo = ArchInfoName(Major, Minor, Profile);
3130fca6ea1SDimitry Andric 
314*62987288SDimitry Andric     CheckFeatureTree(Arch);
3150fca6ea1SDimitry Andric 
3160fca6ea1SDimitry Andric     OS << "  {\n"
3170fca6ea1SDimitry Andric        << "    \"" << Name << "\",\n"
3180fca6ea1SDimitry Andric        << "    " << ArchInfo << ",\n"
3190fca6ea1SDimitry Andric        << "    AArch64::ExtensionBitset({\n";
3200fca6ea1SDimitry Andric 
3210fca6ea1SDimitry Andric     // Keep track of extensions we have seen
3220fca6ea1SDimitry Andric     StringSet<> SeenExts;
3230fca6ea1SDimitry Andric     for (auto *E : Rec->getValueAsListOfDefs("Features"))
3240fca6ea1SDimitry Andric       // Only process subclasses of Extension
3250fca6ea1SDimitry Andric       if (E->isSubClassOf("Extension")) {
3260fca6ea1SDimitry Andric         const auto AEK = E->getValueAsString("ArchExtKindSpelling").upper();
3270fca6ea1SDimitry Andric         if (!SeenExts.insert(AEK).second)
3280fca6ea1SDimitry Andric           PrintFatalError(Rec, "feature already added: " + E->getName());
3290fca6ea1SDimitry Andric         OS << "      AArch64::" << AEK << ",\n";
3300fca6ea1SDimitry Andric       }
3310fca6ea1SDimitry Andric     OS << "    })\n"
3320fca6ea1SDimitry Andric        << "  },\n";
3330fca6ea1SDimitry Andric   }
3340fca6ea1SDimitry Andric   OS << "};\n";
3350fca6ea1SDimitry Andric 
3360fca6ea1SDimitry Andric   OS << "#undef EMIT_CPU_INFO\n"
3370fca6ea1SDimitry Andric      << "#endif // EMIT_CPU_INFO\n"
3380fca6ea1SDimitry Andric      << "\n";
3390fca6ea1SDimitry Andric }
3400fca6ea1SDimitry Andric 
3410fca6ea1SDimitry Andric static TableGen::Emitter::Opt
3420fca6ea1SDimitry Andric     X("gen-arm-target-def", EmitARMTargetDef,
3430fca6ea1SDimitry Andric       "Generate the ARM or AArch64 Architecture information header.");
344