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