1 //===- RISCVTargetDefEmitter.cpp - Generate lists of RISC-V CPUs ----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This tablegen backend emits the include file needed by RISCVTargetParser.cpp
10 // and RISCVISAInfo.cpp to parse the RISC-V CPUs and extensions.
12 //===----------------------------------------------------------------------===//
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"
22 static StringRef
getExtensionName(const Record
*R
) {
23 StringRef Name
= R
->getValueAsString("Name");
24 Name
.consume_front("experimental-");
28 static void printExtensionTable(raw_ostream
&OS
,
29 ArrayRef
<const Record
*> Extensions
,
31 OS
<< "static const RISCVSupportedExtension Supported";
34 OS
<< "Extensions[] = {\n";
36 for (const Record
*R
: Extensions
) {
37 if (R
->getValueAsBit("Experimental") != Experimental
)
40 OS
.indent(4) << "{\"" << getExtensionName(R
) << "\", {"
41 << R
->getValueAsInt("MajorVersion") << ", "
42 << R
->getValueAsInt("MinorVersion") << "}},\n";
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";
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
);
58 if (!Extensions
.empty()) {
59 printExtensionTable(OS
, Extensions
, /*Experimental=*/false);
60 printExtensionTable(OS
, Extensions
, /*Experimental=*/true);
63 OS
<< "#endif // GET_SUPPORTED_EXTENSIONS\n\n";
65 OS
<< "#ifdef GET_IMPLIED_EXTENSIONS\n";
66 OS
<< "#undef GET_IMPLIED_EXTENSIONS\n\n";
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())
75 StringRef Name
= getExtensionName(Ext
);
77 for (auto *ImpliedExt
: ImpliesList
) {
78 if (!ImpliedExt
->isSubClassOf("RISCVExtension"))
81 OS
.indent(4) << "{ {\"" << Name
<< "\"}, \""
82 << getExtensionName(ImpliedExt
) << "\"},\n";
89 OS
<< "#endif // GET_IMPLIED_EXTENSIONS\n\n";
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'.
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
;
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");
112 } else if (FeatureName
== "32bit") {
113 assert(XLen
== 0 && "Already determined XLen");
118 assert(XLen
!= 0 && "Unable to determine XLen");
122 ListSeparator
LS("_");
123 for (auto const &Ext
: Extensions
)
124 OS
<< LS
<< Ext
.first
<< Ext
.second
.Major
<< 'p' << Ext
.second
.Minor
;
127 static void printProfileTable(raw_ostream
&OS
,
128 ArrayRef
<const Record
*> Profiles
,
130 OS
<< "static constexpr RISCVProfile Supported";
132 OS
<< "Experimental";
133 OS
<< "Profiles[] = {\n";
135 for (const Record
*Rec
: Profiles
) {
136 if (Rec
->getValueAsBit("Experimental") != Experimental
)
139 StringRef Name
= Rec
->getValueAsString("Name");
140 Name
.consume_front("experimental-");
141 OS
.indent(4) << "{\"" << Name
<< "\",\"";
142 printMArch(OS
, Rec
->getValueAsListOfDefs("Implies"));
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";
153 auto Profiles
= Records
.getAllDerivedDefinitionsIfDefined("RISCVProfile");
155 if (!Profiles
.empty()) {
156 printProfileTable(OS
, Profiles
, /*Experimental=*/false);
157 bool HasExperimentalProfiles
= any_of(Profiles
, [&](auto &Rec
) {
158 return Rec
->getValueAsBit("Experimental");
160 if (HasExperimentalProfiles
)
161 printProfileTable(OS
, Profiles
, /*Experimental=*/true);
164 OS
<< "#endif // GET_SUPPORTED_PROFILES\n\n";
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"
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";
182 bool FastVectorUnalignedAccess
= any_of(Features
, [&](auto &Feature
) {
183 return Feature
->getValueAsString("Name") == "unaligned-vector-mem";
186 OS
<< "PROC(" << Rec
->getName() << ", {\"" << Rec
->getValueAsString("Name")
189 StringRef MArch
= Rec
->getValueAsString("DefaultMarch");
191 // Compute MArch from features if we don't specify it.
193 printMArch(OS
, Features
);
197 uint32_t MVendorID
= Rec
->getValueAsInt("MVendorID");
198 uint64_t MArchID
= Rec
->getValueAsInt("MArchID");
199 uint64_t MImpID
= Rec
->getValueAsInt("MImpID");
201 OS
<< "\"}, " << FastScalarUnalignedAccess
<< ", "
202 << FastVectorUnalignedAccess
;
203 OS
<< ", " << format_hex(MVendorID
, 10);
204 OS
<< ", " << format_hex(MArchID
, 18);
205 OS
<< ", " << format_hex(MImpID
, 18);
208 OS
<< "\n#undef PROC\n";
210 OS
<< "#ifndef TUNE_PROC\n"
211 << "#define TUNE_PROC(ENUM, NAME)\n"
214 for (const Record
*Rec
:
215 RK
.getAllDerivedDefinitionsIfDefined("RISCVTuneProcessorModel")) {
216 OS
<< "TUNE_PROC(" << Rec
->getName() << ", "
217 << "\"" << Rec
->getValueAsString("Name") << "\")\n";
220 OS
<< "\n#undef TUNE_PROC\n";
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 return getExtensionName(Rec1
) < getExtensionName(Rec2
);
231 llvm::DenseSet
<std::pair
<uint64_t, uint64_t>> Seen
;
234 OS
<< "#ifdef GET_RISCVExtensionBitmaskTable_IMPL\n";
235 OS
<< "static const RISCVExtensionBitmask ExtensionBitmask[]={\n";
236 for (const Record
*Rec
: Extensions
) {
237 unsigned GroupIDVal
= Rec
->getValueAsInt("GroupID");
238 unsigned BitPosVal
= Rec
->getValueAsInt("BitPos");
240 StringRef ExtName
= Rec
->getValueAsString("Name");
241 ExtName
.consume_front("experimental-");
244 assert(Seen
.insert(std::make_pair(GroupIDVal
, BitPosVal
)).second
&&
245 "duplicated bitmask");
249 << "\"" << ExtName
<< "\""
250 << ", " << GroupIDVal
<< ", " << BitPosVal
<< "ULL"
257 static void emitRiscvTargetDef(const RecordKeeper
&RK
, raw_ostream
&OS
) {
258 emitRISCVExtensions(RK
, OS
);
259 emitRISCVProfiles(RK
, OS
);
260 emitRISCVProcs(RK
, OS
);
261 emitRISCVExtensionBitmask(RK
, OS
);
264 static TableGen::Emitter::Opt
X("gen-riscv-target-def", emitRiscvTargetDef
,
265 "Generate the list of CPUs and extensions for "