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
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(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
56static 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
72void 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
215StringRef 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
276std::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
380std::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