clang  16.0.0git
RISCV.cpp
Go to the documentation of this file.
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"
15 #include "clang/Driver/Options.h"
16 #include "llvm/ADT/Optional.h"
17 #include "llvm/Option/ArgList.h"
18 #include "llvm/Support/Error.h"
19 #include "llvm/Support/Host.h"
20 #include "llvm/Support/RISCVISAInfo.h"
21 #include "llvm/Support/TargetParser.h"
22 #include "llvm/Support/raw_ostream.h"
23 
24 using namespace clang::driver;
25 using namespace clang::driver::tools;
26 using namespace clang;
27 using namespace llvm::opt;
28 
29 // Returns false if an error is diagnosed.
30 static bool getArchFeatures(const Driver &D, StringRef Arch,
31  std::vector<StringRef> &Features,
32  const ArgList &Args) {
33  bool EnableExperimentalExtensions =
34  Args.hasArg(options::OPT_menable_experimental_extensions);
35  auto ISAInfo =
36  llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtensions);
37  if (!ISAInfo) {
38  handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) {
39  D.Diag(diag::err_drv_invalid_riscv_arch_name)
40  << Arch << ErrMsg.getMessage();
41  });
42 
43  return false;
44  }
45 
46  (*ISAInfo)->toFeatures(
47  Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); });
48  return true;
49 }
50 
51 // Get features except standard extension feature
52 static 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 
60 void 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  // -mrelax is default, unless -mno-relax is specified.
144  if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) {
145  Features.push_back("+relax");
146  // -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing
147  // into .debug_addr, which is currently not implemented.
148  Arg *A;
149  if (getDebugFissionKind(D, Args, A) != DwarfFissionKind::None)
150  D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation)
151  << A->getAsString(Args);
152  } else {
153  Features.push_back("-relax");
154  }
155 
156  // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is
157  // specified.
158  if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false))
159  Features.push_back("+save-restore");
160  else
161  Features.push_back("-save-restore");
162 
163  // Now add any that the user explicitly requested on the command line,
164  // which may override the defaults.
165  handleTargetFeaturesGroup(Args, Features, options::OPT_m_riscv_Features_Group);
166 }
167 
168 StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
169  assert(Triple.isRISCV() && "Unexpected triple");
170 
171  // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
172  // configured using `--with-abi=`, then the logic for the default choice is
173  // defined in config.gcc. This function is based on the logic in GCC 9.2.0.
174  //
175  // The logic used in GCC 9.2.0 is the following, in order:
176  // 1. Explicit choices using `--with-abi=`
177  // 2. A default based on `--with-arch=`, if provided
178  // 3. A default based on the target triple's arch
179  //
180  // The logic in config.gcc is a little circular but it is not inconsistent.
181  //
182  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
183  // and `-mabi=` respectively instead.
184  //
185  // In order to make chosing logic more clear, Clang uses the following logic,
186  // in order:
187  // 1. Explicit choices using `-mabi=`
188  // 2. A default based on the architecture as determined by getRISCVArch
189  // 3. Choose a default based on the triple
190 
191  // 1. If `-mabi=` is specified, use it.
192  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
193  return A->getValue();
194 
195  // 2. Choose a default based on the target architecture.
196  //
197  // rv32g | rv32*d -> ilp32d
198  // rv32e -> ilp32e
199  // rv32* -> ilp32
200  // rv64g | rv64*d -> lp64d
201  // rv64* -> lp64
202  StringRef Arch = getRISCVArch(Args, Triple);
203 
204  auto ParseResult = llvm::RISCVISAInfo::parseArchString(
205  Arch, /* EnableExperimentalExtension */ true);
206  if (!ParseResult)
207  // Ignore parsing error, just go 3rd step.
208  consumeError(ParseResult.takeError());
209  else
210  return (*ParseResult)->computeDefaultABI();
211 
212  // 3. Choose a default based on the triple
213  //
214  // We deviate from GCC's defaults here:
215  // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
216  // - On all other OSs we use the double floating point calling convention.
217  if (Triple.isRISCV32()) {
218  if (Triple.getOS() == llvm::Triple::UnknownOS)
219  return "ilp32";
220  else
221  return "ilp32d";
222  } else {
223  if (Triple.getOS() == llvm::Triple::UnknownOS)
224  return "lp64";
225  else
226  return "lp64d";
227  }
228 }
229 
230 StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
231  const llvm::Triple &Triple) {
232  assert(Triple.isRISCV() && "Unexpected triple");
233 
234  // GCC's logic around choosing a default `-march=` is complex. If GCC is not
235  // configured using `--with-arch=`, then the logic for the default choice is
236  // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
237  // deviate from GCC's default on additional `-mcpu` option (GCC does not
238  // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`
239  // nor `-mabi` is specified.
240  //
241  // The logic used in GCC 9.2.0 is the following, in order:
242  // 1. Explicit choices using `--with-arch=`
243  // 2. A default based on `--with-abi=`, if provided
244  // 3. A default based on the target triple's arch
245  //
246  // The logic in config.gcc is a little circular but it is not inconsistent.
247  //
248  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
249  // and `-mabi=` respectively instead.
250  //
251  // Clang uses the following logic, in order:
252  // 1. Explicit choices using `-march=`
253  // 2. Based on `-mcpu` if the target CPU has a default ISA string
254  // 3. A default based on `-mabi`, if provided
255  // 4. A default based on the target triple's arch
256  //
257  // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
258  // instead of `rv{XLEN}gc` though they are (currently) equivalent.
259 
260  // 1. If `-march=` is specified, use it.
261  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
262  return A->getValue();
263 
264  // 2. Get march (isa string) based on `-mcpu=`
265  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
266  StringRef CPU = A->getValue();
267  if (CPU == "native")
268  CPU = llvm::sys::getHostCPUName();
269  StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
270  // Bypass if target cpu's default march is empty.
271  if (MArch != "")
272  return MArch;
273  }
274 
275  // 3. Choose a default based on `-mabi=`
276  //
277  // ilp32e -> rv32e
278  // ilp32 | ilp32f | ilp32d -> rv32imafdc
279  // lp64 | lp64f | lp64d -> rv64imafdc
280  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
281  StringRef MABI = A->getValue();
282 
283  if (MABI.equals_insensitive("ilp32e"))
284  return "rv32e";
285  else if (MABI.startswith_insensitive("ilp32"))
286  return "rv32imafdc";
287  else if (MABI.startswith_insensitive("lp64"))
288  return "rv64imafdc";
289  }
290 
291  // 4. Choose a default based on the triple
292  //
293  // We deviate from GCC's defaults here:
294  // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
295  // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
296  if (Triple.isRISCV32()) {
297  if (Triple.getOS() == llvm::Triple::UnknownOS)
298  return "rv32imac";
299  else
300  return "rv32imafdc";
301  } else {
302  if (Triple.getOS() == llvm::Triple::UnknownOS)
303  return "rv64imac";
304  else
305  return "rv64imafdc";
306  }
307 }
308 
309 std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,
310  const llvm::Triple &Triple) {
311  std::string CPU;
312  // If we have -mcpu, use that.
313  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
314  CPU = A->getValue();
315 
316  // Handle CPU name is 'native'.
317  if (CPU == "native")
318  CPU = llvm::sys::getHostCPUName();
319 
320  if (!CPU.empty())
321  return CPU;
322 
323  return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";
324 }
Driver.h
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::driver::tools::getDebugFissionKind
DwarfFissionKind getDebugFissionKind(const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::Arg *&Arg)
clang::driver::tools
Definition: AIX.h:17
RISCV.h
clang::driver::tools::riscv::getRISCVArch
StringRef getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition: RISCV.cpp:230
clang::driver::tools::DwarfFissionKind::None
@ None
clang::driver::Driver::Diag
DiagnosticBuilder Diag(unsigned DiagID) const
Definition: Driver.h:142
Options.h
llvm::opt
Definition: DiagnosticOptions.h:19
DriverDiagnostic.h
clang::driver::tools::handleTargetFeaturesGroup
void handleTargetFeaturesGroup(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.
clang::driver::tools::riscv::getRISCVTargetFeatures
void getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, std::vector< llvm::StringRef > &Features)
CharInfo.h
CommonArgs.h
clang
Definition: CalledOnceCheck.h:17
clang::driver::Driver
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:75
clang::driver::tools::riscv::getRISCVTargetCPU
std::string getRISCVTargetCPU(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition: RISCV.cpp:309
clang::driver::tools::riscv::getRISCVABI
StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
clang::driver
Definition: Action.h:31
getRISCFeaturesFromMcpu
static bool getRISCFeaturesFromMcpu(const llvm::Triple &Triple, StringRef Mcpu, std::vector< StringRef > &Features)
Definition: RISCV.cpp:52
getArchFeatures
static bool getArchFeatures(const Driver &D, StringRef Arch, std::vector< StringRef > &Features, const ArgList &Args)
Definition: RISCV.cpp:30