clang  20.0.0git
RISCV.cpp
Go to the documentation of this file.
1 //===--- RISCV.cpp - RISC-V 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"
15 #include "clang/Driver/Options.h"
16 #include "llvm/Option/ArgList.h"
17 #include "llvm/Support/Error.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include "llvm/TargetParser/Host.h"
20 #include "llvm/TargetParser/RISCVISAInfo.h"
21 #include "llvm/TargetParser/RISCVTargetParser.h"
22 
23 using namespace clang::driver;
24 using namespace clang::driver::tools;
25 using namespace clang;
26 using namespace llvm::opt;
27 
28 // Returns false if an error is diagnosed.
29 static 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  for (const std::string &Str : (*ISAInfo)->toFeatures(/*AddAllExtension=*/true,
46  /*IgnoreUnknown=*/false))
47  Features.push_back(Args.MakeArgString(Str));
48 
49  if (EnableExperimentalExtensions)
50  Features.push_back(Args.MakeArgString("+experimental"));
51 
52  return true;
53 }
54 
55 // Get features except standard extension feature
56 static void getRISCFeaturesFromMcpu(const Driver &D, const Arg *A,
57  const llvm::Triple &Triple,
58  StringRef Mcpu,
59  std::vector<StringRef> &Features) {
60  bool Is64Bit = Triple.isRISCV64();
61  if (!llvm::RISCV::parseCPU(Mcpu, Is64Bit)) {
62  // Try inverting Is64Bit in case the CPU is valid, but for the wrong target.
63  if (llvm::RISCV::parseCPU(Mcpu, !Is64Bit))
64  D.Diag(clang::diag::err_drv_invalid_riscv_cpu_name_for_target)
65  << Mcpu << Is64Bit;
66  else
67  D.Diag(clang::diag::err_drv_unsupported_option_argument)
68  << A->getSpelling() << Mcpu;
69  }
70 }
71 
72 void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
73  const ArgList &Args,
74  std::vector<StringRef> &Features) {
75  std::string MArch = getRISCVArch(Args, Triple);
76 
77  if (!getArchFeatures(D, MArch, Features, Args))
78  return;
79 
80  bool CPUFastScalarUnaligned = false;
81  bool CPUFastVectorUnaligned = false;
82 
83  // If users give march and mcpu, get std extension feature from MArch
84  // and other features (ex. mirco architecture feature) from mcpu
85  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
86  StringRef CPU = A->getValue();
87  if (CPU == "native")
88  CPU = llvm::sys::getHostCPUName();
89 
90  getRISCFeaturesFromMcpu(D, A, Triple, CPU, Features);
91 
92  if (llvm::RISCV::hasFastScalarUnalignedAccess(CPU))
93  CPUFastScalarUnaligned = true;
94  if (llvm::RISCV::hasFastVectorUnalignedAccess(CPU))
95  CPUFastVectorUnaligned = true;
96  }
97 
98  // Handle features corresponding to "-ffixed-X" options
99  if (Args.hasArg(options::OPT_ffixed_x1))
100  Features.push_back("+reserve-x1");
101  if (Args.hasArg(options::OPT_ffixed_x2))
102  Features.push_back("+reserve-x2");
103  if (Args.hasArg(options::OPT_ffixed_x3))
104  Features.push_back("+reserve-x3");
105  if (Args.hasArg(options::OPT_ffixed_x4))
106  Features.push_back("+reserve-x4");
107  if (Args.hasArg(options::OPT_ffixed_x5))
108  Features.push_back("+reserve-x5");
109  if (Args.hasArg(options::OPT_ffixed_x6))
110  Features.push_back("+reserve-x6");
111  if (Args.hasArg(options::OPT_ffixed_x7))
112  Features.push_back("+reserve-x7");
113  if (Args.hasArg(options::OPT_ffixed_x8))
114  Features.push_back("+reserve-x8");
115  if (Args.hasArg(options::OPT_ffixed_x9))
116  Features.push_back("+reserve-x9");
117  if (Args.hasArg(options::OPT_ffixed_x10))
118  Features.push_back("+reserve-x10");
119  if (Args.hasArg(options::OPT_ffixed_x11))
120  Features.push_back("+reserve-x11");
121  if (Args.hasArg(options::OPT_ffixed_x12))
122  Features.push_back("+reserve-x12");
123  if (Args.hasArg(options::OPT_ffixed_x13))
124  Features.push_back("+reserve-x13");
125  if (Args.hasArg(options::OPT_ffixed_x14))
126  Features.push_back("+reserve-x14");
127  if (Args.hasArg(options::OPT_ffixed_x15))
128  Features.push_back("+reserve-x15");
129  if (Args.hasArg(options::OPT_ffixed_x16))
130  Features.push_back("+reserve-x16");
131  if (Args.hasArg(options::OPT_ffixed_x17))
132  Features.push_back("+reserve-x17");
133  if (Args.hasArg(options::OPT_ffixed_x18))
134  Features.push_back("+reserve-x18");
135  if (Args.hasArg(options::OPT_ffixed_x19))
136  Features.push_back("+reserve-x19");
137  if (Args.hasArg(options::OPT_ffixed_x20))
138  Features.push_back("+reserve-x20");
139  if (Args.hasArg(options::OPT_ffixed_x21))
140  Features.push_back("+reserve-x21");
141  if (Args.hasArg(options::OPT_ffixed_x22))
142  Features.push_back("+reserve-x22");
143  if (Args.hasArg(options::OPT_ffixed_x23))
144  Features.push_back("+reserve-x23");
145  if (Args.hasArg(options::OPT_ffixed_x24))
146  Features.push_back("+reserve-x24");
147  if (Args.hasArg(options::OPT_ffixed_x25))
148  Features.push_back("+reserve-x25");
149  if (Args.hasArg(options::OPT_ffixed_x26))
150  Features.push_back("+reserve-x26");
151  if (Args.hasArg(options::OPT_ffixed_x27))
152  Features.push_back("+reserve-x27");
153  if (Args.hasArg(options::OPT_ffixed_x28))
154  Features.push_back("+reserve-x28");
155  if (Args.hasArg(options::OPT_ffixed_x29))
156  Features.push_back("+reserve-x29");
157  if (Args.hasArg(options::OPT_ffixed_x30))
158  Features.push_back("+reserve-x30");
159  if (Args.hasArg(options::OPT_ffixed_x31))
160  Features.push_back("+reserve-x31");
161 
162  // -mrelax is default, unless -mno-relax is specified.
163  if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) {
164  Features.push_back("+relax");
165  // -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing
166  // into .debug_addr, which is currently not implemented.
167  Arg *A;
169  D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation)
170  << A->getAsString(Args);
171  } else {
172  Features.push_back("-relax");
173  }
174 
175  // If -mstrict-align, -mno-strict-align, -mscalar-strict-align, or
176  // -mno-scalar-strict-align is passed, use it. Otherwise, the
177  // unaligned-scalar-mem is enabled if the CPU supports it or the target is
178  // Android.
179  if (const Arg *A = Args.getLastArg(
180  options::OPT_mno_strict_align, options::OPT_mscalar_strict_align,
181  options::OPT_mstrict_align, options::OPT_mno_scalar_strict_align)) {
182  if (A->getOption().matches(options::OPT_mno_strict_align) ||
183  A->getOption().matches(options::OPT_mno_scalar_strict_align)) {
184  Features.push_back("+unaligned-scalar-mem");
185  } else {
186  Features.push_back("-unaligned-scalar-mem");
187  }
188  } else if (CPUFastScalarUnaligned || Triple.isAndroid()) {
189  Features.push_back("+unaligned-scalar-mem");
190  }
191 
192  // If -mstrict-align, -mno-strict-align, -mvector-strict-align, or
193  // -mno-vector-strict-align is passed, use it. Otherwise, the
194  // unaligned-vector-mem is enabled if the CPU supports it or the target is
195  // Android.
196  if (const Arg *A = Args.getLastArg(
197  options::OPT_mno_strict_align, options::OPT_mvector_strict_align,
198  options::OPT_mstrict_align, options::OPT_mno_vector_strict_align)) {
199  if (A->getOption().matches(options::OPT_mno_strict_align) ||
200  A->getOption().matches(options::OPT_mno_vector_strict_align)) {
201  Features.push_back("+unaligned-vector-mem");
202  } else {
203  Features.push_back("-unaligned-vector-mem");
204  }
205  } else if (CPUFastVectorUnaligned || Triple.isAndroid()) {
206  Features.push_back("+unaligned-vector-mem");
207  }
208 
209  // Now add any that the user explicitly requested on the command line,
210  // which may override the defaults.
211  handleTargetFeaturesGroup(D, Triple, Args, Features,
212  options::OPT_m_riscv_Features_Group);
213 }
214 
215 StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
216  assert(Triple.isRISCV() && "Unexpected triple");
217 
218  // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
219  // configured using `--with-abi=`, then the logic for the default choice is
220  // defined in config.gcc. This function is based on the logic in GCC 9.2.0.
221  //
222  // The logic used in GCC 9.2.0 is the following, in order:
223  // 1. Explicit choices using `--with-abi=`
224  // 2. A default based on `--with-arch=`, if provided
225  // 3. A default based on the target triple's arch
226  //
227  // The logic in config.gcc is a little circular but it is not inconsistent.
228  //
229  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
230  // and `-mabi=` respectively instead.
231  //
232  // In order to make chosing logic more clear, Clang uses the following logic,
233  // in order:
234  // 1. Explicit choices using `-mabi=`
235  // 2. A default based on the architecture as determined by getRISCVArch
236  // 3. Choose a default based on the triple
237 
238  // 1. If `-mabi=` is specified, use it.
239  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
240  return A->getValue();
241 
242  // 2. Choose a default based on the target architecture.
243  //
244  // rv32g | rv32*d -> ilp32d
245  // rv32e -> ilp32e
246  // rv32* -> ilp32
247  // rv64g | rv64*d -> lp64d
248  // rv64e -> lp64e
249  // rv64* -> lp64
250  std::string Arch = getRISCVArch(Args, Triple);
251 
252  auto ParseResult = llvm::RISCVISAInfo::parseArchString(
253  Arch, /* EnableExperimentalExtension */ true);
254  // Ignore parsing error, just go 3rd step.
255  if (!llvm::errorToBool(ParseResult.takeError()))
256  return (*ParseResult)->computeDefaultABI();
257 
258  // 3. Choose a default based on the triple
259  //
260  // We deviate from GCC's defaults here:
261  // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
262  // - On all other OSs we use the double floating point calling convention.
263  if (Triple.isRISCV32()) {
264  if (Triple.getOS() == llvm::Triple::UnknownOS)
265  return "ilp32";
266  else
267  return "ilp32d";
268  } else {
269  if (Triple.getOS() == llvm::Triple::UnknownOS)
270  return "lp64";
271  else
272  return "lp64d";
273  }
274 }
275 
276 std::string riscv::getRISCVArch(const llvm::opt::ArgList &Args,
277  const llvm::Triple &Triple) {
278  assert(Triple.isRISCV() && "Unexpected triple");
279 
280  // GCC's logic around choosing a default `-march=` is complex. If GCC is not
281  // configured using `--with-arch=`, then the logic for the default choice is
282  // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
283  // deviate from GCC's default on additional `-mcpu` option (GCC does not
284  // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`
285  // nor `-mabi` is specified.
286  //
287  // The logic used in GCC 9.2.0 is the following, in order:
288  // 1. Explicit choices using `--with-arch=`
289  // 2. A default based on `--with-abi=`, if provided
290  // 3. A default based on the target triple's arch
291  //
292  // The logic in config.gcc is a little circular but it is not inconsistent.
293  //
294  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
295  // and `-mabi=` respectively instead.
296  //
297  // Clang uses the following logic, in order:
298  // 1. Explicit choices using `-march=`
299  // 2. Based on `-mcpu` if the target CPU has a default ISA string
300  // 3. A default based on `-mabi`, if provided
301  // 4. A default based on the target triple's arch
302  //
303  // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
304  // instead of `rv{XLEN}gc` though they are (currently) equivalent.
305 
306  // 1. If `-march=` is specified, use it.
307  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
308  return A->getValue();
309 
310  // 2. Get march (isa string) based on `-mcpu=`
311  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
312  StringRef CPU = A->getValue();
313  if (CPU == "native") {
314  CPU = llvm::sys::getHostCPUName();
315  // If the target cpu is unrecognized, use target features.
316  if (CPU.starts_with("generic")) {
317  auto FeatureMap = llvm::sys::getHostCPUFeatures();
318  // hwprobe may be unavailable on older Linux versions.
319  if (!FeatureMap.empty()) {
320  std::vector<std::string> Features;
321  for (auto &F : FeatureMap)
322  Features.push_back(((F.second ? "+" : "-") + F.first()).str());
323  auto ParseResult = llvm::RISCVISAInfo::parseFeatures(
324  Triple.isRISCV32() ? 32 : 64, Features);
325  if (ParseResult)
326  return (*ParseResult)->toString();
327  }
328  }
329  }
330 
331  StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
332  // Bypass if target cpu's default march is empty.
333  if (MArch != "")
334  return MArch.str();
335  }
336 
337  // 3. Choose a default based on `-mabi=`
338  //
339  // ilp32e -> rv32e
340  // lp64e -> rv64e
341  // ilp32 | ilp32f | ilp32d -> rv32imafdc
342  // lp64 | lp64f | lp64d -> rv64imafdc
343  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
344  StringRef MABI = A->getValue();
345 
346  if (MABI.equals_insensitive("ilp32e"))
347  return "rv32e";
348  else if (MABI.equals_insensitive("lp64e"))
349  return "rv64e";
350  else if (MABI.starts_with_insensitive("ilp32"))
351  return "rv32imafdc";
352  else if (MABI.starts_with_insensitive("lp64")) {
353  if (Triple.isAndroid())
354  return "rv64imafdcv_zba_zbb_zbs";
355 
356  return "rv64imafdc";
357  }
358  }
359 
360  // 4. Choose a default based on the triple
361  //
362  // We deviate from GCC's defaults here:
363  // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
364  // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
365  if (Triple.isRISCV32()) {
366  if (Triple.getOS() == llvm::Triple::UnknownOS)
367  return "rv32imac";
368  else
369  return "rv32imafdc";
370  } else {
371  if (Triple.getOS() == llvm::Triple::UnknownOS)
372  return "rv64imac";
373  else if (Triple.isAndroid())
374  return "rv64imafdcv_zba_zbb_zbs";
375  else
376  return "rv64imafdc";
377  }
378 }
379 
380 std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,
381  const llvm::Triple &Triple) {
382  std::string CPU;
383  // If we have -mcpu, use that.
384  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
385  CPU = A->getValue();
386 
387  // Handle CPU name is 'native'.
388  if (CPU == "native")
389  CPU = llvm::sys::getHostCPUName();
390 
391  if (!CPU.empty())
392  return CPU;
393 
394  return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";
395 }
const Decl * D
static bool getArchFeatures(const Driver &D, StringRef Arch, std::vector< StringRef > &Features, const ArgList &Args)
Definition: RISCV.cpp:29
static void getRISCFeaturesFromMcpu(const Driver &D, const Arg *A, const llvm::Triple &Triple, StringRef Mcpu, std::vector< StringRef > &Features)
Definition: RISCV.cpp:56
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:77
std::string getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition: RISCV.cpp:276
std::string getRISCVTargetCPU(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition: RISCV.cpp:380
StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
void getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, std::vector< llvm::StringRef > &Features)
void handleTargetFeaturesGroup(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, std::vector< StringRef > &Features, llvm::opt::OptSpecifier Group)
Iterate Args and convert -mxxx to +xxx and -mno-xxx to -xxx and append it to Features.
DwarfFissionKind getDebugFissionKind(const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::Arg *&Arg)
The JSON file list parser is used to communicate input to InstallAPI.