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