Coverage Report

Created: 2024-01-17 10:31

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