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