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