Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp
35266 views
1
//===--- RISCV.cpp - Implement RISC-V target feature support --------------===//
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
// This file implements RISC-V TargetInfo objects.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "RISCV.h"
14
#include "clang/Basic/Diagnostic.h"
15
#include "clang/Basic/MacroBuilder.h"
16
#include "clang/Basic/TargetBuiltins.h"
17
#include "llvm/ADT/StringSwitch.h"
18
#include "llvm/Support/raw_ostream.h"
19
#include "llvm/TargetParser/RISCVTargetParser.h"
20
#include <optional>
21
22
using namespace clang;
23
using namespace clang::targets;
24
25
ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
26
// clang-format off
27
static const char *const GCCRegNames[] = {
28
// Integer registers
29
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
30
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
31
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
32
"x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
33
34
// Floating point registers
35
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
36
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
37
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
38
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
39
40
// Vector registers
41
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
42
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
43
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
44
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
45
46
// CSRs
47
"fflags", "frm", "vtype", "vl", "vxsat", "vxrm"
48
};
49
// clang-format on
50
return llvm::ArrayRef(GCCRegNames);
51
}
52
53
ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
54
static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
55
{{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"},
56
{{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"},
57
{{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"},
58
{{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"},
59
{{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"},
60
{{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"},
61
{{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"},
62
{{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"},
63
{{"ft0"}, "f0"}, {{"ft1"}, "f1"}, {{"ft2"}, "f2"}, {{"ft3"}, "f3"},
64
{{"ft4"}, "f4"}, {{"ft5"}, "f5"}, {{"ft6"}, "f6"}, {{"ft7"}, "f7"},
65
{{"fs0"}, "f8"}, {{"fs1"}, "f9"}, {{"fa0"}, "f10"}, {{"fa1"}, "f11"},
66
{{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"}, {{"fa5"}, "f15"},
67
{{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"}, {{"fs3"}, "f19"},
68
{{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"}, {{"fs7"}, "f23"},
69
{{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"},
70
{{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}};
71
return llvm::ArrayRef(GCCRegAliases);
72
}
73
74
bool RISCVTargetInfo::validateAsmConstraint(
75
const char *&Name, TargetInfo::ConstraintInfo &Info) const {
76
switch (*Name) {
77
default:
78
return false;
79
case 'I':
80
// A 12-bit signed immediate.
81
Info.setRequiresImmediate(-2048, 2047);
82
return true;
83
case 'J':
84
// Integer zero.
85
Info.setRequiresImmediate(0);
86
return true;
87
case 'K':
88
// A 5-bit unsigned immediate for CSR access instructions.
89
Info.setRequiresImmediate(0, 31);
90
return true;
91
case 'f':
92
// A floating-point register.
93
Info.setAllowsRegister();
94
return true;
95
case 'A':
96
// An address that is held in a general-purpose register.
97
Info.setAllowsMemory();
98
return true;
99
case 's':
100
case 'S': // A symbol or label reference with a constant offset
101
Info.setAllowsRegister();
102
return true;
103
case 'v':
104
// A vector register.
105
if (Name[1] == 'r' || Name[1] == 'm') {
106
Info.setAllowsRegister();
107
Name += 1;
108
return true;
109
}
110
return false;
111
}
112
}
113
114
std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
115
std::string R;
116
switch (*Constraint) {
117
case 'v':
118
R = std::string("^") + std::string(Constraint, 2);
119
Constraint += 1;
120
break;
121
default:
122
R = TargetInfo::convertConstraint(Constraint);
123
break;
124
}
125
return R;
126
}
127
128
static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
129
return MajorVersion * 1000000 + MinorVersion * 1000;
130
}
131
132
void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
133
MacroBuilder &Builder) const {
134
Builder.defineMacro("__riscv");
135
bool Is64Bit = getTriple().isRISCV64();
136
Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
137
StringRef CodeModel = getTargetOpts().CodeModel;
138
unsigned FLen = ISAInfo->getFLen();
139
unsigned MinVLen = ISAInfo->getMinVLen();
140
unsigned MaxELen = ISAInfo->getMaxELen();
141
unsigned MaxELenFp = ISAInfo->getMaxELenFp();
142
if (CodeModel == "default")
143
CodeModel = "small";
144
145
if (CodeModel == "small")
146
Builder.defineMacro("__riscv_cmodel_medlow");
147
else if (CodeModel == "medium")
148
Builder.defineMacro("__riscv_cmodel_medany");
149
150
StringRef ABIName = getABI();
151
if (ABIName == "ilp32f" || ABIName == "lp64f")
152
Builder.defineMacro("__riscv_float_abi_single");
153
else if (ABIName == "ilp32d" || ABIName == "lp64d")
154
Builder.defineMacro("__riscv_float_abi_double");
155
else
156
Builder.defineMacro("__riscv_float_abi_soft");
157
158
if (ABIName == "ilp32e" || ABIName == "lp64e")
159
Builder.defineMacro("__riscv_abi_rve");
160
161
Builder.defineMacro("__riscv_arch_test");
162
163
for (auto &Extension : ISAInfo->getExtensions()) {
164
auto ExtName = Extension.first;
165
auto ExtInfo = Extension.second;
166
167
Builder.defineMacro(Twine("__riscv_", ExtName),
168
Twine(getVersionValue(ExtInfo.Major, ExtInfo.Minor)));
169
}
170
171
if (ISAInfo->hasExtension("zmmul"))
172
Builder.defineMacro("__riscv_mul");
173
174
if (ISAInfo->hasExtension("m")) {
175
Builder.defineMacro("__riscv_div");
176
Builder.defineMacro("__riscv_muldiv");
177
}
178
179
if (ISAInfo->hasExtension("a")) {
180
Builder.defineMacro("__riscv_atomic");
181
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
182
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
183
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
184
if (Is64Bit)
185
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
186
}
187
188
if (FLen) {
189
Builder.defineMacro("__riscv_flen", Twine(FLen));
190
Builder.defineMacro("__riscv_fdiv");
191
Builder.defineMacro("__riscv_fsqrt");
192
}
193
194
if (MinVLen) {
195
Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
196
Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));
197
Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));
198
}
199
200
if (ISAInfo->hasExtension("c"))
201
Builder.defineMacro("__riscv_compressed");
202
203
if (ISAInfo->hasExtension("zve32x")) {
204
Builder.defineMacro("__riscv_vector");
205
// Currently we support the v0.12 RISC-V V intrinsics.
206
Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 12)));
207
}
208
209
auto VScale = getVScaleRange(Opts);
210
if (VScale && VScale->first && VScale->first == VScale->second)
211
Builder.defineMacro("__riscv_v_fixed_vlen",
212
Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));
213
214
if (FastScalarUnalignedAccess)
215
Builder.defineMacro("__riscv_misaligned_fast");
216
else
217
Builder.defineMacro("__riscv_misaligned_avoid");
218
219
if (ISAInfo->hasExtension("e")) {
220
if (Is64Bit)
221
Builder.defineMacro("__riscv_64e");
222
else
223
Builder.defineMacro("__riscv_32e");
224
}
225
}
226
227
static constexpr Builtin::Info BuiltinInfo[] = {
228
#define BUILTIN(ID, TYPE, ATTRS) \
229
{#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
230
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
231
{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
232
#include "clang/Basic/BuiltinsRISCVVector.def"
233
#define BUILTIN(ID, TYPE, ATTRS) \
234
{#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
235
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
236
{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
237
#include "clang/Basic/BuiltinsRISCV.inc"
238
};
239
240
ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
241
return llvm::ArrayRef(BuiltinInfo,
242
clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);
243
}
244
245
bool RISCVTargetInfo::initFeatureMap(
246
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
247
const std::vector<std::string> &FeaturesVec) const {
248
249
unsigned XLen = 32;
250
251
if (getTriple().isRISCV64()) {
252
Features["64bit"] = true;
253
XLen = 64;
254
} else {
255
Features["32bit"] = true;
256
}
257
258
// If a target attribute specified a full arch string, override all the ISA
259
// extension target features.
260
const auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride");
261
if (I != FeaturesVec.end()) {
262
std::vector<std::string> OverrideFeatures(std::next(I), FeaturesVec.end());
263
264
// Add back any non ISA extension features, e.g. +relax.
265
auto IsNonISAExtFeature = [](StringRef Feature) {
266
assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-'));
267
StringRef Ext = Feature.substr(1); // drop the +/-
268
return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext);
269
};
270
llvm::copy_if(llvm::make_range(FeaturesVec.begin(), I),
271
std::back_inserter(OverrideFeatures), IsNonISAExtFeature);
272
273
return TargetInfo::initFeatureMap(Features, Diags, CPU, OverrideFeatures);
274
}
275
276
// Otherwise, parse the features and add any implied extensions.
277
std::vector<std::string> AllFeatures = FeaturesVec;
278
auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
279
if (!ParseResult) {
280
std::string Buffer;
281
llvm::raw_string_ostream OutputErrMsg(Buffer);
282
handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
283
OutputErrMsg << ErrMsg.getMessage();
284
});
285
Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
286
return false;
287
}
288
289
// Append all features, not just new ones, so we override any negatives.
290
llvm::append_range(AllFeatures, (*ParseResult)->toFeatures());
291
return TargetInfo::initFeatureMap(Features, Diags, CPU, AllFeatures);
292
}
293
294
std::optional<std::pair<unsigned, unsigned>>
295
RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
296
// RISCV::RVVBitsPerBlock is 64.
297
unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
298
299
if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
300
// Treat Zvl*b as a lower bound on vscale.
301
VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);
302
unsigned VScaleMax = LangOpts.VScaleMax;
303
if (VScaleMax != 0 && VScaleMax < VScaleMin)
304
VScaleMax = VScaleMin;
305
return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
306
}
307
308
if (VScaleMin > 0) {
309
unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
310
return std::make_pair(VScaleMin, VScaleMax);
311
}
312
313
return std::nullopt;
314
}
315
316
/// Return true if has this feature, need to sync with handleTargetFeatures.
317
bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
318
bool Is64Bit = getTriple().isRISCV64();
319
auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
320
.Case("riscv", true)
321
.Case("riscv32", !Is64Bit)
322
.Case("riscv64", Is64Bit)
323
.Case("32bit", !Is64Bit)
324
.Case("64bit", Is64Bit)
325
.Case("experimental", HasExperimental)
326
.Default(std::nullopt);
327
if (Result)
328
return *Result;
329
330
return ISAInfo->hasExtension(Feature);
331
}
332
333
/// Perform initialization based on the user configured set of features.
334
bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
335
DiagnosticsEngine &Diags) {
336
unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
337
auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
338
if (!ParseResult) {
339
std::string Buffer;
340
llvm::raw_string_ostream OutputErrMsg(Buffer);
341
handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
342
OutputErrMsg << ErrMsg.getMessage();
343
});
344
Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
345
return false;
346
} else {
347
ISAInfo = std::move(*ParseResult);
348
}
349
350
if (ABI.empty())
351
ABI = ISAInfo->computeDefaultABI().str();
352
353
if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))
354
HasLegalHalfType = true;
355
356
FastScalarUnalignedAccess =
357
llvm::is_contained(Features, "+unaligned-scalar-mem");
358
359
if (llvm::is_contained(Features, "+experimental"))
360
HasExperimental = true;
361
362
if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) {
363
Diags.Report(diag::err_invalid_feature_combination)
364
<< "ILP32E cannot be used with the D ISA extension";
365
return false;
366
}
367
return true;
368
}
369
370
bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
371
bool Is64Bit = getTriple().isArch64Bit();
372
return llvm::RISCV::parseCPU(Name, Is64Bit);
373
}
374
375
void RISCVTargetInfo::fillValidCPUList(
376
SmallVectorImpl<StringRef> &Values) const {
377
bool Is64Bit = getTriple().isArch64Bit();
378
llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
379
}
380
381
bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
382
bool Is64Bit = getTriple().isArch64Bit();
383
return llvm::RISCV::parseTuneCPU(Name, Is64Bit);
384
}
385
386
void RISCVTargetInfo::fillValidTuneCPUList(
387
SmallVectorImpl<StringRef> &Values) const {
388
bool Is64Bit = getTriple().isArch64Bit();
389
llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
390
}
391
392
static void handleFullArchString(StringRef FullArchStr,
393
std::vector<std::string> &Features) {
394
Features.push_back("__RISCV_TargetAttrNeedOverride");
395
auto RII = llvm::RISCVISAInfo::parseArchString(
396
FullArchStr, /* EnableExperimentalExtension */ true);
397
if (llvm::errorToBool(RII.takeError())) {
398
// Forward the invalid FullArchStr.
399
Features.push_back("+" + FullArchStr.str());
400
} else {
401
// Append a full list of features, including any negative extensions so that
402
// we override the CPU's features.
403
std::vector<std::string> FeatStrings =
404
(*RII)->toFeatures(/* AddAllExtensions */ true);
405
Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());
406
}
407
}
408
409
ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
410
ParsedTargetAttr Ret;
411
if (Features == "default")
412
return Ret;
413
SmallVector<StringRef, 1> AttrFeatures;
414
Features.split(AttrFeatures, ";");
415
bool FoundArch = false;
416
417
for (auto &Feature : AttrFeatures) {
418
Feature = Feature.trim();
419
StringRef AttrString = Feature.split("=").second.trim();
420
421
if (Feature.starts_with("arch=")) {
422
// Override last features
423
Ret.Features.clear();
424
if (FoundArch)
425
Ret.Duplicate = "arch=";
426
FoundArch = true;
427
428
if (AttrString.starts_with("+")) {
429
// EXTENSION like arch=+v,+zbb
430
SmallVector<StringRef, 1> Exts;
431
AttrString.split(Exts, ",");
432
for (auto Ext : Exts) {
433
if (Ext.empty())
434
continue;
435
436
StringRef ExtName = Ext.substr(1);
437
std::string TargetFeature =
438
llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);
439
if (!TargetFeature.empty())
440
Ret.Features.push_back(Ext.front() + TargetFeature);
441
else
442
Ret.Features.push_back(Ext.str());
443
}
444
} else {
445
// full-arch-string like arch=rv64gcv
446
handleFullArchString(AttrString, Ret.Features);
447
}
448
} else if (Feature.starts_with("cpu=")) {
449
if (!Ret.CPU.empty())
450
Ret.Duplicate = "cpu=";
451
452
Ret.CPU = AttrString;
453
454
if (!FoundArch) {
455
// Update Features with CPU's features
456
StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU);
457
if (MarchFromCPU != "") {
458
Ret.Features.clear();
459
handleFullArchString(MarchFromCPU, Ret.Features);
460
}
461
}
462
} else if (Feature.starts_with("tune=")) {
463
if (!Ret.Tune.empty())
464
Ret.Duplicate = "tune=";
465
466
Ret.Tune = AttrString;
467
}
468
}
469
return Ret;
470
}
471
472
TargetInfo::CallingConvCheckResult
473
RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
474
switch (CC) {
475
default:
476
return CCCR_Warning;
477
case CC_C:
478
case CC_RISCVVectorCall:
479
return CCCR_OK;
480
}
481
}
482
483