Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/ARMTargetDefEmitter.cpp
35258 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/StringSet.h"15#include "llvm/Support/Format.h"16#include "llvm/Support/FormatVariadic.h"17#include "llvm/TableGen/Error.h"18#include "llvm/TableGen/Record.h"19#include "llvm/TableGen/TableGenBackend.h"20#include <cstdint>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<Record *> &SeenFeats, Record *Rec) {28assert(Rec->isSubClassOf("SubtargetFeature") &&29"Rec is not a SubtargetFeature");3031SeenFeats.insert(Rec);32for (Record *Implied : Rec->getValueAsListOfDefs("Implies"))33CollectImpliedFeatures(SeenFeats, Implied);34}3536static void CheckFeatureTree(Record *Root) {37std::set<Record *> SeenFeats;38CollectImpliedFeatures(SeenFeats, Root);3940// Check that each of the mandatory (implied) features which is an41// ExtensionWithMArch is also enabled by default.42auto DefaultExtsVec = Root->getValueAsListOfDefs("DefaultExts");43std::set<Record *> DefaultExts{DefaultExtsVec.begin(), DefaultExtsVec.end()};44for (auto *Feat : SeenFeats) {45if (Feat->isSubClassOf("ExtensionWithMArch") && !DefaultExts.count(Feat))46PrintFatalError(Root->getLoc(),47"ExtensionWithMArch " + Feat->getName() +48" is implied (mandatory) as a SubtargetFeature, but "49"is not present in DefaultExts");50}51}5253static void EmitARMTargetDef(RecordKeeper &RK, raw_ostream &OS) {54OS << "// Autogenerated by ARMTargetDefEmitter.cpp\n\n";5556// Look through all SubtargetFeature defs with the given FieldName, and57// collect the set of all Values that that FieldName is set to.58auto gatherSubtargetFeatureFieldValues = [&RK](StringRef FieldName) {59llvm::StringSet<> Set;60for (const Record *Rec : RK.getAllDerivedDefinitions("SubtargetFeature")) {61if (Rec->getValueAsString("FieldName") == FieldName) {62Set.insert(Rec->getValueAsString("Value"));63}64}65return Set;66};6768// Sort the extensions alphabetically, so they don't appear in tablegen order.69std::vector<Record *> SortedExtensions =70RK.getAllDerivedDefinitions("Extension");71auto Alphabetical = [](Record *A, Record *B) -> bool {72const auto NameA = A->getValueAsString("Name");73const auto NameB = B->getValueAsString("Name");74return NameA.compare(NameB) < 0; // A lexographically less than B75};76std::sort(SortedExtensions.begin(), SortedExtensions.end(), Alphabetical);7778// The ARMProcFamilyEnum values are initialised by SubtargetFeature defs79// which set the ARMProcFamily field. We can generate the enum from these defs80// which look like this:81//82// def ProcA5 : SubtargetFeature<"a5", "ARMProcFamily", "CortexA5",83// "Cortex-A5 ARM processors", []>;84OS << "#ifndef ARM_PROCESSOR_FAMILY\n"85<< "#define ARM_PROCESSOR_FAMILY(ENUM)\n"86<< "#endif\n\n";87const StringSet<> ARMProcFamilyVals =88gatherSubtargetFeatureFieldValues("ARMProcFamily");89for (const StringRef &Family : ARMProcFamilyVals.keys())90OS << "ARM_PROCESSOR_FAMILY(" << Family << ")\n";91OS << "\n#undef ARM_PROCESSOR_FAMILY\n\n";9293OS << "#ifndef ARM_ARCHITECTURE\n"94<< "#define ARM_ARCHITECTURE(ENUM)\n"95<< "#endif\n\n";96// This should correspond to instances of the Architecture tablegen class.97const StringSet<> ARMArchVals = gatherSubtargetFeatureFieldValues("ARMArch");98for (const StringRef &Arch : ARMArchVals.keys())99OS << "ARM_ARCHITECTURE(" << Arch << ")\n";100OS << "\n#undef ARM_ARCHITECTURE\n\n";101102// Currently only AArch64 (not ARM) is handled beyond this point.103if (!RK.getClass("Architecture64"))104return;105106// Emit the ArchExtKind enum107OS << "#ifdef EMIT_ARCHEXTKIND_ENUM\n"108<< "enum ArchExtKind : unsigned {\n";109for (const Record *Rec : SortedExtensions) {110auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();111OS << " " << AEK << ",\n";112}113OS << " AEK_NUM_EXTENSIONS\n"114<< "};\n"115<< "#undef EMIT_ARCHEXTKIND_ENUM\n"116<< "#endif // EMIT_ARCHEXTKIND_ENUM\n";117118// Emit information for each defined Extension; used to build ArmExtKind.119OS << "#ifdef EMIT_EXTENSIONS\n"120<< "inline constexpr ExtensionInfo Extensions[] = {\n";121for (const Record *Rec : SortedExtensions) {122auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();123OS << " ";124OS << "{\"" << Rec->getValueAsString("UserVisibleName") << "\"";125if (auto Alias = Rec->getValueAsString("UserVisibleAlias"); Alias.empty())126OS << ", {}";127else128OS << ", \"" << Alias << "\"";129OS << ", AArch64::" << AEK;130OS << ", \"" << Rec->getValueAsString("ArchFeatureName") << "\"";131OS << ", \"" << Rec->getValueAsString("Desc") << "\"";132OS << ", \"+" << Rec->getValueAsString("Name") << "\""; // posfeature133OS << ", \"-" << Rec->getValueAsString("Name") << "\""; // negfeature134OS << "},\n";135};136OS << "};\n"137<< "#undef EMIT_EXTENSIONS\n"138<< "#endif // EMIT_EXTENSIONS\n"139<< "\n";140141// Emit FMV information142auto FMVExts = RK.getAllDerivedDefinitionsIfDefined("FMVExtension");143OS << "#ifdef EMIT_FMV_INFO\n"144<< "const std::vector<llvm::AArch64::FMVInfo>& "145"llvm::AArch64::getFMVInfo() {\n"146<< " static std::vector<FMVInfo> I;\n"147<< " if(I.size()) return I;\n"148<< " I.reserve(" << FMVExts.size() << ");\n";149for (const Record *Rec : FMVExts) {150OS << " I.emplace_back(";151OS << "\"" << Rec->getValueAsString("Name") << "\"";152OS << ", " << Rec->getValueAsString("Bit");153OS << ", \"" << Rec->getValueAsString("BackendFeatures") << "\"";154OS << ", " << (uint64_t)Rec->getValueAsInt("Priority");155OS << ");\n";156};157OS << " return I;\n"158<< "}\n"159<< "#undef EMIT_FMV_INFO\n"160<< "#endif // EMIT_FMV_INFO\n"161<< "\n";162163// Emit extension dependencies164OS << "#ifdef EMIT_EXTENSION_DEPENDENCIES\n"165<< "inline constexpr ExtensionDependency ExtensionDependencies[] = {\n";166for (const Record *Rec : SortedExtensions) {167auto LaterAEK = Rec->getValueAsString("ArchExtKindSpelling").upper();168for (const Record *I : Rec->getValueAsListOfDefs("Implies"))169if (auto EarlierAEK = I->getValueAsOptionalString("ArchExtKindSpelling"))170OS << " {" << EarlierAEK->upper() << ", " << LaterAEK << "},\n";171}172// FIXME: Tablegen has the Subtarget Feature FeatureRCPC_IMMO which is implied173// by FeatureRCPC3 and in turn implies FeatureRCPC. The proper fix is to make174// FeatureRCPC_IMMO an Extension but that will expose it to the command line.175OS << " {AEK_RCPC, AEK_RCPC3},\n";176OS << "};\n"177<< "#undef EMIT_EXTENSION_DEPENDENCIES\n"178<< "#endif // EMIT_EXTENSION_DEPENDENCIES\n"179<< "\n";180181// Emit architecture information182OS << "#ifdef EMIT_ARCHITECTURES\n";183184// Return the C++ name of the of an ArchInfo object185auto ArchInfoName = [](int Major, int Minor,186StringRef Profile) -> std::string {187return Minor == 0 ? "ARMV" + std::to_string(Major) + Profile.upper()188: "ARMV" + std::to_string(Major) + "_" +189std::to_string(Minor) + Profile.upper();190};191192auto Architectures = RK.getAllDerivedDefinitionsIfDefined("Architecture64");193std::vector<std::string> CppSpellings;194for (const Record *Rec : Architectures) {195const int Major = Rec->getValueAsInt("Major");196const int Minor = Rec->getValueAsInt("Minor");197const std::string ProfileLower = Rec->getValueAsString("Profile").str();198const std::string ProfileUpper = Rec->getValueAsString("Profile").upper();199200if (ProfileLower != "a" && ProfileLower != "r")201PrintFatalError(Rec->getLoc(),202"error: Profile must be one of 'a' or 'r', got '" +203ProfileLower + "'");204205// Name of the object in C++206const std::string CppSpelling = ArchInfoName(Major, Minor, ProfileUpper);207OS << "inline constexpr ArchInfo " << CppSpelling << " = {\n";208CppSpellings.push_back(CppSpelling);209210OS << llvm::format(" VersionTuple{%d, %d},\n", Major, Minor);211OS << llvm::format(" %sProfile,\n", ProfileUpper.c_str());212213// Name as spelled for -march.214if (Minor == 0)215OS << llvm::format(" \"armv%d-%s\",\n", Major, ProfileLower.c_str());216else217OS << llvm::format(" \"armv%d.%d-%s\",\n", Major, Minor,218ProfileLower.c_str());219220// SubtargetFeature::Name, used for -target-feature. Here the "+" is added.221const auto TargetFeatureName = Rec->getValueAsString("Name");222OS << " \"+" << TargetFeatureName << "\",\n";223224// Construct the list of default extensions225OS << " (AArch64::ExtensionBitset({";226for (auto *E : Rec->getValueAsListOfDefs("DefaultExts")) {227OS << "AArch64::" << E->getValueAsString("ArchExtKindSpelling").upper()228<< ", ";229}230OS << "}))\n";231232OS << "};\n";233}234235OS << "\n"236<< "/// The set of all architectures\n"237<< "static constexpr std::array<const ArchInfo *, " << CppSpellings.size()238<< "> ArchInfos = {\n";239for (StringRef CppSpelling : CppSpellings)240OS << " &" << CppSpelling << ",\n";241OS << "};\n";242243OS << "#undef EMIT_ARCHITECTURES\n"244<< "#endif // EMIT_ARCHITECTURES\n"245<< "\n";246247// Emit CPU Aliases248OS << "#ifdef EMIT_CPU_ALIAS\n"249<< "inline constexpr Alias CpuAliases[] = {\n";250251llvm::StringSet<> Processors;252for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel"))253Processors.insert(Rec->getValueAsString("Name"));254255llvm::StringSet<> Aliases;256for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorAlias")) {257auto Name = Rec->getValueAsString("Name");258auto Alias = Rec->getValueAsString("Alias");259if (!Processors.contains(Alias))260PrintFatalError(261Rec, "Alias '" + Name + "' references a non-existent ProcessorModel '" + Alias + "'");262if (Processors.contains(Name))263PrintFatalError(264Rec, "Alias '" + Name + "' duplicates an existing ProcessorModel");265if (!Aliases.insert(Name).second)266PrintFatalError(267Rec, "Alias '" + Name + "' duplicates an existing ProcessorAlias");268269OS << llvm::formatv(R"( { "{0}", "{1}" },)", Name, Alias) << '\n';270}271272OS << "};\n"273<< "#undef EMIT_CPU_ALIAS\n"274<< "#endif // EMIT_CPU_ALIAS\n"275<< "\n";276277// Emit CPU information278OS << "#ifdef EMIT_CPU_INFO\n"279<< "inline constexpr CpuInfo CpuInfos[] = {\n";280281for (const Record *Rec : RK.getAllDerivedDefinitions("ProcessorModel")) {282auto Name = Rec->getValueAsString("Name");283auto Features = Rec->getValueAsListOfDefs("Features");284285// "apple-latest" is backend-only, should not be accepted by TargetParser.286if (Name == "apple-latest")287continue;288289Record *Arch;290if (Name == "generic") {291// "generic" is an exception. It does not have an architecture, and there292// are tests that depend on e.g. -mattr=-v8.4a meaning HasV8_0aOps==false.293// However, in TargetParser CPUInfo, it is written as 8.0-A.294Arch = RK.getDef("HasV8_0aOps");295} else {296// Search for an Architecture64 in the list of features.297auto IsArch = [](Record *F) { return F->isSubClassOf("Architecture64"); };298auto ArchIter = llvm::find_if(Features, IsArch);299if (ArchIter == Features.end())300PrintFatalError(Rec, "Features must include an Architecture64.");301Arch = *ArchIter;302303// Check there is only one Architecture in the list.304if (llvm::count_if(Features, IsArch) > 1)305PrintFatalError(Rec, "Features has multiple Architecture64 entries");306}307308auto Major = Arch->getValueAsInt("Major");309auto Minor = Arch->getValueAsInt("Minor");310auto Profile = Arch->getValueAsString("Profile");311auto ArchInfo = ArchInfoName(Major, Minor, Profile);312313CheckFeatureTree(Arch);314315OS << " {\n"316<< " \"" << Name << "\",\n"317<< " " << ArchInfo << ",\n"318<< " AArch64::ExtensionBitset({\n";319320// Keep track of extensions we have seen321StringSet<> SeenExts;322for (auto *E : Rec->getValueAsListOfDefs("Features"))323// Only process subclasses of Extension324if (E->isSubClassOf("Extension")) {325const auto AEK = E->getValueAsString("ArchExtKindSpelling").upper();326if (!SeenExts.insert(AEK).second)327PrintFatalError(Rec, "feature already added: " + E->getName());328OS << " AArch64::" << AEK << ",\n";329}330OS << " })\n"331<< " },\n";332}333OS << "};\n";334335OS << "#undef EMIT_CPU_INFO\n"336<< "#endif // EMIT_CPU_INFO\n"337<< "\n";338}339340static TableGen::Emitter::Opt341X("gen-arm-target-def", EmitARMTargetDef,342"Generate the ARM or AArch64 Architecture information header.");343344345