xref: /llvm-project/llvm/lib/TargetParser/RISCVISAInfo.cpp (revision 163935a48df69bde944fae2b4581541dab30c730)
1733a8778SCraig Topper //===-- RISCVISAInfo.cpp - RISC-V Arch String Parser ----------------------===//
2733a8778SCraig Topper //
3733a8778SCraig Topper // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4733a8778SCraig Topper // See https://llvm.org/LICENSE.txt for license information.
5733a8778SCraig Topper // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6733a8778SCraig Topper //
7733a8778SCraig Topper //===----------------------------------------------------------------------===//
8733a8778SCraig Topper 
9733a8778SCraig Topper #include "llvm/TargetParser/RISCVISAInfo.h"
10733a8778SCraig Topper #include "llvm/ADT/STLExtras.h"
11733a8778SCraig Topper #include "llvm/ADT/StringExtras.h"
12733a8778SCraig Topper #include "llvm/ADT/StringRef.h"
13733a8778SCraig Topper #include "llvm/Support/Errc.h"
14733a8778SCraig Topper #include "llvm/Support/Error.h"
15733a8778SCraig Topper #include "llvm/Support/raw_ostream.h"
16733a8778SCraig Topper 
17733a8778SCraig Topper #include <array>
18733a8778SCraig Topper #include <atomic>
19733a8778SCraig Topper #include <optional>
20733a8778SCraig Topper #include <string>
21733a8778SCraig Topper #include <vector>
22733a8778SCraig Topper 
23733a8778SCraig Topper using namespace llvm;
24733a8778SCraig Topper 
25733a8778SCraig Topper namespace {
26733a8778SCraig Topper 
27733a8778SCraig Topper struct RISCVSupportedExtension {
28733a8778SCraig Topper   const char *Name;
29733a8778SCraig Topper   /// Supported version.
30733a8778SCraig Topper   RISCVISAUtils::ExtensionVersion Version;
31733a8778SCraig Topper 
32733a8778SCraig Topper   bool operator<(const RISCVSupportedExtension &RHS) const {
33733a8778SCraig Topper     return StringRef(Name) < StringRef(RHS.Name);
34733a8778SCraig Topper   }
35733a8778SCraig Topper };
36733a8778SCraig Topper 
37733a8778SCraig Topper struct RISCVProfile {
38733a8778SCraig Topper   StringLiteral Name;
39733a8778SCraig Topper   StringLiteral MArch;
4083f065d5SAlex Bradbury 
4183f065d5SAlex Bradbury   bool operator<(const RISCVProfile &RHS) const {
4283f065d5SAlex Bradbury     return StringRef(Name) < StringRef(RHS.Name);
4383f065d5SAlex Bradbury   }
44733a8778SCraig Topper };
45733a8778SCraig Topper 
46733a8778SCraig Topper } // end anonymous namespace
47733a8778SCraig Topper 
48733a8778SCraig Topper static const char *RISCVGImplications[] = {
49733a8778SCraig Topper   "i", "m", "a", "f", "d", "zicsr", "zifencei"
50733a8778SCraig Topper };
51733a8778SCraig Topper 
5280628ee0SCraig Topper #define GET_SUPPORTED_EXTENSIONS
5380628ee0SCraig Topper #include "llvm/TargetParser/RISCVTargetParserDef.inc"
54733a8778SCraig Topper 
55c705c684SPengcheng Wang #define GET_SUPPORTED_PROFILES
56c705c684SPengcheng Wang #include "llvm/TargetParser/RISCVTargetParserDef.inc"
57733a8778SCraig Topper 
58733a8778SCraig Topper static void verifyTables() {
59733a8778SCraig Topper #ifndef NDEBUG
60733a8778SCraig Topper   static std::atomic<bool> TableChecked(false);
61733a8778SCraig Topper   if (!TableChecked.load(std::memory_order_relaxed)) {
62733a8778SCraig Topper     assert(llvm::is_sorted(SupportedExtensions) &&
63733a8778SCraig Topper            "Extensions are not sorted by name");
64733a8778SCraig Topper     assert(llvm::is_sorted(SupportedExperimentalExtensions) &&
65733a8778SCraig Topper            "Experimental extensions are not sorted by name");
6683f065d5SAlex Bradbury     assert(llvm::is_sorted(SupportedProfiles) &&
6783f065d5SAlex Bradbury            "Profiles are not sorted by name");
6883f065d5SAlex Bradbury     assert(llvm::is_sorted(SupportedExperimentalProfiles) &&
6983f065d5SAlex Bradbury            "Experimental profiles are not sorted by name");
70733a8778SCraig Topper     TableChecked.store(true, std::memory_order_relaxed);
71733a8778SCraig Topper   }
72733a8778SCraig Topper #endif
73733a8778SCraig Topper }
74733a8778SCraig Topper 
75733a8778SCraig Topper static void PrintExtension(StringRef Name, StringRef Version,
76733a8778SCraig Topper                            StringRef Description) {
77733a8778SCraig Topper   outs().indent(4);
78733a8778SCraig Topper   unsigned VersionWidth = Description.empty() ? 0 : 10;
79733a8778SCraig Topper   outs() << left_justify(Name, 21) << left_justify(Version, VersionWidth)
80733a8778SCraig Topper          << Description << "\n";
81733a8778SCraig Topper }
82733a8778SCraig Topper 
83eee5d2d3SMichael Maitland void RISCVISAInfo::printSupportedExtensions(StringMap<StringRef> &DescMap) {
84733a8778SCraig Topper   outs() << "All available -march extensions for RISC-V\n\n";
85733a8778SCraig Topper   PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description"));
86733a8778SCraig Topper 
87de375fbcSCraig Topper   RISCVISAUtils::OrderedExtensionMap ExtMap;
88733a8778SCraig Topper   for (const auto &E : SupportedExtensions)
89733a8778SCraig Topper     ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
90733a8778SCraig Topper   for (const auto &E : ExtMap) {
91733a8778SCraig Topper     std::string Version =
92733a8778SCraig Topper         std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
93733a8778SCraig Topper     PrintExtension(E.first, Version, DescMap[E.first]);
94733a8778SCraig Topper   }
95733a8778SCraig Topper 
96733a8778SCraig Topper   outs() << "\nExperimental extensions\n";
97733a8778SCraig Topper   ExtMap.clear();
98733a8778SCraig Topper   for (const auto &E : SupportedExperimentalExtensions)
99733a8778SCraig Topper     ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
100733a8778SCraig Topper   for (const auto &E : ExtMap) {
101733a8778SCraig Topper     std::string Version =
102733a8778SCraig Topper         std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
103733a8778SCraig Topper     PrintExtension(E.first, Version, DescMap["experimental-" + E.first]);
104733a8778SCraig Topper   }
105733a8778SCraig Topper 
106ab8ac36fSCraig Topper   outs() << "\nSupported Profiles\n";
107ab8ac36fSCraig Topper   for (const auto &P : SupportedProfiles)
108ab8ac36fSCraig Topper     outs().indent(4) << P.Name << "\n";
109ab8ac36fSCraig Topper 
110891d6871SAlex Bradbury   outs() << "\nExperimental Profiles\n";
111891d6871SAlex Bradbury   for (const auto &P : SupportedExperimentalProfiles)
112891d6871SAlex Bradbury     outs().indent(4) << P.Name << "\n";
113891d6871SAlex Bradbury 
114733a8778SCraig Topper   outs() << "\nUse -march to specify the target's extension.\n"
115733a8778SCraig Topper             "For example, clang -march=rv32i_v1p0\n";
116733a8778SCraig Topper }
117733a8778SCraig Topper 
118eee5d2d3SMichael Maitland void RISCVISAInfo::printEnabledExtensions(
119eee5d2d3SMichael Maitland     bool IsRV64, std::set<StringRef> &EnabledFeatureNames,
120eee5d2d3SMichael Maitland     StringMap<StringRef> &DescMap) {
121eee5d2d3SMichael Maitland   outs() << "Extensions enabled for the given RISC-V target\n\n";
122eee5d2d3SMichael Maitland   PrintExtension("Name", "Version", (DescMap.empty() ? "" : "Description"));
123eee5d2d3SMichael Maitland 
124eee5d2d3SMichael Maitland   RISCVISAUtils::OrderedExtensionMap FullExtMap;
125eee5d2d3SMichael Maitland   RISCVISAUtils::OrderedExtensionMap ExtMap;
126eee5d2d3SMichael Maitland   for (const auto &E : SupportedExtensions)
127eee5d2d3SMichael Maitland     if (EnabledFeatureNames.count(E.Name) != 0) {
128eee5d2d3SMichael Maitland       FullExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
129eee5d2d3SMichael Maitland       ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
130eee5d2d3SMichael Maitland     }
131eee5d2d3SMichael Maitland   for (const auto &E : ExtMap) {
132eee5d2d3SMichael Maitland     std::string Version =
133eee5d2d3SMichael Maitland         std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
134eee5d2d3SMichael Maitland     PrintExtension(E.first, Version, DescMap[E.first]);
135eee5d2d3SMichael Maitland   }
136eee5d2d3SMichael Maitland 
137eee5d2d3SMichael Maitland   outs() << "\nExperimental extensions\n";
138eee5d2d3SMichael Maitland   ExtMap.clear();
139eee5d2d3SMichael Maitland   for (const auto &E : SupportedExperimentalExtensions) {
140eee5d2d3SMichael Maitland     StringRef Name(E.Name);
141eee5d2d3SMichael Maitland     if (EnabledFeatureNames.count("experimental-" + Name.str()) != 0) {
142eee5d2d3SMichael Maitland       FullExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
143eee5d2d3SMichael Maitland       ExtMap[E.Name] = {E.Version.Major, E.Version.Minor};
144eee5d2d3SMichael Maitland     }
145eee5d2d3SMichael Maitland   }
146eee5d2d3SMichael Maitland   for (const auto &E : ExtMap) {
147eee5d2d3SMichael Maitland     std::string Version =
148eee5d2d3SMichael Maitland         std::to_string(E.second.Major) + "." + std::to_string(E.second.Minor);
149eee5d2d3SMichael Maitland     PrintExtension(E.first, Version, DescMap["experimental-" + E.first]);
150eee5d2d3SMichael Maitland   }
151eee5d2d3SMichael Maitland 
152eee5d2d3SMichael Maitland   unsigned XLen = IsRV64 ? 64 : 32;
153eee5d2d3SMichael Maitland   if (auto ISAString = RISCVISAInfo::createFromExtMap(XLen, FullExtMap))
154cd6750faSShao-Ce SUN     outs() << "\nISA String: " << ISAString.get()->toString() << "\n";
155eee5d2d3SMichael Maitland }
156eee5d2d3SMichael Maitland 
157733a8778SCraig Topper static bool stripExperimentalPrefix(StringRef &Ext) {
158733a8778SCraig Topper   return Ext.consume_front("experimental-");
159733a8778SCraig Topper }
160733a8778SCraig Topper 
161733a8778SCraig Topper // This function finds the last character that doesn't belong to a version
162733a8778SCraig Topper // (e.g. zba1p0 is extension 'zba' of version '1p0'). So the function will
163733a8778SCraig Topper // consume [0-9]*p[0-9]* starting from the backward. An extension name will not
164733a8778SCraig Topper // end with a digit or the letter 'p', so this function will parse correctly.
165733a8778SCraig Topper // NOTE: This function is NOT able to take empty strings or strings that only
166733a8778SCraig Topper // have version numbers and no extension name. It assumes the extension name
167733a8778SCraig Topper // will be at least more than one character.
168733a8778SCraig Topper static size_t findLastNonVersionCharacter(StringRef Ext) {
169733a8778SCraig Topper   assert(!Ext.empty() &&
170733a8778SCraig Topper          "Already guarded by if-statement in ::parseArchString");
171733a8778SCraig Topper 
172733a8778SCraig Topper   int Pos = Ext.size() - 1;
173733a8778SCraig Topper   while (Pos > 0 && isDigit(Ext[Pos]))
174733a8778SCraig Topper     Pos--;
175733a8778SCraig Topper   if (Pos > 0 && Ext[Pos] == 'p' && isDigit(Ext[Pos - 1])) {
176733a8778SCraig Topper     Pos--;
177733a8778SCraig Topper     while (Pos > 0 && isDigit(Ext[Pos]))
178733a8778SCraig Topper       Pos--;
179733a8778SCraig Topper   }
180733a8778SCraig Topper   return Pos;
181733a8778SCraig Topper }
182733a8778SCraig Topper 
183733a8778SCraig Topper namespace {
184733a8778SCraig Topper struct LessExtName {
185733a8778SCraig Topper   bool operator()(const RISCVSupportedExtension &LHS, StringRef RHS) {
186733a8778SCraig Topper     return StringRef(LHS.Name) < RHS;
187733a8778SCraig Topper   }
188733a8778SCraig Topper   bool operator()(StringRef LHS, const RISCVSupportedExtension &RHS) {
189733a8778SCraig Topper     return LHS < StringRef(RHS.Name);
190733a8778SCraig Topper   }
191733a8778SCraig Topper };
192733a8778SCraig Topper } // namespace
193733a8778SCraig Topper 
194733a8778SCraig Topper static std::optional<RISCVISAUtils::ExtensionVersion>
195733a8778SCraig Topper findDefaultVersion(StringRef ExtName) {
196733a8778SCraig Topper   // Find default version of an extension.
197733a8778SCraig Topper   // TODO: We might set default version based on profile or ISA spec.
198733a8778SCraig Topper   for (auto &ExtInfo : {ArrayRef(SupportedExtensions),
199733a8778SCraig Topper                         ArrayRef(SupportedExperimentalExtensions)}) {
200733a8778SCraig Topper     auto I = llvm::lower_bound(ExtInfo, ExtName, LessExtName());
201733a8778SCraig Topper 
202733a8778SCraig Topper     if (I == ExtInfo.end() || I->Name != ExtName)
203733a8778SCraig Topper       continue;
204733a8778SCraig Topper 
205733a8778SCraig Topper     return I->Version;
206733a8778SCraig Topper   }
207733a8778SCraig Topper   return std::nullopt;
208733a8778SCraig Topper }
209733a8778SCraig Topper 
210733a8778SCraig Topper static StringRef getExtensionTypeDesc(StringRef Ext) {
211bd488c12SCraig Topper   if (Ext.starts_with('s'))
212733a8778SCraig Topper     return "standard supervisor-level extension";
213bd488c12SCraig Topper   if (Ext.starts_with('x'))
214733a8778SCraig Topper     return "non-standard user-level extension";
215bd488c12SCraig Topper   if (Ext.starts_with('z'))
216733a8778SCraig Topper     return "standard user-level extension";
217733a8778SCraig Topper   return StringRef();
218733a8778SCraig Topper }
219733a8778SCraig Topper 
220733a8778SCraig Topper static StringRef getExtensionType(StringRef Ext) {
221bd488c12SCraig Topper   if (Ext.starts_with('s'))
222733a8778SCraig Topper     return "s";
223bd488c12SCraig Topper   if (Ext.starts_with('x'))
224733a8778SCraig Topper     return "x";
225bd488c12SCraig Topper   if (Ext.starts_with('z'))
226733a8778SCraig Topper     return "z";
227733a8778SCraig Topper   return StringRef();
228733a8778SCraig Topper }
229733a8778SCraig Topper 
230733a8778SCraig Topper static std::optional<RISCVISAUtils::ExtensionVersion>
231733a8778SCraig Topper isExperimentalExtension(StringRef Ext) {
232733a8778SCraig Topper   auto I =
233733a8778SCraig Topper       llvm::lower_bound(SupportedExperimentalExtensions, Ext, LessExtName());
234733a8778SCraig Topper   if (I == std::end(SupportedExperimentalExtensions) || I->Name != Ext)
235733a8778SCraig Topper     return std::nullopt;
236733a8778SCraig Topper 
237733a8778SCraig Topper   return I->Version;
238733a8778SCraig Topper }
239733a8778SCraig Topper 
240733a8778SCraig Topper bool RISCVISAInfo::isSupportedExtensionFeature(StringRef Ext) {
241733a8778SCraig Topper   bool IsExperimental = stripExperimentalPrefix(Ext);
242733a8778SCraig Topper 
243733a8778SCraig Topper   ArrayRef<RISCVSupportedExtension> ExtInfo =
244733a8778SCraig Topper       IsExperimental ? ArrayRef(SupportedExperimentalExtensions)
245733a8778SCraig Topper                      : ArrayRef(SupportedExtensions);
246733a8778SCraig Topper 
247733a8778SCraig Topper   auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
248733a8778SCraig Topper   return I != ExtInfo.end() && I->Name == Ext;
249733a8778SCraig Topper }
250733a8778SCraig Topper 
251733a8778SCraig Topper bool RISCVISAInfo::isSupportedExtension(StringRef Ext) {
252733a8778SCraig Topper   verifyTables();
253733a8778SCraig Topper 
254733a8778SCraig Topper   for (auto ExtInfo : {ArrayRef(SupportedExtensions),
255733a8778SCraig Topper                        ArrayRef(SupportedExperimentalExtensions)}) {
256733a8778SCraig Topper     auto I = llvm::lower_bound(ExtInfo, Ext, LessExtName());
257733a8778SCraig Topper     if (I != ExtInfo.end() && I->Name == Ext)
258733a8778SCraig Topper       return true;
259733a8778SCraig Topper   }
260733a8778SCraig Topper 
261733a8778SCraig Topper   return false;
262733a8778SCraig Topper }
263733a8778SCraig Topper 
264733a8778SCraig Topper bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
265733a8778SCraig Topper                                         unsigned MinorVersion) {
266733a8778SCraig Topper   for (auto ExtInfo : {ArrayRef(SupportedExtensions),
267733a8778SCraig Topper                        ArrayRef(SupportedExperimentalExtensions)}) {
268733a8778SCraig Topper     auto Range =
269733a8778SCraig Topper         std::equal_range(ExtInfo.begin(), ExtInfo.end(), Ext, LessExtName());
270733a8778SCraig Topper     for (auto I = Range.first, E = Range.second; I != E; ++I)
271733a8778SCraig Topper       if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion)
272733a8778SCraig Topper         return true;
273733a8778SCraig Topper   }
274733a8778SCraig Topper 
275733a8778SCraig Topper   return false;
276733a8778SCraig Topper }
277733a8778SCraig Topper 
278733a8778SCraig Topper bool RISCVISAInfo::hasExtension(StringRef Ext) const {
279733a8778SCraig Topper   stripExperimentalPrefix(Ext);
280733a8778SCraig Topper 
281733a8778SCraig Topper   if (!isSupportedExtension(Ext))
282733a8778SCraig Topper     return false;
283733a8778SCraig Topper 
284733a8778SCraig Topper   return Exts.count(Ext.str()) != 0;
285733a8778SCraig Topper }
286733a8778SCraig Topper 
287733a8778SCraig Topper std::vector<std::string> RISCVISAInfo::toFeatures(bool AddAllExtensions,
288733a8778SCraig Topper                                                   bool IgnoreUnknown) const {
289733a8778SCraig Topper   std::vector<std::string> Features;
290733a8778SCraig Topper   for (const auto &[ExtName, _] : Exts) {
291733a8778SCraig Topper     // i is a base instruction set, not an extension (see
292733a8778SCraig Topper     // https://github.com/riscv/riscv-isa-manual/blob/main/src/naming.adoc#base-integer-isa)
293733a8778SCraig Topper     // and is not recognized in clang -cc1
294733a8778SCraig Topper     if (ExtName == "i")
295733a8778SCraig Topper       continue;
296733a8778SCraig Topper     if (IgnoreUnknown && !isSupportedExtension(ExtName))
297733a8778SCraig Topper       continue;
298733a8778SCraig Topper 
299733a8778SCraig Topper     if (isExperimentalExtension(ExtName)) {
300733a8778SCraig Topper       Features.push_back((llvm::Twine("+experimental-") + ExtName).str());
301733a8778SCraig Topper     } else {
302733a8778SCraig Topper       Features.push_back((llvm::Twine("+") + ExtName).str());
303733a8778SCraig Topper     }
304733a8778SCraig Topper   }
305733a8778SCraig Topper   if (AddAllExtensions) {
306733a8778SCraig Topper     for (const RISCVSupportedExtension &Ext : SupportedExtensions) {
307733a8778SCraig Topper       if (Exts.count(Ext.Name))
308733a8778SCraig Topper         continue;
309733a8778SCraig Topper       Features.push_back((llvm::Twine("-") + Ext.Name).str());
310733a8778SCraig Topper     }
311733a8778SCraig Topper 
312733a8778SCraig Topper     for (const RISCVSupportedExtension &Ext : SupportedExperimentalExtensions) {
313733a8778SCraig Topper       if (Exts.count(Ext.Name))
314733a8778SCraig Topper         continue;
315733a8778SCraig Topper       Features.push_back((llvm::Twine("-experimental-") + Ext.Name).str());
316733a8778SCraig Topper     }
317733a8778SCraig Topper   }
318733a8778SCraig Topper   return Features;
319733a8778SCraig Topper }
320733a8778SCraig Topper 
321c785eaecSCraig Topper static Error getError(const Twine &Message) {
322c785eaecSCraig Topper   return createStringError(errc::invalid_argument, Message);
323733a8778SCraig Topper }
324c785eaecSCraig Topper 
325c785eaecSCraig Topper static Error getErrorForInvalidExt(StringRef ExtName) {
326c785eaecSCraig Topper   if (ExtName.size() == 1) {
327c785eaecSCraig Topper     return getError("unsupported standard user-level extension '" + ExtName +
328c785eaecSCraig Topper                     "'");
329c785eaecSCraig Topper   }
330c785eaecSCraig Topper   return getError("unsupported " + getExtensionTypeDesc(ExtName) + " '" +
331c785eaecSCraig Topper                   ExtName + "'");
332733a8778SCraig Topper }
333733a8778SCraig Topper 
334733a8778SCraig Topper // Extensions may have a version number, and may be separated by
335733a8778SCraig Topper // an underscore '_' e.g.: rv32i2_m2.
336733a8778SCraig Topper // Version number is divided into major and minor version numbers,
337733a8778SCraig Topper // separated by a 'p'. If the minor version is 0 then 'p0' can be
338733a8778SCraig Topper // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
339733a8778SCraig Topper static Error getExtensionVersion(StringRef Ext, StringRef In, unsigned &Major,
340733a8778SCraig Topper                                  unsigned &Minor, unsigned &ConsumeLength,
341733a8778SCraig Topper                                  bool EnableExperimentalExtension,
342733a8778SCraig Topper                                  bool ExperimentalExtensionVersionCheck) {
343733a8778SCraig Topper   StringRef MajorStr, MinorStr;
344733a8778SCraig Topper   Major = 0;
345733a8778SCraig Topper   Minor = 0;
346733a8778SCraig Topper   ConsumeLength = 0;
347733a8778SCraig Topper   MajorStr = In.take_while(isDigit);
348733a8778SCraig Topper   In = In.substr(MajorStr.size());
349733a8778SCraig Topper 
350733a8778SCraig Topper   if (!MajorStr.empty() && In.consume_front("p")) {
351733a8778SCraig Topper     MinorStr = In.take_while(isDigit);
352733a8778SCraig Topper     In = In.substr(MajorStr.size() + MinorStr.size() - 1);
353733a8778SCraig Topper 
354733a8778SCraig Topper     // Expected 'p' to be followed by minor version number.
355733a8778SCraig Topper     if (MinorStr.empty()) {
356c785eaecSCraig Topper       return getError("minor version number missing after 'p' for extension '" +
357c785eaecSCraig Topper                       Ext + "'");
358733a8778SCraig Topper     }
359733a8778SCraig Topper   }
360733a8778SCraig Topper 
361733a8778SCraig Topper   if (!MajorStr.empty() && MajorStr.getAsInteger(10, Major))
362c785eaecSCraig Topper     return getError("Failed to parse major version number for extension '" +
363c785eaecSCraig Topper                     Ext + "'");
364733a8778SCraig Topper 
365733a8778SCraig Topper   if (!MinorStr.empty() && MinorStr.getAsInteger(10, Minor))
366c785eaecSCraig Topper     return getError("Failed to parse minor version number for extension '" +
367c785eaecSCraig Topper                     Ext + "'");
368733a8778SCraig Topper 
369733a8778SCraig Topper   ConsumeLength = MajorStr.size();
370733a8778SCraig Topper 
371733a8778SCraig Topper   if (!MinorStr.empty())
372733a8778SCraig Topper     ConsumeLength += MinorStr.size() + 1 /*'p'*/;
373733a8778SCraig Topper 
374733a8778SCraig Topper   // Expected multi-character extension with version number to have no
375733a8778SCraig Topper   // subsequent characters (i.e. must either end string or be followed by
376733a8778SCraig Topper   // an underscore).
377733a8778SCraig Topper   if (Ext.size() > 1 && In.size())
378c785eaecSCraig Topper     return getError(
379733a8778SCraig Topper         "multi-character extensions must be separated by underscores");
380733a8778SCraig Topper 
381733a8778SCraig Topper   // If experimental extension, require use of current version number
382733a8778SCraig Topper   if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
383733a8778SCraig Topper     if (!EnableExperimentalExtension)
384c785eaecSCraig Topper       return getError("requires '-menable-experimental-extensions' "
385733a8778SCraig Topper                       "for experimental extension '" +
386733a8778SCraig Topper                       Ext + "'");
387733a8778SCraig Topper 
388733a8778SCraig Topper     if (ExperimentalExtensionVersionCheck &&
389733a8778SCraig Topper         (MajorStr.empty() && MinorStr.empty()))
390c785eaecSCraig Topper       return getError(
391733a8778SCraig Topper           "experimental extension requires explicit version number `" + Ext +
392733a8778SCraig Topper           "`");
393733a8778SCraig Topper 
394733a8778SCraig Topper     auto SupportedVers = *ExperimentalExtension;
395733a8778SCraig Topper     if (ExperimentalExtensionVersionCheck &&
396733a8778SCraig Topper         (Major != SupportedVers.Major || Minor != SupportedVers.Minor)) {
397733a8778SCraig Topper       std::string Error = "unsupported version number " + MajorStr.str();
398733a8778SCraig Topper       if (!MinorStr.empty())
399733a8778SCraig Topper         Error += "." + MinorStr.str();
400733a8778SCraig Topper       Error += " for experimental extension '" + Ext.str() +
401733a8778SCraig Topper                "' (this compiler supports " + utostr(SupportedVers.Major) +
402733a8778SCraig Topper                "." + utostr(SupportedVers.Minor) + ")";
403c785eaecSCraig Topper       return getError(Error);
404733a8778SCraig Topper     }
405733a8778SCraig Topper     return Error::success();
406733a8778SCraig Topper   }
407733a8778SCraig Topper 
408733a8778SCraig Topper   // Exception rule for `g`, we don't have clear version scheme for that on
409733a8778SCraig Topper   // ISA spec.
410733a8778SCraig Topper   if (Ext == "g")
411733a8778SCraig Topper     return Error::success();
412733a8778SCraig Topper 
413733a8778SCraig Topper   if (MajorStr.empty() && MinorStr.empty()) {
414733a8778SCraig Topper     if (auto DefaultVersion = findDefaultVersion(Ext)) {
415733a8778SCraig Topper       Major = DefaultVersion->Major;
416733a8778SCraig Topper       Minor = DefaultVersion->Minor;
417733a8778SCraig Topper     }
418733a8778SCraig Topper     // No matter found or not, return success, assume other place will
419733a8778SCraig Topper     // verify.
420733a8778SCraig Topper     return Error::success();
421733a8778SCraig Topper   }
422733a8778SCraig Topper 
423733a8778SCraig Topper   if (RISCVISAInfo::isSupportedExtension(Ext, Major, Minor))
424733a8778SCraig Topper     return Error::success();
425733a8778SCraig Topper 
426733a8778SCraig Topper   if (!RISCVISAInfo::isSupportedExtension(Ext))
427c785eaecSCraig Topper     return getErrorForInvalidExt(Ext);
428733a8778SCraig Topper 
429c785eaecSCraig Topper   std::string Error = "unsupported version number " + MajorStr.str();
430733a8778SCraig Topper   if (!MinorStr.empty())
431733a8778SCraig Topper     Error += "." + MinorStr.str();
432733a8778SCraig Topper   Error += " for extension '" + Ext.str() + "'";
433c785eaecSCraig Topper   return getError(Error);
434733a8778SCraig Topper }
435733a8778SCraig Topper 
436733a8778SCraig Topper llvm::Expected<std::unique_ptr<RISCVISAInfo>>
43766470112SCraig Topper RISCVISAInfo::createFromExtMap(unsigned XLen,
43866470112SCraig Topper                                const RISCVISAUtils::OrderedExtensionMap &Exts) {
43966470112SCraig Topper   assert(XLen == 32 || XLen == 64);
44066470112SCraig Topper   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
44166470112SCraig Topper 
44266470112SCraig Topper   ISAInfo->Exts = Exts;
44366470112SCraig Topper 
44466470112SCraig Topper   return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
44566470112SCraig Topper }
44666470112SCraig Topper 
44766470112SCraig Topper llvm::Expected<std::unique_ptr<RISCVISAInfo>>
448733a8778SCraig Topper RISCVISAInfo::parseFeatures(unsigned XLen,
449733a8778SCraig Topper                             const std::vector<std::string> &Features) {
450733a8778SCraig Topper   assert(XLen == 32 || XLen == 64);
451733a8778SCraig Topper   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
452733a8778SCraig Topper 
453733a8778SCraig Topper   for (auto &Feature : Features) {
454733a8778SCraig Topper     StringRef ExtName = Feature;
455733a8778SCraig Topper     assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-'));
456733a8778SCraig Topper     bool Add = ExtName[0] == '+';
457733a8778SCraig Topper     ExtName = ExtName.drop_front(1); // Drop '+' or '-'
458326667d7SCraig Topper     bool Experimental = stripExperimentalPrefix(ExtName);
459733a8778SCraig Topper     auto ExtensionInfos = Experimental
460733a8778SCraig Topper                               ? ArrayRef(SupportedExperimentalExtensions)
461733a8778SCraig Topper                               : ArrayRef(SupportedExtensions);
462733a8778SCraig Topper     auto ExtensionInfoIterator =
463733a8778SCraig Topper         llvm::lower_bound(ExtensionInfos, ExtName, LessExtName());
464733a8778SCraig Topper 
465733a8778SCraig Topper     // Not all features is related to ISA extension, like `relax` or
466733a8778SCraig Topper     // `save-restore`, skip those feature.
467733a8778SCraig Topper     if (ExtensionInfoIterator == ExtensionInfos.end() ||
468733a8778SCraig Topper         ExtensionInfoIterator->Name != ExtName)
469733a8778SCraig Topper       continue;
470733a8778SCraig Topper 
471733a8778SCraig Topper     if (Add)
47208969ca1SCraig Topper       ISAInfo->Exts[ExtName.str()] = ExtensionInfoIterator->Version;
473733a8778SCraig Topper     else
474733a8778SCraig Topper       ISAInfo->Exts.erase(ExtName.str());
475733a8778SCraig Topper   }
476733a8778SCraig Topper 
477733a8778SCraig Topper   return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
478733a8778SCraig Topper }
479733a8778SCraig Topper 
480733a8778SCraig Topper llvm::Expected<std::unique_ptr<RISCVISAInfo>>
481733a8778SCraig Topper RISCVISAInfo::parseNormalizedArchString(StringRef Arch) {
482941eab10SCraig Topper   // RISC-V ISA strings must be [a-z0-9_]
483941eab10SCraig Topper   if (!llvm::all_of(
484941eab10SCraig Topper           Arch, [](char C) { return isDigit(C) || isLower(C) || C == '_'; }))
485c785eaecSCraig Topper     return getError("string may only contain [a-z0-9_]");
486f0cc3735SCraig Topper 
487733a8778SCraig Topper   // Must start with a valid base ISA name.
4881b942ae3SCraig Topper   unsigned XLen = 0;
4891b942ae3SCraig Topper   if (Arch.consume_front("rv32"))
490733a8778SCraig Topper     XLen = 32;
4911b942ae3SCraig Topper   else if (Arch.consume_front("rv64"))
492733a8778SCraig Topper     XLen = 64;
4931b942ae3SCraig Topper 
4941b942ae3SCraig Topper   if (XLen == 0 || Arch.empty() || (Arch[0] != 'i' && Arch[0] != 'e'))
495c785eaecSCraig Topper     return getError("arch string must begin with valid base ISA");
4961b942ae3SCraig Topper 
497733a8778SCraig Topper   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
498733a8778SCraig Topper 
499733a8778SCraig Topper   // Each extension is of the form ${name}${major_version}p${minor_version}
500733a8778SCraig Topper   // and separated by _. Split by _ and then extract the name and version
501733a8778SCraig Topper   // information for each extension.
502d8f8ac8fSCraig Topper   while (!Arch.empty()) {
503d8f8ac8fSCraig Topper     if (Arch[0] == '_') {
504d8f8ac8fSCraig Topper       if (Arch.size() == 1 || Arch[1] == '_')
505c785eaecSCraig Topper         return getError("extension name missing after separator '_'");
506d8f8ac8fSCraig Topper       Arch = Arch.drop_front();
507d8f8ac8fSCraig Topper     }
508d8f8ac8fSCraig Topper 
509d8f8ac8fSCraig Topper     size_t Idx = Arch.find('_');
510d8f8ac8fSCraig Topper     StringRef Ext = Arch.slice(0, Idx);
51133e7cd6fSKazu Hirata     Arch = Arch.substr(Idx);
512d8f8ac8fSCraig Topper 
513733a8778SCraig Topper     StringRef Prefix, MinorVersionStr;
514733a8778SCraig Topper     std::tie(Prefix, MinorVersionStr) = Ext.rsplit('p');
515733a8778SCraig Topper     if (MinorVersionStr.empty())
516c785eaecSCraig Topper       return getError("extension lacks version in expected format");
517733a8778SCraig Topper     unsigned MajorVersion, MinorVersion;
518733a8778SCraig Topper     if (MinorVersionStr.getAsInteger(10, MinorVersion))
519c785eaecSCraig Topper       return getError("failed to parse minor version number");
520733a8778SCraig Topper 
521733a8778SCraig Topper     // Split Prefix into the extension name and the major version number
522733a8778SCraig Topper     // (the trailing digits of Prefix).
523500dda04SCraig Topper     size_t VersionStart = Prefix.size();
524500dda04SCraig Topper     while (VersionStart != 0) {
525500dda04SCraig Topper       if (!isDigit(Prefix[VersionStart - 1]))
526733a8778SCraig Topper         break;
527500dda04SCraig Topper       --VersionStart;
528733a8778SCraig Topper     }
529500dda04SCraig Topper     if (VersionStart == Prefix.size())
530c785eaecSCraig Topper       return getError("extension lacks version in expected format");
531733a8778SCraig Topper 
5325445a35dSCraig Topper     if (VersionStart == 0)
533c785eaecSCraig Topper       return getError("missing extension name");
5345445a35dSCraig Topper 
535500dda04SCraig Topper     StringRef ExtName = Prefix.slice(0, VersionStart);
53633e7cd6fSKazu Hirata     StringRef MajorVersionStr = Prefix.substr(VersionStart);
537733a8778SCraig Topper     if (MajorVersionStr.getAsInteger(10, MajorVersion))
538c785eaecSCraig Topper       return getError("failed to parse major version number");
5397a6847e0SCraig Topper 
5406cba93f2SCraig Topper     if ((ExtName[0] == 'z' || ExtName[0] == 's' || ExtName[0] == 'x') &&
5416cba93f2SCraig Topper         (ExtName.size() == 1 || isDigit(ExtName[1])))
542c785eaecSCraig Topper       return getError("'" + Twine(ExtName[0]) +
5436cba93f2SCraig Topper                       "' must be followed by a letter");
5447a6847e0SCraig Topper 
54508969ca1SCraig Topper     if (!ISAInfo->Exts
54608969ca1SCraig Topper              .emplace(
54708969ca1SCraig Topper                  ExtName.str(),
54808969ca1SCraig Topper                  RISCVISAUtils::ExtensionVersion{MajorVersion, MinorVersion})
54908969ca1SCraig Topper              .second)
550c785eaecSCraig Topper       return getError("duplicate extension '" + ExtName + "'");
551733a8778SCraig Topper   }
552cf3c714eSCraig Topper   ISAInfo->updateImpliedLengths();
553733a8778SCraig Topper   return std::move(ISAInfo);
554733a8778SCraig Topper }
555733a8778SCraig Topper 
556733a8778SCraig Topper llvm::Expected<std::unique_ptr<RISCVISAInfo>>
557733a8778SCraig Topper RISCVISAInfo::parseArchString(StringRef Arch, bool EnableExperimentalExtension,
55887de4975SCraig Topper                               bool ExperimentalExtensionVersionCheck) {
5590faf4942SCraig Topper   // RISC-V ISA strings must be [a-z0-9_]
5600faf4942SCraig Topper   if (!llvm::all_of(
5610faf4942SCraig Topper           Arch, [](char C) { return isDigit(C) || isLower(C) || C == '_'; }))
562c785eaecSCraig Topper     return getError("string may only contain [a-z0-9_]");
563733a8778SCraig Topper 
56409f4b06dSCraig Topper   // ISA string must begin with rv32, rv64, or a profile.
56509f4b06dSCraig Topper   unsigned XLen = 0;
56609f4b06dSCraig Topper   if (Arch.consume_front("rv32")) {
56709f4b06dSCraig Topper     XLen = 32;
56809f4b06dSCraig Topper   } else if (Arch.consume_front("rv64")) {
56909f4b06dSCraig Topper     XLen = 64;
57009f4b06dSCraig Topper   } else {
57109f4b06dSCraig Topper     // Try parsing as a profile.
572891d6871SAlex Bradbury     auto ProfileCmp = [](StringRef Arch, const RISCVProfile &Profile) {
573a7e07988SCraig Topper       return Arch < Profile.Name;
574891d6871SAlex Bradbury     };
575891d6871SAlex Bradbury     auto I = llvm::upper_bound(SupportedProfiles, Arch, ProfileCmp);
576891d6871SAlex Bradbury     bool FoundProfile = I != std::begin(SupportedProfiles) &&
577891d6871SAlex Bradbury                         Arch.starts_with(std::prev(I)->Name);
578891d6871SAlex Bradbury     if (!FoundProfile) {
579891d6871SAlex Bradbury       I = llvm::upper_bound(SupportedExperimentalProfiles, Arch, ProfileCmp);
580891d6871SAlex Bradbury       FoundProfile = (I != std::begin(SupportedExperimentalProfiles) &&
581891d6871SAlex Bradbury                       Arch.starts_with(std::prev(I)->Name));
582891d6871SAlex Bradbury       if (FoundProfile && !EnableExperimentalExtension) {
583c785eaecSCraig Topper         return getError("requires '-menable-experimental-extensions' "
584891d6871SAlex Bradbury                         "for profile '" +
585891d6871SAlex Bradbury                         std::prev(I)->Name + "'");
586891d6871SAlex Bradbury       }
587891d6871SAlex Bradbury     }
588891d6871SAlex Bradbury     if (FoundProfile) {
589891d6871SAlex Bradbury       --I;
590a7e07988SCraig Topper       std::string NewArch = I->MArch.str();
591a7e07988SCraig Topper       StringRef ArchWithoutProfile = Arch.drop_front(I->Name.size());
592733a8778SCraig Topper       if (!ArchWithoutProfile.empty()) {
59309f4b06dSCraig Topper         if (ArchWithoutProfile.front() != '_')
594c785eaecSCraig Topper           return getError("additional extensions must be after separator '_'");
595733a8778SCraig Topper         NewArch += ArchWithoutProfile.str();
596733a8778SCraig Topper       }
597733a8778SCraig Topper       return parseArchString(NewArch, EnableExperimentalExtension,
59887de4975SCraig Topper                              ExperimentalExtensionVersionCheck);
599733a8778SCraig Topper     }
60009f4b06dSCraig Topper   }
6011b942ae3SCraig Topper 
6021b942ae3SCraig Topper   if (XLen == 0 || Arch.empty())
603c785eaecSCraig Topper     return getError(
60409f4b06dSCraig Topper         "string must begin with rv32{i,e,g}, rv64{i,e,g}, or a supported "
60509f4b06dSCraig Topper         "profile name");
606733a8778SCraig Topper 
607733a8778SCraig Topper   std::unique_ptr<RISCVISAInfo> ISAInfo(new RISCVISAInfo(XLen));
608733a8778SCraig Topper 
609733a8778SCraig Topper   // The canonical order specified in ISA manual.
610733a8778SCraig Topper   // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
6111b942ae3SCraig Topper   char Baseline = Arch.front();
612299d3ddcSCraig Topper   // Skip the baseline.
6137aa906ddSCraig Topper   Arch = Arch.drop_front();
614299d3ddcSCraig Topper 
615299d3ddcSCraig Topper   unsigned Major, Minor, ConsumeLength;
616733a8778SCraig Topper 
617733a8778SCraig Topper   // First letter should be 'e', 'i' or 'g'.
618733a8778SCraig Topper   switch (Baseline) {
619733a8778SCraig Topper   default:
620c785eaecSCraig Topper     return getError("first letter after \'rv" + Twine(XLen) +
6216f02120aSDavid Spickett                     "\' should be 'e', 'i' or 'g'");
622733a8778SCraig Topper   case 'e':
623733a8778SCraig Topper   case 'i':
624733a8778SCraig Topper     // Baseline is `i` or `e`
625733a8778SCraig Topper     if (auto E = getExtensionVersion(
6267aa906ddSCraig Topper             StringRef(&Baseline, 1), Arch, Major, Minor, ConsumeLength,
62787de4975SCraig Topper             EnableExperimentalExtension, ExperimentalExtensionVersionCheck))
628733a8778SCraig Topper       return std::move(E);
629733a8778SCraig Topper 
630c156d421SCraig Topper     ISAInfo->Exts[std::string(1, Baseline)] = {Major, Minor};
631299d3ddcSCraig Topper     break;
632299d3ddcSCraig Topper   case 'g':
633299d3ddcSCraig Topper     // g expands to extensions in RISCVGImplications.
6347aa906ddSCraig Topper     if (!Arch.empty() && isDigit(Arch.front()))
635c785eaecSCraig Topper       return getError("version not supported for 'g'");
636299d3ddcSCraig Topper 
637299d3ddcSCraig Topper     // Versions for g are disallowed, and this was checked for previously.
638299d3ddcSCraig Topper     ConsumeLength = 0;
639299d3ddcSCraig Topper 
640299d3ddcSCraig Topper     // No matter which version is given to `g`, we always set imafd to default
641299d3ddcSCraig Topper     // version since the we don't have clear version scheme for that on
642299d3ddcSCraig Topper     // ISA spec.
643c156d421SCraig Topper     for (const char *Ext : RISCVGImplications) {
644299d3ddcSCraig Topper       auto Version = findDefaultVersion(Ext);
645299d3ddcSCraig Topper       assert(Version && "Default extension version not found?");
646299d3ddcSCraig Topper       // Postpone AddExtension until end of this function
647c156d421SCraig Topper       ISAInfo->Exts[std::string(Ext)] = {Version->Major, Version->Minor};
648299d3ddcSCraig Topper     }
649299d3ddcSCraig Topper     break;
650733a8778SCraig Topper   }
651733a8778SCraig Topper 
652733a8778SCraig Topper   // Consume the base ISA version number and any '_' between rvxxx and the
653733a8778SCraig Topper   // first extension
6547aa906ddSCraig Topper   Arch = Arch.drop_front(ConsumeLength);
655733a8778SCraig Topper 
6567aa906ddSCraig Topper   while (!Arch.empty()) {
6577aa906ddSCraig Topper     if (Arch.front() == '_') {
6587aa906ddSCraig Topper       if (Arch.size() == 1 || Arch[1] == '_')
659c785eaecSCraig Topper         return getError("extension name missing after separator '_'");
6607aa906ddSCraig Topper       Arch = Arch.drop_front();
66130aa49cbSCraig Topper     }
66230aa49cbSCraig Topper 
6637aa906ddSCraig Topper     size_t Idx = Arch.find('_');
6647aa906ddSCraig Topper     StringRef Ext = Arch.slice(0, Idx);
66533e7cd6fSKazu Hirata     Arch = Arch.substr(Idx);
6661aaab334SCraig Topper 
6671aaab334SCraig Topper     do {
668f906e3ddSCraig Topper       StringRef Name, Vers, Desc;
6691aaab334SCraig Topper       if (RISCVISAUtils::AllStdExts.contains(Ext.front())) {
670f906e3ddSCraig Topper         Name = Ext.take_front(1);
671f906e3ddSCraig Topper         Ext = Ext.drop_front();
672f906e3ddSCraig Topper         Vers = Ext;
673f906e3ddSCraig Topper         Desc = "standard user-level extension";
6741aaab334SCraig Topper       } else if (Ext.front() == 'z' || Ext.front() == 's' ||
6751aaab334SCraig Topper                  Ext.front() == 'x') {
676733a8778SCraig Topper         // Handle other types of extensions other than the standard
677733a8778SCraig Topper         // general purpose and standard user-level extensions.
678733a8778SCraig Topper         // Parse the ISA string containing non-standard user-level
679733a8778SCraig Topper         // extensions, standard supervisor-level extensions and
680733a8778SCraig Topper         // non-standard supervisor-level extensions.
681733a8778SCraig Topper         // These extensions start with 'z', 's', 'x' prefixes, might have a
682733a8778SCraig Topper         // version number (major, minor) and are separated by a single
683733a8778SCraig Topper         // underscore '_'. We do not enforce a canonical order for them.
684f906e3ddSCraig Topper         StringRef Type = getExtensionType(Ext);
685f906e3ddSCraig Topper         Desc = getExtensionTypeDesc(Ext);
686f906e3ddSCraig Topper         auto Pos = findLastNonVersionCharacter(Ext) + 1;
687f906e3ddSCraig Topper         Name = Ext.substr(0, Pos);
688f906e3ddSCraig Topper         Vers = Ext.substr(Pos);
689f906e3ddSCraig Topper         Ext = StringRef();
690f906e3ddSCraig Topper 
691f906e3ddSCraig Topper         assert(!Type.empty() && "Empty type?");
69287de4975SCraig Topper         if (Name.size() == Type.size())
693c785eaecSCraig Topper           return getError(Desc + " name missing after '" + Type + "'");
694733a8778SCraig Topper       } else {
695c785eaecSCraig Topper         return getError("invalid standard user-level extension '" +
6961aaab334SCraig Topper                         Twine(Ext.front()) + "'");
697733a8778SCraig Topper       }
698f906e3ddSCraig Topper 
699f906e3ddSCraig Topper       unsigned Major, Minor, ConsumeLength;
700f906e3ddSCraig Topper       if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
701f906e3ddSCraig Topper                                        EnableExperimentalExtension,
70287de4975SCraig Topper                                        ExperimentalExtensionVersionCheck))
703299d3ddcSCraig Topper         return E;
704299d3ddcSCraig Topper 
705f906e3ddSCraig Topper       if (Name.size() == 1)
706f906e3ddSCraig Topper         Ext = Ext.substr(ConsumeLength);
707f906e3ddSCraig Topper 
708c156d421SCraig Topper       if (!RISCVISAInfo::isSupportedExtension(Name))
709c156d421SCraig Topper         return getErrorForInvalidExt(Name);
710c156d421SCraig Topper 
711c156d421SCraig Topper       // Insert and error for duplicates.
712c156d421SCraig Topper       if (!ISAInfo->Exts
713c156d421SCraig Topper                .emplace(Name.str(),
714c156d421SCraig Topper                         RISCVISAUtils::ExtensionVersion{Major, Minor})
715c156d421SCraig Topper                .second)
716c785eaecSCraig Topper         return getError("duplicated " + Desc + " '" + Name + "'");
717f906e3ddSCraig Topper 
7181aaab334SCraig Topper     } while (!Ext.empty());
719733a8778SCraig Topper   }
720733a8778SCraig Topper 
721733a8778SCraig Topper   return RISCVISAInfo::postProcessAndChecking(std::move(ISAInfo));
722733a8778SCraig Topper }
723733a8778SCraig Topper 
72410a4f1efSCraig Topper static Error getIncompatibleError(StringRef Ext1, StringRef Ext2) {
72510a4f1efSCraig Topper   return getError("'" + Ext1 + "' and '" + Ext2 +
72610a4f1efSCraig Topper                   "' extensions are incompatible");
72710a4f1efSCraig Topper }
72810a4f1efSCraig Topper 
72910a4f1efSCraig Topper static Error getExtensionRequiresError(StringRef Ext, StringRef ReqExt) {
73010a4f1efSCraig Topper   return getError("'" + Ext + "' requires '" + ReqExt +
73110a4f1efSCraig Topper                   "' extension to also be specified");
73210a4f1efSCraig Topper }
73310a4f1efSCraig Topper 
734733a8778SCraig Topper Error RISCVISAInfo::checkDependency() {
735844355a8SVincentWu   bool HasE = Exts.count("e") != 0;
736844355a8SVincentWu   bool HasI = Exts.count("i") != 0;
737733a8778SCraig Topper   bool HasC = Exts.count("c") != 0;
738733a8778SCraig Topper   bool HasF = Exts.count("f") != 0;
7393c5f929aSR   bool HasD = Exts.count("d") != 0;
740733a8778SCraig Topper   bool HasZfinx = Exts.count("zfinx") != 0;
741733a8778SCraig Topper   bool HasVector = Exts.count("zve32x") != 0;
742733a8778SCraig Topper   bool HasZvl = MinVLen != 0;
743733a8778SCraig Topper   bool HasZcmt = Exts.count("zcmt") != 0;
7446881c6d2SSudharsan Veeravalli   static constexpr StringLiteral XqciExts[] = {
745171d3eddSquic_hchandel       {"xqcia"},   {"xqciac"},  {"xqcicli"}, {"xqcicm"},  {"xqcics"},
746*163935a4Squic_hchandel       {"xqcicsr"}, {"xqciint"}, {"xqcilo"},  {"xqcilsm"}, {"xqcisls"}};
747733a8778SCraig Topper 
748844355a8SVincentWu   if (HasI && HasE)
749371f936cSCraig Topper     return getIncompatibleError("i", "e");
750844355a8SVincentWu 
751733a8778SCraig Topper   if (HasF && HasZfinx)
75210a4f1efSCraig Topper     return getIncompatibleError("f", "zfinx");
753733a8778SCraig Topper 
754733a8778SCraig Topper   if (HasZvl && !HasVector)
75510a4f1efSCraig Topper     return getExtensionRequiresError("zvl*b", "v' or 'zve*");
756733a8778SCraig Topper 
7573c5f929aSR   if ((HasZcmt || Exts.count("zcmp")) && HasD && (HasC || Exts.count("zcd")))
758c785eaecSCraig Topper     return getError(Twine("'") + (HasZcmt ? "zcmt" : "zcmp") +
759c785eaecSCraig Topper                     "' extension is incompatible with '" +
760c785eaecSCraig Topper                     (HasC ? "c" : "zcd") +
761733a8778SCraig Topper                     "' extension when 'd' extension is enabled");
762733a8778SCraig Topper 
763733a8778SCraig Topper   if (XLen != 32 && Exts.count("zcf"))
764c785eaecSCraig Topper     return getError("'zcf' is only supported for 'rv32'");
765733a8778SCraig Topper 
7663c5f929aSR   if (Exts.count("xwchc") != 0) {
7673c5f929aSR     if (XLen != 32)
768371f936cSCraig Topper       return getError("'xwchc' is only supported for 'rv32'");
7693c5f929aSR 
7703c5f929aSR     if (HasD)
771371f936cSCraig Topper       return getIncompatibleError("d", "xwchc");
7723c5f929aSR 
7733c5f929aSR     if (Exts.count("zcb") != 0)
774371f936cSCraig Topper       return getIncompatibleError("xwchc", "zcb");
7753c5f929aSR   }
7763c5f929aSR 
7778fcbba82SSudharsan Veeravalli   for (auto Ext : XqciExts)
7788fcbba82SSudharsan Veeravalli     if (Exts.count(Ext.str()) && (XLen != 32))
7798fcbba82SSudharsan Veeravalli       return getError("'" + Twine(Ext) + "'" + " is only supported for 'rv32'");
780c4645ffeSSudharsan Veeravalli 
781733a8778SCraig Topper   return Error::success();
782733a8778SCraig Topper }
783733a8778SCraig Topper 
784733a8778SCraig Topper struct ImpliedExtsEntry {
785733a8778SCraig Topper   StringLiteral Name;
786451e853eSCraig Topper   const char *ImpliedExt;
787733a8778SCraig Topper 
788733a8778SCraig Topper   bool operator<(const ImpliedExtsEntry &Other) const {
789733a8778SCraig Topper     return Name < Other.Name;
790733a8778SCraig Topper   }
791733a8778SCraig Topper };
792733a8778SCraig Topper 
793451e853eSCraig Topper static bool operator<(const ImpliedExtsEntry &LHS, StringRef RHS) {
794451e853eSCraig Topper   return LHS.Name < RHS;
795451e853eSCraig Topper }
796451e853eSCraig Topper 
797451e853eSCraig Topper static bool operator<(StringRef LHS, const ImpliedExtsEntry &RHS) {
798451e853eSCraig Topper   return LHS < RHS.Name;
799451e853eSCraig Topper }
800451e853eSCraig Topper 
80180628ee0SCraig Topper #define GET_IMPLIED_EXTENSIONS
80280628ee0SCraig Topper #include "llvm/TargetParser/RISCVTargetParserDef.inc"
803733a8778SCraig Topper 
804733a8778SCraig Topper void RISCVISAInfo::updateImplication() {
805733a8778SCraig Topper   bool HasE = Exts.count("e") != 0;
806733a8778SCraig Topper   bool HasI = Exts.count("i") != 0;
807733a8778SCraig Topper 
808733a8778SCraig Topper   // If not in e extension and i extension does not exist, i extension is
809733a8778SCraig Topper   // implied
810733a8778SCraig Topper   if (!HasE && !HasI) {
811733a8778SCraig Topper     auto Version = findDefaultVersion("i");
81208969ca1SCraig Topper     Exts["i"] = *Version;
813733a8778SCraig Topper   }
814733a8778SCraig Topper 
815844355a8SVincentWu   if (HasE && HasI)
816844355a8SVincentWu     Exts.erase("i");
817844355a8SVincentWu 
818733a8778SCraig Topper   assert(llvm::is_sorted(ImpliedExts) && "Table not sorted by Name");
819733a8778SCraig Topper 
820733a8778SCraig Topper   // This loop may execute over 1 iteration since implication can be layered
821733a8778SCraig Topper   // Exits loop if no more implication is applied
8220e938017SCraig Topper   SmallVector<StringRef, 16> WorkList;
823733a8778SCraig Topper   for (auto const &Ext : Exts)
8240e938017SCraig Topper     WorkList.push_back(Ext.first);
825733a8778SCraig Topper 
826733a8778SCraig Topper   while (!WorkList.empty()) {
827733a8778SCraig Topper     StringRef ExtName = WorkList.pop_back_val();
828451e853eSCraig Topper     auto Range = std::equal_range(std::begin(ImpliedExts),
829451e853eSCraig Topper                                   std::end(ImpliedExts), ExtName);
830451e853eSCraig Topper     std::for_each(Range.first, Range.second,
831451e853eSCraig Topper                   [&](const ImpliedExtsEntry &Implied) {
832451e853eSCraig Topper                     const char *ImpliedExt = Implied.ImpliedExt;
833733a8778SCraig Topper                     if (Exts.count(ImpliedExt))
834451e853eSCraig Topper                       return;
835733a8778SCraig Topper                     auto Version = findDefaultVersion(ImpliedExt);
83608969ca1SCraig Topper                     Exts[ImpliedExt] = *Version;
8370e938017SCraig Topper                     WorkList.push_back(ImpliedExt);
838451e853eSCraig Topper                   });
839733a8778SCraig Topper   }
840733a8778SCraig Topper 
841733a8778SCraig Topper   // Add Zcf if Zce and F are enabled on RV32.
842733a8778SCraig Topper   if (XLen == 32 && Exts.count("zce") && Exts.count("f") &&
843733a8778SCraig Topper       !Exts.count("zcf")) {
844733a8778SCraig Topper     auto Version = findDefaultVersion("zcf");
84508969ca1SCraig Topper     Exts["zcf"] = *Version;
846733a8778SCraig Topper   }
847733a8778SCraig Topper }
848733a8778SCraig Topper 
849451e853eSCraig Topper static constexpr StringLiteral CombineIntoExts[] = {
850451e853eSCraig Topper     {"zk"},    {"zkn"},  {"zks"},   {"zvkn"},  {"zvknc"},
851451e853eSCraig Topper     {"zvkng"}, {"zvks"}, {"zvksc"}, {"zvksg"},
852733a8778SCraig Topper };
853733a8778SCraig Topper 
854733a8778SCraig Topper void RISCVISAInfo::updateCombination() {
855451e853eSCraig Topper   bool MadeChange = false;
856733a8778SCraig Topper   do {
857451e853eSCraig Topper     MadeChange = false;
858451e853eSCraig Topper     for (StringRef CombineExt : CombineIntoExts) {
859e069bb7fSCraig Topper       if (Exts.count(CombineExt.str()))
860733a8778SCraig Topper         continue;
861451e853eSCraig Topper 
862451e853eSCraig Topper       // Look up the extension in the ImpliesExt table to find everything it
863451e853eSCraig Topper       // depends on.
864451e853eSCraig Topper       auto Range = std::equal_range(std::begin(ImpliedExts),
865451e853eSCraig Topper                                     std::end(ImpliedExts), CombineExt);
866451e853eSCraig Topper       bool HasAllRequiredFeatures = std::all_of(
867451e853eSCraig Topper           Range.first, Range.second, [&](const ImpliedExtsEntry &Implied) {
868e069bb7fSCraig Topper             return Exts.count(Implied.ImpliedExt);
869451e853eSCraig Topper           });
870451e853eSCraig Topper       if (HasAllRequiredFeatures) {
871733a8778SCraig Topper         auto Version = findDefaultVersion(CombineExt);
87208969ca1SCraig Topper         Exts[CombineExt.str()] = *Version;
873451e853eSCraig Topper         MadeChange = true;
874733a8778SCraig Topper       }
875733a8778SCraig Topper     }
876451e853eSCraig Topper   } while (MadeChange);
877733a8778SCraig Topper }
878733a8778SCraig Topper 
879cf3c714eSCraig Topper void RISCVISAInfo::updateImpliedLengths() {
880cf3c714eSCraig Topper   assert(FLen == 0 && MaxELenFp == 0 && MaxELen == 0 && MinVLen == 0 &&
881cf3c714eSCraig Topper          "Expected lengths to be initialied to zero");
882cf3c714eSCraig Topper 
883733a8778SCraig Topper   // TODO: Handle q extension.
884733a8778SCraig Topper   if (Exts.count("d"))
885733a8778SCraig Topper     FLen = 64;
886733a8778SCraig Topper   else if (Exts.count("f"))
887733a8778SCraig Topper     FLen = 32;
888733a8778SCraig Topper 
88905d04f0aSCraig Topper   if (Exts.count("v")) {
89005d04f0aSCraig Topper     MaxELenFp = std::max(MaxELenFp, 64u);
89105d04f0aSCraig Topper     MaxELen = std::max(MaxELen, 64u);
89205d04f0aSCraig Topper   }
89305d04f0aSCraig Topper 
894733a8778SCraig Topper   for (auto const &Ext : Exts) {
895733a8778SCraig Topper     StringRef ExtName = Ext.first;
896cf3c714eSCraig Topper     // Infer MaxELen and MaxELenFp from Zve(32/64)(x/f/d)
897cf3c714eSCraig Topper     if (ExtName.consume_front("zve")) {
898cf3c714eSCraig Topper       unsigned ZveELen;
899cf3c714eSCraig Topper       if (ExtName.consumeInteger(10, ZveELen))
90005d04f0aSCraig Topper         continue;
90105d04f0aSCraig Topper 
902cf3c714eSCraig Topper       if (ExtName == "f")
903cf3c714eSCraig Topper         MaxELenFp = std::max(MaxELenFp, 32u);
904cf3c714eSCraig Topper       else if (ExtName == "d")
905cf3c714eSCraig Topper         MaxELenFp = std::max(MaxELenFp, 64u);
906cf3c714eSCraig Topper       else if (ExtName != "x")
907cf3c714eSCraig Topper         continue;
908cf3c714eSCraig Topper 
909733a8778SCraig Topper       MaxELen = std::max(MaxELen, ZveELen);
910cf3c714eSCraig Topper       continue;
911cf3c714eSCraig Topper     }
912cf3c714eSCraig Topper 
913cf3c714eSCraig Topper     // Infer MinVLen from zvl*b.
914cf3c714eSCraig Topper     if (ExtName.consume_front("zvl")) {
915cf3c714eSCraig Topper       unsigned ZvlLen;
916cf3c714eSCraig Topper       if (ExtName.consumeInteger(10, ZvlLen))
917cf3c714eSCraig Topper         continue;
918cf3c714eSCraig Topper 
919cf3c714eSCraig Topper       if (ExtName != "b")
920cf3c714eSCraig Topper         continue;
921cf3c714eSCraig Topper 
922cf3c714eSCraig Topper       MinVLen = std::max(MinVLen, ZvlLen);
923cf3c714eSCraig Topper       continue;
924733a8778SCraig Topper     }
925733a8778SCraig Topper   }
926733a8778SCraig Topper }
927733a8778SCraig Topper 
928733a8778SCraig Topper std::string RISCVISAInfo::toString() const {
929733a8778SCraig Topper   std::string Buffer;
930733a8778SCraig Topper   raw_string_ostream Arch(Buffer);
931733a8778SCraig Topper 
932733a8778SCraig Topper   Arch << "rv" << XLen;
933733a8778SCraig Topper 
934733a8778SCraig Topper   ListSeparator LS("_");
935733a8778SCraig Topper   for (auto const &Ext : Exts) {
936733a8778SCraig Topper     StringRef ExtName = Ext.first;
937733a8778SCraig Topper     auto ExtInfo = Ext.second;
938733a8778SCraig Topper     Arch << LS << ExtName;
939733a8778SCraig Topper     Arch << ExtInfo.Major << "p" << ExtInfo.Minor;
940733a8778SCraig Topper   }
941733a8778SCraig Topper 
942733a8778SCraig Topper   return Arch.str();
943733a8778SCraig Topper }
944733a8778SCraig Topper 
945733a8778SCraig Topper llvm::Expected<std::unique_ptr<RISCVISAInfo>>
946733a8778SCraig Topper RISCVISAInfo::postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo) {
947733a8778SCraig Topper   ISAInfo->updateImplication();
948733a8778SCraig Topper   ISAInfo->updateCombination();
949cf3c714eSCraig Topper   ISAInfo->updateImpliedLengths();
950733a8778SCraig Topper 
951733a8778SCraig Topper   if (Error Result = ISAInfo->checkDependency())
952733a8778SCraig Topper     return std::move(Result);
953733a8778SCraig Topper   return std::move(ISAInfo);
954733a8778SCraig Topper }
955733a8778SCraig Topper 
956733a8778SCraig Topper StringRef RISCVISAInfo::computeDefaultABI() const {
957733a8778SCraig Topper   if (XLen == 32) {
9587237bef5SCraig Topper     if (Exts.count("e"))
959733a8778SCraig Topper       return "ilp32e";
9607237bef5SCraig Topper     if (Exts.count("d"))
961733a8778SCraig Topper       return "ilp32d";
9627237bef5SCraig Topper     if (Exts.count("f"))
963733a8778SCraig Topper       return "ilp32f";
964733a8778SCraig Topper     return "ilp32";
965733a8778SCraig Topper   } else if (XLen == 64) {
9667237bef5SCraig Topper     if (Exts.count("e"))
967733a8778SCraig Topper       return "lp64e";
9687237bef5SCraig Topper     if (Exts.count("d"))
969733a8778SCraig Topper       return "lp64d";
9707237bef5SCraig Topper     if (Exts.count("f"))
971733a8778SCraig Topper       return "lp64f";
972733a8778SCraig Topper     return "lp64";
973733a8778SCraig Topper   }
974733a8778SCraig Topper   llvm_unreachable("Invalid XLEN");
975733a8778SCraig Topper }
976733a8778SCraig Topper 
977733a8778SCraig Topper bool RISCVISAInfo::isSupportedExtensionWithVersion(StringRef Ext) {
978733a8778SCraig Topper   if (Ext.empty())
979733a8778SCraig Topper     return false;
980733a8778SCraig Topper 
981733a8778SCraig Topper   auto Pos = findLastNonVersionCharacter(Ext) + 1;
982733a8778SCraig Topper   StringRef Name = Ext.substr(0, Pos);
983733a8778SCraig Topper   StringRef Vers = Ext.substr(Pos);
984733a8778SCraig Topper   if (Vers.empty())
985733a8778SCraig Topper     return false;
986733a8778SCraig Topper 
987733a8778SCraig Topper   unsigned Major, Minor, ConsumeLength;
988733a8778SCraig Topper   if (auto E = getExtensionVersion(Name, Vers, Major, Minor, ConsumeLength,
989733a8778SCraig Topper                                    true, true)) {
990733a8778SCraig Topper     consumeError(std::move(E));
991733a8778SCraig Topper     return false;
992733a8778SCraig Topper   }
993733a8778SCraig Topper 
994733a8778SCraig Topper   return true;
995733a8778SCraig Topper }
996733a8778SCraig Topper 
997733a8778SCraig Topper std::string RISCVISAInfo::getTargetFeatureForExtension(StringRef Ext) {
998733a8778SCraig Topper   if (Ext.empty())
999733a8778SCraig Topper     return std::string();
1000733a8778SCraig Topper 
1001733a8778SCraig Topper   auto Pos = findLastNonVersionCharacter(Ext) + 1;
1002733a8778SCraig Topper   StringRef Name = Ext.substr(0, Pos);
1003733a8778SCraig Topper 
1004733a8778SCraig Topper   if (Pos != Ext.size() && !isSupportedExtensionWithVersion(Ext))
1005733a8778SCraig Topper     return std::string();
1006733a8778SCraig Topper 
1007733a8778SCraig Topper   if (!isSupportedExtension(Name))
1008733a8778SCraig Topper     return std::string();
1009733a8778SCraig Topper 
1010733a8778SCraig Topper   return isExperimentalExtension(Name) ? "experimental-" + Name.str()
1011733a8778SCraig Topper                                        : Name.str();
1012733a8778SCraig Topper }
1013d1e28e2aSPhilip Reames 
1014d1e28e2aSPhilip Reames struct RISCVExtBit {
1015d1e28e2aSPhilip Reames   const StringLiteral ext;
101682f52d9cSPiyou Chen   uint8_t groupid;
1017d1e28e2aSPhilip Reames   uint8_t bitpos;
1018d1e28e2aSPhilip Reames };
1019d1e28e2aSPhilip Reames 
102082f52d9cSPiyou Chen constexpr static RISCVExtBit RISCVBitPositions[] = {
102182f52d9cSPiyou Chen     {"a", 0, 0},          {"c", 0, 2},
102282f52d9cSPiyou Chen     {"d", 0, 3},          {"f", 0, 5},
102382f52d9cSPiyou Chen     {"i", 0, 8},          {"m", 0, 12},
102482f52d9cSPiyou Chen     {"v", 0, 21},         {"zacas", 0, 26},
102582f52d9cSPiyou Chen     {"zba", 0, 27},       {"zbb", 0, 28},
102682f52d9cSPiyou Chen     {"zbc", 0, 29},       {"zbkb", 0, 30},
102782f52d9cSPiyou Chen     {"zbkc", 0, 31},      {"zbkx", 0, 32},
102882f52d9cSPiyou Chen     {"zbs", 0, 33},       {"zfa", 0, 34},
102982f52d9cSPiyou Chen     {"zfh", 0, 35},       {"zfhmin", 0, 36},
103082f52d9cSPiyou Chen     {"zicboz", 0, 37},    {"zicond", 0, 38},
103182f52d9cSPiyou Chen     {"zihintntl", 0, 39}, {"zihintpause", 0, 40},
103282f52d9cSPiyou Chen     {"zknd", 0, 41},      {"zkne", 0, 42},
103382f52d9cSPiyou Chen     {"zknh", 0, 43},      {"zksed", 0, 44},
103482f52d9cSPiyou Chen     {"zksh", 0, 45},      {"zkt", 0, 46},
103582f52d9cSPiyou Chen     {"ztso", 0, 47},      {"zvbb", 0, 48},
103682f52d9cSPiyou Chen     {"zvbc", 0, 49},      {"zvfh", 0, 50},
103782f52d9cSPiyou Chen     {"zvfhmin", 0, 51},   {"zvkb", 0, 52},
103882f52d9cSPiyou Chen     {"zvkg", 0, 53},      {"zvkned", 0, 54},
103982f52d9cSPiyou Chen     {"zvknha", 0, 55},    {"zvknhb", 0, 56},
104082f52d9cSPiyou Chen     {"zvksed", 0, 57},    {"zvksh", 0, 58},
104182f52d9cSPiyou Chen     {"zvkt", 0, 59},      {"zve32x", 0, 60},
104282f52d9cSPiyou Chen     {"zve32f", 0, 61},    {"zve64x", 0, 62},
1043a2994dedSPiyou Chen     {"zve64f", 0, 63},    {"zve64d", 1, 0},
104482f52d9cSPiyou Chen     {"zimop", 1, 1},      {"zca", 1, 2},
104582f52d9cSPiyou Chen     {"zcb", 1, 3},        {"zcd", 1, 4},
104682f52d9cSPiyou Chen     {"zcf", 1, 5},        {"zcmop", 1, 6},
104782f52d9cSPiyou Chen     {"zawrs", 1, 7}};
104882f52d9cSPiyou Chen 
104982f52d9cSPiyou Chen std::pair<int, int> RISCVISAInfo::getRISCVFeaturesBitsInfo(StringRef Ext) {
1050d1e28e2aSPhilip Reames   // Note that this code currently accepts mixed case extension names, but
1051d1e28e2aSPhilip Reames   // does not handle extension versions at all.  That's probably fine because
1052d1e28e2aSPhilip Reames   // there's only one extension version in the __riscv_feature_bits vector.
105382f52d9cSPiyou Chen   for (auto E : RISCVBitPositions)
1054d1e28e2aSPhilip Reames     if (E.ext.equals_insensitive(Ext))
105582f52d9cSPiyou Chen       return std::make_pair(E.groupid, E.bitpos);
105682f52d9cSPiyou Chen   return std::make_pair(-1, -1);
1057d1e28e2aSPhilip Reames }
1058