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// NOTE: This table should be sorted alphabetically by extension name.
51static const RISCVSupportedExtension SupportedExtensions[] = {
52 {"a", {2, 1}},
53 {"c", {2, 0}},
54 {"d", {2, 2}},
55 {"e", {2, 0}},
56 {"f", {2, 2}},
57 {"h", {1, 0}},
58 {"i", {2, 1}},
59 {"m", {2, 0}},
60
61 {"shcounterenw", {1, 0}},
62 {"shgatpa", {1, 0}},
63 {"shtvala", {1, 0}},
64 {"shvsatpa", {1, 0}},
65 {"shvstvala", {1, 0}},
66 {"shvstvecd", {1, 0}},
67 {"smaia", {1, 0}},
68 {"smepmp", {1, 0}},
69 {"ssaia", {1, 0}},
70 {"ssccptr", {1, 0}},
71 {"sscofpmf", {1, 0}},
72 {"sscounterenw", {1, 0}},
73 {"ssstateen", {1, 0}},
74 {"ssstrict", {1, 0}},
75 {"sstc", {1, 0}},
76 {"sstvala", {1, 0}},
77 {"sstvecd", {1, 0}},
78 {"ssu64xl", {1, 0}},
79 {"svade", {1, 0}},
80 {"svadu", {1, 0}},
81 {"svbare", {1, 0}},
82 {"svinval", {1, 0}},
83 {"svnapot", {1, 0}},
84 {"svpbmt", {1, 0}},
85
86 {"v", {1, 0}},
87
88 // vendor-defined ('X') extensions
89 {"xcvalu", {1, 0}},
90 {"xcvbi", {1, 0}},
91 {"xcvbitmanip", {1, 0}},
92 {"xcvelw", {1, 0}},
93 {"xcvmac", {1, 0}},
94 {"xcvmem", {1, 0}},
95 {"xcvsimd", {1, 0}},
96 {"xsfcease", {1, 0}},
97 {"xsfvcp", {1, 0}},
98 {"xsfvfnrclipxfqf", {1, 0}},
99 {"xsfvfwmaccqqq", {1, 0}},
100 {"xsfvqmaccdod", {1, 0}},
101 {"xsfvqmaccqoq", {1, 0}},
102 {"xsifivecdiscarddlone", {1, 0}},
103 {"xsifivecflushdlone", {1, 0}},
104 {"xtheadba", {1, 0}},
105 {"xtheadbb", {1, 0}},
106 {"xtheadbs", {1, 0}},
107 {"xtheadcmo", {1, 0}},
108 {"xtheadcondmov", {1, 0}},
109 {"xtheadfmemidx", {1, 0}},
110 {"xtheadmac", {1, 0}},
111 {"xtheadmemidx", {1, 0}},
112 {"xtheadmempair", {1, 0}},
113 {"xtheadsync", {1, 0}},
114 {"xtheadvdot", {1, 0}},
115 {"xventanacondops", {1, 0}},
116
117 {"za128rs", {1, 0}},
118 {"za64rs", {1, 0}},
119 {"zacas", {1, 0}},
120 {"zama16b", {1, 0}},
121 {"zawrs", {1, 0}},
122
123 {"zba", {1, 0}},
124 {"zbb", {1, 0}},
125 {"zbc", {1, 0}},
126 {"zbkb", {1, 0}},
127 {"zbkc", {1, 0}},
128 {"zbkx", {1, 0}},
129 {"zbs", {1, 0}},
130
131 {"zca", {1, 0}},
132 {"zcb", {1, 0}},
133 {"zcd", {1, 0}},
134 {"zce", {1, 0}},
135 {"zcf", {1, 0}},
136 {"zcmop", {1, 0}},
137 {"zcmp", {1, 0}},
138 {"zcmt", {1, 0}},
139
140 {"zdinx", {1, 0}},
141
142 {"zfa", {1, 0}},
143 {"zfh", {1, 0}},
144 {"zfhmin", {1, 0}},
145 {"zfinx", {1, 0}},
146
147 {"zhinx", {1, 0}},
148 {"zhinxmin", {1, 0}},
149
150 {"zic64b", {1, 0}},
151 {"zicbom", {1, 0}},
152 {"zicbop", {1, 0}},
153 {"zicboz", {1, 0}},
154 {"ziccamoa", {1, 0}},
155 {"ziccif", {1, 0}},
156 {"zicclsm", {1, 0}},
157 {"ziccrse", {1, 0}},
158 {"zicntr", {2, 0}},
159 {"zicond", {1, 0}},
160 {"zicsr", {2, 0}},
161 {"zifencei", {2, 0}},
162 {"zihintntl", {1, 0}},
163 {"zihintpause", {2, 0}},
164 {"zihpm", {2, 0}},
165 {"zimop", {1, 0}},
166
167 {"zk", {1, 0}},
168 {"zkn", {1, 0}},
169 {"zknd", {1, 0}},
170 {"zkne", {1, 0}},
171 {"zknh", {1, 0}},
172 {"zkr", {1, 0}},
173 {"zks", {1, 0}},
174 {"zksed", {1, 0}},
175 {"zksh", {1, 0}},
176 {"zkt", {1, 0}},
177
178 {"zmmul", {1, 0}},
179
180 {"zvbb", {1, 0}},
181 {"zvbc", {1, 0}},
182
183 {"zve32f", {1, 0}},
184 {"zve32x", {1, 0}},
185 {"zve64d", {1, 0}},
186 {"zve64f", {1, 0}},
187 {"zve64x", {1, 0}},
188
189 {"zvfh", {1, 0}},
190 {"zvfhmin", {1, 0}},
191
192 // vector crypto
193 {"zvkb", {1, 0}},
194 {"zvkg", {1, 0}},
195 {"zvkn", {1, 0}},
196 {"zvknc", {1, 0}},
197 {"zvkned", {1, 0}},
198 {"zvkng", {1, 0}},
199 {"zvknha", {1, 0}},
200 {"zvknhb", {1, 0}},
201 {"zvks", {1, 0}},
202 {"zvksc", {1, 0}},
203 {"zvksed", {1, 0}},
204 {"zvksg", {1, 0}},
205 {"zvksh", {1, 0}},
206 {"zvkt", {1, 0}},
207
208 {"zvl1024b", {1, 0}},
209 {"zvl128b", {1, 0}},
210 {"zvl16384b", {1, 0}},
211 {"zvl2048b", {1, 0}},
212 {"zvl256b", {1, 0}},
213 {"zvl32768b", {1, 0}},
214 {"zvl32b", {1, 0}},
215 {"zvl4096b", {1, 0}},
216 {"zvl512b", {1, 0}},
217 {"zvl64b", {1, 0}},
218 {"zvl65536b", {1, 0}},
219 {"zvl8192b", {1, 0}},
220};
221
222// NOTE: This table should be sorted alphabetically by extension name.
223// clang-format off
224static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
225 {"smmpm", {0, 8}},
226 {"smnpm", {0, 8}},
227 {"ssnpm", {0, 8}},
228 {"sspm", {0, 8}},
229 {"ssqosid", {1, 0}},
230 {"supm", {0, 8}},
231
232 {"zaamo", {0, 2}},
233 {"zabha", {1, 0}},
234 {"zalasr", {0, 1}},
235 {"zalrsc", {0, 2}},
236
237 {"zfbfmin", {1, 0}},
238
239 {"zicfilp", {0, 4}},
240 {"zicfiss", {0, 4}},
241
242 {"ztso", {0, 1}},
243
244 {"zvfbfmin", {1, 0}},
245 {"zvfbfwma", {1, 0}},
246};
247// clang-format on
248
249static constexpr RISCVProfile SupportedProfiles[] = {
250 {"rvi20u32", "rv32i"},
251 {"rvi20u64", "rv64i"},
252 {"rva20u64", "rv64imafdc_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_za128rs"},
253 {"rva20s64", "rv64imafdc_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zifencei_"
254 "za128rs_ssccptr_sstvala_sstvecd_svade_svbare"},
255 {"rva22u64",
256 "rv64imafdc_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_"
257 "zicntr_zihintpause_zihpm_za64rs_zfhmin_zba_zbb_zbs_zkt"},
258 {"rva22s64",
259 "rv64imafdc_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_"
260 "zicntr_zifencei_zihintpause_zihpm_za64rs_zfhmin_zba_zbb_zbs_zkt_ssccptr_"
261 "sscounterenw_sstvala_sstvecd_svade_svbare_svinval_svpbmt"},
262 {"rva23u64",
263 "rv64imafdcv_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_"
264 "zicntr_zicond_zihintntl_zihintpause_zihpm_zimop_za64rs_zawrs_zfa_zfhmin_"
265 "zcb_zcmop_zba_zbb_zbs_zkt_zvbb_zvfhmin_zvkt"},
266 {"rva23s64",
267 "rv64imafdcvh_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_"
268 "zicntr_zicond_zifencei_zihintntl_zihintpause_zihpm_zimop_za64rs_zawrs_"
269 "zfa_zfhmin_zcb_zcmop_zba_zbb_zbs_zkt_zvbb_zvfhmin_zvkt_shcounterenw_"
270 "shgatpa_shtvala_shvsatpa_shvstvala_shvstvecd_ssccptr_sscofpmf_"
271 "sscounterenw_ssnpm0p8_ssstateen_sstc_sstvala_sstvecd_ssu64xl_svade_"
272 "svbare_svinval_svnapot_svpbmt"},
273 {"rvb23u64", "rv64imafdc_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_"
274 "zicclsm_ziccrse_zicntr_zicond_zihintntl_zihintpause_zihpm_"
275 "zimop_za64rs_zawrs_zfa_zcb_zcmop_zba_zbb_zbs_zkt"},
276 {"rvb23s64",
277 "rv64imafdc_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_"
278 "zicntr_zicond_zifencei_zihintntl_zihintpause_zihpm_zimop_za64rs_zawrs_"
279 "zfa_zcb_zcmop_zba_zbb_zbs_zkt_ssccptr_sscofpmf_sscounterenw_sstc_sstvala_"
280 "sstvecd_ssu64xl_svade_svbare_svinval_svnapot_svpbmt"},
281 {"rvm23u32", "rv32im_zicbop_zicond_zicsr_zihintntl_zihintpause_zimop_zca_"
282 "zcb_zce_zcmop_zcmp_zcmt_zba_zbb_zbs"},
283};
284
285static void verifyTables() {
286#ifndef NDEBUG
287 static std::atomic<bool> TableChecked(false);
288 if (!TableChecked.load(std::memory_order_relaxed)) {
290 "Extensions are not sorted by name");
292 "Experimental extensions are not sorted by name");
293 TableChecked.store(true, std::memory_order_relaxed);
294 }
295#endif
296}
297
299 StringRef Description) {
300 outs().indent(4);
301 unsigned VersionWidth = Description.empty() ? 0 : 10;
302 outs() << left_justify(Name, 21) << left_justify(Version, VersionWidth)
303 << Description << "\n";
304}
305
307
308 outs() << "All available -march extensions for RISC-V\n\n";
309 PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description"));
310
312 for (const auto &E : SupportedExtensions)
313 ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
314 for (const auto &E : ExtMap) {
315 std::string Version =
316 std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
317 PrintExtension(E.first, Version, DescMap[E.first]);
318 }
319
320 outs() << "\nExperimental extensions\n";
321 ExtMap.clear();
322 for (const auto &E : SupportedExperimentalExtensions)
323 ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
324 for (const auto &E : ExtMap) {
325 std::string Version =
326 std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
327 PrintExtension(E.first, Version, DescMap["experimental-" + E.first]);
328 }
329
330 outs() << "\nUse -march to specify the target's extension.\n"
331 "For example, clang -march=rv32i_v1p0\n";
332}
333
335 return Ext.consume_front("experimental-");
336}
337
338// This function finds the last character that doesn't belong to a version
339// (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will
340// consume [0-9]*p[0-9]* starting from the backward. An extension name will not
341// end with a digit or the letter 'p', so this function will parse correctly.
342// NOTE: This function is NOT able to take empty strings or strings that only
343// have version numbers and no extension name. It assumes the extension name
344// will be at least more than one character.
346 assert(!Ext.empty() &&
347 "Already guarded by if-statement in ::parseArchString");
348
349 int Pos = Ext.size() - 1;
350 while (Pos > 0 && isDigit(Ext[Pos]))
351 Pos--;
352 if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {
353 Pos--;
354 while (Pos > 0 && isDigit(Ext[Pos]))
355 Pos--;
356 }
357 return Pos;
358}
359
360namespace {
361struct LessExtName {
362 bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) {
363 return StringRef(LHS.Name) < RHS;
364 }
365 bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) {
366 return LHS < StringRef(RHS.Name);
367 }
368};
369} // namespace
370
371static std::optional<RISCVISAUtils::ExtensionVersion>
373 // Find default version of an extension.
374 // TODO: We might set default version based on profile or ISA spec.
375 for (auto &ExtInfo : {ArrayRef(SupportedExtensions),
377 auto I = llvm::lower_bound(ExtInfo, ExtName, LessExtName());
378
379 if (I == ExtInfo.end() || I->Name != ExtName)
380 continue;
381
382 return I->Version;
383 }
384 return std::nullopt;
385}
386
387void RISCVISAInfo::addExtension(StringRef ExtName,
389 Exts[ExtName.str()] = Version;
390}
391
393 if (Ext.starts_with("s"))
394 return "standard supervisor-level extension";
395 if (Ext.starts_with("x"))
396 return "non-standard user-level extension";
397 if (Ext.starts_with("z"))
398 return "standard user-level extension";
399 return StringRef();
400}
401
403 if (Ext.starts_with("s"))
404 return "s";
405 if (Ext.starts_with("x"))
406 return "x";
407 if (Ext.starts_with("z"))
408 return "z";
409 return StringRef();
410}
411
412static std::optional<RISCVISAUtils::ExtensionVersion>
414 auto I =
416 if (I == std::end(SupportedExperimentalExtensions) || I->Name != Ext)
417 return std::nullopt;
418
419 return I->Version;
420}
421
423 bool IsExperimental = stripExperimentalPrefix(Ext);
424
428
429 auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
430 return I != ExtInfo.end() && I->Name == Ext;
431}
432
434 verifyTables();
435
436 for (auto ExtInfo : {ArrayRef(SupportedExtensions),
438 auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
439 if (I != ExtInfo.end() && I->Name == Ext)
440 return true;
441 }
442
443 return false;
444}
445
446bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
447 unsigned MinorVersion) {
448 for (auto ExtInfo : {ArrayRef(SupportedExtensions),
450 auto Range =
451 std::equal_range(ExtInfo.begin(), ExtInfo.end(), Ext, LessExtName());
452 for (auto I = Range.first, E = Range.second; I != E; ++I)
453 if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion)
454 return true;
455 }
456
457 return false;
458}
459
462
463 if (!isSupportedExtension(Ext))
464 return false;
465
466 return Exts.count(Ext.str()) != 0;
467}
468
469std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions,
470 bool IgnoreUnknown) const {
471 std::vector<std::string> Features;
472 for (const auto &[ExtName, _] : Exts) {
473 // i is a base instruction set, not an extension (see
474 // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa)
475 // and is not recognized in clang -cc1
476 if (ExtName == "i")
477 continue;
478 if (IgnoreUnknown && !isSupportedExtension(ExtName))
479 continue;
480
481 if (isExperimentalExtension(ExtName)) {
482 Features.push_back((llvm::Twine("+experimental-") + ExtName).str());
483 } else {
484 Features.push_back((llvm::Twine("+") + ExtName).str());
485 }
486 }
487 if (AddAllExtensions) {
488 for (const RISCVSupportedExtension &Ext : SupportedExtensions) {
489 if (Exts.count(Ext.Name))
490 continue;
491 Features.push_back((llvm::Twine("-") + Ext.Name).str());
492 }
493
494 for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {
495 if (Exts.count(Ext.Name))
496 continue;
497 Features.push_back((llvm::Twine("-experimental-") + Ext.Name).str());
498 }
499 }
500 return Features;
501}
502
503static Error getStringErrorForInvalidExt(std::string_view ExtName) {
504 if (ExtName.size() == 1) {
506 "unsupported standard user-level extension '" +
507 ExtName + "'");
508 }
510 "unsupported " + getExtensionTypeDesc(ExtName) +
511 " '" + ExtName + "'");
512}
513
514// Extensions may have a version number, and may be separated by
515// an underscore '_' e.g.: rv32i2_m2.
516// Version number is divided into major and minor version numbers,
517// separated by a 'p'. If the minor version is 0 then 'p0' can be
518// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
519static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
520 unsigned &Minor, unsigned &ConsumeLength,
521 bool EnableExperimentalExtension,
522 bool ExperimentalExtensionVersionCheck) {
523 StringRef MajorStr, MinorStr;
524 Major = 0;
525 Minor = 0;
526 ConsumeLength = 0;
527 MajorStr = In.take_while(isDigit);
528 In = In.substr(MajorStr.size());
529
530 if (!MajorStr.empty() && In.consume_front("p")) {
531 MinorStr = In.take_while(isDigit);
532 In = In.substr(MajorStr.size() + MinorStr.size() - 1);
533
534 // Expected 'p' to be followed by minor version number.
535 if (MinorStr.empty()) {
536 return createStringError(
538 "minor version number missing after 'p' for extension '" + Ext + "'");
539 }
540 }
541
542 if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
543 return createStringError(
545 "Failed to parse major version number for extension '" + Ext + "'");
546
547 if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
548 return createStringError(
550 "Failed to parse minor version number for extension '" + Ext + "'");
551
552 ConsumeLength = MajorStr.size();
553
554 if (!MinorStr.empty())
555 ConsumeLength += MinorStr.size() + 1 /*'p'*/;
556
557 // Expected multi-character extension with version number to have no
558 // subsequent characters (i.e. must either end string or be followed by
559 // an underscore).
560 if (Ext.size() > 1 && In.size())
561 return createStringError(
563 "multi-character extensions must be separated by underscores");
564
565 // If experimental extension, require use of current version number
566 if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
567 if (!EnableExperimentalExtension)
569 "requires '-menable-experimental-extensions' "
570 "for experimental extension '" +
571 Ext + "'");
572
573 if (ExperimentalExtensionVersionCheck &&
574 (MajorStr.empty() && MinorStr.empty()))
575 return createStringError(
577 "experimental extension requires explicit version number `" + Ext +
578 "`");
579
580 auto SupportedVers = *ExperimentalExtension;
581 if (ExperimentalExtensionVersionCheck &&
582 (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
583 std::string Error = "unsupported version number " + MajorStr.str();
584 if (!MinorStr.empty())
585 Error += "." + MinorStr.str();
586 Error += " for experimental extension '" + Ext.str() +
587 "' (this compiler supports " + utostr(SupportedVers.Major) +
588 "." + utostr(SupportedVers.Minor) + ")";
590 }
591 return Error::success();
592 }
593
594 // Exception rule for `g`, we don't have clear version scheme for that on
595 // ISA spec.
596 if (Ext == "g")
597 return Error::success();
598
599 if (MajorStr.empty() && MinorStr.empty()) {
600 if (auto DefaultVersion = findDefaultVersion(Ext)) {
601 Major = DefaultVersion->Major;
602 Minor = DefaultVersion->Minor;
603 }
604 // No matter found or not, return success, assume other place will
605 // verify.
606 return Error::success();
607 }
608
609 if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
610 return Error::success();
611
613 return getStringErrorForInvalidExt(Ext);
614
615 std::string Error = "unsupported version number " + std::string(MajorStr);
616 if (!MinorStr.empty())
617 Error += "." + MinorStr.str();
618 Error += " for extension '" + Ext.str() + "'";
620}
621
624 const std::vector<std::string> &Features) {
625 assert(XLen == 32 || XLen == 64);
626 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
627
628 for (auto &Feature : Features) {
629 StringRef ExtName = Feature;
630 bool Experimental = false;
631 assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
632 bool Add = ExtName[0] == '+';
633 ExtName = ExtName.drop_front(1); // Drop '+' or '-'
634 Experimental = stripExperimentalPrefix(ExtName);
635 auto ExtensionInfos = Experimental
638 auto ExtensionInfoIterator =
639 llvm::lower_bound(ExtensionInfos, ExtName, LessExtName());
640
641 // Not all features is related to ISA extension, like `relax` or
642 // `save-restore`, skip those feature.
643 if (ExtensionInfoIterator == ExtensionInfos.end() ||
644 ExtensionInfoIterator->Name != ExtName)
645 continue;
646
647 if (Add)
648 ISAInfo->addExtension(ExtName, ExtensionInfoIterator->Version);
649 else
650 ISAInfo->Exts.erase(ExtName.str());
651 }
652
653 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
654}
655
658 if (llvm::any_of(Arch, isupper)) {
660 "string must be lowercase");
661 }
662 // Must start with a valid base ISA name.
663 unsigned XLen;
664 if (Arch.starts_with("rv32i") || Arch.starts_with("rv32e"))
665 XLen = 32;
666 else if (Arch.starts_with("rv64i") || Arch.starts_with("rv64e"))
667 XLen = 64;
668 else
670 "arch string must begin with valid base ISA");
671 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
672 // Discard rv32/rv64 prefix.
673 Arch = Arch.substr(4);
674
675 // Each extension is of the form ${name}${major_version}p${minor_version}
676 // and separated by _. Split by _ and then extract the name and version
677 // information for each extension.
679 Arch.split(Split, '_');
680 for (StringRef Ext : Split) {
681 StringRef Prefix, MinorVersionStr;
682 std::tie(Prefix, MinorVersionStr) = Ext.rsplit('p');
683 if (MinorVersionStr.empty())
685 "extension lacks version in expected format");
686 unsigned MajorVersion, MinorVersion;
687 if (MinorVersionStr.getAsInteger(10, MinorVersion))
689 "failed to parse minor version number");
690
691 // Split Prefix into the extension name and the major version number
692 // (the trailing digits of Prefix).
693 int TrailingDigits = 0;
694 StringRef ExtName = Prefix;
695 while (!ExtName.empty()) {
696 if (!isDigit(ExtName.back()))
697 break;
698 ExtName = ExtName.drop_back(1);
699 TrailingDigits++;
700 }
701 if (!TrailingDigits)
703 "extension lacks version in expected format");
704
705 StringRef MajorVersionStr = Prefix.take_back(TrailingDigits);
706 if (MajorVersionStr.getAsInteger(10, MajorVersion))
708 "failed to parse major version number");
709 ISAInfo->addExtension(ExtName, {MajorVersion, MinorVersion});
710 }
711 ISAInfo->updateFLen();
712 ISAInfo->updateMinVLen();
713 ISAInfo->updateMaxELen();
714 return std::move(ISAInfo);
715}
716
718 std::vector<std::string> &SplitExts) {
720 if (Exts.empty())
721 return Error::success();
722
723 Exts.split(Split, "_");
724
725 for (auto Ext : Split) {
726 if (Ext.empty())
728 "extension name missing after separator '_'");
729
730 SplitExts.push_back(Ext.str());
731 }
732 return Error::success();
733}
734
736 StringRef RawExt,
738 std::map<std::string, unsigned>> &SeenExtMap,
739 bool IgnoreUnknown, bool EnableExperimentalExtension,
740 bool ExperimentalExtensionVersionCheck) {
743 auto Pos = findLastNonVersionCharacter(RawExt) + 1;
744 StringRef Name(RawExt.substr(0, Pos));
745 StringRef Vers(RawExt.substr(Pos));
746
747 if (Type.empty()) {
748 if (IgnoreUnknown)
749 return Error::success();
751 "invalid extension prefix '" + RawExt + "'");
752 }
753
754 if (!IgnoreUnknown && Name.size() == Type.size())
756 Desc + " name missing after '" + Type + "'");
757
758 unsigned Major, Minor, ConsumeLength;
759 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
760 EnableExperimentalExtension,
761 ExperimentalExtensionVersionCheck)) {
762 if (IgnoreUnknown) {
763 consumeError(std::move(E));
764 return Error::success();
765 }
766 return E;
767 }
768
769 // Check if duplicated extension.
770 if (!IgnoreUnknown && SeenExtMap.contains(Name.str()))
772 "duplicated " + Desc + " '" + Name + "'");
773
774 if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Name))
775 return Error::success();
776
777 SeenExtMap[Name.str()] = {Major, Minor};
778 return Error::success();
779}
780
782 StringRef &RawExt,
784 std::map<std::string, unsigned>> &SeenExtMap,
785 bool IgnoreUnknown, bool EnableExperimentalExtension,
786 bool ExperimentalExtensionVersionCheck) {
787 unsigned Major, Minor, ConsumeLength;
788 StringRef Name = RawExt.take_front(1);
789 RawExt.consume_front(Name);
790 if (auto E = getExtensionVersion(Name, RawExt, Major, Minor, ConsumeLength,
791 EnableExperimentalExtension,
792 ExperimentalExtensionVersionCheck)) {
793 if (IgnoreUnknown) {
794 consumeError(std::move(E));
795 RawExt = RawExt.substr(ConsumeLength);
796 return Error::success();
797 }
798 return E;
799 }
800
801 RawExt = RawExt.substr(ConsumeLength);
802
803 // Check if duplicated extension.
804 if (!IgnoreUnknown && SeenExtMap.contains(Name.str()))
806 "duplicated standard user-level extension '" +
807 Name + "'");
808
809 if (IgnoreUnknown && !RISCVISAInfo::isSupportedExtension(Name))
810 return Error::success();
811
812 SeenExtMap[Name.str()] = {Major, Minor};
813 return Error::success();
814}
815
817RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
818 bool ExperimentalExtensionVersionCheck,
819 bool IgnoreUnknown) {
820 // RISC-V ISA strings must be lowercase.
821 if (llvm::any_of(Arch, isupper)) {
823 "string must be lowercase");
824 }
825
826 if (Arch.starts_with("rvi") || Arch.starts_with("rva") ||
827 Arch.starts_with("rvb") || Arch.starts_with("rvm")) {
828 const auto *FoundProfile =
829 llvm::find_if(SupportedProfiles, [Arch](const RISCVProfile &Profile) {
830 return Arch.starts_with(Profile.Name);
831 });
832
833 if (FoundProfile == std::end(SupportedProfiles))
834 return createStringError(errc::invalid_argument, "unsupported profile");
835
836 std::string NewArch = FoundProfile->MArch.str();
837 StringRef ArchWithoutProfile = Arch.substr(FoundProfile->Name.size());
838 if (!ArchWithoutProfile.empty()) {
839 if (!ArchWithoutProfile.starts_with("_"))
840 return createStringError(
842 "additional extensions must be after separator '_'");
843 NewArch += ArchWithoutProfile.str();
844 }
845 return parseArchString(NewArch, EnableExperimentalExtension,
846 ExperimentalExtensionVersionCheck, IgnoreUnknown);
847 }
848
849 bool HasRV64 = Arch.starts_with("rv64");
850 // ISA string must begin with rv32 or rv64.
851 if (!(Arch.starts_with("rv32") || HasRV64) || (Arch.size() < 5)) {
852 return createStringError(
854 "string must begin with rv32{i,e,g} or rv64{i,e,g}");
855 }
856
857 unsigned XLen = HasRV64 ? 64 : 32;
858 std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
860 std::map<std::string, unsigned>>
861 SeenExtMap;
862
863 // The canonical order specified in ISA manual.
864 // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
865 char Baseline = Arch[4];
866
867 // First letter should be 'e', 'i' or 'g'.
868 switch (Baseline) {
869 default:
871 "first letter should be 'e', 'i' or 'g'");
872 case 'e':
873 case 'i':
874 break;
875 case 'g':
876 // g expands to extensions in RISCVGImplications.
877 if (Arch.size() > 5 && isDigit(Arch[5]))
879 "version not supported for 'g'");
880 break;
881 }
882
883 if (Arch.back() == '_')
885 "extension name missing after separator '_'");
886
887 // Skip rvxxx
888 StringRef Exts = Arch.substr(5);
889
890 unsigned Major, Minor, ConsumeLength;
891 if (Baseline == 'g') {
892 // Versions for g are disallowed, and this was checked for previously.
893 ConsumeLength = 0;
894
895 // No matter which version is given to `g`, we always set imafd to default
896 // version since the we don't have clear version scheme for that on
897 // ISA spec.
898 for (const auto *Ext : RISCVGImplications) {
899 if (auto Version = findDefaultVersion(Ext)) {
900 // Postpone AddExtension until end of this function
901 SeenExtMap[Ext] = {Version->Major, Version->Minor};
902 } else
903 llvm_unreachable("Default extension version not found?");
904 }
905 } else {
906 // Baseline is `i` or `e`
907 if (auto E = getExtensionVersion(
908 StringRef(&Baseline, 1), Exts, Major, Minor, ConsumeLength,
909 EnableExperimentalExtension, ExperimentalExtensionVersionCheck)) {
910 if (!IgnoreUnknown)
911 return std::move(E);
912 // If IgnoreUnknown, then ignore an unrecognised version of the baseline
913 // ISA and just use the default supported version.
914 consumeError(std::move(E));
915 auto Version = findDefaultVersion(StringRef(&Baseline, 1));
916 Major = Version->Major;
917 Minor = Version->Minor;
918 }
919
920 // Postpone AddExtension until end of this function
921 SeenExtMap[StringRef(&Baseline, 1).str()] = {Major, Minor};
922 }
923
924 // Consume the base ISA version number and any '_' between rvxxx and the
925 // first extension
926 Exts = Exts.drop_front(ConsumeLength);
927 Exts.consume_front("_");
928
929 std::vector<std::string> SplitExts;
930 if (auto E = splitExtsByUnderscore(Exts, SplitExts))
931 return std::move(E);
932
933 for (auto &Ext : SplitExts) {
934 StringRef CurrExt = Ext;
935 while (!CurrExt.empty()) {
937 if (auto E = processSingleLetterExtension(
938 CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension,
939 ExperimentalExtensionVersionCheck))
940 return std::move(E);
941 } else if (CurrExt.front() == 'z' || CurrExt.front() == 's' ||
942 CurrExt.front() == 'x') {
943 // Handle other types of extensions other than the standard
944 // general purpose and standard user-level extensions.
945 // Parse the ISA string containing non-standard user-level
946 // extensions, standard supervisor-level extensions and
947 // non-standard supervisor-level extensions.
948 // These extensions start with 'z', 's', 'x' prefixes, might have a
949 // version number (major, minor) and are separated by a single
950 // underscore '_'. We do not enforce a canonical order for them.
951 if (auto E = processMultiLetterExtension(
952 CurrExt, SeenExtMap, IgnoreUnknown, EnableExperimentalExtension,
953 ExperimentalExtensionVersionCheck))
954 return std::move(E);
955 // Multi-letter extension must be seperate following extension with
956 // underscore
957 break;
958 } else {
959 // FIXME: Could it be ignored by IgnoreUnknown?
961 "invalid standard user-level extension '" +
962 Twine(CurrExt.front()) + "'");
963 }
964 }
965 }
966
967 // Check all Extensions are supported.
968 for (auto &SeenExtAndVers : SeenExtMap) {
969 const std::string &ExtName = SeenExtAndVers.first;
970 RISCVISAUtils::ExtensionVersion ExtVers = SeenExtAndVers.second;
971
973 return getStringErrorForInvalidExt(ExtName);
974 ISAInfo->addExtension(ExtName, ExtVers);
975 }
976
977 return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
978}
979
980Error RISCVISAInfo::checkDependency() {
981 bool HasC = Exts.count("c") != 0;
982 bool HasF = Exts.count("f") != 0;
983 bool HasZfinx = Exts.count("zfinx") != 0;
984 bool HasVector = Exts.count("zve32x") != 0;
985 bool HasZvl = MinVLen != 0;
986 bool HasZcmt = Exts.count("zcmt") != 0;
987
988 if (HasF && HasZfinx)
990 "'f' and 'zfinx' extensions are incompatible");
991
992 if (HasZvl && !HasVector)
993 return createStringError(
995 "'zvl*b' requires 'v' or 'zve*' extension to also be specified");
996
997 if (Exts.count("zvbb") && !HasVector)
998 return createStringError(
1000 "'zvbb' requires 'v' or 'zve*' extension to also be specified");
1001
1002 if (Exts.count("zvbc") && !Exts.count("zve64x"))
1003 return createStringError(
1005 "'zvbc' requires 'v' or 'zve64*' extension to also be specified");
1006
1007 if ((Exts.count("zvkb") || Exts.count("zvkg") || Exts.count("zvkned") ||
1008 Exts.count("zvknha") || Exts.count("zvksed") || Exts.count("zvksh")) &&
1009 !HasVector)
1010 return createStringError(
1012 "'zvk*' requires 'v' or 'zve*' extension to also be specified");
1013
1014 if (Exts.count("zvknhb") && !Exts.count("zve64x"))
1015 return createStringError(
1017 "'zvknhb' requires 'v' or 'zve64*' extension to also be specified");
1018
1019 if ((HasZcmt || Exts.count("zcmp")) && Exts.count("d") &&
1020 (HasC || Exts.count("zcd")))
1021 return createStringError(
1023 Twine("'") + (HasZcmt ? "zcmt" : "zcmp") +
1024 "' extension is incompatible with '" + (HasC ? "c" : "zcd") +
1025 "' extension when 'd' extension is enabled");
1026
1027 if (XLen != 32 && Exts.count("zcf"))
1029 "'zcf' is only supported for 'rv32'");
1030
1031 if (Exts.count("zacas") && !(Exts.count("a") || Exts.count("zamo")))
1032 return createStringError(
1034 "'zacas' requires 'a' or 'zaamo' extension to also be specified");
1035
1036 if (Exts.count("zabha") && !(Exts.count("a") || Exts.count("zamo")))
1037 return createStringError(
1039 "'zabha' requires 'a' or 'zaamo' extension to also be specified");
1040
1041 return Error::success();
1042}
1043
1044static const char *ImpliedExtsD[] = {"f"};
1045static const char *ImpliedExtsF[] = {"zicsr"};
1046static const char *ImpliedExtsV[] = {"zvl128b", "zve64d"};
1047static const char *ImpliedExtsXSfvcp[] = {"zve32x"};
1048static const char *ImpliedExtsXSfvfnrclipxfqf[] = {"zve32f"};
1049static const char *ImpliedExtsXSfvfwmaccqqq[] = {"zvfbfmin"};
1050static const char *ImpliedExtsXSfvqmaccdod[] = {"zve32x"};
1051static const char *ImpliedExtsXSfvqmaccqoq[] = {"zve32x"};
1052static const char *ImpliedExtsXTHeadVdot[] = {"v"};
1053static const char *ImpliedExtsZcb[] = {"zca"};
1054static const char *ImpliedExtsZcd[] = {"d", "zca"};
1055static const char *ImpliedExtsZce[] = {"zcb", "zcmp", "zcmt"};
1056static const char *ImpliedExtsZcf[] = {"f", "zca"};
1057static const char *ImpliedExtsZcmop[] = {"zca"};
1058static const char *ImpliedExtsZcmp[] = {"zca"};
1059static const char *ImpliedExtsZcmt[] = {"zca", "zicsr"};
1060static const char *ImpliedExtsZdinx[] = {"zfinx"};
1061static const char *ImpliedExtsZfa[] = {"f"};
1062static const char *ImpliedExtsZfbfmin[] = {"f"};
1063static const char *ImpliedExtsZfh[] = {"zfhmin"};
1064static const char *ImpliedExtsZfhmin[] = {"f"};
1065static const char *ImpliedExtsZfinx[] = {"zicsr"};
1066static const char *ImpliedExtsZhinx[] = {"zhinxmin"};
1067static const char *ImpliedExtsZhinxmin[] = {"zfinx"};
1068static const char *ImpliedExtsZicfiss[] = {"zicsr", "zimop"};
1069static const char *ImpliedExtsZicntr[] = {"zicsr"};
1070static const char *ImpliedExtsZihpm[] = {"zicsr"};
1071static const char *ImpliedExtsZk[] = {"zkn", "zkt", "zkr"};
1072static const char *ImpliedExtsZkn[] = {"zbkb", "zbkc", "zbkx",
1073 "zkne", "zknd", "zknh"};
1074static const char *ImpliedExtsZks[] = {"zbkb", "zbkc", "zbkx", "zksed", "zksh"};
1075static const char *ImpliedExtsZvbb[] = {"zvkb"};
1076static const char *ImpliedExtsZve32f[] = {"zve32x", "f"};
1077static const char *ImpliedExtsZve32x[] = {"zvl32b", "zicsr"};
1078static const char *ImpliedExtsZve64d[] = {"zve64f", "d"};
1079static const char *ImpliedExtsZve64f[] = {"zve64x", "zve32f"};
1080static const char *ImpliedExtsZve64x[] = {"zve32x", "zvl64b"};
1081static const char *ImpliedExtsZvfbfmin[] = {"zve32f"};
1082static const char *ImpliedExtsZvfbfwma[] = {"zvfbfmin", "zfbfmin"};
1083static const char *ImpliedExtsZvfh[] = {"zvfhmin", "zfhmin"};
1084static const char *ImpliedExtsZvfhmin[] = {"zve32f"};
1085static const char *ImpliedExtsZvkn[] = {"zvkb", "zvkned", "zvknhb", "zvkt"};
1086static const char *ImpliedExtsZvknc[] = {"zvbc", "zvkn"};
1087static const char *ImpliedExtsZvkng[] = {"zvkg", "zvkn"};
1088static const char *ImpliedExtsZvknhb[] = {"zve64x"};
1089static const char *ImpliedExtsZvks[] = {"zvkb", "zvksed", "zvksh", "zvkt"};
1090static const char *ImpliedExtsZvksc[] = {"zvbc", "zvks"};
1091static const char *ImpliedExtsZvksg[] = {"zvkg", "zvks"};
1092static const char *ImpliedExtsZvl1024b[] = {"zvl512b"};
1093static const char *ImpliedExtsZvl128b[] = {"zvl64b"};
1094static const char *ImpliedExtsZvl16384b[] = {"zvl8192b"};
1095static const char *ImpliedExtsZvl2048b[] = {"zvl1024b"};
1096static const char *ImpliedExtsZvl256b[] = {"zvl128b"};
1097static const char *ImpliedExtsZvl32768b[] = {"zvl16384b"};
1098static const char *ImpliedExtsZvl4096b[] = {"zvl2048b"};
1099static const char *ImpliedExtsZvl512b[] = {"zvl256b"};
1100static const char *ImpliedExtsZvl64b[] = {"zvl32b"};
1101static const char *ImpliedExtsZvl65536b[] = {"zvl32768b"};
1102static const char *ImpliedExtsZvl8192b[] = {"zvl4096b"};
1103
1107
1108 bool operator<(const ImpliedExtsEntry &Other) const {
1109 return Name < Other.Name;
1110 }
1111
1112 bool operator<(StringRef Other) const { return Name < Other; }
1113};
1114
1115// Note: The table needs to be sorted by name.
1116static constexpr ImpliedExtsEntry ImpliedExts[] = {
1117 {{"d"}, {ImpliedExtsD}},
1118 {{"f"}, {ImpliedExtsF}},
1119 {{"v"}, {ImpliedExtsV}},
1120 {{"xsfvcp"}, {ImpliedExtsXSfvcp}},
1121 {{"xsfvfnrclipxfqf"}, {ImpliedExtsXSfvfnrclipxfqf}},
1122 {{"xsfvfwmaccqqq"}, {ImpliedExtsXSfvfwmaccqqq}},
1123 {{"xsfvqmaccdod"}, {ImpliedExtsXSfvqmaccdod}},
1124 {{"xsfvqmaccqoq"}, {ImpliedExtsXSfvqmaccqoq}},
1125 {{"xtheadvdot"}, {ImpliedExtsXTHeadVdot}},
1126 {{"zcb"}, {ImpliedExtsZcb}},
1127 {{"zcd"}, {ImpliedExtsZcd}},
1128 {{"zce"}, {ImpliedExtsZce}},
1129 {{"zcf"}, {ImpliedExtsZcf}},
1130 {{"zcmop"}, {ImpliedExtsZcmop}},
1131 {{"zcmp"}, {ImpliedExtsZcmp}},
1132 {{"zcmt"}, {ImpliedExtsZcmt}},
1133 {{"zdinx"}, {ImpliedExtsZdinx}},
1134 {{"zfa"}, {ImpliedExtsZfa}},
1135 {{"zfbfmin"}, {ImpliedExtsZfbfmin}},
1136 {{"zfh"}, {ImpliedExtsZfh}},
1137 {{"zfhmin"}, {ImpliedExtsZfhmin}},
1138 {{"zfinx"}, {ImpliedExtsZfinx}},
1139 {{"zhinx"}, {ImpliedExtsZhinx}},
1140 {{"zhinxmin"}, {ImpliedExtsZhinxmin}},
1141 {{"zicfiss"}, {ImpliedExtsZicfiss}},
1142 {{"zicntr"}, {ImpliedExtsZicntr}},
1143 {{"zihpm"}, {ImpliedExtsZihpm}},
1144 {{"zk"}, {ImpliedExtsZk}},
1145 {{"zkn"}, {ImpliedExtsZkn}},
1146 {{"zks"}, {ImpliedExtsZks}},
1147 {{"zvbb"}, {ImpliedExtsZvbb}},
1148 {{"zve32f"}, {ImpliedExtsZve32f}},
1149 {{"zve32x"}, {ImpliedExtsZve32x}},
1150 {{"zve64d"}, {ImpliedExtsZve64d}},
1151 {{"zve64f"}, {ImpliedExtsZve64f}},
1152 {{"zve64x"}, {ImpliedExtsZve64x}},
1153 {{"zvfbfmin"}, {ImpliedExtsZvfbfmin}},
1154 {{"zvfbfwma"}, {ImpliedExtsZvfbfwma}},
1155 {{"zvfh"}, {ImpliedExtsZvfh}},
1156 {{"zvfhmin"}, {ImpliedExtsZvfhmin}},
1157 {{"zvkn"}, {ImpliedExtsZvkn}},
1158 {{"zvknc"}, {ImpliedExtsZvknc}},
1159 {{"zvkng"}, {ImpliedExtsZvkng}},
1160 {{"zvknhb"}, {ImpliedExtsZvknhb}},
1161 {{"zvks"}, {ImpliedExtsZvks}},
1162 {{"zvksc"}, {ImpliedExtsZvksc}},
1163 {{"zvksg"}, {ImpliedExtsZvksg}},
1164 {{"zvl1024b"}, {ImpliedExtsZvl1024b}},
1165 {{"zvl128b"}, {ImpliedExtsZvl128b}},
1166 {{"zvl16384b"}, {ImpliedExtsZvl16384b}},
1167 {{"zvl2048b"}, {ImpliedExtsZvl2048b}},
1168 {{"zvl256b"}, {ImpliedExtsZvl256b}},
1169 {{"zvl32768b"}, {ImpliedExtsZvl32768b}},
1170 {{"zvl4096b"}, {ImpliedExtsZvl4096b}},
1171 {{"zvl512b"}, {ImpliedExtsZvl512b}},
1172 {{"zvl64b"}, {ImpliedExtsZvl64b}},
1173 {{"zvl65536b"}, {ImpliedExtsZvl65536b}},
1174 {{"zvl8192b"}, {ImpliedExtsZvl8192b}},
1175};
1176
1177void RISCVISAInfo::updateImplication() {
1178 bool HasE = Exts.count("e") != 0;
1179 bool HasI = Exts.count("i") != 0;
1180
1181 // If not in e extension and i extension does not exist, i extension is
1182 // implied
1183 if (!HasE && !HasI) {
1184 auto Version = findDefaultVersion("i");
1185 addExtension("i", Version.value());
1186 }
1187
1188 assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
1189
1190 // This loop may execute over 1 iteration since implication can be layered
1191 // Exits loop if no more implication is applied
1193 for (auto const &Ext : Exts)
1194 WorkList.insert(Ext.first);
1195
1196 while (!WorkList.empty()) {
1197 StringRef ExtName = WorkList.pop_back_val();
1198 auto I = llvm::lower_bound(ImpliedExts, ExtName);
1199 if (I != std::end(ImpliedExts) && I->Name == ExtName) {
1200 for (const char *ImpliedExt : I->Exts) {
1201 if (WorkList.count(ImpliedExt))
1202 continue;
1203 if (Exts.count(ImpliedExt))
1204 continue;
1205 auto Version = findDefaultVersion(ImpliedExt);
1206 addExtension(ImpliedExt, Version.value());
1207 WorkList.insert(ImpliedExt);
1208 }
1209 }
1210 }
1211
1212 // Add Zcf if Zce and F are enabled on RV32.
1213 if (XLen == 32 && Exts.count("zce") && Exts.count("f") &&
1214 !Exts.count("zcf")) {
1215 auto Version = findDefaultVersion("zcf");
1216 addExtension("zcf", Version.value());
1217 }
1218}
1219
1223};
1224
1226 {{"zk"}, {ImpliedExtsZk}},
1227 {{"zkn"}, {ImpliedExtsZkn}},
1228 {{"zks"}, {ImpliedExtsZks}},
1229 {{"zvkn"}, {ImpliedExtsZvkn}},
1230 {{"zvknc"}, {ImpliedExtsZvknc}},
1231 {{"zvkng"}, {ImpliedExtsZvkng}},
1232 {{"zvks"}, {ImpliedExtsZvks}},
1233 {{"zvksc"}, {ImpliedExtsZvksc}},
1234 {{"zvksg"}, {ImpliedExtsZvksg}},
1235};
1236
1237void RISCVISAInfo::updateCombination() {
1238 bool IsNewCombine = false;
1239 do {
1240 IsNewCombine = false;
1241 for (CombinedExtsEntry CombineIntoExt : CombineIntoExts) {
1242 auto CombineExt = CombineIntoExt.CombineExt;
1243 auto RequiredExts = CombineIntoExt.RequiredExts;
1244 if (hasExtension(CombineExt))
1245 continue;
1246 bool IsAllRequiredFeatureExist = true;
1247 for (const char *Ext : RequiredExts)
1248 IsAllRequiredFeatureExist &= hasExtension(Ext);
1249 if (IsAllRequiredFeatureExist) {
1250 auto Version = findDefaultVersion(CombineExt);
1251 addExtension(CombineExt, Version.value());
1252 IsNewCombine = true;
1253 }
1254 }
1255 } while (IsNewCombine);
1256}
1257
1258void RISCVISAInfo::updateFLen() {
1259 FLen = 0;
1260 // TODO: Handle q extension.
1261 if (Exts.count("d"))
1262 FLen = 64;
1263 else if (Exts.count("f"))
1264 FLen = 32;
1265}
1266
1267void RISCVISAInfo::updateMinVLen() {
1268 for (auto const &Ext : Exts) {
1269 StringRef ExtName = Ext.first;
1270 bool IsZvlExt = ExtName.consume_front("zvl") && ExtName.consume_back("b");
1271 if (IsZvlExt) {
1272 unsigned ZvlLen;
1273 if (!ExtName.getAsInteger(10, ZvlLen))
1274 MinVLen = std::max(MinVLen, ZvlLen);
1275 }
1276 }
1277}
1278
1279void RISCVISAInfo::updateMaxELen() {
1280 // handles EEW restriction by sub-extension zve
1281 for (auto const &Ext : Exts) {
1282 StringRef ExtName = Ext.first;
1283 bool IsZveExt = ExtName.consume_front("zve");
1284 if (IsZveExt) {
1285 if (ExtName.back() == 'f')
1286 MaxELenFp = std::max(MaxELenFp, 32u);
1287 if (ExtName.back() == 'd')
1288 MaxELenFp = std::max(MaxELenFp, 64u);
1289 ExtName = ExtName.drop_back();
1290 unsigned ZveELen;
1291 ExtName.getAsInteger(10, ZveELen);
1292 MaxELen = std::max(MaxELen, ZveELen);
1293 }
1294 }
1295}
1296
1297std::string RISCVISAInfo::toString() const {
1298 std::string Buffer;
1299 raw_string_ostream Arch(Buffer);
1300
1301 Arch << "rv" << XLen;
1302
1303 ListSeparator LS("_");
1304 for (auto const &Ext : Exts) {
1305 StringRef ExtName = Ext.first;
1306 auto ExtInfo = Ext.second;
1307 Arch << LS << ExtName;
1308 Arch << ExtInfo.Major << "p" << ExtInfo.Minor;
1309 }
1310
1311 return Arch.str();
1312}
1313
1315RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
1316 ISAInfo->updateImplication();
1317 ISAInfo->updateCombination();
1318 ISAInfo->updateFLen();
1319 ISAInfo->updateMinVLen();
1320 ISAInfo->updateMaxELen();
1321
1322 if (Error Result = ISAInfo->checkDependency())
1323 return std::move(Result);
1324 return std::move(ISAInfo);
1325}
1326
1328 if (XLen == 32) {
1329 if (hasExtension("e"))
1330 return "ilp32e";
1331 if (hasExtension("d"))
1332 return "ilp32d";
1333 if (hasExtension("f"))
1334 return "ilp32f";
1335 return "ilp32";
1336 } else if (XLen == 64) {
1337 if (hasExtension("e"))
1338 return "lp64e";
1339 if (hasExtension("d"))
1340 return "lp64d";
1341 if (hasExtension("f"))
1342 return "lp64f";
1343 return "lp64";
1344 }
1345 llvm_unreachable("Invalid XLEN");
1346}
1347
1349 if (Ext.empty())
1350 return false;
1351
1352 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1353 StringRef Name = Ext.substr(0, Pos);
1354 StringRef Vers = Ext.substr(Pos);
1355 if (Vers.empty())
1356 return false;
1357
1358 unsigned Major, Minor, ConsumeLength;
1359 if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
1360 true, true)) {
1361 consumeError(std::move(E));
1362 return false;
1363 }
1364
1365 return true;
1366}
1367
1369 if (Ext.empty())
1370 return std::string();
1371
1372 auto Pos = findLastNonVersionCharacter(Ext) + 1;
1373 StringRef Name = Ext.substr(0, Pos);
1374
1375 if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext))
1376 return std::string();
1377
1379 return std::string();
1380
1381 return isExperimentalExtension(Name) ? "experimental-" + Name.str()
1382 : Name.str();
1383}
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 const char * ImpliedExtsZcd[]
static const char * ImpliedExtsZvl8192b[]
static const char * ImpliedExtsZks[]
static const char * ImpliedExtsZcb[]
static const char * ImpliedExtsZvksg[]
static const char * ImpliedExtsZvl2048b[]
static const char * ImpliedExtsXTHeadVdot[]
static StringRef getExtensionTypeDesc(StringRef Ext)
static const char * ImpliedExtsZvl512b[]
static const char * ImpliedExtsZve32x[]
static constexpr ImpliedExtsEntry ImpliedExts[]
static const char * ImpliedExtsZve32f[]
static const char * ImpliedExtsZvl4096b[]
static Error processSingleLetterExtension(StringRef &RawExt, MapVector< std::string, RISCVISAUtils::ExtensionVersion, std::map< std::string, unsigned > > &SeenExtMap, bool IgnoreUnknown, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static const RISCVSupportedExtension SupportedExtensions[]
static const char * ImpliedExtsXSfvqmaccqoq[]
static const char * ImpliedExtsZvfh[]
static const char * ImpliedExtsZvl65536b[]
static const char * ImpliedExtsZvkn[]
static const char * ImpliedExtsZve64f[]
static const char * ImpliedExtsXSfvfnrclipxfqf[]
static std::optional< RISCVISAUtils::ExtensionVersion > findDefaultVersion(StringRef ExtName)
static size_t findLastNonVersionCharacter(StringRef Ext)
static const char * ImpliedExtsZicntr[]
static constexpr RISCVProfile SupportedProfiles[]
static const char * ImpliedExtsZvl1024b[]
static const char * ImpliedExtsZhinx[]
static constexpr CombinedExtsEntry CombineIntoExts[]
static const char * ImpliedExtsZcmt[]
static const char * ImpliedExtsZvkng[]
static const char * ImpliedExtsZvks[]
static const char * ImpliedExtsZve64x[]
static const char * ImpliedExtsZk[]
static const char * ImpliedExtsXSfvfwmaccqqq[]
static const char * ImpliedExtsZce[]
static const RISCVSupportedExtension SupportedExperimentalExtensions[]
static const char * ImpliedExtsXSfvcp[]
static const char * ImpliedExtsZvfbfwma[]
static const char * ImpliedExtsZvl256b[]
static StringRef getExtensionType(StringRef Ext)
static const char * ImpliedExtsZfhmin[]
static const char * ImpliedExtsZcf[]
static const char * ImpliedExtsZvknc[]
static const char * ImpliedExtsZicfiss[]
static const char * ImpliedExtsZcmp[]
static const char * ImpliedExtsD[]
static const char * ImpliedExtsZkn[]
static const char * ImpliedExtsXSfvqmaccdod[]
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 const char * ImpliedExtsZvl64b[]
static void PrintExtension(StringRef Name, StringRef Version, StringRef Description)
static const char * ImpliedExtsZihpm[]
static const char * ImpliedExtsZvl16384b[]
static const char * ImpliedExtsZvl128b[]
static const char * ImpliedExtsZvfbfmin[]
static const char * ImpliedExtsZfbfmin[]
static const char * ImpliedExtsF[]
static const char * ImpliedExtsZfh[]
static const char * ImpliedExtsZvknhb[]
static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major, unsigned &Minor, unsigned &ConsumeLength, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck)
static const char * ImpliedExtsZvl32768b[]
static const char * ImpliedExtsZfinx[]
static const char * ImpliedExtsZfa[]
static const char * ImpliedExtsZvksc[]
static const char * ImpliedExtsZcmop[]
static const char * ImpliedExtsZvbb[]
static const char * ImpliedExtsZdinx[]
static const char * ImpliedExtsZhinxmin[]
static const char * RISCVGImplications[]
static const char * ImpliedExtsV[]
static Error getStringErrorForInvalidExt(std::string_view ExtName)
static const char * ImpliedExtsZve64d[]
static Error splitExtsByUnderscore(StringRef Exts, std::vector< std::string > &SplitExts)
static const char * ImpliedExtsZvfhmin[]
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::map< std::string, RISCVISAUtils::ExtensionVersion, RISCVISAUtils::ExtensionComparator > OrderedExtensionMap
OrderedExtensionMap is std::map, it's specialized to keep entries in canonical order of extension.
Definition: RISCVISAInfo.h:33
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)
size_type count(const key_type &key) const
Count the number of elements of a given key in the SetVector.
Definition: SetVector.h:264
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:839
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:686
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
Definition: StringRef.h:641
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:456
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:557
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:595
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:621
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:566
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
Definition: StringRef.h:602
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:22
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 CombineExt
ArrayRef< const char * > RequiredExts
StringLiteral Name
ArrayRef< const char * > Exts
bool operator<(const ImpliedExtsEntry &Other) const
bool operator<(StringRef Other) const
Description of the encoding of one expression Op.
Represents the major and version number components of a RISC-V extension.
Definition: RISCVISAUtils.h:25