LLVM 19.0.0git
RISCVISAInfo.cpp
Go to the documentation of this file.
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
10#include "llvm/ADT/MapVector.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/SetVector.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/Errc.h"
16#include "llvm/Support/Error.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.
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 {"a", {2, 1}},
50 {"c", {2, 0}},
51 {"d", {2, 2}},
52 {"e", {2, 0}},
53 {"f", {2, 2}},
54 {"h", {1, 0}},
55 {"i", {2, 1}},
56 {"m", {2, 0}},
57
58 {"shcounterenw", {1, 0}},
59 {"shgatpa", {1, 0}},
60 {"shtvala", {1, 0}},
61 {"shvsatpa", {1, 0}},
62 {"shvstvala", {1, 0}},
63 {"shvstvecd", {1, 0}},
64 {"smaia", {1, 0}},
65 {"smepmp", {1, 0}},
66 {"ssaia", {1, 0}},
67 {"ssccptr", {1, 0}},
68 {"sscounterenw", {1, 0}},
69 {"ssstateen", {1, 0}},
70 {"ssstrict", {1, 0}},
71 {"sstc", {1, 0}},
72 {"sstvala", {1, 0}},
73 {"sstvecd", {1, 0}},
74 {"ssu64xl", {1, 0}},
75 {"svade", {1, 0}},
76 {"svadu", {1, 0}},
77 {"svbare", {1, 0}},
78 {"svinval", {1, 0}},
79 {"svnapot", {1, 0}},
80 {"svpbmt", {1, 0}},
81
82 {"v", {1, 0}},
83
84 // vendor-defined ('X') extensions
85 {"xcvalu", {1, 0}},
86 {"xcvbi", {1, 0}},
87 {"xcvbitmanip", {1, 0}},
88 {"xcvelw", {1, 0}},
89 {"xcvmac", {1, 0}},
90 {"xcvmem", {1, 0}},
91 {"xcvsimd", {1, 0}},
92 {"xsfvcp", {1, 0}},
93 {"xsfvfnrclipxfqf", {1, 0}},
94 {"xsfvfwmaccqqq", {1, 0}},
95 {"xsfvqmaccdod", {1, 0}},
96 {"xsfvqmaccqoq", {1, 0}},
97 {"xtheadba", {1, 0}},
98 {"xtheadbb", {1, 0}},
99 {"xtheadbs", {1, 0}},
100 {"xtheadcmo", {1, 0}},
101 {"xtheadcondmov", {1, 0}},
102 {"xtheadfmemidx", {1, 0}},
103 {"xtheadmac", {1, 0}},
104 {"xtheadmemidx", {1, 0}},
105 {"xtheadmempair", {1, 0}},
106 {"xtheadsync", {1, 0}},
107 {"xtheadvdot", {1, 0}},
108 {"xventanacondops", {1, 0}},
109
110 {"za128rs", {1, 0}},
111 {"za64rs", {1, 0}},
112 {"zawrs", {1, 0}},
113
114 {"zba", {1, 0}},
115 {"zbb", {1, 0}},
116 {"zbc", {1, 0}},
117 {"zbkb", {1, 0}},
118 {"zbkc", {1, 0}},
119 {"zbkx", {1, 0}},
120 {"zbs", {1, 0}},
121
122 {"zca", {1, 0}},
123 {"zcb", {1, 0}},
124 {"zcd", {1, 0}},
125 {"zce", {1, 0}},
126 {"zcf", {1, 0}},
127 {"zcmp", {1, 0}},
128 {"zcmt", {1, 0}},
129
130 {"zdinx", {1, 0}},
131
132 {"zfa", {1, 0}},
133 {"zfh", {1, 0}},
134 {"zfhmin", {1, 0}},
135 {"zfinx", {1, 0}},
136
137 {"zhinx", {1, 0}},
138 {"zhinxmin", {1, 0}},
139
140 {"zic64b", {1, 0}},
141 {"zicbom", {1, 0}},
142 {"zicbop", {1, 0}},
143 {"zicboz", {1, 0}},
144 {"ziccamoa", {1, 0}},
145 {"ziccif", {1, 0}},
146 {"zicclsm", {1, 0}},
147 {"ziccrse", {1, 0}},
148 {"zicntr", {2, 0}},
149 {"zicond", {1, 0}},
150 {"zicsr", {2, 0}},
151 {"zifencei", {2, 0}},
152 {"zihintntl", {1, 0}},
153 {"zihintpause", {2, 0}},
154 {"zihpm", {2, 0}},
155
156 {"zk", {1, 0}},
157 {"zkn", {1, 0}},
158 {"zknd", {1, 0}},
159 {"zkne", {1, 0}},
160 {"zknh", {1, 0}},
161 {"zkr", {1, 0}},
162 {"zks", {1, 0}},
163 {"zksed", {1, 0}},
164 {"zksh", {1, 0}},
165 {"zkt", {1, 0}},
166
167 {"zmmul", {1, 0}},
168
169 {"zvbb", {1, 0}},
170 {"zvbc", {1, 0}},
171
172 {"zve32f", {1, 0}},
173 {"zve32x", {1, 0}},
174 {"zve64d", {1, 0}},
175 {"zve64f", {1, 0}},
176 {"zve64x", {1, 0}},
177
178 {"zvfh", {1, 0}},
179 {"zvfhmin", {1, 0}},
180
181 // vector crypto
182 {"zvkb", {1, 0}},
183 {"zvkg", {1, 0}},
184 {"zvkn", {1, 0}},
185 {"zvknc", {1, 0}},
186 {"zvkned", {1, 0}},
187 {"zvkng", {1, 0}},
188 {"zvknha", {1, 0}},
189 {"zvknhb", {1, 0}},
190 {"zvks", {1, 0}},
191 {"zvksc", {1, 0}},
192 {"zvksed", {1, 0}},
193 {"zvksg", {1, 0}},
194 {"zvksh", {1, 0}},
195 {"zvkt", {1, 0}},
196
197 {"zvl1024b", {1, 0}},
198 {"zvl128b", {1, 0}},
199 {"zvl16384b", {1, 0}},
200 {"zvl2048b", {1, 0}},
201 {"zvl256b", {1, 0}},
202 {"zvl32768b", {1, 0}},
203 {"zvl32b", {1, 0}},
204 {"zvl4096b", {1, 0}},
205 {"zvl512b", {1, 0}},
206 {"zvl64b", {1, 0}},
207 {"zvl65536b", {1, 0}},
208 {"zvl8192b", {1, 0}},
209};
210
211// NOTE: This table should be sorted alphabetically by extension name.
212// clang-format off
213static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
214 {"smmpm", {0, 8}},
215 {"smnpm", {0, 8}},
216 {"ssnpm", {0, 8}},
217 {"sspm", {0, 8}},
218 {"ssqosid", {1, 0}},
219 {"supm", {0, 8}},
220
221 {"zaamo", {0, 2}},
222 {"zabha", {1, 0}},
223 {"zacas", {1, 0}},
224 {"zalasr", {0, 1}},
225 {"zalrsc", {0, 2}},
226
227 {"zcmop", {0, 2}},
228
229 {"zfbfmin", {1, 0}},
230
231 {"zicfilp", {0, 4}},
232 {"zicfiss", {0, 4}},
233
234 {"zimop", {0, 1}},
235
236 {"ztso", {0, 1}},
237
238 {"zvfbfmin", {1, 0}},
239 {"zvfbfwma", {1, 0}},
240};
241// clang-format on
242
243static void verifyTables() {
244#ifndef NDEBUG
245 static std::atomic<bool> TableChecked(false);
246 if (!TableChecked.load(std::memory_order_relaxed)) {
248 "Extensions are not sorted by name");
250 "Experimental extensions are not sorted by name");
251 TableChecked.store(true, std::memory_order_relaxed);
252 }
253#endif
254}
255
257 StringRef Description) {
258 outs().indent(4);
259 unsigned VersionWidth = Description.empty() ? 0 : 10;
260 outs() << left_justify(Name, 20) << left_justify(Version, VersionWidth)
261 << Description << "\n";
262}
263
265
266 outs() << "All available -march extensions for RISC-V\n\n";
267 PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description"));
268
270 for (const auto &E : SupportedExtensions)
271 ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
272 for (const auto &E : ExtMap) {
273 std::string Version =
274 std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
275 PrintExtension(E.first, Version, DescMap[E.first]);
276 }
277
278 outs() << "\nExperimental extensions\n";
279 ExtMap.clear();
280 for (const auto &E : SupportedExperimentalExtensions)
281 ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
282 for (const auto &E : ExtMap) {
283 std::string Version =
284 std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
285 PrintExtension(E.first, Version, 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
293 return Ext.consume_front("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.
304 assert(!Ext.empty() &&
305 "Already guarded by if-statement in ::parseArchString");
306
307 int Pos = Ext.size() - 1;
308 while (Pos > 0 && isDigit(Ext[Pos]))
309 Pos--;
310 if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {
311 Pos--;
312 while (Pos > 0 && isDigit(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>
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),
335 auto I = llvm::lower_bound(ExtInfo, ExtName, 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,
347 Exts[ExtName.str()] = Version;
348}
349
351 if (Ext.starts_with("s"))
352 return "standard supervisor-level extension";
353 if (Ext.starts_with("x"))
354 return "non-standard user-level extension";
355 if (Ext.starts_with("z"))
356 return "standard user-level extension";
357 return StringRef();
358}
359
361 if (Ext.starts_with("s"))
362 return "s";
363 if (Ext.starts_with("x"))
364 return "x";
365 if (Ext.starts_with("z"))
366 return "z";
367 return StringRef();
368}
369
370static std::optional<RISCVISAInfo::ExtensionVersion>
372 auto I =
374 if (I == std::end(SupportedExperimentalExtensions) || I->Name != Ext)
375 return std::nullopt;
376
377 return I->Version;
378}
379
381 bool IsExperimental = stripExperimentalPrefix(Ext);
382
386
387 auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
388 return I != ExtInfo.end() && I->Name == Ext;
389}
390
392 verifyTables();
393
394 for (auto ExtInfo : {ArrayRef(SupportedExtensions),
396 auto I = llvm::lower_bound(ExtInfo, Ext, 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),
408 auto Range =
409 std::equal_range(ExtInfo.begin(), ExtInfo.end(), Ext, 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
420
421 if (!isSupportedExtension(Ext))
422 return false;
423
424 return Exts.count(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'.
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(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(ExtName[1]);
476 case 'x':
477 return RF_X_EXTENSION;
478 default:
479 assert(ExtName.size() == 1);
480 return singleLetterExtensionRank(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(LHS);
489 unsigned RHSRank = getExtensionRank(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(ExtName))
509 continue;
510
511 if (isExperimentalExtension(ExtName)) {
512 Features.push_back((llvm::Twine("+experimental-") + ExtName).str());
513 } else {
514 Features.push_back((llvm::Twine("+") + ExtName).str());
515 }
516 }
517 if (AddAllExtensions) {
518 for (const RISCVSupportedExtension &Ext : SupportedExtensions) {
519 if (Exts.count(Ext.Name))
520 continue;
521 Features.push_back((llvm::Twine("-") + Ext.Name).str());
522 }
523
524 for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {
525 if (Exts.count(Ext.Name))
526 continue;
527 Features.push_back((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(isDigit);
547 In = In.substr(MajorStr.size());
548
549 if (!MajorStr.empty() && In.consume_front("p")) {
550 MinorStr = In.take_while(isDigit);
551 In = In.substr(MajorStr.size() + MinorStr.size() - 1);
552
553 // Expected 'p' to be followed by minor version number.
554 if (MinorStr.empty()) {
555 return createStringError(
557 "minor version number missing after 'p' for extension '" + Ext + "'");
558 }
559 }
560
561 if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
562 return createStringError(
564 "Failed to parse major version number for extension '" + Ext + "'");
565
566 if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
567 return createStringError(
569 "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(
582 "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)
588 "requires '-menable-experimental-extensions' "
589 "for experimental extension '" +
590 Ext + "'");
591
592 if (ExperimentalExtensionVersionCheck &&
593 (MajorStr.empty() && MinorStr.empty()))
594 return createStringError(
596 "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(SupportedVers.Major) +
607 "." + utostr(SupportedVers.Minor) + ")";
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(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, Major, 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() + "'";
636}
637
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(1); // Drop '+' or '-'
650 Experimental = stripExperimentalPrefix(ExtName);
651 auto ExtensionInfos = Experimental
654 auto ExtensionInfoIterator =
655 llvm::lower_bound(ExtensionInfos, ExtName, 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, ExtensionInfoIterator->Version);
665 else
666 ISAInfo->Exts.erase(ExtName.str());
667 }
668
669 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
670}
671
674 if (llvm::any_of(Arch, isupper)) {
676 "string must be lowercase");
677 }
678 // Must start with a valid base ISA name.
679 unsigned XLen;
680 if (Arch.starts_with("rv32i") || Arch.starts_with("rv32e"))
681 XLen = 32;
682 else if (Arch.starts_with("rv64i") || Arch.starts_with("rv64e"))
683 XLen = 64;
684 else
686 "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(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.
695 Arch.split(Split, '_');
696 for (StringRef Ext : Split) {
697 StringRef Prefix, MinorVersionStr;
698 std::tie(Prefix, MinorVersionStr) = Ext.rsplit('p');
699 if (MinorVersionStr.empty())
701 "extension lacks version in expected format");
702 unsigned MajorVersion, MinorVersion;
703 if (MinorVersionStr.getAsInteger(10, MinorVersion))
705 "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(ExtName.back()))
713 break;
714 ExtName = ExtName.drop_back(1);
715 TrailingDigits++;
716 }
717 if (!TrailingDigits)
719 "extension lacks version in expected format");
720
721 StringRef MajorVersionStr = Prefix.take_back(TrailingDigits);
722 if (MajorVersionStr.getAsInteger(10, MajorVersion))
724 "failed to parse major version number");
725 ISAInfo->addExtension(ExtName, {MajorVersion, MinorVersion});
726 }
727 ISAInfo->updateFLen();
728 ISAInfo->updateMinVLen();
729 ISAInfo->updateMaxELen();
730 return std::move(ISAInfo);
731}
732
734 std::vector<std::string> &SplitExts) {
736 if (Exts.empty())
737 return Error::success();
738
739 Exts.split(Split, "_");
740
741 for (auto Ext : Split) {
742 if (Ext.empty())
744 "extension name missing after separator '_'");
745
746 SplitExts.push_back(Ext.str());
747 }
748 return Error::success();
749}
750
752 StringRef RawExt,
754 std::map<std::string, unsigned>> &SeenExtMap,
755 bool IgnoreUnknown, bool EnableExperimentalExtension,
756 bool ExperimentalExtensionVersionCheck) {
759 auto Pos = findLastNonVersionCharacter(RawExt) + 1;
760 StringRef Name(RawExt.substr(0, Pos));
761 StringRef Vers(RawExt.substr(Pos));
762
763 if (Type.empty()) {
764 if (IgnoreUnknown)
765 return Error::success();
767 "invalid extension prefix '" + RawExt + "'");
768 }
769
770 if (!IgnoreUnknown && Name.size() == Type.size())
772 Desc + " name missing after '" + Type + "'");
773
774 unsigned Major, Minor, ConsumeLength;
775 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
776 EnableExperimentalExtension,
777 ExperimentalExtensionVersionCheck)) {
778 if (IgnoreUnknown) {
779 consumeError(std::move(E));
780 return Error::success();
781 }
782 return E;
783 }
784
785 // Check if duplicated extension.
786 if (!IgnoreUnknown && SeenExtMap.contains(Name.str()))
788 "duplicated " + Desc + " '" + Name + "'");
789
790 if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Name))
791 return Error::success();
792
793 SeenExtMap[Name.str()] = {Major, Minor};
794 return Error::success();
795}
796
798 StringRef &RawExt,
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(1);
805 RawExt.consume_front(Name);
806 if (auto E = getExtensionVersion(Name, RawExt, Major, Minor, ConsumeLength,
807 EnableExperimentalExtension,
808 ExperimentalExtensionVersionCheck)) {
809 if (IgnoreUnknown) {
810 consumeError(std::move(E));
811 RawExt = RawExt.substr(ConsumeLength);
812 return Error::success();
813 }
814 return E;
815 }
816
817 RawExt = RawExt.substr(ConsumeLength);
818
819 // Check if duplicated extension.
820 if (!IgnoreUnknown && SeenExtMap.contains(Name.str()))
822 "duplicated standard user-level extension '" +
823 Name + "'");
824
825 if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Name))
826 return Error::success();
827
828 SeenExtMap[Name.str()] = {Major, Minor};
829 return Error::success();
830}
831
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(Arch, isupper)) {
839 "string must be lowercase");
840 }
841
842 bool HasRV64 = Arch.starts_with("rv64");
843 // ISA string must begin with rv32 or rv64.
844 if (!(Arch.starts_with("rv32") || HasRV64) || (Arch.size() < 5)) {
845 return createStringError(
847 "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));
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:
865 "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(Arch[5]))
873 "version not supported for 'g'");
874 StdExts = StdExts.drop_front(4);
875 break;
876 }
877
878 if (Arch.back() == '_')
880 "extension name missing after separator '_'");
881
882 // Skip rvxxx
883 StringRef Exts = Arch.substr(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(Ext)) {
895 // Postpone AddExtension until end of this function
896 SeenExtMap[Ext] = {Version->Major, 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 StringRef(&Baseline, 1), 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(std::move(E));
910 auto Version = findDefaultVersion(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, Minor};
917 }
918
919 // Consume the base ISA version number and any '_' between rvxxx and the
920 // first extension
921 Exts = Exts.drop_front(ConsumeLength);
922 Exts.consume_front("_");
923
924 std::vector<std::string> SplittedExts;
925 if (auto E = splitExtsByUnderscore(Exts, SplittedExts))
926 return std::move(E);
927
928 for (auto &Ext : SplittedExts) {
929 StringRef CurrExt = Ext;
930 while (!CurrExt.empty()) {
931 if (AllStdExts.contains(CurrExt.front())) {
933 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.
947 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?
956 "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
968 if (ExtName.size() == 1) {
970 "unsupported standard user-level extension '" +
971 ExtName + "'");
972 }
974 "unsupported " + getExtensionTypeDesc(ExtName) +
975 " '" + ExtName + "'");
976 }
977 ISAInfo->addExtension(ExtName, ExtVers);
978 }
979
980 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
981}
982
983Error RISCVISAInfo::checkDependency() {
984 bool HasC = Exts.count("c") != 0;
985 bool HasF = Exts.count("f") != 0;
986 bool HasZfinx = Exts.count("zfinx") != 0;
987 bool HasVector = Exts.count("zve32x") != 0;
988 bool HasZvl = MinVLen != 0;
989 bool HasZcmt = Exts.count("zcmt") != 0;
990
991 if (HasF && HasZfinx)
993 "'f' and 'zfinx' extensions are incompatible");
994
995 if (HasZvl && !HasVector)
996 return createStringError(
998 "'zvl*b' requires 'v' or 'zve*' extension to also be specified");
999
1000 if (Exts.count("zvbb") && !HasVector)
1001 return createStringError(
1003 "'zvbb' requires 'v' or 'zve*' extension to also be specified");
1004
1005 if (Exts.count("zvbc") && !Exts.count("zve64x"))
1006 return createStringError(
1008 "'zvbc' requires 'v' or 'zve64*' extension to also be specified");
1009
1010 if ((Exts.count("zvkb") || Exts.count("zvkg") || Exts.count("zvkned") ||
1011 Exts.count("zvknha") || Exts.count("zvksed") || Exts.count("zvksh")) &&
1012 !HasVector)
1013 return createStringError(
1015 "'zvk*' requires 'v' or 'zve*' extension to also be specified");
1016
1017 if (Exts.count("zvknhb") && !Exts.count("zve64x"))
1018 return createStringError(
1020 "'zvknhb' requires 'v' or 'zve64*' extension to also be specified");
1021
1022 if ((HasZcmt || Exts.count("zcmp")) && Exts.count("d") &&
1023 (HasC || Exts.count("zcd")))
1024 return createStringError(
1026 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("zcf"))
1032 "'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
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 {{"d"}, {ImpliedExtsD}},
1113 {{"f"}, {ImpliedExtsF}},
1114 {{"v"}, {ImpliedExtsV}},
1115 {{"xsfvcp"}, {ImpliedExtsXSfvcp}},
1116 {{"xsfvfnrclipxfqf"}, {ImpliedExtsXSfvfnrclipxfqf}},
1117 {{"xsfvfwmaccqqq"}, {ImpliedExtsXSfvfwmaccqqq}},
1118 {{"xsfvqmaccdod"}, {ImpliedExtsXSfvqmaccdod}},
1119 {{"xsfvqmaccqoq"}, {ImpliedExtsXSfvqmaccqoq}},
1120 {{"xtheadvdot"}, {ImpliedExtsXTHeadVdot}},
1121 {{"zabha"}, {ImpliedExtsZabha}},
1122 {{"zacas"}, {ImpliedExtsZacas}},
1123 {{"zcb"}, {ImpliedExtsZcb}},
1124 {{"zcd"}, {ImpliedExtsZcd}},
1125 {{"zce"}, {ImpliedExtsZce}},
1126 {{"zcf"}, {ImpliedExtsZcf}},
1127 {{"zcmop"}, {ImpliedExtsZcmop}},
1128 {{"zcmp"}, {ImpliedExtsZcmp}},
1129 {{"zcmt"}, {ImpliedExtsZcmt}},
1130 {{"zdinx"}, {ImpliedExtsZdinx}},
1131 {{"zfa"}, {ImpliedExtsZfa}},
1132 {{"zfbfmin"}, {ImpliedExtsZfbfmin}},
1133 {{"zfh"}, {ImpliedExtsZfh}},
1134 {{"zfhmin"}, {ImpliedExtsZfhmin}},
1135 {{"zfinx"}, {ImpliedExtsZfinx}},
1136 {{"zhinx"}, {ImpliedExtsZhinx}},
1137 {{"zhinxmin"}, {ImpliedExtsZhinxmin}},
1138 {{"zicfiss"}, {ImpliedExtsZicfiss}},
1139 {{"zicntr"}, {ImpliedExtsZicntr}},
1140 {{"zihpm"}, {ImpliedExtsZihpm}},
1141 {{"zk"}, {ImpliedExtsZk}},
1142 {{"zkn"}, {ImpliedExtsZkn}},
1143 {{"zks"}, {ImpliedExtsZks}},
1144 {{"zvbb"}, {ImpliedExtsZvbb}},
1145 {{"zve32f"}, {ImpliedExtsZve32f}},
1146 {{"zve32x"}, {ImpliedExtsZve32x}},
1147 {{"zve64d"}, {ImpliedExtsZve64d}},
1148 {{"zve64f"}, {ImpliedExtsZve64f}},
1149 {{"zve64x"}, {ImpliedExtsZve64x}},
1150 {{"zvfbfmin"}, {ImpliedExtsZvfbfmin}},
1151 {{"zvfbfwma"}, {ImpliedExtsZvfbfwma}},
1152 {{"zvfh"}, {ImpliedExtsZvfh}},
1153 {{"zvfhmin"}, {ImpliedExtsZvfhmin}},
1154 {{"zvkn"}, {ImpliedExtsZvkn}},
1155 {{"zvknc"}, {ImpliedExtsZvknc}},
1156 {{"zvkng"}, {ImpliedExtsZvkng}},
1157 {{"zvknhb"}, {ImpliedExtsZvknhb}},
1158 {{"zvks"}, {ImpliedExtsZvks}},
1159 {{"zvksc"}, {ImpliedExtsZvksc}},
1160 {{"zvksg"}, {ImpliedExtsZvksg}},
1161 {{"zvl1024b"}, {ImpliedExtsZvl1024b}},
1162 {{"zvl128b"}, {ImpliedExtsZvl128b}},
1163 {{"zvl16384b"}, {ImpliedExtsZvl16384b}},
1164 {{"zvl2048b"}, {ImpliedExtsZvl2048b}},
1165 {{"zvl256b"}, {ImpliedExtsZvl256b}},
1166 {{"zvl32768b"}, {ImpliedExtsZvl32768b}},
1167 {{"zvl4096b"}, {ImpliedExtsZvl4096b}},
1168 {{"zvl512b"}, {ImpliedExtsZvl512b}},
1169 {{"zvl64b"}, {ImpliedExtsZvl64b}},
1170 {{"zvl65536b"}, {ImpliedExtsZvl65536b}},
1171 {{"zvl8192b"}, {ImpliedExtsZvl8192b}},
1172};
1173
1174void RISCVISAInfo::updateImplication() {
1175 bool HasE = Exts.count("e") != 0;
1176 bool HasI = Exts.count("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("i");
1182 addExtension("i", 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
1190 for (auto const &Ext : Exts)
1191 WorkList.insert(Ext.first);
1192
1193 while (!WorkList.empty()) {
1194 StringRef ExtName = WorkList.pop_back_val();
1195 auto I = llvm::lower_bound(ImpliedExts, ExtName);
1196 if (I != std::end(ImpliedExts) && I->Name == ExtName) {
1197 for (const char *ImpliedExt : I->Exts) {
1198 if (WorkList.count(ImpliedExt))
1199 continue;
1200 if (Exts.count(ImpliedExt))
1201 continue;
1202 auto Version = findDefaultVersion(ImpliedExt);
1203 addExtension(ImpliedExt, Version.value());
1204 WorkList.insert(ImpliedExt);
1205 }
1206 }
1207 }
1208
1209 // Add Zcf if Zce and F are enabled on RV32.
1210 if (XLen == 32 && Exts.count("zce") && Exts.count("f") &&
1211 !Exts.count("zcf")) {
1212 auto Version = findDefaultVersion("zcf");
1213 addExtension("zcf", Version.value());
1214 }
1215}
1216
1220};
1221
1223 {{"zk"}, {ImpliedExtsZk}},
1224 {{"zkn"}, {ImpliedExtsZkn}},
1225 {{"zks"}, {ImpliedExtsZks}},
1226 {{"zvkn"}, {ImpliedExtsZvkn}},
1227 {{"zvknc"}, {ImpliedExtsZvknc}},
1228 {{"zvkng"}, {ImpliedExtsZvkng}},
1229 {{"zvks"}, {ImpliedExtsZvks}},
1230 {{"zvksc"}, {ImpliedExtsZvksc}},
1231 {{"zvksg"}, {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(CombineExt))
1242 continue;
1243 bool IsAllRequiredFeatureExist = true;
1244 for (const char *Ext : RequiredExts)
1245 IsAllRequiredFeatureExist &= hasExtension(Ext);
1246 if (IsAllRequiredFeatureExist) {
1247 auto Version = findDefaultVersion(CombineExt);
1248 addExtension(CombineExt, 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("d"))
1259 FLen = 64;
1260 else if (Exts.count("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("zvl") && ExtName.consume_back("b");
1268 if (IsZvlExt) {
1269 unsigned ZvlLen;
1270 if (!ExtName.getAsInteger(10, ZvlLen))
1271 MinVLen = std::max(MinVLen, 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("zve");
1281 if (IsZveExt) {
1282 if (ExtName.back() == 'f')
1283 MaxELenFp = std::max(MaxELenFp, 32u);
1284 if (ExtName.back() == 'd')
1285 MaxELenFp = std::max(MaxELenFp, 64u);
1286 ExtName = ExtName.drop_back();
1287 unsigned ZveELen;
1288 ExtName.getAsInteger(10, ZveELen);
1289 MaxELen = std::max(MaxELen, 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
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
1325 if (XLen == 32) {
1326 if (hasExtension("e"))
1327 return "ilp32e";
1328 if (hasExtension("d"))
1329 return "ilp32d";
1330 if (hasExtension("f"))
1331 return "ilp32f";
1332 return "ilp32";
1333 } else if (XLen == 64) {
1334 if (hasExtension("e"))
1335 return "lp64e";
1336 if (hasExtension("d"))
1337 return "lp64d";
1338 if (hasExtension("f"))
1339 return "lp64f";
1340 return "lp64";
1341 }
1342 llvm_unreachable("Invalid XLEN");
1343}
1344
1346 if (Ext.empty())
1347 return false;
1348
1349 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1350 StringRef Name = Ext.substr(0, Pos);
1351 StringRef Vers = Ext.substr(Pos);
1352 if (Vers.empty())
1353 return false;
1354
1355 unsigned Major, Minor, ConsumeLength;
1356 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
1357 true, true)) {
1358 consumeError(std::move(E));
1359 return false;
1360 }
1361
1362 return true;
1363}
1364
1366 if (Ext.empty())
1367 return std::string();
1368
1369 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1370 StringRef Name = Ext.substr(0, Pos);
1371
1372 if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext))
1373 return std::string();
1374
1376 return std::string();
1377
1378 return isExperimentalExtension(Name) ? "experimental-" + Name.str()
1379 : Name.str();
1380}
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::string Name
std::optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1290
#define _
#define I(x, y, z)
Definition: MD5.cpp:58
This file implements a map that provides insertion order iteration.
static void verifyTables()
static const char * ImpliedExtsZcd[]
static const char * ImpliedExtsZvl8192b[]
static const char * ImpliedExtsZks[]
static const char * ImpliedExtsZcb[]
static const char * ImpliedExtsZvksg[]
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 const char * ImpliedExtsXSfvqmaccqoq[]
static const char * ImpliedExtsZvfh[]
static const char * ImpliedExtsZvl65536b[]
static const char * ImpliedExtsZvkn[]
static const char * ImpliedExtsZve64f[]
static const char * ImpliedExtsXSfvfnrclipxfqf[]
static size_t findLastNonVersionCharacter(StringRef Ext)
static const char * ImpliedExtsZicntr[]
static Error processMultiLetterExtension(StringRef RawExt, MapVector< std::string, RISCVISAInfo::ExtensionVersion, std::map< std::string, unsigned > > &SeenExtMap, bool IgnoreUnknown, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static const char * ImpliedExtsZvl1024b[]
static const char * ImpliedExtsZhinx[]
static constexpr CombinedExtsEntry CombineIntoExts[]
static std::optional< RISCVISAInfo::ExtensionVersion > findDefaultVersion(StringRef ExtName)
static const char * ImpliedExtsZcmt[]
static const char * ImpliedExtsZvkng[]
static const char * ImpliedExtsZvks[]
static const char * ImpliedExtsZve64x[]
static const char * ImpliedExtsZk[]
static const char * ImpliedExtsXSfvfwmaccqqq[]
static const char * ImpliedExtsZce[]
static const RISCVSupportedExtension SupportedExperimentalExtensions[]
static const char * ImpliedExtsXSfvcp[]
static const char * ImpliedExtsZvfbfwma[]
static const char * ImpliedExtsZvl256b[]
static StringRef getExtensionType(StringRef Ext)
static const char * ImpliedExtsZfhmin[]
static const char * ImpliedExtsZcf[]
static const char * ImpliedExtsZvknc[]
static const char * ImpliedExtsZacas[]
static const char * ImpliedExtsZicfiss[]
static const char * ImpliedExtsZcmp[]
static const char * ImpliedExtsD[]
static const char * ImpliedExtsZkn[]
static const char * ImpliedExtsXSfvqmaccdod[]
static bool stripExperimentalPrefix(StringRef &Ext)
static std::optional< RISCVISAInfo::ExtensionVersion > isExperimentalExtension(StringRef Ext)
static const char * ImpliedExtsZvl64b[]
static void PrintExtension(StringRef Name, StringRef Version, StringRef Description)
static const char * ImpliedExtsZihpm[]
static const char * ImpliedExtsZvl16384b[]
static const char * ImpliedExtsZvl128b[]
static const char * ImpliedExtsZvfbfmin[]
static constexpr StringLiteral AllStdExts
static const char * ImpliedExtsZfbfmin[]
static const char * ImpliedExtsF[]
static const char * ImpliedExtsZfh[]
static const char * ImpliedExtsZabha[]
static const char * ImpliedExtsZvknhb[]
static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, unsigned &Minor, unsigned &ConsumeLength, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static const char * ImpliedExtsZvl32768b[]
static const char * ImpliedExtsZfinx[]
static const char * ImpliedExtsZfa[]
static const char * ImpliedExtsZvksc[]
static const char * ImpliedExtsZcmop[]
RankFlags
@ RF_S_EXTENSION
@ RF_Z_EXTENSION
@ RF_X_EXTENSION
static Error processSingleLetterExtension(StringRef &RawExt, MapVector< std::string, RISCVISAInfo::ExtensionVersion, std::map< std::string, unsigned > > &SeenExtMap, bool IgnoreUnknown, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static const char * ImpliedExtsZvbb[]
static unsigned getExtensionRank(const std::string &ExtName)
static const char * ImpliedExtsZdinx[]
static unsigned singleLetterExtensionRank(char Ext)
static const char * ImpliedExtsZhinxmin[]
static const char * RISCVGImplications[]
static const char * ImpliedExtsV[]
static const char * ImpliedExtsZve64d[]
static Error splitExtsByUnderscore(StringRef Exts, std::vector< std::string > &SplitExts)
static const char * ImpliedExtsZvfhmin[]
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
iterator end() const
Definition: ArrayRef.h:154
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
Tagged union holding either a T or a Error.
Definition: Error.h:474
This class implements a map that also provides access to all stored values in a deterministic order.
Definition: MapVector.h:36
std::map< std::string, ExtensionVersion, ExtensionComparator > OrderedExtensionMap
OrderedExtensionMap is std::map, it's specialized to keep entries in canonical order of extension.
Definition: RISCVISAInfo.h:46
static bool isSupportedExtensionFeature(StringRef Ext)
static std::string getTargetFeatureForExtension(StringRef Ext)
static llvm::Expected< std::unique_ptr< RISCVISAInfo > > parseNormalizedArchString(StringRef Arch)
Parse RISC-V ISA info from an arch string that is already in normalized form (as defined in the psABI...
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)
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 RISC-V ISA info from feature vector.
std::vector< std::string > toFeatures(bool AddAllExtensions=false, bool IgnoreUnknown=true) const
Convert RISC-V 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 RISC-V ISA info from arch string.
static bool isSupportedExtensionWithVersion(StringRef Ext)
size_type count(const key_type &key) const
Count the number of elements of a given key in the SetVector.
Definition: SetVector.h:264
bool empty() const
Determine if the SetVector is empty or not.
Definition: SetVector.h:93
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition: SetVector.h:162
value_type pop_back_val()
Definition: SetVector.h:285
A SetVector that performs no allocations if smaller than a certain size.
Definition: SetVector.h:370
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition: StringRef.h:849
bool empty() const
Definition: StringMap.h:103
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:128
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:696
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
Definition: StringRef.h:651
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:466
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:567
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:257
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:605
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
char front() const
front - Get the first character in the string.
Definition: StringRef.h:140
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
Definition: StringRef.h:420
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition: StringRef.h:631
StringRef take_front(size_t N=1) const
Return a StringRef equal to 'this' but with only the first N elements remaining.
Definition: StringRef.h:576
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:293
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:612
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
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:660
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:678
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const uint64_t Version
Definition: InstrProf.h:1042
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool operator<(int64_t V1, const APSInt &V2)
Definition: APSInt.h:361
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1244
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:1738
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:1911
void riscvExtensionsHelp(StringMap< StringRef > DescMap)
FormattedString left_justify(StringRef Str, unsigned Width)
left_justify - append spaces after string so total output is Width characters.
Definition: Format.h:146
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:1950
@ Add
Sum of integers.
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1041
StringLiteral CombineExt
ArrayRef< const char * > RequiredExts
StringLiteral Name
ArrayRef< const char * > Exts
bool operator<(const ImpliedExtsEntry &Other) const
bool operator<(StringRef Other) const
Description of the encoding of one expression Op.
Represents the major and version number components of a RISC-V extension.
Definition: RISCVISAInfo.h:29