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