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.substr(Idx);
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.substr(VersionStart);
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.substr(Idx);
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 static constexpr StringLiteral XqciExts[] = {
745 {"xqcia"}, {"xqcics"}, {"xqcicsr"}, {"xqcilsm"}, {"xqcisls"}};
746
747 if (HasI && HasE)
748 return getIncompatibleError("i", "e");
749
750 if (HasF && HasZfinx)
751 return getIncompatibleError("f", "zfinx");
752
753 if (HasZvl && !HasVector)
754 return getExtensionRequiresError("zvl*b", "v' or 'zve*");
755
756 if ((HasZcmt || Exts.count("zcmp")) && HasD && (HasC || Exts.count("zcd")))
757 return getError(Twine("'") + (HasZcmt ? "zcmt" : "zcmp") +
758 "' extension is incompatible with '" +
759 (HasC ? "c" : "zcd") +
760 "' extension when 'd' extension is enabled");
761
762 if (XLen != 32 && Exts.count("zcf"))
763 return getError("'zcf' is only supported for 'rv32'");
764
765 if (Exts.count("xwchc") != 0) {
766 if (XLen != 32)
767 return getError("'xwchc' is only supported for 'rv32'");
768
769 if (HasD)
770 return getIncompatibleError("d", "xwchc");
771
772 if (Exts.count("zcb") != 0)
773 return getIncompatibleError("xwchc", "zcb");
774 }
775
776 for (auto Ext : XqciExts)
777 if (Exts.count(Ext.str()) && (XLen != 32))
778 return getError("'" + Twine(Ext) + "'" + " is only supported for 'rv32'");
779
780 return Error::success();
781}
782
785 const char *ImpliedExt;
786
787 bool operator<(const ImpliedExtsEntry &Other) const {
788 return Name < Other.Name;
789 }
790};
791
792static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS) {
793 return LHS.Name < RHS;
794}
795
796static bool operator<(StringRef LHS, const ImpliedExtsEntry &RHS) {
797 return LHS < RHS.Name;
798}
799
800#define GET_IMPLIED_EXTENSIONS
801#include "llvm/TargetParser/RISCVTargetParserDef.inc"
802
803void RISCVISAInfo::updateImplication() {
804 bool HasE = Exts.count("e") != 0;
805 bool HasI = Exts.count("i") != 0;
806
807 // If not in e extension and i extension does not exist, i extension is
808 // implied
809 if (!HasE && !HasI) {
810 auto Version = findDefaultVersion("i");
811 Exts["i"] = *Version;
812 }
813
814 if (HasE && HasI)
815 Exts.erase("i");
816
817 assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
818
819 // This loop may execute over 1 iteration since implication can be layered
820 // Exits loop if no more implication is applied
822 for (auto const &Ext : Exts)
823 WorkList.push_back(Ext.first);
824
825 while (!WorkList.empty()) {
826 StringRef ExtName = WorkList.pop_back_val();
827 auto Range = std::equal_range(std::begin(ImpliedExts),
828 std::end(ImpliedExts), ExtName);
829 std::for_each(Range.first, Range.second,
830 [&](const ImpliedExtsEntry &Implied) {
831 const char *ImpliedExt = Implied.ImpliedExt;
832 if (Exts.count(ImpliedExt))
833 return;
834 auto Version = findDefaultVersion(ImpliedExt);
835 Exts[ImpliedExt] = *Version;
836 WorkList.push_back(ImpliedExt);
837 });
838 }
839
840 // Add Zcf if Zce and F are enabled on RV32.
841 if (XLen == 32 && Exts.count("zce") && Exts.count("f") &&
842 !Exts.count("zcf")) {
843 auto Version = findDefaultVersion("zcf");
844 Exts["zcf"] = *Version;
845 }
846}
847
848static constexpr StringLiteral CombineIntoExts[] = {
849 {"zk"}, {"zkn"}, {"zks"}, {"zvkn"}, {"zvknc"},
850 {"zvkng"}, {"zvks"}, {"zvksc"}, {"zvksg"},
851};
852
853void RISCVISAInfo::updateCombination() {
854 bool MadeChange = false;
855 do {
856 MadeChange = false;
857 for (StringRef CombineExt : CombineIntoExts) {
858 if (Exts.count(CombineExt.str()))
859 continue;
860
861 // Look up the extension in the ImpliesExt table to find everything it
862 // depends on.
863 auto Range = std::equal_range(std::begin(ImpliedExts),
864 std::end(ImpliedExts), CombineExt);
865 bool HasAllRequiredFeatures = std::all_of(
866 Range.first, Range.second, [&](const ImpliedExtsEntry &Implied) {
867 return Exts.count(Implied.ImpliedExt);
868 });
869 if (HasAllRequiredFeatures) {
870 auto Version = findDefaultVersion(CombineExt);
871 Exts[CombineExt.str()] = *Version;
872 MadeChange = true;
873 }
874 }
875 } while (MadeChange);
876}
877
878void RISCVISAInfo::updateImpliedLengths() {
879 assert(FLen == 0 && MaxELenFp == 0 && MaxELen == 0 && MinVLen == 0 &&
880 "Expected lengths to be initialied to zero");
881
882 // TODO: Handle q extension.
883 if (Exts.count("d"))
884 FLen = 64;
885 else if (Exts.count("f"))
886 FLen = 32;
887
888 if (Exts.count("v")) {
889 MaxELenFp = std::max(MaxELenFp, 64u);
890 MaxELen = std::max(MaxELen, 64u);
891 }
892
893 for (auto const &Ext : Exts) {
894 StringRef ExtName = Ext.first;
895 // Infer MaxELen and MaxELenFp from Zve(32/64)(x/f/d)
896 if (ExtName.consume_front("zve")) {
897 unsigned ZveELen;
898 if (ExtName.consumeInteger(10, ZveELen))
899 continue;
900
901 if (ExtName == "f")
902 MaxELenFp = std::max(MaxELenFp, 32u);
903 else if (ExtName == "d")
904 MaxELenFp = std::max(MaxELenFp, 64u);
905 else if (ExtName != "x")
906 continue;
907
908 MaxELen = std::max(MaxELen, ZveELen);
909 continue;
910 }
911
912 // Infer MinVLen from zvl*b.
913 if (ExtName.consume_front("zvl")) {
914 unsigned ZvlLen;
915 if (ExtName.consumeInteger(10, ZvlLen))
916 continue;
917
918 if (ExtName != "b")
919 continue;
920
921 MinVLen = std::max(MinVLen, ZvlLen);
922 continue;
923 }
924 }
925}
926
927std::string RISCVISAInfo::toString() const {
928 std::string Buffer;
929 raw_string_ostream Arch(Buffer);
930
931 Arch << "rv" << XLen;
932
933 ListSeparator LS("_");
934 for (auto const &Ext : Exts) {
935 StringRef ExtName = Ext.first;
936 auto ExtInfo = Ext.second;
937 Arch << LS << ExtName;
938 Arch << ExtInfo.Major << "p" << ExtInfo.Minor;
939 }
940
941 return Arch.str();
942}
943
945RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
946 ISAInfo->updateImplication();
947 ISAInfo->updateCombination();
948 ISAInfo->updateImpliedLengths();
949
950 if (Error Result = ISAInfo->checkDependency())
951 return std::move(Result);
952 return std::move(ISAInfo);
953}
954
956 if (XLen == 32) {
957 if (Exts.count("e"))
958 return "ilp32e";
959 if (Exts.count("d"))
960 return "ilp32d";
961 if (Exts.count("f"))
962 return "ilp32f";
963 return "ilp32";
964 } else if (XLen == 64) {
965 if (Exts.count("e"))
966 return "lp64e";
967 if (Exts.count("d"))
968 return "lp64d";
969 if (Exts.count("f"))
970 return "lp64f";
971 return "lp64";
972 }
973 llvm_unreachable("Invalid XLEN");
974}
975
977 if (Ext.empty())
978 return false;
979
980 auto Pos = findLastNonVersionCharacter(Ext) + 1;
981 StringRef Name = Ext.substr(0, Pos);
982 StringRef Vers = Ext.substr(Pos);
983 if (Vers.empty())
984 return false;
985
986 unsigned Major, Minor, ConsumeLength;
987 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
988 true, true)) {
989 consumeError(std::move(E));
990 return false;
991 }
992
993 return true;
994}
995
997 if (Ext.empty())
998 return std::string();
999
1000 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1001 StringRef Name = Ext.substr(0, Pos);
1002
1003 if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext))
1004 return std::string();
1005
1007 return std::string();
1008
1009 return isExperimentalExtension(Name) ? "experimental-" + Name.str()
1010 : Name.str();
1011}
1012
1017};
1018
1019constexpr static RISCVExtBit RISCVBitPositions[] = {
1020 {"a", 0, 0}, {"c", 0, 2},
1021 {"d", 0, 3}, {"f", 0, 5},
1022 {"i", 0, 8}, {"m", 0, 12},
1023 {"v", 0, 21}, {"zacas", 0, 26},
1024 {"zba", 0, 27}, {"zbb", 0, 28},
1025 {"zbc", 0, 29}, {"zbkb", 0, 30},
1026 {"zbkc", 0, 31}, {"zbkx", 0, 32},
1027 {"zbs", 0, 33}, {"zfa", 0, 34},
1028 {"zfh", 0, 35}, {"zfhmin", 0, 36},
1029 {"zicboz", 0, 37}, {"zicond", 0, 38},
1030 {"zihintntl", 0, 39}, {"zihintpause", 0, 40},
1031 {"zknd", 0, 41}, {"zkne", 0, 42},
1032 {"zknh", 0, 43}, {"zksed", 0, 44},
1033 {"zksh", 0, 45}, {"zkt", 0, 46},
1034 {"ztso", 0, 47}, {"zvbb", 0, 48},
1035 {"zvbc", 0, 49}, {"zvfh", 0, 50},
1036 {"zvfhmin", 0, 51}, {"zvkb", 0, 52},
1037 {"zvkg", 0, 53}, {"zvkned", 0, 54},
1038 {"zvknha", 0, 55}, {"zvknhb", 0, 56},
1039 {"zvksed", 0, 57}, {"zvksh", 0, 58},
1040 {"zvkt", 0, 59}, {"zve32x", 0, 60},
1041 {"zve32f", 0, 61}, {"zve64x", 0, 62},
1042 {"zve64f", 0, 63}, {"zve64d", 1, 0},
1043 {"zimop", 1, 1}, {"zca", 1, 2},
1044 {"zcb", 1, 3}, {"zcd", 1, 4},
1045 {"zcf", 1, 5}, {"zcmop", 1, 6},
1046 {"zawrs", 1, 7}};
1047
1049 // Note that this code currently accepts mixed case extension names, but
1050 // does not handle extension versions at all. That's probably fine because
1051 // there's only one extension version in the __riscv_feature_bits vector.
1052 for (auto E : RISCVBitPositions)
1053 if (E.ext.equals_insensitive(Ext))
1054 return std::make_pair(E.groupid, E.bitpos);
1055 return std::make_pair(-1, -1);
1056}
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:1313
#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.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition: Value.cpp:469
This file contains some functions that are useful when dealing with strings.
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:157
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:81
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition: StringRef.h:853
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:51
bool consumeInteger(unsigned Radix, T &Result)
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:499
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:470
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:229
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:571
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:265
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:147
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition: StringRef.h:609
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
Definition: StringRef.h:684
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:150
char front() const
front - Get the first character in the string.
Definition: StringRef.h:153
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition: StringRef.h:635
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:297
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:286
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:1739
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:1991
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1291
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:1926
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:1978
@ 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