clang 18.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"
13#include "clang/Driver/Driver.h"
16#include "llvm/Option/ArgList.h"
17#include "llvm/Support/Error.h"
18#include "llvm/Support/RISCVISAInfo.h"
19#include "llvm/Support/raw_ostream.h"
20#include "llvm/TargetParser/Host.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 void getRISCFeaturesFromMcpu(const Driver &D, const Arg *A,
53 const llvm::Triple &Triple,
54 StringRef Mcpu,
55 std::vector<StringRef> &Features) {
56 bool Is64Bit = Triple.isRISCV64();
57 if (!llvm::RISCV::parseCPU(Mcpu, Is64Bit)) {
58 // Try inverting Is64Bit in case the CPU is valid, but for the wrong target.
59 if (llvm::RISCV::parseCPU(Mcpu, !Is64Bit))
60 D.Diag(clang::diag::err_drv_invalid_riscv_cpu_name_for_target)
61 << Mcpu << Is64Bit;
62 else
63 D.Diag(clang::diag::err_drv_unsupported_option_argument)
64 << A->getSpelling() << Mcpu;
65 }
66}
67
68void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
69 const ArgList &Args,
70 std::vector<StringRef> &Features) {
71 StringRef MArch = getRISCVArch(Args, Triple);
72
73 if (!getArchFeatures(D, MArch, Features, Args))
74 return;
75
76 // If users give march and mcpu, get std extension feature from MArch
77 // and other features (ex. mirco architecture feature) from mcpu
78 if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
79 StringRef CPU = A->getValue();
80 if (CPU == "native")
81 CPU = llvm::sys::getHostCPUName();
82
83 getRISCFeaturesFromMcpu(D, A, Triple, CPU, Features);
84 }
85
86 // Handle features corresponding to "-ffixed-X" options
87 if (Args.hasArg(options::OPT_ffixed_x1))
88 Features.push_back("+reserve-x1");
89 if (Args.hasArg(options::OPT_ffixed_x2))
90 Features.push_back("+reserve-x2");
91 if (Args.hasArg(options::OPT_ffixed_x3))
92 Features.push_back("+reserve-x3");
93 if (Args.hasArg(options::OPT_ffixed_x4))
94 Features.push_back("+reserve-x4");
95 if (Args.hasArg(options::OPT_ffixed_x5))
96 Features.push_back("+reserve-x5");
97 if (Args.hasArg(options::OPT_ffixed_x6))
98 Features.push_back("+reserve-x6");
99 if (Args.hasArg(options::OPT_ffixed_x7))
100 Features.push_back("+reserve-x7");
101 if (Args.hasArg(options::OPT_ffixed_x8))
102 Features.push_back("+reserve-x8");
103 if (Args.hasArg(options::OPT_ffixed_x9))
104 Features.push_back("+reserve-x9");
105 if (Args.hasArg(options::OPT_ffixed_x10))
106 Features.push_back("+reserve-x10");
107 if (Args.hasArg(options::OPT_ffixed_x11))
108 Features.push_back("+reserve-x11");
109 if (Args.hasArg(options::OPT_ffixed_x12))
110 Features.push_back("+reserve-x12");
111 if (Args.hasArg(options::OPT_ffixed_x13))
112 Features.push_back("+reserve-x13");
113 if (Args.hasArg(options::OPT_ffixed_x14))
114 Features.push_back("+reserve-x14");
115 if (Args.hasArg(options::OPT_ffixed_x15))
116 Features.push_back("+reserve-x15");
117 if (Args.hasArg(options::OPT_ffixed_x16))
118 Features.push_back("+reserve-x16");
119 if (Args.hasArg(options::OPT_ffixed_x17))
120 Features.push_back("+reserve-x17");
121 if (Args.hasArg(options::OPT_ffixed_x18))
122 Features.push_back("+reserve-x18");
123 if (Args.hasArg(options::OPT_ffixed_x19))
124 Features.push_back("+reserve-x19");
125 if (Args.hasArg(options::OPT_ffixed_x20))
126 Features.push_back("+reserve-x20");
127 if (Args.hasArg(options::OPT_ffixed_x21))
128 Features.push_back("+reserve-x21");
129 if (Args.hasArg(options::OPT_ffixed_x22))
130 Features.push_back("+reserve-x22");
131 if (Args.hasArg(options::OPT_ffixed_x23))
132 Features.push_back("+reserve-x23");
133 if (Args.hasArg(options::OPT_ffixed_x24))
134 Features.push_back("+reserve-x24");
135 if (Args.hasArg(options::OPT_ffixed_x25))
136 Features.push_back("+reserve-x25");
137 if (Args.hasArg(options::OPT_ffixed_x26))
138 Features.push_back("+reserve-x26");
139 if (Args.hasArg(options::OPT_ffixed_x27))
140 Features.push_back("+reserve-x27");
141 if (Args.hasArg(options::OPT_ffixed_x28))
142 Features.push_back("+reserve-x28");
143 if (Args.hasArg(options::OPT_ffixed_x29))
144 Features.push_back("+reserve-x29");
145 if (Args.hasArg(options::OPT_ffixed_x30))
146 Features.push_back("+reserve-x30");
147 if (Args.hasArg(options::OPT_ffixed_x31))
148 Features.push_back("+reserve-x31");
149
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
163 // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is
164 // specified.
165 if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false))
166 Features.push_back("+save-restore");
167 else
168 Features.push_back("-save-restore");
169
170 // -mno-unaligned-access is default, unless -munaligned-access is specified.
171 bool HasV = llvm::is_contained(Features, "+zve32x");
172 if (const Arg *A = Args.getLastArg(options::OPT_munaligned_access,
173 options::OPT_mno_unaligned_access)) {
174 if (A->getOption().matches(options::OPT_munaligned_access)) {
175 Features.push_back("+unaligned-scalar-mem");
176 if (HasV)
177 Features.push_back("+unaligned-vector-mem");
178 } else {
179 Features.push_back("-unaligned-scalar-mem");
180 if (HasV)
181 Features.push_back("-unaligned-vector-mem");
182 }
183 }
184
185 // Now add any that the user explicitly requested on the command line,
186 // which may override the defaults.
187 handleTargetFeaturesGroup(D, Triple, Args, Features,
188 options::OPT_m_riscv_Features_Group);
189}
190
191StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
192 assert(Triple.isRISCV() && "Unexpected triple");
193
194 // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
195 // configured using `--with-abi=`, then the logic for the default choice is
196 // defined in config.gcc. This function is based on the logic in GCC 9.2.0.
197 //
198 // The logic used in GCC 9.2.0 is the following, in order:
199 // 1. Explicit choices using `--with-abi=`
200 // 2. A default based on `--with-arch=`, if provided
201 // 3. A default based on the target triple's arch
202 //
203 // The logic in config.gcc is a little circular but it is not inconsistent.
204 //
205 // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
206 // and `-mabi=` respectively instead.
207 //
208 // In order to make chosing logic more clear, Clang uses the following logic,
209 // in order:
210 // 1. Explicit choices using `-mabi=`
211 // 2. A default based on the architecture as determined by getRISCVArch
212 // 3. Choose a default based on the triple
213
214 // 1. If `-mabi=` is specified, use it.
215 if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
216 return A->getValue();
217
218 // 2. Choose a default based on the target architecture.
219 //
220 // rv32g | rv32*d -> ilp32d
221 // rv32e -> ilp32e
222 // rv32* -> ilp32
223 // rv64g | rv64*d -> lp64d
224 // rv64* -> lp64
225 StringRef Arch = getRISCVArch(Args, Triple);
226
227 auto ParseResult = llvm::RISCVISAInfo::parseArchString(
228 Arch, /* EnableExperimentalExtension */ true);
229 if (!ParseResult)
230 // Ignore parsing error, just go 3rd step.
231 consumeError(ParseResult.takeError());
232 else
233 return (*ParseResult)->computeDefaultABI();
234
235 // 3. Choose a default based on the triple
236 //
237 // We deviate from GCC's defaults here:
238 // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
239 // - On all other OSs we use the double floating point calling convention.
240 if (Triple.isRISCV32()) {
241 if (Triple.getOS() == llvm::Triple::UnknownOS)
242 return "ilp32";
243 else
244 return "ilp32d";
245 } else {
246 if (Triple.getOS() == llvm::Triple::UnknownOS)
247 return "lp64";
248 else
249 return "lp64d";
250 }
251}
252
253StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
254 const llvm::Triple &Triple) {
255 assert(Triple.isRISCV() && "Unexpected triple");
256
257 // GCC's logic around choosing a default `-march=` is complex. If GCC is not
258 // configured using `--with-arch=`, then the logic for the default choice is
259 // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
260 // deviate from GCC's default on additional `-mcpu` option (GCC does not
261 // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`
262 // nor `-mabi` is specified.
263 //
264 // The logic used in GCC 9.2.0 is the following, in order:
265 // 1. Explicit choices using `--with-arch=`
266 // 2. A default based on `--with-abi=`, if provided
267 // 3. A default based on the target triple's arch
268 //
269 // The logic in config.gcc is a little circular but it is not inconsistent.
270 //
271 // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
272 // and `-mabi=` respectively instead.
273 //
274 // Clang uses the following logic, in order:
275 // 1. Explicit choices using `-march=`
276 // 2. Based on `-mcpu` if the target CPU has a default ISA string
277 // 3. A default based on `-mabi`, if provided
278 // 4. A default based on the target triple's arch
279 //
280 // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
281 // instead of `rv{XLEN}gc` though they are (currently) equivalent.
282
283 // 1. If `-march=` is specified, use it.
284 if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
285 return A->getValue();
286
287 // 2. Get march (isa string) based on `-mcpu=`
288 if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
289 StringRef CPU = A->getValue();
290 if (CPU == "native")
291 CPU = llvm::sys::getHostCPUName();
292 StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
293 // Bypass if target cpu's default march is empty.
294 if (MArch != "")
295 return MArch;
296 }
297
298 // 3. Choose a default based on `-mabi=`
299 //
300 // ilp32e -> rv32e
301 // ilp32 | ilp32f | ilp32d -> rv32imafdc
302 // lp64 | lp64f | lp64d -> rv64imafdc
303 if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
304 StringRef MABI = A->getValue();
305
306 if (MABI.equals_insensitive("ilp32e"))
307 return "rv32e";
308 else if (MABI.starts_with_insensitive("ilp32"))
309 return "rv32imafdc";
310 else if (MABI.starts_with_insensitive("lp64")) {
311 if (Triple.isAndroid())
312 return "rv64imafdc_zba_zbb_zbs";
313
314 return "rv64imafdc";
315 }
316 }
317
318 // 4. Choose a default based on the triple
319 //
320 // We deviate from GCC's defaults here:
321 // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
322 // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
323 if (Triple.isRISCV32()) {
324 if (Triple.getOS() == llvm::Triple::UnknownOS)
325 return "rv32imac";
326 else
327 return "rv32imafdc";
328 } else {
329 if (Triple.getOS() == llvm::Triple::UnknownOS)
330 return "rv64imac";
331 else if (Triple.isAndroid())
332 return "rv64imafdc_zba_zbb_zbs";
333 else
334 return "rv64imafdc";
335 }
336}
337
338std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,
339 const llvm::Triple &Triple) {
340 std::string CPU;
341 // If we have -mcpu, use that.
342 if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
343 CPU = A->getValue();
344
345 // Handle CPU name is 'native'.
346 if (CPU == "native")
347 CPU = llvm::sys::getHostCPUName();
348
349 if (!CPU.empty())
350 return CPU;
351
352 return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";
353}
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:52
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:77
DiagnosticBuilder Diag(unsigned DiagID) const
Definition: Driver.h:144
std::string getRISCVTargetCPU(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition: RISCV.cpp:338
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)
StringRef getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition: RISCV.cpp:253
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)