brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.8 KiB · b63ce36 Raw
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