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