brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.0 KiB · f795937 Raw
275 lines · cpp
1//===- RISCVTargetDefEmitter.cpp - Generate lists of RISC-V CPUs ----------===//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 emits the include file needed by RISCVTargetParser.cpp10// and RISCVISAInfo.cpp to parse the RISC-V CPUs and extensions.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/ADT/DenseSet.h"15#include "llvm/Support/Format.h"16#include "llvm/Support/RISCVISAUtils.h"17#include "llvm/TableGen/Record.h"18#include "llvm/TableGen/TableGenBackend.h"19 20using namespace llvm;21 22static StringRef getExtensionName(const Record *R) {23  StringRef Name = R->getValueAsString("Name");24  Name.consume_front("experimental-");25  return Name;26}27 28static void printExtensionTable(raw_ostream &OS,29                                ArrayRef<const Record *> Extensions,30                                bool Experimental) {31  OS << "static const RISCVSupportedExtension Supported";32  if (Experimental)33    OS << "Experimental";34  OS << "Extensions[] = {\n";35 36  for (const Record *R : Extensions) {37    if (R->getValueAsBit("Experimental") != Experimental)38      continue;39 40    OS.indent(4) << "{\"" << getExtensionName(R) << "\", {"41                 << R->getValueAsInt("MajorVersion") << ", "42                 << R->getValueAsInt("MinorVersion") << "}},\n";43  }44 45  OS << "};\n\n";46}47 48static void emitRISCVExtensions(const RecordKeeper &Records, raw_ostream &OS) {49  OS << "#ifdef GET_SUPPORTED_EXTENSIONS\n";50  OS << "#undef GET_SUPPORTED_EXTENSIONS\n\n";51 52  std::vector<const Record *> Extensions =53      Records.getAllDerivedDefinitionsIfDefined("RISCVExtension");54  llvm::sort(Extensions, [](const Record *Rec1, const Record *Rec2) {55    return getExtensionName(Rec1) < getExtensionName(Rec2);56  });57 58  if (!Extensions.empty()) {59    printExtensionTable(OS, Extensions, /*Experimental=*/false);60    printExtensionTable(OS, Extensions, /*Experimental=*/true);61  }62 63  OS << "#endif // GET_SUPPORTED_EXTENSIONS\n\n";64 65  OS << "#ifdef GET_IMPLIED_EXTENSIONS\n";66  OS << "#undef GET_IMPLIED_EXTENSIONS\n\n";67 68  if (!Extensions.empty()) {69    OS << "\nstatic constexpr ImpliedExtsEntry ImpliedExts[] = {\n";70    for (const Record *Ext : Extensions) {71      std::vector<const Record *> ImpliesList =72          Ext->getValueAsListOfDefs("Implies");73      if (ImpliesList.empty())74        continue;75 76      StringRef Name = getExtensionName(Ext);77 78      for (const Record *ImpliedExt : ImpliesList) {79        if (!ImpliedExt->isSubClassOf("RISCVExtension"))80          continue;81 82        OS.indent(4) << "{ {\"" << Name << "\"}, \""83                     << getExtensionName(ImpliedExt) << "\"},\n";84      }85    }86 87    OS << "};\n\n";88  }89 90  OS << "#endif // GET_IMPLIED_EXTENSIONS\n\n";91}92 93// We can generate march string from target features as what has been described94// in RISC-V ISA specification (version 20191213) 'Chapter 27. ISA Extension95// Naming Conventions'.96//97// This is almost the same as RISCVFeatures::parseFeatureBits, except that we98// get feature name from feature records instead of feature bits.99static void printMArch(raw_ostream &OS, ArrayRef<const Record *> Features) {100  RISCVISAUtils::OrderedExtensionMap Extensions;101  unsigned XLen = 0;102 103  // Convert features to FeatureVector.104  for (const Record *Feature : Features) {105    StringRef FeatureName = getExtensionName(Feature);106    if (Feature->isSubClassOf("RISCVExtension")) {107      unsigned Major = Feature->getValueAsInt("MajorVersion");108      unsigned Minor = Feature->getValueAsInt("MinorVersion");109      Extensions[FeatureName.str()] = {Major, Minor};110    } else if (FeatureName == "64bit") {111      assert(XLen == 0 && "Already determined XLen");112      XLen = 64;113    } else if (FeatureName == "32bit") {114      assert(XLen == 0 && "Already determined XLen");115      XLen = 32;116    }117  }118 119  assert(XLen != 0 && "Unable to determine XLen");120 121  OS << "rv" << XLen;122 123  ListSeparator LS("_");124  for (auto const &Ext : Extensions)125    OS << LS << Ext.first << Ext.second.Major << 'p' << Ext.second.Minor;126}127 128static void printProfileTable(raw_ostream &OS,129                              ArrayRef<const Record *> Profiles,130                              bool Experimental) {131  OS << "static constexpr RISCVProfile Supported";132  if (Experimental)133    OS << "Experimental";134  OS << "Profiles[] = {\n";135 136  for (const Record *Rec : Profiles) {137    if (Rec->getValueAsBit("Experimental") != Experimental)138      continue;139 140    StringRef Name = Rec->getValueAsString("Name");141    Name.consume_front("experimental-");142    OS.indent(4) << "{\"" << Name << "\",\"";143    printMArch(OS, Rec->getValueAsListOfDefs("Implies"));144    OS << "\"},\n";145  }146 147  OS << "};\n\n";148}149 150static void emitRISCVProfiles(const RecordKeeper &Records, raw_ostream &OS) {151  OS << "#ifdef GET_SUPPORTED_PROFILES\n";152  OS << "#undef GET_SUPPORTED_PROFILES\n\n";153 154  ArrayRef<const Record *> Profiles =155      Records.getAllDerivedDefinitionsIfDefined("RISCVProfile");156 157  if (!Profiles.empty()) {158    printProfileTable(OS, Profiles, /*Experimental=*/false);159    bool HasExperimentalProfiles = any_of(Profiles, [&](const Record *Rec) {160      return Rec->getValueAsBit("Experimental");161    });162    if (HasExperimentalProfiles)163      printProfileTable(OS, Profiles, /*Experimental=*/true);164  }165 166  OS << "#endif // GET_SUPPORTED_PROFILES\n\n";167}168 169static void emitRISCVProcs(const RecordKeeper &RK, raw_ostream &OS) {170  OS << "#ifndef PROC\n"171     << "#define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN"172     << ", FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID)\n"173     << "#endif\n\n";174 175  // Iterate on all definition records.176  for (const Record *Rec :177       RK.getAllDerivedDefinitionsIfDefined("RISCVProcessorModel")) {178    std::vector<const Record *> Features =179        Rec->getValueAsListOfDefs("Features");180    bool FastScalarUnalignedAccess =181        any_of(Features, [&](const Record *Feature) {182          return Feature->getValueAsString("Name") == "unaligned-scalar-mem";183        });184 185    bool FastVectorUnalignedAccess =186        any_of(Features, [&](const Record *Feature) {187          return Feature->getValueAsString("Name") == "unaligned-vector-mem";188        });189 190    OS << "PROC(" << Rec->getName() << ", {\"" << Rec->getValueAsString("Name")191       << "\"}, {\"";192 193    StringRef MArch = Rec->getValueAsString("DefaultMarch");194 195    // Compute MArch from features if we don't specify it.196    if (MArch.empty())197      printMArch(OS, Features);198    else199      OS << MArch;200 201    uint32_t MVendorID = Rec->getValueAsInt("MVendorID");202    uint64_t MArchID = Rec->getValueAsInt("MArchID");203    uint64_t MImpID = Rec->getValueAsInt("MImpID");204 205    OS << "\"}, " << FastScalarUnalignedAccess << ", "206       << FastVectorUnalignedAccess;207    OS << ", " << format_hex(MVendorID, 10);208    OS << ", " << format_hex(MArchID, 18);209    OS << ", " << format_hex(MImpID, 18);210    OS << ")\n";211  }212  OS << "\n#undef PROC\n";213  OS << "\n";214  OS << "#ifndef TUNE_PROC\n"215     << "#define TUNE_PROC(ENUM, NAME)\n"216     << "#endif\n\n";217 218  for (const Record *Rec :219       RK.getAllDerivedDefinitionsIfDefined("RISCVTuneProcessorModel")) {220    OS << "TUNE_PROC(" << Rec->getName() << ", "221       << "\"" << Rec->getValueAsString("Name") << "\")\n";222  }223 224  OS << "\n#undef TUNE_PROC\n";225}226 227static void emitRISCVExtensionBitmask(const RecordKeeper &RK, raw_ostream &OS) {228  std::vector<const Record *> Extensions =229      RK.getAllDerivedDefinitionsIfDefined("RISCVExtensionBitmask");230  llvm::sort(Extensions, [](const Record *Rec1, const Record *Rec2) {231    unsigned GroupID1 = Rec1->getValueAsInt("GroupID");232    unsigned GroupID2 = Rec2->getValueAsInt("GroupID");233    if (GroupID1 != GroupID2)234      return GroupID1 < GroupID2;235 236    return Rec1->getValueAsInt("BitPos") < Rec2->getValueAsInt("BitPos");237  });238 239#ifndef NDEBUG240  llvm::DenseSet<std::pair<uint64_t, uint64_t>> Seen;241#endif242 243  OS << "#ifdef GET_RISCVExtensionBitmaskTable_IMPL\n";244  OS << "static const RISCVExtensionBitmask ExtensionBitmask[]={\n";245  for (const Record *Rec : Extensions) {246    unsigned GroupIDVal = Rec->getValueAsInt("GroupID");247    unsigned BitPosVal = Rec->getValueAsInt("BitPos");248 249    StringRef ExtName = Rec->getValueAsString("Name");250    ExtName.consume_front("experimental-");251 252#ifndef NDEBUG253    assert(Seen.insert({GroupIDVal, BitPosVal}).second && "duplicated bitmask");254#endif255 256    OS.indent(4) << "{"257                 << "\"" << ExtName << "\""258                 << ", " << GroupIDVal << ", " << BitPosVal << "ULL"259                 << "},\n";260  }261  OS << "};\n";262  OS << "#endif\n";263}264 265static void emitRiscvTargetDef(const RecordKeeper &RK, raw_ostream &OS) {266  emitRISCVExtensions(RK, OS);267  emitRISCVProfiles(RK, OS);268  emitRISCVProcs(RK, OS);269  emitRISCVExtensionBitmask(RK, OS);270}271 272static TableGen::Emitter::Opt X("gen-riscv-target-def", emitRiscvTargetDef,273                                "Generate the list of CPUs and extensions for "274                                "RISC-V");275