Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/RISCVTargetDefEmitter.cpp
35258 views
//===- RISCVTargetDefEmitter.cpp - Generate lists of RISC-V CPUs ----------===//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 emits the include file needed by RISCVTargetParser.cpp9// and RISCVISAInfo.cpp to parse the RISC-V CPUs and extensions.10//11//===----------------------------------------------------------------------===//1213#include "llvm/ADT/DenseSet.h"14#include "llvm/Support/RISCVISAUtils.h"15#include "llvm/TableGen/Record.h"16#include "llvm/TableGen/TableGenBackend.h"1718using namespace llvm;1920static StringRef getExtensionName(const Record *R) {21StringRef Name = R->getValueAsString("Name");22Name.consume_front("experimental-");23return Name;24}2526static void printExtensionTable(raw_ostream &OS,27const std::vector<Record *> &Extensions,28bool Experimental) {29OS << "static const RISCVSupportedExtension Supported";30if (Experimental)31OS << "Experimental";32OS << "Extensions[] = {\n";3334for (Record *R : Extensions) {35if (R->getValueAsBit("Experimental") != Experimental)36continue;3738OS << " {\"" << getExtensionName(R) << "\", {"39<< R->getValueAsInt("MajorVersion") << ", "40<< R->getValueAsInt("MinorVersion") << "}},\n";41}4243OS << "};\n\n";44}4546static void emitRISCVExtensions(RecordKeeper &Records, raw_ostream &OS) {47OS << "#ifdef GET_SUPPORTED_EXTENSIONS\n";48OS << "#undef GET_SUPPORTED_EXTENSIONS\n\n";4950std::vector<Record *> Extensions =51Records.getAllDerivedDefinitionsIfDefined("RISCVExtension");52llvm::sort(Extensions, [](const Record *Rec1, const Record *Rec2) {53return getExtensionName(Rec1) < getExtensionName(Rec2);54});5556if (!Extensions.empty()) {57printExtensionTable(OS, Extensions, /*Experimental=*/false);58printExtensionTable(OS, Extensions, /*Experimental=*/true);59}6061OS << "#endif // GET_SUPPORTED_EXTENSIONS\n\n";6263OS << "#ifdef GET_IMPLIED_EXTENSIONS\n";64OS << "#undef GET_IMPLIED_EXTENSIONS\n\n";6566if (!Extensions.empty()) {67OS << "\nstatic constexpr ImpliedExtsEntry ImpliedExts[] = {\n";68for (Record *Ext : Extensions) {69auto ImpliesList = Ext->getValueAsListOfDefs("Implies");70if (ImpliesList.empty())71continue;7273StringRef Name = getExtensionName(Ext);7475for (auto *ImpliedExt : ImpliesList) {76if (!ImpliedExt->isSubClassOf("RISCVExtension"))77continue;7879OS << " { {\"" << Name << "\"}, \"" << getExtensionName(ImpliedExt)80<< "\"},\n";81}82}8384OS << "};\n\n";85}8687OS << "#endif // GET_IMPLIED_EXTENSIONS\n\n";88}8990// We can generate march string from target features as what has been described91// in RISC-V ISA specification (version 20191213) 'Chapter 27. ISA Extension92// Naming Conventions'.93//94// This is almost the same as RISCVFeatures::parseFeatureBits, except that we95// get feature name from feature records instead of feature bits.96static void printMArch(raw_ostream &OS, const std::vector<Record *> &Features) {97RISCVISAUtils::OrderedExtensionMap Extensions;98unsigned XLen = 0;99100// Convert features to FeatureVector.101for (auto *Feature : Features) {102StringRef FeatureName = getExtensionName(Feature);103if (Feature->isSubClassOf("RISCVExtension")) {104unsigned Major = Feature->getValueAsInt("MajorVersion");105unsigned Minor = Feature->getValueAsInt("MinorVersion");106Extensions[FeatureName.str()] = {Major, Minor};107} else if (FeatureName == "64bit") {108assert(XLen == 0 && "Already determined XLen");109XLen = 64;110} else if (FeatureName == "32bit") {111assert(XLen == 0 && "Already determined XLen");112XLen = 32;113}114}115116assert(XLen != 0 && "Unable to determine XLen");117118OS << "rv" << XLen;119120ListSeparator LS("_");121for (auto const &Ext : Extensions)122OS << LS << Ext.first << Ext.second.Major << 'p' << Ext.second.Minor;123}124125static void printProfileTable(raw_ostream &OS,126const std::vector<Record *> &Profiles,127bool Experimental) {128OS << "static constexpr RISCVProfile Supported";129if (Experimental)130OS << "Experimental";131OS << "Profiles[] = {\n";132133for (const Record *Rec : Profiles) {134if (Rec->getValueAsBit("Experimental") != Experimental)135continue;136137StringRef Name = Rec->getValueAsString("Name");138Name.consume_front("experimental-");139OS.indent(4) << "{\"" << Name << "\",\"";140printMArch(OS, Rec->getValueAsListOfDefs("Implies"));141OS << "\"},\n";142}143144OS << "};\n\n";145}146147static void emitRISCVProfiles(RecordKeeper &Records, raw_ostream &OS) {148OS << "#ifdef GET_SUPPORTED_PROFILES\n";149OS << "#undef GET_SUPPORTED_PROFILES\n\n";150151auto Profiles = Records.getAllDerivedDefinitionsIfDefined("RISCVProfile");152153if (!Profiles.empty()) {154printProfileTable(OS, Profiles, /*Experimental=*/false);155bool HasExperimentalProfiles = any_of(Profiles, [&](auto &Rec) {156return Rec->getValueAsBit("Experimental");157});158if (HasExperimentalProfiles)159printProfileTable(OS, Profiles, /*Experimental=*/true);160}161162OS << "#endif // GET_SUPPORTED_PROFILES\n\n";163}164165static void emitRISCVProcs(RecordKeeper &RK, raw_ostream &OS) {166OS << "#ifndef PROC\n"167<< "#define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN"168<< ", FAST_VECTOR_UNALIGN)\n"169<< "#endif\n\n";170171// Iterate on all definition records.172for (const Record *Rec :173RK.getAllDerivedDefinitionsIfDefined("RISCVProcessorModel")) {174const std::vector<Record *> &Features =175Rec->getValueAsListOfDefs("Features");176bool FastScalarUnalignedAccess = any_of(Features, [&](auto &Feature) {177return Feature->getValueAsString("Name") == "unaligned-scalar-mem";178});179180bool FastVectorUnalignedAccess = any_of(Features, [&](auto &Feature) {181return Feature->getValueAsString("Name") == "unaligned-vector-mem";182});183184OS << "PROC(" << Rec->getName() << ", {\"" << Rec->getValueAsString("Name")185<< "\"}, {\"";186187StringRef MArch = Rec->getValueAsString("DefaultMarch");188189// Compute MArch from features if we don't specify it.190if (MArch.empty())191printMArch(OS, Features);192else193OS << MArch;194OS << "\"}, " << FastScalarUnalignedAccess << ", "195<< FastVectorUnalignedAccess << ")\n";196}197OS << "\n#undef PROC\n";198OS << "\n";199OS << "#ifndef TUNE_PROC\n"200<< "#define TUNE_PROC(ENUM, NAME)\n"201<< "#endif\n\n";202203for (const Record *Rec :204RK.getAllDerivedDefinitionsIfDefined("RISCVTuneProcessorModel")) {205OS << "TUNE_PROC(" << Rec->getName() << ", "206<< "\"" << Rec->getValueAsString("Name") << "\")\n";207}208209OS << "\n#undef TUNE_PROC\n";210}211212static void emitRISCVExtensionBitmask(RecordKeeper &RK, raw_ostream &OS) {213214std::vector<Record *> Extensions =215RK.getAllDerivedDefinitionsIfDefined("RISCVExtensionBitmask");216llvm::sort(Extensions, [](const Record *Rec1, const Record *Rec2) {217return getExtensionName(Rec1) < getExtensionName(Rec2);218});219220#ifndef NDEBUG221llvm::DenseSet<std::pair<uint64_t, uint64_t>> Seen;222#endif223224OS << "#ifdef GET_RISCVExtensionBitmaskTable_IMPL\n";225OS << "static const RISCVExtensionBitmask ExtensionBitmask[]={\n";226for (const Record *Rec : Extensions) {227unsigned GroupIDVal = Rec->getValueAsInt("GroupID");228unsigned BitPosVal = Rec->getValueAsInt("BitPos");229230StringRef ExtName = Rec->getValueAsString("Name");231ExtName.consume_front("experimental-");232233#ifndef NDEBUG234assert(Seen.insert(std::make_pair(GroupIDVal, BitPosVal)).second &&235"duplicated bitmask");236#endif237238OS << " {"239<< "\"" << ExtName << "\""240<< ", " << GroupIDVal << ", " << BitPosVal << "ULL"241<< "},\n";242}243OS << "};\n";244OS << "#endif\n";245}246247static void EmitRISCVTargetDef(RecordKeeper &RK, raw_ostream &OS) {248emitRISCVExtensions(RK, OS);249emitRISCVProfiles(RK, OS);250emitRISCVProcs(RK, OS);251emitRISCVExtensionBitmask(RK, OS);252}253254static TableGen::Emitter::Opt X("gen-riscv-target-def", EmitRISCVTargetDef,255"Generate the list of CPUs and extensions for "256"RISC-V");257258259