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