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" |
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/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(Ids: options::OPT_menable_experimental_extensions); |
34 | auto ISAInfo = |
35 | llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtension: EnableExperimentalExtensions); |
36 | if (!ISAInfo) { |
37 | handleAllErrors(E: ISAInfo.takeError(), Handlers: [&](llvm::StringError &ErrMsg) { |
38 | D.Diag(DiagID: 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=*/AddAllExtensions: true, |
46 | /*IgnoreUnknown=*/false)) |
47 | Features.push_back(x: Args.MakeArgString(Str)); |
48 | |
49 | if (EnableExperimentalExtensions) |
50 | Features.push_back(x: Args.MakeArgString(Str: "+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(CPU: Mcpu, IsRV64: Is64Bit)) { |
62 | // Try inverting Is64Bit in case the CPU is valid, but for the wrong target. |
63 | if (llvm::RISCV::parseCPU(CPU: Mcpu, IsRV64: !Is64Bit)) |
64 | D.Diag(DiagID: clang::diag::err_drv_invalid_riscv_cpu_name_for_target) |
65 | << Mcpu << Is64Bit; |
66 | else |
67 | D.Diag(DiagID: 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, Arch: 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(Ids: options::OPT_mcpu_EQ)) { |
86 | StringRef CPU = A->getValue(); |
87 | if (CPU == "native" ) |
88 | CPU = llvm::sys::getHostCPUName(); |
89 | |
90 | getRISCFeaturesFromMcpu(D, A, Triple, Mcpu: 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(Ids: options::OPT_ffixed_x1)) |
100 | Features.push_back(x: "+reserve-x1" ); |
101 | if (Args.hasArg(Ids: options::OPT_ffixed_x2)) |
102 | Features.push_back(x: "+reserve-x2" ); |
103 | if (Args.hasArg(Ids: options::OPT_ffixed_x3)) |
104 | Features.push_back(x: "+reserve-x3" ); |
105 | if (Args.hasArg(Ids: options::OPT_ffixed_x4)) |
106 | Features.push_back(x: "+reserve-x4" ); |
107 | if (Args.hasArg(Ids: options::OPT_ffixed_x5)) |
108 | Features.push_back(x: "+reserve-x5" ); |
109 | if (Args.hasArg(Ids: options::OPT_ffixed_x6)) |
110 | Features.push_back(x: "+reserve-x6" ); |
111 | if (Args.hasArg(Ids: options::OPT_ffixed_x7)) |
112 | Features.push_back(x: "+reserve-x7" ); |
113 | if (Args.hasArg(Ids: options::OPT_ffixed_x8)) |
114 | Features.push_back(x: "+reserve-x8" ); |
115 | if (Args.hasArg(Ids: options::OPT_ffixed_x9)) |
116 | Features.push_back(x: "+reserve-x9" ); |
117 | if (Args.hasArg(Ids: options::OPT_ffixed_x10)) |
118 | Features.push_back(x: "+reserve-x10" ); |
119 | if (Args.hasArg(Ids: options::OPT_ffixed_x11)) |
120 | Features.push_back(x: "+reserve-x11" ); |
121 | if (Args.hasArg(Ids: options::OPT_ffixed_x12)) |
122 | Features.push_back(x: "+reserve-x12" ); |
123 | if (Args.hasArg(Ids: options::OPT_ffixed_x13)) |
124 | Features.push_back(x: "+reserve-x13" ); |
125 | if (Args.hasArg(Ids: options::OPT_ffixed_x14)) |
126 | Features.push_back(x: "+reserve-x14" ); |
127 | if (Args.hasArg(Ids: options::OPT_ffixed_x15)) |
128 | Features.push_back(x: "+reserve-x15" ); |
129 | if (Args.hasArg(Ids: options::OPT_ffixed_x16)) |
130 | Features.push_back(x: "+reserve-x16" ); |
131 | if (Args.hasArg(Ids: options::OPT_ffixed_x17)) |
132 | Features.push_back(x: "+reserve-x17" ); |
133 | if (Args.hasArg(Ids: options::OPT_ffixed_x18)) |
134 | Features.push_back(x: "+reserve-x18" ); |
135 | if (Args.hasArg(Ids: options::OPT_ffixed_x19)) |
136 | Features.push_back(x: "+reserve-x19" ); |
137 | if (Args.hasArg(Ids: options::OPT_ffixed_x20)) |
138 | Features.push_back(x: "+reserve-x20" ); |
139 | if (Args.hasArg(Ids: options::OPT_ffixed_x21)) |
140 | Features.push_back(x: "+reserve-x21" ); |
141 | if (Args.hasArg(Ids: options::OPT_ffixed_x22)) |
142 | Features.push_back(x: "+reserve-x22" ); |
143 | if (Args.hasArg(Ids: options::OPT_ffixed_x23)) |
144 | Features.push_back(x: "+reserve-x23" ); |
145 | if (Args.hasArg(Ids: options::OPT_ffixed_x24)) |
146 | Features.push_back(x: "+reserve-x24" ); |
147 | if (Args.hasArg(Ids: options::OPT_ffixed_x25)) |
148 | Features.push_back(x: "+reserve-x25" ); |
149 | if (Args.hasArg(Ids: options::OPT_ffixed_x26)) |
150 | Features.push_back(x: "+reserve-x26" ); |
151 | if (Args.hasArg(Ids: options::OPT_ffixed_x27)) |
152 | Features.push_back(x: "+reserve-x27" ); |
153 | if (Args.hasArg(Ids: options::OPT_ffixed_x28)) |
154 | Features.push_back(x: "+reserve-x28" ); |
155 | if (Args.hasArg(Ids: options::OPT_ffixed_x29)) |
156 | Features.push_back(x: "+reserve-x29" ); |
157 | if (Args.hasArg(Ids: options::OPT_ffixed_x30)) |
158 | Features.push_back(x: "+reserve-x30" ); |
159 | if (Args.hasArg(Ids: options::OPT_ffixed_x31)) |
160 | Features.push_back(x: "+reserve-x31" ); |
161 | |
162 | // -mrelax is default, unless -mno-relax is specified. |
163 | if (Args.hasFlag(Pos: options::OPT_mrelax, Neg: options::OPT_mno_relax, Default: true)) { |
164 | Features.push_back(x: "+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; |
168 | if (getDebugFissionKind(D, Args, Arg&: A) != DwarfFissionKind::None) |
169 | D.Diag(DiagID: clang::diag::err_drv_riscv_unsupported_with_linker_relaxation) |
170 | << A->getAsString(Args); |
171 | } else { |
172 | Features.push_back(x: "-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 | Ids: options::OPT_mno_strict_align, Ids: options::OPT_mscalar_strict_align, |
181 | Ids: options::OPT_mstrict_align, Ids: options::OPT_mno_scalar_strict_align)) { |
182 | if (A->getOption().matches(ID: options::OPT_mno_strict_align) || |
183 | A->getOption().matches(ID: options::OPT_mno_scalar_strict_align)) { |
184 | Features.push_back(x: "+unaligned-scalar-mem" ); |
185 | } else { |
186 | Features.push_back(x: "-unaligned-scalar-mem" ); |
187 | } |
188 | } else if (CPUFastScalarUnaligned || Triple.isAndroid()) { |
189 | Features.push_back(x: "+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 | Ids: options::OPT_mno_strict_align, Ids: options::OPT_mvector_strict_align, |
198 | Ids: options::OPT_mstrict_align, Ids: options::OPT_mno_vector_strict_align)) { |
199 | if (A->getOption().matches(ID: options::OPT_mno_strict_align) || |
200 | A->getOption().matches(ID: options::OPT_mno_vector_strict_align)) { |
201 | Features.push_back(x: "+unaligned-vector-mem" ); |
202 | } else { |
203 | Features.push_back(x: "-unaligned-vector-mem" ); |
204 | } |
205 | } else if (CPUFastVectorUnaligned || Triple.isAndroid()) { |
206 | Features.push_back(x: "+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 | Group: 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(Ids: 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(Err: 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(Ids: 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(Ids: 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(Prefix: "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(x: ((F.second ? "+" : "-" ) + F.first()).str()); |
323 | auto ParseResult = llvm::RISCVISAInfo::parseFeatures( |
324 | XLen: 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(Ids: options::OPT_mabi_EQ)) { |
344 | StringRef MABI = A->getValue(); |
345 | |
346 | if (MABI.equals_insensitive(RHS: "ilp32e" )) |
347 | return "rv32e" ; |
348 | else if (MABI.equals_insensitive(RHS: "lp64e" )) |
349 | return "rv64e" ; |
350 | else if (MABI.starts_with_insensitive(Prefix: "ilp32" )) |
351 | return "rv32imafdc" ; |
352 | else if (MABI.starts_with_insensitive(Prefix: "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(Ids: 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 | } |
396 | |