LLVM 19.0.0git
RISCVISAInfo.cpp
Go to the documentation of this file.
1//===-- RISCVISAInfo.cpp - RISC-V Arch String Parser ----------------------===//
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
39struct RISCVProfile {
41 StringLiteral MArch;
42};
43
44} // end anonymous namespace
45
46static const char *RISCVGImplications[] = {
47 "i", "m", "a", "f", "d", "zicsr", "zifencei"
48};
49
50#define GET_SUPPORTED_EXTENSIONS
51#include "llvm/TargetParser/RISCVTargetParserDef.inc"
52
53#define GET_SUPPORTED_PROFILES
54#include "llvm/TargetParser/RISCVTargetParserDef.inc"
55
56static void verifyTables() {
57#ifndef NDEBUG
58 static std::atomic<bool> TableChecked(false);
59 if (!TableChecked.load(std::memory_order_relaxed)) {
60 assert(llvm::is_sorted(SupportedExtensions) &&
61 "Extensions are not sorted by name");
62 assert(llvm::is_sorted(SupportedExperimentalExtensions) &&
63 "Experimental extensions are not sorted by name");
64 TableChecked.store(true, std::memory_order_relaxed);
65 }
66#endif
67}
68
70 StringRef Description) {
71 outs().indent(4);
72 unsigned VersionWidth = Description.empty() ? 0 : 10;
73 outs() << left_justify(Name, 21) << left_justify(Version, VersionWidth)
74 << Description << "\n";
75}
76
78
79 outs() << "All available -march extensions for RISC-V\n\n";
80 PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description"));
81
83 for (const auto &E : SupportedExtensions)
84 ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
85 for (const auto &E : ExtMap) {
86 std::string Version =
87 std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
88 PrintExtension(E.first, Version, DescMap[E.first]);
89 }
90
91 outs() << "\nExperimental extensions\n";
92 ExtMap.clear();
93 for (const auto &E : SupportedExperimentalExtensions)
94 ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
95 for (const auto &E : ExtMap) {
96 std::string Version =
97 std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
98 PrintExtension(E.first, Version, DescMap["experimental-" + E.first]);
99 }
100
101 outs() << "\nSupported Profiles\n";
102 for (const auto &P : SupportedProfiles)
103 outs().indent(4) << P.Name << "\n";
104
105 outs() << "\nUse -march to specify the target's extension.\n"
106 "For example, clang -march=rv32i_v1p0\n";
107}
108
110 return Ext.consume_front("experimental-");
111}
112
113// This function finds the last character that doesn't belong to a version
114// (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will
115// consume [0-9]*p[0-9]* starting from the backward. An extension name will not
116// end with a digit or the letter 'p', so this function will parse correctly.
117// NOTE: This function is NOT able to take empty strings or strings that only
118// have version numbers and no extension name. It assumes the extension name
119// will be at least more than one character.
121 assert(!Ext.empty() &&
122 "Already guarded by if-statement in ::parseArchString");
123
124 int Pos = Ext.size() - 1;
125 while (Pos > 0 && isDigit(Ext[Pos]))
126 Pos--;
127 if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {
128 Pos--;
129 while (Pos > 0 && isDigit(Ext[Pos]))
130 Pos--;
131 }
132 return Pos;
133}
134
135namespace {
136struct LessExtName {
137 bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) {
138 return StringRef(LHS.Name) < RHS;
139 }
140 bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) {
141 return LHS < StringRef(RHS.Name);
142 }
143};
144} // namespace
145
146static std::optional<RISCVISAUtils::ExtensionVersion>
148 // Find default version of an extension.
149 // TODO: We might set default version based on profile or ISA spec.
150 for (auto &ExtInfo : {ArrayRef(SupportedExtensions),
151 ArrayRef(SupportedExperimentalExtensions)}) {
152 auto I = llvm::lower_bound(ExtInfo, ExtName, LessExtName());
153
154 if (I == ExtInfo.end() || I->Name != ExtName)
155 continue;
156
157 return I->Version;
158 }
159 return std::nullopt;
160}
161
162void RISCVISAInfo::addExtension(StringRef ExtName,
164 Exts[ExtName.str()] = Version;
165}
166
168 if (Ext.starts_with("s"))
169 return "standard supervisor-level extension";
170 if (Ext.starts_with("x"))
171 return "non-standard user-level extension";
172 if (Ext.starts_with("z"))
173 return "standard user-level extension";
174 return StringRef();
175}
176
178 if (Ext.starts_with("s"))
179 return "s";
180 if (Ext.starts_with("x"))
181 return "x";
182 if (Ext.starts_with("z"))
183 return "z";
184 return StringRef();
185}
186
187static std::optional<RISCVISAUtils::ExtensionVersion>
189 auto I =
190 llvm::lower_bound(SupportedExperimentalExtensions, Ext, LessExtName());
191 if (I == std::end(SupportedExperimentalExtensions) || I->Name != Ext)
192 return std::nullopt;
193
194 return I->Version;
195}
196
198 bool IsExperimental = stripExperimentalPrefix(Ext);
199
201 IsExperimental ? ArrayRef(SupportedExperimentalExtensions)
202 : ArrayRef(SupportedExtensions);
203
204 auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
205 return I != ExtInfo.end() && I->Name == Ext;
206}
207
209 verifyTables();
210
211 for (auto ExtInfo : {ArrayRef(SupportedExtensions),
212 ArrayRef(SupportedExperimentalExtensions)}) {
213 auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
214 if (I != ExtInfo.end() && I->Name == Ext)
215 return true;
216 }
217
218 return false;
219}
220
221bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
222 unsigned MinorVersion) {
223 for (auto ExtInfo : {ArrayRef(SupportedExtensions),
224 ArrayRef(SupportedExperimentalExtensions)}) {
225 auto Range =
226 std::equal_range(ExtInfo.begin(), ExtInfo.end(), Ext, LessExtName());
227 for (auto I = Range.first, E = Range.second; I != E; ++I)
228 if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion)
229 return true;
230 }
231
232 return false;
233}
234
237
238 if (!isSupportedExtension(Ext))
239 return false;
240
241 return Exts.count(Ext.str()) != 0;
242}
243
244std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions,
245 bool IgnoreUnknown) const {
246 std::vector<std::string> Features;
247 for (const auto &[ExtName, _] : Exts) {
248 // i is a base instruction set, not an extension (see
249 // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa)
250 // and is not recognized in clang -cc1
251 if (ExtName == "i")
252 continue;
253 if (IgnoreUnknown && !isSupportedExtension(ExtName))
254 continue;
255
256 if (isExperimentalExtension(ExtName)) {
257 Features.push_back((llvm::Twine("+experimental-") + ExtName).str());
258 } else {
259 Features.push_back((llvm::Twine("+") + ExtName).str());
260 }
261 }
262 if (AddAllExtensions) {
263 for (const RISCVSupportedExtension &Ext : SupportedExtensions) {
264 if (Exts.count(Ext.Name))
265 continue;
266 Features.push_back((llvm::Twine("-") + Ext.Name).str());
267 }
268
269 for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {
270 if (Exts.count(Ext.Name))
271 continue;
272 Features.push_back((llvm::Twine("-experimental-") + Ext.Name).str());
273 }
274 }
275 return Features;
276}
277
278static Error getStringErrorForInvalidExt(std::string_view ExtName) {
279 if (ExtName.size() == 1) {
281 "unsupported standard user-level extension '" +
282 ExtName + "'");
283 }
285 "unsupported " + getExtensionTypeDesc(ExtName) +
286 " '" + ExtName + "'");
287}
288
289// Extensions may have a version number, and may be separated by
290// an underscore '_' e.g.: rv32i2_m2.
291// Version number is divided into major and minor version numbers,
292// separated by a 'p'. If the minor version is 0 then 'p0' can be
293// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
294static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
295 unsigned &Minor, unsigned &ConsumeLength,
296 bool EnableExperimentalExtension,
297 bool ExperimentalExtensionVersionCheck) {
298 StringRef MajorStr, MinorStr;
299 Major = 0;
300 Minor = 0;
301 ConsumeLength = 0;
302 MajorStr = In.take_while(isDigit);
303 In = In.substr(MajorStr.size());
304
305 if (!MajorStr.empty() && In.consume_front("p")) {
306 MinorStr = In.take_while(isDigit);
307 In = In.substr(MajorStr.size() + MinorStr.size() - 1);
308
309 // Expected 'p' to be followed by minor version number.
310 if (MinorStr.empty()) {
311 return createStringError(
313 "minor version number missing after 'p' for extension '" + Ext + "'");
314 }
315 }
316
317 if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
318 return createStringError(
320 "Failed to parse major version number for extension '" + Ext + "'");
321
322 if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
323 return createStringError(
325 "Failed to parse minor version number for extension '" + Ext + "'");
326
327 ConsumeLength = MajorStr.size();
328
329 if (!MinorStr.empty())
330 ConsumeLength += MinorStr.size() + 1 /*'p'*/;
331
332 // Expected multi-character extension with version number to have no
333 // subsequent characters (i.e. must either end string or be followed by
334 // an underscore).
335 if (Ext.size() > 1 && In.size())
336 return createStringError(
338 "multi-character extensions must be separated by underscores");
339
340 // If experimental extension, require use of current version number
341 if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
342 if (!EnableExperimentalExtension)
344 "requires '-menable-experimental-extensions' "
345 "for experimental extension '" +
346 Ext + "'");
347
348 if (ExperimentalExtensionVersionCheck &&
349 (MajorStr.empty() && MinorStr.empty()))
350 return createStringError(
352 "experimental extension requires explicit version number `" + Ext +
353 "`");
354
355 auto SupportedVers = *ExperimentalExtension;
356 if (ExperimentalExtensionVersionCheck &&
357 (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
358 std::string Error = "unsupported version number " + MajorStr.str();
359 if (!MinorStr.empty())
360 Error += "." + MinorStr.str();
361 Error += " for experimental extension '" + Ext.str() +
362 "' (this compiler supports " + utostr(SupportedVers.Major) +
363 "." + utostr(SupportedVers.Minor) + ")";
365 }
366 return Error::success();
367 }
368
369 // Exception rule for `g`, we don't have clear version scheme for that on
370 // ISA spec.
371 if (Ext == "g")
372 return Error::success();
373
374 if (MajorStr.empty() && MinorStr.empty()) {
375 if (auto DefaultVersion = findDefaultVersion(Ext)) {
376 Major = DefaultVersion->Major;
377 Minor = DefaultVersion->Minor;
378 }
379 // No matter found or not, return success, assume other place will
380 // verify.
381 return Error::success();
382 }
383
384 if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
385 return Error::success();
386
388 return getStringErrorForInvalidExt(Ext);
389
390 std::string Error = "unsupported version number " + std::string(MajorStr);
391 if (!MinorStr.empty())
392 Error += "." + MinorStr.str();
393 Error += " for extension '" + Ext.str() + "'";
395}
396
399 const std::vector<std::string> &Features) {
400 assert(XLen == 32 || XLen == 64);
401 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
402
403 for (auto &Feature : Features) {
404 StringRef ExtName = Feature;
405 assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
406 bool Add = ExtName[0] == '+';
407 ExtName = ExtName.drop_front(1); // Drop '+' or '-'
408 bool Experimental = stripExperimentalPrefix(ExtName);
409 auto ExtensionInfos = Experimental
410 ? ArrayRef(SupportedExperimentalExtensions)
411 : ArrayRef(SupportedExtensions);
412 auto ExtensionInfoIterator =
413 llvm::lower_bound(ExtensionInfos, ExtName, LessExtName());
414
415 // Not all features is related to ISA extension, like `relax` or
416 // `save-restore`, skip those feature.
417 if (ExtensionInfoIterator == ExtensionInfos.end() ||
418 ExtensionInfoIterator->Name != ExtName)
419 continue;
420
421 if (Add)
422 ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version);
423 else
424 ISAInfo->Exts.erase(ExtName.str());
425 }
426
427 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
428}
429
432 // RISC-V ISA strings must be [a-z0-9_]
433 if (!llvm::all_of(
434 Arch, [](char C) { return isDigit(C) || isLower(C) || C == '_'; }))
436 "string may only contain [a-z0-9_]");
437
438 // Must start with a valid base ISA name.
439 unsigned XLen = 0;
440 if (Arch.consume_front("rv32"))
441 XLen = 32;
442 else if (Arch.consume_front("rv64"))
443 XLen = 64;
444
445 if (XLen == 0 || Arch.empty() || (Arch[0] != 'i' && Arch[0] != 'e'))
447 "arch string must begin with valid base ISA");
448
449 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
450
451 // Each extension is of the form ${name}${major_version}p${minor_version}
452 // and separated by _. Split by _ and then extract the name and version
453 // information for each extension.
455 Arch.split(Split, '_');
456 for (StringRef Ext : Split) {
457 StringRef Prefix, MinorVersionStr;
458 std::tie(Prefix, MinorVersionStr) = Ext.rsplit('p');
459 if (MinorVersionStr.empty())
461 "extension lacks version in expected format");
462 unsigned MajorVersion, MinorVersion;
463 if (MinorVersionStr.getAsInteger(10, MinorVersion))
465 "failed to parse minor version number");
466
467 // Split Prefix into the extension name and the major version number
468 // (the trailing digits of Prefix).
469 size_t VersionStart = Prefix.size();
470 while (VersionStart != 0) {
471 if (!isDigit(Prefix[VersionStart - 1]))
472 break;
473 --VersionStart;
474 }
475 if (VersionStart == Prefix.size())
477 "extension lacks version in expected format");
478
479 if (VersionStart == 0)
481 "missing extension name");
482
483 StringRef ExtName = Prefix.slice(0, VersionStart);
484 StringRef MajorVersionStr = Prefix.slice(VersionStart, StringRef::npos);
485 if (MajorVersionStr.getAsInteger(10, MajorVersion))
487 "failed to parse major version number");
488
489 if ((ExtName[0] == 'z' || ExtName[0] == 's' || ExtName[0] == 'x') &&
490 (ExtName.size() == 1 || isDigit(ExtName[1])))
492 "'" + Twine(ExtName[0]) +
493 "' must be followed by a letter");
494
495 ISAInfo->addExtension(ExtName, {MajorVersion, MinorVersion});
496 }
497 ISAInfo->updateImpliedLengths();
498 return std::move(ISAInfo);
499}
500
502 std::vector<std::string> &SplitExts) {
504 if (Exts.empty())
505 return Error::success();
506
507 Exts.split(Split, "_");
508
509 for (auto Ext : Split) {
510 if (Ext.empty())
512 "extension name missing after separator '_'");
513
514 SplitExts.push_back(Ext.str());
515 }
516 return Error::success();
517}
518
520 StringRef RawExt,
522 std::map<std::string, unsigned>> &SeenExtMap,
523 bool IgnoreUnknown, bool EnableExperimentalExtension,
524 bool ExperimentalExtensionVersionCheck) {
527 auto Pos = findLastNonVersionCharacter(RawExt) + 1;
528 StringRef Name(RawExt.substr(0, Pos));
529 StringRef Vers(RawExt.substr(Pos));
530
531 if (Type.empty()) {
532 if (IgnoreUnknown)
533 return Error::success();
535 "invalid extension prefix '" + RawExt + "'");
536 }
537
538 if (!IgnoreUnknown && Name.size() == Type.size())
540 Desc + " name missing after '" + Type + "'");
541
542 unsigned Major, Minor, ConsumeLength;
543 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
544 EnableExperimentalExtension,
545 ExperimentalExtensionVersionCheck)) {
546 if (IgnoreUnknown) {
547 consumeError(std::move(E));
548 return Error::success();
549 }
550 return E;
551 }
552
553 // Check if duplicated extension.
554 if (!IgnoreUnknown && SeenExtMap.contains(Name.str()))
556 "duplicated " + Desc + " '" + Name + "'");
557
558 if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Name))
559 return Error::success();
560
561 SeenExtMap[Name.str()] = {Major, Minor};
562 return Error::success();
563}
564
566 StringRef &RawExt,
568 std::map<std::string, unsigned>> &SeenExtMap,
569 bool IgnoreUnknown, bool EnableExperimentalExtension,
570 bool ExperimentalExtensionVersionCheck) {
571 unsigned Major, Minor, ConsumeLength;
572 StringRef Name = RawExt.take_front(1);
573 RawExt.consume_front(Name);
574 if (auto E = getExtensionVersion(Name, RawExt, Major, Minor, ConsumeLength,
575 EnableExperimentalExtension,
576 ExperimentalExtensionVersionCheck)) {
577 if (IgnoreUnknown) {
578 consumeError(std::move(E));
579 RawExt = RawExt.substr(ConsumeLength);
580 return Error::success();
581 }
582 return E;
583 }
584
585 RawExt = RawExt.substr(ConsumeLength);
586
587 // Check if duplicated extension.
588 if (!IgnoreUnknown && SeenExtMap.contains(Name.str()))
590 "duplicated standard user-level extension '" +
591 Name + "'");
592
593 if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Name))
594 return Error::success();
595
596 SeenExtMap[Name.str()] = {Major, Minor};
597 return Error::success();
598}
599
601RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
602 bool ExperimentalExtensionVersionCheck,
603 bool IgnoreUnknown) {
604 // RISC-V ISA strings must be [a-z0-9_]
605 if (!llvm::all_of(
606 Arch, [](char C) { return isDigit(C) || isLower(C) || C == '_'; }))
608 "string may only contain [a-z0-9_]");
609
610 // ISA string must begin with rv32, rv64, or a profile.
611 unsigned XLen = 0;
612 if (Arch.consume_front("rv32")) {
613 XLen = 32;
614 } else if (Arch.consume_front("rv64")) {
615 XLen = 64;
616 } else {
617 // Try parsing as a profile.
618 auto I = llvm::upper_bound(SupportedProfiles, Arch,
619 [](StringRef Arch, const RISCVProfile &Profile) {
620 return Arch < Profile.Name;
621 });
622
623 if (I != std::begin(SupportedProfiles) && Arch.starts_with((--I)->Name)) {
624 std::string NewArch = I->MArch.str();
625 StringRef ArchWithoutProfile = Arch.drop_front(I->Name.size());
626 if (!ArchWithoutProfile.empty()) {
627 if (ArchWithoutProfile.front() != '_')
628 return createStringError(
630 "additional extensions must be after separator '_'");
631 NewArch += ArchWithoutProfile.str();
632 }
633 return parseArchString(NewArch, EnableExperimentalExtension,
634 ExperimentalExtensionVersionCheck, IgnoreUnknown);
635 }
636 }
637
638 if (XLen == 0 || Arch.empty())
639 return createStringError(
641 "string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "
642 "profile name");
643
644 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
646 std::map<std::string, unsigned>>
647 SeenExtMap;
648
649 // The canonical order specified in ISA manual.
650 // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
651 char Baseline = Arch.front();
652
653 // First letter should be 'e', 'i' or 'g'.
654 switch (Baseline) {
655 default:
657 "first letter after \'rv" + Twine(XLen) +
658 "\' should be 'e', 'i' or 'g'");
659 case 'e':
660 case 'i':
661 break;
662 case 'g':
663 // g expands to extensions in RISCVGImplications.
664 if (Arch.size() > 1 && isDigit(Arch[1]))
666 "version not supported for 'g'");
667 break;
668 }
669
670 if (Arch.back() == '_')
672 "extension name missing after separator '_'");
673
674 // Skip baseline.
675 StringRef Exts = Arch.drop_front(1);
676
677 unsigned Major, Minor, ConsumeLength;
678 if (Baseline == 'g') {
679 // Versions for g are disallowed, and this was checked for previously.
680 ConsumeLength = 0;
681
682 // No matter which version is given to `g`, we always set imafd to default
683 // version since the we don't have clear version scheme for that on
684 // ISA spec.
685 for (const auto *Ext : RISCVGImplications) {
686 auto Version = findDefaultVersion(Ext);
687 assert(Version && "Default extension version not found?");
688 // Postpone AddExtension until end of this function
689 SeenExtMap[Ext] = {Version->Major, Version->Minor};
690 }
691 } else {
692 // Baseline is `i` or `e`
693 if (auto E = getExtensionVersion(
694 StringRef(&Baseline, 1), Exts, Major, Minor, ConsumeLength,
695 EnableExperimentalExtension, ExperimentalExtensionVersionCheck)) {
696 if (!IgnoreUnknown)
697 return std::move(E);
698 // If IgnoreUnknown, then ignore an unrecognised version of the baseline
699 // ISA and just use the default supported version.
700 consumeError(std::move(E));
701 auto Version = findDefaultVersion(StringRef(&Baseline, 1));
702 Major = Version->Major;
703 Minor = Version->Minor;
704 }
705
706 // Postpone AddExtension until end of this function
707 SeenExtMap[StringRef(&Baseline, 1).str()] = {Major, Minor};
708 }
709
710 // Consume the base ISA version number and any '_' between rvxxx and the
711 // first extension
712 Exts = Exts.drop_front(ConsumeLength);
713 Exts.consume_front("_");
714
715 std::vector<std::string> SplitExts;
716 if (auto E = splitExtsByUnderscore(Exts, SplitExts))
717 return std::move(E);
718
719 for (auto &Ext : SplitExts) {
720 StringRef CurrExt = Ext;
721 while (!CurrExt.empty()) {
723 if (auto E = processSingleLetterExtension(
724 CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension,
725 ExperimentalExtensionVersionCheck))
726 return std::move(E);
727 } else if (CurrExt.front() == 'z' || CurrExt.front() == 's' ||
728 CurrExt.front() == 'x') {
729 // Handle other types of extensions other than the standard
730 // general purpose and standard user-level extensions.
731 // Parse the ISA string containing non-standard user-level
732 // extensions, standard supervisor-level extensions and
733 // non-standard supervisor-level extensions.
734 // These extensions start with 'z', 's', 'x' prefixes, might have a
735 // version number (major, minor) and are separated by a single
736 // underscore '_'. We do not enforce a canonical order for them.
737 if (auto E = processMultiLetterExtension(
738 CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension,
739 ExperimentalExtensionVersionCheck))
740 return std::move(E);
741 // Multi-letter extension must be seperate following extension with
742 // underscore
743 break;
744 } else {
745 // FIXME: Could it be ignored by IgnoreUnknown?
747 "invalid standard user-level extension '" +
748 Twine(CurrExt.front()) + "'");
749 }
750 }
751 }
752
753 // Check all Extensions are supported.
754 for (auto &SeenExtAndVers : SeenExtMap) {
755 const std::string &ExtName = SeenExtAndVers.first;
756 RISCVISAUtils::ExtensionVersion ExtVers = SeenExtAndVers.second;
757
759 return getStringErrorForInvalidExt(ExtName);
760 ISAInfo->addExtension(ExtName, ExtVers);
761 }
762
763 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
764}
765
766Error RISCVISAInfo::checkDependency() {
767 bool HasC = Exts.count("c") != 0;
768 bool HasF = Exts.count("f") != 0;
769 bool HasZfinx = Exts.count("zfinx") != 0;
770 bool HasVector = Exts.count("zve32x") != 0;
771 bool HasZvl = MinVLen != 0;
772 bool HasZcmt = Exts.count("zcmt") != 0;
773
774 if (HasF && HasZfinx)
776 "'f' and 'zfinx' extensions are incompatible");
777
778 if (HasZvl && !HasVector)
779 return createStringError(
781 "'zvl*b' requires 'v' or 'zve*' extension to also be specified");
782
783 if (Exts.count("zvbb") && !HasVector)
784 return createStringError(
786 "'zvbb' requires 'v' or 'zve*' extension to also be specified");
787
788 if (Exts.count("zvbc") && !Exts.count("zve64x"))
789 return createStringError(
791 "'zvbc' requires 'v' or 'zve64*' extension to also be specified");
792
793 if ((Exts.count("zvkb") || Exts.count("zvkg") || Exts.count("zvkned") ||
794 Exts.count("zvknha") || Exts.count("zvksed") || Exts.count("zvksh")) &&
795 !HasVector)
796 return createStringError(
798 "'zvk*' requires 'v' or 'zve*' extension to also be specified");
799
800 if (Exts.count("zvknhb") && !Exts.count("zve64x"))
801 return createStringError(
803 "'zvknhb' requires 'v' or 'zve64*' extension to also be specified");
804
805 if ((HasZcmt || Exts.count("zcmp")) && Exts.count("d") &&
806 (HasC || Exts.count("zcd")))
807 return createStringError(
809 Twine("'") + (HasZcmt ? "zcmt" : "zcmp") +
810 "' extension is incompatible with '" + (HasC ? "c" : "zcd") +
811 "' extension when 'd' extension is enabled");
812
813 if (XLen != 32 && Exts.count("zcf"))
815 "'zcf' is only supported for 'rv32'");
816
817 if (Exts.count("zacas") && !(Exts.count("a") || Exts.count("zamo")))
818 return createStringError(
820 "'zacas' requires 'a' or 'zaamo' extension to also be specified");
821
822 if (Exts.count("zabha") && !(Exts.count("a") || Exts.count("zamo")))
823 return createStringError(
825 "'zabha' requires 'a' or 'zaamo' extension to also be specified");
826
827 return Error::success();
828}
829
832 const char *ImpliedExt;
833
834 bool operator<(const ImpliedExtsEntry &Other) const {
835 return Name < Other.Name;
836 }
837};
838
839static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS) {
840 return LHS.Name < RHS;
841}
842
843static bool operator<(StringRef LHS, const ImpliedExtsEntry &RHS) {
844 return LHS < RHS.Name;
845}
846
847#define GET_IMPLIED_EXTENSIONS
848#include "llvm/TargetParser/RISCVTargetParserDef.inc"
849
850void RISCVISAInfo::updateImplication() {
851 bool HasE = Exts.count("e") != 0;
852 bool HasI = Exts.count("i") != 0;
853
854 // If not in e extension and i extension does not exist, i extension is
855 // implied
856 if (!HasE && !HasI) {
857 auto Version = findDefaultVersion("i");
858 addExtension("i", Version.value());
859 }
860
861 assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
862
863 // This loop may execute over 1 iteration since implication can be layered
864 // Exits loop if no more implication is applied
866 for (auto const &Ext : Exts)
867 WorkList.insert(Ext.first);
868
869 while (!WorkList.empty()) {
870 StringRef ExtName = WorkList.pop_back_val();
871 auto Range = std::equal_range(std::begin(ImpliedExts),
872 std::end(ImpliedExts), ExtName);
873 std::for_each(Range.first, Range.second,
874 [&](const ImpliedExtsEntry &Implied) {
875 const char *ImpliedExt = Implied.ImpliedExt;
876 if (WorkList.count(ImpliedExt))
877 return;
878 if (Exts.count(ImpliedExt))
879 return;
880 auto Version = findDefaultVersion(ImpliedExt);
881 addExtension(ImpliedExt, Version.value());
882 WorkList.insert(ImpliedExt);
883 });
884 }
885
886 // Add Zcf if Zce and F are enabled on RV32.
887 if (XLen == 32 && Exts.count("zce") && Exts.count("f") &&
888 !Exts.count("zcf")) {
889 auto Version = findDefaultVersion("zcf");
890 addExtension("zcf", Version.value());
891 }
892}
893
894static constexpr StringLiteral CombineIntoExts[] = {
895 {"zk"}, {"zkn"}, {"zks"}, {"zvkn"}, {"zvknc"},
896 {"zvkng"}, {"zvks"}, {"zvksc"}, {"zvksg"},
897};
898
899void RISCVISAInfo::updateCombination() {
900 bool MadeChange = false;
901 do {
902 MadeChange = false;
903 for (StringRef CombineExt : CombineIntoExts) {
904 if (hasExtension(CombineExt))
905 continue;
906
907 // Look up the extension in the ImpliesExt table to find everything it
908 // depends on.
909 auto Range = std::equal_range(std::begin(ImpliedExts),
910 std::end(ImpliedExts), CombineExt);
911 bool HasAllRequiredFeatures = std::all_of(
912 Range.first, Range.second, [&](const ImpliedExtsEntry &Implied) {
913 return hasExtension(Implied.ImpliedExt);
914 });
915 if (HasAllRequiredFeatures) {
916 auto Version = findDefaultVersion(CombineExt);
917 addExtension(CombineExt, Version.value());
918 MadeChange = true;
919 }
920 }
921 } while (MadeChange);
922}
923
924void RISCVISAInfo::updateImpliedLengths() {
925 assert(FLen == 0 && MaxELenFp == 0 && MaxELen == 0 && MinVLen == 0 &&
926 "Expected lengths to be initialied to zero");
927
928 // TODO: Handle q extension.
929 if (Exts.count("d"))
930 FLen = 64;
931 else if (Exts.count("f"))
932 FLen = 32;
933
934 if (Exts.count("v")) {
935 MaxELenFp = std::max(MaxELenFp, 64u);
936 MaxELen = std::max(MaxELen, 64u);
937 }
938
939 for (auto const &Ext : Exts) {
940 StringRef ExtName = Ext.first;
941 // Infer MaxELen and MaxELenFp from Zve(32/64)(x/f/d)
942 if (ExtName.consume_front("zve")) {
943 unsigned ZveELen;
944 if (ExtName.consumeInteger(10, ZveELen))
945 continue;
946
947 if (ExtName == "f")
948 MaxELenFp = std::max(MaxELenFp, 32u);
949 else if (ExtName == "d")
950 MaxELenFp = std::max(MaxELenFp, 64u);
951 else if (ExtName != "x")
952 continue;
953
954 MaxELen = std::max(MaxELen, ZveELen);
955 continue;
956 }
957
958 // Infer MinVLen from zvl*b.
959 if (ExtName.consume_front("zvl")) {
960 unsigned ZvlLen;
961 if (ExtName.consumeInteger(10, ZvlLen))
962 continue;
963
964 if (ExtName != "b")
965 continue;
966
967 MinVLen = std::max(MinVLen, ZvlLen);
968 continue;
969 }
970 }
971}
972
973std::string RISCVISAInfo::toString() const {
974 std::string Buffer;
975 raw_string_ostream Arch(Buffer);
976
977 Arch << "rv" << XLen;
978
979 ListSeparator LS("_");
980 for (auto const &Ext : Exts) {
981 StringRef ExtName = Ext.first;
982 auto ExtInfo = Ext.second;
983 Arch << LS << ExtName;
984 Arch << ExtInfo.Major << "p" << ExtInfo.Minor;
985 }
986
987 return Arch.str();
988}
989
991RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
992 ISAInfo->updateImplication();
993 ISAInfo->updateCombination();
994 ISAInfo->updateImpliedLengths();
995
996 if (Error Result = ISAInfo->checkDependency())
997 return std::move(Result);
998 return std::move(ISAInfo);
999}
1000
1002 if (XLen == 32) {
1003 if (hasExtension("e"))
1004 return "ilp32e";
1005 if (hasExtension("d"))
1006 return "ilp32d";
1007 if (hasExtension("f"))
1008 return "ilp32f";
1009 return "ilp32";
1010 } else if (XLen == 64) {
1011 if (hasExtension("e"))
1012 return "lp64e";
1013 if (hasExtension("d"))
1014 return "lp64d";
1015 if (hasExtension("f"))
1016 return "lp64f";
1017 return "lp64";
1018 }
1019 llvm_unreachable("Invalid XLEN");
1020}
1021
1023 if (Ext.empty())
1024 return false;
1025
1026 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1027 StringRef Name = Ext.substr(0, Pos);
1028 StringRef Vers = Ext.substr(Pos);
1029 if (Vers.empty())
1030 return false;
1031
1032 unsigned Major, Minor, ConsumeLength;
1033 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
1034 true, true)) {
1035 consumeError(std::move(E));
1036 return false;
1037 }
1038
1039 return true;
1040}
1041
1043 if (Ext.empty())
1044 return std::string();
1045
1046 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1047 StringRef Name = Ext.substr(0, Pos);
1048
1049 if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext))
1050 return std::string();
1051
1053 return std::string();
1054
1055 return isExperimentalExtension(Name) ? "experimental-" + Name.str()
1056 : Name.str();
1057}
std::string Name
std::optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1291
#define _
#define I(x, y, z)
Definition: MD5.cpp:58
Load MIR Sample Profile
This file implements a map that provides insertion order iteration.
#define P(N)
static void verifyTables()
static StringRef getExtensionTypeDesc(StringRef Ext)
static Error processSingleLetterExtension(StringRef &RawExt, MapVector< std::string, RISCVISAUtils::ExtensionVersion, std::map< std::string, unsigned > > &SeenExtMap, bool IgnoreUnknown, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static std::optional< RISCVISAUtils::ExtensionVersion > findDefaultVersion(StringRef ExtName)
static size_t findLastNonVersionCharacter(StringRef Ext)
static StringRef getExtensionType(StringRef Ext)
static constexpr StringLiteral CombineIntoExts[]
static bool stripExperimentalPrefix(StringRef &Ext)
static Error processMultiLetterExtension(StringRef RawExt, MapVector< std::string, RISCVISAUtils::ExtensionVersion, std::map< std::string, unsigned > > &SeenExtMap, bool IgnoreUnknown, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static std::optional< RISCVISAUtils::ExtensionVersion > isExperimentalExtension(StringRef Ext)
static void PrintExtension(StringRef Name, StringRef Version, StringRef Description)
static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS)
static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, unsigned &Minor, unsigned &ConsumeLength, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static const char * RISCVGImplications[]
static Error getStringErrorForInvalidExt(std::string_view ExtName)
static Error splitExtsByUnderscore(StringRef Exts, std::vector< std::string > &SplitExts)
static bool isDigit(const char C)
static bool isLower(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.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition: Value.cpp:469
static void verifyTables()
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
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
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)
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:845
bool empty() const
Definition: StringMap.h:102
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:127
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:692
bool consumeInteger(unsigned Radix, T &Result)
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:491
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:462
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:563
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:601
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 consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition: StringRef.h:627
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:572
static constexpr size_t npos
Definition: StringRef.h:52
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.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
const uint64_t Version
Definition: InstrProf.h:1153
constexpr StringLiteral AllStdExts
Definition: RISCVISAUtils.h:23
std::map< std::string, ExtensionVersion, ExtensionComparator > OrderedExtensionMap
OrderedExtensionMap is std::map, it's specialized to keep entries in canonical order of extension.
Definition: RISCVISAUtils.h:43
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
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1722
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
auto upper_bound(R &&Range, T &&Value)
Provide wrappers to std::upper_bound which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:1967
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1258
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:1902
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:1954
@ Add
Sum of integers.
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1041
StringLiteral Name
bool operator<(const ImpliedExtsEntry &Other) const
const char * ImpliedExt
Description of the encoding of one expression Op.
Represents the major and version number components of a RISC-V extension.
Definition: RISCVISAUtils.h:26