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