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