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