LLVM 17.0.0git
RISCVISAInfo.cpp
Go to the documentation of this file.
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
10#include "llvm/ADT/STLExtras.h"
11#include "llvm/ADT/SetVector.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/Support/Errc.h"
15#include "llvm/Support/Error.h"
17
18#include <array>
19#include <optional>
20#include <string>
21#include <vector>
22
23using namespace llvm;
24
25namespace {
26/// Represents the major and version number components of a RISC-V extension
27struct RISCVExtensionVersion {
28 unsigned Major;
29 unsigned Minor;
30};
31
32struct RISCVSupportedExtension {
33 const char *Name;
34 /// Supported version.
35 RISCVExtensionVersion Version;
36};
37
38} // end anonymous namespace
39
40static constexpr StringLiteral AllStdExts = "mafdqlcbkjtpvnh";
41
42static 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
111 // vendor-defined ('X') extensions
112 {"xtheadvdot", RISCVExtensionVersion{1, 0}},
113 {"xventanacondops", RISCVExtensionVersion{1, 0}},
114};
115
116static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
117 {"zihintntl", RISCVExtensionVersion{0, 2}},
118
119 {"zca", RISCVExtensionVersion{1, 0}},
120 {"zcb", RISCVExtensionVersion{1, 0}},
121 {"zcd", RISCVExtensionVersion{1, 0}},
122 {"zcf", RISCVExtensionVersion{1, 0}},
123 {"zvfh", RISCVExtensionVersion{0, 1}},
124 {"zawrs", RISCVExtensionVersion{1, 0}},
125 {"ztso", RISCVExtensionVersion{0, 1}},
126};
127
129 return Ext.consume_front("experimental-");
130}
131
132// This function finds the first character that doesn't belong to a version
133// (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will
134// consume [0-9]*p[0-9]* starting from the backward. An extension name will not
135// end with a digit or the letter 'p', so this function will parse correctly.
136// NOTE: This function is NOT able to take empty strings or strings that only
137// have version numbers and no extension name. It assumes the extension name
138// will be at least more than one character.
140 assert(!Ext.empty() &&
141 "Already guarded by if-statement in ::parseArchString");
142
143 int Pos = Ext.size() - 1;
144 while (Pos > 0 && isDigit(Ext[Pos]))
145 Pos--;
146 if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {
147 Pos--;
148 while (Pos > 0 && isDigit(Ext[Pos]))
149 Pos--;
150 }
151 return Pos;
152}
153
154namespace {
155struct FindByName {
156 FindByName(StringRef Ext) : Ext(Ext){};
158 bool operator()(const RISCVSupportedExtension &ExtInfo) {
159 return ExtInfo.Name == Ext;
160 }
161};
162} // namespace
163
164static std::optional<RISCVExtensionVersion>
166 // Find default version of an extension.
167 // TODO: We might set default version based on profile or ISA spec.
168 for (auto &ExtInfo : {ArrayRef(SupportedExtensions),
170 auto ExtensionInfoIterator = llvm::find_if(ExtInfo, FindByName(ExtName));
171
172 if (ExtensionInfoIterator == ExtInfo.end()) {
173 continue;
174 }
175 return ExtensionInfoIterator->Version;
176 }
177 return std::nullopt;
178}
179
180void RISCVISAInfo::addExtension(StringRef ExtName, unsigned MajorVersion,
181 unsigned MinorVersion) {
183 Ext.ExtName = ExtName.str();
184 Ext.MajorVersion = MajorVersion;
185 Ext.MinorVersion = MinorVersion;
186 Exts[ExtName.str()] = Ext;
187}
188
190 if (Ext.startswith("sx"))
191 return "non-standard supervisor-level extension";
192 if (Ext.startswith("s"))
193 return "standard supervisor-level extension";
194 if (Ext.startswith("x"))
195 return "non-standard user-level extension";
196 if (Ext.startswith("z"))
197 return "standard user-level extension";
198 return StringRef();
199}
200
202 if (Ext.startswith("sx"))
203 return "sx";
204 if (Ext.startswith("s"))
205 return "s";
206 if (Ext.startswith("x"))
207 return "x";
208 if (Ext.startswith("z"))
209 return "z";
210 return StringRef();
211}
212
213static std::optional<RISCVExtensionVersion>
215 auto ExtIterator =
217 if (ExtIterator == std::end(SupportedExperimentalExtensions))
218 return std::nullopt;
219
220 return ExtIterator->Version;
221}
222
224 bool IsExperimental = stripExperimentalPrefix(Ext);
225
226 if (IsExperimental)
227 return llvm::any_of(SupportedExperimentalExtensions, FindByName(Ext));
228 else
229 return llvm::any_of(SupportedExtensions, FindByName(Ext));
230}
231
233 return llvm::any_of(SupportedExtensions, FindByName(Ext)) ||
235}
236
237bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
238 unsigned MinorVersion) {
239 auto FindByNameAndVersion = [=](const RISCVSupportedExtension &ExtInfo) {
240 return ExtInfo.Name == Ext && (MajorVersion == ExtInfo.Version.Major) &&
241 (MinorVersion == ExtInfo.Version.Minor);
242 };
243 return llvm::any_of(SupportedExtensions, FindByNameAndVersion) ||
244 llvm::any_of(SupportedExperimentalExtensions, FindByNameAndVersion);
245}
246
249
250 if (!isSupportedExtension(Ext))
251 return false;
252
253 return Exts.count(Ext.str()) != 0;
254}
255
256// Get the rank for single-letter extension, lower value meaning higher
257// priority.
258static int singleLetterExtensionRank(char Ext) {
259 switch (Ext) {
260 case 'i':
261 return -2;
262 case 'e':
263 return -1;
264 default:
265 break;
266 }
267
268 size_t Pos = AllStdExts.find(Ext);
269 int Rank;
270 if (Pos == StringRef::npos)
271 // If we got an unknown extension letter, then give it an alphabetical
272 // order, but after all known standard extensions.
273 Rank = AllStdExts.size() + (Ext - 'a');
274 else
275 Rank = Pos;
276
277 return Rank;
278}
279
280// Get the rank for multi-letter extension, lower value meaning higher
281// priority/order in canonical order.
282static int multiLetterExtensionRank(const std::string &ExtName) {
283 assert(ExtName.length() >= 2);
284 int HighOrder;
285 int LowOrder = 0;
286 // The order between multi-char extensions: s -> h -> z -> x.
287 char ExtClass = ExtName[0];
288 switch (ExtClass) {
289 case 's':
290 HighOrder = 0;
291 break;
292 case 'z':
293 HighOrder = 1;
294 // `z` extension must be sorted by canonical order of second letter.
295 // e.g. zmx has higher rank than zax.
296 LowOrder = singleLetterExtensionRank(ExtName[1]);
297 break;
298 case 'x':
299 HighOrder = 2;
300 break;
301 default:
302 llvm_unreachable("Unknown prefix for multi-char extension");
303 return -1;
304 }
305
306 return (HighOrder << 8) + LowOrder;
307}
308
309// Compare function for extension.
310// Only compare the extension name, ignore version comparison.
311bool RISCVISAInfo::compareExtension(const std::string &LHS,
312 const std::string &RHS) {
313 size_t LHSLen = LHS.length();
314 size_t RHSLen = RHS.length();
315 if (LHSLen == 1 && RHSLen != 1)
316 return true;
317
318 if (LHSLen != 1 && RHSLen == 1)
319 return false;
320
321 if (LHSLen == 1 && RHSLen == 1)
322 return singleLetterExtensionRank(LHS[0]) <
324
325 // Both are multi-char ext here.
326 int LHSRank = multiLetterExtensionRank(LHS);
327 int RHSRank = multiLetterExtensionRank(RHS);
328 if (LHSRank != RHSRank)
329 return LHSRank < RHSRank;
330
331 // If the rank is same, it must be sorted by lexicographic order.
332 return LHS < RHS;
333}
334
336 std::vector<StringRef> &Features,
337 llvm::function_ref<StringRef(const Twine &)> StrAlloc,
338 bool AddAllExtensions) const {
339 for (auto const &Ext : Exts) {
340 StringRef ExtName = Ext.first;
341
342 if (ExtName == "i")
343 continue;
344
345 if (isExperimentalExtension(ExtName)) {
346 Features.push_back(StrAlloc("+experimental-" + ExtName));
347 } else {
348 Features.push_back(StrAlloc("+" + ExtName));
349 }
350 }
351 if (AddAllExtensions) {
352 for (const RISCVSupportedExtension &Ext : SupportedExtensions) {
353 if (Exts.count(Ext.Name))
354 continue;
355 Features.push_back(StrAlloc(Twine("-") + Ext.Name));
356 }
357
358 for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {
359 if (Exts.count(Ext.Name))
360 continue;
361 Features.push_back(StrAlloc(Twine("-experimental-") + Ext.Name));
362 }
363 }
364}
365
366// Extensions may have a version number, and may be separated by
367// an underscore '_' e.g.: rv32i2_m2.
368// Version number is divided into major and minor version numbers,
369// separated by a 'p'. If the minor version is 0 then 'p0' can be
370// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
371static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
372 unsigned &Minor, unsigned &ConsumeLength,
373 bool EnableExperimentalExtension,
374 bool ExperimentalExtensionVersionCheck) {
375 StringRef MajorStr, MinorStr;
376 Major = 0;
377 Minor = 0;
378 ConsumeLength = 0;
379 MajorStr = In.take_while(isDigit);
380 In = In.substr(MajorStr.size());
381
382 if (!MajorStr.empty() && In.consume_front("p")) {
383 MinorStr = In.take_while(isDigit);
384 In = In.substr(MajorStr.size() + MinorStr.size() - 1);
385
386 // Expected 'p' to be followed by minor version number.
387 if (MinorStr.empty()) {
388 return createStringError(
390 "minor version number missing after 'p' for extension '" + Ext + "'");
391 }
392 }
393
394 if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
395 return createStringError(
397 "Failed to parse major version number for extension '" + Ext + "'");
398
399 if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
400 return createStringError(
402 "Failed to parse minor version number for extension '" + Ext + "'");
403
404 ConsumeLength = MajorStr.size();
405
406 if (!MinorStr.empty())
407 ConsumeLength += MinorStr.size() + 1 /*'p'*/;
408
409 // Expected multi-character extension with version number to have no
410 // subsequent characters (i.e. must either end string or be followed by
411 // an underscore).
412 if (Ext.size() > 1 && In.size()) {
413 std::string Error =
414 "multi-character extensions must be separated by underscores";
416 }
417
418 // If experimental extension, require use of current version number number
419 if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
420 if (!EnableExperimentalExtension) {
421 std::string Error = "requires '-menable-experimental-extensions' for "
422 "experimental extension '" +
423 Ext.str() + "'";
425 }
426
427 if (ExperimentalExtensionVersionCheck &&
428 (MajorStr.empty() && MinorStr.empty())) {
429 std::string Error =
430 "experimental extension requires explicit version number `" +
431 Ext.str() + "`";
433 }
434
435 auto SupportedVers = *ExperimentalExtension;
436 if (ExperimentalExtensionVersionCheck &&
437 (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
438 std::string Error = "unsupported version number " + MajorStr.str();
439 if (!MinorStr.empty())
440 Error += "." + MinorStr.str();
441 Error += " for experimental extension '" + Ext.str() +
442 "' (this compiler supports " + utostr(SupportedVers.Major) +
443 "." + utostr(SupportedVers.Minor) + ")";
445 }
446 return Error::success();
447 }
448
449 // Exception rule for `g`, we don't have clear version scheme for that on
450 // ISA spec.
451 if (Ext == "g")
452 return Error::success();
453
454 if (MajorStr.empty() && MinorStr.empty()) {
455 if (auto DefaultVersion = findDefaultVersion(Ext)) {
456 Major = DefaultVersion->Major;
457 Minor = DefaultVersion->Minor;
458 }
459 // No matter found or not, return success, assume other place will
460 // verify.
461 return Error::success();
462 }
463
464 if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
465 return Error::success();
466
467 std::string Error = "unsupported version number " + std::string(MajorStr);
468 if (!MinorStr.empty())
469 Error += "." + MinorStr.str();
470 Error += " for extension '" + Ext.str() + "'";
472}
473
476 const std::vector<std::string> &Features) {
477 assert(XLen == 32 || XLen == 64);
478 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
479
480 for (auto &Feature : Features) {
481 StringRef ExtName = Feature;
482 bool Experimental = false;
483 assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
484 bool Add = ExtName[0] == '+';
485 ExtName = ExtName.drop_front(1); // Drop '+' or '-'
486 Experimental = stripExperimentalPrefix(ExtName);
487 auto ExtensionInfos = Experimental
490 auto ExtensionInfoIterator =
491 llvm::find_if(ExtensionInfos, FindByName(ExtName));
492
493 // Not all features is related to ISA extension, like `relax` or
494 // `save-restore`, skip those feature.
495 if (ExtensionInfoIterator == ExtensionInfos.end())
496 continue;
497
498 if (Add)
499 ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version.Major,
500 ExtensionInfoIterator->Version.Minor);
501 else
502 ISAInfo->Exts.erase(ExtName.str());
503 }
504
505 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
506}
507
509RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
510 bool ExperimentalExtensionVersionCheck,
511 bool IgnoreUnknown) {
512 // RISC-V ISA strings must be lowercase.
513 if (llvm::any_of(Arch, isupper)) {
515 "string must be lowercase");
516 }
517
518 bool HasRV64 = Arch.startswith("rv64");
519 // ISA string must begin with rv32 or rv64.
520 if (!(Arch.startswith("rv32") || HasRV64) || (Arch.size() < 5)) {
522 "string must begin with rv32{i,e,g} or rv64{i,g}");
523 }
524
525 unsigned XLen = HasRV64 ? 64 : 32;
526 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
527
528 // The canonical order specified in ISA manual.
529 // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
530 StringRef StdExts = AllStdExts;
531 char Baseline = Arch[4];
532
533 // First letter should be 'e', 'i' or 'g'.
534 switch (Baseline) {
535 default:
537 "first letter should be 'e', 'i' or 'g'");
538 case 'e': {
539 // Extension 'e' is not allowed in rv64.
540 if (HasRV64)
541 return createStringError(
543 "standard user-level extension 'e' requires 'rv32'");
544 break;
545 }
546 case 'i':
547 break;
548 case 'g':
549 // g = imafd
550 StdExts = StdExts.drop_front(4);
551 break;
552 }
553
554 // Skip rvxxx
555 StringRef Exts = Arch.substr(5);
556
557 // Remove multi-letter standard extensions, non-standard extensions and
558 // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
559 // Parse them at the end.
560 // Find the very first occurrence of 's', 'x' or 'z'.
561 StringRef OtherExts;
562 size_t Pos = Exts.find_first_of("zsx");
563 if (Pos != StringRef::npos) {
564 OtherExts = Exts.substr(Pos);
565 Exts = Exts.substr(0, Pos);
566 }
567
568 unsigned Major, Minor, ConsumeLength;
569 if (auto E = getExtensionVersion(std::string(1, Baseline), Exts, Major, Minor,
570 ConsumeLength, EnableExperimentalExtension,
571 ExperimentalExtensionVersionCheck))
572 return std::move(E);
573
574 if (Baseline == 'g') {
575 // No matter which version is given to `g`, we always set imafd to default
576 // version since the we don't have clear version scheme for that on
577 // ISA spec.
578 for (const auto *Ext : {"i", "m", "a", "f", "d"})
579 if (auto Version = findDefaultVersion(Ext))
580 ISAInfo->addExtension(Ext, Version->Major, Version->Minor);
581 else
582 llvm_unreachable("Default extension version not found?");
583 } else
584 // Baseline is `i` or `e`
585 ISAInfo->addExtension(std::string(1, Baseline), Major, Minor);
586
587 // Consume the base ISA version number and any '_' between rvxxx and the
588 // first extension
589 Exts = Exts.drop_front(ConsumeLength);
590 Exts.consume_front("_");
591
592 // TODO: Use version number when setting target features
593
594 auto StdExtsItr = StdExts.begin();
595 auto StdExtsEnd = StdExts.end();
596 auto GoToNextExt = [](StringRef::iterator &I, unsigned ConsumeLength) {
597 I += 1 + ConsumeLength;
598 if (*I == '_')
599 ++I;
600 };
601 for (auto I = Exts.begin(), E = Exts.end(); I != E;) {
602 char C = *I;
603
604 // Check ISA extensions are specified in the canonical order.
605 while (StdExtsItr != StdExtsEnd && *StdExtsItr != C)
606 ++StdExtsItr;
607
608 if (StdExtsItr == StdExtsEnd) {
609 // Either c contains a valid extension but it was not given in
610 // canonical order or it is an invalid extension.
611 if (StdExts.contains(C)) {
612 return createStringError(
614 "standard user-level extension not given in canonical order '%c'",
615 C);
616 }
617
619 "invalid standard user-level extension '%c'", C);
620 }
621
622 // Move to next char to prevent repeated letter.
623 ++StdExtsItr;
624
625 std::string Next;
626 unsigned Major, Minor, ConsumeLength;
627 if (std::next(I) != E)
628 Next = std::string(std::next(I), E);
629 if (auto E = getExtensionVersion(std::string(1, C), Next, Major, Minor,
630 ConsumeLength, EnableExperimentalExtension,
631 ExperimentalExtensionVersionCheck)) {
632 if (IgnoreUnknown) {
633 consumeError(std::move(E));
634 GoToNextExt(I, ConsumeLength);
635 continue;
636 }
637 return std::move(E);
638 }
639
640 // The order is OK, then push it into features.
641 // TODO: Use version number when setting target features
642 // Currently LLVM supports only "mafdcvh".
643 if (!isSupportedExtension(StringRef(&C, 1))) {
644 if (IgnoreUnknown) {
645 GoToNextExt(I, ConsumeLength);
646 continue;
647 }
649 "unsupported standard user-level extension '%c'",
650 C);
651 }
652 ISAInfo->addExtension(std::string(1, C), Major, Minor);
653
654 // Consume full extension name and version, including any optional '_'
655 // between this extension and the next
656 GoToNextExt(I, ConsumeLength);
657 }
658
659 // Handle other types of extensions other than the standard
660 // general purpose and standard user-level extensions.
661 // Parse the ISA string containing non-standard user-level
662 // extensions, standard supervisor-level extensions and
663 // non-standard supervisor-level extensions.
664 // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
665 // canonical order, might have a version number (major, minor)
666 // and are separated by a single underscore '_'.
667 // Set the hardware features for the extensions that are supported.
668
669 // Multi-letter extensions are seperated by a single underscore
670 // as described in RISC-V User-Level ISA V2.2.
672 OtherExts.split(Split, '_');
673
675 std::array<StringRef, 4> Prefix{"z", "x", "s", "sx"};
676 auto I = Prefix.begin();
677 auto E = Prefix.end();
678 if (Split.size() > 1 || Split[0] != "") {
679 for (StringRef Ext : Split) {
680 if (Ext.empty())
682 "extension name missing after separator '_'");
683
686 auto Pos = findFirstNonVersionCharacter(Ext) + 1;
687 StringRef Name(Ext.substr(0, Pos));
688 StringRef Vers(Ext.substr(Pos));
689
690 if (Type.empty()) {
691 if (IgnoreUnknown)
692 continue;
694 "invalid extension prefix '" + Ext + "'");
695 }
696
697 // Check ISA extensions are specified in the canonical order.
698 while (I != E && *I != Type)
699 ++I;
700
701 if (I == E) {
702 if (IgnoreUnknown)
703 continue;
705 "%s not given in canonical order '%s'",
706 Desc.str().c_str(), Ext.str().c_str());
707 }
708
709 if (!IgnoreUnknown && Name.size() == Type.size()) {
711 "%s name missing after '%s'",
712 Desc.str().c_str(), Type.str().c_str());
713 }
714
715 unsigned Major, Minor, ConsumeLength;
716 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
717 EnableExperimentalExtension,
718 ExperimentalExtensionVersionCheck)) {
719 if (IgnoreUnknown) {
720 consumeError(std::move(E));
721 continue;
722 }
723 return std::move(E);
724 }
725
726 // Check if duplicated extension.
727 if (!IgnoreUnknown && llvm::is_contained(AllExts, Name)) {
728 return createStringError(errc::invalid_argument, "duplicated %s '%s'",
729 Desc.str().c_str(), Name.str().c_str());
730 }
731
732 ISAInfo->addExtension(Name, Major, Minor);
733 // Extension format is correct, keep parsing the extensions.
734 // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
735 AllExts.push_back(Name);
736 }
737 }
738
739 for (auto Ext : AllExts) {
740 if (!isSupportedExtension(Ext)) {
742 return createStringError(errc::invalid_argument, "unsupported %s '%s'",
743 Desc.str().c_str(), Ext.str().c_str());
744 }
745 }
746
747 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
748}
749
750Error RISCVISAInfo::checkDependency() {
751 bool IsRv32 = XLen == 32;
752 bool HasE = Exts.count("e") != 0;
753 bool HasD = Exts.count("d") != 0;
754 bool HasF = Exts.count("f") != 0;
755 bool HasZfinx = Exts.count("zfinx") != 0;
756 bool HasZdinx = Exts.count("zdinx") != 0;
757 bool HasVector = Exts.count("zve32x") != 0;
758 bool HasZve32f = Exts.count("zve32f") != 0;
759 bool HasZve64d = Exts.count("zve64d") != 0;
760 bool HasZvl = MinVLen != 0;
761
762 if (HasE && !IsRv32)
763 return createStringError(
765 "standard user-level extension 'e' requires 'rv32'");
766
767 // It's illegal to specify the 'd' (double-precision floating point)
768 // extension without also specifying the 'f' (single precision
769 // floating-point) extension.
770 // TODO: This has been removed in later specs, which specify that D implies F
771 if (HasD && !HasF)
773 "d requires f extension to also be specified");
774
775 if (HasZve32f && !HasF && !HasZfinx)
776 return createStringError(
778 "zve32f requires f or zfinx extension to also be specified");
779
780 if (HasZve64d && !HasD && !HasZdinx)
781 return createStringError(
783 "zve64d requires d or zdinx extension to also be specified");
784
785 if (Exts.count("zvfh") && !Exts.count("zfh") && !Exts.count("zfhmin") &&
786 !Exts.count("zhinx") && !Exts.count("zhinxmin"))
787 return createStringError(
789 "zvfh requires zfh, zfhmin, zhinx or zhinxmin extension to also be "
790 "specified");
791
792 if (HasZvl && !HasVector)
793 return createStringError(
795 "zvl*b requires v or zve* extension to also be specified");
796
797 // Additional dependency checks.
798 // TODO: The 'q' extension requires rv64.
799 // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
800
801 return Error::success();
802}
803
804static const char *ImpliedExtsV[] = {"zvl128b", "zve64d", "f", "d"};
805static const char *ImpliedExtsZfhmin[] = {"f"};
806static const char *ImpliedExtsZfh[] = {"f"};
807static const char *ImpliedExtsZdinx[] = {"zfinx"};
808static const char *ImpliedExtsZhinxmin[] = {"zfinx"};
809static const char *ImpliedExtsZhinx[] = {"zfinx"};
810static const char *ImpliedExtsZve64d[] = {"zve64f"};
811static const char *ImpliedExtsZve64f[] = {"zve64x", "zve32f"};
812static const char *ImpliedExtsZve64x[] = {"zve32x", "zvl64b"};
813static const char *ImpliedExtsZve32f[] = {"zve32x"};
814static const char *ImpliedExtsZve32x[] = {"zvl32b"};
815static const char *ImpliedExtsZvl65536b[] = {"zvl32768b"};
816static const char *ImpliedExtsZvl32768b[] = {"zvl16384b"};
817static const char *ImpliedExtsZvl16384b[] = {"zvl8192b"};
818static const char *ImpliedExtsZvl8192b[] = {"zvl4096b"};
819static const char *ImpliedExtsZvl4096b[] = {"zvl2048b"};
820static const char *ImpliedExtsZvl2048b[] = {"zvl1024b"};
821static const char *ImpliedExtsZvl1024b[] = {"zvl512b"};
822static const char *ImpliedExtsZvl512b[] = {"zvl256b"};
823static const char *ImpliedExtsZvl256b[] = {"zvl128b"};
824static const char *ImpliedExtsZvl128b[] = {"zvl64b"};
825static const char *ImpliedExtsZvl64b[] = {"zvl32b"};
826static const char *ImpliedExtsZk[] = {"zkn", "zkt", "zkr"};
827static const char *ImpliedExtsZkn[] = {"zbkb", "zbkc", "zbkx",
828 "zkne", "zknd", "zknh"};
829static const char *ImpliedExtsZks[] = {"zbkb", "zbkc", "zbkx", "zksed", "zksh"};
830static const char *ImpliedExtsZvfh[] = {"zve32f"};
831static const char *ImpliedExtsXTHeadVdot[] = {"v"};
832static const char *ImpliedExtsZcb[] = {"zca"};
833
837
838 bool operator<(const ImpliedExtsEntry &Other) const {
839 return Name < Other.Name;
840 }
841
842 bool operator<(StringRef Other) const { return Name < Other; }
843};
844
845// Note: The table needs to be sorted by name.
846static constexpr ImpliedExtsEntry ImpliedExts[] = {
847 {{"v"}, {ImpliedExtsV}},
848 {{"xtheadvdot"}, {ImpliedExtsXTHeadVdot}},
849 {{"zcb"}, {ImpliedExtsZcb}},
850 {{"zdinx"}, {ImpliedExtsZdinx}},
851 {{"zfh"}, {ImpliedExtsZfh}},
852 {{"zfhmin"}, {ImpliedExtsZfhmin}},
853 {{"zhinx"}, {ImpliedExtsZhinx}},
854 {{"zhinxmin"}, {ImpliedExtsZhinxmin}},
855 {{"zk"}, {ImpliedExtsZk}},
856 {{"zkn"}, {ImpliedExtsZkn}},
857 {{"zks"}, {ImpliedExtsZks}},
858 {{"zve32f"}, {ImpliedExtsZve32f}},
859 {{"zve32x"}, {ImpliedExtsZve32x}},
860 {{"zve64d"}, {ImpliedExtsZve64d}},
861 {{"zve64f"}, {ImpliedExtsZve64f}},
862 {{"zve64x"}, {ImpliedExtsZve64x}},
863 {{"zvfh"}, {ImpliedExtsZvfh}},
864 {{"zvl1024b"}, {ImpliedExtsZvl1024b}},
865 {{"zvl128b"}, {ImpliedExtsZvl128b}},
866 {{"zvl16384b"}, {ImpliedExtsZvl16384b}},
867 {{"zvl2048b"}, {ImpliedExtsZvl2048b}},
868 {{"zvl256b"}, {ImpliedExtsZvl256b}},
869 {{"zvl32768b"}, {ImpliedExtsZvl32768b}},
870 {{"zvl4096b"}, {ImpliedExtsZvl4096b}},
871 {{"zvl512b"}, {ImpliedExtsZvl512b}},
872 {{"zvl64b"}, {ImpliedExtsZvl64b}},
873 {{"zvl65536b"}, {ImpliedExtsZvl65536b}},
874 {{"zvl8192b"}, {ImpliedExtsZvl8192b}},
875};
876
877void RISCVISAInfo::updateImplication() {
878 bool HasE = Exts.count("e") != 0;
879 bool HasI = Exts.count("i") != 0;
880
881 // If not in e extension and i extension does not exist, i extension is
882 // implied
883 if (!HasE && !HasI) {
884 auto Version = findDefaultVersion("i");
885 addExtension("i", Version->Major, Version->Minor);
886 }
887
888 assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
889
890 // This loop may execute over 1 iteration since implication can be layered
891 // Exits loop if no more implication is applied
893 for (auto const &Ext : Exts)
894 WorkList.insert(Ext.first);
895
896 while (!WorkList.empty()) {
897 StringRef ExtName = WorkList.pop_back_val();
898 auto I = llvm::lower_bound(ImpliedExts, ExtName);
899 if (I != std::end(ImpliedExts) && I->Name == ExtName) {
900 for (const char *ImpliedExt : I->Exts) {
901 if (WorkList.count(ImpliedExt))
902 continue;
903 if (Exts.count(ImpliedExt))
904 continue;
905 auto Version = findDefaultVersion(ImpliedExt);
906 addExtension(ImpliedExt, Version->Major, Version->Minor);
907 WorkList.insert(ImpliedExt);
908 }
909 }
910 }
911}
912
916};
917
918static constexpr CombinedExtsEntry CombineIntoExts[] = {
919 {{"zk"}, {ImpliedExtsZk}},
920 {{"zkn"}, {ImpliedExtsZkn}},
921 {{"zks"}, {ImpliedExtsZks}},
922};
923
924void RISCVISAInfo::updateCombination() {
925 bool IsNewCombine = false;
926 do {
927 IsNewCombine = false;
928 for (CombinedExtsEntry CombineIntoExt : CombineIntoExts) {
929 auto CombineExt = CombineIntoExt.CombineExt;
930 auto RequiredExts = CombineIntoExt.RequiredExts;
931 if (hasExtension(CombineExt))
932 continue;
933 bool IsAllRequiredFeatureExist = true;
934 for (const char *Ext : RequiredExts)
935 IsAllRequiredFeatureExist &= hasExtension(Ext);
936 if (IsAllRequiredFeatureExist) {
937 auto Version = findDefaultVersion(CombineExt);
938 addExtension(CombineExt, Version->Major, Version->Minor);
939 IsNewCombine = true;
940 }
941 }
942 } while (IsNewCombine);
943}
944
945void RISCVISAInfo::updateFLen() {
946 FLen = 0;
947 // TODO: Handle q extension.
948 if (Exts.count("d"))
949 FLen = 64;
950 else if (Exts.count("f"))
951 FLen = 32;
952}
953
954void RISCVISAInfo::updateMinVLen() {
955 for (auto const &Ext : Exts) {
956 StringRef ExtName = Ext.first;
957 bool IsZvlExt = ExtName.consume_front("zvl") && ExtName.consume_back("b");
958 if (IsZvlExt) {
959 unsigned ZvlLen;
960 if (!ExtName.getAsInteger(10, ZvlLen))
961 MinVLen = std::max(MinVLen, ZvlLen);
962 }
963 }
964}
965
966void RISCVISAInfo::updateMaxELen() {
967 // handles EEW restriction by sub-extension zve
968 for (auto const &Ext : Exts) {
969 StringRef ExtName = Ext.first;
970 bool IsZveExt = ExtName.consume_front("zve");
971 if (IsZveExt) {
972 if (ExtName.back() == 'f')
973 MaxELenFp = std::max(MaxELenFp, 32u);
974 if (ExtName.back() == 'd')
975 MaxELenFp = std::max(MaxELenFp, 64u);
976 ExtName = ExtName.drop_back();
977 unsigned ZveELen;
978 ExtName.getAsInteger(10, ZveELen);
979 MaxELen = std::max(MaxELen, ZveELen);
980 }
981 }
982}
983
984std::string RISCVISAInfo::toString() const {
985 std::string Buffer;
986 raw_string_ostream Arch(Buffer);
987
988 Arch << "rv" << XLen;
989
990 ListSeparator LS("_");
991 for (auto const &Ext : Exts) {
992 StringRef ExtName = Ext.first;
993 auto ExtInfo = Ext.second;
994 Arch << LS << ExtName;
995 Arch << ExtInfo.MajorVersion << "p" << ExtInfo.MinorVersion;
996 }
997
998 return Arch.str();
999}
1000
1001std::vector<std::string> RISCVISAInfo::toFeatureVector() const {
1002 std::vector<std::string> FeatureVector;
1003 for (auto const &Ext : Exts) {
1004 std::string ExtName = Ext.first;
1005 if (ExtName == "i") // i is not recognized in clang -cc1
1006 continue;
1007 std::string Feature = isExperimentalExtension(ExtName)
1008 ? "+experimental-" + ExtName
1009 : "+" + ExtName;
1010 FeatureVector.push_back(Feature);
1011 }
1012 return FeatureVector;
1013}
1014
1016RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
1017 ISAInfo->updateImplication();
1018 ISAInfo->updateCombination();
1019 ISAInfo->updateFLen();
1020 ISAInfo->updateMinVLen();
1021 ISAInfo->updateMaxELen();
1022
1023 if (Error Result = ISAInfo->checkDependency())
1024 return std::move(Result);
1025 return std::move(ISAInfo);
1026}
1027
1029 if (XLen == 32) {
1030 if (hasExtension("d"))
1031 return "ilp32d";
1032 if (hasExtension("e"))
1033 return "ilp32e";
1034 return "ilp32";
1035 } else if (XLen == 64) {
1036 if (hasExtension("d"))
1037 return "lp64d";
1038 return "lp64";
1039 }
1040 llvm_unreachable("Invalid XLEN");
1041}
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::string Name
std::optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1260
#define I(x, y, z)
Definition: MD5.cpp:58
static const char * ImpliedExtsZvl8192b[]
static const char * ImpliedExtsZks[]
static const char * ImpliedExtsZcb[]
static const char * ImpliedExtsZvl2048b[]
static const char * ImpliedExtsXTHeadVdot[]
static StringRef getExtensionTypeDesc(StringRef Ext)
static const char * ImpliedExtsZvl512b[]
static const char * ImpliedExtsZve32x[]
static constexpr ImpliedExtsEntry ImpliedExts[]
static const char * ImpliedExtsZve32f[]
static const char * ImpliedExtsZvl4096b[]
static const RISCVSupportedExtension SupportedExtensions[]
static int singleLetterExtensionRank(char Ext)
static const char * ImpliedExtsZvfh[]
static const char * ImpliedExtsZvl65536b[]
static const char * ImpliedExtsZve64f[]
static const char * ImpliedExtsZvl1024b[]
static const char * ImpliedExtsZhinx[]
static constexpr CombinedExtsEntry CombineIntoExts[]
static const char * ImpliedExtsZve64x[]
static const char * ImpliedExtsZk[]
static const RISCVSupportedExtension SupportedExperimentalExtensions[]
static int multiLetterExtensionRank(const std::string &ExtName)
static const char * ImpliedExtsZvl256b[]
static StringRef getExtensionType(StringRef Ext)
static const char * ImpliedExtsZfhmin[]
static std::optional< RISCVExtensionVersion > isExperimentalExtension(StringRef Ext)
static const char * ImpliedExtsZkn[]
static bool stripExperimentalPrefix(StringRef &Ext)
static std::optional< RISCVExtensionVersion > findDefaultVersion(StringRef ExtName)
static const char * ImpliedExtsZvl64b[]
static const char * ImpliedExtsZvl16384b[]
static const char * ImpliedExtsZvl128b[]
static constexpr StringLiteral AllStdExts
static const char * ImpliedExtsZfh[]
static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, unsigned &Minor, unsigned &ConsumeLength, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static const char * ImpliedExtsZvl32768b[]
static const char * ImpliedExtsZdinx[]
static size_t findFirstNonVersionCharacter(StringRef Ext)
static const char * ImpliedExtsZhinxmin[]
static const char * ImpliedExtsV[]
static const char * ImpliedExtsZve64d[]
static bool isDigit(const char C)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
This file implements a set that has insertion order iteration characteristics.
This file contains some functions that are useful when dealing with strings.
Value * RHS
Value * LHS
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
Tagged union holding either a T or a Error.
Definition: Error.h:470
static bool isSupportedExtensionFeature(StringRef Ext)
bool hasExtension(StringRef Ext) const
static bool compareExtension(const std::string &LHS, const std::string &RHS)
std::string toString() const
static llvm::Expected< std::unique_ptr< RISCVISAInfo > > postProcessAndChecking(std::unique_ptr< RISCVISAInfo > &&ISAInfo)
std::vector< std::string > toFeatureVector() const
StringRef computeDefaultABI() const
static bool isSupportedExtension(StringRef Ext)
static llvm::Expected< std::unique_ptr< RISCVISAInfo > > parseFeatures(unsigned XLen, const std::vector< std::string > &Features)
Parse RISCV ISA info from feature vector.
void toFeatures(std::vector< StringRef > &Features, llvm::function_ref< StringRef(const Twine &)> StrAlloc, bool AddAllExtensions) const
Convert RISCV ISA info to a feature vector.
static llvm::Expected< std::unique_ptr< RISCVISAInfo > > parseArchString(StringRef Arch, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck=true, bool IgnoreUnknown=false)
Parse RISCV ISA info from arch string.
size_type count(const key_type &key) const
Count the number of elements of a given key in the SetVector.
Definition: SetVector.h:208
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition: SetVector.h:141
bool empty() const
Determine if the SetVector is empty or not.
Definition: SetVector.h:72
A SetVector that performs no allocations if smaller than a certain size.
Definition: SetVector.h:301
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition: StringRef.h:841
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:688
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
Definition: StringRef.h:643
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:469
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:222
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:559
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition: StringRef.h:597
iterator begin() const
Definition: StringRef.h:111
char back() const
back - Get the last character in the string.
Definition: StringRef.h:146
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
Definition: StringRef.h:423
bool startswith(StringRef Prefix) const
Definition: StringRef.h:261
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition: StringRef.h:623
size_t find_first_of(char C, size_t From=0) const
Find the first character in the string that is C, or npos if not found.
Definition: StringRef.h:376
iterator end() const
Definition: StringRef.h:113
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:295
static constexpr size_t npos
Definition: StringRef.h:52
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
Definition: StringRef.h:604
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
An efficient, type-erasing, non-owning reference to a callable.
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:642
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:660
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
const uint64_t Version
Definition: InstrProf.h:1058
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1246
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1742
bool is_sorted(R &&Range, Compare C)
Wrapper function around std::is_sorted to check if elements in a range R are sorted with respect to a...
Definition: STLExtras.h:1884
auto lower_bound(R &&Range, T &&Value)
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:1923
@ Add
Sum of integers.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1762
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.
Definition: STLExtras.h:1869
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1043
StringLiteral CombineExt
ArrayRef< const char * > RequiredExts
StringLiteral Name
ArrayRef< const char * > Exts
bool operator<(const ImpliedExtsEntry &Other) const
bool operator<(StringRef Other) const