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