106c3fb27SDimitry Andric //===--- RISCV.cpp - RISC-V Helpers for Tools -------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "RISCV.h"
10fcaf7f86SDimitry Andric #include "../Clang.h"
11349cc55cSDimitry Andric #include "ToolChains/CommonArgs.h"
120b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h"
130b57cec5SDimitry Andric #include "clang/Driver/Driver.h"
140b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
150b57cec5SDimitry Andric #include "clang/Driver/Options.h"
16349cc55cSDimitry Andric #include "llvm/Option/ArgList.h"
17349cc55cSDimitry Andric #include "llvm/Support/Error.h"
180b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
1906c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
20*0fca6ea1SDimitry Andric #include "llvm/TargetParser/RISCVISAInfo.h"
21bdd1243dSDimitry Andric #include "llvm/TargetParser/RISCVTargetParser.h"
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric using namespace clang::driver;
240b57cec5SDimitry Andric using namespace clang::driver::tools;
250b57cec5SDimitry Andric using namespace clang;
260b57cec5SDimitry Andric using namespace llvm::opt;
270b57cec5SDimitry Andric
28a7dea167SDimitry Andric // Returns false if an error is diagnosed.
getArchFeatures(const Driver & D,StringRef Arch,std::vector<StringRef> & Features,const ArgList & Args)29349cc55cSDimitry Andric static bool getArchFeatures(const Driver &D, StringRef Arch,
30a7dea167SDimitry Andric std::vector<StringRef> &Features,
31a7dea167SDimitry Andric const ArgList &Args) {
32349cc55cSDimitry Andric bool EnableExperimentalExtensions =
33349cc55cSDimitry Andric Args.hasArg(options::OPT_menable_experimental_extensions);
34349cc55cSDimitry Andric auto ISAInfo =
35349cc55cSDimitry Andric llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtensions);
36349cc55cSDimitry Andric if (!ISAInfo) {
37349cc55cSDimitry Andric handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) {
380b57cec5SDimitry Andric D.Diag(diag::err_drv_invalid_riscv_arch_name)
39349cc55cSDimitry Andric << Arch << ErrMsg.getMessage();
40349cc55cSDimitry Andric });
41349cc55cSDimitry Andric
42a7dea167SDimitry Andric return false;
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric
451db9f3b2SDimitry Andric for (const std::string &Str : (*ISAInfo)->toFeatures(/*AddAllExtension=*/true,
461db9f3b2SDimitry Andric /*IgnoreUnknown=*/false))
471db9f3b2SDimitry Andric Features.push_back(Args.MakeArgString(Str));
48cb14a3feSDimitry Andric
49cb14a3feSDimitry Andric if (EnableExperimentalExtensions)
50cb14a3feSDimitry Andric Features.push_back(Args.MakeArgString("+experimental"));
51cb14a3feSDimitry Andric
52a7dea167SDimitry Andric return true;
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric
55590d96feSDimitry Andric // Get features except standard extension feature
getRISCFeaturesFromMcpu(const Driver & D,const Arg * A,const llvm::Triple & Triple,StringRef Mcpu,std::vector<StringRef> & Features)5606c3fb27SDimitry Andric static void getRISCFeaturesFromMcpu(const Driver &D, const Arg *A,
5706c3fb27SDimitry Andric const llvm::Triple &Triple,
5806c3fb27SDimitry Andric StringRef Mcpu,
59590d96feSDimitry Andric std::vector<StringRef> &Features) {
60bdd1243dSDimitry Andric bool Is64Bit = Triple.isRISCV64();
6106c3fb27SDimitry Andric if (!llvm::RISCV::parseCPU(Mcpu, Is64Bit)) {
6206c3fb27SDimitry Andric // Try inverting Is64Bit in case the CPU is valid, but for the wrong target.
6306c3fb27SDimitry Andric if (llvm::RISCV::parseCPU(Mcpu, !Is64Bit))
6406c3fb27SDimitry Andric D.Diag(clang::diag::err_drv_invalid_riscv_cpu_name_for_target)
6506c3fb27SDimitry Andric << Mcpu << Is64Bit;
6606c3fb27SDimitry Andric else
6706c3fb27SDimitry Andric D.Diag(clang::diag::err_drv_unsupported_option_argument)
6806c3fb27SDimitry Andric << A->getSpelling() << Mcpu;
6906c3fb27SDimitry Andric }
70590d96feSDimitry Andric }
71590d96feSDimitry Andric
getRISCVTargetFeatures(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,std::vector<StringRef> & Features)72a7dea167SDimitry Andric void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
73a7dea167SDimitry Andric const ArgList &Args,
74a7dea167SDimitry Andric std::vector<StringRef> &Features) {
75*0fca6ea1SDimitry Andric std::string MArch = getRISCVArch(Args, Triple);
76a7dea167SDimitry Andric
77480093f4SDimitry Andric if (!getArchFeatures(D, MArch, Features, Args))
78a7dea167SDimitry Andric return;
79a7dea167SDimitry Andric
80*0fca6ea1SDimitry Andric bool CPUFastScalarUnaligned = false;
81*0fca6ea1SDimitry Andric bool CPUFastVectorUnaligned = false;
82*0fca6ea1SDimitry Andric
83590d96feSDimitry Andric // If users give march and mcpu, get std extension feature from MArch
84590d96feSDimitry Andric // and other features (ex. mirco architecture feature) from mcpu
85bdd1243dSDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
86bdd1243dSDimitry Andric StringRef CPU = A->getValue();
87bdd1243dSDimitry Andric if (CPU == "native")
88bdd1243dSDimitry Andric CPU = llvm::sys::getHostCPUName();
8906c3fb27SDimitry Andric
9006c3fb27SDimitry Andric getRISCFeaturesFromMcpu(D, A, Triple, CPU, Features);
91*0fca6ea1SDimitry Andric
92*0fca6ea1SDimitry Andric if (llvm::RISCV::hasFastScalarUnalignedAccess(CPU))
93*0fca6ea1SDimitry Andric CPUFastScalarUnaligned = true;
94*0fca6ea1SDimitry Andric if (llvm::RISCV::hasFastVectorUnalignedAccess(CPU))
95*0fca6ea1SDimitry Andric CPUFastVectorUnaligned = true;
96bdd1243dSDimitry Andric }
97590d96feSDimitry Andric
98480093f4SDimitry Andric // Handle features corresponding to "-ffixed-X" options
99480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x1))
100480093f4SDimitry Andric Features.push_back("+reserve-x1");
101480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x2))
102480093f4SDimitry Andric Features.push_back("+reserve-x2");
103480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x3))
104480093f4SDimitry Andric Features.push_back("+reserve-x3");
105480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x4))
106480093f4SDimitry Andric Features.push_back("+reserve-x4");
107480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x5))
108480093f4SDimitry Andric Features.push_back("+reserve-x5");
109480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x6))
110480093f4SDimitry Andric Features.push_back("+reserve-x6");
111480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x7))
112480093f4SDimitry Andric Features.push_back("+reserve-x7");
113480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x8))
114480093f4SDimitry Andric Features.push_back("+reserve-x8");
115480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x9))
116480093f4SDimitry Andric Features.push_back("+reserve-x9");
117480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x10))
118480093f4SDimitry Andric Features.push_back("+reserve-x10");
119480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x11))
120480093f4SDimitry Andric Features.push_back("+reserve-x11");
121480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x12))
122480093f4SDimitry Andric Features.push_back("+reserve-x12");
123480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x13))
124480093f4SDimitry Andric Features.push_back("+reserve-x13");
125480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x14))
126480093f4SDimitry Andric Features.push_back("+reserve-x14");
127480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x15))
128480093f4SDimitry Andric Features.push_back("+reserve-x15");
129480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x16))
130480093f4SDimitry Andric Features.push_back("+reserve-x16");
131480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x17))
132480093f4SDimitry Andric Features.push_back("+reserve-x17");
133480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x18))
134480093f4SDimitry Andric Features.push_back("+reserve-x18");
135480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x19))
136480093f4SDimitry Andric Features.push_back("+reserve-x19");
137480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x20))
138480093f4SDimitry Andric Features.push_back("+reserve-x20");
139480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x21))
140480093f4SDimitry Andric Features.push_back("+reserve-x21");
141480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x22))
142480093f4SDimitry Andric Features.push_back("+reserve-x22");
143480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x23))
144480093f4SDimitry Andric Features.push_back("+reserve-x23");
145480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x24))
146480093f4SDimitry Andric Features.push_back("+reserve-x24");
147480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x25))
148480093f4SDimitry Andric Features.push_back("+reserve-x25");
149480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x26))
150480093f4SDimitry Andric Features.push_back("+reserve-x26");
151480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x27))
152480093f4SDimitry Andric Features.push_back("+reserve-x27");
153480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x28))
154480093f4SDimitry Andric Features.push_back("+reserve-x28");
155480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x29))
156480093f4SDimitry Andric Features.push_back("+reserve-x29");
157480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x30))
158480093f4SDimitry Andric Features.push_back("+reserve-x30");
159480093f4SDimitry Andric if (Args.hasArg(options::OPT_ffixed_x31))
160480093f4SDimitry Andric Features.push_back("+reserve-x31");
161480093f4SDimitry Andric
16282343267SDimitry Andric // FreeBSD local, because ld.lld doesn't support relaxations
16382343267SDimitry Andric // -mno-relax is default, unless -mrelax is specified.
164fcaf7f86SDimitry Andric if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) {
1650b57cec5SDimitry Andric Features.push_back("+relax");
166fcaf7f86SDimitry Andric // -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing
167fcaf7f86SDimitry Andric // into .debug_addr, which is currently not implemented.
168fcaf7f86SDimitry Andric Arg *A;
169fcaf7f86SDimitry Andric if (getDebugFissionKind(D, Args, A) != DwarfFissionKind::None)
170fcaf7f86SDimitry Andric D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation)
171fcaf7f86SDimitry Andric << A->getAsString(Args);
172fcaf7f86SDimitry Andric } else {
1730b57cec5SDimitry Andric Features.push_back("-relax");
174fcaf7f86SDimitry Andric }
1750b57cec5SDimitry Andric
176*0fca6ea1SDimitry Andric // If -mstrict-align, -mno-strict-align, -mscalar-strict-align, or
177*0fca6ea1SDimitry Andric // -mno-scalar-strict-align is passed, use it. Otherwise, the
178*0fca6ea1SDimitry Andric // unaligned-scalar-mem is enabled if the CPU supports it or the target is
179*0fca6ea1SDimitry Andric // Android.
180*0fca6ea1SDimitry Andric if (const Arg *A = Args.getLastArg(
181*0fca6ea1SDimitry Andric options::OPT_mno_strict_align, options::OPT_mscalar_strict_align,
182*0fca6ea1SDimitry Andric options::OPT_mstrict_align, options::OPT_mno_scalar_strict_align)) {
183*0fca6ea1SDimitry Andric if (A->getOption().matches(options::OPT_mno_strict_align) ||
184*0fca6ea1SDimitry Andric A->getOption().matches(options::OPT_mno_scalar_strict_align)) {
185*0fca6ea1SDimitry Andric Features.push_back("+unaligned-scalar-mem");
186*0fca6ea1SDimitry Andric } else {
187*0fca6ea1SDimitry Andric Features.push_back("-unaligned-scalar-mem");
188*0fca6ea1SDimitry Andric }
189*0fca6ea1SDimitry Andric } else if (CPUFastScalarUnaligned || Triple.isAndroid()) {
190*0fca6ea1SDimitry Andric Features.push_back("+unaligned-scalar-mem");
191*0fca6ea1SDimitry Andric }
192*0fca6ea1SDimitry Andric
193*0fca6ea1SDimitry Andric // If -mstrict-align, -mno-strict-align, -mvector-strict-align, or
194*0fca6ea1SDimitry Andric // -mno-vector-strict-align is passed, use it. Otherwise, the
195*0fca6ea1SDimitry Andric // unaligned-vector-mem is enabled if the CPU supports it or the target is
196*0fca6ea1SDimitry Andric // Android.
197*0fca6ea1SDimitry Andric if (const Arg *A = Args.getLastArg(
198*0fca6ea1SDimitry Andric options::OPT_mno_strict_align, options::OPT_mvector_strict_align,
199*0fca6ea1SDimitry Andric options::OPT_mstrict_align, options::OPT_mno_vector_strict_align)) {
200*0fca6ea1SDimitry Andric if (A->getOption().matches(options::OPT_mno_strict_align) ||
201*0fca6ea1SDimitry Andric A->getOption().matches(options::OPT_mno_vector_strict_align)) {
202*0fca6ea1SDimitry Andric Features.push_back("+unaligned-vector-mem");
203*0fca6ea1SDimitry Andric } else {
204*0fca6ea1SDimitry Andric Features.push_back("-unaligned-vector-mem");
205*0fca6ea1SDimitry Andric }
206*0fca6ea1SDimitry Andric } else if (CPUFastVectorUnaligned || Triple.isAndroid()) {
207*0fca6ea1SDimitry Andric Features.push_back("+unaligned-vector-mem");
208*0fca6ea1SDimitry Andric }
2095f757f3fSDimitry Andric
2100b57cec5SDimitry Andric // Now add any that the user explicitly requested on the command line,
2110b57cec5SDimitry Andric // which may override the defaults.
21206c3fb27SDimitry Andric handleTargetFeaturesGroup(D, Triple, Args, Features,
21306c3fb27SDimitry Andric options::OPT_m_riscv_Features_Group);
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric
getRISCVABI(const ArgList & Args,const llvm::Triple & Triple)2160b57cec5SDimitry Andric StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
217bdd1243dSDimitry Andric assert(Triple.isRISCV() && "Unexpected triple");
218a7dea167SDimitry Andric
219480093f4SDimitry Andric // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
220480093f4SDimitry Andric // configured using `--with-abi=`, then the logic for the default choice is
221590d96feSDimitry Andric // defined in config.gcc. This function is based on the logic in GCC 9.2.0.
222480093f4SDimitry Andric //
223590d96feSDimitry Andric // The logic used in GCC 9.2.0 is the following, in order:
224480093f4SDimitry Andric // 1. Explicit choices using `--with-abi=`
225480093f4SDimitry Andric // 2. A default based on `--with-arch=`, if provided
226480093f4SDimitry Andric // 3. A default based on the target triple's arch
227480093f4SDimitry Andric //
228480093f4SDimitry Andric // The logic in config.gcc is a little circular but it is not inconsistent.
229480093f4SDimitry Andric //
230480093f4SDimitry Andric // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
231480093f4SDimitry Andric // and `-mabi=` respectively instead.
232590d96feSDimitry Andric //
233590d96feSDimitry Andric // In order to make chosing logic more clear, Clang uses the following logic,
234590d96feSDimitry Andric // in order:
235590d96feSDimitry Andric // 1. Explicit choices using `-mabi=`
236590d96feSDimitry Andric // 2. A default based on the architecture as determined by getRISCVArch
237590d96feSDimitry Andric // 3. Choose a default based on the triple
238480093f4SDimitry Andric
239480093f4SDimitry Andric // 1. If `-mabi=` is specified, use it.
240a7dea167SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
2410b57cec5SDimitry Andric return A->getValue();
2420b57cec5SDimitry Andric
243590d96feSDimitry Andric // 2. Choose a default based on the target architecture.
244480093f4SDimitry Andric //
245480093f4SDimitry Andric // rv32g | rv32*d -> ilp32d
246480093f4SDimitry Andric // rv32e -> ilp32e
247480093f4SDimitry Andric // rv32* -> ilp32
248480093f4SDimitry Andric // rv64g | rv64*d -> lp64d
2497a6dacacSDimitry Andric // rv64e -> lp64e
250480093f4SDimitry Andric // rv64* -> lp64
251*0fca6ea1SDimitry Andric std::string Arch = getRISCVArch(Args, Triple);
252480093f4SDimitry Andric
253349cc55cSDimitry Andric auto ParseResult = llvm::RISCVISAInfo::parseArchString(
254349cc55cSDimitry Andric Arch, /* EnableExperimentalExtension */ true);
255349cc55cSDimitry Andric // Ignore parsing error, just go 3rd step.
256647cbc5dSDimitry Andric if (!llvm::errorToBool(ParseResult.takeError()))
25781ad6265SDimitry Andric return (*ParseResult)->computeDefaultABI();
258480093f4SDimitry Andric
259480093f4SDimitry Andric // 3. Choose a default based on the triple
260480093f4SDimitry Andric //
261480093f4SDimitry Andric // We deviate from GCC's defaults here:
262480093f4SDimitry Andric // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
263480093f4SDimitry Andric // - On all other OSs we use the double floating point calling convention.
264bdd1243dSDimitry Andric if (Triple.isRISCV32()) {
265480093f4SDimitry Andric if (Triple.getOS() == llvm::Triple::UnknownOS)
266480093f4SDimitry Andric return "ilp32";
267480093f4SDimitry Andric else
268480093f4SDimitry Andric return "ilp32d";
269480093f4SDimitry Andric } else {
270480093f4SDimitry Andric if (Triple.getOS() == llvm::Triple::UnknownOS)
271480093f4SDimitry Andric return "lp64";
272480093f4SDimitry Andric else
273480093f4SDimitry Andric return "lp64d";
274480093f4SDimitry Andric }
275480093f4SDimitry Andric }
276480093f4SDimitry Andric
getRISCVArch(const llvm::opt::ArgList & Args,const llvm::Triple & Triple)277*0fca6ea1SDimitry Andric std::string riscv::getRISCVArch(const llvm::opt::ArgList &Args,
278480093f4SDimitry Andric const llvm::Triple &Triple) {
279bdd1243dSDimitry Andric assert(Triple.isRISCV() && "Unexpected triple");
280480093f4SDimitry Andric
281480093f4SDimitry Andric // GCC's logic around choosing a default `-march=` is complex. If GCC is not
282480093f4SDimitry Andric // configured using `--with-arch=`, then the logic for the default choice is
283480093f4SDimitry Andric // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
284590d96feSDimitry Andric // deviate from GCC's default on additional `-mcpu` option (GCC does not
285590d96feSDimitry Andric // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`
286590d96feSDimitry Andric // nor `-mabi` is specified.
287480093f4SDimitry Andric //
288590d96feSDimitry Andric // The logic used in GCC 9.2.0 is the following, in order:
289480093f4SDimitry Andric // 1. Explicit choices using `--with-arch=`
290480093f4SDimitry Andric // 2. A default based on `--with-abi=`, if provided
291480093f4SDimitry Andric // 3. A default based on the target triple's arch
292480093f4SDimitry Andric //
293480093f4SDimitry Andric // The logic in config.gcc is a little circular but it is not inconsistent.
294480093f4SDimitry Andric //
295480093f4SDimitry Andric // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
296480093f4SDimitry Andric // and `-mabi=` respectively instead.
297480093f4SDimitry Andric //
298590d96feSDimitry Andric // Clang uses the following logic, in order:
299590d96feSDimitry Andric // 1. Explicit choices using `-march=`
300590d96feSDimitry Andric // 2. Based on `-mcpu` if the target CPU has a default ISA string
301590d96feSDimitry Andric // 3. A default based on `-mabi`, if provided
302590d96feSDimitry Andric // 4. A default based on the target triple's arch
303590d96feSDimitry Andric //
304480093f4SDimitry Andric // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
305480093f4SDimitry Andric // instead of `rv{XLEN}gc` though they are (currently) equivalent.
306480093f4SDimitry Andric
307480093f4SDimitry Andric // 1. If `-march=` is specified, use it.
308480093f4SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
309480093f4SDimitry Andric return A->getValue();
310480093f4SDimitry Andric
311590d96feSDimitry Andric // 2. Get march (isa string) based on `-mcpu=`
312590d96feSDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
313bdd1243dSDimitry Andric StringRef CPU = A->getValue();
314*0fca6ea1SDimitry Andric if (CPU == "native") {
315bdd1243dSDimitry Andric CPU = llvm::sys::getHostCPUName();
316*0fca6ea1SDimitry Andric // If the target cpu is unrecognized, use target features.
317*0fca6ea1SDimitry Andric if (CPU.starts_with("generic")) {
318*0fca6ea1SDimitry Andric auto FeatureMap = llvm::sys::getHostCPUFeatures();
319*0fca6ea1SDimitry Andric // hwprobe may be unavailable on older Linux versions.
320*0fca6ea1SDimitry Andric if (!FeatureMap.empty()) {
321*0fca6ea1SDimitry Andric std::vector<std::string> Features;
322*0fca6ea1SDimitry Andric for (auto &F : FeatureMap)
323*0fca6ea1SDimitry Andric Features.push_back(((F.second ? "+" : "-") + F.first()).str());
324*0fca6ea1SDimitry Andric auto ParseResult = llvm::RISCVISAInfo::parseFeatures(
325*0fca6ea1SDimitry Andric Triple.isRISCV32() ? 32 : 64, Features);
326*0fca6ea1SDimitry Andric if (ParseResult)
327*0fca6ea1SDimitry Andric return (*ParseResult)->toString();
328*0fca6ea1SDimitry Andric }
329*0fca6ea1SDimitry Andric }
330*0fca6ea1SDimitry Andric }
331*0fca6ea1SDimitry Andric
332bdd1243dSDimitry Andric StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
333590d96feSDimitry Andric // Bypass if target cpu's default march is empty.
334590d96feSDimitry Andric if (MArch != "")
335*0fca6ea1SDimitry Andric return MArch.str();
336590d96feSDimitry Andric }
337590d96feSDimitry Andric
338590d96feSDimitry Andric // 3. Choose a default based on `-mabi=`
339480093f4SDimitry Andric //
340480093f4SDimitry Andric // ilp32e -> rv32e
3417a6dacacSDimitry Andric // lp64e -> rv64e
342480093f4SDimitry Andric // ilp32 | ilp32f | ilp32d -> rv32imafdc
343480093f4SDimitry Andric // lp64 | lp64f | lp64d -> rv64imafdc
344480093f4SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
345480093f4SDimitry Andric StringRef MABI = A->getValue();
346480093f4SDimitry Andric
347fe6060f1SDimitry Andric if (MABI.equals_insensitive("ilp32e"))
348480093f4SDimitry Andric return "rv32e";
3497a6dacacSDimitry Andric else if (MABI.equals_insensitive("lp64e"))
3507a6dacacSDimitry Andric return "rv64e";
35106c3fb27SDimitry Andric else if (MABI.starts_with_insensitive("ilp32"))
352480093f4SDimitry Andric return "rv32imafdc";
35306c3fb27SDimitry Andric else if (MABI.starts_with_insensitive("lp64")) {
35406c3fb27SDimitry Andric if (Triple.isAndroid())
3555f757f3fSDimitry Andric return "rv64imafdcv_zba_zbb_zbs";
35606c3fb27SDimitry Andric
357480093f4SDimitry Andric return "rv64imafdc";
358480093f4SDimitry Andric }
35906c3fb27SDimitry Andric }
360480093f4SDimitry Andric
361590d96feSDimitry Andric // 4. Choose a default based on the triple
362480093f4SDimitry Andric //
363480093f4SDimitry Andric // We deviate from GCC's defaults here:
364480093f4SDimitry Andric // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
365480093f4SDimitry Andric // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
366bdd1243dSDimitry Andric if (Triple.isRISCV32()) {
367480093f4SDimitry Andric if (Triple.getOS() == llvm::Triple::UnknownOS)
368480093f4SDimitry Andric return "rv32imac";
369480093f4SDimitry Andric else
370480093f4SDimitry Andric return "rv32imafdc";
371480093f4SDimitry Andric } else {
372480093f4SDimitry Andric if (Triple.getOS() == llvm::Triple::UnknownOS)
373480093f4SDimitry Andric return "rv64imac";
37406c3fb27SDimitry Andric else if (Triple.isAndroid())
3755f757f3fSDimitry Andric return "rv64imafdcv_zba_zbb_zbs";
376480093f4SDimitry Andric else
377480093f4SDimitry Andric return "rv64imafdc";
378480093f4SDimitry Andric }
3790b57cec5SDimitry Andric }
380bdd1243dSDimitry Andric
getRISCVTargetCPU(const llvm::opt::ArgList & Args,const llvm::Triple & Triple)381bdd1243dSDimitry Andric std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,
382bdd1243dSDimitry Andric const llvm::Triple &Triple) {
383bdd1243dSDimitry Andric std::string CPU;
384bdd1243dSDimitry Andric // If we have -mcpu, use that.
385bdd1243dSDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
386bdd1243dSDimitry Andric CPU = A->getValue();
387bdd1243dSDimitry Andric
388bdd1243dSDimitry Andric // Handle CPU name is 'native'.
389bdd1243dSDimitry Andric if (CPU == "native")
390bdd1243dSDimitry Andric CPU = llvm::sys::getHostCPUName();
391bdd1243dSDimitry Andric
392bdd1243dSDimitry Andric if (!CPU.empty())
393bdd1243dSDimitry Andric return CPU;
394bdd1243dSDimitry Andric
395bdd1243dSDimitry Andric return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";
396bdd1243dSDimitry Andric }
397