1//===-- RISCVISAInfo.cpp - RISC-V Arch String Parser ------------*- C++ -*-===//
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#include "llvm/Support/RISCVISAInfo.h"
10#include "llvm/ADT/MapVector.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/SetVector.h"
13#include "llvm/ADT/StringExtras.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/Errc.h"
16#include "llvm/Support/Error.h"
17#include "llvm/Support/raw_ostream.h"
18
19#include <array>
20#include <atomic>
21#include <optional>
22#include <string>
23#include <vector>
24
25using namespace llvm;
26
27namespace {
28
29struct RISCVSupportedExtension {
30 const char *Name;
31 /// Supported version.
32 RISCVISAInfo::ExtensionVersion Version;
33
34 bool operator<(const RISCVSupportedExtension &RHS) const {
35 return StringRef(Name) < StringRef(RHS.Name);
36 }
37};
38
39} // end anonymous namespace
40
41static constexpr StringLiteral AllStdExts = "mafdqlcbkjtpvnh";
42
43static const char *RISCVGImplications[] = {
44 "i", "m", "a", "f", "d", "zicsr", "zifencei"
45};
46
47// NOTE: This table should be sorted alphabetically by extension name.
48static const RISCVSupportedExtension SupportedExtensions[] = {
49 {.Name: "a", .Version: {.Major: 2, .Minor: 1}},
50 {.Name: "c", .Version: {.Major: 2, .Minor: 0}},
51 {.Name: "d", .Version: {.Major: 2, .Minor: 2}},
52 {.Name: "e", .Version: {.Major: 2, .Minor: 0}},
53 {.Name: "f", .Version: {.Major: 2, .Minor: 2}},
54 {.Name: "h", .Version: {.Major: 1, .Minor: 0}},
55 {.Name: "i", .Version: {.Major: 2, .Minor: 1}},
56 {.Name: "m", .Version: {.Major: 2, .Minor: 0}},
57
58 {.Name: "shcounterenw", .Version: {.Major: 1, .Minor: 0}},
59 {.Name: "shgatpa", .Version: {.Major: 1, .Minor: 0}},
60 {.Name: "shtvala", .Version: {.Major: 1, .Minor: 0}},
61 {.Name: "shvsatpa", .Version: {.Major: 1, .Minor: 0}},
62 {.Name: "shvstvala", .Version: {.Major: 1, .Minor: 0}},
63 {.Name: "shvstvecd", .Version: {.Major: 1, .Minor: 0}},
64 {.Name: "smaia", .Version: {.Major: 1, .Minor: 0}},
65 {.Name: "smepmp", .Version: {.Major: 1, .Minor: 0}},
66 {.Name: "ssaia", .Version: {.Major: 1, .Minor: 0}},
67 {.Name: "ssccptr", .Version: {.Major: 1, .Minor: 0}},
68 {.Name: "sscounterenw", .Version: {.Major: 1, .Minor: 0}},
69 {.Name: "ssstateen", .Version: {.Major: 1, .Minor: 0}},
70 {.Name: "ssstrict", .Version: {.Major: 1, .Minor: 0}},
71 {.Name: "sstc", .Version: {.Major: 1, .Minor: 0}},
72 {.Name: "sstvala", .Version: {.Major: 1, .Minor: 0}},
73 {.Name: "sstvecd", .Version: {.Major: 1, .Minor: 0}},
74 {.Name: "ssu64xl", .Version: {.Major: 1, .Minor: 0}},
75 {.Name: "svade", .Version: {.Major: 1, .Minor: 0}},
76 {.Name: "svadu", .Version: {.Major: 1, .Minor: 0}},
77 {.Name: "svbare", .Version: {.Major: 1, .Minor: 0}},
78 {.Name: "svinval", .Version: {.Major: 1, .Minor: 0}},
79 {.Name: "svnapot", .Version: {.Major: 1, .Minor: 0}},
80 {.Name: "svpbmt", .Version: {.Major: 1, .Minor: 0}},
81
82 {.Name: "v", .Version: {.Major: 1, .Minor: 0}},
83
84 // vendor-defined ('X') extensions
85 {.Name: "xcvalu", .Version: {.Major: 1, .Minor: 0}},
86 {.Name: "xcvbi", .Version: {.Major: 1, .Minor: 0}},
87 {.Name: "xcvbitmanip", .Version: {.Major: 1, .Minor: 0}},
88 {.Name: "xcvelw", .Version: {.Major: 1, .Minor: 0}},
89 {.Name: "xcvmac", .Version: {.Major: 1, .Minor: 0}},
90 {.Name: "xcvmem", .Version: {.Major: 1, .Minor: 0}},
91 {.Name: "xcvsimd", .Version: {.Major: 1, .Minor: 0}},
92 {.Name: "xsfvcp", .Version: {.Major: 1, .Minor: 0}},
93 {.Name: "xsfvfnrclipxfqf", .Version: {.Major: 1, .Minor: 0}},
94 {.Name: "xsfvfwmaccqqq", .Version: {.Major: 1, .Minor: 0}},
95 {.Name: "xsfvqmaccdod", .Version: {.Major: 1, .Minor: 0}},
96 {.Name: "xsfvqmaccqoq", .Version: {.Major: 1, .Minor: 0}},
97 {.Name: "xtheadba", .Version: {.Major: 1, .Minor: 0}},
98 {.Name: "xtheadbb", .Version: {.Major: 1, .Minor: 0}},
99 {.Name: "xtheadbs", .Version: {.Major: 1, .Minor: 0}},
100 {.Name: "xtheadcmo", .Version: {.Major: 1, .Minor: 0}},
101 {.Name: "xtheadcondmov", .Version: {.Major: 1, .Minor: 0}},
102 {.Name: "xtheadfmemidx", .Version: {.Major: 1, .Minor: 0}},
103 {.Name: "xtheadmac", .Version: {.Major: 1, .Minor: 0}},
104 {.Name: "xtheadmemidx", .Version: {.Major: 1, .Minor: 0}},
105 {.Name: "xtheadmempair", .Version: {.Major: 1, .Minor: 0}},
106 {.Name: "xtheadsync", .Version: {.Major: 1, .Minor: 0}},
107 {.Name: "xtheadvdot", .Version: {.Major: 1, .Minor: 0}},
108 {.Name: "xventanacondops", .Version: {.Major: 1, .Minor: 0}},
109
110 {.Name: "za128rs", .Version: {.Major: 1, .Minor: 0}},
111 {.Name: "za64rs", .Version: {.Major: 1, .Minor: 0}},
112 {.Name: "zawrs", .Version: {.Major: 1, .Minor: 0}},
113
114 {.Name: "zba", .Version: {.Major: 1, .Minor: 0}},
115 {.Name: "zbb", .Version: {.Major: 1, .Minor: 0}},
116 {.Name: "zbc", .Version: {.Major: 1, .Minor: 0}},
117 {.Name: "zbkb", .Version: {.Major: 1, .Minor: 0}},
118 {.Name: "zbkc", .Version: {.Major: 1, .Minor: 0}},
119 {.Name: "zbkx", .Version: {.Major: 1, .Minor: 0}},
120 {.Name: "zbs", .Version: {.Major: 1, .Minor: 0}},
121
122 {.Name: "zca", .Version: {.Major: 1, .Minor: 0}},
123 {.Name: "zcb", .Version: {.Major: 1, .Minor: 0}},
124 {.Name: "zcd", .Version: {.Major: 1, .Minor: 0}},
125 {.Name: "zce", .Version: {.Major: 1, .Minor: 0}},
126 {.Name: "zcf", .Version: {.Major: 1, .Minor: 0}},
127 {.Name: "zcmp", .Version: {.Major: 1, .Minor: 0}},
128 {.Name: "zcmt", .Version: {.Major: 1, .Minor: 0}},
129
130 {.Name: "zdinx", .Version: {.Major: 1, .Minor: 0}},
131
132 {.Name: "zfa", .Version: {.Major: 1, .Minor: 0}},
133 {.Name: "zfh", .Version: {.Major: 1, .Minor: 0}},
134 {.Name: "zfhmin", .Version: {.Major: 1, .Minor: 0}},
135 {.Name: "zfinx", .Version: {.Major: 1, .Minor: 0}},
136
137 {.Name: "zhinx", .Version: {.Major: 1, .Minor: 0}},
138 {.Name: "zhinxmin", .Version: {.Major: 1, .Minor: 0}},
139
140 {.Name: "zic64b", .Version: {.Major: 1, .Minor: 0}},
141 {.Name: "zicbom", .Version: {.Major: 1, .Minor: 0}},
142 {.Name: "zicbop", .Version: {.Major: 1, .Minor: 0}},
143 {.Name: "zicboz", .Version: {.Major: 1, .Minor: 0}},
144 {.Name: "ziccamoa", .Version: {.Major: 1, .Minor: 0}},
145 {.Name: "ziccif", .Version: {.Major: 1, .Minor: 0}},
146 {.Name: "zicclsm", .Version: {.Major: 1, .Minor: 0}},
147 {.Name: "ziccrse", .Version: {.Major: 1, .Minor: 0}},
148 {.Name: "zicntr", .Version: {.Major: 2, .Minor: 0}},
149 {.Name: "zicond", .Version: {.Major: 1, .Minor: 0}},
150 {.Name: "zicsr", .Version: {.Major: 2, .Minor: 0}},
151 {.Name: "zifencei", .Version: {.Major: 2, .Minor: 0}},
152 {.Name: "zihintntl", .Version: {.Major: 1, .Minor: 0}},
153 {.Name: "zihintpause", .Version: {.Major: 2, .Minor: 0}},
154 {.Name: "zihpm", .Version: {.Major: 2, .Minor: 0}},
155
156 {.Name: "zk", .Version: {.Major: 1, .Minor: 0}},
157 {.Name: "zkn", .Version: {.Major: 1, .Minor: 0}},
158 {.Name: "zknd", .Version: {.Major: 1, .Minor: 0}},
159 {.Name: "zkne", .Version: {.Major: 1, .Minor: 0}},
160 {.Name: "zknh", .Version: {.Major: 1, .Minor: 0}},
161 {.Name: "zkr", .Version: {.Major: 1, .Minor: 0}},
162 {.Name: "zks", .Version: {.Major: 1, .Minor: 0}},
163 {.Name: "zksed", .Version: {.Major: 1, .Minor: 0}},
164 {.Name: "zksh", .Version: {.Major: 1, .Minor: 0}},
165 {.Name: "zkt", .Version: {.Major: 1, .Minor: 0}},
166
167 {.Name: "zmmul", .Version: {.Major: 1, .Minor: 0}},
168
169 {.Name: "zvbb", .Version: {.Major: 1, .Minor: 0}},
170 {.Name: "zvbc", .Version: {.Major: 1, .Minor: 0}},
171
172 {.Name: "zve32f", .Version: {.Major: 1, .Minor: 0}},
173 {.Name: "zve32x", .Version: {.Major: 1, .Minor: 0}},
174 {.Name: "zve64d", .Version: {.Major: 1, .Minor: 0}},
175 {.Name: "zve64f", .Version: {.Major: 1, .Minor: 0}},
176 {.Name: "zve64x", .Version: {.Major: 1, .Minor: 0}},
177
178 {.Name: "zvfh", .Version: {.Major: 1, .Minor: 0}},
179 {.Name: "zvfhmin", .Version: {.Major: 1, .Minor: 0}},
180
181 // vector crypto
182 {.Name: "zvkb", .Version: {.Major: 1, .Minor: 0}},
183 {.Name: "zvkg", .Version: {.Major: 1, .Minor: 0}},
184 {.Name: "zvkn", .Version: {.Major: 1, .Minor: 0}},
185 {.Name: "zvknc", .Version: {.Major: 1, .Minor: 0}},
186 {.Name: "zvkned", .Version: {.Major: 1, .Minor: 0}},
187 {.Name: "zvkng", .Version: {.Major: 1, .Minor: 0}},
188 {.Name: "zvknha", .Version: {.Major: 1, .Minor: 0}},
189 {.Name: "zvknhb", .Version: {.Major: 1, .Minor: 0}},
190 {.Name: "zvks", .Version: {.Major: 1, .Minor: 0}},
191 {.Name: "zvksc", .Version: {.Major: 1, .Minor: 0}},
192 {.Name: "zvksed", .Version: {.Major: 1, .Minor: 0}},
193 {.Name: "zvksg", .Version: {.Major: 1, .Minor: 0}},
194 {.Name: "zvksh", .Version: {.Major: 1, .Minor: 0}},
195 {.Name: "zvkt", .Version: {.Major: 1, .Minor: 0}},
196
197 {.Name: "zvl1024b", .Version: {.Major: 1, .Minor: 0}},
198 {.Name: "zvl128b", .Version: {.Major: 1, .Minor: 0}},
199 {.Name: "zvl16384b", .Version: {.Major: 1, .Minor: 0}},
200 {.Name: "zvl2048b", .Version: {.Major: 1, .Minor: 0}},
201 {.Name: "zvl256b", .Version: {.Major: 1, .Minor: 0}},
202 {.Name: "zvl32768b", .Version: {.Major: 1, .Minor: 0}},
203 {.Name: "zvl32b", .Version: {.Major: 1, .Minor: 0}},
204 {.Name: "zvl4096b", .Version: {.Major: 1, .Minor: 0}},
205 {.Name: "zvl512b", .Version: {.Major: 1, .Minor: 0}},
206 {.Name: "zvl64b", .Version: {.Major: 1, .Minor: 0}},
207 {.Name: "zvl65536b", .Version: {.Major: 1, .Minor: 0}},
208 {.Name: "zvl8192b", .Version: {.Major: 1, .Minor: 0}},
209};
210
211// NOTE: This table should be sorted alphabetically by extension name.
212// clang-format off
213static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
214 {.Name: "smmpm", .Version: {.Major: 0, .Minor: 8}},
215 {.Name: "smnpm", .Version: {.Major: 0, .Minor: 8}},
216 {.Name: "ssnpm", .Version: {.Major: 0, .Minor: 8}},
217 {.Name: "sspm", .Version: {.Major: 0, .Minor: 8}},
218 {.Name: "ssqosid", .Version: {.Major: 1, .Minor: 0}},
219 {.Name: "supm", .Version: {.Major: 0, .Minor: 8}},
220
221 {.Name: "zaamo", .Version: {.Major: 0, .Minor: 2}},
222 {.Name: "zabha", .Version: {.Major: 1, .Minor: 0}},
223 {.Name: "zacas", .Version: {.Major: 1, .Minor: 0}},
224 {.Name: "zalasr", .Version: {.Major: 0, .Minor: 1}},
225 {.Name: "zalrsc", .Version: {.Major: 0, .Minor: 2}},
226
227 {.Name: "zcmop", .Version: {.Major: 0, .Minor: 2}},
228
229 {.Name: "zfbfmin", .Version: {.Major: 1, .Minor: 0}},
230
231 {.Name: "zicfilp", .Version: {.Major: 0, .Minor: 4}},
232 {.Name: "zicfiss", .Version: {.Major: 0, .Minor: 4}},
233
234 {.Name: "zimop", .Version: {.Major: 0, .Minor: 1}},
235
236 {.Name: "ztso", .Version: {.Major: 0, .Minor: 1}},
237
238 {.Name: "zvfbfmin", .Version: {.Major: 1, .Minor: 0}},
239 {.Name: "zvfbfwma", .Version: {.Major: 1, .Minor: 0}},
240};
241// clang-format on
242
243static void verifyTables() {
244#ifndef NDEBUG
245 static std::atomic<bool> TableChecked(false);
246 if (!TableChecked.load(m: std::memory_order_relaxed)) {
247 assert(llvm::is_sorted(SupportedExtensions) &&
248 "Extensions are not sorted by name");
249 assert(llvm::is_sorted(SupportedExperimentalExtensions) &&
250 "Experimental extensions are not sorted by name");
251 TableChecked.store(i: true, m: std::memory_order_relaxed);
252 }
253#endif
254}
255
256static void PrintExtension(StringRef Name, StringRef Version,
257 StringRef Description) {
258 outs().indent(NumSpaces: 4);
259 unsigned VersionWidth = Description.empty() ? 0 : 10;
260 outs() << left_justify(Str: Name, Width: 20) << left_justify(Str: Version, Width: VersionWidth)
261 << Description << "\n";
262}
263
264void llvm::riscvExtensionsHelp(StringMap<StringRef> DescMap) {
265
266 outs() << "All available -march extensions for RISC-V\n\n";
267 PrintExtension(Name: "Name", Version: "Version", Description: (DescMap.empty() ? "" : "Description"));
268
269 RISCVISAInfo::OrderedExtensionMap ExtMap;
270 for (const auto &E : SupportedExtensions)
271 ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor};
272 for (const auto &E : ExtMap) {
273 std::string Version =
274 std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor);
275 PrintExtension(Name: E.first, Version, Description: DescMap[E.first]);
276 }
277
278 outs() << "\nExperimental extensions\n";
279 ExtMap.clear();
280 for (const auto &E : SupportedExperimentalExtensions)
281 ExtMap[E.Name] = {.Major: E.Version.Major, .Minor: E.Version.Minor};
282 for (const auto &E : ExtMap) {
283 std::string Version =
284 std::to_string(val: E.second.Major) + "." + std::to_string(val: E.second.Minor);
285 PrintExtension(Name: E.first, Version, Description: DescMap["experimental-" + E.first]);
286 }
287
288 outs() << "\nUse -march to specify the target's extension.\n"
289 "For example, clang -march=rv32i_v1p0\n";
290}
291
292static bool stripExperimentalPrefix(StringRef &Ext) {
293 return Ext.consume_front(Prefix: "experimental-");
294}
295
296// This function finds the last character that doesn't belong to a version
297// (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will
298// consume [0-9]*p[0-9]* starting from the backward. An extension name will not
299// end with a digit or the letter 'p', so this function will parse correctly.
300// NOTE: This function is NOT able to take empty strings or strings that only
301// have version numbers and no extension name. It assumes the extension name
302// will be at least more than one character.
303static size_t findLastNonVersionCharacter(StringRef Ext) {
304 assert(!Ext.empty() &&
305 "Already guarded by if-statement in ::parseArchString");
306
307 int Pos = Ext.size() - 1;
308 while (Pos > 0 && isDigit(C: Ext[Pos]))
309 Pos--;
310 if (Pos > 0 && Ext[Pos] == 'p' && isDigit(C: Ext[Pos - 1])) {
311 Pos--;
312 while (Pos > 0 && isDigit(C: Ext[Pos]))
313 Pos--;
314 }
315 return Pos;
316}
317
318namespace {
319struct LessExtName {
320 bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) {
321 return StringRef(LHS.Name) < RHS;
322 }
323 bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) {
324 return LHS < StringRef(RHS.Name);
325 }
326};
327} // namespace
328
329static std::optional<RISCVISAInfo::ExtensionVersion>
330findDefaultVersion(StringRef ExtName) {
331 // Find default version of an extension.
332 // TODO: We might set default version based on profile or ISA spec.
333 for (auto &ExtInfo : {ArrayRef(SupportedExtensions),
334 ArrayRef(SupportedExperimentalExtensions)}) {
335 auto I = llvm::lower_bound(Range: ExtInfo, Value&: ExtName, C: LessExtName());
336
337 if (I == ExtInfo.end() || I->Name != ExtName)
338 continue;
339
340 return I->Version;
341 }
342 return std::nullopt;
343}
344
345void RISCVISAInfo::addExtension(StringRef ExtName,
346 RISCVISAInfo::ExtensionVersion Version) {
347 Exts[ExtName.str()] = Version;
348}
349
350static StringRef getExtensionTypeDesc(StringRef Ext) {
351 if (Ext.starts_with(Prefix: "s"))
352 return "standard supervisor-level extension";
353 if (Ext.starts_with(Prefix: "x"))
354 return "non-standard user-level extension";
355 if (Ext.starts_with(Prefix: "z"))
356 return "standard user-level extension";
357 return StringRef();
358}
359
360static StringRef getExtensionType(StringRef Ext) {
361 if (Ext.starts_with(Prefix: "s"))
362 return "s";
363 if (Ext.starts_with(Prefix: "x"))
364 return "x";
365 if (Ext.starts_with(Prefix: "z"))
366 return "z";
367 return StringRef();
368}
369
370static std::optional<RISCVISAInfo::ExtensionVersion>
371isExperimentalExtension(StringRef Ext) {
372 auto I =
373 llvm::lower_bound(Range: SupportedExperimentalExtensions, Value&: Ext, C: LessExtName());
374 if (I == std::end(arr: SupportedExperimentalExtensions) || I->Name != Ext)
375 return std::nullopt;
376
377 return I->Version;
378}
379
380bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) {
381 bool IsExperimental = stripExperimentalPrefix(Ext);
382
383 ArrayRef<RISCVSupportedExtension> ExtInfo =
384 IsExperimental ? ArrayRef(SupportedExperimentalExtensions)
385 : ArrayRef(SupportedExtensions);
386
387 auto I = llvm::lower_bound(Range&: ExtInfo, Value&: Ext, C: LessExtName());
388 return I != ExtInfo.end() && I->Name == Ext;
389}
390
391bool RISCVISAInfo::isSupportedExtension(StringRef Ext) {
392 verifyTables();
393
394 for (auto ExtInfo : {ArrayRef(SupportedExtensions),
395 ArrayRef(SupportedExperimentalExtensions)}) {
396 auto I = llvm::lower_bound(Range&: ExtInfo, Value&: Ext, C: LessExtName());
397 if (I != ExtInfo.end() && I->Name == Ext)
398 return true;
399 }
400
401 return false;
402}
403
404bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
405 unsigned MinorVersion) {
406 for (auto ExtInfo : {ArrayRef(SupportedExtensions),
407 ArrayRef(SupportedExperimentalExtensions)}) {
408 auto Range =
409 std::equal_range(first: ExtInfo.begin(), last: ExtInfo.end(), val: Ext, comp: LessExtName());
410 for (auto I = Range.first, E = Range.second; I != E; ++I)
411 if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion)
412 return true;
413 }
414
415 return false;
416}
417
418bool RISCVISAInfo::hasExtension(StringRef Ext) const {
419 stripExperimentalPrefix(Ext);
420
421 if (!isSupportedExtension(Ext))
422 return false;
423
424 return Exts.count(x: Ext.str()) != 0;
425}
426
427// We rank extensions in the following order:
428// -Single letter extensions in canonical order.
429// -Unknown single letter extensions in alphabetical order.
430// -Multi-letter extensions starting with 'z' sorted by canonical order of
431// the second letter then sorted alphabetically.
432// -Multi-letter extensions starting with 's' in alphabetical order.
433// -(TODO) Multi-letter extensions starting with 'zxm' in alphabetical order.
434// -X extensions in alphabetical order.
435// These flags are used to indicate the category. The first 6 bits store the
436// single letter extension rank for single letter and multi-letter extensions
437// starting with 'z'.
438enum RankFlags {
439 RF_Z_EXTENSION = 1 << 6,
440 RF_S_EXTENSION = 1 << 7,
441 RF_X_EXTENSION = 1 << 8,
442};
443
444// Get the rank for single-letter extension, lower value meaning higher
445// priority.
446static unsigned singleLetterExtensionRank(char Ext) {
447 assert(Ext >= 'a' && Ext <= 'z');
448 switch (Ext) {
449 case 'i':
450 return 0;
451 case 'e':
452 return 1;
453 }
454
455 size_t Pos = AllStdExts.find(C: Ext);
456 if (Pos != StringRef::npos)
457 return Pos + 2; // Skip 'e' and 'i' from above.
458
459 // If we got an unknown extension letter, then give it an alphabetical
460 // order, but after all known standard extensions.
461 return 2 + AllStdExts.size() + (Ext - 'a');
462}
463
464// Get the rank for multi-letter extension, lower value meaning higher
465// priority/order in canonical order.
466static unsigned getExtensionRank(const std::string &ExtName) {
467 assert(ExtName.size() >= 1);
468 switch (ExtName[0]) {
469 case 's':
470 return RF_S_EXTENSION;
471 case 'z':
472 assert(ExtName.size() >= 2);
473 // `z` extension must be sorted by canonical order of second letter.
474 // e.g. zmx has higher rank than zax.
475 return RF_Z_EXTENSION | singleLetterExtensionRank(Ext: ExtName[1]);
476 case 'x':
477 return RF_X_EXTENSION;
478 default:
479 assert(ExtName.size() == 1);
480 return singleLetterExtensionRank(Ext: ExtName[0]);
481 }
482}
483
484// Compare function for extension.
485// Only compare the extension name, ignore version comparison.
486bool RISCVISAInfo::compareExtension(const std::string &LHS,
487 const std::string &RHS) {
488 unsigned LHSRank = getExtensionRank(ExtName: LHS);
489 unsigned RHSRank = getExtensionRank(ExtName: RHS);
490
491 // If the ranks differ, pick the lower rank.
492 if (LHSRank != RHSRank)
493 return LHSRank < RHSRank;
494
495 // If the rank is same, it must be sorted by lexicographic order.
496 return LHS < RHS;
497}
498
499std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions,
500 bool IgnoreUnknown) const {
501 std::vector<std::string> Features;
502 for (const auto &[ExtName, _] : Exts) {
503 // i is a base instruction set, not an extension (see
504 // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa)
505 // and is not recognized in clang -cc1
506 if (ExtName == "i")
507 continue;
508 if (IgnoreUnknown && !isSupportedExtension(Ext: ExtName))
509 continue;
510
511 if (isExperimentalExtension(Ext: ExtName)) {
512 Features.push_back(x: (llvm::Twine("+experimental-") + ExtName).str());
513 } else {
514 Features.push_back(x: (llvm::Twine("+") + ExtName).str());
515 }
516 }
517 if (AddAllExtensions) {
518 for (const RISCVSupportedExtension &Ext : SupportedExtensions) {
519 if (Exts.count(x: Ext.Name))
520 continue;
521 Features.push_back(x: (llvm::Twine("-") + Ext.Name).str());
522 }
523
524 for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {
525 if (Exts.count(x: Ext.Name))
526 continue;
527 Features.push_back(x: (llvm::Twine("-experimental-") + Ext.Name).str());
528 }
529 }
530 return Features;
531}
532
533// Extensions may have a version number, and may be separated by
534// an underscore '_' e.g.: rv32i2_m2.
535// Version number is divided into major and minor version numbers,
536// separated by a 'p'. If the minor version is 0 then 'p0' can be
537// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
538static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
539 unsigned &Minor, unsigned &ConsumeLength,
540 bool EnableExperimentalExtension,
541 bool ExperimentalExtensionVersionCheck) {
542 StringRef MajorStr, MinorStr;
543 Major = 0;
544 Minor = 0;
545 ConsumeLength = 0;
546 MajorStr = In.take_while(F: isDigit);
547 In = In.substr(Start: MajorStr.size());
548
549 if (!MajorStr.empty() && In.consume_front(Prefix: "p")) {
550 MinorStr = In.take_while(F: isDigit);
551 In = In.substr(Start: MajorStr.size() + MinorStr.size() - 1);
552
553 // Expected 'p' to be followed by minor version number.
554 if (MinorStr.empty()) {
555 return createStringError(
556 EC: errc::invalid_argument,
557 S: "minor version number missing after 'p' for extension '" + Ext + "'");
558 }
559 }
560
561 if (!MajorStr.empty() && MajorStr.getAsInteger(Radix: 10, Result&: Major))
562 return createStringError(
563 EC: errc::invalid_argument,
564 S: "Failed to parse major version number for extension '" + Ext + "'");
565
566 if (!MinorStr.empty() && MinorStr.getAsInteger(Radix: 10, Result&: Minor))
567 return createStringError(
568 EC: errc::invalid_argument,
569 S: "Failed to parse minor version number for extension '" + Ext + "'");
570
571 ConsumeLength = MajorStr.size();
572
573 if (!MinorStr.empty())
574 ConsumeLength += MinorStr.size() + 1 /*'p'*/;
575
576 // Expected multi-character extension with version number to have no
577 // subsequent characters (i.e. must either end string or be followed by
578 // an underscore).
579 if (Ext.size() > 1 && In.size())
580 return createStringError(
581 EC: errc::invalid_argument,
582 Msg: "multi-character extensions must be separated by underscores");
583
584 // If experimental extension, require use of current version number
585 if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
586 if (!EnableExperimentalExtension)
587 return createStringError(EC: errc::invalid_argument,
588 S: "requires '-menable-experimental-extensions' "
589 "for experimental extension '" +
590 Ext + "'");
591
592 if (ExperimentalExtensionVersionCheck &&
593 (MajorStr.empty() && MinorStr.empty()))
594 return createStringError(
595 EC: errc::invalid_argument,
596 S: "experimental extension requires explicit version number `" + Ext +
597 "`");
598
599 auto SupportedVers = *ExperimentalExtension;
600 if (ExperimentalExtensionVersionCheck &&
601 (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
602 std::string Error = "unsupported version number " + MajorStr.str();
603 if (!MinorStr.empty())
604 Error += "." + MinorStr.str();
605 Error += " for experimental extension '" + Ext.str() +
606 "' (this compiler supports " + utostr(X: SupportedVers.Major) +
607 "." + utostr(X: SupportedVers.Minor) + ")";
608 return createStringError(EC: errc::invalid_argument, S: Error);
609 }
610 return Error::success();
611 }
612
613 // Exception rule for `g`, we don't have clear version scheme for that on
614 // ISA spec.
615 if (Ext == "g")
616 return Error::success();
617
618 if (MajorStr.empty() && MinorStr.empty()) {
619 if (auto DefaultVersion = findDefaultVersion(ExtName: Ext)) {
620 Major = DefaultVersion->Major;
621 Minor = DefaultVersion->Minor;
622 }
623 // No matter found or not, return success, assume other place will
624 // verify.
625 return Error::success();
626 }
627
628 if (RISCVISAInfo::isSupportedExtension(Ext, MajorVersion: Major, MinorVersion: Minor))
629 return Error::success();
630
631 std::string Error = "unsupported version number " + std::string(MajorStr);
632 if (!MinorStr.empty())
633 Error += "." + MinorStr.str();
634 Error += " for extension '" + Ext.str() + "'";
635 return createStringError(EC: errc::invalid_argument, S: Error);
636}
637
638llvm::Expected<std::unique_ptr<RISCVISAInfo>>
639RISCVISAInfo::parseFeatures(unsigned XLen,
640 const std::vector<std::string> &Features) {
641 assert(XLen == 32 || XLen == 64);
642 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
643
644 for (auto &Feature : Features) {
645 StringRef ExtName = Feature;
646 bool Experimental = false;
647 assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
648 bool Add = ExtName[0] == '+';
649 ExtName = ExtName.drop_front(N: 1); // Drop '+' or '-'
650 Experimental = stripExperimentalPrefix(Ext&: ExtName);
651 auto ExtensionInfos = Experimental
652 ? ArrayRef(SupportedExperimentalExtensions)
653 : ArrayRef(SupportedExtensions);
654 auto ExtensionInfoIterator =
655 llvm::lower_bound(Range&: ExtensionInfos, Value&: ExtName, C: LessExtName());
656
657 // Not all features is related to ISA extension, like `relax` or
658 // `save-restore`, skip those feature.
659 if (ExtensionInfoIterator == ExtensionInfos.end() ||
660 ExtensionInfoIterator->Name != ExtName)
661 continue;
662
663 if (Add)
664 ISAInfo->addExtension(ExtName, Version: ExtensionInfoIterator->Version);
665 else
666 ISAInfo->Exts.erase(x: ExtName.str());
667 }
668
669 return RISCVISAInfo::postProcessAndChecking(ISAInfo: std::move(ISAInfo));
670}
671
672llvm::Expected<std::unique_ptr<RISCVISAInfo>>
673RISCVISAInfo::parseNormalizedArchString(StringRef Arch) {
674 if (llvm::any_of(Range&: Arch, P: isupper)) {
675 return createStringError(EC: errc::invalid_argument,
676 Msg: "string must be lowercase");
677 }
678 // Must start with a valid base ISA name.
679 unsigned XLen;
680 if (Arch.starts_with(Prefix: "rv32i") || Arch.starts_with(Prefix: "rv32e"))
681 XLen = 32;
682 else if (Arch.starts_with(Prefix: "rv64i") || Arch.starts_with(Prefix: "rv64e"))
683 XLen = 64;
684 else
685 return createStringError(EC: errc::invalid_argument,
686 Msg: "arch string must begin with valid base ISA");
687 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
688 // Discard rv32/rv64 prefix.
689 Arch = Arch.substr(Start: 4);
690
691 // Each extension is of the form ${name}${major_version}p${minor_version}
692 // and separated by _. Split by _ and then extract the name and version
693 // information for each extension.
694 SmallVector<StringRef, 8> Split;
695 Arch.split(A&: Split, Separator: '_');
696 for (StringRef Ext : Split) {
697 StringRef Prefix, MinorVersionStr;
698 std::tie(args&: Prefix, args&: MinorVersionStr) = Ext.rsplit(Separator: 'p');
699 if (MinorVersionStr.empty())
700 return createStringError(EC: errc::invalid_argument,
701 Msg: "extension lacks version in expected format");
702 unsigned MajorVersion, MinorVersion;
703 if (MinorVersionStr.getAsInteger(Radix: 10, Result&: MinorVersion))
704 return createStringError(EC: errc::invalid_argument,
705 Msg: "failed to parse minor version number");
706
707 // Split Prefix into the extension name and the major version number
708 // (the trailing digits of Prefix).
709 int TrailingDigits = 0;
710 StringRef ExtName = Prefix;
711 while (!ExtName.empty()) {
712 if (!isDigit(C: ExtName.back()))
713 break;
714 ExtName = ExtName.drop_back(N: 1);
715 TrailingDigits++;
716 }
717 if (!TrailingDigits)
718 return createStringError(EC: errc::invalid_argument,
719 Msg: "extension lacks version in expected format");
720
721 StringRef MajorVersionStr = Prefix.take_back(N: TrailingDigits);
722 if (MajorVersionStr.getAsInteger(Radix: 10, Result&: MajorVersion))
723 return createStringError(EC: errc::invalid_argument,
724 Msg: "failed to parse major version number");
725 ISAInfo->addExtension(ExtName, Version: {.Major: MajorVersion, .Minor: MinorVersion});
726 }
727 ISAInfo->updateFLen();
728 ISAInfo->updateMinVLen();
729 ISAInfo->updateMaxELen();
730 return std::move(ISAInfo);
731}
732
733static Error splitExtsByUnderscore(StringRef Exts,
734 std::vector<std::string> &SplitExts) {
735 SmallVector<StringRef, 8> Split;
736 if (Exts.empty())
737 return Error::success();
738
739 Exts.split(A&: Split, Separator: "_");
740
741 for (auto Ext : Split) {
742 if (Ext.empty())
743 return createStringError(EC: errc::invalid_argument,
744 Msg: "extension name missing after separator '_'");
745
746 SplitExts.push_back(x: Ext.str());
747 }
748 return Error::success();
749}
750
751static Error processMultiLetterExtension(
752 StringRef RawExt,
753 MapVector<std::string, RISCVISAInfo::ExtensionVersion,
754 std::map<std::string, unsigned>> &SeenExtMap,
755 bool IgnoreUnknown, bool EnableExperimentalExtension,
756 bool ExperimentalExtensionVersionCheck) {
757 StringRef Type = getExtensionType(Ext: RawExt);
758 StringRef Desc = getExtensionTypeDesc(Ext: RawExt);
759 auto Pos = findLastNonVersionCharacter(Ext: RawExt) + 1;
760 StringRef Name(RawExt.substr(Start: 0, N: Pos));
761 StringRef Vers(RawExt.substr(Start: Pos));
762
763 if (Type.empty()) {
764 if (IgnoreUnknown)
765 return Error::success();
766 return createStringError(EC: errc::invalid_argument,
767 S: "invalid extension prefix '" + RawExt + "'");
768 }
769
770 if (!IgnoreUnknown && Name.size() == Type.size())
771 return createStringError(EC: errc::invalid_argument,
772 S: Desc + " name missing after '" + Type + "'");
773
774 unsigned Major, Minor, ConsumeLength;
775 if (auto E = getExtensionVersion(Ext: Name, In: Vers, Major, Minor, ConsumeLength,
776 EnableExperimentalExtension,
777 ExperimentalExtensionVersionCheck)) {
778 if (IgnoreUnknown) {
779 consumeError(Err: std::move(E));
780 return Error::success();
781 }
782 return E;
783 }
784
785 // Check if duplicated extension.
786 if (!IgnoreUnknown && SeenExtMap.contains(Key: Name.str()))
787 return createStringError(EC: errc::invalid_argument,
788 S: "duplicated " + Desc + " '" + Name + "'");
789
790 if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Ext: Name))
791 return Error::success();
792
793 SeenExtMap[Name.str()] = {.Major: Major, .Minor: Minor};
794 return Error::success();
795}
796
797static Error processSingleLetterExtension(
798 StringRef &RawExt,
799 MapVector<std::string, RISCVISAInfo::ExtensionVersion,
800 std::map<std::string, unsigned>> &SeenExtMap,
801 bool IgnoreUnknown, bool EnableExperimentalExtension,
802 bool ExperimentalExtensionVersionCheck) {
803 unsigned Major, Minor, ConsumeLength;
804 StringRef Name = RawExt.take_front(N: 1);
805 RawExt.consume_front(Prefix: Name);
806 if (auto E = getExtensionVersion(Ext: Name, In: RawExt, Major, Minor, ConsumeLength,
807 EnableExperimentalExtension,
808 ExperimentalExtensionVersionCheck)) {
809 if (IgnoreUnknown) {
810 consumeError(Err: std::move(E));
811 RawExt = RawExt.substr(Start: ConsumeLength);
812 return Error::success();
813 }
814 return E;
815 }
816
817 RawExt = RawExt.substr(Start: ConsumeLength);
818
819 // Check if duplicated extension.
820 if (!IgnoreUnknown && SeenExtMap.contains(Key: Name.str()))
821 return createStringError(EC: errc::invalid_argument,
822 S: "duplicated standard user-level extension '" +
823 Name + "'");
824
825 if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Ext: Name))
826 return Error::success();
827
828 SeenExtMap[Name.str()] = {.Major: Major, .Minor: Minor};
829 return Error::success();
830}
831
832llvm::Expected<std::unique_ptr<RISCVISAInfo>>
833RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
834 bool ExperimentalExtensionVersionCheck,
835 bool IgnoreUnknown) {
836 // RISC-V ISA strings must be lowercase.
837 if (llvm::any_of(Range&: Arch, P: isupper)) {
838 return createStringError(EC: errc::invalid_argument,
839 Msg: "string must be lowercase");
840 }
841
842 bool HasRV64 = Arch.starts_with(Prefix: "rv64");
843 // ISA string must begin with rv32 or rv64.
844 if (!(Arch.starts_with(Prefix: "rv32") || HasRV64) || (Arch.size() < 5)) {
845 return createStringError(
846 EC: errc::invalid_argument,
847 Msg: "string must begin with rv32{i,e,g} or rv64{i,e,g}");
848 }
849
850 unsigned XLen = HasRV64 ? 64 : 32;
851 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
852 MapVector<std::string, RISCVISAInfo::ExtensionVersion,
853 std::map<std::string, unsigned>>
854 SeenExtMap;
855
856 // The canonical order specified in ISA manual.
857 // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
858 StringRef StdExts = AllStdExts;
859 char Baseline = Arch[4];
860
861 // First letter should be 'e', 'i' or 'g'.
862 switch (Baseline) {
863 default:
864 return createStringError(EC: errc::invalid_argument,
865 Msg: "first letter should be 'e', 'i' or 'g'");
866 case 'e':
867 case 'i':
868 break;
869 case 'g':
870 // g expands to extensions in RISCVGImplications.
871 if (Arch.size() > 5 && isDigit(C: Arch[5]))
872 return createStringError(EC: errc::invalid_argument,
873 Msg: "version not supported for 'g'");
874 StdExts = StdExts.drop_front(N: 4);
875 break;
876 }
877
878 if (Arch.back() == '_')
879 return createStringError(EC: errc::invalid_argument,
880 Msg: "extension name missing after separator '_'");
881
882 // Skip rvxxx
883 StringRef Exts = Arch.substr(Start: 5);
884
885 unsigned Major, Minor, ConsumeLength;
886 if (Baseline == 'g') {
887 // Versions for g are disallowed, and this was checked for previously.
888 ConsumeLength = 0;
889
890 // No matter which version is given to `g`, we always set imafd to default
891 // version since the we don't have clear version scheme for that on
892 // ISA spec.
893 for (const auto *Ext : RISCVGImplications) {
894 if (auto Version = findDefaultVersion(ExtName: Ext)) {
895 // Postpone AddExtension until end of this function
896 SeenExtMap[Ext] = {.Major: Version->Major, .Minor: Version->Minor};
897 } else
898 llvm_unreachable("Default extension version not found?");
899 }
900 } else {
901 // Baseline is `i` or `e`
902 if (auto E = getExtensionVersion(
903 Ext: StringRef(&Baseline, 1), In: Exts, Major, Minor, ConsumeLength,
904 EnableExperimentalExtension, ExperimentalExtensionVersionCheck)) {
905 if (!IgnoreUnknown)
906 return std::move(E);
907 // If IgnoreUnknown, then ignore an unrecognised version of the baseline
908 // ISA and just use the default supported version.
909 consumeError(Err: std::move(E));
910 auto Version = findDefaultVersion(ExtName: StringRef(&Baseline, 1));
911 Major = Version->Major;
912 Minor = Version->Minor;
913 }
914
915 // Postpone AddExtension until end of this function
916 SeenExtMap[StringRef(&Baseline, 1).str()] = {.Major: Major, .Minor: Minor};
917 }
918
919 // Consume the base ISA version number and any '_' between rvxxx and the
920 // first extension
921 Exts = Exts.drop_front(N: ConsumeLength);
922 Exts.consume_front(Prefix: "_");
923
924 std::vector<std::string> SplittedExts;
925 if (auto E = splitExtsByUnderscore(Exts, SplitExts&: SplittedExts))
926 return std::move(E);
927
928 for (auto &Ext : SplittedExts) {
929 StringRef CurrExt = Ext;
930 while (!CurrExt.empty()) {
931 if (AllStdExts.contains(C: CurrExt.front())) {
932 if (auto E = processSingleLetterExtension(
933 RawExt&: CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension,
934 ExperimentalExtensionVersionCheck))
935 return std::move(E);
936 } else if (CurrExt.front() == 'z' || CurrExt.front() == 's' ||
937 CurrExt.front() == 'x') {
938 // Handle other types of extensions other than the standard
939 // general purpose and standard user-level extensions.
940 // Parse the ISA string containing non-standard user-level
941 // extensions, standard supervisor-level extensions and
942 // non-standard supervisor-level extensions.
943 // These extensions start with 'z', 's', 'x' prefixes, might have a
944 // version number (major, minor) and are separated by a single
945 // underscore '_'. We do not enforce a canonical order for them.
946 if (auto E = processMultiLetterExtension(
947 RawExt: CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension,
948 ExperimentalExtensionVersionCheck))
949 return std::move(E);
950 // Multi-letter extension must be seperate following extension with
951 // underscore
952 break;
953 } else {
954 // FIXME: Could it be ignored by IgnoreUnknown?
955 return createStringError(EC: errc::invalid_argument,
956 S: "invalid standard user-level extension '" +
957 Twine(CurrExt.front()) + "'");
958 }
959 }
960 }
961
962 // Check all Extensions are supported.
963 for (auto &SeenExtAndVers : SeenExtMap) {
964 const std::string &ExtName = SeenExtAndVers.first;
965 RISCVISAInfo::ExtensionVersion ExtVers = SeenExtAndVers.second;
966
967 if (!RISCVISAInfo::isSupportedExtension(Ext: ExtName)) {
968 if (ExtName.size() == 1) {
969 return createStringError(EC: errc::invalid_argument,
970 S: "unsupported standard user-level extension '" +
971 ExtName + "'");
972 }
973 return createStringError(EC: errc::invalid_argument,
974 S: "unsupported " + getExtensionTypeDesc(Ext: ExtName) +
975 " '" + ExtName + "'");
976 }
977 ISAInfo->addExtension(ExtName, Version: ExtVers);
978 }
979
980 return RISCVISAInfo::postProcessAndChecking(ISAInfo: std::move(ISAInfo));
981}
982
983Error RISCVISAInfo::checkDependency() {
984 bool HasC = Exts.count(x: "c") != 0;
985 bool HasF = Exts.count(x: "f") != 0;
986 bool HasZfinx = Exts.count(x: "zfinx") != 0;
987 bool HasVector = Exts.count(x: "zve32x") != 0;
988 bool HasZvl = MinVLen != 0;
989 bool HasZcmt = Exts.count(x: "zcmt") != 0;
990
991 if (HasF && HasZfinx)
992 return createStringError(EC: errc::invalid_argument,
993 Msg: "'f' and 'zfinx' extensions are incompatible");
994
995 if (HasZvl && !HasVector)
996 return createStringError(
997 EC: errc::invalid_argument,
998 Msg: "'zvl*b' requires 'v' or 'zve*' extension to also be specified");
999
1000 if (Exts.count(x: "zvbb") && !HasVector)
1001 return createStringError(
1002 EC: errc::invalid_argument,
1003 Msg: "'zvbb' requires 'v' or 'zve*' extension to also be specified");
1004
1005 if (Exts.count(x: "zvbc") && !Exts.count(x: "zve64x"))
1006 return createStringError(
1007 EC: errc::invalid_argument,
1008 Msg: "'zvbc' requires 'v' or 'zve64*' extension to also be specified");
1009
1010 if ((Exts.count(x: "zvkb") || Exts.count(x: "zvkg") || Exts.count(x: "zvkned") ||
1011 Exts.count(x: "zvknha") || Exts.count(x: "zvksed") || Exts.count(x: "zvksh")) &&
1012 !HasVector)
1013 return createStringError(
1014 EC: errc::invalid_argument,
1015 Msg: "'zvk*' requires 'v' or 'zve*' extension to also be specified");
1016
1017 if (Exts.count(x: "zvknhb") && !Exts.count(x: "zve64x"))
1018 return createStringError(
1019 EC: errc::invalid_argument,
1020 Msg: "'zvknhb' requires 'v' or 'zve64*' extension to also be specified");
1021
1022 if ((HasZcmt || Exts.count(x: "zcmp")) && Exts.count(x: "d") &&
1023 (HasC || Exts.count(x: "zcd")))
1024 return createStringError(
1025 EC: errc::invalid_argument,
1026 S: Twine("'") + (HasZcmt ? "zcmt" : "zcmp") +
1027 "' extension is incompatible with '" + (HasC ? "c" : "zcd") +
1028 "' extension when 'd' extension is enabled");
1029
1030 if (XLen != 32 && Exts.count(x: "zcf"))
1031 return createStringError(EC: errc::invalid_argument,
1032 Msg: "'zcf' is only supported for 'rv32'");
1033
1034 return Error::success();
1035}
1036
1037static const char *ImpliedExtsD[] = {"f"};
1038static const char *ImpliedExtsF[] = {"zicsr"};
1039static const char *ImpliedExtsV[] = {"zvl128b", "zve64d"};
1040static const char *ImpliedExtsXTHeadVdot[] = {"v"};
1041static const char *ImpliedExtsXSfvcp[] = {"zve32x"};
1042static const char *ImpliedExtsXSfvfnrclipxfqf[] = {"zve32f"};
1043static const char *ImpliedExtsXSfvfwmaccqqq[] = {"zvfbfmin"};
1044static const char *ImpliedExtsXSfvqmaccdod[] = {"zve32x"};
1045static const char *ImpliedExtsXSfvqmaccqoq[] = {"zve32x"};
1046static const char *ImpliedExtsZabha[] = {"a"};
1047static const char *ImpliedExtsZacas[] = {"a"};
1048static const char *ImpliedExtsZcb[] = {"zca"};
1049static const char *ImpliedExtsZcd[] = {"d", "zca"};
1050static const char *ImpliedExtsZce[] = {"zcb", "zcmp", "zcmt"};
1051static const char *ImpliedExtsZcf[] = {"f", "zca"};
1052static const char *ImpliedExtsZcmop[] = {"zca"};
1053static const char *ImpliedExtsZcmp[] = {"zca"};
1054static const char *ImpliedExtsZcmt[] = {"zca", "zicsr"};
1055static const char *ImpliedExtsZdinx[] = {"zfinx"};
1056static const char *ImpliedExtsZfa[] = {"f"};
1057static const char *ImpliedExtsZfbfmin[] = {"f"};
1058static const char *ImpliedExtsZfh[] = {"zfhmin"};
1059static const char *ImpliedExtsZfhmin[] = {"f"};
1060static const char *ImpliedExtsZfinx[] = {"zicsr"};
1061static const char *ImpliedExtsZhinx[] = {"zhinxmin"};
1062static const char *ImpliedExtsZhinxmin[] = {"zfinx"};
1063static const char *ImpliedExtsZicntr[] = {"zicsr"};
1064static const char *ImpliedExtsZicfiss[] = {"zicsr", "zimop"};
1065static const char *ImpliedExtsZihpm[] = {"zicsr"};
1066static const char *ImpliedExtsZk[] = {"zkn", "zkt", "zkr"};
1067static const char *ImpliedExtsZkn[] = {"zbkb", "zbkc", "zbkx",
1068 "zkne", "zknd", "zknh"};
1069static const char *ImpliedExtsZks[] = {"zbkb", "zbkc", "zbkx", "zksed", "zksh"};
1070static const char *ImpliedExtsZvbb[] = {"zvkb"};
1071static const char *ImpliedExtsZve32f[] = {"zve32x", "f"};
1072static const char *ImpliedExtsZve32x[] = {"zvl32b", "zicsr"};
1073static const char *ImpliedExtsZve64d[] = {"zve64f", "d"};
1074static const char *ImpliedExtsZve64f[] = {"zve64x", "zve32f"};
1075static const char *ImpliedExtsZve64x[] = {"zve32x", "zvl64b"};
1076static const char *ImpliedExtsZvfbfmin[] = {"zve32f"};
1077static const char *ImpliedExtsZvfbfwma[] = {"zvfbfmin", "zfbfmin"};
1078static const char *ImpliedExtsZvfh[] = {"zvfhmin", "zfhmin"};
1079static const char *ImpliedExtsZvfhmin[] = {"zve32f"};
1080static const char *ImpliedExtsZvkn[] = {"zvkb", "zvkned", "zvknhb", "zvkt"};
1081static const char *ImpliedExtsZvknc[] = {"zvbc", "zvkn"};
1082static const char *ImpliedExtsZvkng[] = {"zvkg", "zvkn"};
1083static const char *ImpliedExtsZvknhb[] = {"zve64x"};
1084static const char *ImpliedExtsZvks[] = {"zvkb", "zvksed", "zvksh", "zvkt"};
1085static const char *ImpliedExtsZvksc[] = {"zvbc", "zvks"};
1086static const char *ImpliedExtsZvksg[] = {"zvkg", "zvks"};
1087static const char *ImpliedExtsZvl1024b[] = {"zvl512b"};
1088static const char *ImpliedExtsZvl128b[] = {"zvl64b"};
1089static const char *ImpliedExtsZvl16384b[] = {"zvl8192b"};
1090static const char *ImpliedExtsZvl2048b[] = {"zvl1024b"};
1091static const char *ImpliedExtsZvl256b[] = {"zvl128b"};
1092static const char *ImpliedExtsZvl32768b[] = {"zvl16384b"};
1093static const char *ImpliedExtsZvl4096b[] = {"zvl2048b"};
1094static const char *ImpliedExtsZvl512b[] = {"zvl256b"};
1095static const char *ImpliedExtsZvl64b[] = {"zvl32b"};
1096static const char *ImpliedExtsZvl65536b[] = {"zvl32768b"};
1097static const char *ImpliedExtsZvl8192b[] = {"zvl4096b"};
1098
1099struct ImpliedExtsEntry {
1100 StringLiteral Name;
1101 ArrayRef<const char *> Exts;
1102
1103 bool operator<(const ImpliedExtsEntry &Other) const {
1104 return Name < Other.Name;
1105 }
1106
1107 bool operator<(StringRef Other) const { return Name < Other; }
1108};
1109
1110// Note: The table needs to be sorted by name.
1111static constexpr ImpliedExtsEntry ImpliedExts[] = {
1112 {.Name: {"d"}, .Exts: {ImpliedExtsD}},
1113 {.Name: {"f"}, .Exts: {ImpliedExtsF}},
1114 {.Name: {"v"}, .Exts: {ImpliedExtsV}},
1115 {.Name: {"xsfvcp"}, .Exts: {ImpliedExtsXSfvcp}},
1116 {.Name: {"xsfvfnrclipxfqf"}, .Exts: {ImpliedExtsXSfvfnrclipxfqf}},
1117 {.Name: {"xsfvfwmaccqqq"}, .Exts: {ImpliedExtsXSfvfwmaccqqq}},
1118 {.Name: {"xsfvqmaccdod"}, .Exts: {ImpliedExtsXSfvqmaccdod}},
1119 {.Name: {"xsfvqmaccqoq"}, .Exts: {ImpliedExtsXSfvqmaccqoq}},
1120 {.Name: {"xtheadvdot"}, .Exts: {ImpliedExtsXTHeadVdot}},
1121 {.Name: {"zabha"}, .Exts: {ImpliedExtsZabha}},
1122 {.Name: {"zacas"}, .Exts: {ImpliedExtsZacas}},
1123 {.Name: {"zcb"}, .Exts: {ImpliedExtsZcb}},
1124 {.Name: {"zcd"}, .Exts: {ImpliedExtsZcd}},
1125 {.Name: {"zce"}, .Exts: {ImpliedExtsZce}},
1126 {.Name: {"zcf"}, .Exts: {ImpliedExtsZcf}},
1127 {.Name: {"zcmop"}, .Exts: {ImpliedExtsZcmop}},
1128 {.Name: {"zcmp"}, .Exts: {ImpliedExtsZcmp}},
1129 {.Name: {"zcmt"}, .Exts: {ImpliedExtsZcmt}},
1130 {.Name: {"zdinx"}, .Exts: {ImpliedExtsZdinx}},
1131 {.Name: {"zfa"}, .Exts: {ImpliedExtsZfa}},
1132 {.Name: {"zfbfmin"}, .Exts: {ImpliedExtsZfbfmin}},
1133 {.Name: {"zfh"}, .Exts: {ImpliedExtsZfh}},
1134 {.Name: {"zfhmin"}, .Exts: {ImpliedExtsZfhmin}},
1135 {.Name: {"zfinx"}, .Exts: {ImpliedExtsZfinx}},
1136 {.Name: {"zhinx"}, .Exts: {ImpliedExtsZhinx}},
1137 {.Name: {"zhinxmin"}, .Exts: {ImpliedExtsZhinxmin}},
1138 {.Name: {"zicfiss"}, .Exts: {ImpliedExtsZicfiss}},
1139 {.Name: {"zicntr"}, .Exts: {ImpliedExtsZicntr}},
1140 {.Name: {"zihpm"}, .Exts: {ImpliedExtsZihpm}},
1141 {.Name: {"zk"}, .Exts: {ImpliedExtsZk}},
1142 {.Name: {"zkn"}, .Exts: {ImpliedExtsZkn}},
1143 {.Name: {"zks"}, .Exts: {ImpliedExtsZks}},
1144 {.Name: {"zvbb"}, .Exts: {ImpliedExtsZvbb}},
1145 {.Name: {"zve32f"}, .Exts: {ImpliedExtsZve32f}},
1146 {.Name: {"zve32x"}, .Exts: {ImpliedExtsZve32x}},
1147 {.Name: {"zve64d"}, .Exts: {ImpliedExtsZve64d}},
1148 {.Name: {"zve64f"}, .Exts: {ImpliedExtsZve64f}},
1149 {.Name: {"zve64x"}, .Exts: {ImpliedExtsZve64x}},
1150 {.Name: {"zvfbfmin"}, .Exts: {ImpliedExtsZvfbfmin}},
1151 {.Name: {"zvfbfwma"}, .Exts: {ImpliedExtsZvfbfwma}},
1152 {.Name: {"zvfh"}, .Exts: {ImpliedExtsZvfh}},
1153 {.Name: {"zvfhmin"}, .Exts: {ImpliedExtsZvfhmin}},
1154 {.Name: {"zvkn"}, .Exts: {ImpliedExtsZvkn}},
1155 {.Name: {"zvknc"}, .Exts: {ImpliedExtsZvknc}},
1156 {.Name: {"zvkng"}, .Exts: {ImpliedExtsZvkng}},
1157 {.Name: {"zvknhb"}, .Exts: {ImpliedExtsZvknhb}},
1158 {.Name: {"zvks"}, .Exts: {ImpliedExtsZvks}},
1159 {.Name: {"zvksc"}, .Exts: {ImpliedExtsZvksc}},
1160 {.Name: {"zvksg"}, .Exts: {ImpliedExtsZvksg}},
1161 {.Name: {"zvl1024b"}, .Exts: {ImpliedExtsZvl1024b}},
1162 {.Name: {"zvl128b"}, .Exts: {ImpliedExtsZvl128b}},
1163 {.Name: {"zvl16384b"}, .Exts: {ImpliedExtsZvl16384b}},
1164 {.Name: {"zvl2048b"}, .Exts: {ImpliedExtsZvl2048b}},
1165 {.Name: {"zvl256b"}, .Exts: {ImpliedExtsZvl256b}},
1166 {.Name: {"zvl32768b"}, .Exts: {ImpliedExtsZvl32768b}},
1167 {.Name: {"zvl4096b"}, .Exts: {ImpliedExtsZvl4096b}},
1168 {.Name: {"zvl512b"}, .Exts: {ImpliedExtsZvl512b}},
1169 {.Name: {"zvl64b"}, .Exts: {ImpliedExtsZvl64b}},
1170 {.Name: {"zvl65536b"}, .Exts: {ImpliedExtsZvl65536b}},
1171 {.Name: {"zvl8192b"}, .Exts: {ImpliedExtsZvl8192b}},
1172};
1173
1174void RISCVISAInfo::updateImplication() {
1175 bool HasE = Exts.count(x: "e") != 0;
1176 bool HasI = Exts.count(x: "i") != 0;
1177
1178 // If not in e extension and i extension does not exist, i extension is
1179 // implied
1180 if (!HasE && !HasI) {
1181 auto Version = findDefaultVersion(ExtName: "i");
1182 addExtension(ExtName: "i", Version: Version.value());
1183 }
1184
1185 assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
1186
1187 // This loop may execute over 1 iteration since implication can be layered
1188 // Exits loop if no more implication is applied
1189 SmallSetVector<StringRef, 16> WorkList;
1190 for (auto const &Ext : Exts)
1191 WorkList.insert(X: Ext.first);
1192
1193 while (!WorkList.empty()) {
1194 StringRef ExtName = WorkList.pop_back_val();
1195 auto I = llvm::lower_bound(Range: ImpliedExts, Value&: ExtName);
1196 if (I != std::end(arr: ImpliedExts) && I->Name == ExtName) {
1197 for (const char *ImpliedExt : I->Exts) {
1198 if (WorkList.count(key: ImpliedExt))
1199 continue;
1200 if (Exts.count(x: ImpliedExt))
1201 continue;
1202 auto Version = findDefaultVersion(ExtName: ImpliedExt);
1203 addExtension(ExtName: ImpliedExt, Version: Version.value());
1204 WorkList.insert(X: ImpliedExt);
1205 }
1206 }
1207 }
1208
1209 // Add Zcf if Zce and F are enabled on RV32.
1210 if (XLen == 32 && Exts.count(x: "zce") && Exts.count(x: "f") &&
1211 !Exts.count(x: "zcf")) {
1212 auto Version = findDefaultVersion(ExtName: "zcf");
1213 addExtension(ExtName: "zcf", Version: Version.value());
1214 }
1215}
1216
1217struct CombinedExtsEntry {
1218 StringLiteral CombineExt;
1219 ArrayRef<const char *> RequiredExts;
1220};
1221
1222static constexpr CombinedExtsEntry CombineIntoExts[] = {
1223 {.CombineExt: {"zk"}, .RequiredExts: {ImpliedExtsZk}},
1224 {.CombineExt: {"zkn"}, .RequiredExts: {ImpliedExtsZkn}},
1225 {.CombineExt: {"zks"}, .RequiredExts: {ImpliedExtsZks}},
1226 {.CombineExt: {"zvkn"}, .RequiredExts: {ImpliedExtsZvkn}},
1227 {.CombineExt: {"zvknc"}, .RequiredExts: {ImpliedExtsZvknc}},
1228 {.CombineExt: {"zvkng"}, .RequiredExts: {ImpliedExtsZvkng}},
1229 {.CombineExt: {"zvks"}, .RequiredExts: {ImpliedExtsZvks}},
1230 {.CombineExt: {"zvksc"}, .RequiredExts: {ImpliedExtsZvksc}},
1231 {.CombineExt: {"zvksg"}, .RequiredExts: {ImpliedExtsZvksg}},
1232};
1233
1234void RISCVISAInfo::updateCombination() {
1235 bool IsNewCombine = false;
1236 do {
1237 IsNewCombine = false;
1238 for (CombinedExtsEntry CombineIntoExt : CombineIntoExts) {
1239 auto CombineExt = CombineIntoExt.CombineExt;
1240 auto RequiredExts = CombineIntoExt.RequiredExts;
1241 if (hasExtension(Ext: CombineExt))
1242 continue;
1243 bool IsAllRequiredFeatureExist = true;
1244 for (const char *Ext : RequiredExts)
1245 IsAllRequiredFeatureExist &= hasExtension(Ext);
1246 if (IsAllRequiredFeatureExist) {
1247 auto Version = findDefaultVersion(ExtName: CombineExt);
1248 addExtension(ExtName: CombineExt, Version: Version.value());
1249 IsNewCombine = true;
1250 }
1251 }
1252 } while (IsNewCombine);
1253}
1254
1255void RISCVISAInfo::updateFLen() {
1256 FLen = 0;
1257 // TODO: Handle q extension.
1258 if (Exts.count(x: "d"))
1259 FLen = 64;
1260 else if (Exts.count(x: "f"))
1261 FLen = 32;
1262}
1263
1264void RISCVISAInfo::updateMinVLen() {
1265 for (auto const &Ext : Exts) {
1266 StringRef ExtName = Ext.first;
1267 bool IsZvlExt = ExtName.consume_front(Prefix: "zvl") && ExtName.consume_back(Suffix: "b");
1268 if (IsZvlExt) {
1269 unsigned ZvlLen;
1270 if (!ExtName.getAsInteger(Radix: 10, Result&: ZvlLen))
1271 MinVLen = std::max(a: MinVLen, b: ZvlLen);
1272 }
1273 }
1274}
1275
1276void RISCVISAInfo::updateMaxELen() {
1277 // handles EEW restriction by sub-extension zve
1278 for (auto const &Ext : Exts) {
1279 StringRef ExtName = Ext.first;
1280 bool IsZveExt = ExtName.consume_front(Prefix: "zve");
1281 if (IsZveExt) {
1282 if (ExtName.back() == 'f')
1283 MaxELenFp = std::max(a: MaxELenFp, b: 32u);
1284 if (ExtName.back() == 'd')
1285 MaxELenFp = std::max(a: MaxELenFp, b: 64u);
1286 ExtName = ExtName.drop_back();
1287 unsigned ZveELen;
1288 ExtName.getAsInteger(Radix: 10, Result&: ZveELen);
1289 MaxELen = std::max(a: MaxELen, b: ZveELen);
1290 }
1291 }
1292}
1293
1294std::string RISCVISAInfo::toString() const {
1295 std::string Buffer;
1296 raw_string_ostream Arch(Buffer);
1297
1298 Arch << "rv" << XLen;
1299
1300 ListSeparator LS("_");
1301 for (auto const &Ext : Exts) {
1302 StringRef ExtName = Ext.first;
1303 auto ExtInfo = Ext.second;
1304 Arch << LS << ExtName;
1305 Arch << ExtInfo.Major << "p" << ExtInfo.Minor;
1306 }
1307
1308 return Arch.str();
1309}
1310
1311llvm::Expected<std::unique_ptr<RISCVISAInfo>>
1312RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
1313 ISAInfo->updateImplication();
1314 ISAInfo->updateCombination();
1315 ISAInfo->updateFLen();
1316 ISAInfo->updateMinVLen();
1317 ISAInfo->updateMaxELen();
1318
1319 if (Error Result = ISAInfo->checkDependency())
1320 return std::move(Result);
1321 return std::move(ISAInfo);
1322}
1323
1324StringRef RISCVISAInfo::computeDefaultABI() const {
1325 if (XLen == 32) {
1326 if (hasExtension(Ext: "e"))
1327 return "ilp32e";
1328 if (hasExtension(Ext: "d"))
1329 return "ilp32d";
1330 if (hasExtension(Ext: "f"))
1331 return "ilp32f";
1332 return "ilp32";
1333 } else if (XLen == 64) {
1334 if (hasExtension(Ext: "e"))
1335 return "lp64e";
1336 if (hasExtension(Ext: "d"))
1337 return "lp64d";
1338 if (hasExtension(Ext: "f"))
1339 return "lp64f";
1340 return "lp64";
1341 }
1342 llvm_unreachable("Invalid XLEN");
1343}
1344
1345bool RISCVISAInfo::isSupportedExtensionWithVersion(StringRef Ext) {
1346 if (Ext.empty())
1347 return false;
1348
1349 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1350 StringRef Name = Ext.substr(Start: 0, N: Pos);
1351 StringRef Vers = Ext.substr(Start: Pos);
1352 if (Vers.empty())
1353 return false;
1354
1355 unsigned Major, Minor, ConsumeLength;
1356 if (auto E = getExtensionVersion(Ext: Name, In: Vers, Major, Minor, ConsumeLength,
1357 EnableExperimentalExtension: true, ExperimentalExtensionVersionCheck: true)) {
1358 consumeError(Err: std::move(E));
1359 return false;
1360 }
1361
1362 return true;
1363}
1364
1365std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) {
1366 if (Ext.empty())
1367 return std::string();
1368
1369 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1370 StringRef Name = Ext.substr(Start: 0, N: Pos);
1371
1372 if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext))
1373 return std::string();
1374
1375 if (!isSupportedExtension(Ext: Name))
1376 return std::string();
1377
1378 return isExperimentalExtension(Ext: Name) ? "experimental-" + Name.str()
1379 : Name.str();
1380}
1381

source code of llvm/lib/Support/RISCVISAInfo.cpp