Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp
213799 views
//===- ARMTargetDefEmitter.cpp - Generate data about ARM Architectures ----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This tablegen backend exports information about CPUs, FPUs, architectures,9// and features into a common format that can be used by both TargetParser and10// the ARM and AArch64 backends.11//12//===----------------------------------------------------------------------===//1314#include "llvm/ADT/DenseMap.h"15#include "llvm/ADT/StringSet.h"16#include "llvm/Support/Format.h"17#include "llvm/Support/FormatVariadic.h"18#include "llvm/TableGen/Error.h"19#include "llvm/TableGen/Record.h"20#include "llvm/TableGen/TableGenBackend.h"21#include <set>22#include <string>2324using namespace llvm;2526/// Collect the full set of implied features for a SubtargetFeature.27static void collectImpliedFeatures(std::set<const Record *> &SeenFeats,28const Record *Rec) {29assert(Rec->isSubClassOf("SubtargetFeature") &&30"Rec is not a SubtargetFeature");3132SeenFeats.insert(Rec);33for (const Record *Implied : Rec->getValueAsListOfDefs("Implies"))34collectImpliedFeatures(SeenFeats, Implied);35}3637static void checkFeatureTree(const Record *Root) {38std::set<const Record *> SeenFeats;39collectImpliedFeatures(SeenFeats, Root);4041// Check that each of the mandatory (implied) features which is an42// ExtensionWithMArch is also enabled by default.43auto DefaultExtsVec = Root->getValueAsListOfDefs("DefaultExts");44std::set<const Record *> DefaultExts{DefaultExtsVec.begin(),45DefaultExtsVec.end()};46for (const Record *Feat : SeenFeats) {47if (Feat->isSubClassOf("ExtensionWithMArch") && !DefaultExts.count(Feat))48PrintFatalError(Root->getLoc(),49"ExtensionWithMArch " + Feat->getName() +50" is implied (mandatory) as a SubtargetFeature, but "51"is not present in DefaultExts");52}53}5455static void emitARMTargetDef(const RecordKeeper &RK, raw_ostream &OS) {56OS << "// Autogenerated by ARMTargetDefEmitter.cpp\n\n";5758// Look through all SubtargetFeature defs with the given FieldName, and59// collect the set of all Values that that FieldName is set to.60auto GatherSubtargetFeatureFieldValues = [&RK](StringRef FieldName) {61llvm::StringSet<> Set;62for (const Record *Rec : RK.getAllDerivedDefinitions("SubtargetFeature")) {63if (Rec->getValueAsString("FieldName") == FieldName) {64Set.insert(Rec->getValueAsString("Value"));65}66}67return Set;68};6970// Sort the extensions alphabetically, so they don't appear in tablegen order.71std::vector<const Record *> SortedExtensions =72RK.getAllDerivedDefinitions("Extension");73auto Alphabetical = [](const Record *A, const Record *B) -> bool {74const auto NameA = A->getValueAsString("Name");75const auto NameB = B->getValueAsString("Name");76return NameA.compare(NameB) < 0; // A lexographically less than B77};78sort(SortedExtensions, Alphabetical);7980// Cache Extension records for quick lookup.81DenseMap<StringRef, const Record *> ExtensionMap;82for (const Record *Rec : SortedExtensions) {83auto Name = Rec->getValueAsString("UserVisibleName");84if (Name.empty())85Name = Rec->getValueAsString("Name");86ExtensionMap[Name] = Rec;87}8889// The ARMProcFamilyEnum values are initialised by SubtargetFeature defs90// which set the ARMProcFamily field. We can generate the enum from these defs91// which look like this:92//93// def ProcA5 : SubtargetFeature<"a5", "ARMProcFamily", "CortexA5",94// "Cortex-A5 ARM processors", []>;95OS << "#ifndef ARM_PROCESSOR_FAMILY\n"96<< "#define ARM_PROCESSOR_FAMILY(ENUM)\n"97<< "#endif\n\n";98const StringSet<> ARMProcFamilyVals =99GatherSubtargetFeatureFieldValues("ARMProcFamily");100for (const StringRef &Family : ARMProcFamilyVals.keys())101OS << "ARM_PROCESSOR_FAMILY(" << Family << ")\n";102OS << "\n#undef ARM_PROCESSOR_FAMILY\n\n";103104OS << "#ifndef ARM_ARCHITECTURE\n"105<< "#define ARM_ARCHITECTURE(ENUM)\n"106<< "#endif\n\n";107// This should correspond to instances of the Architecture tablegen class.108const StringSet<> ARMArchVals = GatherSubtargetFeatureFieldValues("ARMArch");109for (const StringRef &Arch : ARMArchVals.keys())110OS << "ARM_ARCHITECTURE(" << Arch << ")\n";111OS << "\n#undef ARM_ARCHITECTURE\n\n";112113// Currently only AArch64 (not ARM) is handled beyond this point.114if (!RK.getClass("Architecture64"))115return;116117// Emit the ArchExtKind enum118OS << "#ifdef EMIT_ARCHEXTKIND_ENUM\n"119<< "enum ArchExtKind : unsigned {\n";120for (const Record *Rec : SortedExtensions) {121auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();122OS << " " << AEK << ",\n";123}124OS << " AEK_NUM_EXTENSIONS\n"125<< "};\n"126<< "#undef EMIT_ARCHEXTKIND_ENUM\n"127<< "#endif // EMIT_ARCHEXTKIND_ENUM\n";128129// Emit information for each defined Extension; used to build ArmExtKind.130OS << "#ifdef EMIT_EXTENSIONS\n"131<< "inline constexpr ExtensionInfo Extensions[] = {\n";132for (const Record *Rec : SortedExtensions) {133auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();134OS << " ";135OS << "{\"" << Rec->getValueAsString("UserVisibleName") << "\"";136if (auto Alias = Rec->getValueAsString("UserVisibleAlias"); Alias.empty())137OS << ", {}";138else139OS << ", \"" << Alias << "\"";140OS << ", AArch64::" << AEK;141OS << ", \"" << Rec->getValueAsString("ArchFeatureName") << "\"";142OS << ", \"" << Rec->getValueAsString("Desc") << "\"";143OS << ", \"+" << Rec->getValueAsString("Name") << "\""; // posfeature144OS << ", \"-" << Rec->getValueAsString("Name") << "\""; // negfeature145OS << "},\n";146};147OS << "};\n"148<< "#undef EMIT_EXTENSIONS\n"149<< "#endif // EMIT_EXTENSIONS\n"150<< "\n";151152// Emit FMV information153auto FMVExts = RK.getAllDerivedDefinitionsIfDefined("FMVExtension");154OS << "#ifdef EMIT_FMV_INFO\n"155<< "const std::vector<llvm::AArch64::FMVInfo>& "156"llvm::AArch64::getFMVInfo() {\n"157<< " static std::vector<FMVInfo> I;\n"158<< " if(I.size()) return I;\n"159<< " I.reserve(" << FMVExts.size() << ");\n";160for (const Record *Rec : FMVExts) {161OS << " I.emplace_back(";162OS << "\"" << Rec->getValueAsString("Name") << "\"";163OS << ", " << Rec->getValueAsString("FeatureBit");164OS << ", " << Rec->getValueAsString("PriorityBit");165auto FeatName = Rec->getValueAsString("BackendFeature");166const Record *FeatRec = ExtensionMap[FeatName];167if (FeatRec)168OS << ", " << FeatRec->getValueAsString("ArchExtKindSpelling").upper();169else170OS << ", std::nullopt";171OS << ");\n";172};173OS << " return I;\n"174<< "}\n"175<< "#undef EMIT_FMV_INFO\n"176<< "#endif // EMIT_FMV_INFO\n"177<< "\n";178179// Emit extension dependencies180OS << "#ifdef EMIT_EXTENSION_DEPENDENCIES\n"181<< "inline constexpr ExtensionDependency ExtensionDependencies[] = {\n";182for (const Record *Rec : SortedExtensions) {183auto LaterAEK = Rec->getValueAsString("ArchExtKindSpelling").upper();184for (const Record *I : Rec->getValueAsListOfDefs("Implies"))185if (auto EarlierAEK = I->getValueAsOptionalString("ArchExtKindSpelling"))186OS << " {" << EarlierAEK->upper() << ", " << LaterAEK << "},\n";187}188// FIXME: Tablegen has the Subtarget Feature FeatureRCPC_IMMO which is implied189// by FeatureRCPC3 and in turn implies FeatureRCPC. The proper fix is to make190// FeatureRCPC_IMMO an Extension but that will expose it to the command line.191OS << " {AEK_RCPC, AEK_RCPC3},\n";192OS << "};\n"193<< "#undef EMIT_EXTENSION_DEPENDENCIES\n"194<< "#endif // EMIT_EXTENSION_DEPENDENCIES\n"195<< "\n";196197// Emit architecture information198OS << "#ifdef EMIT_ARCHITECTURES\n";199200// Return the C++ name of the of an ArchInfo object201auto ArchInfoName = [](int Major, int Minor,202StringRef Profile) -> std::string {203return Minor == 0 ? "ARMV" + std::to_string(Major) + Profile.upper()204: "ARMV" + std::to_string(Major) + "_" +205std::to_string(Minor) + Profile.upper();206};207208auto Architectures = RK.getAllDerivedDefinitionsIfDefined("Architecture64");209std::vector<std::string> CppSpellings;210for (const Record *Rec : Architectures) {211const int Major = Rec->getValueAsInt("Major");212const int Minor = Rec->getValueAsInt("Minor");213const std::string ProfileLower = Rec->getValueAsString("Profile").str();214const std::string ProfileUpper = Rec->getValueAsString("Profile").upper();215216if (ProfileLower != "a" && ProfileLower != "r")217PrintFatalError(Rec->getLoc(),218"error: Profile must be one of 'a' or 'r', got '" +219ProfileLower + "'");220221// Name of the object in C++222const std::string CppSpelling = ArchInfoName(Major, Minor, ProfileUpper);223OS << "inline constexpr ArchInfo " << CppSpelling << " = {\n";224CppSpellings.push_back(std::move(CppSpelling));225226OS << llvm::format(" VersionTuple{%d, %d},\n", Major, Minor);227OS << llvm::format(" %sProfile,\n", ProfileUpper.c_str());228229// Name as spelled for -march.230if (Minor == 0)231OS << llvm::format(" \"armv%d-%s\",\n", Major, ProfileLower.c_str());232else233OS << llvm::format(" \"armv%d.%d-%s\",\n", Major, Minor,234ProfileLower.c_str());235236// SubtargetFeature::Name, used for -target-feature. Here the "+" is added.237const auto TargetFeatureName = Rec->getValueAsString("Name");238OS << " \"+" << TargetFeatureName << "\",\n";239240// Construct the list of default extensions241OS << " (AArch64::ExtensionBitset({";242for (auto *E : Rec->getValueAsListOfDefs("DefaultExts")) {243OS << "AArch64::" << E->getValueAsString("ArchExtKindSpelling").upper()244<< ", ";245}246OS << "}))\n";247248OS << "};\n";249}250251OS << "\n"252<< "/// The set of all architectures\n"253<< "static constexpr std::array<const ArchInfo *, " << CppSpellings.size()254<< "> ArchInfos = {\n";255for (StringRef CppSpelling : CppSpellings)256OS << " &" << CppSpelling << ",\n";257OS << "};\n";258259OS << "#undef EMIT_ARCHITECTURES\n"260<< "#endif // EMIT_ARCHITECTURES\n"261<< "\n";262263// Emit CPU Aliases264OS << "#ifdef EMIT_CPU_ALIAS\n"265<< "inline constexpr Alias CpuAliases[] = {\n";266267llvm::StringSet<> Processors;268for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel"))269Processors.insert(Rec->getValueAsString("Name"));270271llvm::StringSet<> Aliases;272for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorAlias")) {273auto Name = Rec->getValueAsString("Name");274auto Alias = Rec->getValueAsString("Alias");275if (!Processors.contains(Alias))276PrintFatalError(277Rec, "Alias '" + Name + "' references a non-existent ProcessorModel '" + Alias + "'");278if (Processors.contains(Name))279PrintFatalError(280Rec, "Alias '" + Name + "' duplicates an existing ProcessorModel");281if (!Aliases.insert(Name).second)282PrintFatalError(283Rec, "Alias '" + Name + "' duplicates an existing ProcessorAlias");284285OS << llvm::formatv(R"( { "{0}", "{1}" },)", Name, Alias) << '\n';286}287288OS << "};\n"289<< "#undef EMIT_CPU_ALIAS\n"290<< "#endif // EMIT_CPU_ALIAS\n"291<< "\n";292293// Emit CPU information294OS << "#ifdef EMIT_CPU_INFO\n"295<< "inline constexpr CpuInfo CpuInfos[] = {\n";296297for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel")) {298auto Name = Rec->getValueAsString("Name");299auto Features = Rec->getValueAsListOfDefs("Features");300301// "apple-latest" is backend-only, should not be accepted by TargetParser.302if (Name == "apple-latest")303continue;304305const Record *Arch;306if (Name == "generic") {307// "generic" is an exception. It does not have an architecture, and there308// are tests that depend on e.g. -mattr=-v8.4a meaning HasV8_0aOps==false.309// However, in TargetParser CPUInfo, it is written as 8.0-A.310Arch = RK.getDef("HasV8_0aOps");311} else {312// Search for an Architecture64 in the list of features.313auto IsArch = [](const Record *F) {314return F->isSubClassOf("Architecture64");315};316auto ArchIter = llvm::find_if(Features, IsArch);317if (ArchIter == Features.end())318PrintFatalError(Rec, "Features must include an Architecture64.");319Arch = *ArchIter;320321// Check there is only one Architecture in the list.322if (llvm::count_if(Features, IsArch) > 1)323PrintFatalError(Rec, "Features has multiple Architecture64 entries");324}325326auto Major = Arch->getValueAsInt("Major");327auto Minor = Arch->getValueAsInt("Minor");328auto Profile = Arch->getValueAsString("Profile");329auto ArchInfo = ArchInfoName(Major, Minor, Profile);330331checkFeatureTree(Arch);332333OS << " {\n"334<< " \"" << Name << "\",\n"335<< " " << ArchInfo << ",\n"336<< " AArch64::ExtensionBitset({\n";337338// Keep track of extensions we have seen339StringSet<> SeenExts;340for (const Record *E : Rec->getValueAsListOfDefs("Features"))341// Only process subclasses of Extension342if (E->isSubClassOf("Extension")) {343const auto AEK = E->getValueAsString("ArchExtKindSpelling").upper();344if (!SeenExts.insert(AEK).second)345PrintFatalError(Rec, "feature already added: " + E->getName());346OS << " AArch64::" << AEK << ",\n";347}348OS << " })\n"349<< " },\n";350}351OS << "};\n";352353OS << "#undef EMIT_CPU_INFO\n"354<< "#endif // EMIT_CPU_INFO\n"355<< "\n";356}357358static TableGen::Emitter::Opt359X("gen-arm-target-def", emitARMTargetDef,360"Generate the ARM or AArch64 Architecture information header.");361362363