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