LLVM 19.0.0git
RISCVISAInfo.cpp
Go to the documentation of this file.
1//===-- RISCVISAInfo.cpp - RISC-V Arch String Parser ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "llvm/ADT/MapVector.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/SetVector.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/Errc.h"
16#include "llvm/Support/Error.h"
18
19#include <array>
20#include <atomic>
21#include <optional>
22#include <string>
23#include <vector>
24
25using namespace llvm;
26
27namespace {
28
29struct RISCVSupportedExtension {
30 const char *Name;
31 /// Supported version.
33
34 bool operator<(const RISCVSupportedExtension &RHS) const {
35 return StringRef(Name) < StringRef(RHS.Name);
36 }
37};
38
39struct RISCVProfile {
41 StringLiteral MArch;
42};
43
44} // end anonymous namespace
45
46static const char *RISCVGImplications[] = {
47 "i", "m", "a", "f", "d", "zicsr", "zifencei"
48};
49
50#define GET_SUPPORTED_EXTENSIONS
51#include "llvm/TargetParser/RISCVTargetParserDef.inc"
52
53static constexpr RISCVProfile SupportedProfiles[] = {
54 {"rvi20u32", "rv32i"},
55 {"rvi20u64", "rv64i"},
56 {"rva20u64", "rv64imafdc_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_za128rs"},
57 {"rva20s64", "rv64imafdc_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zifencei_"
58 "za128rs_ssccptr_sstvala_sstvecd_svade_svbare"},
59 {"rva22u64",
60 "rv64imafdc_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_"
61 "zicntr_zihintpause_zihpm_za64rs_zfhmin_zba_zbb_zbs_zkt"},
62 {"rva22s64",
63 "rv64imafdc_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_"
64 "zicntr_zifencei_zihintpause_zihpm_za64rs_zfhmin_zba_zbb_zbs_zkt_ssccptr_"
65 "sscounterenw_sstvala_sstvecd_svade_svbare_svinval_svpbmt"},
66 {"rva23u64",
67 "rv64imafdcv_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_"
68 "zicntr_zicond_zihintntl_zihintpause_zihpm_zimop_za64rs_zawrs_zfa_zfhmin_"
69 "zcb_zcmop_zba_zbb_zbs_zkt_zvbb_zvfhmin_zvkt"},
70 {"rva23s64",
71 "rv64imafdcvh_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_"
72 "zicntr_zicond_zifencei_zihintntl_zihintpause_zihpm_zimop_za64rs_zawrs_"
73 "zfa_zfhmin_zcb_zcmop_zba_zbb_zbs_zkt_zvbb_zvfhmin_zvkt_shcounterenw_"
74 "shgatpa_shtvala_shvsatpa_shvstvala_shvstvecd_ssccptr_sscofpmf_"
75 "sscounterenw_ssnpm0p8_ssstateen_sstc_sstvala_sstvecd_ssu64xl_svade_"
76 "svbare_svinval_svnapot_svpbmt"},
77 {"rvb23u64", "rv64imafdc_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_"
78 "zicclsm_ziccrse_zicntr_zicond_zihintntl_zihintpause_zihpm_"
79 "zimop_za64rs_zawrs_zfa_zcb_zcmop_zba_zbb_zbs_zkt"},
80 {"rvb23s64",
81 "rv64imafdc_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_"
82 "zicntr_zicond_zifencei_zihintntl_zihintpause_zihpm_zimop_za64rs_zawrs_"
83 "zfa_zcb_zcmop_zba_zbb_zbs_zkt_ssccptr_sscofpmf_sscounterenw_sstc_sstvala_"
84 "sstvecd_ssu64xl_svade_svbare_svinval_svnapot_svpbmt"},
85 {"rvm23u32", "rv32im_zicbop_zicond_zicsr_zihintntl_zihintpause_zimop_zca_"
86 "zcb_zce_zcmop_zcmp_zcmt_zba_zbb_zbs"},
87};
88
89static void verifyTables() {
90#ifndef NDEBUG
91 static std::atomic<bool> TableChecked(false);
92 if (!TableChecked.load(std::memory_order_relaxed)) {
93 assert(llvm::is_sorted(SupportedExtensions) &&
94 "Extensions are not sorted by name");
95 assert(llvm::is_sorted(SupportedExperimentalExtensions) &&
96 "Experimental extensions are not sorted by name");
97 TableChecked.store(true, std::memory_order_relaxed);
98 }
99#endif
100}
101
103 StringRef Description) {
104 outs().indent(4);
105 unsigned VersionWidth = Description.empty() ? 0 : 10;
106 outs() << left_justify(Name, 21) << left_justify(Version, VersionWidth)
107 << Description << "\n";
108}
109
111
112 outs() << "All available -march extensions for RISC-V\n\n";
113 PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description"));
114
116 for (const auto &E : SupportedExtensions)
117 ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
118 for (const auto &E : ExtMap) {
119 std::string Version =
120 std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
121 PrintExtension(E.first, Version, DescMap[E.first]);
122 }
123
124 outs() << "\nExperimental extensions\n";
125 ExtMap.clear();
126 for (const auto &E : SupportedExperimentalExtensions)
127 ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
128 for (const auto &E : ExtMap) {
129 std::string Version =
130 std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
131 PrintExtension(E.first, Version, DescMap["experimental-" + E.first]);
132 }
133
134 outs() << "\nUse -march to specify the target's extension.\n"
135 "For example, clang -march=rv32i_v1p0\n";
136}
137
139 return Ext.consume_front("experimental-");
140}
141
142// This function finds the last character that doesn't belong to a version
143// (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will
144// consume [0-9]*p[0-9]* starting from the backward. An extension name will not
145// end with a digit or the letter 'p', so this function will parse correctly.
146// NOTE: This function is NOT able to take empty strings or strings that only
147// have version numbers and no extension name. It assumes the extension name
148// will be at least more than one character.
150 assert(!Ext.empty() &&
151 "Already guarded by if-statement in ::parseArchString");
152
153 int Pos = Ext.size() - 1;
154 while (Pos > 0 && isDigit(Ext[Pos]))
155 Pos--;
156 if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {
157 Pos--;
158 while (Pos > 0 && isDigit(Ext[Pos]))
159 Pos--;
160 }
161 return Pos;
162}
163
164namespace {
165struct LessExtName {
166 bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) {
167 return StringRef(LHS.Name) < RHS;
168 }
169 bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) {
170 return LHS < StringRef(RHS.Name);
171 }
172};
173} // namespace
174
175static std::optional<RISCVISAUtils::ExtensionVersion>
177 // Find default version of an extension.
178 // TODO: We might set default version based on profile or ISA spec.
179 for (auto &ExtInfo : {ArrayRef(SupportedExtensions),
180 ArrayRef(SupportedExperimentalExtensions)}) {
181 auto I = llvm::lower_bound(ExtInfo, ExtName, LessExtName());
182
183 if (I == ExtInfo.end() || I->Name != ExtName)
184 continue;
185
186 return I->Version;
187 }
188 return std::nullopt;
189}
190
191void RISCVISAInfo::addExtension(StringRef ExtName,
193 Exts[ExtName.str()] = Version;
194}
195
197 if (Ext.starts_with("s"))
198 return "standard supervisor-level extension";
199 if (Ext.starts_with("x"))
200 return "non-standard user-level extension";
201 if (Ext.starts_with("z"))
202 return "standard user-level extension";
203 return StringRef();
204}
205
207 if (Ext.starts_with("s"))
208 return "s";
209 if (Ext.starts_with("x"))
210 return "x";
211 if (Ext.starts_with("z"))
212 return "z";
213 return StringRef();
214}
215
216static std::optional<RISCVISAUtils::ExtensionVersion>
218 auto I =
219 llvm::lower_bound(SupportedExperimentalExtensions, Ext, LessExtName());
220 if (I == std::end(SupportedExperimentalExtensions) || I->Name != Ext)
221 return std::nullopt;
222
223 return I->Version;
224}
225
227 bool IsExperimental = stripExperimentalPrefix(Ext);
228
230 IsExperimental ? ArrayRef(SupportedExperimentalExtensions)
231 : ArrayRef(SupportedExtensions);
232
233 auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
234 return I != ExtInfo.end() && I->Name == Ext;
235}
236
238 verifyTables();
239
240 for (auto ExtInfo : {ArrayRef(SupportedExtensions),
241 ArrayRef(SupportedExperimentalExtensions)}) {
242 auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
243 if (I != ExtInfo.end() && I->Name == Ext)
244 return true;
245 }
246
247 return false;
248}
249
250bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
251 unsigned MinorVersion) {
252 for (auto ExtInfo : {ArrayRef(SupportedExtensions),
253 ArrayRef(SupportedExperimentalExtensions)}) {
254 auto Range =
255 std::equal_range(ExtInfo.begin(), ExtInfo.end(), Ext, LessExtName());
256 for (auto I = Range.first, E = Range.second; I != E; ++I)
257 if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion)
258 return true;
259 }
260
261 return false;
262}
263
266
267 if (!isSupportedExtension(Ext))
268 return false;
269
270 return Exts.count(Ext.str()) != 0;
271}
272
273std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions,
274 bool IgnoreUnknown) const {
275 std::vector<std::string> Features;
276 for (const auto &[ExtName, _] : Exts) {
277 // i is a base instruction set, not an extension (see
278 // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa)
279 // and is not recognized in clang -cc1
280 if (ExtName == "i")
281 continue;
282 if (IgnoreUnknown && !isSupportedExtension(ExtName))
283 continue;
284
285 if (isExperimentalExtension(ExtName)) {
286 Features.push_back((llvm::Twine("+experimental-") + ExtName).str());
287 } else {
288 Features.push_back((llvm::Twine("+") + ExtName).str());
289 }
290 }
291 if (AddAllExtensions) {
292 for (const RISCVSupportedExtension &Ext : SupportedExtensions) {
293 if (Exts.count(Ext.Name))
294 continue;
295 Features.push_back((llvm::Twine("-") + Ext.Name).str());
296 }
297
298 for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {
299 if (Exts.count(Ext.Name))
300 continue;
301 Features.push_back((llvm::Twine("-experimental-") + Ext.Name).str());
302 }
303 }
304 return Features;
305}
306
307static Error getStringErrorForInvalidExt(std::string_view ExtName) {
308 if (ExtName.size() == 1) {
310 "unsupported standard user-level extension '" +
311 ExtName + "'");
312 }
314 "unsupported " + getExtensionTypeDesc(ExtName) +
315 " '" + ExtName + "'");
316}
317
318// Extensions may have a version number, and may be separated by
319// an underscore '_' e.g.: rv32i2_m2.
320// Version number is divided into major and minor version numbers,
321// separated by a 'p'. If the minor version is 0 then 'p0' can be
322// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
323static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
324 unsigned &Minor, unsigned &ConsumeLength,
325 bool EnableExperimentalExtension,
326 bool ExperimentalExtensionVersionCheck) {
327 StringRef MajorStr, MinorStr;
328 Major = 0;
329 Minor = 0;
330 ConsumeLength = 0;
331 MajorStr = In.take_while(isDigit);
332 In = In.substr(MajorStr.size());
333
334 if (!MajorStr.empty() && In.consume_front("p")) {
335 MinorStr = In.take_while(isDigit);
336 In = In.substr(MajorStr.size() + MinorStr.size() - 1);
337
338 // Expected 'p' to be followed by minor version number.
339 if (MinorStr.empty()) {
340 return createStringError(
342 "minor version number missing after 'p' for extension '" + Ext + "'");
343 }
344 }
345
346 if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
347 return createStringError(
349 "Failed to parse major version number for extension '" + Ext + "'");
350
351 if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
352 return createStringError(
354 "Failed to parse minor version number for extension '" + Ext + "'");
355
356 ConsumeLength = MajorStr.size();
357
358 if (!MinorStr.empty())
359 ConsumeLength += MinorStr.size() + 1 /*'p'*/;
360
361 // Expected multi-character extension with version number to have no
362 // subsequent characters (i.e. must either end string or be followed by
363 // an underscore).
364 if (Ext.size() > 1 && In.size())
365 return createStringError(
367 "multi-character extensions must be separated by underscores");
368
369 // If experimental extension, require use of current version number
370 if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
371 if (!EnableExperimentalExtension)
373 "requires '-menable-experimental-extensions' "
374 "for experimental extension '" +
375 Ext + "'");
376
377 if (ExperimentalExtensionVersionCheck &&
378 (MajorStr.empty() && MinorStr.empty()))
379 return createStringError(
381 "experimental extension requires explicit version number `" + Ext +
382 "`");
383
384 auto SupportedVers = *ExperimentalExtension;
385 if (ExperimentalExtensionVersionCheck &&
386 (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
387 std::string Error = "unsupported version number " + MajorStr.str();
388 if (!MinorStr.empty())
389 Error += "." + MinorStr.str();
390 Error += " for experimental extension '" + Ext.str() +
391 "' (this compiler supports " + utostr(SupportedVers.Major) +
392 "." + utostr(SupportedVers.Minor) + ")";
394 }
395 return Error::success();
396 }
397
398 // Exception rule for `g`, we don't have clear version scheme for that on
399 // ISA spec.
400 if (Ext == "g")
401 return Error::success();
402
403 if (MajorStr.empty() && MinorStr.empty()) {
404 if (auto DefaultVersion = findDefaultVersion(Ext)) {
405 Major = DefaultVersion->Major;
406 Minor = DefaultVersion->Minor;
407 }
408 // No matter found or not, return success, assume other place will
409 // verify.
410 return Error::success();
411 }
412
413 if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
414 return Error::success();
415
417 return getStringErrorForInvalidExt(Ext);
418
419 std::string Error = "unsupported version number " + std::string(MajorStr);
420 if (!MinorStr.empty())
421 Error += "." + MinorStr.str();
422 Error += " for extension '" + Ext.str() + "'";
424}
425
428 const std::vector<std::string> &Features) {
429 assert(XLen == 32 || XLen == 64);
430 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
431
432 for (auto &Feature : Features) {
433 StringRef ExtName = Feature;
434 bool Experimental = false;
435 assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
436 bool Add = ExtName[0] == '+';
437 ExtName = ExtName.drop_front(1); // Drop '+' or '-'
438 Experimental = stripExperimentalPrefix(ExtName);
439 auto ExtensionInfos = Experimental
440 ? ArrayRef(SupportedExperimentalExtensions)
441 : ArrayRef(SupportedExtensions);
442 auto ExtensionInfoIterator =
443 llvm::lower_bound(ExtensionInfos, ExtName, LessExtName());
444
445 // Not all features is related to ISA extension, like `relax` or
446 // `save-restore`, skip those feature.
447 if (ExtensionInfoIterator == ExtensionInfos.end() ||
448 ExtensionInfoIterator->Name != ExtName)
449 continue;
450
451 if (Add)
452 ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version);
453 else
454 ISAInfo->Exts.erase(ExtName.str());
455 }
456
457 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
458}
459
462 if (llvm::any_of(Arch, isupper)) {
464 "string must be lowercase");
465 }
466 // Must start with a valid base ISA name.
467 unsigned XLen;
468 if (Arch.starts_with("rv32i") || Arch.starts_with("rv32e"))
469 XLen = 32;
470 else if (Arch.starts_with("rv64i") || Arch.starts_with("rv64e"))
471 XLen = 64;
472 else
474 "arch string must begin with valid base ISA");
475 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
476 // Discard rv32/rv64 prefix.
477 Arch = Arch.substr(4);
478
479 // Each extension is of the form ${name}${major_version}p${minor_version}
480 // and separated by _. Split by _ and then extract the name and version
481 // information for each extension.
483 Arch.split(Split, '_');
484 for (StringRef Ext : Split) {
485 StringRef Prefix, MinorVersionStr;
486 std::tie(Prefix, MinorVersionStr) = Ext.rsplit('p');
487 if (MinorVersionStr.empty())
489 "extension lacks version in expected format");
490 unsigned MajorVersion, MinorVersion;
491 if (MinorVersionStr.getAsInteger(10, MinorVersion))
493 "failed to parse minor version number");
494
495 // Split Prefix into the extension name and the major version number
496 // (the trailing digits of Prefix).
497 int TrailingDigits = 0;
498 StringRef ExtName = Prefix;
499 while (!ExtName.empty()) {
500 if (!isDigit(ExtName.back()))
501 break;
502 ExtName = ExtName.drop_back(1);
503 TrailingDigits++;
504 }
505 if (!TrailingDigits)
507 "extension lacks version in expected format");
508
509 StringRef MajorVersionStr = Prefix.take_back(TrailingDigits);
510 if (MajorVersionStr.getAsInteger(10, MajorVersion))
512 "failed to parse major version number");
513 ISAInfo->addExtension(ExtName, {MajorVersion, MinorVersion});
514 }
515 ISAInfo->updateFLen();
516 ISAInfo->updateMinVLen();
517 ISAInfo->updateMaxELen();
518 return std::move(ISAInfo);
519}
520
522 std::vector<std::string> &SplitExts) {
524 if (Exts.empty())
525 return Error::success();
526
527 Exts.split(Split, "_");
528
529 for (auto Ext : Split) {
530 if (Ext.empty())
532 "extension name missing after separator '_'");
533
534 SplitExts.push_back(Ext.str());
535 }
536 return Error::success();
537}
538
540 StringRef RawExt,
542 std::map<std::string, unsigned>> &SeenExtMap,
543 bool IgnoreUnknown, bool EnableExperimentalExtension,
544 bool ExperimentalExtensionVersionCheck) {
547 auto Pos = findLastNonVersionCharacter(RawExt) + 1;
548 StringRef Name(RawExt.substr(0, Pos));
549 StringRef Vers(RawExt.substr(Pos));
550
551 if (Type.empty()) {
552 if (IgnoreUnknown)
553 return Error::success();
555 "invalid extension prefix '" + RawExt + "'");
556 }
557
558 if (!IgnoreUnknown && Name.size() == Type.size())
560 Desc + " name missing after '" + Type + "'");
561
562 unsigned Major, Minor, ConsumeLength;
563 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
564 EnableExperimentalExtension,
565 ExperimentalExtensionVersionCheck)) {
566 if (IgnoreUnknown) {
567 consumeError(std::move(E));
568 return Error::success();
569 }
570 return E;
571 }
572
573 // Check if duplicated extension.
574 if (!IgnoreUnknown && SeenExtMap.contains(Name.str()))
576 "duplicated " + Desc + " '" + Name + "'");
577
578 if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Name))
579 return Error::success();
580
581 SeenExtMap[Name.str()] = {Major, Minor};
582 return Error::success();
583}
584
586 StringRef &RawExt,
588 std::map<std::string, unsigned>> &SeenExtMap,
589 bool IgnoreUnknown, bool EnableExperimentalExtension,
590 bool ExperimentalExtensionVersionCheck) {
591 unsigned Major, Minor, ConsumeLength;
592 StringRef Name = RawExt.take_front(1);
593 RawExt.consume_front(Name);
594 if (auto E = getExtensionVersion(Name, RawExt, Major, Minor, ConsumeLength,
595 EnableExperimentalExtension,
596 ExperimentalExtensionVersionCheck)) {
597 if (IgnoreUnknown) {
598 consumeError(std::move(E));
599 RawExt = RawExt.substr(ConsumeLength);
600 return Error::success();
601 }
602 return E;
603 }
604
605 RawExt = RawExt.substr(ConsumeLength);
606
607 // Check if duplicated extension.
608 if (!IgnoreUnknown && SeenExtMap.contains(Name.str()))
610 "duplicated standard user-level extension '" +
611 Name + "'");
612
613 if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Name))
614 return Error::success();
615
616 SeenExtMap[Name.str()] = {Major, Minor};
617 return Error::success();
618}
619
621RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
622 bool ExperimentalExtensionVersionCheck,
623 bool IgnoreUnknown) {
624 // RISC-V ISA strings must be lowercase.
625 if (llvm::any_of(Arch, isupper)) {
627 "string must be lowercase");
628 }
629
630 if (Arch.starts_with("rvi") || Arch.starts_with("rva") ||
631 Arch.starts_with("rvb") || Arch.starts_with("rvm")) {
632 const auto *FoundProfile =
633 llvm::find_if(SupportedProfiles, [Arch](const RISCVProfile &Profile) {
634 return Arch.starts_with(Profile.Name);
635 });
636
637 if (FoundProfile == std::end(SupportedProfiles))
638 return createStringError(errc::invalid_argument, "unsupported profile");
639
640 std::string NewArch = FoundProfile->MArch.str();
641 StringRef ArchWithoutProfile = Arch.substr(FoundProfile->Name.size());
642 if (!ArchWithoutProfile.empty()) {
643 if (!ArchWithoutProfile.starts_with("_"))
644 return createStringError(
646 "additional extensions must be after separator '_'");
647 NewArch += ArchWithoutProfile.str();
648 }
649 return parseArchString(NewArch, EnableExperimentalExtension,
650 ExperimentalExtensionVersionCheck, IgnoreUnknown);
651 }
652
653 bool HasRV64 = Arch.starts_with("rv64");
654 // ISA string must begin with rv32 or rv64.
655 if (!(Arch.starts_with("rv32") || HasRV64) || (Arch.size() < 5)) {
656 return createStringError(
658 "string must begin with rv32{i,e,g} or rv64{i,e,g}");
659 }
660
661 unsigned XLen = HasRV64 ? 64 : 32;
662 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
664 std::map<std::string, unsigned>>
665 SeenExtMap;
666
667 // The canonical order specified in ISA manual.
668 // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
669 char Baseline = Arch[4];
670
671 // First letter should be 'e', 'i' or 'g'.
672 switch (Baseline) {
673 default:
675 "first letter should be 'e', 'i' or 'g'");
676 case 'e':
677 case 'i':
678 break;
679 case 'g':
680 // g expands to extensions in RISCVGImplications.
681 if (Arch.size() > 5 && isDigit(Arch[5]))
683 "version not supported for 'g'");
684 break;
685 }
686
687 if (Arch.back() == '_')
689 "extension name missing after separator '_'");
690
691 // Skip rvxxx
692 StringRef Exts = Arch.substr(5);
693
694 unsigned Major, Minor, ConsumeLength;
695 if (Baseline == 'g') {
696 // Versions for g are disallowed, and this was checked for previously.
697 ConsumeLength = 0;
698
699 // No matter which version is given to `g`, we always set imafd to default
700 // version since the we don't have clear version scheme for that on
701 // ISA spec.
702 for (const auto *Ext : RISCVGImplications) {
703 if (auto Version = findDefaultVersion(Ext)) {
704 // Postpone AddExtension until end of this function
705 SeenExtMap[Ext] = {Version->Major, Version->Minor};
706 } else
707 llvm_unreachable("Default extension version not found?");
708 }
709 } else {
710 // Baseline is `i` or `e`
711 if (auto E = getExtensionVersion(
712 StringRef(&Baseline, 1), Exts, Major, Minor, ConsumeLength,
713 EnableExperimentalExtension, ExperimentalExtensionVersionCheck)) {
714 if (!IgnoreUnknown)
715 return std::move(E);
716 // If IgnoreUnknown, then ignore an unrecognised version of the baseline
717 // ISA and just use the default supported version.
718 consumeError(std::move(E));
719 auto Version = findDefaultVersion(StringRef(&Baseline, 1));
720 Major = Version->Major;
721 Minor = Version->Minor;
722 }
723
724 // Postpone AddExtension until end of this function
725 SeenExtMap[StringRef(&Baseline, 1).str()] = {Major, Minor};
726 }
727
728 // Consume the base ISA version number and any '_' between rvxxx and the
729 // first extension
730 Exts = Exts.drop_front(ConsumeLength);
731 Exts.consume_front("_");
732
733 std::vector<std::string> SplitExts;
734 if (auto E = splitExtsByUnderscore(Exts, SplitExts))
735 return std::move(E);
736
737 for (auto &Ext : SplitExts) {
738 StringRef CurrExt = Ext;
739 while (!CurrExt.empty()) {
741 if (auto E = processSingleLetterExtension(
742 CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension,
743 ExperimentalExtensionVersionCheck))
744 return std::move(E);
745 } else if (CurrExt.front() == 'z' || CurrExt.front() == 's' ||
746 CurrExt.front() == 'x') {
747 // Handle other types of extensions other than the standard
748 // general purpose and standard user-level extensions.
749 // Parse the ISA string containing non-standard user-level
750 // extensions, standard supervisor-level extensions and
751 // non-standard supervisor-level extensions.
752 // These extensions start with 'z', 's', 'x' prefixes, might have a
753 // version number (major, minor) and are separated by a single
754 // underscore '_'. We do not enforce a canonical order for them.
755 if (auto E = processMultiLetterExtension(
756 CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension,
757 ExperimentalExtensionVersionCheck))
758 return std::move(E);
759 // Multi-letter extension must be seperate following extension with
760 // underscore
761 break;
762 } else {
763 // FIXME: Could it be ignored by IgnoreUnknown?
765 "invalid standard user-level extension '" +
766 Twine(CurrExt.front()) + "'");
767 }
768 }
769 }
770
771 // Check all Extensions are supported.
772 for (auto &SeenExtAndVers : SeenExtMap) {
773 const std::string &ExtName = SeenExtAndVers.first;
774 RISCVISAUtils::ExtensionVersion ExtVers = SeenExtAndVers.second;
775
777 return getStringErrorForInvalidExt(ExtName);
778 ISAInfo->addExtension(ExtName, ExtVers);
779 }
780
781 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
782}
783
784Error RISCVISAInfo::checkDependency() {
785 bool HasC = Exts.count("c") != 0;
786 bool HasF = Exts.count("f") != 0;
787 bool HasZfinx = Exts.count("zfinx") != 0;
788 bool HasVector = Exts.count("zve32x") != 0;
789 bool HasZvl = MinVLen != 0;
790 bool HasZcmt = Exts.count("zcmt") != 0;
791
792 if (HasF && HasZfinx)
794 "'f' and 'zfinx' extensions are incompatible");
795
796 if (HasZvl && !HasVector)
797 return createStringError(
799 "'zvl*b' requires 'v' or 'zve*' extension to also be specified");
800
801 if (Exts.count("zvbb") && !HasVector)
802 return createStringError(
804 "'zvbb' requires 'v' or 'zve*' extension to also be specified");
805
806 if (Exts.count("zvbc") && !Exts.count("zve64x"))
807 return createStringError(
809 "'zvbc' requires 'v' or 'zve64*' extension to also be specified");
810
811 if ((Exts.count("zvkb") || Exts.count("zvkg") || Exts.count("zvkned") ||
812 Exts.count("zvknha") || Exts.count("zvksed") || Exts.count("zvksh")) &&
813 !HasVector)
814 return createStringError(
816 "'zvk*' requires 'v' or 'zve*' extension to also be specified");
817
818 if (Exts.count("zvknhb") && !Exts.count("zve64x"))
819 return createStringError(
821 "'zvknhb' requires 'v' or 'zve64*' extension to also be specified");
822
823 if ((HasZcmt || Exts.count("zcmp")) && Exts.count("d") &&
824 (HasC || Exts.count("zcd")))
825 return createStringError(
827 Twine("'") + (HasZcmt ? "zcmt" : "zcmp") +
828 "' extension is incompatible with '" + (HasC ? "c" : "zcd") +
829 "' extension when 'd' extension is enabled");
830
831 if (XLen != 32 && Exts.count("zcf"))
833 "'zcf' is only supported for 'rv32'");
834
835 if (Exts.count("zacas") && !(Exts.count("a") || Exts.count("zamo")))
836 return createStringError(
838 "'zacas' requires 'a' or 'zaamo' extension to also be specified");
839
840 if (Exts.count("zabha") && !(Exts.count("a") || Exts.count("zamo")))
841 return createStringError(
843 "'zabha' requires 'a' or 'zaamo' extension to also be specified");
844
845 return Error::success();
846}
847
850 const char *ImpliedExt;
851
852 bool operator<(const ImpliedExtsEntry &Other) const {
853 return Name < Other.Name;
854 }
855};
856
857static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS) {
858 return LHS.Name < RHS;
859}
860
861static bool operator<(StringRef LHS, const ImpliedExtsEntry &RHS) {
862 return LHS < RHS.Name;
863}
864
865#define GET_IMPLIED_EXTENSIONS
866#include "llvm/TargetParser/RISCVTargetParserDef.inc"
867
868void RISCVISAInfo::updateImplication() {
869 bool HasE = Exts.count("e") != 0;
870 bool HasI = Exts.count("i") != 0;
871
872 // If not in e extension and i extension does not exist, i extension is
873 // implied
874 if (!HasE && !HasI) {
875 auto Version = findDefaultVersion("i");
876 addExtension("i", Version.value());
877 }
878
879 assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
880
881 // This loop may execute over 1 iteration since implication can be layered
882 // Exits loop if no more implication is applied
884 for (auto const &Ext : Exts)
885 WorkList.insert(Ext.first);
886
887 while (!WorkList.empty()) {
888 StringRef ExtName = WorkList.pop_back_val();
889 auto Range = std::equal_range(std::begin(ImpliedExts),
890 std::end(ImpliedExts), ExtName);
891 std::for_each(Range.first, Range.second,
892 [&](const ImpliedExtsEntry &Implied) {
893 const char *ImpliedExt = Implied.ImpliedExt;
894 if (WorkList.count(ImpliedExt))
895 return;
896 if (Exts.count(ImpliedExt))
897 return;
898 auto Version = findDefaultVersion(ImpliedExt);
899 addExtension(ImpliedExt, Version.value());
900 WorkList.insert(ImpliedExt);
901 });
902 }
903
904 // Add Zcf if Zce and F are enabled on RV32.
905 if (XLen == 32 && Exts.count("zce") && Exts.count("f") &&
906 !Exts.count("zcf")) {
907 auto Version = findDefaultVersion("zcf");
908 addExtension("zcf", Version.value());
909 }
910}
911
912static constexpr StringLiteral CombineIntoExts[] = {
913 {"zk"}, {"zkn"}, {"zks"}, {"zvkn"}, {"zvknc"},
914 {"zvkng"}, {"zvks"}, {"zvksc"}, {"zvksg"},
915};
916
917void RISCVISAInfo::updateCombination() {
918 bool MadeChange = false;
919 do {
920 MadeChange = false;
921 for (StringRef CombineExt : CombineIntoExts) {
922 if (hasExtension(CombineExt))
923 continue;
924
925 // Look up the extension in the ImpliesExt table to find everything it
926 // depends on.
927 auto Range = std::equal_range(std::begin(ImpliedExts),
928 std::end(ImpliedExts), CombineExt);
929 bool HasAllRequiredFeatures = std::all_of(
930 Range.first, Range.second, [&](const ImpliedExtsEntry &Implied) {
931 return hasExtension(Implied.ImpliedExt);
932 });
933 if (HasAllRequiredFeatures) {
934 auto Version = findDefaultVersion(CombineExt);
935 addExtension(CombineExt, Version.value());
936 MadeChange = true;
937 }
938 }
939 } while (MadeChange);
940}
941
942void RISCVISAInfo::updateFLen() {
943 FLen = 0;
944 // TODO: Handle q extension.
945 if (Exts.count("d"))
946 FLen = 64;
947 else if (Exts.count("f"))
948 FLen = 32;
949}
950
951void RISCVISAInfo::updateMinVLen() {
952 for (auto const &Ext : Exts) {
953 StringRef ExtName = Ext.first;
954 bool IsZvlExt = ExtName.consume_front("zvl") && ExtName.consume_back("b");
955 if (IsZvlExt) {
956 unsigned ZvlLen;
957 if (!ExtName.getAsInteger(10, ZvlLen))
958 MinVLen = std::max(MinVLen, ZvlLen);
959 }
960 }
961}
962
963void RISCVISAInfo::updateMaxELen() {
964 // handles EEW restriction by sub-extension zve
965 for (auto const &Ext : Exts) {
966 StringRef ExtName = Ext.first;
967 bool IsZveExt = ExtName.consume_front("zve");
968 if (IsZveExt) {
969 if (ExtName.back() == 'f')
970 MaxELenFp = std::max(MaxELenFp, 32u);
971 if (ExtName.back() == 'd')
972 MaxELenFp = std::max(MaxELenFp, 64u);
973 ExtName = ExtName.drop_back();
974 unsigned ZveELen;
975 ExtName.getAsInteger(10, ZveELen);
976 MaxELen = std::max(MaxELen, ZveELen);
977 }
978 }
979}
980
981std::string RISCVISAInfo::toString() const {
982 std::string Buffer;
983 raw_string_ostream Arch(Buffer);
984
985 Arch << "rv" << XLen;
986
987 ListSeparator LS("_");
988 for (auto const &Ext : Exts) {
989 StringRef ExtName = Ext.first;
990 auto ExtInfo = Ext.second;
991 Arch << LS << ExtName;
992 Arch << ExtInfo.Major << "p" << ExtInfo.Minor;
993 }
994
995 return Arch.str();
996}
997
999RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
1000 ISAInfo->updateImplication();
1001 ISAInfo->updateCombination();
1002 ISAInfo->updateFLen();
1003 ISAInfo->updateMinVLen();
1004 ISAInfo->updateMaxELen();
1005
1006 if (Error Result = ISAInfo->checkDependency())
1007 return std::move(Result);
1008 return std::move(ISAInfo);
1009}
1010
1012 if (XLen == 32) {
1013 if (hasExtension("e"))
1014 return "ilp32e";
1015 if (hasExtension("d"))
1016 return "ilp32d";
1017 if (hasExtension("f"))
1018 return "ilp32f";
1019 return "ilp32";
1020 } else if (XLen == 64) {
1021 if (hasExtension("e"))
1022 return "lp64e";
1023 if (hasExtension("d"))
1024 return "lp64d";
1025 if (hasExtension("f"))
1026 return "lp64f";
1027 return "lp64";
1028 }
1029 llvm_unreachable("Invalid XLEN");
1030}
1031
1033 if (Ext.empty())
1034 return false;
1035
1036 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1037 StringRef Name = Ext.substr(0, Pos);
1038 StringRef Vers = Ext.substr(Pos);
1039 if (Vers.empty())
1040 return false;
1041
1042 unsigned Major, Minor, ConsumeLength;
1043 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
1044 true, true)) {
1045 consumeError(std::move(E));
1046 return false;
1047 }
1048
1049 return true;
1050}
1051
1053 if (Ext.empty())
1054 return std::string();
1055
1056 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1057 StringRef Name = Ext.substr(0, Pos);
1058
1059 if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext))
1060 return std::string();
1061
1063 return std::string();
1064
1065 return isExperimentalExtension(Name) ? "experimental-" + Name.str()
1066 : Name.str();
1067}
std::string Name
std::optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1291
#define _
#define I(x, y, z)
Definition: MD5.cpp:58
Load MIR Sample Profile
This file implements a map that provides insertion order iteration.
static void verifyTables()
static StringRef getExtensionTypeDesc(StringRef Ext)
static Error processSingleLetterExtension(StringRef &RawExt, MapVector< std::string, RISCVISAUtils::ExtensionVersion, std::map< std::string, unsigned > > &SeenExtMap, bool IgnoreUnknown, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static std::optional< RISCVISAUtils::ExtensionVersion > findDefaultVersion(StringRef ExtName)
static size_t findLastNonVersionCharacter(StringRef Ext)
static constexpr RISCVProfile SupportedProfiles[]
static StringRef getExtensionType(StringRef Ext)
static constexpr StringLiteral CombineIntoExts[]
static bool stripExperimentalPrefix(StringRef &Ext)
static Error processMultiLetterExtension(StringRef RawExt, MapVector< std::string, RISCVISAUtils::ExtensionVersion, std::map< std::string, unsigned > > &SeenExtMap, bool IgnoreUnknown, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static std::optional< RISCVISAUtils::ExtensionVersion > isExperimentalExtension(StringRef Ext)
static void PrintExtension(StringRef Name, StringRef Version, StringRef Description)
static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS)
static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, unsigned &Minor, unsigned &ConsumeLength, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static const char * RISCVGImplications[]
static Error getStringErrorForInvalidExt(std::string_view ExtName)
static Error splitExtsByUnderscore(StringRef Exts, std::vector< std::string > &SplitExts)
static bool isDigit(const char C)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
This file implements a set that has insertion order iteration characteristics.
This file contains some functions that are useful when dealing with strings.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition: Value.cpp:469
static void verifyTables()
Value * RHS
Value * LHS
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
iterator end() const
Definition: ArrayRef.h:154
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
Tagged union holding either a T or a Error.
Definition: Error.h:474
This class implements a map that also provides access to all stored values in a deterministic order.
Definition: MapVector.h:36
static bool isSupportedExtensionFeature(StringRef Ext)
static std::string getTargetFeatureForExtension(StringRef Ext)
static llvm::Expected< std::unique_ptr< RISCVISAInfo > > parseNormalizedArchString(StringRef Arch)
Parse RISC-V ISA info from an arch string that is already in normalized form (as defined in the psABI...
bool hasExtension(StringRef Ext) const
std::string toString() const
static llvm::Expected< std::unique_ptr< RISCVISAInfo > > postProcessAndChecking(std::unique_ptr< RISCVISAInfo > &&ISAInfo)
StringRef computeDefaultABI() const
static bool isSupportedExtension(StringRef Ext)
static llvm::Expected< std::unique_ptr< RISCVISAInfo > > parseFeatures(unsigned XLen, const std::vector< std::string > &Features)
Parse RISC-V ISA info from feature vector.
std::vector< std::string > toFeatures(bool AddAllExtensions=false, bool IgnoreUnknown=true) const
Convert RISC-V ISA info to a feature vector.
static llvm::Expected< std::unique_ptr< RISCVISAInfo > > parseArchString(StringRef Arch, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck=true, bool IgnoreUnknown=false)
Parse RISC-V ISA info from arch string.
static bool isSupportedExtensionWithVersion(StringRef Ext)
bool empty() const
Determine if the SetVector is empty or not.
Definition: SetVector.h:93
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition: SetVector.h:162
value_type pop_back_val()
Definition: SetVector.h:285
A SetVector that performs no allocations if smaller than a certain size.
Definition: SetVector.h:370
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:845
bool empty() const
Definition: StringMap.h:102
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:127
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:692
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
Definition: StringRef.h:647
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:462
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:222
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:563
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:257
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition: StringRef.h:601
char back() const
back - Get the last character in the string.
Definition: StringRef.h:146
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
char front() const
front - Get the first character in the string.
Definition: StringRef.h:140
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition: StringRef.h:627
StringRef take_front(size_t N=1) const
Return a StringRef equal to 'this' but with only the first N elements remaining.
Definition: StringRef.h:572
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
Definition: StringRef.h:608
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:660
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:678
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const uint64_t Version
Definition: InstrProf.h:1153
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
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1258
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1729
bool is_sorted(R &&Range, Compare C)
Wrapper function around std::is_sorted to check if elements in a range R are sorted with respect to a...
Definition: STLExtras.h:1902
void riscvExtensionsHelp(StringMap< StringRef > DescMap)
FormattedString left_justify(StringRef Str, unsigned Width)
left_justify - append spaces after string so total output is Width characters.
Definition: Format.h:146
auto lower_bound(R &&Range, T &&Value)
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:1954
@ Add
Sum of integers.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1749
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1041
StringLiteral Name
bool operator<(const ImpliedExtsEntry &Other) const
const char * ImpliedExt
Description of the encoding of one expression Op.
Represents the major and version number components of a RISC-V extension.
Definition: RISCVISAUtils.h:26