diff options
author | NAKAMURA Takumi <geek4civic@gmail.com> | 2025-01-09 17:50:40 +0900 |
---|---|---|
committer | NAKAMURA Takumi <geek4civic@gmail.com> | 2025-01-09 17:50:40 +0900 |
commit | fea7da1b00cc97d742faede2df96c7d327950f49 (patch) | |
tree | 4de1d6b4ddc69f4f32daabb11ad5c71ab0cf895e /llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp | |
parent | 9b99dde0d47102625d93c5d1cbbc04951025a6c9 (diff) | |
parent | 0aa930a41f2d1ebf1fa90ec42da8f96d15a4dcbb (diff) | |
download | llvm-users/chapuni/cov/single/nextcount.zip llvm-users/chapuni/cov/single/nextcount.tar.gz llvm-users/chapuni/cov/single/nextcount.tar.bz2 |
Merge branch 'users/chapuni/cov/single/nextcount-base' into users/chapuni/cov/single/nextcountusers/chapuni/cov/single/nextcount
Diffstat (limited to 'llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp')
-rw-r--r-- | llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp new file mode 100644 index 0000000..4dea89e --- /dev/null +++ b/llvm/utils/TableGen/Basic/ARMTargetDefEmitter.cpp @@ -0,0 +1,362 @@ +//===- ARMTargetDefEmitter.cpp - Generate data about ARM Architectures ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend exports information about CPUs, FPUs, architectures, +// and features into a common format that can be used by both TargetParser and +// the ARM and AArch64 backends. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <cstdint> +#include <set> +#include <string> + +using namespace llvm; + +/// Collect the full set of implied features for a SubtargetFeature. +static void collectImpliedFeatures(std::set<const Record *> &SeenFeats, + const Record *Rec) { + assert(Rec->isSubClassOf("SubtargetFeature") && + "Rec is not a SubtargetFeature"); + + SeenFeats.insert(Rec); + for (const Record *Implied : Rec->getValueAsListOfDefs("Implies")) + collectImpliedFeatures(SeenFeats, Implied); +} + +static void checkFeatureTree(const Record *Root) { + std::set<const Record *> SeenFeats; + collectImpliedFeatures(SeenFeats, Root); + + // Check that each of the mandatory (implied) features which is an + // ExtensionWithMArch is also enabled by default. + auto DefaultExtsVec = Root->getValueAsListOfDefs("DefaultExts"); + std::set<const Record *> DefaultExts{DefaultExtsVec.begin(), + DefaultExtsVec.end()}; + for (const Record *Feat : SeenFeats) { + if (Feat->isSubClassOf("ExtensionWithMArch") && !DefaultExts.count(Feat)) + PrintFatalError(Root->getLoc(), + "ExtensionWithMArch " + Feat->getName() + + " is implied (mandatory) as a SubtargetFeature, but " + "is not present in DefaultExts"); + } +} + +static void emitARMTargetDef(const RecordKeeper &RK, raw_ostream &OS) { + OS << "// Autogenerated by ARMTargetDefEmitter.cpp\n\n"; + + // Look through all SubtargetFeature defs with the given FieldName, and + // collect the set of all Values that that FieldName is set to. + auto GatherSubtargetFeatureFieldValues = [&RK](StringRef FieldName) { + llvm::StringSet<> Set; + for (const Record *Rec : RK.getAllDerivedDefinitions("SubtargetFeature")) { + if (Rec->getValueAsString("FieldName") == FieldName) { + Set.insert(Rec->getValueAsString("Value")); + } + } + return Set; + }; + + // Sort the extensions alphabetically, so they don't appear in tablegen order. + std::vector<const Record *> SortedExtensions = + RK.getAllDerivedDefinitions("Extension"); + auto Alphabetical = [](const Record *A, const Record *B) -> bool { + const auto NameA = A->getValueAsString("Name"); + const auto NameB = B->getValueAsString("Name"); + return NameA.compare(NameB) < 0; // A lexographically less than B + }; + sort(SortedExtensions, Alphabetical); + + // Cache Extension records for quick lookup. + DenseMap<StringRef, const Record *> ExtensionMap; + for (const Record *Rec : SortedExtensions) { + auto Name = Rec->getValueAsString("UserVisibleName"); + if (Name.empty()) + Name = Rec->getValueAsString("Name"); + ExtensionMap[Name] = Rec; + } + + // The ARMProcFamilyEnum values are initialised by SubtargetFeature defs + // which set the ARMProcFamily field. We can generate the enum from these defs + // which look like this: + // + // def ProcA5 : SubtargetFeature<"a5", "ARMProcFamily", "CortexA5", + // "Cortex-A5 ARM processors", []>; + OS << "#ifndef ARM_PROCESSOR_FAMILY\n" + << "#define ARM_PROCESSOR_FAMILY(ENUM)\n" + << "#endif\n\n"; + const StringSet<> ARMProcFamilyVals = + GatherSubtargetFeatureFieldValues("ARMProcFamily"); + for (const StringRef &Family : ARMProcFamilyVals.keys()) + OS << "ARM_PROCESSOR_FAMILY(" << Family << ")\n"; + OS << "\n#undef ARM_PROCESSOR_FAMILY\n\n"; + + OS << "#ifndef ARM_ARCHITECTURE\n" + << "#define ARM_ARCHITECTURE(ENUM)\n" + << "#endif\n\n"; + // This should correspond to instances of the Architecture tablegen class. + const StringSet<> ARMArchVals = GatherSubtargetFeatureFieldValues("ARMArch"); + for (const StringRef &Arch : ARMArchVals.keys()) + OS << "ARM_ARCHITECTURE(" << Arch << ")\n"; + OS << "\n#undef ARM_ARCHITECTURE\n\n"; + + // Currently only AArch64 (not ARM) is handled beyond this point. + if (!RK.getClass("Architecture64")) + return; + + // Emit the ArchExtKind enum + OS << "#ifdef EMIT_ARCHEXTKIND_ENUM\n" + << "enum ArchExtKind : unsigned {\n"; + for (const Record *Rec : SortedExtensions) { + auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper(); + OS << " " << AEK << ",\n"; + } + OS << " AEK_NUM_EXTENSIONS\n" + << "};\n" + << "#undef EMIT_ARCHEXTKIND_ENUM\n" + << "#endif // EMIT_ARCHEXTKIND_ENUM\n"; + + // Emit information for each defined Extension; used to build ArmExtKind. + OS << "#ifdef EMIT_EXTENSIONS\n" + << "inline constexpr ExtensionInfo Extensions[] = {\n"; + for (const Record *Rec : SortedExtensions) { + auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper(); + OS << " "; + OS << "{\"" << Rec->getValueAsString("UserVisibleName") << "\""; + if (auto Alias = Rec->getValueAsString("UserVisibleAlias"); Alias.empty()) + OS << ", {}"; + else + OS << ", \"" << Alias << "\""; + OS << ", AArch64::" << AEK; + OS << ", \"" << Rec->getValueAsString("ArchFeatureName") << "\""; + OS << ", \"" << Rec->getValueAsString("Desc") << "\""; + OS << ", \"+" << Rec->getValueAsString("Name") << "\""; // posfeature + OS << ", \"-" << Rec->getValueAsString("Name") << "\""; // negfeature + OS << "},\n"; + }; + OS << "};\n" + << "#undef EMIT_EXTENSIONS\n" + << "#endif // EMIT_EXTENSIONS\n" + << "\n"; + + // Emit FMV information + auto FMVExts = RK.getAllDerivedDefinitionsIfDefined("FMVExtension"); + OS << "#ifdef EMIT_FMV_INFO\n" + << "const std::vector<llvm::AArch64::FMVInfo>& " + "llvm::AArch64::getFMVInfo() {\n" + << " static std::vector<FMVInfo> I;\n" + << " if(I.size()) return I;\n" + << " I.reserve(" << FMVExts.size() << ");\n"; + for (const Record *Rec : FMVExts) { + OS << " I.emplace_back("; + OS << "\"" << Rec->getValueAsString("Name") << "\""; + OS << ", " << Rec->getValueAsString("FeatureBit"); + OS << ", " << Rec->getValueAsString("PriorityBit"); + auto FeatName = Rec->getValueAsString("BackendFeature"); + const Record *FeatRec = ExtensionMap[FeatName]; + if (FeatRec) + OS << ", " << FeatRec->getValueAsString("ArchExtKindSpelling").upper(); + else + OS << ", std::nullopt"; + OS << ");\n"; + }; + OS << " return I;\n" + << "}\n" + << "#undef EMIT_FMV_INFO\n" + << "#endif // EMIT_FMV_INFO\n" + << "\n"; + + // Emit extension dependencies + OS << "#ifdef EMIT_EXTENSION_DEPENDENCIES\n" + << "inline constexpr ExtensionDependency ExtensionDependencies[] = {\n"; + for (const Record *Rec : SortedExtensions) { + auto LaterAEK = Rec->getValueAsString("ArchExtKindSpelling").upper(); + for (const Record *I : Rec->getValueAsListOfDefs("Implies")) + if (auto EarlierAEK = I->getValueAsOptionalString("ArchExtKindSpelling")) + OS << " {" << EarlierAEK->upper() << ", " << LaterAEK << "},\n"; + } + // FIXME: Tablegen has the Subtarget Feature FeatureRCPC_IMMO which is implied + // by FeatureRCPC3 and in turn implies FeatureRCPC. The proper fix is to make + // FeatureRCPC_IMMO an Extension but that will expose it to the command line. + OS << " {AEK_RCPC, AEK_RCPC3},\n"; + OS << "};\n" + << "#undef EMIT_EXTENSION_DEPENDENCIES\n" + << "#endif // EMIT_EXTENSION_DEPENDENCIES\n" + << "\n"; + + // Emit architecture information + OS << "#ifdef EMIT_ARCHITECTURES\n"; + + // Return the C++ name of the of an ArchInfo object + auto ArchInfoName = [](int Major, int Minor, + StringRef Profile) -> std::string { + return Minor == 0 ? "ARMV" + std::to_string(Major) + Profile.upper() + : "ARMV" + std::to_string(Major) + "_" + + std::to_string(Minor) + Profile.upper(); + }; + + auto Architectures = RK.getAllDerivedDefinitionsIfDefined("Architecture64"); + std::vector<std::string> CppSpellings; + for (const Record *Rec : Architectures) { + const int Major = Rec->getValueAsInt("Major"); + const int Minor = Rec->getValueAsInt("Minor"); + const std::string ProfileLower = Rec->getValueAsString("Profile").str(); + const std::string ProfileUpper = Rec->getValueAsString("Profile").upper(); + + if (ProfileLower != "a" && ProfileLower != "r") + PrintFatalError(Rec->getLoc(), + "error: Profile must be one of 'a' or 'r', got '" + + ProfileLower + "'"); + + // Name of the object in C++ + const std::string CppSpelling = ArchInfoName(Major, Minor, ProfileUpper); + OS << "inline constexpr ArchInfo " << CppSpelling << " = {\n"; + CppSpellings.push_back(std::move(CppSpelling)); + + OS << llvm::format(" VersionTuple{%d, %d},\n", Major, Minor); + OS << llvm::format(" %sProfile,\n", ProfileUpper.c_str()); + + // Name as spelled for -march. + if (Minor == 0) + OS << llvm::format(" \"armv%d-%s\",\n", Major, ProfileLower.c_str()); + else + OS << llvm::format(" \"armv%d.%d-%s\",\n", Major, Minor, + ProfileLower.c_str()); + + // SubtargetFeature::Name, used for -target-feature. Here the "+" is added. + const auto TargetFeatureName = Rec->getValueAsString("Name"); + OS << " \"+" << TargetFeatureName << "\",\n"; + + // Construct the list of default extensions + OS << " (AArch64::ExtensionBitset({"; + for (auto *E : Rec->getValueAsListOfDefs("DefaultExts")) { + OS << "AArch64::" << E->getValueAsString("ArchExtKindSpelling").upper() + << ", "; + } + OS << "}))\n"; + + OS << "};\n"; + } + + OS << "\n" + << "/// The set of all architectures\n" + << "static constexpr std::array<const ArchInfo *, " << CppSpellings.size() + << "> ArchInfos = {\n"; + for (StringRef CppSpelling : CppSpellings) + OS << " &" << CppSpelling << ",\n"; + OS << "};\n"; + + OS << "#undef EMIT_ARCHITECTURES\n" + << "#endif // EMIT_ARCHITECTURES\n" + << "\n"; + + // Emit CPU Aliases + OS << "#ifdef EMIT_CPU_ALIAS\n" + << "inline constexpr Alias CpuAliases[] = {\n"; + + llvm::StringSet<> Processors; + for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel")) + Processors.insert(Rec->getValueAsString("Name")); + + llvm::StringSet<> Aliases; + for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorAlias")) { + auto Name = Rec->getValueAsString("Name"); + auto Alias = Rec->getValueAsString("Alias"); + if (!Processors.contains(Alias)) + PrintFatalError( + Rec, "Alias '" + Name + "' references a non-existent ProcessorModel '" + Alias + "'"); + if (Processors.contains(Name)) + PrintFatalError( + Rec, "Alias '" + Name + "' duplicates an existing ProcessorModel"); + if (!Aliases.insert(Name).second) + PrintFatalError( + Rec, "Alias '" + Name + "' duplicates an existing ProcessorAlias"); + + OS << llvm::formatv(R"( { "{0}", "{1}" },)", Name, Alias) << '\n'; + } + + OS << "};\n" + << "#undef EMIT_CPU_ALIAS\n" + << "#endif // EMIT_CPU_ALIAS\n" + << "\n"; + + // Emit CPU information + OS << "#ifdef EMIT_CPU_INFO\n" + << "inline constexpr CpuInfo CpuInfos[] = {\n"; + + for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel")) { + auto Name = Rec->getValueAsString("Name"); + auto Features = Rec->getValueAsListOfDefs("Features"); + + // "apple-latest" is backend-only, should not be accepted by TargetParser. + if (Name == "apple-latest") + continue; + + const Record *Arch; + if (Name == "generic") { + // "generic" is an exception. It does not have an architecture, and there + // are tests that depend on e.g. -mattr=-v8.4a meaning HasV8_0aOps==false. + // However, in TargetParser CPUInfo, it is written as 8.0-A. + Arch = RK.getDef("HasV8_0aOps"); + } else { + // Search for an Architecture64 in the list of features. + auto IsArch = [](const Record *F) { + return F->isSubClassOf("Architecture64"); + }; + auto ArchIter = llvm::find_if(Features, IsArch); + if (ArchIter == Features.end()) + PrintFatalError(Rec, "Features must include an Architecture64."); + Arch = *ArchIter; + + // Check there is only one Architecture in the list. + if (llvm::count_if(Features, IsArch) > 1) + PrintFatalError(Rec, "Features has multiple Architecture64 entries"); + } + + auto Major = Arch->getValueAsInt("Major"); + auto Minor = Arch->getValueAsInt("Minor"); + auto Profile = Arch->getValueAsString("Profile"); + auto ArchInfo = ArchInfoName(Major, Minor, Profile); + + checkFeatureTree(Arch); + + OS << " {\n" + << " \"" << Name << "\",\n" + << " " << ArchInfo << ",\n" + << " AArch64::ExtensionBitset({\n"; + + // Keep track of extensions we have seen + StringSet<> SeenExts; + for (const Record *E : Rec->getValueAsListOfDefs("Features")) + // Only process subclasses of Extension + if (E->isSubClassOf("Extension")) { + const auto AEK = E->getValueAsString("ArchExtKindSpelling").upper(); + if (!SeenExts.insert(AEK).second) + PrintFatalError(Rec, "feature already added: " + E->getName()); + OS << " AArch64::" << AEK << ",\n"; + } + OS << " })\n" + << " },\n"; + } + OS << "};\n"; + + OS << "#undef EMIT_CPU_INFO\n" + << "#endif // EMIT_CPU_INFO\n" + << "\n"; +} + +static TableGen::Emitter::Opt + X("gen-arm-target-def", emitARMTargetDef, + "Generate the ARM or AArch64 Architecture information header."); |