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