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