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
724Error RISCVISAInfo::checkDependency() {
725 bool HasE = Exts.count("e") != 0;
726 bool HasI = Exts.count("i") != 0;
727 bool HasC = Exts.count("c") != 0;
728 bool HasF = Exts.count("f") != 0;
729 bool HasD = Exts.count("d") != 0;
730 bool HasZfinx = Exts.count("zfinx") != 0;
731 bool HasVector = Exts.count("zve32x") != 0;
732 bool HasZvl = MinVLen != 0;
733 bool HasZcmt = Exts.count("zcmt") != 0;
734
735 if (HasI && HasE)
736 return getError("'I' and 'E' extensions are incompatible");
737
738 if (HasF && HasZfinx)
739 return getError("'f' and 'zfinx' extensions are incompatible");
740
741 if (HasZvl && !HasVector)
742 return getError(
743 "'zvl*b' requires 'v' or 'zve*' extension to also be specified");
744
745 if (Exts.count("zvbb") && !HasVector)
746 return getError(
747 "'zvbb' requires 'v' or 'zve*' extension to also be specified");
748
749 if (Exts.count("zvbc") && !Exts.count("zve64x"))
750 return getError(
751 "'zvbc' requires 'v' or 'zve64*' extension to also be specified");
752
753 if ((Exts.count("zvkb") || Exts.count("zvkg") || Exts.count("zvkned") ||
754 Exts.count("zvknha") || Exts.count("zvksed") || Exts.count("zvksh")) &&
755 !HasVector)
756 return getError(
757 "'zvk*' requires 'v' or 'zve*' extension to also be specified");
758
759 if (Exts.count("zvknhb") && !Exts.count("zve64x"))
760 return getError(
761 "'zvknhb' requires 'v' or 'zve64*' extension to also be specified");
762
763 if ((HasZcmt || Exts.count("zcmp")) && HasD && (HasC || Exts.count("zcd")))
764 return getError(Twine("'") + (HasZcmt ? "zcmt" : "zcmp") +
765 "' extension is incompatible with '" +
766 (HasC ? "c" : "zcd") +
767 "' extension when 'd' extension is enabled");
768
769 if (XLen != 32 && Exts.count("zcf"))
770 return getError("'zcf' is only supported for 'rv32'");
771
772 if (Exts.count("zacas") && !(Exts.count("a") || Exts.count("zaamo")))
773 return getError(
774 "'zacas' requires 'a' or 'zaamo' extension to also be specified");
775
776 if (Exts.count("zabha") && !(Exts.count("a") || Exts.count("zaamo")))
777 return getError(
778 "'zabha' requires 'a' or 'zaamo' extension to also be specified");
779
780 if (Exts.count("xwchc") != 0) {
781 if (XLen != 32)
782 return getError("'Xwchc' is only supported for 'rv32'");
783
784 if (HasD)
785 return getError("'D' and 'Xwchc' extensions are incompatible");
786
787 if (Exts.count("zcb") != 0)
788 return getError("'Xwchc' and 'Zcb' extensions are incompatible");
789 }
790
791 return Error::success();
792}
793
796 const char *ImpliedExt;
797
798 bool operator<(const ImpliedExtsEntry &Other) const {
799 return Name < Other.Name;
800 }
801};
802
803static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS) {
804 return LHS.Name < RHS;
805}
806
807static bool operator<(StringRef LHS, const ImpliedExtsEntry &RHS) {
808 return LHS < RHS.Name;
809}
810
811#define GET_IMPLIED_EXTENSIONS
812#include "llvm/TargetParser/RISCVTargetParserDef.inc"
813
814void RISCVISAInfo::updateImplication() {
815 bool HasE = Exts.count("e") != 0;
816 bool HasI = Exts.count("i") != 0;
817
818 // If not in e extension and i extension does not exist, i extension is
819 // implied
820 if (!HasE && !HasI) {
821 auto Version = findDefaultVersion("i");
822 Exts["i"] = *Version;
823 }
824
825 if (HasE && HasI)
826 Exts.erase("i");
827
828 assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
829
830 // This loop may execute over 1 iteration since implication can be layered
831 // Exits loop if no more implication is applied
833 for (auto const &Ext : Exts)
834 WorkList.push_back(Ext.first);
835
836 while (!WorkList.empty()) {
837 StringRef ExtName = WorkList.pop_back_val();
838 auto Range = std::equal_range(std::begin(ImpliedExts),
839 std::end(ImpliedExts), ExtName);
840 std::for_each(Range.first, Range.second,
841 [&](const ImpliedExtsEntry &Implied) {
842 const char *ImpliedExt = Implied.ImpliedExt;
843 if (Exts.count(ImpliedExt))
844 return;
845 auto Version = findDefaultVersion(ImpliedExt);
846 Exts[ImpliedExt] = *Version;
847 WorkList.push_back(ImpliedExt);
848 });
849 }
850
851 // Add Zcf if Zce and F are enabled on RV32.
852 if (XLen == 32 && Exts.count("zce") && Exts.count("f") &&
853 !Exts.count("zcf")) {
854 auto Version = findDefaultVersion("zcf");
855 Exts["zcf"] = *Version;
856 }
857}
858
859static constexpr StringLiteral CombineIntoExts[] = {
860 {"zk"}, {"zkn"}, {"zks"}, {"zvkn"}, {"zvknc"},
861 {"zvkng"}, {"zvks"}, {"zvksc"}, {"zvksg"},
862};
863
864void RISCVISAInfo::updateCombination() {
865 bool MadeChange = false;
866 do {
867 MadeChange = false;
868 for (StringRef CombineExt : CombineIntoExts) {
869 if (Exts.count(CombineExt.str()))
870 continue;
871
872 // Look up the extension in the ImpliesExt table to find everything it
873 // depends on.
874 auto Range = std::equal_range(std::begin(ImpliedExts),
875 std::end(ImpliedExts), CombineExt);
876 bool HasAllRequiredFeatures = std::all_of(
877 Range.first, Range.second, [&](const ImpliedExtsEntry &Implied) {
878 return Exts.count(Implied.ImpliedExt);
879 });
880 if (HasAllRequiredFeatures) {
881 auto Version = findDefaultVersion(CombineExt);
882 Exts[CombineExt.str()] = *Version;
883 MadeChange = true;
884 }
885 }
886 } while (MadeChange);
887}
888
889void RISCVISAInfo::updateImpliedLengths() {
890 assert(FLen == 0 && MaxELenFp == 0 && MaxELen == 0 && MinVLen == 0 &&
891 "Expected lengths to be initialied to zero");
892
893 // TODO: Handle q extension.
894 if (Exts.count("d"))
895 FLen = 64;
896 else if (Exts.count("f"))
897 FLen = 32;
898
899 if (Exts.count("v")) {
900 MaxELenFp = std::max(MaxELenFp, 64u);
901 MaxELen = std::max(MaxELen, 64u);
902 }
903
904 for (auto const &Ext : Exts) {
905 StringRef ExtName = Ext.first;
906 // Infer MaxELen and MaxELenFp from Zve(32/64)(x/f/d)
907 if (ExtName.consume_front("zve")) {
908 unsigned ZveELen;
909 if (ExtName.consumeInteger(10, ZveELen))
910 continue;
911
912 if (ExtName == "f")
913 MaxELenFp = std::max(MaxELenFp, 32u);
914 else if (ExtName == "d")
915 MaxELenFp = std::max(MaxELenFp, 64u);
916 else if (ExtName != "x")
917 continue;
918
919 MaxELen = std::max(MaxELen, ZveELen);
920 continue;
921 }
922
923 // Infer MinVLen from zvl*b.
924 if (ExtName.consume_front("zvl")) {
925 unsigned ZvlLen;
926 if (ExtName.consumeInteger(10, ZvlLen))
927 continue;
928
929 if (ExtName != "b")
930 continue;
931
932 MinVLen = std::max(MinVLen, ZvlLen);
933 continue;
934 }
935 }
936}
937
938std::string RISCVISAInfo::toString() const {
939 std::string Buffer;
940 raw_string_ostream Arch(Buffer);
941
942 Arch << "rv" << XLen;
943
944 ListSeparator LS("_");
945 for (auto const &Ext : Exts) {
946 StringRef ExtName = Ext.first;
947 auto ExtInfo = Ext.second;
948 Arch << LS << ExtName;
949 Arch << ExtInfo.Major << "p" << ExtInfo.Minor;
950 }
951
952 return Arch.str();
953}
954
956RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
957 ISAInfo->updateImplication();
958 ISAInfo->updateCombination();
959 ISAInfo->updateImpliedLengths();
960
961 if (Error Result = ISAInfo->checkDependency())
962 return std::move(Result);
963 return std::move(ISAInfo);
964}
965
967 if (XLen == 32) {
968 if (Exts.count("e"))
969 return "ilp32e";
970 if (Exts.count("d"))
971 return "ilp32d";
972 if (Exts.count("f"))
973 return "ilp32f";
974 return "ilp32";
975 } else if (XLen == 64) {
976 if (Exts.count("e"))
977 return "lp64e";
978 if (Exts.count("d"))
979 return "lp64d";
980 if (Exts.count("f"))
981 return "lp64f";
982 return "lp64";
983 }
984 llvm_unreachable("Invalid XLEN");
985}
986
988 if (Ext.empty())
989 return false;
990
991 auto Pos = findLastNonVersionCharacter(Ext) + 1;
992 StringRef Name = Ext.substr(0, Pos);
993 StringRef Vers = Ext.substr(Pos);
994 if (Vers.empty())
995 return false;
996
997 unsigned Major, Minor, ConsumeLength;
998 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
999 true, true)) {
1000 consumeError(std::move(E));
1001 return false;
1002 }
1003
1004 return true;
1005}
1006
1008 if (Ext.empty())
1009 return std::string();
1010
1011 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1012 StringRef Name = Ext.substr(0, Pos);
1013
1014 if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext))
1015 return std::string();
1016
1018 return std::string();
1019
1020 return isExperimentalExtension(Name) ? "experimental-" + Name.str()
1021 : Name.str();
1022}
1023
1026 uint8_t bitpos;
1027};
1028
1029/// Maps extensions with assigned bit positions within group 0 of
1030/// __riscv_features_bits to their respective bit position. At the
1031/// moment all extensions are within group 0.
1033 {"a", 0}, {"c", 2},
1034 {"d", 3}, {"f", 5},
1035 {"i", 8}, {"m", 12},
1036 {"v", 21}, {"zacas", 26},
1037 {"zba", 27}, {"zbb", 28},
1038 {"zbc", 29}, {"zbkb", 30},
1039 {"zbkc", 31}, {"zbkx", 32},
1040 {"zbs", 33}, {"zfa", 34},
1041 {"zfh", 35}, {"zfhmin", 36},
1042 {"zicboz", 37}, {"zicond", 38},
1043 {"zihintntl", 39}, {"zihintpause", 40},
1044 {"zknd", 41}, {"zkne", 42},
1045 {"zknh", 43}, {"zksed", 44},
1046 {"zksh", 45}, {"zkt", 46},
1047 {"ztso", 47}, {"zvbb", 48},
1048 {"zvbc", 49}, {"zvfh", 50},
1049 {"zvfhmin", 51}, {"zvkb", 52},
1050 {"zvkg", 53}, {"zvkned", 54},
1051 {"zvknha", 55}, {"zvknhb", 56},
1052 {"zvksed", 57}, {"zvksh", 58},
1053 {"zvkt", 59}};
1055 // Note that this code currently accepts mixed case extension names, but
1056 // does not handle extension versions at all. That's probably fine because
1057 // there's only one extension version in the __riscv_feature_bits vector.
1058 for (auto E : RISCVGroup0BitPositions)
1059 if (E.ext.equals_insensitive(Ext))
1060 return E.bitpos;
1061 return -1;
1062}
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:1294
#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 constexpr RISCVExtBit RISCVGroup0BitPositions[]
Maps extensions with assigned bit positions within group 0 of __riscv_features_bits to their respecti...
static StringRef getExtensionTypeDesc(StringRef Ext)
static std::optional< RISCVISAUtils::ExtensionVersion > findDefaultVersion(StringRef ExtName)
static size_t findLastNonVersionCharacter(StringRef Ext)
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 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 int getRISCVFeaturesBitPosition(StringRef Ext)
Return the bit position (in group 0) 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: InstrProf.h:1107
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: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:1902
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: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