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