1 //===-- RISCVISAInfo.cpp - RISCV 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/STLExtras.h"
11 #include "llvm/ADT/SetVector.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/Support/Errc.h"
15 #include "llvm/Support/Error.h"
16 #include "llvm/Support/raw_ostream.h"
17
18 #include <array>
19 #include <optional>
20 #include <string>
21 #include <vector>
22
23 using namespace llvm;
24
25 namespace {
26 /// Represents the major and version number components of a RISC-V extension
27 struct RISCVExtensionVersion {
28 unsigned Major;
29 unsigned Minor;
30 };
31
32 struct RISCVSupportedExtension {
33 const char *Name;
34 /// Supported version.
35 RISCVExtensionVersion Version;
36 };
37
38 } // end anonymous namespace
39
40 static constexpr StringLiteral AllStdExts = "mafdqlcbkjtpvnh";
41
42 static const RISCVSupportedExtension SupportedExtensions[] = {
43 {"i", RISCVExtensionVersion{2, 0}},
44 {"e", RISCVExtensionVersion{1, 9}},
45 {"m", RISCVExtensionVersion{2, 0}},
46 {"a", RISCVExtensionVersion{2, 0}},
47 {"f", RISCVExtensionVersion{2, 0}},
48 {"d", RISCVExtensionVersion{2, 0}},
49 {"c", RISCVExtensionVersion{2, 0}},
50
51 {"h", RISCVExtensionVersion{1, 0}},
52
53 {"zihintpause", RISCVExtensionVersion{2, 0}},
54
55 {"zfhmin", RISCVExtensionVersion{1, 0}},
56 {"zfh", RISCVExtensionVersion{1, 0}},
57
58 {"zfinx", RISCVExtensionVersion{1, 0}},
59 {"zdinx", RISCVExtensionVersion{1, 0}},
60 {"zhinxmin", RISCVExtensionVersion{1, 0}},
61 {"zhinx", RISCVExtensionVersion{1, 0}},
62
63 {"zba", RISCVExtensionVersion{1, 0}},
64 {"zbb", RISCVExtensionVersion{1, 0}},
65 {"zbc", RISCVExtensionVersion{1, 0}},
66 {"zbs", RISCVExtensionVersion{1, 0}},
67
68 {"zbkb", RISCVExtensionVersion{1, 0}},
69 {"zbkc", RISCVExtensionVersion{1, 0}},
70 {"zbkx", RISCVExtensionVersion{1, 0}},
71 {"zknd", RISCVExtensionVersion{1, 0}},
72 {"zkne", RISCVExtensionVersion{1, 0}},
73 {"zknh", RISCVExtensionVersion{1, 0}},
74 {"zksed", RISCVExtensionVersion{1, 0}},
75 {"zksh", RISCVExtensionVersion{1, 0}},
76 {"zkr", RISCVExtensionVersion{1, 0}},
77 {"zkn", RISCVExtensionVersion{1, 0}},
78 {"zks", RISCVExtensionVersion{1, 0}},
79 {"zkt", RISCVExtensionVersion{1, 0}},
80 {"zk", RISCVExtensionVersion{1, 0}},
81
82 {"zmmul", RISCVExtensionVersion{1, 0}},
83
84 {"v", RISCVExtensionVersion{1, 0}},
85 {"zvl32b", RISCVExtensionVersion{1, 0}},
86 {"zvl64b", RISCVExtensionVersion{1, 0}},
87 {"zvl128b", RISCVExtensionVersion{1, 0}},
88 {"zvl256b", RISCVExtensionVersion{1, 0}},
89 {"zvl512b", RISCVExtensionVersion{1, 0}},
90 {"zvl1024b", RISCVExtensionVersion{1, 0}},
91 {"zvl2048b", RISCVExtensionVersion{1, 0}},
92 {"zvl4096b", RISCVExtensionVersion{1, 0}},
93 {"zvl8192b", RISCVExtensionVersion{1, 0}},
94 {"zvl16384b", RISCVExtensionVersion{1, 0}},
95 {"zvl32768b", RISCVExtensionVersion{1, 0}},
96 {"zvl65536b", RISCVExtensionVersion{1, 0}},
97 {"zve32x", RISCVExtensionVersion{1, 0}},
98 {"zve32f", RISCVExtensionVersion{1, 0}},
99 {"zve64x", RISCVExtensionVersion{1, 0}},
100 {"zve64f", RISCVExtensionVersion{1, 0}},
101 {"zve64d", RISCVExtensionVersion{1, 0}},
102
103 {"zicbom", RISCVExtensionVersion{1, 0}},
104 {"zicboz", RISCVExtensionVersion{1, 0}},
105 {"zicbop", RISCVExtensionVersion{1, 0}},
106
107 {"svnapot", RISCVExtensionVersion{1, 0}},
108 {"svpbmt", RISCVExtensionVersion{1, 0}},
109 {"svinval", RISCVExtensionVersion{1, 0}},
110 {"xventanacondops", RISCVExtensionVersion{1, 0}},
111 {"xtheadvdot", RISCVExtensionVersion{1, 0}},
112 };
113
114 static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
115 {"zihintntl", RISCVExtensionVersion{0, 2}},
116
117 {"zca", RISCVExtensionVersion{0, 70}},
118 {"zcd", RISCVExtensionVersion{0, 70}},
119 {"zcf", RISCVExtensionVersion{0, 70}},
120 {"zvfh", RISCVExtensionVersion{0, 1}},
121 {"zawrs", RISCVExtensionVersion{1, 0}},
122 {"ztso", RISCVExtensionVersion{0, 1}},
123 };
124
stripExperimentalPrefix(StringRef & Ext)125 static bool stripExperimentalPrefix(StringRef &Ext) {
126 return Ext.consume_front("experimental-");
127 }
128
129 // This function finds the first character that doesn't belong to a version
130 // (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will
131 // consume [0-9]*p[0-9]* starting from the backward. An extension name will not
132 // end with a digit or the letter 'p', so this function will parse correctly.
133 // NOTE: This function is NOT able to take empty strings or strings that only
134 // have version numbers and no extension name. It assumes the extension name
135 // will be at least more than one character.
findFirstNonVersionCharacter(StringRef Ext)136 static size_t findFirstNonVersionCharacter(StringRef Ext) {
137 assert(!Ext.empty() &&
138 "Already guarded by if-statement in ::parseArchString");
139
140 int Pos = Ext.size() - 1;
141 while (Pos > 0 && isDigit(Ext[Pos]))
142 Pos--;
143 if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {
144 Pos--;
145 while (Pos > 0 && isDigit(Ext[Pos]))
146 Pos--;
147 }
148 return Pos;
149 }
150
151 namespace {
152 struct FindByName {
FindByName__anon2338e1790211::FindByName153 FindByName(StringRef Ext) : Ext(Ext){};
154 StringRef Ext;
operator ()__anon2338e1790211::FindByName155 bool operator()(const RISCVSupportedExtension &ExtInfo) {
156 return ExtInfo.Name == Ext;
157 }
158 };
159 } // namespace
160
161 static std::optional<RISCVExtensionVersion>
findDefaultVersion(StringRef ExtName)162 findDefaultVersion(StringRef ExtName) {
163 // Find default version of an extension.
164 // TODO: We might set default version based on profile or ISA spec.
165 for (auto &ExtInfo : {ArrayRef(SupportedExtensions),
166 ArrayRef(SupportedExperimentalExtensions)}) {
167 auto ExtensionInfoIterator = llvm::find_if(ExtInfo, FindByName(ExtName));
168
169 if (ExtensionInfoIterator == ExtInfo.end()) {
170 continue;
171 }
172 return ExtensionInfoIterator->Version;
173 }
174 return std::nullopt;
175 }
176
addExtension(StringRef ExtName,unsigned MajorVersion,unsigned MinorVersion)177 void RISCVISAInfo::addExtension(StringRef ExtName, unsigned MajorVersion,
178 unsigned MinorVersion) {
179 RISCVExtensionInfo Ext;
180 Ext.ExtName = ExtName.str();
181 Ext.MajorVersion = MajorVersion;
182 Ext.MinorVersion = MinorVersion;
183 Exts[ExtName.str()] = Ext;
184 }
185
getExtensionTypeDesc(StringRef Ext)186 static StringRef getExtensionTypeDesc(StringRef Ext) {
187 if (Ext.startswith("sx"))
188 return "non-standard supervisor-level extension";
189 if (Ext.startswith("s"))
190 return "standard supervisor-level extension";
191 if (Ext.startswith("x"))
192 return "non-standard user-level extension";
193 if (Ext.startswith("z"))
194 return "standard user-level extension";
195 return StringRef();
196 }
197
getExtensionType(StringRef Ext)198 static StringRef getExtensionType(StringRef Ext) {
199 if (Ext.startswith("sx"))
200 return "sx";
201 if (Ext.startswith("s"))
202 return "s";
203 if (Ext.startswith("x"))
204 return "x";
205 if (Ext.startswith("z"))
206 return "z";
207 return StringRef();
208 }
209
210 static std::optional<RISCVExtensionVersion>
isExperimentalExtension(StringRef Ext)211 isExperimentalExtension(StringRef Ext) {
212 auto ExtIterator =
213 llvm::find_if(SupportedExperimentalExtensions, FindByName(Ext));
214 if (ExtIterator == std::end(SupportedExperimentalExtensions))
215 return std::nullopt;
216
217 return ExtIterator->Version;
218 }
219
isSupportedExtensionFeature(StringRef Ext)220 bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) {
221 bool IsExperimental = stripExperimentalPrefix(Ext);
222
223 if (IsExperimental)
224 return llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
225 else
226 return llvm::any_of(SupportedExtensions, FindByName(Ext));
227 }
228
isSupportedExtension(StringRef Ext)229 bool RISCVISAInfo::isSupportedExtension(StringRef Ext) {
230 return llvm::any_of(SupportedExtensions, FindByName(Ext)) ||
231 llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
232 }
233
isSupportedExtension(StringRef Ext,unsigned MajorVersion,unsigned MinorVersion)234 bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
235 unsigned MinorVersion) {
236 auto FindByNameAndVersion = [=](const RISCVSupportedExtension &ExtInfo) {
237 return ExtInfo.Name == Ext && (MajorVersion == ExtInfo.Version.Major) &&
238 (MinorVersion == ExtInfo.Version.Minor);
239 };
240 return llvm::any_of(SupportedExtensions, FindByNameAndVersion) ||
241 llvm::any_of(SupportedExperimentalExtensions, FindByNameAndVersion);
242 }
243
hasExtension(StringRef Ext) const244 bool RISCVISAInfo::hasExtension(StringRef Ext) const {
245 stripExperimentalPrefix(Ext);
246
247 if (!isSupportedExtension(Ext))
248 return false;
249
250 return Exts.count(Ext.str()) != 0;
251 }
252
253 // Get the rank for single-letter extension, lower value meaning higher
254 // priority.
singleLetterExtensionRank(char Ext)255 static int singleLetterExtensionRank(char Ext) {
256 switch (Ext) {
257 case 'i':
258 return -2;
259 case 'e':
260 return -1;
261 default:
262 break;
263 }
264
265 size_t Pos = AllStdExts.find(Ext);
266 int Rank;
267 if (Pos == StringRef::npos)
268 // If we got an unknown extension letter, then give it an alphabetical
269 // order, but after all known standard extensions.
270 Rank = AllStdExts.size() + (Ext - 'a');
271 else
272 Rank = Pos;
273
274 return Rank;
275 }
276
277 // Get the rank for multi-letter extension, lower value meaning higher
278 // priority/order in canonical order.
multiLetterExtensionRank(const std::string & ExtName)279 static int multiLetterExtensionRank(const std::string &ExtName) {
280 assert(ExtName.length() >= 2);
281 int HighOrder;
282 int LowOrder = 0;
283 // The order between multi-char extensions: s -> h -> z -> x.
284 char ExtClass = ExtName[0];
285 switch (ExtClass) {
286 case 's':
287 HighOrder = 0;
288 break;
289 case 'z':
290 HighOrder = 1;
291 // `z` extension must be sorted by canonical order of second letter.
292 // e.g. zmx has higher rank than zax.
293 LowOrder = singleLetterExtensionRank(ExtName[1]);
294 break;
295 case 'x':
296 HighOrder = 2;
297 break;
298 default:
299 llvm_unreachable("Unknown prefix for multi-char extension");
300 return -1;
301 }
302
303 return (HighOrder << 8) + LowOrder;
304 }
305
306 // Compare function for extension.
307 // Only compare the extension name, ignore version comparison.
compareExtension(const std::string & LHS,const std::string & RHS)308 bool RISCVISAInfo::compareExtension(const std::string &LHS,
309 const std::string &RHS) {
310 size_t LHSLen = LHS.length();
311 size_t RHSLen = RHS.length();
312 if (LHSLen == 1 && RHSLen != 1)
313 return true;
314
315 if (LHSLen != 1 && RHSLen == 1)
316 return false;
317
318 if (LHSLen == 1 && RHSLen == 1)
319 return singleLetterExtensionRank(LHS[0]) <
320 singleLetterExtensionRank(RHS[0]);
321
322 // Both are multi-char ext here.
323 int LHSRank = multiLetterExtensionRank(LHS);
324 int RHSRank = multiLetterExtensionRank(RHS);
325 if (LHSRank != RHSRank)
326 return LHSRank < RHSRank;
327
328 // If the rank is same, it must be sorted by lexicographic order.
329 return LHS < RHS;
330 }
331
toFeatures(std::vector<StringRef> & Features,llvm::function_ref<StringRef (const Twine &)> StrAlloc,bool AddAllExtensions) const332 void RISCVISAInfo::toFeatures(
333 std::vector<StringRef> &Features,
334 llvm::function_ref<StringRef(const Twine &)> StrAlloc,
335 bool AddAllExtensions) const {
336 for (auto const &Ext : Exts) {
337 StringRef ExtName = Ext.first;
338
339 if (ExtName == "i")
340 continue;
341
342 if (isExperimentalExtension(ExtName)) {
343 Features.push_back(StrAlloc("+experimental-" + ExtName));
344 } else {
345 Features.push_back(StrAlloc("+" + ExtName));
346 }
347 }
348 if (AddAllExtensions) {
349 for (const RISCVSupportedExtension &Ext : SupportedExtensions) {
350 if (Exts.count(Ext.Name))
351 continue;
352 Features.push_back(StrAlloc(Twine("-") + Ext.Name));
353 }
354
355 for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {
356 if (Exts.count(Ext.Name))
357 continue;
358 Features.push_back(StrAlloc(Twine("-experimental-") + Ext.Name));
359 }
360 }
361 }
362
363 // Extensions may have a version number, and may be separated by
364 // an underscore '_' e.g.: rv32i2_m2.
365 // Version number is divided into major and minor version numbers,
366 // separated by a 'p'. If the minor version is 0 then 'p0' can be
367 // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
getExtensionVersion(StringRef Ext,StringRef In,unsigned & Major,unsigned & Minor,unsigned & ConsumeLength,bool EnableExperimentalExtension,bool ExperimentalExtensionVersionCheck)368 static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
369 unsigned &Minor, unsigned &ConsumeLength,
370 bool EnableExperimentalExtension,
371 bool ExperimentalExtensionVersionCheck) {
372 StringRef MajorStr, MinorStr;
373 Major = 0;
374 Minor = 0;
375 ConsumeLength = 0;
376 MajorStr = In.take_while(isDigit);
377 In = In.substr(MajorStr.size());
378
379 if (!MajorStr.empty() && In.consume_front("p")) {
380 MinorStr = In.take_while(isDigit);
381 In = In.substr(MajorStr.size() + MinorStr.size() - 1);
382
383 // Expected 'p' to be followed by minor version number.
384 if (MinorStr.empty()) {
385 return createStringError(
386 errc::invalid_argument,
387 "minor version number missing after 'p' for extension '" + Ext + "'");
388 }
389 }
390
391 if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
392 return createStringError(
393 errc::invalid_argument,
394 "Failed to parse major version number for extension '" + Ext + "'");
395
396 if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
397 return createStringError(
398 errc::invalid_argument,
399 "Failed to parse minor version number for extension '" + Ext + "'");
400
401 ConsumeLength = MajorStr.size();
402
403 if (!MinorStr.empty())
404 ConsumeLength += MinorStr.size() + 1 /*'p'*/;
405
406 // Expected multi-character extension with version number to have no
407 // subsequent characters (i.e. must either end string or be followed by
408 // an underscore).
409 if (Ext.size() > 1 && In.size()) {
410 std::string Error =
411 "multi-character extensions must be separated by underscores";
412 return createStringError(errc::invalid_argument, Error);
413 }
414
415 // If experimental extension, require use of current version number number
416 if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
417 if (!EnableExperimentalExtension) {
418 std::string Error = "requires '-menable-experimental-extensions' for "
419 "experimental extension '" +
420 Ext.str() + "'";
421 return createStringError(errc::invalid_argument, Error);
422 }
423
424 if (ExperimentalExtensionVersionCheck &&
425 (MajorStr.empty() && MinorStr.empty())) {
426 std::string Error =
427 "experimental extension requires explicit version number `" +
428 Ext.str() + "`";
429 return createStringError(errc::invalid_argument, Error);
430 }
431
432 auto SupportedVers = *ExperimentalExtension;
433 if (ExperimentalExtensionVersionCheck &&
434 (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
435 std::string Error = "unsupported version number " + MajorStr.str();
436 if (!MinorStr.empty())
437 Error += "." + MinorStr.str();
438 Error += " for experimental extension '" + Ext.str() +
439 "' (this compiler supports " + utostr(SupportedVers.Major) +
440 "." + utostr(SupportedVers.Minor) + ")";
441 return createStringError(errc::invalid_argument, Error);
442 }
443 return Error::success();
444 }
445
446 // Exception rule for `g`, we don't have clear version scheme for that on
447 // ISA spec.
448 if (Ext == "g")
449 return Error::success();
450
451 if (MajorStr.empty() && MinorStr.empty()) {
452 if (auto DefaultVersion = findDefaultVersion(Ext)) {
453 Major = DefaultVersion->Major;
454 Minor = DefaultVersion->Minor;
455 }
456 // No matter found or not, return success, assume other place will
457 // verify.
458 return Error::success();
459 }
460
461 if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
462 return Error::success();
463
464 std::string Error = "unsupported version number " + std::string(MajorStr);
465 if (!MinorStr.empty())
466 Error += "." + MinorStr.str();
467 Error += " for extension '" + Ext.str() + "'";
468 return createStringError(errc::invalid_argument, Error);
469 }
470
471 llvm::Expected<std::unique_ptr<RISCVISAInfo>>
parseFeatures(unsigned XLen,const std::vector<std::string> & Features)472 RISCVISAInfo::parseFeatures(unsigned XLen,
473 const std::vector<std::string> &Features) {
474 assert(XLen == 32 || XLen == 64);
475 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
476
477 for (auto &Feature : Features) {
478 StringRef ExtName = Feature;
479 bool Experimental = false;
480 assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
481 bool Add = ExtName[0] == '+';
482 ExtName = ExtName.drop_front(1); // Drop '+' or '-'
483 Experimental = stripExperimentalPrefix(ExtName);
484 auto ExtensionInfos = Experimental
485 ? ArrayRef(SupportedExperimentalExtensions)
486 : ArrayRef(SupportedExtensions);
487 auto ExtensionInfoIterator =
488 llvm::find_if(ExtensionInfos, FindByName(ExtName));
489
490 // Not all features is related to ISA extension, like `relax` or
491 // `save-restore`, skip those feature.
492 if (ExtensionInfoIterator == ExtensionInfos.end())
493 continue;
494
495 if (Add)
496 ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major,
497 ExtensionInfoIterator->Version.Minor);
498 else
499 ISAInfo->Exts.erase(ExtName.str());
500 }
501
502 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
503 }
504
505 llvm::Expected<std::unique_ptr<RISCVISAInfo>>
parseNormalizedArchString(StringRef Arch)506 RISCVISAInfo::parseNormalizedArchString(StringRef Arch) {
507 if (llvm::any_of(Arch, isupper)) {
508 return createStringError(errc::invalid_argument,
509 "string must be lowercase");
510 }
511 // Must start with a valid base ISA name.
512 unsigned XLen;
513 if (Arch.startswith("rv32i") || Arch.startswith("rv32e"))
514 XLen = 32;
515 else if (Arch.startswith("rv64i") || Arch.startswith("rv64e"))
516 XLen = 64;
517 else
518 return createStringError(errc::invalid_argument,
519 "arch string must begin with valid base ISA");
520 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
521 // Discard rv32/rv64 prefix.
522 Arch = Arch.substr(4);
523
524 // Each extension is of the form ${name}${major_version}p${minor_version}
525 // and separated by _. Split by _ and then extract the name and version
526 // information for each extension.
527 SmallVector<StringRef, 8> Split;
528 Arch.split(Split, '_');
529 for (StringRef Ext : Split) {
530 StringRef Prefix, MinorVersionStr;
531 std::tie(Prefix, MinorVersionStr) = Ext.rsplit('p');
532 if (MinorVersionStr.empty())
533 return createStringError(errc::invalid_argument,
534 "extension lacks version in expected format");
535 unsigned MajorVersion, MinorVersion;
536 if (MinorVersionStr.getAsInteger(10, MinorVersion))
537 return createStringError(errc::invalid_argument,
538 "failed to parse minor version number");
539
540 // Split Prefix into the extension name and the major version number
541 // (the trailing digits of Prefix).
542 int TrailingDigits = 0;
543 StringRef ExtName = Prefix;
544 while (!ExtName.empty()) {
545 if (!isDigit(ExtName.back()))
546 break;
547 ExtName = ExtName.drop_back(1);
548 TrailingDigits++;
549 }
550 if (!TrailingDigits)
551 return createStringError(errc::invalid_argument,
552 "extension lacks version in expected format");
553
554 StringRef MajorVersionStr = Prefix.take_back(TrailingDigits);
555 if (MajorVersionStr.getAsInteger(10, MajorVersion))
556 return createStringError(errc::invalid_argument,
557 "failed to parse major version number");
558 ISAInfo->addExtension(ExtName, MajorVersion, MinorVersion);
559 }
560 ISAInfo->updateFLen();
561 ISAInfo->updateMinVLen();
562 ISAInfo->updateMaxELen();
563 return std::move(ISAInfo);
564 }
565
566 llvm::Expected<std::unique_ptr<RISCVISAInfo>>
parseArchString(StringRef Arch,bool EnableExperimentalExtension,bool ExperimentalExtensionVersionCheck,bool IgnoreUnknown)567 RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
568 bool ExperimentalExtensionVersionCheck,
569 bool IgnoreUnknown) {
570 // RISC-V ISA strings must be lowercase.
571 if (llvm::any_of(Arch, isupper)) {
572 return createStringError(errc::invalid_argument,
573 "string must be lowercase");
574 }
575
576 bool HasRV64 = Arch.startswith("rv64");
577 // ISA string must begin with rv32 or rv64.
578 if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) {
579 return createStringError(errc::invalid_argument,
580 "string must begin with rv32{i,e,g} or rv64{i,g}");
581 }
582
583 unsigned XLen = HasRV64 ? 64 : 32;
584 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
585
586 // The canonical order specified in ISA manual.
587 // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
588 StringRef StdExts = AllStdExts;
589 char Baseline = Arch[4];
590
591 // First letter should be 'e', 'i' or 'g'.
592 switch (Baseline) {
593 default:
594 return createStringError(errc::invalid_argument,
595 "first letter should be 'e', 'i' or 'g'");
596 case 'e': {
597 // Extension 'e' is not allowed in rv64.
598 if (HasRV64)
599 return createStringError(
600 errc::invalid_argument,
601 "standard user-level extension 'e' requires 'rv32'");
602 break;
603 }
604 case 'i':
605 break;
606 case 'g':
607 // g = imafd
608 StdExts = StdExts.drop_front(4);
609 break;
610 }
611
612 // Skip rvxxx
613 StringRef Exts = Arch.substr(5);
614
615 // Remove multi-letter standard extensions, non-standard extensions and
616 // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
617 // Parse them at the end.
618 // Find the very first occurrence of 's', 'x' or 'z'.
619 StringRef OtherExts;
620 size_t Pos = Exts.find_first_of("zsx");
621 if (Pos != StringRef::npos) {
622 OtherExts = Exts.substr(Pos);
623 Exts = Exts.substr(0, Pos);
624 }
625
626 unsigned Major, Minor, ConsumeLength;
627 if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor,
628 ConsumeLength, EnableExperimentalExtension,
629 ExperimentalExtensionVersionCheck))
630 return std::move(E);
631
632 if (Baseline == 'g') {
633 // No matter which version is given to `g`, we always set imafd to default
634 // version since the we don't have clear version scheme for that on
635 // ISA spec.
636 for (const auto *Ext : {"i", "m", "a", "f", "d"})
637 if (auto Version = findDefaultVersion(Ext))
638 ISAInfo->addExtension(Ext, Version->Major, Version->Minor);
639 else
640 llvm_unreachable("Default extension version not found?");
641 } else
642 // Baseline is `i` or `e`
643 ISAInfo->addExtension(std::string(1, Baseline), Major, Minor);
644
645 // Consume the base ISA version number and any '_' between rvxxx and the
646 // first extension
647 Exts = Exts.drop_front(ConsumeLength);
648 Exts.consume_front("_");
649
650 // TODO: Use version number when setting target features
651
652 auto StdExtsItr = StdExts.begin();
653 auto StdExtsEnd = StdExts.end();
654 auto GoToNextExt = [](StringRef::iterator &I, unsigned ConsumeLength) {
655 I += 1 + ConsumeLength;
656 if (*I == '_')
657 ++I;
658 };
659 for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
660 char C = *I;
661
662 // Check ISA extensions are specified in the canonical order.
663 while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
664 ++StdExtsItr;
665
666 if (StdExtsItr == StdExtsEnd) {
667 // Either c contains a valid extension but it was not given in
668 // canonical order or it is an invalid extension.
669 if (StdExts.contains(C)) {
670 return createStringError(
671 errc::invalid_argument,
672 "standard user-level extension not given in canonical order '%c'",
673 C);
674 }
675
676 return createStringError(errc::invalid_argument,
677 "invalid standard user-level extension '%c'", C);
678 }
679
680 // Move to next char to prevent repeated letter.
681 ++StdExtsItr;
682
683 std::string Next;
684 unsigned Major, Minor, ConsumeLength;
685 if (std::next(I) != E)
686 Next = std::string(std::next(I), E);
687 if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor,
688 ConsumeLength, EnableExperimentalExtension,
689 ExperimentalExtensionVersionCheck)) {
690 if (IgnoreUnknown) {
691 consumeError(std::move(E));
692 GoToNextExt(I, ConsumeLength);
693 continue;
694 }
695 return std::move(E);
696 }
697
698 // The order is OK, then push it into features.
699 // TODO: Use version number when setting target features
700 // Currently LLVM supports only "mafdcvh".
701 if (!isSupportedExtension(StringRef(&C, 1))) {
702 if (IgnoreUnknown) {
703 GoToNextExt(I, ConsumeLength);
704 continue;
705 }
706 return createStringError(errc::invalid_argument,
707 "unsupported standard user-level extension '%c'",
708 C);
709 }
710 ISAInfo->addExtension(std::string(1, C), Major, Minor);
711
712 // Consume full extension name and version, including any optional '_'
713 // between this extension and the next
714 GoToNextExt(I, ConsumeLength);
715 }
716
717 // Handle other types of extensions other than the standard
718 // general purpose and standard user-level extensions.
719 // Parse the ISA string containing non-standard user-level
720 // extensions, standard supervisor-level extensions and
721 // non-standard supervisor-level extensions.
722 // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
723 // canonical order, might have a version number (major, minor)
724 // and are separated by a single underscore '_'.
725 // Set the hardware features for the extensions that are supported.
726
727 // Multi-letter extensions are seperated by a single underscore
728 // as described in RISC-V User-Level ISA V2.2.
729 SmallVector<StringRef, 8> Split;
730 OtherExts.split(Split, '_');
731
732 SmallVector<StringRef, 8> AllExts;
733 std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"};
734 auto I = Prefix.begin();
735 auto E = Prefix.end();
736 if (Split.size() > 1 || Split[0] != "") {
737 for (StringRef Ext : Split) {
738 if (Ext.empty())
739 return createStringError(errc::invalid_argument,
740 "extension name missing after separator '_'");
741
742 StringRef Type = getExtensionType(Ext);
743 StringRef Desc = getExtensionTypeDesc(Ext);
744 auto Pos = findFirstNonVersionCharacter(Ext) + 1;
745 StringRef Name(Ext.substr(0, Pos));
746 StringRef Vers(Ext.substr(Pos));
747
748 if (Type.empty()) {
749 if (IgnoreUnknown)
750 continue;
751 return createStringError(errc::invalid_argument,
752 "invalid extension prefix '" + Ext + "'");
753 }
754
755 // Check ISA extensions are specified in the canonical order.
756 while (I != E && *I != Type)
757 ++I;
758
759 if (I == E) {
760 if (IgnoreUnknown)
761 continue;
762 return createStringError(errc::invalid_argument,
763 "%s not given in canonical order '%s'",
764 Desc.str().c_str(), Ext.str().c_str());
765 }
766
767 if (!IgnoreUnknown && Name.size() == Type.size()) {
768 return createStringError(errc::invalid_argument,
769 "%s name missing after '%s'",
770 Desc.str().c_str(), Type.str().c_str());
771 }
772
773 unsigned Major, Minor, ConsumeLength;
774 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
775 EnableExperimentalExtension,
776 ExperimentalExtensionVersionCheck)) {
777 if (IgnoreUnknown) {
778 consumeError(std::move(E));
779 continue;
780 }
781 return std::move(E);
782 }
783
784 // Check if duplicated extension.
785 if (!IgnoreUnknown && llvm::is_contained(AllExts, Name)) {
786 return createStringError(errc::invalid_argument, "duplicated %s '%s'",
787 Desc.str().c_str(), Name.str().c_str());
788 }
789
790 ISAInfo->addExtension(Name, Major, Minor);
791 // Extension format is correct, keep parsing the extensions.
792 // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
793 AllExts.push_back(Name);
794 }
795 }
796
797 for (auto Ext : AllExts) {
798 if (!isSupportedExtension(Ext)) {
799 StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
800 return createStringError(errc::invalid_argument, "unsupported %s '%s'",
801 Desc.str().c_str(), Ext.str().c_str());
802 }
803 }
804
805 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
806 }
807
checkDependency()808 Error RISCVISAInfo::checkDependency() {
809 bool IsRv32 = XLen == 32;
810 bool HasE = Exts.count("e") != 0;
811 bool HasD = Exts.count("d") != 0;
812 bool HasF = Exts.count("f") != 0;
813 bool HasZfinx = Exts.count("zfinx") != 0;
814 bool HasZdinx = Exts.count("zdinx") != 0;
815 bool HasVector = Exts.count("zve32x") != 0;
816 bool HasZve32f = Exts.count("zve32f") != 0;
817 bool HasZve64d = Exts.count("zve64d") != 0;
818 bool HasZvl = MinVLen != 0;
819
820 if (HasE && !IsRv32)
821 return createStringError(
822 errc::invalid_argument,
823 "standard user-level extension 'e' requires 'rv32'");
824
825 // It's illegal to specify the 'd' (double-precision floating point)
826 // extension without also specifying the 'f' (single precision
827 // floating-point) extension.
828 // TODO: This has been removed in later specs, which specify that D implies F
829 if (HasD && !HasF)
830 return createStringError(errc::invalid_argument,
831 "d requires f extension to also be specified");
832
833 if (HasZve32f && !HasF && !HasZfinx)
834 return createStringError(
835 errc::invalid_argument,
836 "zve32f requires f or zfinx extension to also be specified");
837
838 if (HasZve64d && !HasD && !HasZdinx)
839 return createStringError(
840 errc::invalid_argument,
841 "zve64d requires d or zdinx extension to also be specified");
842
843 if (Exts.count("zvfh") && !Exts.count("zfh") && !Exts.count("zfhmin") &&
844 !Exts.count("zhinx") && !Exts.count("zhinxmin"))
845 return createStringError(
846 errc::invalid_argument,
847 "zvfh requires zfh, zfhmin, zhinx or zhinxmin extension to also be "
848 "specified");
849
850 if (HasZvl && !HasVector)
851 return createStringError(
852 errc::invalid_argument,
853 "zvl*b requires v or zve* extension to also be specified");
854
855 // Additional dependency checks.
856 // TODO: The 'q' extension requires rv64.
857 // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
858
859 return Error::success();
860 }
861
862 static const char *ImpliedExtsV[] = {"zvl128b", "zve64d", "f", "d"};
863 static const char *ImpliedExtsZfhmin[] = {"f"};
864 static const char *ImpliedExtsZfh[] = {"f"};
865 static const char *ImpliedExtsZdinx[] = {"zfinx"};
866 static const char *ImpliedExtsZhinxmin[] = {"zfinx"};
867 static const char *ImpliedExtsZhinx[] = {"zfinx"};
868 static const char *ImpliedExtsZve64d[] = {"zve64f"};
869 static const char *ImpliedExtsZve64f[] = {"zve64x", "zve32f"};
870 static const char *ImpliedExtsZve64x[] = {"zve32x", "zvl64b"};
871 static const char *ImpliedExtsZve32f[] = {"zve32x"};
872 static const char *ImpliedExtsZve32x[] = {"zvl32b"};
873 static const char *ImpliedExtsZvl65536b[] = {"zvl32768b"};
874 static const char *ImpliedExtsZvl32768b[] = {"zvl16384b"};
875 static const char *ImpliedExtsZvl16384b[] = {"zvl8192b"};
876 static const char *ImpliedExtsZvl8192b[] = {"zvl4096b"};
877 static const char *ImpliedExtsZvl4096b[] = {"zvl2048b"};
878 static const char *ImpliedExtsZvl2048b[] = {"zvl1024b"};
879 static const char *ImpliedExtsZvl1024b[] = {"zvl512b"};
880 static const char *ImpliedExtsZvl512b[] = {"zvl256b"};
881 static const char *ImpliedExtsZvl256b[] = {"zvl128b"};
882 static const char *ImpliedExtsZvl128b[] = {"zvl64b"};
883 static const char *ImpliedExtsZvl64b[] = {"zvl32b"};
884 static const char *ImpliedExtsZk[] = {"zkn", "zkt", "zkr"};
885 static const char *ImpliedExtsZkn[] = {"zbkb", "zbkc", "zbkx",
886 "zkne", "zknd", "zknh"};
887 static const char *ImpliedExtsZks[] = {"zbkb", "zbkc", "zbkx", "zksed", "zksh"};
888 static const char *ImpliedExtsZvfh[] = {"zve32f"};
889 static const char *ImpliedExtsXTHeadVdot[] = {"v"};
890
891 struct ImpliedExtsEntry {
892 StringLiteral Name;
893 ArrayRef<const char *> Exts;
894
operator <ImpliedExtsEntry895 bool operator<(const ImpliedExtsEntry &Other) const {
896 return Name < Other.Name;
897 }
898
operator <ImpliedExtsEntry899 bool operator<(StringRef Other) const { return Name < Other; }
900 };
901
902 // Note: The table needs to be sorted by name.
903 static constexpr ImpliedExtsEntry ImpliedExts[] = {
904 {{"v"}, {ImpliedExtsV}},
905 {{"xtheadvdot"}, {ImpliedExtsXTHeadVdot}},
906 {{"zdinx"}, {ImpliedExtsZdinx}},
907 {{"zfh"}, {ImpliedExtsZfh}},
908 {{"zfhmin"}, {ImpliedExtsZfhmin}},
909 {{"zhinx"}, {ImpliedExtsZhinx}},
910 {{"zhinxmin"}, {ImpliedExtsZhinxmin}},
911 {{"zk"}, {ImpliedExtsZk}},
912 {{"zkn"}, {ImpliedExtsZkn}},
913 {{"zks"}, {ImpliedExtsZks}},
914 {{"zve32f"}, {ImpliedExtsZve32f}},
915 {{"zve32x"}, {ImpliedExtsZve32x}},
916 {{"zve64d"}, {ImpliedExtsZve64d}},
917 {{"zve64f"}, {ImpliedExtsZve64f}},
918 {{"zve64x"}, {ImpliedExtsZve64x}},
919 {{"zvfh"}, {ImpliedExtsZvfh}},
920 {{"zvl1024b"}, {ImpliedExtsZvl1024b}},
921 {{"zvl128b"}, {ImpliedExtsZvl128b}},
922 {{"zvl16384b"}, {ImpliedExtsZvl16384b}},
923 {{"zvl2048b"}, {ImpliedExtsZvl2048b}},
924 {{"zvl256b"}, {ImpliedExtsZvl256b}},
925 {{"zvl32768b"}, {ImpliedExtsZvl32768b}},
926 {{"zvl4096b"}, {ImpliedExtsZvl4096b}},
927 {{"zvl512b"}, {ImpliedExtsZvl512b}},
928 {{"zvl64b"}, {ImpliedExtsZvl64b}},
929 {{"zvl65536b"}, {ImpliedExtsZvl65536b}},
930 {{"zvl8192b"}, {ImpliedExtsZvl8192b}},
931 };
932
updateImplication()933 void RISCVISAInfo::updateImplication() {
934 bool HasE = Exts.count("e") != 0;
935 bool HasI = Exts.count("i") != 0;
936
937 // If not in e extension and i extension does not exist, i extension is
938 // implied
939 if (!HasE && !HasI) {
940 auto Version = findDefaultVersion("i");
941 addExtension("i", Version->Major, Version->Minor);
942 }
943
944 assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
945
946 // This loop may execute over 1 iteration since implication can be layered
947 // Exits loop if no more implication is applied
948 SmallSetVector<StringRef, 16> WorkList;
949 for (auto const &Ext : Exts)
950 WorkList.insert(Ext.first);
951
952 while (!WorkList.empty()) {
953 StringRef ExtName = WorkList.pop_back_val();
954 auto I = llvm::lower_bound(ImpliedExts, ExtName);
955 if (I != std::end(ImpliedExts) && I->Name == ExtName) {
956 for (const char *ImpliedExt : I->Exts) {
957 if (WorkList.count(ImpliedExt))
958 continue;
959 if (Exts.count(ImpliedExt))
960 continue;
961 auto Version = findDefaultVersion(ImpliedExt);
962 addExtension(ImpliedExt, Version->Major, Version->Minor);
963 WorkList.insert(ImpliedExt);
964 }
965 }
966 }
967 }
968
969 struct CombinedExtsEntry {
970 StringLiteral CombineExt;
971 ArrayRef<const char *> RequiredExts;
972 };
973
974 static constexpr CombinedExtsEntry CombineIntoExts[] = {
975 {{"zk"}, {ImpliedExtsZk}},
976 {{"zkn"}, {ImpliedExtsZkn}},
977 {{"zks"}, {ImpliedExtsZks}},
978 };
979
updateCombination()980 void RISCVISAInfo::updateCombination() {
981 bool IsNewCombine = false;
982 do {
983 IsNewCombine = false;
984 for (CombinedExtsEntry CombineIntoExt : CombineIntoExts) {
985 auto CombineExt = CombineIntoExt.CombineExt;
986 auto RequiredExts = CombineIntoExt.RequiredExts;
987 if (hasExtension(CombineExt))
988 continue;
989 bool IsAllRequiredFeatureExist = true;
990 for (const char *Ext : RequiredExts)
991 IsAllRequiredFeatureExist &= hasExtension(Ext);
992 if (IsAllRequiredFeatureExist) {
993 auto Version = findDefaultVersion(CombineExt);
994 addExtension(CombineExt, Version->Major, Version->Minor);
995 IsNewCombine = true;
996 }
997 }
998 } while (IsNewCombine);
999 }
1000
updateFLen()1001 void RISCVISAInfo::updateFLen() {
1002 FLen = 0;
1003 // TODO: Handle q extension.
1004 if (Exts.count("d"))
1005 FLen = 64;
1006 else if (Exts.count("f"))
1007 FLen = 32;
1008 }
1009
updateMinVLen()1010 void RISCVISAInfo::updateMinVLen() {
1011 for (auto const &Ext : Exts) {
1012 StringRef ExtName = Ext.first;
1013 bool IsZvlExt = ExtName.consume_front("zvl") && ExtName.consume_back("b");
1014 if (IsZvlExt) {
1015 unsigned ZvlLen;
1016 if (!ExtName.getAsInteger(10, ZvlLen))
1017 MinVLen = std::max(MinVLen, ZvlLen);
1018 }
1019 }
1020 }
1021
updateMaxELen()1022 void RISCVISAInfo::updateMaxELen() {
1023 // handles EEW restriction by sub-extension zve
1024 for (auto const &Ext : Exts) {
1025 StringRef ExtName = Ext.first;
1026 bool IsZveExt = ExtName.consume_front("zve");
1027 if (IsZveExt) {
1028 if (ExtName.back() == 'f')
1029 MaxELenFp = std::max(MaxELenFp, 32u);
1030 if (ExtName.back() == 'd')
1031 MaxELenFp = std::max(MaxELenFp, 64u);
1032 ExtName = ExtName.drop_back();
1033 unsigned ZveELen;
1034 ExtName.getAsInteger(10, ZveELen);
1035 MaxELen = std::max(MaxELen, ZveELen);
1036 }
1037 }
1038 }
1039
toString() const1040 std::string RISCVISAInfo::toString() const {
1041 std::string Buffer;
1042 raw_string_ostream Arch(Buffer);
1043
1044 Arch << "rv" << XLen;
1045
1046 ListSeparator LS("_");
1047 for (auto const &Ext : Exts) {
1048 StringRef ExtName = Ext.first;
1049 auto ExtInfo = Ext.second;
1050 Arch << LS << ExtName;
1051 Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion;
1052 }
1053
1054 return Arch.str();
1055 }
1056
toFeatureVector() const1057 std::vector<std::string> RISCVISAInfo::toFeatureVector() const {
1058 std::vector<std::string> FeatureVector;
1059 for (auto const &Ext : Exts) {
1060 std::string ExtName = Ext.first;
1061 if (ExtName == "i") // i is not recognized in clang -cc1
1062 continue;
1063 if (!isSupportedExtension(ExtName))
1064 continue;
1065 std::string Feature = isExperimentalExtension(ExtName)
1066 ? "+experimental-" + ExtName
1067 : "+" + ExtName;
1068 FeatureVector.push_back(Feature);
1069 }
1070 return FeatureVector;
1071 }
1072
1073 llvm::Expected<std::unique_ptr<RISCVISAInfo>>
postProcessAndChecking(std::unique_ptr<RISCVISAInfo> && ISAInfo)1074 RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
1075 ISAInfo->updateImplication();
1076 ISAInfo->updateCombination();
1077 ISAInfo->updateFLen();
1078 ISAInfo->updateMinVLen();
1079 ISAInfo->updateMaxELen();
1080
1081 if (Error Result = ISAInfo->checkDependency())
1082 return std::move(Result);
1083 return std::move(ISAInfo);
1084 }
1085
computeDefaultABI() const1086 StringRef RISCVISAInfo::computeDefaultABI() const {
1087 if (XLen == 32) {
1088 if (hasExtension("d"))
1089 return "ilp32d";
1090 if (hasExtension("e"))
1091 return "ilp32e";
1092 return "ilp32";
1093 } else if (XLen == 64) {
1094 if (hasExtension("d"))
1095 return "lp64d";
1096 return "lp64";
1097 }
1098 llvm_unreachable("Invalid XLEN");
1099 }
1100