RISCV.cpp revision 1.4
1//===--- RISCV.cpp - RISCV Helpers for Tools --------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "RISCV.h"
10#include "../Clang.h"
11#include "ToolChains/CommonArgs.h"
12#include "clang/Basic/CharInfo.h"
13#include "clang/Driver/Driver.h"
14#include "clang/Driver/DriverDiagnostic.h"
15#include "clang/Driver/Options.h"
16#include "llvm/Option/ArgList.h"
17#include "llvm/Support/Error.h"
18#include "llvm/Support/Host.h"
19#include "llvm/Support/RISCVISAInfo.h"
20#include "llvm/Support/raw_ostream.h"
21#include "llvm/TargetParser/RISCVTargetParser.h"
22
23using namespace clang::driver;
24using namespace clang::driver::tools;
25using namespace clang;
26using namespace llvm::opt;
27
28// Returns false if an error is diagnosed.
29static bool getArchFeatures(const Driver &D, StringRef Arch,
30                            std::vector<StringRef> &Features,
31                            const ArgList &Args) {
32  bool EnableExperimentalExtensions =
33      Args.hasArg(options::OPT_menable_experimental_extensions);
34  auto ISAInfo =
35      llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtensions);
36  if (!ISAInfo) {
37    handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) {
38      D.Diag(diag::err_drv_invalid_riscv_arch_name)
39          << Arch << ErrMsg.getMessage();
40    });
41
42    return false;
43  }
44
45  (*ISAInfo)->toFeatures(
46      Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); },
47      /*AddAllExtensions=*/true);
48  return true;
49}
50
51// Get features except standard extension feature
52static bool getRISCFeaturesFromMcpu(const llvm::Triple &Triple, StringRef Mcpu,
53                                    std::vector<StringRef> &Features) {
54  bool Is64Bit = Triple.isRISCV64();
55  llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu);
56  return llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) &&
57         llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features);
58}
59
60void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
61                                   const ArgList &Args,
62                                   std::vector<StringRef> &Features) {
63  StringRef MArch = getRISCVArch(Args, Triple);
64
65  if (!getArchFeatures(D, MArch, Features, Args))
66    return;
67
68  // If users give march and mcpu, get std extension feature from MArch
69  // and other features (ex. mirco architecture feature) from mcpu
70  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
71    StringRef CPU = A->getValue();
72    if (CPU == "native")
73      CPU = llvm::sys::getHostCPUName();
74    if (!getRISCFeaturesFromMcpu(Triple, CPU, Features))
75      D.Diag(clang::diag::err_drv_unsupported_option_argument)
76          << A->getSpelling() << CPU;
77  }
78
79  // Handle features corresponding to "-ffixed-X" options
80  if (Args.hasArg(options::OPT_ffixed_x1))
81    Features.push_back("+reserve-x1");
82  if (Args.hasArg(options::OPT_ffixed_x2))
83    Features.push_back("+reserve-x2");
84  if (Args.hasArg(options::OPT_ffixed_x3))
85    Features.push_back("+reserve-x3");
86  if (Args.hasArg(options::OPT_ffixed_x4))
87    Features.push_back("+reserve-x4");
88  if (Args.hasArg(options::OPT_ffixed_x5))
89    Features.push_back("+reserve-x5");
90  if (Args.hasArg(options::OPT_ffixed_x6))
91    Features.push_back("+reserve-x6");
92  if (Args.hasArg(options::OPT_ffixed_x7))
93    Features.push_back("+reserve-x7");
94  if (Args.hasArg(options::OPT_ffixed_x8))
95    Features.push_back("+reserve-x8");
96  if (Args.hasArg(options::OPT_ffixed_x9))
97    Features.push_back("+reserve-x9");
98  if (Args.hasArg(options::OPT_ffixed_x10))
99    Features.push_back("+reserve-x10");
100  if (Args.hasArg(options::OPT_ffixed_x11))
101    Features.push_back("+reserve-x11");
102  if (Args.hasArg(options::OPT_ffixed_x12))
103    Features.push_back("+reserve-x12");
104  if (Args.hasArg(options::OPT_ffixed_x13))
105    Features.push_back("+reserve-x13");
106  if (Args.hasArg(options::OPT_ffixed_x14))
107    Features.push_back("+reserve-x14");
108  if (Args.hasArg(options::OPT_ffixed_x15))
109    Features.push_back("+reserve-x15");
110  if (Args.hasArg(options::OPT_ffixed_x16))
111    Features.push_back("+reserve-x16");
112  if (Args.hasArg(options::OPT_ffixed_x17))
113    Features.push_back("+reserve-x17");
114  if (Args.hasArg(options::OPT_ffixed_x18))
115    Features.push_back("+reserve-x18");
116  if (Args.hasArg(options::OPT_ffixed_x19))
117    Features.push_back("+reserve-x19");
118  if (Args.hasArg(options::OPT_ffixed_x20))
119    Features.push_back("+reserve-x20");
120  if (Args.hasArg(options::OPT_ffixed_x21))
121    Features.push_back("+reserve-x21");
122  if (Args.hasArg(options::OPT_ffixed_x22))
123    Features.push_back("+reserve-x22");
124  if (Args.hasArg(options::OPT_ffixed_x23))
125    Features.push_back("+reserve-x23");
126  if (Args.hasArg(options::OPT_ffixed_x24))
127    Features.push_back("+reserve-x24");
128  if (Args.hasArg(options::OPT_ffixed_x25))
129    Features.push_back("+reserve-x25");
130  if (Args.hasArg(options::OPT_ffixed_x26))
131    Features.push_back("+reserve-x26");
132  if (Args.hasArg(options::OPT_ffixed_x27))
133    Features.push_back("+reserve-x27");
134  if (Args.hasArg(options::OPT_ffixed_x28))
135    Features.push_back("+reserve-x28");
136  if (Args.hasArg(options::OPT_ffixed_x29))
137    Features.push_back("+reserve-x29");
138  if (Args.hasArg(options::OPT_ffixed_x30))
139    Features.push_back("+reserve-x30");
140  if (Args.hasArg(options::OPT_ffixed_x31))
141    Features.push_back("+reserve-x31");
142
143#ifdef __OpenBSD__
144  // -mno-relax is default, unless -mrelax is specified.
145  if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false))
146    Features.push_back("+relax");
147  else
148    Features.push_back("-relax");
149#else
150  // -mrelax is default, unless -mno-relax is specified.
151  if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) {
152    Features.push_back("+relax");
153    // -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing
154    // into .debug_addr, which is currently not implemented.
155    Arg *A;
156    if (getDebugFissionKind(D, Args, A) != DwarfFissionKind::None)
157      D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation)
158          << A->getAsString(Args);
159  } else {
160    Features.push_back("-relax");
161  }
162#endif
163
164  // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is
165  // specified.
166  if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false))
167    Features.push_back("+save-restore");
168  else
169    Features.push_back("-save-restore");
170
171  // Now add any that the user explicitly requested on the command line,
172  // which may override the defaults.
173  handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group);
174}
175
176StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
177  assert(Triple.isRISCV() && "Unexpected triple");
178
179  // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
180  // configured using `--with-abi=`, then the logic for the default choice is
181  // defined in config.gcc. This function is based on the logic in GCC 9.2.0.
182  //
183  // The logic used in GCC 9.2.0 is the following, in order:
184  // 1. Explicit choices using `--with-abi=`
185  // 2. A default based on `--with-arch=`, if provided
186  // 3. A default based on the target triple's arch
187  //
188  // The logic in config.gcc is a little circular but it is not inconsistent.
189  //
190  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
191  // and `-mabi=` respectively instead.
192  //
193  // In order to make chosing logic more clear, Clang uses the following logic,
194  // in order:
195  // 1. Explicit choices using `-mabi=`
196  // 2. A default based on the architecture as determined by getRISCVArch
197  // 3. Choose a default based on the triple
198
199  // 1. If `-mabi=` is specified, use it.
200  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
201    return A->getValue();
202
203  // 2. Choose a default based on the target architecture.
204  //
205  // rv32g | rv32*d -> ilp32d
206  // rv32e -> ilp32e
207  // rv32* -> ilp32
208  // rv64g | rv64*d -> lp64d
209  // rv64* -> lp64
210  StringRef Arch = getRISCVArch(Args, Triple);
211
212  auto ParseResult = llvm::RISCVISAInfo::parseArchString(
213      Arch, /* EnableExperimentalExtension */ true);
214  if (!ParseResult)
215    // Ignore parsing error, just go 3rd step.
216    consumeError(ParseResult.takeError());
217  else
218    return (*ParseResult)->computeDefaultABI();
219
220  // 3. Choose a default based on the triple
221  //
222  // We deviate from GCC's defaults here:
223  // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
224  // - On all other OSs we use the double floating point calling convention.
225  if (Triple.isRISCV32()) {
226    if (Triple.getOS() == llvm::Triple::UnknownOS)
227      return "ilp32";
228    else
229      return "ilp32d";
230  } else {
231    if (Triple.getOS() == llvm::Triple::UnknownOS)
232      return "lp64";
233    else
234      return "lp64d";
235  }
236}
237
238StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
239                              const llvm::Triple &Triple) {
240  assert(Triple.isRISCV() && "Unexpected triple");
241
242  // GCC's logic around choosing a default `-march=` is complex. If GCC is not
243  // configured using `--with-arch=`, then the logic for the default choice is
244  // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
245  // deviate from GCC's default on additional `-mcpu` option (GCC does not
246  // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`
247  // nor `-mabi` is specified.
248  //
249  // The logic used in GCC 9.2.0 is the following, in order:
250  // 1. Explicit choices using `--with-arch=`
251  // 2. A default based on `--with-abi=`, if provided
252  // 3. A default based on the target triple's arch
253  //
254  // The logic in config.gcc is a little circular but it is not inconsistent.
255  //
256  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
257  // and `-mabi=` respectively instead.
258  //
259  // Clang uses the following logic, in order:
260  // 1. Explicit choices using `-march=`
261  // 2. Based on `-mcpu` if the target CPU has a default ISA string
262  // 3. A default based on `-mabi`, if provided
263  // 4. A default based on the target triple's arch
264  //
265  // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
266  // instead of `rv{XLEN}gc` though they are (currently) equivalent.
267
268  // 1. If `-march=` is specified, use it.
269  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
270    return A->getValue();
271
272  // 2. Get march (isa string) based on `-mcpu=`
273  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
274    StringRef CPU = A->getValue();
275    if (CPU == "native")
276      CPU = llvm::sys::getHostCPUName();
277    StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
278    // Bypass if target cpu's default march is empty.
279    if (MArch != "")
280      return MArch;
281  }
282
283  // 3. Choose a default based on `-mabi=`
284  //
285  // ilp32e -> rv32e
286  // ilp32 | ilp32f | ilp32d -> rv32imafdc
287  // lp64 | lp64f | lp64d -> rv64imafdc
288  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
289    StringRef MABI = A->getValue();
290
291    if (MABI.equals_insensitive("ilp32e"))
292      return "rv32e";
293    else if (MABI.startswith_insensitive("ilp32"))
294      return "rv32imafdc";
295    else if (MABI.startswith_insensitive("lp64"))
296      return "rv64imafdc";
297  }
298
299  // 4. Choose a default based on the triple
300  //
301  // We deviate from GCC's defaults here:
302  // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
303  // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
304  if (Triple.isRISCV32()) {
305    if (Triple.getOS() == llvm::Triple::UnknownOS)
306      return "rv32imac";
307    else
308      return "rv32imafdc";
309  } else {
310    if (Triple.getOS() == llvm::Triple::UnknownOS)
311      return "rv64imac";
312    else
313      return "rv64imafdc";
314  }
315}
316
317std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,
318                                     const llvm::Triple &Triple) {
319  std::string CPU;
320  // If we have -mcpu, use that.
321  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
322    CPU = A->getValue();
323
324  // Handle CPU name is 'native'.
325  if (CPU == "native")
326    CPU = llvm::sys::getHostCPUName();
327
328  if (!CPU.empty())
329    return CPU;
330
331  return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";
332}
333