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