xref: /llvm-project/llvm/utils/TableGen/Basic/RISCVTargetDefEmitter.cpp (revision 4e8c9d28132039a98feb97cec2759cddeb37d934)
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