127f30029SMichael Kruse //===- RISCVTargetDefEmitter.cpp - Generate lists of RISC-V CPUs ----------===// 227f30029SMichael Kruse // 327f30029SMichael Kruse // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 427f30029SMichael Kruse // See https://llvm.org/LICENSE.txt for license information. 527f30029SMichael Kruse // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 627f30029SMichael Kruse // 727f30029SMichael Kruse //===----------------------------------------------------------------------===// 827f30029SMichael Kruse // 927f30029SMichael Kruse // This tablegen backend emits the include file needed by RISCVTargetParser.cpp 1027f30029SMichael Kruse // and RISCVISAInfo.cpp to parse the RISC-V CPUs and extensions. 1127f30029SMichael Kruse // 1227f30029SMichael Kruse //===----------------------------------------------------------------------===// 1327f30029SMichael Kruse 1427f30029SMichael Kruse #include "llvm/ADT/DenseSet.h" 1527f30029SMichael Kruse #include "llvm/Support/Format.h" 1627f30029SMichael Kruse #include "llvm/Support/RISCVISAUtils.h" 1727f30029SMichael Kruse #include "llvm/TableGen/Record.h" 1827f30029SMichael Kruse #include "llvm/TableGen/TableGenBackend.h" 1927f30029SMichael Kruse 2027f30029SMichael Kruse using namespace llvm; 2127f30029SMichael Kruse 2227f30029SMichael Kruse static StringRef getExtensionName(const Record *R) { 2327f30029SMichael Kruse StringRef Name = R->getValueAsString("Name"); 2427f30029SMichael Kruse Name.consume_front("experimental-"); 2527f30029SMichael Kruse return Name; 2627f30029SMichael Kruse } 2727f30029SMichael Kruse 2827f30029SMichael Kruse static void printExtensionTable(raw_ostream &OS, 2927f30029SMichael Kruse ArrayRef<const Record *> Extensions, 3027f30029SMichael Kruse bool Experimental) { 3127f30029SMichael Kruse OS << "static const RISCVSupportedExtension Supported"; 3227f30029SMichael Kruse if (Experimental) 3327f30029SMichael Kruse OS << "Experimental"; 3427f30029SMichael Kruse OS << "Extensions[] = {\n"; 3527f30029SMichael Kruse 3627f30029SMichael Kruse for (const Record *R : Extensions) { 3727f30029SMichael Kruse if (R->getValueAsBit("Experimental") != Experimental) 3827f30029SMichael Kruse continue; 3927f30029SMichael Kruse 4027f30029SMichael Kruse OS.indent(4) << "{\"" << getExtensionName(R) << "\", {" 4127f30029SMichael Kruse << R->getValueAsInt("MajorVersion") << ", " 4227f30029SMichael Kruse << R->getValueAsInt("MinorVersion") << "}},\n"; 4327f30029SMichael Kruse } 4427f30029SMichael Kruse 4527f30029SMichael Kruse OS << "};\n\n"; 4627f30029SMichael Kruse } 4727f30029SMichael Kruse 4827f30029SMichael Kruse static void emitRISCVExtensions(const RecordKeeper &Records, raw_ostream &OS) { 4927f30029SMichael Kruse OS << "#ifdef GET_SUPPORTED_EXTENSIONS\n"; 5027f30029SMichael Kruse OS << "#undef GET_SUPPORTED_EXTENSIONS\n\n"; 5127f30029SMichael Kruse 5227f30029SMichael Kruse std::vector<const Record *> Extensions = 5327f30029SMichael Kruse Records.getAllDerivedDefinitionsIfDefined("RISCVExtension"); 5427f30029SMichael Kruse llvm::sort(Extensions, [](const Record *Rec1, const Record *Rec2) { 5527f30029SMichael Kruse return getExtensionName(Rec1) < getExtensionName(Rec2); 5627f30029SMichael Kruse }); 5727f30029SMichael Kruse 5827f30029SMichael Kruse if (!Extensions.empty()) { 5927f30029SMichael Kruse printExtensionTable(OS, Extensions, /*Experimental=*/false); 6027f30029SMichael Kruse printExtensionTable(OS, Extensions, /*Experimental=*/true); 6127f30029SMichael Kruse } 6227f30029SMichael Kruse 6327f30029SMichael Kruse OS << "#endif // GET_SUPPORTED_EXTENSIONS\n\n"; 6427f30029SMichael Kruse 6527f30029SMichael Kruse OS << "#ifdef GET_IMPLIED_EXTENSIONS\n"; 6627f30029SMichael Kruse OS << "#undef GET_IMPLIED_EXTENSIONS\n\n"; 6727f30029SMichael Kruse 6827f30029SMichael Kruse if (!Extensions.empty()) { 6927f30029SMichael Kruse OS << "\nstatic constexpr ImpliedExtsEntry ImpliedExts[] = {\n"; 7027f30029SMichael Kruse for (const Record *Ext : Extensions) { 7127f30029SMichael Kruse auto ImpliesList = Ext->getValueAsListOfDefs("Implies"); 7227f30029SMichael Kruse if (ImpliesList.empty()) 7327f30029SMichael Kruse continue; 7427f30029SMichael Kruse 7527f30029SMichael Kruse StringRef Name = getExtensionName(Ext); 7627f30029SMichael Kruse 7727f30029SMichael Kruse for (auto *ImpliedExt : ImpliesList) { 7827f30029SMichael Kruse if (!ImpliedExt->isSubClassOf("RISCVExtension")) 7927f30029SMichael Kruse continue; 8027f30029SMichael Kruse 8127f30029SMichael Kruse OS.indent(4) << "{ {\"" << Name << "\"}, \"" 8227f30029SMichael Kruse << getExtensionName(ImpliedExt) << "\"},\n"; 8327f30029SMichael Kruse } 8427f30029SMichael Kruse } 8527f30029SMichael Kruse 8627f30029SMichael Kruse OS << "};\n\n"; 8727f30029SMichael Kruse } 8827f30029SMichael Kruse 8927f30029SMichael Kruse OS << "#endif // GET_IMPLIED_EXTENSIONS\n\n"; 9027f30029SMichael Kruse } 9127f30029SMichael Kruse 9227f30029SMichael Kruse // We can generate march string from target features as what has been described 9327f30029SMichael Kruse // in RISC-V ISA specification (version 20191213) 'Chapter 27. ISA Extension 9427f30029SMichael Kruse // Naming Conventions'. 9527f30029SMichael Kruse // 9627f30029SMichael Kruse // This is almost the same as RISCVFeatures::parseFeatureBits, except that we 9727f30029SMichael Kruse // get feature name from feature records instead of feature bits. 9827f30029SMichael Kruse static void printMArch(raw_ostream &OS, ArrayRef<const Record *> Features) { 9927f30029SMichael Kruse RISCVISAUtils::OrderedExtensionMap Extensions; 10027f30029SMichael Kruse unsigned XLen = 0; 10127f30029SMichael Kruse 10227f30029SMichael Kruse // Convert features to FeatureVector. 10327f30029SMichael Kruse for (const Record *Feature : Features) { 10427f30029SMichael Kruse StringRef FeatureName = getExtensionName(Feature); 10527f30029SMichael Kruse if (Feature->isSubClassOf("RISCVExtension")) { 10627f30029SMichael Kruse unsigned Major = Feature->getValueAsInt("MajorVersion"); 10727f30029SMichael Kruse unsigned Minor = Feature->getValueAsInt("MinorVersion"); 10827f30029SMichael Kruse Extensions[FeatureName.str()] = {Major, Minor}; 10927f30029SMichael Kruse } else if (FeatureName == "64bit") { 11027f30029SMichael Kruse assert(XLen == 0 && "Already determined XLen"); 11127f30029SMichael Kruse XLen = 64; 11227f30029SMichael Kruse } else if (FeatureName == "32bit") { 11327f30029SMichael Kruse assert(XLen == 0 && "Already determined XLen"); 11427f30029SMichael Kruse XLen = 32; 11527f30029SMichael Kruse } 11627f30029SMichael Kruse } 11727f30029SMichael Kruse 11827f30029SMichael Kruse assert(XLen != 0 && "Unable to determine XLen"); 11927f30029SMichael Kruse 12027f30029SMichael Kruse OS << "rv" << XLen; 12127f30029SMichael Kruse 12227f30029SMichael Kruse ListSeparator LS("_"); 12327f30029SMichael Kruse for (auto const &Ext : Extensions) 12427f30029SMichael Kruse OS << LS << Ext.first << Ext.second.Major << 'p' << Ext.second.Minor; 12527f30029SMichael Kruse } 12627f30029SMichael Kruse 12727f30029SMichael Kruse static void printProfileTable(raw_ostream &OS, 12827f30029SMichael Kruse ArrayRef<const Record *> Profiles, 12927f30029SMichael Kruse bool Experimental) { 13027f30029SMichael Kruse OS << "static constexpr RISCVProfile Supported"; 13127f30029SMichael Kruse if (Experimental) 13227f30029SMichael Kruse OS << "Experimental"; 13327f30029SMichael Kruse OS << "Profiles[] = {\n"; 13427f30029SMichael Kruse 13527f30029SMichael Kruse for (const Record *Rec : Profiles) { 13627f30029SMichael Kruse if (Rec->getValueAsBit("Experimental") != Experimental) 13727f30029SMichael Kruse continue; 13827f30029SMichael Kruse 13927f30029SMichael Kruse StringRef Name = Rec->getValueAsString("Name"); 14027f30029SMichael Kruse Name.consume_front("experimental-"); 14127f30029SMichael Kruse OS.indent(4) << "{\"" << Name << "\",\""; 14227f30029SMichael Kruse printMArch(OS, Rec->getValueAsListOfDefs("Implies")); 14327f30029SMichael Kruse OS << "\"},\n"; 14427f30029SMichael Kruse } 14527f30029SMichael Kruse 14627f30029SMichael Kruse OS << "};\n\n"; 14727f30029SMichael Kruse } 14827f30029SMichael Kruse 14927f30029SMichael Kruse static void emitRISCVProfiles(const RecordKeeper &Records, raw_ostream &OS) { 15027f30029SMichael Kruse OS << "#ifdef GET_SUPPORTED_PROFILES\n"; 15127f30029SMichael Kruse OS << "#undef GET_SUPPORTED_PROFILES\n\n"; 15227f30029SMichael Kruse 15327f30029SMichael Kruse auto Profiles = Records.getAllDerivedDefinitionsIfDefined("RISCVProfile"); 15427f30029SMichael Kruse 15527f30029SMichael Kruse if (!Profiles.empty()) { 15627f30029SMichael Kruse printProfileTable(OS, Profiles, /*Experimental=*/false); 15727f30029SMichael Kruse bool HasExperimentalProfiles = any_of(Profiles, [&](auto &Rec) { 15827f30029SMichael Kruse return Rec->getValueAsBit("Experimental"); 15927f30029SMichael Kruse }); 16027f30029SMichael Kruse if (HasExperimentalProfiles) 16127f30029SMichael Kruse printProfileTable(OS, Profiles, /*Experimental=*/true); 16227f30029SMichael Kruse } 16327f30029SMichael Kruse 16427f30029SMichael Kruse OS << "#endif // GET_SUPPORTED_PROFILES\n\n"; 16527f30029SMichael Kruse } 16627f30029SMichael Kruse 16727f30029SMichael Kruse static void emitRISCVProcs(const RecordKeeper &RK, raw_ostream &OS) { 16827f30029SMichael Kruse OS << "#ifndef PROC\n" 16927f30029SMichael Kruse << "#define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN" 17027f30029SMichael Kruse << ", FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID)\n" 17127f30029SMichael Kruse << "#endif\n\n"; 17227f30029SMichael Kruse 17327f30029SMichael Kruse // Iterate on all definition records. 17427f30029SMichael Kruse for (const Record *Rec : 17527f30029SMichael Kruse RK.getAllDerivedDefinitionsIfDefined("RISCVProcessorModel")) { 17627f30029SMichael Kruse const std::vector<const Record *> &Features = 17727f30029SMichael Kruse Rec->getValueAsListOfDefs("Features"); 17827f30029SMichael Kruse bool FastScalarUnalignedAccess = any_of(Features, [&](auto &Feature) { 17927f30029SMichael Kruse return Feature->getValueAsString("Name") == "unaligned-scalar-mem"; 18027f30029SMichael Kruse }); 18127f30029SMichael Kruse 18227f30029SMichael Kruse bool FastVectorUnalignedAccess = any_of(Features, [&](auto &Feature) { 18327f30029SMichael Kruse return Feature->getValueAsString("Name") == "unaligned-vector-mem"; 18427f30029SMichael Kruse }); 18527f30029SMichael Kruse 18627f30029SMichael Kruse OS << "PROC(" << Rec->getName() << ", {\"" << Rec->getValueAsString("Name") 18727f30029SMichael Kruse << "\"}, {\""; 18827f30029SMichael Kruse 18927f30029SMichael Kruse StringRef MArch = Rec->getValueAsString("DefaultMarch"); 19027f30029SMichael Kruse 19127f30029SMichael Kruse // Compute MArch from features if we don't specify it. 19227f30029SMichael Kruse if (MArch.empty()) 19327f30029SMichael Kruse printMArch(OS, Features); 19427f30029SMichael Kruse else 19527f30029SMichael Kruse OS << MArch; 19627f30029SMichael Kruse 19727f30029SMichael Kruse uint32_t MVendorID = Rec->getValueAsInt("MVendorID"); 19827f30029SMichael Kruse uint64_t MArchID = Rec->getValueAsInt("MArchID"); 19927f30029SMichael Kruse uint64_t MImpID = Rec->getValueAsInt("MImpID"); 20027f30029SMichael Kruse 20127f30029SMichael Kruse OS << "\"}, " << FastScalarUnalignedAccess << ", " 20227f30029SMichael Kruse << FastVectorUnalignedAccess; 20327f30029SMichael Kruse OS << ", " << format_hex(MVendorID, 10); 20427f30029SMichael Kruse OS << ", " << format_hex(MArchID, 18); 20527f30029SMichael Kruse OS << ", " << format_hex(MImpID, 18); 20627f30029SMichael Kruse OS << ")\n"; 20727f30029SMichael Kruse } 20827f30029SMichael Kruse OS << "\n#undef PROC\n"; 20927f30029SMichael Kruse OS << "\n"; 21027f30029SMichael Kruse OS << "#ifndef TUNE_PROC\n" 21127f30029SMichael Kruse << "#define TUNE_PROC(ENUM, NAME)\n" 21227f30029SMichael Kruse << "#endif\n\n"; 21327f30029SMichael Kruse 21427f30029SMichael Kruse for (const Record *Rec : 21527f30029SMichael Kruse RK.getAllDerivedDefinitionsIfDefined("RISCVTuneProcessorModel")) { 21627f30029SMichael Kruse OS << "TUNE_PROC(" << Rec->getName() << ", " 21727f30029SMichael Kruse << "\"" << Rec->getValueAsString("Name") << "\")\n"; 21827f30029SMichael Kruse } 21927f30029SMichael Kruse 22027f30029SMichael Kruse OS << "\n#undef TUNE_PROC\n"; 22127f30029SMichael Kruse } 22227f30029SMichael Kruse 22327f30029SMichael Kruse static void emitRISCVExtensionBitmask(const RecordKeeper &RK, raw_ostream &OS) { 22427f30029SMichael Kruse std::vector<const Record *> Extensions = 22527f30029SMichael Kruse RK.getAllDerivedDefinitionsIfDefined("RISCVExtensionBitmask"); 22627f30029SMichael Kruse llvm::sort(Extensions, [](const Record *Rec1, const Record *Rec2) { 22727f30029SMichael Kruse return getExtensionName(Rec1) < getExtensionName(Rec2); 22827f30029SMichael Kruse }); 22927f30029SMichael Kruse 23027f30029SMichael Kruse #ifndef NDEBUG 23127f30029SMichael Kruse llvm::DenseSet<std::pair<uint64_t, uint64_t>> Seen; 23227f30029SMichael Kruse #endif 23327f30029SMichael Kruse 23427f30029SMichael Kruse OS << "#ifdef GET_RISCVExtensionBitmaskTable_IMPL\n"; 23527f30029SMichael Kruse OS << "static const RISCVExtensionBitmask ExtensionBitmask[]={\n"; 23627f30029SMichael Kruse for (const Record *Rec : Extensions) { 23727f30029SMichael Kruse unsigned GroupIDVal = Rec->getValueAsInt("GroupID"); 23827f30029SMichael Kruse unsigned BitPosVal = Rec->getValueAsInt("BitPos"); 23927f30029SMichael Kruse 24027f30029SMichael Kruse StringRef ExtName = Rec->getValueAsString("Name"); 24127f30029SMichael Kruse ExtName.consume_front("experimental-"); 24227f30029SMichael Kruse 24327f30029SMichael Kruse #ifndef NDEBUG 244*4e8c9d28SJay Foad assert(Seen.insert({GroupIDVal, BitPosVal}).second && "duplicated bitmask"); 24527f30029SMichael Kruse #endif 24627f30029SMichael Kruse 24727f30029SMichael Kruse OS.indent(4) << "{" 24827f30029SMichael Kruse << "\"" << ExtName << "\"" 24927f30029SMichael Kruse << ", " << GroupIDVal << ", " << BitPosVal << "ULL" 25027f30029SMichael Kruse << "},\n"; 25127f30029SMichael Kruse } 25227f30029SMichael Kruse OS << "};\n"; 25327f30029SMichael Kruse OS << "#endif\n"; 25427f30029SMichael Kruse } 25527f30029SMichael Kruse 25627f30029SMichael Kruse static void emitRiscvTargetDef(const RecordKeeper &RK, raw_ostream &OS) { 25727f30029SMichael Kruse emitRISCVExtensions(RK, OS); 25827f30029SMichael Kruse emitRISCVProfiles(RK, OS); 25927f30029SMichael Kruse emitRISCVProcs(RK, OS); 26027f30029SMichael Kruse emitRISCVExtensionBitmask(RK, OS); 26127f30029SMichael Kruse } 26227f30029SMichael Kruse 26327f30029SMichael Kruse static TableGen::Emitter::Opt X("gen-riscv-target-def", emitRiscvTargetDef, 26427f30029SMichael Kruse "Generate the list of CPUs and extensions for " 26527f30029SMichael Kruse "RISC-V"); 266