133965Sjdp//===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===//
2218822Sdim//
333965Sjdp// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
433965Sjdp// See https://llvm.org/LICENSE.txt for license information.
533965Sjdp// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
633965Sjdp//
733965Sjdp//===----------------------------------------------------------------------===//
833965Sjdp
933965Sjdp#include "RISCV.h"
1033965Sjdp#include "clang/Basic/CharInfo.h"
1133965Sjdp#include "clang/Driver/Driver.h"
1233965Sjdp#include "clang/Driver/DriverDiagnostic.h"
1333965Sjdp#include "clang/Driver/Options.h"
1433965Sjdp#include "llvm/Option/ArgList.h"
1533965Sjdp#include "llvm/ADT/Optional.h"
1633965Sjdp#include "llvm/Support/TargetParser.h"
1733965Sjdp#include "llvm/Support/raw_ostream.h"
1833965Sjdp#include "ToolChains/CommonArgs.h"
1933965Sjdp
2033965Sjdpusing namespace clang::driver;
21218822Sdimusing namespace clang::driver::tools;
22218822Sdimusing namespace clang;
2333965Sjdpusing namespace llvm::opt;
24218822Sdim
2533965Sjdpstatic StringRef getExtensionTypeDesc(StringRef Ext) {
2633965Sjdp  if (Ext.startswith("sx"))
2733965Sjdp    return "non-standard supervisor-level extension";
2833965Sjdp  if (Ext.startswith("s"))
2933965Sjdp    return "standard supervisor-level extension";
3033965Sjdp  if (Ext.startswith("x"))
3133965Sjdp    return "non-standard user-level extension";
3233965Sjdp  return StringRef();
3333965Sjdp}
3433965Sjdp
3533965Sjdpstatic StringRef getExtensionType(StringRef Ext) {
3633965Sjdp  if (Ext.startswith("sx"))
3733965Sjdp    return "sx";
3833965Sjdp  if (Ext.startswith("s"))
39218822Sdim    return "s";
4033965Sjdp  if (Ext.startswith("x"))
41218822Sdim    return "x";
42130561Sobrien  return StringRef();
4333965Sjdp}
4433965Sjdp
45218822Sdimstatic bool isSupportedExtension(StringRef Ext) {
4633965Sjdp  // LLVM does not support "sx", "s" nor "x" extensions.
4733965Sjdp  return false;
48218822Sdim}
49218822Sdim
50218822Sdim// Extensions may have a version number, and may be separated by
51218822Sdim// an underscore '_' e.g.: rv32i2_m2.
5233965Sjdp// Version number is divided into major and minor version numbers,
53218822Sdim// separated by a 'p'. If the minor version is 0 then 'p0' can be
5433965Sjdp// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1.
55218822Sdimstatic bool getExtensionVersion(const Driver &D, StringRef MArch,
56130561Sobrien                                StringRef Ext, StringRef In,
5733965Sjdp                                std::string &Major, std::string &Minor) {
58218822Sdim  Major = In.take_while(isDigit);
5933965Sjdp  In = In.substr(Major.size());
6033965Sjdp  if (Major.empty())
61218822Sdim    return true;
6233965Sjdp
6333965Sjdp  if (In.consume_front("p")) {
6433965Sjdp    Minor = In.take_while(isDigit);
6533965Sjdp    In = In.substr(Major.size());
66218822Sdim
6733965Sjdp    // Expected 'p' to be followed by minor version number.
6833965Sjdp    if (Minor.empty()) {
6933965Sjdp      std::string Error =
7033965Sjdp        "minor version number missing after 'p' for extension";
7133965Sjdp      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
7233965Sjdp        << MArch << Error << Ext;
7333965Sjdp      return false;
74218822Sdim    }
7533965Sjdp  }
7633965Sjdp
77218822Sdim  // TODO: Handle extensions with version number.
7833965Sjdp  std::string Error = "unsupported version number " + Major;
7933965Sjdp  if (!Minor.empty())
8033965Sjdp    Error += "." + Minor;
8133965Sjdp  Error += " for extension";
8233965Sjdp  D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext;
8333965Sjdp
8433965Sjdp  return false;
85130561Sobrien}
8633965Sjdp
8733965Sjdp// Handle other types of extensions other than the standard
8833965Sjdp// general purpose and standard user-level extensions.
8933965Sjdp// Parse the ISA string containing non-standard user-level
90218822Sdim// extensions, standard supervisor-level extensions and
9133965Sjdp// non-standard supervisor-level extensions.
9233965Sjdp// These extensions start with 'x', 's', 'sx' prefixes, follow a
93130561Sobrien// canonical order, might have a version number (major, minor)
9433965Sjdp// and are separated by a single underscore '_'.
95218822Sdim// Set the hardware features for the extensions that are supported.
9633965Sjdpstatic void getExtensionFeatures(const Driver &D,
9733965Sjdp                                 const ArgList &Args,
9833965Sjdp                                 std::vector<StringRef> &Features,
9933965Sjdp                                 StringRef &MArch, StringRef &Exts) {
100218822Sdim  if (Exts.empty())
10133965Sjdp    return;
10233965Sjdp
103130561Sobrien  // Multi-letter extensions are seperated by a single underscore
10433965Sjdp  // as described in RISC-V User-Level ISA V2.2.
10533965Sjdp  SmallVector<StringRef, 8> Split;
10633965Sjdp  Exts.split(Split, StringRef("_"));
10733965Sjdp
10833965Sjdp  SmallVector<StringRef, 3> Prefix{"x", "s", "sx"};
10933965Sjdp  auto I = Prefix.begin();
110218822Sdim  auto E = Prefix.end();
111218822Sdim
112218822Sdim  SmallVector<StringRef, 8> AllExts;
113218822Sdim
114218822Sdim  for (StringRef Ext : Split) {
115218822Sdim    if (Ext.empty()) {
116218822Sdim      D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
117218822Sdim        << "extension name missing after separator '_'";
118218822Sdim      return;
119218822Sdim    }
120218822Sdim
121218822Sdim    StringRef Type = getExtensionType(Ext);
122218822Sdim    StringRef Name(Ext.substr(Type.size()));
123218822Sdim    StringRef Desc = getExtensionTypeDesc(Ext);
124218822Sdim
125218822Sdim    if (Type.empty()) {
126218822Sdim      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
127218822Sdim        << MArch << "invalid extension prefix" << Ext;
128218822Sdim      return;
129218822Sdim    }
130218822Sdim
131218822Sdim    // Check ISA extensions are specified in the canonical order.
132218822Sdim    while (I != E && *I != Type)
133218822Sdim      ++I;
134218822Sdim
135218822Sdim    if (I == E) {
136218822Sdim      std::string Error = Desc;
137218822Sdim      Error += " not given in canonical order";
138218822Sdim      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
139218822Sdim        << MArch <<  Error << Ext;
140218822Sdim      return;
141218822Sdim    }
142218822Sdim
14377298Sobrien    // The order is OK, do not advance I to the next prefix
14433965Sjdp    // to allow repeated extension type, e.g.: rv32ixabc_xdef.
14533965Sjdp
146130561Sobrien    if (Name.empty()) {
14733965Sjdp      std::string Error = Desc;
14833965Sjdp      Error += " name missing after";
14933965Sjdp      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
15033965Sjdp        << MArch << Error << Ext;
15133965Sjdp      return;
152218822Sdim    }
15333965Sjdp
15433965Sjdp    std::string Major, Minor;
15533965Sjdp    auto Pos = Name.find_if(isDigit);
15633965Sjdp    if (Pos != StringRef::npos) {
15733965Sjdp      auto Next =  Name.substr(Pos);
15833965Sjdp      Name = Name.substr(0, Pos);
15933965Sjdp      if (!getExtensionVersion(D, MArch, Ext, Next, Major, Minor))
16033965Sjdp        return;
16133965Sjdp    }
162218822Sdim
16333965Sjdp    // Check if duplicated extension.
16433965Sjdp    if (llvm::is_contained(AllExts, Ext)) {
165130561Sobrien      std::string Error = "duplicated ";
16633965Sjdp      Error += Desc;
16733965Sjdp      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
16833965Sjdp        << MArch << Error << Ext;
16933965Sjdp      return;
170218822Sdim    }
17133965Sjdp
17233965Sjdp    // Extension format is correct, keep parsing the extensions.
173130561Sobrien    // TODO: Save Type, Name, Major, Minor to avoid parsing them later.
17433965Sjdp    AllExts.push_back(Ext);
17533965Sjdp  }
17633965Sjdp
17733965Sjdp  // Set target features.
17833965Sjdp  // TODO: Hardware features to be handled in Support/TargetParser.cpp.
179218822Sdim  // TODO: Use version number when setting target features.
18033965Sjdp  for (auto Ext : AllExts) {
18133965Sjdp    if (!isSupportedExtension(Ext)) {
182130561Sobrien      StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext));
18333965Sjdp      std::string Error = "unsupported ";
18433965Sjdp      Error += Desc;
18533965Sjdp      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
18633965Sjdp        << MArch << Error << Ext;
18733965Sjdp      return;
18833965Sjdp    }
18933965Sjdp    Features.push_back(Args.MakeArgString("+" + Ext));
190218822Sdim  }
19133965Sjdp}
19233965Sjdp
193130561Sobrien// Returns false if an error is diagnosed.
19433965Sjdpstatic bool getArchFeatures(const Driver &D, StringRef MArch,
19533965Sjdp                            std::vector<StringRef> &Features,
19633965Sjdp                            const ArgList &Args) {
19733965Sjdp  // RISC-V ISA strings must be lowercase.
19833965Sjdp  if (llvm::any_of(MArch, [](char c) { return isupper(c); })) {
19933965Sjdp    D.Diag(diag::err_drv_invalid_riscv_arch_name)
200218822Sdim        << MArch << "string must be lowercase";
20133965Sjdp    return false;
20233965Sjdp  }
203130561Sobrien
20433965Sjdp  // ISA string must begin with rv32 or rv64.
20533965Sjdp  if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) ||
20633965Sjdp      (MArch.size() < 5)) {
20733965Sjdp    D.Diag(diag::err_drv_invalid_riscv_arch_name)
20833965Sjdp        << MArch << "string must begin with rv32{i,e,g} or rv64{i,g}";
20933965Sjdp    return false;
210218822Sdim  }
211218822Sdim
21233965Sjdp  bool HasRV64 = MArch.startswith("rv64");
21333965Sjdp
214130561Sobrien  // The canonical order specified in ISA manual.
21533965Sjdp  // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
21633965Sjdp  StringRef StdExts = "mafdqlcbjtpvn";
21733965Sjdp  bool HasF = false, HasD = false;
21833965Sjdp  char Baseline = MArch[4];
21933965Sjdp
22033965Sjdp  // First letter should be 'e', 'i' or 'g'.
22133965Sjdp  switch (Baseline) {
22233965Sjdp  default:
223218822Sdim    D.Diag(diag::err_drv_invalid_riscv_arch_name)
224130561Sobrien        << MArch << "first letter should be 'e', 'i' or 'g'";
22577298Sobrien    return false;
22633965Sjdp  case 'e': {
22733965Sjdp    StringRef Error;
228130561Sobrien    // Currently LLVM does not support 'e'.
22933965Sjdp    // Extension 'e' is not allowed in rv64.
23033965Sjdp    if (HasRV64)
23133965Sjdp      Error = "standard user-level extension 'e' requires 'rv32'";
23233965Sjdp    else
23333965Sjdp      Error = "unsupported standard user-level extension 'e'";
23433965Sjdp    D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch << Error;
23533965Sjdp    return false;
23633965Sjdp  }
23733965Sjdp  case 'i':
23833965Sjdp    break;
23933965Sjdp  case 'g':
24033965Sjdp    // g = imafd
24133965Sjdp    StdExts = StdExts.drop_front(4);
24233965Sjdp    Features.push_back("+m");
24333965Sjdp    Features.push_back("+a");
24433965Sjdp    Features.push_back("+f");
24533965Sjdp    Features.push_back("+d");
246    HasF = true;
247    HasD = true;
248    break;
249  }
250
251  // Skip rvxxx
252  StringRef Exts = MArch.substr(5);
253
254  // Remove non-standard extensions and supervisor-level extensions.
255  // They have 'x', 's', 'sx' prefixes. Parse them at the end.
256  // Find the very first occurrence of 's' or 'x'.
257  StringRef OtherExts;
258  size_t Pos = Exts.find_first_of("sx");
259  if (Pos != StringRef::npos) {
260    OtherExts = Exts.substr(Pos);
261    Exts = Exts.substr(0, Pos);
262  }
263
264  std::string Major, Minor;
265  if (!getExtensionVersion(D, MArch, std::string(1, Baseline), Exts, Major,
266                           Minor))
267    return false;
268
269  // TODO: Use version number when setting target features
270  // and consume the underscore '_' that might follow.
271
272  auto StdExtsItr = StdExts.begin();
273  auto StdExtsEnd = StdExts.end();
274
275  for (auto I = Exts.begin(), E = Exts.end(); I != E; ++I) {
276    char c = *I;
277
278    // Check ISA extensions are specified in the canonical order.
279    while (StdExtsItr != StdExtsEnd && *StdExtsItr != c)
280      ++StdExtsItr;
281
282    if (StdExtsItr == StdExtsEnd) {
283      // Either c contains a valid extension but it was not given in
284      // canonical order or it is an invalid extension.
285      StringRef Error;
286      if (StdExts.contains(c))
287        Error = "standard user-level extension not given in canonical order";
288      else
289        Error = "invalid standard user-level extension";
290      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
291          << MArch << Error << std::string(1, c);
292      return false;
293    }
294
295    // Move to next char to prevent repeated letter.
296    ++StdExtsItr;
297
298    if (std::next(I) != E) {
299      // Skip c.
300      std::string Next = std::string(std::next(I), E);
301      std::string Major, Minor;
302      if (!getExtensionVersion(D, MArch, std::string(1, c), Next, Major, Minor))
303        return false;
304
305      // TODO: Use version number when setting target features
306      // and consume the underscore '_' that might follow.
307    }
308
309    // The order is OK, then push it into features.
310    switch (c) {
311    default:
312      // Currently LLVM supports only "mafdc".
313      D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
314          << MArch << "unsupported standard user-level extension"
315          << std::string(1, c);
316      return false;
317    case 'm':
318      Features.push_back("+m");
319      break;
320    case 'a':
321      Features.push_back("+a");
322      break;
323    case 'f':
324      Features.push_back("+f");
325      HasF = true;
326      break;
327    case 'd':
328      Features.push_back("+d");
329      HasD = true;
330      break;
331    case 'c':
332      Features.push_back("+c");
333      break;
334    }
335  }
336
337  // Dependency check.
338  // It's illegal to specify the 'd' (double-precision floating point)
339  // extension without also specifying the 'f' (single precision
340  // floating-point) extension.
341  if (HasD && !HasF) {
342    D.Diag(diag::err_drv_invalid_riscv_arch_name)
343        << MArch << "d requires f extension to also be specified";
344    return false;
345  }
346
347  // Additional dependency checks.
348  // TODO: The 'q' extension requires rv64.
349  // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
350
351  // Handle all other types of extensions.
352  getExtensionFeatures(D, Args, Features, MArch, OtherExts);
353
354  return true;
355}
356
357void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
358                                   const ArgList &Args,
359                                   std::vector<StringRef> &Features) {
360  StringRef MArch = getRISCVArch(Args, Triple);
361
362  if (!getArchFeatures(D, MArch, Features, Args))
363    return;
364
365  // Handle features corresponding to "-ffixed-X" options
366  if (Args.hasArg(options::OPT_ffixed_x1))
367    Features.push_back("+reserve-x1");
368  if (Args.hasArg(options::OPT_ffixed_x2))
369    Features.push_back("+reserve-x2");
370  if (Args.hasArg(options::OPT_ffixed_x3))
371    Features.push_back("+reserve-x3");
372  if (Args.hasArg(options::OPT_ffixed_x4))
373    Features.push_back("+reserve-x4");
374  if (Args.hasArg(options::OPT_ffixed_x5))
375    Features.push_back("+reserve-x5");
376  if (Args.hasArg(options::OPT_ffixed_x6))
377    Features.push_back("+reserve-x6");
378  if (Args.hasArg(options::OPT_ffixed_x7))
379    Features.push_back("+reserve-x7");
380  if (Args.hasArg(options::OPT_ffixed_x8))
381    Features.push_back("+reserve-x8");
382  if (Args.hasArg(options::OPT_ffixed_x9))
383    Features.push_back("+reserve-x9");
384  if (Args.hasArg(options::OPT_ffixed_x10))
385    Features.push_back("+reserve-x10");
386  if (Args.hasArg(options::OPT_ffixed_x11))
387    Features.push_back("+reserve-x11");
388  if (Args.hasArg(options::OPT_ffixed_x12))
389    Features.push_back("+reserve-x12");
390  if (Args.hasArg(options::OPT_ffixed_x13))
391    Features.push_back("+reserve-x13");
392  if (Args.hasArg(options::OPT_ffixed_x14))
393    Features.push_back("+reserve-x14");
394  if (Args.hasArg(options::OPT_ffixed_x15))
395    Features.push_back("+reserve-x15");
396  if (Args.hasArg(options::OPT_ffixed_x16))
397    Features.push_back("+reserve-x16");
398  if (Args.hasArg(options::OPT_ffixed_x17))
399    Features.push_back("+reserve-x17");
400  if (Args.hasArg(options::OPT_ffixed_x18))
401    Features.push_back("+reserve-x18");
402  if (Args.hasArg(options::OPT_ffixed_x19))
403    Features.push_back("+reserve-x19");
404  if (Args.hasArg(options::OPT_ffixed_x20))
405    Features.push_back("+reserve-x20");
406  if (Args.hasArg(options::OPT_ffixed_x21))
407    Features.push_back("+reserve-x21");
408  if (Args.hasArg(options::OPT_ffixed_x22))
409    Features.push_back("+reserve-x22");
410  if (Args.hasArg(options::OPT_ffixed_x23))
411    Features.push_back("+reserve-x23");
412  if (Args.hasArg(options::OPT_ffixed_x24))
413    Features.push_back("+reserve-x24");
414  if (Args.hasArg(options::OPT_ffixed_x25))
415    Features.push_back("+reserve-x25");
416  if (Args.hasArg(options::OPT_ffixed_x26))
417    Features.push_back("+reserve-x26");
418  if (Args.hasArg(options::OPT_ffixed_x27))
419    Features.push_back("+reserve-x27");
420  if (Args.hasArg(options::OPT_ffixed_x28))
421    Features.push_back("+reserve-x28");
422  if (Args.hasArg(options::OPT_ffixed_x29))
423    Features.push_back("+reserve-x29");
424  if (Args.hasArg(options::OPT_ffixed_x30))
425    Features.push_back("+reserve-x30");
426  if (Args.hasArg(options::OPT_ffixed_x31))
427    Features.push_back("+reserve-x31");
428
429  // FreeBSD local, because ld.lld doesn't support relaxations
430  // -mno-relax is default, unless -mrelax is specified.
431  if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false))
432    Features.push_back("+relax");
433  else
434    Features.push_back("-relax");
435
436  // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is
437  // specified...
438  if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false)) {
439    // ... but we don't support -msave-restore, so issue a warning.
440    D.Diag(diag::warn_drv_clang_unsupported)
441      << Args.getLastArg(options::OPT_msave_restore)->getAsString(Args);
442  }
443
444  // Now add any that the user explicitly requested on the command line,
445  // which may override the defaults.
446  handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group);
447}
448
449StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
450  assert((Triple.getArch() == llvm::Triple::riscv32 ||
451          Triple.getArch() == llvm::Triple::riscv64) &&
452         "Unexpected triple");
453
454  // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
455  // configured using `--with-abi=`, then the logic for the default choice is
456  // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
457  // deviate from GCC's default only on baremetal targets (UnknownOS) where
458  // neither `-march` nor `-mabi` is specified.
459  //
460  // The logic uses the following, in order:
461  // 1. Explicit choices using `--with-abi=`
462  // 2. A default based on `--with-arch=`, if provided
463  // 3. A default based on the target triple's arch
464  //
465  // The logic in config.gcc is a little circular but it is not inconsistent.
466  //
467  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
468  // and `-mabi=` respectively instead.
469
470  // 1. If `-mabi=` is specified, use it.
471  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
472    return A->getValue();
473
474  // 2. Choose a default based on `-march=`
475  //
476  // rv32g | rv32*d -> ilp32d
477  // rv32e -> ilp32e
478  // rv32* -> ilp32
479  // rv64g | rv64*d -> lp64d
480  // rv64* -> lp64
481  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
482    StringRef MArch = A->getValue();
483
484    if (MArch.startswith_lower("rv32")) {
485      // FIXME: parse `March` to find `D` extension properly
486      if (MArch.substr(4).contains_lower("d") ||
487          MArch.startswith_lower("rv32g"))
488        return "ilp32d";
489      else if (MArch.startswith_lower("rv32e"))
490        return "ilp32e";
491      else
492        return "ilp32";
493    } else if (MArch.startswith_lower("rv64")) {
494      // FIXME: parse `March` to find `D` extension properly
495      if (MArch.substr(4).contains_lower("d") ||
496          MArch.startswith_lower("rv64g"))
497        return "lp64d";
498      else
499        return "lp64";
500    }
501  }
502
503  // 3. Choose a default based on the triple
504  //
505  // We deviate from GCC's defaults here:
506  // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
507  // - On all other OSs we use the double floating point calling convention.
508  if (Triple.getArch() == llvm::Triple::riscv32) {
509    if (Triple.getOS() == llvm::Triple::UnknownOS)
510      return "ilp32";
511    else
512      return "ilp32d";
513  } else {
514    if (Triple.getOS() == llvm::Triple::UnknownOS)
515      return "lp64";
516    else
517      return "lp64d";
518  }
519}
520
521StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
522                              const llvm::Triple &Triple) {
523  assert((Triple.getArch() == llvm::Triple::riscv32 ||
524          Triple.getArch() == llvm::Triple::riscv64) &&
525         "Unexpected triple");
526
527  // GCC's logic around choosing a default `-march=` is complex. If GCC is not
528  // configured using `--with-arch=`, then the logic for the default choice is
529  // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
530  // deviate from GCC's default only on baremetal targets (UnknownOS) where
531  // neither `-march` nor `-mabi` is specified.
532  //
533  // The logic uses the following, in order:
534  // 1. Explicit choices using `--with-arch=`
535  // 2. A default based on `--with-abi=`, if provided
536  // 3. A default based on the target triple's arch
537  //
538  // The logic in config.gcc is a little circular but it is not inconsistent.
539  //
540  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
541  // and `-mabi=` respectively instead.
542  //
543  // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
544  // instead of `rv{XLEN}gc` though they are (currently) equivalent.
545
546  // 1. If `-march=` is specified, use it.
547  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
548    return A->getValue();
549
550  // 2. Choose a default based on `-mabi=`
551  //
552  // ilp32e -> rv32e
553  // ilp32 | ilp32f | ilp32d -> rv32imafdc
554  // lp64 | lp64f | lp64d -> rv64imafdc
555  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
556    StringRef MABI = A->getValue();
557
558    if (MABI.equals_lower("ilp32e"))
559      return "rv32e";
560    else if (MABI.startswith_lower("ilp32"))
561      return "rv32imafdc";
562    else if (MABI.startswith_lower("lp64"))
563      return "rv64imafdc";
564  }
565
566  // 3. Choose a default based on the triple
567  //
568  // We deviate from GCC's defaults here:
569  // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
570  // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
571  if (Triple.getArch() == llvm::Triple::riscv32) {
572    if (Triple.getOS() == llvm::Triple::UnknownOS)
573      return "rv32imac";
574    else
575      return "rv32imafdc";
576  } else {
577    if (Triple.getOS() == llvm::Triple::UnknownOS)
578      return "rv64imac";
579    else
580      return "rv64imafdc";
581  }
582}
583