xref: /llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp (revision 164d1230f78b32647e1a6e948245e75f557a8068)
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(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   for (const std::string &Str : (*ISAInfo)->toFeatures(/*AddAllExtension=*/true,
46                                                        /*IgnoreUnknown=*/false))
47     Features.push_back(Args.MakeArgString(Str));
48 
49   if (EnableExperimentalExtensions)
50     Features.push_back(Args.MakeArgString("+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(Mcpu, Is64Bit)) {
62     // Try inverting Is64Bit in case the CPU is valid, but for the wrong target.
63     if (llvm::RISCV::parseCPU(Mcpu, !Is64Bit))
64       D.Diag(clang::diag::err_drv_invalid_riscv_cpu_name_for_target)
65           << Mcpu << Is64Bit;
66     else
67       D.Diag(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, 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(options::OPT_mcpu_EQ)) {
86     StringRef CPU = A->getValue();
87     if (CPU == "native")
88       CPU = llvm::sys::getHostCPUName();
89 
90     getRISCFeaturesFromMcpu(D, A, Triple, 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 #define RESERVE_REG(REG)                                                       \
100   if (Args.hasArg(options::OPT_ffixed_##REG))                                  \
101     Features.push_back("+reserve-" #REG);
102   RESERVE_REG(x1)
103   RESERVE_REG(x2)
104   RESERVE_REG(x3)
105   RESERVE_REG(x4)
106   RESERVE_REG(x5)
107   RESERVE_REG(x6)
108   RESERVE_REG(x7)
109   RESERVE_REG(x8)
110   RESERVE_REG(x9)
111   RESERVE_REG(x10)
112   RESERVE_REG(x11)
113   RESERVE_REG(x12)
114   RESERVE_REG(x13)
115   RESERVE_REG(x14)
116   RESERVE_REG(x15)
117   RESERVE_REG(x16)
118   RESERVE_REG(x17)
119   RESERVE_REG(x18)
120   RESERVE_REG(x19)
121   RESERVE_REG(x20)
122   RESERVE_REG(x21)
123   RESERVE_REG(x22)
124   RESERVE_REG(x23)
125   RESERVE_REG(x24)
126   RESERVE_REG(x25)
127   RESERVE_REG(x26)
128   RESERVE_REG(x27)
129   RESERVE_REG(x28)
130   RESERVE_REG(x29)
131   RESERVE_REG(x30)
132   RESERVE_REG(x31)
133 #undef RESERVE_REG
134 
135   // -mrelax is default, unless -mno-relax is specified.
136   if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) {
137     Features.push_back("+relax");
138     // -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing
139     // into .debug_addr, which is currently not implemented.
140     Arg *A;
141     if (getDebugFissionKind(D, Args, A) != DwarfFissionKind::None)
142       D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation)
143           << A->getAsString(Args);
144   } else {
145     Features.push_back("-relax");
146   }
147 
148   // If -mstrict-align, -mno-strict-align, -mscalar-strict-align, or
149   // -mno-scalar-strict-align is passed, use it. Otherwise, the
150   // unaligned-scalar-mem is enabled if the CPU supports it or the target is
151   // Android.
152   if (const Arg *A = Args.getLastArg(
153           options::OPT_mno_strict_align, options::OPT_mscalar_strict_align,
154           options::OPT_mstrict_align, options::OPT_mno_scalar_strict_align)) {
155     if (A->getOption().matches(options::OPT_mno_strict_align) ||
156         A->getOption().matches(options::OPT_mno_scalar_strict_align)) {
157       Features.push_back("+unaligned-scalar-mem");
158     } else {
159       Features.push_back("-unaligned-scalar-mem");
160     }
161   } else if (CPUFastScalarUnaligned || Triple.isAndroid()) {
162     Features.push_back("+unaligned-scalar-mem");
163   }
164 
165   // If -mstrict-align, -mno-strict-align, -mvector-strict-align, or
166   // -mno-vector-strict-align is passed, use it. Otherwise, the
167   // unaligned-vector-mem is enabled if the CPU supports it or the target is
168   // Android.
169   if (const Arg *A = Args.getLastArg(
170           options::OPT_mno_strict_align, options::OPT_mvector_strict_align,
171           options::OPT_mstrict_align, options::OPT_mno_vector_strict_align)) {
172     if (A->getOption().matches(options::OPT_mno_strict_align) ||
173         A->getOption().matches(options::OPT_mno_vector_strict_align)) {
174       Features.push_back("+unaligned-vector-mem");
175     } else {
176       Features.push_back("-unaligned-vector-mem");
177     }
178   } else if (CPUFastVectorUnaligned || Triple.isAndroid()) {
179     Features.push_back("+unaligned-vector-mem");
180   }
181 
182   // Now add any that the user explicitly requested on the command line,
183   // which may override the defaults.
184   handleTargetFeaturesGroup(D, Triple, Args, Features,
185                             options::OPT_m_riscv_Features_Group);
186 }
187 
188 StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
189   assert(Triple.isRISCV() && "Unexpected triple");
190 
191   // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
192   // configured using `--with-abi=`, then the logic for the default choice is
193   // defined in config.gcc. This function is based on the logic in GCC 9.2.0.
194   //
195   // The logic used in GCC 9.2.0 is the following, in order:
196   // 1. Explicit choices using `--with-abi=`
197   // 2. A default based on `--with-arch=`, if provided
198   // 3. A default based on the target triple's arch
199   //
200   // The logic in config.gcc is a little circular but it is not inconsistent.
201   //
202   // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
203   // and `-mabi=` respectively instead.
204   //
205   // In order to make chosing logic more clear, Clang uses the following logic,
206   // in order:
207   // 1. Explicit choices using `-mabi=`
208   // 2. A default based on the architecture as determined by getRISCVArch
209   // 3. Choose a default based on the triple
210 
211   // 1. If `-mabi=` is specified, use it.
212   if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
213     return A->getValue();
214 
215   // 2. Choose a default based on the target architecture.
216   //
217   // rv32g | rv32*d -> ilp32d
218   // rv32e -> ilp32e
219   // rv32* -> ilp32
220   // rv64g | rv64*d -> lp64d
221   // rv64e -> lp64e
222   // rv64* -> lp64
223   std::string Arch = getRISCVArch(Args, Triple);
224 
225   auto ParseResult = llvm::RISCVISAInfo::parseArchString(
226       Arch, /* EnableExperimentalExtension */ true);
227   // Ignore parsing error, just go 3rd step.
228   if (!llvm::errorToBool(ParseResult.takeError()))
229     return (*ParseResult)->computeDefaultABI();
230 
231   // 3. Choose a default based on the triple
232   //
233   // We deviate from GCC's defaults here:
234   // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
235   // - On all other OSs we use the double floating point calling convention.
236   if (Triple.isRISCV32()) {
237     if (Triple.getOS() == llvm::Triple::UnknownOS)
238       return "ilp32";
239     else
240       return "ilp32d";
241   } else {
242     if (Triple.getOS() == llvm::Triple::UnknownOS)
243       return "lp64";
244     else
245       return "lp64d";
246   }
247 }
248 
249 std::string riscv::getRISCVArch(const llvm::opt::ArgList &Args,
250                                 const llvm::Triple &Triple) {
251   assert(Triple.isRISCV() && "Unexpected triple");
252 
253   // GCC's logic around choosing a default `-march=` is complex. If GCC is not
254   // configured using `--with-arch=`, then the logic for the default choice is
255   // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
256   // deviate from GCC's default on additional `-mcpu` option (GCC does not
257   // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`
258   // nor `-mabi` is specified.
259   //
260   // The logic used in GCC 9.2.0 is the following, in order:
261   // 1. Explicit choices using `--with-arch=`
262   // 2. A default based on `--with-abi=`, if provided
263   // 3. A default based on the target triple's arch
264   //
265   // The logic in config.gcc is a little circular but it is not inconsistent.
266   //
267   // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
268   // and `-mabi=` respectively instead.
269   //
270   // Clang uses the following logic, in order:
271   // 1. Explicit choices using `-march=`
272   // 2. Based on `-mcpu` if the target CPU has a default ISA string
273   // 3. A default based on `-mabi`, if provided
274   // 4. A default based on the target triple's arch
275   //
276   // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
277   // instead of `rv{XLEN}gc` though they are (currently) equivalent.
278 
279   // 1. If `-march=` is specified, use it.
280   if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
281     return A->getValue();
282 
283   // 2. Get march (isa string) based on `-mcpu=`
284   if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
285     StringRef CPU = A->getValue();
286     if (CPU == "native") {
287       CPU = llvm::sys::getHostCPUName();
288       // If the target cpu is unrecognized, use target features.
289       if (CPU.starts_with("generic")) {
290         auto FeatureMap = llvm::sys::getHostCPUFeatures();
291         // hwprobe may be unavailable on older Linux versions.
292         if (!FeatureMap.empty()) {
293           std::vector<std::string> Features;
294           for (auto &F : FeatureMap)
295             Features.push_back(((F.second ? "+" : "-") + F.first()).str());
296           auto ParseResult = llvm::RISCVISAInfo::parseFeatures(
297               Triple.isRISCV32() ? 32 : 64, Features);
298           if (ParseResult)
299             return (*ParseResult)->toString();
300         }
301       }
302     }
303 
304     StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
305     // Bypass if target cpu's default march is empty.
306     if (MArch != "")
307       return MArch.str();
308   }
309 
310   // 3. Choose a default based on `-mabi=`
311   //
312   // ilp32e -> rv32e
313   // lp64e -> rv64e
314   // ilp32 | ilp32f | ilp32d -> rv32imafdc
315   // lp64 | lp64f | lp64d -> rv64imafdc
316   if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
317     StringRef MABI = A->getValue();
318 
319     if (MABI.equals_insensitive("ilp32e"))
320       return "rv32e";
321     else if (MABI.equals_insensitive("lp64e"))
322       return "rv64e";
323     else if (MABI.starts_with_insensitive("ilp32"))
324       return "rv32imafdc";
325     else if (MABI.starts_with_insensitive("lp64")) {
326       if (Triple.isAndroid())
327         return "rv64imafdcv_zba_zbb_zbs";
328 
329       return "rv64imafdc";
330     }
331   }
332 
333   // 4. Choose a default based on the triple
334   //
335   // We deviate from GCC's defaults here:
336   // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
337   // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
338   if (Triple.isRISCV32()) {
339     if (Triple.getOS() == llvm::Triple::UnknownOS)
340       return "rv32imac";
341     else
342       return "rv32imafdc";
343   } else {
344     if (Triple.getOS() == llvm::Triple::UnknownOS)
345       return "rv64imac";
346     else if (Triple.isAndroid())
347       return "rv64imafdcv_zba_zbb_zbs";
348     else
349       return "rv64imafdc";
350   }
351 }
352 
353 std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,
354                                      const llvm::Triple &Triple) {
355   std::string CPU;
356   // If we have -mcpu, use that.
357   if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
358     CPU = A->getValue();
359 
360   // Handle CPU name is 'native'.
361   if (CPU == "native")
362     CPU = llvm::sys::getHostCPUName();
363 
364   if (!CPU.empty())
365     return CPU;
366 
367   return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";
368 }
369