xref: /openbsd-src/gnu/llvm/clang/lib/Driver/ToolChains/Arch/RISCV.cpp (revision e15071f8abee7f13d1a7093171d170e7b38b9568)
1e5dd7070Spatrick //===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick 
9e5dd7070Spatrick #include "RISCV.h"
10e5dd7070Spatrick #include "clang/Basic/CharInfo.h"
11e5dd7070Spatrick #include "clang/Driver/Driver.h"
12e5dd7070Spatrick #include "clang/Driver/DriverDiagnostic.h"
13e5dd7070Spatrick #include "clang/Driver/Options.h"
14e5dd7070Spatrick #include "llvm/Option/ArgList.h"
15e5dd7070Spatrick #include "llvm/ADT/Optional.h"
16e5dd7070Spatrick #include "llvm/Support/TargetParser.h"
17e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
18e5dd7070Spatrick #include "ToolChains/CommonArgs.h"
19e5dd7070Spatrick 
20e5dd7070Spatrick using namespace clang::driver;
21e5dd7070Spatrick using namespace clang::driver::tools;
22e5dd7070Spatrick using namespace clang;
23e5dd7070Spatrick using namespace llvm::opt;
24e5dd7070Spatrick 
25ec727ea7Spatrick namespace {
26ec727ea7Spatrick // Represents the major and version number components of a RISC-V extension
27ec727ea7Spatrick struct RISCVExtensionVersion {
28ec727ea7Spatrick   StringRef Major;
29ec727ea7Spatrick   StringRef Minor;
30ec727ea7Spatrick };
31ec727ea7Spatrick } // end anonymous namespace
32ec727ea7Spatrick 
33e5dd7070Spatrick static StringRef getExtensionTypeDesc(StringRef Ext) {
34e5dd7070Spatrick   if (Ext.startswith("sx"))
35e5dd7070Spatrick     return "non-standard supervisor-level extension";
36e5dd7070Spatrick   if (Ext.startswith("s"))
37e5dd7070Spatrick     return "standard supervisor-level extension";
38e5dd7070Spatrick   if (Ext.startswith("x"))
39e5dd7070Spatrick     return "non-standard user-level extension";
40ec727ea7Spatrick   if (Ext.startswith("z"))
41ec727ea7Spatrick     return "standard user-level extension";
42e5dd7070Spatrick   return StringRef();
43e5dd7070Spatrick }
44e5dd7070Spatrick 
45e5dd7070Spatrick static StringRef getExtensionType(StringRef Ext) {
46e5dd7070Spatrick   if (Ext.startswith("sx"))
47e5dd7070Spatrick     return "sx";
48e5dd7070Spatrick   if (Ext.startswith("s"))
49e5dd7070Spatrick     return "s";
50e5dd7070Spatrick   if (Ext.startswith("x"))
51e5dd7070Spatrick     return "x";
52ec727ea7Spatrick   if (Ext.startswith("z"))
53ec727ea7Spatrick     return "z";
54e5dd7070Spatrick   return StringRef();
55e5dd7070Spatrick }
56e5dd7070Spatrick 
57ec727ea7Spatrick // If the extension is supported as experimental, return the version of that
58ec727ea7Spatrick // extension that the compiler currently supports.
59ec727ea7Spatrick static Optional<RISCVExtensionVersion>
60ec727ea7Spatrick isExperimentalExtension(StringRef Ext) {
61ec727ea7Spatrick   if (Ext == "b" || Ext == "zbb" || Ext == "zbc" || Ext == "zbe" ||
62ec727ea7Spatrick       Ext == "zbf" || Ext == "zbm" || Ext == "zbp" || Ext == "zbr" ||
63ec727ea7Spatrick       Ext == "zbs" || Ext == "zbt" || Ext == "zbproposedc")
64ec727ea7Spatrick     return RISCVExtensionVersion{"0", "92"};
65ec727ea7Spatrick   if (Ext == "v")
66ec727ea7Spatrick     return RISCVExtensionVersion{"0", "8"};
67ec727ea7Spatrick   return None;
68ec727ea7Spatrick }
69ec727ea7Spatrick 
70e5dd7070Spatrick static bool isSupportedExtension(StringRef Ext) {
71ec727ea7Spatrick   // LLVM supports "z" extensions which are marked as experimental.
72ec727ea7Spatrick   if (isExperimentalExtension(Ext))
73ec727ea7Spatrick     return true;
74ec727ea7Spatrick 
75e5dd7070Spatrick   // LLVM does not support "sx", "s" nor "x" extensions.
76e5dd7070Spatrick   return false;
77e5dd7070Spatrick }
78e5dd7070Spatrick 
79e5dd7070Spatrick // Extensions may have a version number, and may be separated by
80e5dd7070Spatrick // an underscore '_' e.g.: rv32i2_m2.
81e5dd7070Spatrick // Version number is divided into major and minor version numbers,
82e5dd7070Spatrick // separated by a 'p'. If the minor version is 0 then 'p0' can be
83e5dd7070Spatrick // omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
84ec727ea7Spatrick static bool getExtensionVersion(const Driver &D, const ArgList &Args,
85ec727ea7Spatrick                                 StringRef MArch, StringRef Ext, StringRef In,
86e5dd7070Spatrick                                 std::string &Major, std::string &Minor) {
87ec727ea7Spatrick   Major = std::string(In.take_while(isDigit));
88e5dd7070Spatrick   In = In.substr(Major.size());
89e5dd7070Spatrick 
90ec727ea7Spatrick   if (Major.size() && In.consume_front("p")) {
91ec727ea7Spatrick     Minor = std::string(In.take_while(isDigit));
92ec727ea7Spatrick     In = In.substr(Major.size() + 1);
93e5dd7070Spatrick 
94e5dd7070Spatrick     // Expected 'p' to be followed by minor version number.
95e5dd7070Spatrick     if (Minor.empty()) {
96e5dd7070Spatrick       std::string Error =
97e5dd7070Spatrick         "minor version number missing after 'p' for extension";
98e5dd7070Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
99e5dd7070Spatrick         << MArch << Error << Ext;
100e5dd7070Spatrick       return false;
101e5dd7070Spatrick     }
102e5dd7070Spatrick   }
103e5dd7070Spatrick 
104ec727ea7Spatrick   // Expected multi-character extension with version number to have no
105ec727ea7Spatrick   // subsequent characters (i.e. must either end string or be followed by
106ec727ea7Spatrick   // an underscore).
107ec727ea7Spatrick   if (Ext.size() > 1 && In.size()) {
108ec727ea7Spatrick     std::string Error =
109ec727ea7Spatrick         "multi-character extensions must be separated by underscores";
110ec727ea7Spatrick     D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << In;
111ec727ea7Spatrick     return false;
112ec727ea7Spatrick   }
113ec727ea7Spatrick 
114ec727ea7Spatrick   // If experimental extension, require use of current version number number
115ec727ea7Spatrick   if (auto ExperimentalExtension = isExperimentalExtension(Ext)) {
116ec727ea7Spatrick     if (!Args.hasArg(options::OPT_menable_experimental_extensions)) {
117ec727ea7Spatrick       std::string Error =
118ec727ea7Spatrick           "requires '-menable-experimental-extensions' for experimental extension";
119ec727ea7Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
120ec727ea7Spatrick           << MArch << Error << Ext;
121ec727ea7Spatrick       return false;
122ec727ea7Spatrick     } else if (Major.empty() && Minor.empty()) {
123ec727ea7Spatrick       std::string Error =
124ec727ea7Spatrick           "experimental extension requires explicit version number";
125ec727ea7Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
126ec727ea7Spatrick           << MArch << Error << Ext;
127ec727ea7Spatrick       return false;
128ec727ea7Spatrick     }
129ec727ea7Spatrick     auto SupportedVers = *ExperimentalExtension;
130ec727ea7Spatrick     if (Major != SupportedVers.Major || Minor != SupportedVers.Minor) {
131ec727ea7Spatrick       std::string Error =
132ec727ea7Spatrick           "unsupported version number " + Major;
133ec727ea7Spatrick       if (!Minor.empty())
134ec727ea7Spatrick         Error += "." + Minor;
135ec727ea7Spatrick       Error += " for experimental extension (this compiler supports "
136ec727ea7Spatrick             + SupportedVers.Major.str() + "."
137ec727ea7Spatrick             + SupportedVers.Minor.str() + ")";
138ec727ea7Spatrick 
139ec727ea7Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
140ec727ea7Spatrick           << MArch << Error << Ext;
141ec727ea7Spatrick       return false;
142ec727ea7Spatrick     }
143ec727ea7Spatrick     return true;
144ec727ea7Spatrick   }
145ec727ea7Spatrick 
146ec727ea7Spatrick   // Allow extensions to declare no version number
147ec727ea7Spatrick   if (Major.empty() && Minor.empty())
148ec727ea7Spatrick     return true;
149ec727ea7Spatrick 
150ec727ea7Spatrick   // TODO: Handle supported extensions with version number.
151e5dd7070Spatrick   std::string Error = "unsupported version number " + Major;
152e5dd7070Spatrick   if (!Minor.empty())
153e5dd7070Spatrick     Error += "." + Minor;
154e5dd7070Spatrick   Error += " for extension";
155e5dd7070Spatrick   D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext;
156e5dd7070Spatrick 
157e5dd7070Spatrick   return false;
158e5dd7070Spatrick }
159e5dd7070Spatrick 
160e5dd7070Spatrick // Handle other types of extensions other than the standard
161e5dd7070Spatrick // general purpose and standard user-level extensions.
162e5dd7070Spatrick // Parse the ISA string containing non-standard user-level
163e5dd7070Spatrick // extensions, standard supervisor-level extensions and
164e5dd7070Spatrick // non-standard supervisor-level extensions.
165ec727ea7Spatrick // These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a
166e5dd7070Spatrick // canonical order, might have a version number (major, minor)
167e5dd7070Spatrick // and are separated by a single underscore '_'.
168e5dd7070Spatrick // Set the hardware features for the extensions that are supported.
169e5dd7070Spatrick static void getExtensionFeatures(const Driver &D,
170e5dd7070Spatrick                                  const ArgList &Args,
171e5dd7070Spatrick                                  std::vector<StringRef> &Features,
172e5dd7070Spatrick                                  StringRef &MArch, StringRef &Exts) {
173e5dd7070Spatrick   if (Exts.empty())
174e5dd7070Spatrick     return;
175e5dd7070Spatrick 
176e5dd7070Spatrick   // Multi-letter extensions are seperated by a single underscore
177e5dd7070Spatrick   // as described in RISC-V User-Level ISA V2.2.
178e5dd7070Spatrick   SmallVector<StringRef, 8> Split;
179e5dd7070Spatrick   Exts.split(Split, StringRef("_"));
180e5dd7070Spatrick 
181ec727ea7Spatrick   SmallVector<StringRef, 4> Prefix{"z", "x", "s", "sx"};
182e5dd7070Spatrick   auto I = Prefix.begin();
183e5dd7070Spatrick   auto E = Prefix.end();
184e5dd7070Spatrick 
185e5dd7070Spatrick   SmallVector<StringRef, 8> AllExts;
186e5dd7070Spatrick 
187e5dd7070Spatrick   for (StringRef Ext : Split) {
188e5dd7070Spatrick     if (Ext.empty()) {
189e5dd7070Spatrick       D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
190e5dd7070Spatrick         << "extension name missing after separator '_'";
191e5dd7070Spatrick       return;
192e5dd7070Spatrick     }
193e5dd7070Spatrick 
194e5dd7070Spatrick     StringRef Type = getExtensionType(Ext);
195e5dd7070Spatrick     StringRef Desc = getExtensionTypeDesc(Ext);
196ec727ea7Spatrick     auto Pos = Ext.find_if(isDigit);
197ec727ea7Spatrick     StringRef Name(Ext.substr(0, Pos));
198ec727ea7Spatrick     StringRef Vers(Ext.substr(Pos));
199e5dd7070Spatrick 
200e5dd7070Spatrick     if (Type.empty()) {
201e5dd7070Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
202e5dd7070Spatrick         << MArch << "invalid extension prefix" << Ext;
203e5dd7070Spatrick       return;
204e5dd7070Spatrick     }
205e5dd7070Spatrick 
206e5dd7070Spatrick     // Check ISA extensions are specified in the canonical order.
207e5dd7070Spatrick     while (I != E && *I != Type)
208e5dd7070Spatrick       ++I;
209e5dd7070Spatrick 
210e5dd7070Spatrick     if (I == E) {
211ec727ea7Spatrick       std::string Error = std::string(Desc);
212e5dd7070Spatrick       Error += " not given in canonical order";
213e5dd7070Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
214e5dd7070Spatrick         << MArch <<  Error << Ext;
215e5dd7070Spatrick       return;
216e5dd7070Spatrick     }
217e5dd7070Spatrick 
218e5dd7070Spatrick     // The order is OK, do not advance I to the next prefix
219e5dd7070Spatrick     // to allow repeated extension type, e.g.: rv32ixabc_xdef.
220e5dd7070Spatrick 
221ec727ea7Spatrick     if (Name.size() == Type.size()) {
222ec727ea7Spatrick       std::string Error = std::string(Desc);
223e5dd7070Spatrick       Error += " name missing after";
224e5dd7070Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
225ec727ea7Spatrick         << MArch << Error << Type;
226e5dd7070Spatrick       return;
227e5dd7070Spatrick     }
228e5dd7070Spatrick 
229e5dd7070Spatrick     std::string Major, Minor;
230ec727ea7Spatrick     if (!getExtensionVersion(D, Args, MArch, Name, Vers, Major, Minor))
231e5dd7070Spatrick       return;
232e5dd7070Spatrick 
233e5dd7070Spatrick     // Check if duplicated extension.
234ec727ea7Spatrick     if (llvm::is_contained(AllExts, Name)) {
235e5dd7070Spatrick       std::string Error = "duplicated ";
236e5dd7070Spatrick       Error += Desc;
237e5dd7070Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
238ec727ea7Spatrick         << MArch << Error << Name;
239e5dd7070Spatrick       return;
240e5dd7070Spatrick     }
241e5dd7070Spatrick 
242e5dd7070Spatrick     // Extension format is correct, keep parsing the extensions.
243e5dd7070Spatrick     // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
244ec727ea7Spatrick     AllExts.push_back(Name);
245e5dd7070Spatrick   }
246e5dd7070Spatrick 
247e5dd7070Spatrick   // Set target features.
248e5dd7070Spatrick   // TODO: Hardware features to be handled in Support/TargetParser.cpp.
249e5dd7070Spatrick   // TODO: Use version number when setting target features.
250e5dd7070Spatrick   for (auto Ext : AllExts) {
251e5dd7070Spatrick     if (!isSupportedExtension(Ext)) {
252e5dd7070Spatrick       StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
253e5dd7070Spatrick       std::string Error = "unsupported ";
254e5dd7070Spatrick       Error += Desc;
255e5dd7070Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
256e5dd7070Spatrick         << MArch << Error << Ext;
257e5dd7070Spatrick       return;
258e5dd7070Spatrick     }
259ec727ea7Spatrick     if (isExperimentalExtension(Ext))
260ec727ea7Spatrick       Features.push_back(Args.MakeArgString("+experimental-" + Ext));
261ec727ea7Spatrick     else
262e5dd7070Spatrick       Features.push_back(Args.MakeArgString("+" + Ext));
263e5dd7070Spatrick   }
264e5dd7070Spatrick }
265e5dd7070Spatrick 
266e5dd7070Spatrick // Returns false if an error is diagnosed.
267e5dd7070Spatrick static bool getArchFeatures(const Driver &D, StringRef MArch,
268e5dd7070Spatrick                             std::vector<StringRef> &Features,
269e5dd7070Spatrick                             const ArgList &Args) {
270e5dd7070Spatrick   // RISC-V ISA strings must be lowercase.
271e5dd7070Spatrick   if (llvm::any_of(MArch, [](char c) { return isupper(c); })) {
272e5dd7070Spatrick     D.Diag(diag::err_drv_invalid_riscv_arch_name)
273e5dd7070Spatrick         << MArch << "string must be lowercase";
274e5dd7070Spatrick     return false;
275e5dd7070Spatrick   }
276e5dd7070Spatrick 
277e5dd7070Spatrick   // ISA string must begin with rv32 or rv64.
278e5dd7070Spatrick   if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) ||
279e5dd7070Spatrick       (MArch.size() < 5)) {
280e5dd7070Spatrick     D.Diag(diag::err_drv_invalid_riscv_arch_name)
281e5dd7070Spatrick         << MArch << "string must begin with rv32{i,e,g} or rv64{i,g}";
282e5dd7070Spatrick     return false;
283e5dd7070Spatrick   }
284e5dd7070Spatrick 
285e5dd7070Spatrick   bool HasRV64 = MArch.startswith("rv64");
286e5dd7070Spatrick 
287e5dd7070Spatrick   // The canonical order specified in ISA manual.
288e5dd7070Spatrick   // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
289e5dd7070Spatrick   StringRef StdExts = "mafdqlcbjtpvn";
290e5dd7070Spatrick   bool HasF = false, HasD = false;
291e5dd7070Spatrick   char Baseline = MArch[4];
292e5dd7070Spatrick 
293e5dd7070Spatrick   // First letter should be 'e', 'i' or 'g'.
294e5dd7070Spatrick   switch (Baseline) {
295e5dd7070Spatrick   default:
296e5dd7070Spatrick     D.Diag(diag::err_drv_invalid_riscv_arch_name)
297e5dd7070Spatrick         << MArch << "first letter should be 'e', 'i' or 'g'";
298e5dd7070Spatrick     return false;
299e5dd7070Spatrick   case 'e': {
300e5dd7070Spatrick     StringRef Error;
301e5dd7070Spatrick     // Currently LLVM does not support 'e'.
302e5dd7070Spatrick     // Extension 'e' is not allowed in rv64.
303e5dd7070Spatrick     if (HasRV64)
304e5dd7070Spatrick       Error = "standard user-level extension 'e' requires 'rv32'";
305e5dd7070Spatrick     else
306e5dd7070Spatrick       Error = "unsupported standard user-level extension 'e'";
307e5dd7070Spatrick     D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch << Error;
308e5dd7070Spatrick     return false;
309e5dd7070Spatrick   }
310e5dd7070Spatrick   case 'i':
311e5dd7070Spatrick     break;
312e5dd7070Spatrick   case 'g':
313e5dd7070Spatrick     // g = imafd
314e5dd7070Spatrick     StdExts = StdExts.drop_front(4);
315e5dd7070Spatrick     Features.push_back("+m");
316e5dd7070Spatrick     Features.push_back("+a");
317e5dd7070Spatrick     Features.push_back("+f");
318e5dd7070Spatrick     Features.push_back("+d");
319e5dd7070Spatrick     HasF = true;
320e5dd7070Spatrick     HasD = true;
321e5dd7070Spatrick     break;
322e5dd7070Spatrick   }
323e5dd7070Spatrick 
324e5dd7070Spatrick   // Skip rvxxx
325e5dd7070Spatrick   StringRef Exts = MArch.substr(5);
326e5dd7070Spatrick 
327ec727ea7Spatrick   // Remove multi-letter standard extensions, non-standard extensions and
328ec727ea7Spatrick   // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes.
329ec727ea7Spatrick   // Parse them at the end.
330ec727ea7Spatrick   // Find the very first occurrence of 's', 'x' or 'z'.
331e5dd7070Spatrick   StringRef OtherExts;
332ec727ea7Spatrick   size_t Pos = Exts.find_first_of("zsx");
333e5dd7070Spatrick   if (Pos != StringRef::npos) {
334e5dd7070Spatrick     OtherExts = Exts.substr(Pos);
335e5dd7070Spatrick     Exts = Exts.substr(0, Pos);
336e5dd7070Spatrick   }
337e5dd7070Spatrick 
338e5dd7070Spatrick   std::string Major, Minor;
339ec727ea7Spatrick   if (!getExtensionVersion(D, Args, MArch, std::string(1, Baseline), Exts,
340ec727ea7Spatrick                            Major, Minor))
341e5dd7070Spatrick     return false;
342e5dd7070Spatrick 
343ec727ea7Spatrick   // Consume the base ISA version number and any '_' between rvxxx and the
344ec727ea7Spatrick   // first extension
345ec727ea7Spatrick   Exts = Exts.drop_front(Major.size());
346ec727ea7Spatrick   if (!Minor.empty())
347ec727ea7Spatrick     Exts = Exts.drop_front(Minor.size() + 1 /*'p'*/);
348ec727ea7Spatrick   Exts.consume_front("_");
349ec727ea7Spatrick 
350e5dd7070Spatrick   // TODO: Use version number when setting target features
351e5dd7070Spatrick 
352e5dd7070Spatrick   auto StdExtsItr = StdExts.begin();
353e5dd7070Spatrick   auto StdExtsEnd = StdExts.end();
354e5dd7070Spatrick 
355ec727ea7Spatrick   for (auto I = Exts.begin(), E = Exts.end(); I != E; ) {
356e5dd7070Spatrick     char c = *I;
357e5dd7070Spatrick 
358e5dd7070Spatrick     // Check ISA extensions are specified in the canonical order.
359e5dd7070Spatrick     while (StdExtsItr != StdExtsEnd && *StdExtsItr != c)
360e5dd7070Spatrick       ++StdExtsItr;
361e5dd7070Spatrick 
362e5dd7070Spatrick     if (StdExtsItr == StdExtsEnd) {
363e5dd7070Spatrick       // Either c contains a valid extension but it was not given in
364e5dd7070Spatrick       // canonical order or it is an invalid extension.
365e5dd7070Spatrick       StringRef Error;
366e5dd7070Spatrick       if (StdExts.contains(c))
367e5dd7070Spatrick         Error = "standard user-level extension not given in canonical order";
368e5dd7070Spatrick       else
369e5dd7070Spatrick         Error = "invalid standard user-level extension";
370e5dd7070Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
371e5dd7070Spatrick           << MArch << Error << std::string(1, c);
372e5dd7070Spatrick       return false;
373e5dd7070Spatrick     }
374e5dd7070Spatrick 
375e5dd7070Spatrick     // Move to next char to prevent repeated letter.
376e5dd7070Spatrick     ++StdExtsItr;
377e5dd7070Spatrick 
378ec727ea7Spatrick     std::string Next, Major, Minor;
379ec727ea7Spatrick     if (std::next(I) != E)
380ec727ea7Spatrick       Next = std::string(std::next(I), E);
381ec727ea7Spatrick     if (!getExtensionVersion(D, Args, MArch, std::string(1, c), Next, Major,
382ec727ea7Spatrick                              Minor))
383e5dd7070Spatrick       return false;
384e5dd7070Spatrick 
385e5dd7070Spatrick     // The order is OK, then push it into features.
386ec727ea7Spatrick     // TODO: Use version number when setting target features
387e5dd7070Spatrick     switch (c) {
388e5dd7070Spatrick     default:
389e5dd7070Spatrick       // Currently LLVM supports only "mafdc".
390e5dd7070Spatrick       D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
391e5dd7070Spatrick           << MArch << "unsupported standard user-level extension"
392e5dd7070Spatrick           << std::string(1, c);
393e5dd7070Spatrick       return false;
394e5dd7070Spatrick     case 'm':
395e5dd7070Spatrick       Features.push_back("+m");
396e5dd7070Spatrick       break;
397e5dd7070Spatrick     case 'a':
398e5dd7070Spatrick       Features.push_back("+a");
399e5dd7070Spatrick       break;
400e5dd7070Spatrick     case 'f':
401e5dd7070Spatrick       Features.push_back("+f");
402e5dd7070Spatrick       HasF = true;
403e5dd7070Spatrick       break;
404e5dd7070Spatrick     case 'd':
405e5dd7070Spatrick       Features.push_back("+d");
406e5dd7070Spatrick       HasD = true;
407e5dd7070Spatrick       break;
408e5dd7070Spatrick     case 'c':
409e5dd7070Spatrick       Features.push_back("+c");
410e5dd7070Spatrick       break;
411ec727ea7Spatrick     case 'b':
412ec727ea7Spatrick       Features.push_back("+experimental-b");
413ec727ea7Spatrick       break;
414ec727ea7Spatrick     case 'v':
415ec727ea7Spatrick       Features.push_back("+experimental-v");
416ec727ea7Spatrick       break;
417e5dd7070Spatrick     }
418ec727ea7Spatrick 
419ec727ea7Spatrick     // Consume full extension name and version, including any optional '_'
420ec727ea7Spatrick     // between this extension and the next
421ec727ea7Spatrick     ++I;
422ec727ea7Spatrick     I += Major.size();
423ec727ea7Spatrick     if (Minor.size())
424ec727ea7Spatrick       I += Minor.size() + 1 /*'p'*/;
425ec727ea7Spatrick     if (*I == '_')
426ec727ea7Spatrick       ++I;
427e5dd7070Spatrick   }
428e5dd7070Spatrick 
429e5dd7070Spatrick   // Dependency check.
430e5dd7070Spatrick   // It's illegal to specify the 'd' (double-precision floating point)
431e5dd7070Spatrick   // extension without also specifying the 'f' (single precision
432e5dd7070Spatrick   // floating-point) extension.
433e5dd7070Spatrick   if (HasD && !HasF) {
434e5dd7070Spatrick     D.Diag(diag::err_drv_invalid_riscv_arch_name)
435e5dd7070Spatrick         << MArch << "d requires f extension to also be specified";
436e5dd7070Spatrick     return false;
437e5dd7070Spatrick   }
438e5dd7070Spatrick 
439e5dd7070Spatrick   // Additional dependency checks.
440e5dd7070Spatrick   // TODO: The 'q' extension requires rv64.
441e5dd7070Spatrick   // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
442e5dd7070Spatrick 
443e5dd7070Spatrick   // Handle all other types of extensions.
444e5dd7070Spatrick   getExtensionFeatures(D, Args, Features, MArch, OtherExts);
445e5dd7070Spatrick 
446e5dd7070Spatrick   return true;
447e5dd7070Spatrick }
448e5dd7070Spatrick 
449ec727ea7Spatrick // Get features except standard extension feature
450ec727ea7Spatrick void getRISCFeaturesFromMcpu(const Driver &D, const llvm::Triple &Triple,
451ec727ea7Spatrick                              const llvm::opt::ArgList &Args,
452ec727ea7Spatrick                              const llvm::opt::Arg *A, StringRef Mcpu,
453ec727ea7Spatrick                              std::vector<StringRef> &Features) {
454ec727ea7Spatrick   bool Is64Bit = (Triple.getArch() == llvm::Triple::riscv64);
455ec727ea7Spatrick   llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu);
456ec727ea7Spatrick   if (!llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) ||
457ec727ea7Spatrick       !llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features)) {
458ec727ea7Spatrick     D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
459ec727ea7Spatrick   }
460ec727ea7Spatrick }
461ec727ea7Spatrick 
462e5dd7070Spatrick void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
463e5dd7070Spatrick                                    const ArgList &Args,
464e5dd7070Spatrick                                    std::vector<StringRef> &Features) {
465e5dd7070Spatrick   StringRef MArch = getRISCVArch(Args, Triple);
466e5dd7070Spatrick 
467e5dd7070Spatrick   if (!getArchFeatures(D, MArch, Features, Args))
468e5dd7070Spatrick     return;
469e5dd7070Spatrick 
470ec727ea7Spatrick   // If users give march and mcpu, get std extension feature from MArch
471ec727ea7Spatrick   // and other features (ex. mirco architecture feature) from mcpu
472ec727ea7Spatrick   if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
473ec727ea7Spatrick     getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features);
474ec727ea7Spatrick 
475e5dd7070Spatrick   // Handle features corresponding to "-ffixed-X" options
476e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x1))
477e5dd7070Spatrick     Features.push_back("+reserve-x1");
478e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x2))
479e5dd7070Spatrick     Features.push_back("+reserve-x2");
480e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x3))
481e5dd7070Spatrick     Features.push_back("+reserve-x3");
482e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x4))
483e5dd7070Spatrick     Features.push_back("+reserve-x4");
484e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x5))
485e5dd7070Spatrick     Features.push_back("+reserve-x5");
486e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x6))
487e5dd7070Spatrick     Features.push_back("+reserve-x6");
488e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x7))
489e5dd7070Spatrick     Features.push_back("+reserve-x7");
490e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x8))
491e5dd7070Spatrick     Features.push_back("+reserve-x8");
492e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x9))
493e5dd7070Spatrick     Features.push_back("+reserve-x9");
494e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x10))
495e5dd7070Spatrick     Features.push_back("+reserve-x10");
496e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x11))
497e5dd7070Spatrick     Features.push_back("+reserve-x11");
498e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x12))
499e5dd7070Spatrick     Features.push_back("+reserve-x12");
500e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x13))
501e5dd7070Spatrick     Features.push_back("+reserve-x13");
502e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x14))
503e5dd7070Spatrick     Features.push_back("+reserve-x14");
504e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x15))
505e5dd7070Spatrick     Features.push_back("+reserve-x15");
506e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x16))
507e5dd7070Spatrick     Features.push_back("+reserve-x16");
508e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x17))
509e5dd7070Spatrick     Features.push_back("+reserve-x17");
510e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x18))
511e5dd7070Spatrick     Features.push_back("+reserve-x18");
512e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x19))
513e5dd7070Spatrick     Features.push_back("+reserve-x19");
514e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x20))
515e5dd7070Spatrick     Features.push_back("+reserve-x20");
516e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x21))
517e5dd7070Spatrick     Features.push_back("+reserve-x21");
518e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x22))
519e5dd7070Spatrick     Features.push_back("+reserve-x22");
520e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x23))
521e5dd7070Spatrick     Features.push_back("+reserve-x23");
522e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x24))
523e5dd7070Spatrick     Features.push_back("+reserve-x24");
524e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x25))
525e5dd7070Spatrick     Features.push_back("+reserve-x25");
526e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x26))
527e5dd7070Spatrick     Features.push_back("+reserve-x26");
528e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x27))
529e5dd7070Spatrick     Features.push_back("+reserve-x27");
530e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x28))
531e5dd7070Spatrick     Features.push_back("+reserve-x28");
532e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x29))
533e5dd7070Spatrick     Features.push_back("+reserve-x29");
534e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x30))
535e5dd7070Spatrick     Features.push_back("+reserve-x30");
536e5dd7070Spatrick   if (Args.hasArg(options::OPT_ffixed_x31))
537e5dd7070Spatrick     Features.push_back("+reserve-x31");
538e5dd7070Spatrick 
539*e15071f8Skettenis #ifdef __OpenBSD__
540*e15071f8Skettenis   // -mno-relax is default, unless -mrelax is specified.
541*e15071f8Skettenis   if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false))
542*e15071f8Skettenis     Features.push_back("+relax");
543*e15071f8Skettenis   else
544*e15071f8Skettenis     Features.push_back("-relax");
545*e15071f8Skettenis #else
546e5dd7070Spatrick   // -mrelax is default, unless -mno-relax is specified.
547e5dd7070Spatrick   if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true))
548e5dd7070Spatrick     Features.push_back("+relax");
549e5dd7070Spatrick   else
550e5dd7070Spatrick     Features.push_back("-relax");
551*e15071f8Skettenis #endif
552e5dd7070Spatrick 
553e5dd7070Spatrick   // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is
554ec727ea7Spatrick   // specified.
555ec727ea7Spatrick   if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false))
556ec727ea7Spatrick     Features.push_back("+save-restore");
557ec727ea7Spatrick   else
558ec727ea7Spatrick     Features.push_back("-save-restore");
559e5dd7070Spatrick 
560e5dd7070Spatrick   // Now add any that the user explicitly requested on the command line,
561e5dd7070Spatrick   // which may override the defaults.
562e5dd7070Spatrick   handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group);
563e5dd7070Spatrick }
564e5dd7070Spatrick 
565e5dd7070Spatrick StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
566e5dd7070Spatrick   assert((Triple.getArch() == llvm::Triple::riscv32 ||
567e5dd7070Spatrick           Triple.getArch() == llvm::Triple::riscv64) &&
568e5dd7070Spatrick          "Unexpected triple");
569e5dd7070Spatrick 
570e5dd7070Spatrick   // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
571e5dd7070Spatrick   // configured using `--with-abi=`, then the logic for the default choice is
572ec727ea7Spatrick   // defined in config.gcc. This function is based on the logic in GCC 9.2.0.
573e5dd7070Spatrick   //
574ec727ea7Spatrick   // The logic used in GCC 9.2.0 is the following, in order:
575e5dd7070Spatrick   // 1. Explicit choices using `--with-abi=`
576e5dd7070Spatrick   // 2. A default based on `--with-arch=`, if provided
577e5dd7070Spatrick   // 3. A default based on the target triple's arch
578e5dd7070Spatrick   //
579e5dd7070Spatrick   // The logic in config.gcc is a little circular but it is not inconsistent.
580e5dd7070Spatrick   //
581e5dd7070Spatrick   // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
582e5dd7070Spatrick   // and `-mabi=` respectively instead.
583ec727ea7Spatrick   //
584ec727ea7Spatrick   // In order to make chosing logic more clear, Clang uses the following logic,
585ec727ea7Spatrick   // in order:
586ec727ea7Spatrick   // 1. Explicit choices using `-mabi=`
587ec727ea7Spatrick   // 2. A default based on the architecture as determined by getRISCVArch
588ec727ea7Spatrick   // 3. Choose a default based on the triple
589e5dd7070Spatrick 
590e5dd7070Spatrick   // 1. If `-mabi=` is specified, use it.
591e5dd7070Spatrick   if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
592e5dd7070Spatrick     return A->getValue();
593e5dd7070Spatrick 
594ec727ea7Spatrick   // 2. Choose a default based on the target architecture.
595e5dd7070Spatrick   //
596e5dd7070Spatrick   // rv32g | rv32*d -> ilp32d
597e5dd7070Spatrick   // rv32e -> ilp32e
598e5dd7070Spatrick   // rv32* -> ilp32
599e5dd7070Spatrick   // rv64g | rv64*d -> lp64d
600e5dd7070Spatrick   // rv64* -> lp64
601ec727ea7Spatrick   StringRef MArch = getRISCVArch(Args, Triple);
602e5dd7070Spatrick 
603e5dd7070Spatrick   if (MArch.startswith_lower("rv32")) {
604e5dd7070Spatrick     // FIXME: parse `March` to find `D` extension properly
605ec727ea7Spatrick     if (MArch.substr(4).contains_lower("d") || MArch.startswith_lower("rv32g"))
606e5dd7070Spatrick       return "ilp32d";
607e5dd7070Spatrick     else if (MArch.startswith_lower("rv32e"))
608e5dd7070Spatrick       return "ilp32e";
609e5dd7070Spatrick     else
610e5dd7070Spatrick       return "ilp32";
611e5dd7070Spatrick   } else if (MArch.startswith_lower("rv64")) {
612e5dd7070Spatrick     // FIXME: parse `March` to find `D` extension properly
613ec727ea7Spatrick     if (MArch.substr(4).contains_lower("d") || MArch.startswith_lower("rv64g"))
614e5dd7070Spatrick       return "lp64d";
615e5dd7070Spatrick     else
616e5dd7070Spatrick       return "lp64";
617e5dd7070Spatrick   }
618e5dd7070Spatrick 
619e5dd7070Spatrick   // 3. Choose a default based on the triple
620e5dd7070Spatrick   //
621e5dd7070Spatrick   // We deviate from GCC's defaults here:
622e5dd7070Spatrick   // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
623e5dd7070Spatrick   // - On all other OSs we use the double floating point calling convention.
624e5dd7070Spatrick   if (Triple.getArch() == llvm::Triple::riscv32) {
625e5dd7070Spatrick     if (Triple.getOS() == llvm::Triple::UnknownOS)
626e5dd7070Spatrick       return "ilp32";
627e5dd7070Spatrick     else
628e5dd7070Spatrick       return "ilp32d";
629e5dd7070Spatrick   } else {
630e5dd7070Spatrick     if (Triple.getOS() == llvm::Triple::UnknownOS)
631e5dd7070Spatrick       return "lp64";
632e5dd7070Spatrick     else
633e5dd7070Spatrick       return "lp64d";
634e5dd7070Spatrick   }
635e5dd7070Spatrick }
636e5dd7070Spatrick 
637e5dd7070Spatrick StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
638e5dd7070Spatrick                               const llvm::Triple &Triple) {
639e5dd7070Spatrick   assert((Triple.getArch() == llvm::Triple::riscv32 ||
640e5dd7070Spatrick           Triple.getArch() == llvm::Triple::riscv64) &&
641e5dd7070Spatrick          "Unexpected triple");
642e5dd7070Spatrick 
643e5dd7070Spatrick   // GCC's logic around choosing a default `-march=` is complex. If GCC is not
644e5dd7070Spatrick   // configured using `--with-arch=`, then the logic for the default choice is
645e5dd7070Spatrick   // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
646ec727ea7Spatrick   // deviate from GCC's default on additional `-mcpu` option (GCC does not
647ec727ea7Spatrick   // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`
648ec727ea7Spatrick   // nor `-mabi` is specified.
649e5dd7070Spatrick   //
650ec727ea7Spatrick   // The logic used in GCC 9.2.0 is the following, in order:
651e5dd7070Spatrick   // 1. Explicit choices using `--with-arch=`
652e5dd7070Spatrick   // 2. A default based on `--with-abi=`, if provided
653e5dd7070Spatrick   // 3. A default based on the target triple's arch
654e5dd7070Spatrick   //
655e5dd7070Spatrick   // The logic in config.gcc is a little circular but it is not inconsistent.
656e5dd7070Spatrick   //
657e5dd7070Spatrick   // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
658e5dd7070Spatrick   // and `-mabi=` respectively instead.
659e5dd7070Spatrick   //
660ec727ea7Spatrick   // Clang uses the following logic, in order:
661ec727ea7Spatrick   // 1. Explicit choices using `-march=`
662ec727ea7Spatrick   // 2. Based on `-mcpu` if the target CPU has a default ISA string
663ec727ea7Spatrick   // 3. A default based on `-mabi`, if provided
664ec727ea7Spatrick   // 4. A default based on the target triple's arch
665ec727ea7Spatrick   //
666e5dd7070Spatrick   // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
667e5dd7070Spatrick   // instead of `rv{XLEN}gc` though they are (currently) equivalent.
668e5dd7070Spatrick 
669e5dd7070Spatrick   // 1. If `-march=` is specified, use it.
670e5dd7070Spatrick   if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
671e5dd7070Spatrick     return A->getValue();
672e5dd7070Spatrick 
673ec727ea7Spatrick   // 2. Get march (isa string) based on `-mcpu=`
674ec727ea7Spatrick   if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
675ec727ea7Spatrick     StringRef MArch = llvm::RISCV::getMArchFromMcpu(A->getValue());
676ec727ea7Spatrick     // Bypass if target cpu's default march is empty.
677ec727ea7Spatrick     if (MArch != "")
678ec727ea7Spatrick       return MArch;
679ec727ea7Spatrick   }
680ec727ea7Spatrick 
681ec727ea7Spatrick   // 3. Choose a default based on `-mabi=`
682e5dd7070Spatrick   //
683e5dd7070Spatrick   // ilp32e -> rv32e
684e5dd7070Spatrick   // ilp32 | ilp32f | ilp32d -> rv32imafdc
685e5dd7070Spatrick   // lp64 | lp64f | lp64d -> rv64imafdc
686e5dd7070Spatrick   if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
687e5dd7070Spatrick     StringRef MABI = A->getValue();
688e5dd7070Spatrick 
689e5dd7070Spatrick     if (MABI.equals_lower("ilp32e"))
690e5dd7070Spatrick       return "rv32e";
691e5dd7070Spatrick     else if (MABI.startswith_lower("ilp32"))
692e5dd7070Spatrick       return "rv32imafdc";
693e5dd7070Spatrick     else if (MABI.startswith_lower("lp64"))
694e5dd7070Spatrick       return "rv64imafdc";
695e5dd7070Spatrick   }
696e5dd7070Spatrick 
697ec727ea7Spatrick   // 4. Choose a default based on the triple
698e5dd7070Spatrick   //
699e5dd7070Spatrick   // We deviate from GCC's defaults here:
700e5dd7070Spatrick   // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
701e5dd7070Spatrick   // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
702e5dd7070Spatrick   if (Triple.getArch() == llvm::Triple::riscv32) {
703e5dd7070Spatrick     if (Triple.getOS() == llvm::Triple::UnknownOS)
704e5dd7070Spatrick       return "rv32imac";
705e5dd7070Spatrick     else
706e5dd7070Spatrick       return "rv32imafdc";
707e5dd7070Spatrick   } else {
708e5dd7070Spatrick     if (Triple.getOS() == llvm::Triple::UnknownOS)
709e5dd7070Spatrick       return "rv64imac";
710e5dd7070Spatrick     else
711e5dd7070Spatrick       return "rv64imafdc";
712e5dd7070Spatrick   }
713e5dd7070Spatrick }
714