Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
Line
Count
Source (jump to first uncovered line)
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/RISCVISAInfo.h"
19
#include "llvm/Support/raw_ostream.h"
20
#include "llvm/TargetParser/Host.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
0
                            const ArgList &Args) {
32
0
  bool EnableExperimentalExtensions =
33
0
      Args.hasArg(options::OPT_menable_experimental_extensions);
34
0
  auto ISAInfo =
35
0
      llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtensions);
36
0
  if (!ISAInfo) {
37
0
    handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) {
38
0
      D.Diag(diag::err_drv_invalid_riscv_arch_name)
39
0
          << Arch << ErrMsg.getMessage();
40
0
    });
41
42
0
    return false;
43
0
  }
44
45
0
  for (const std::string &Str : (*ISAInfo)->toFeatures(/*AddAllExtension=*/true,
46
0
                                                       /*IgnoreUnknown=*/false))
47
0
    Features.push_back(Args.MakeArgString(Str));
48
49
0
  if (EnableExperimentalExtensions)
50
0
    Features.push_back(Args.MakeArgString("+experimental"));
51
52
0
  return true;
53
0
}
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
0
                                    std::vector<StringRef> &Features) {
60
0
  bool Is64Bit = Triple.isRISCV64();
61
0
  if (!llvm::RISCV::parseCPU(Mcpu, Is64Bit)) {
62
    // Try inverting Is64Bit in case the CPU is valid, but for the wrong target.
63
0
    if (llvm::RISCV::parseCPU(Mcpu, !Is64Bit))
64
0
      D.Diag(clang::diag::err_drv_invalid_riscv_cpu_name_for_target)
65
0
          << Mcpu << Is64Bit;
66
0
    else
67
0
      D.Diag(clang::diag::err_drv_unsupported_option_argument)
68
0
          << A->getSpelling() << Mcpu;
69
0
  }
70
71
0
  if (llvm::RISCV::hasFastUnalignedAccess(Mcpu))
72
0
    Features.push_back("+fast-unaligned-access");
73
0
}
74
75
void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
76
                                   const ArgList &Args,
77
0
                                   std::vector<StringRef> &Features) {
78
0
  StringRef MArch = getRISCVArch(Args, Triple);
79
80
0
  if (!getArchFeatures(D, MArch, Features, Args))
81
0
    return;
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
0
  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
86
0
    StringRef CPU = A->getValue();
87
0
    if (CPU == "native")
88
0
      CPU = llvm::sys::getHostCPUName();
89
90
0
    getRISCFeaturesFromMcpu(D, A, Triple, CPU, Features);
91
0
  }
92
93
  // Handle features corresponding to "-ffixed-X" options
94
0
  if (Args.hasArg(options::OPT_ffixed_x1))
95
0
    Features.push_back("+reserve-x1");
96
0
  if (Args.hasArg(options::OPT_ffixed_x2))
97
0
    Features.push_back("+reserve-x2");
98
0
  if (Args.hasArg(options::OPT_ffixed_x3))
99
0
    Features.push_back("+reserve-x3");
100
0
  if (Args.hasArg(options::OPT_ffixed_x4))
101
0
    Features.push_back("+reserve-x4");
102
0
  if (Args.hasArg(options::OPT_ffixed_x5))
103
0
    Features.push_back("+reserve-x5");
104
0
  if (Args.hasArg(options::OPT_ffixed_x6))
105
0
    Features.push_back("+reserve-x6");
106
0
  if (Args.hasArg(options::OPT_ffixed_x7))
107
0
    Features.push_back("+reserve-x7");
108
0
  if (Args.hasArg(options::OPT_ffixed_x8))
109
0
    Features.push_back("+reserve-x8");
110
0
  if (Args.hasArg(options::OPT_ffixed_x9))
111
0
    Features.push_back("+reserve-x9");
112
0
  if (Args.hasArg(options::OPT_ffixed_x10))
113
0
    Features.push_back("+reserve-x10");
114
0
  if (Args.hasArg(options::OPT_ffixed_x11))
115
0
    Features.push_back("+reserve-x11");
116
0
  if (Args.hasArg(options::OPT_ffixed_x12))
117
0
    Features.push_back("+reserve-x12");
118
0
  if (Args.hasArg(options::OPT_ffixed_x13))
119
0
    Features.push_back("+reserve-x13");
120
0
  if (Args.hasArg(options::OPT_ffixed_x14))
121
0
    Features.push_back("+reserve-x14");
122
0
  if (Args.hasArg(options::OPT_ffixed_x15))
123
0
    Features.push_back("+reserve-x15");
124
0
  if (Args.hasArg(options::OPT_ffixed_x16))
125
0
    Features.push_back("+reserve-x16");
126
0
  if (Args.hasArg(options::OPT_ffixed_x17))
127
0
    Features.push_back("+reserve-x17");
128
0
  if (Args.hasArg(options::OPT_ffixed_x18))
129
0
    Features.push_back("+reserve-x18");
130
0
  if (Args.hasArg(options::OPT_ffixed_x19))
131
0
    Features.push_back("+reserve-x19");
132
0
  if (Args.hasArg(options::OPT_ffixed_x20))
133
0
    Features.push_back("+reserve-x20");
134
0
  if (Args.hasArg(options::OPT_ffixed_x21))
135
0
    Features.push_back("+reserve-x21");
136
0
  if (Args.hasArg(options::OPT_ffixed_x22))
137
0
    Features.push_back("+reserve-x22");
138
0
  if (Args.hasArg(options::OPT_ffixed_x23))
139
0
    Features.push_back("+reserve-x23");
140
0
  if (Args.hasArg(options::OPT_ffixed_x24))
141
0
    Features.push_back("+reserve-x24");
142
0
  if (Args.hasArg(options::OPT_ffixed_x25))
143
0
    Features.push_back("+reserve-x25");
144
0
  if (Args.hasArg(options::OPT_ffixed_x26))
145
0
    Features.push_back("+reserve-x26");
146
0
  if (Args.hasArg(options::OPT_ffixed_x27))
147
0
    Features.push_back("+reserve-x27");
148
0
  if (Args.hasArg(options::OPT_ffixed_x28))
149
0
    Features.push_back("+reserve-x28");
150
0
  if (Args.hasArg(options::OPT_ffixed_x29))
151
0
    Features.push_back("+reserve-x29");
152
0
  if (Args.hasArg(options::OPT_ffixed_x30))
153
0
    Features.push_back("+reserve-x30");
154
0
  if (Args.hasArg(options::OPT_ffixed_x31))
155
0
    Features.push_back("+reserve-x31");
156
157
  // -mrelax is default, unless -mno-relax is specified.
158
0
  if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) {
159
0
    Features.push_back("+relax");
160
    // -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing
161
    // into .debug_addr, which is currently not implemented.
162
0
    Arg *A;
163
0
    if (getDebugFissionKind(D, Args, A) != DwarfFissionKind::None)
164
0
      D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation)
165
0
          << A->getAsString(Args);
166
0
  } else {
167
0
    Features.push_back("-relax");
168
0
  }
169
170
  // -mno-unaligned-access is default, unless -munaligned-access is specified.
171
0
  AddTargetFeature(Args, Features, options::OPT_munaligned_access,
172
0
                   options::OPT_mno_unaligned_access, "fast-unaligned-access");
173
174
  // Now add any that the user explicitly requested on the command line,
175
  // which may override the defaults.
176
0
  handleTargetFeaturesGroup(D, Triple, Args, Features,
177
0
                            options::OPT_m_riscv_Features_Group);
178
0
}
179
180
0
StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
181
0
  assert(Triple.isRISCV() && "Unexpected triple");
182
183
  // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
184
  // configured using `--with-abi=`, then the logic for the default choice is
185
  // defined in config.gcc. This function is based on the logic in GCC 9.2.0.
186
  //
187
  // The logic used in GCC 9.2.0 is the following, in order:
188
  // 1. Explicit choices using `--with-abi=`
189
  // 2. A default based on `--with-arch=`, if provided
190
  // 3. A default based on the target triple's arch
191
  //
192
  // The logic in config.gcc is a little circular but it is not inconsistent.
193
  //
194
  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
195
  // and `-mabi=` respectively instead.
196
  //
197
  // In order to make chosing logic more clear, Clang uses the following logic,
198
  // in order:
199
  // 1. Explicit choices using `-mabi=`
200
  // 2. A default based on the architecture as determined by getRISCVArch
201
  // 3. Choose a default based on the triple
202
203
  // 1. If `-mabi=` is specified, use it.
204
0
  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
205
0
    return A->getValue();
206
207
  // 2. Choose a default based on the target architecture.
208
  //
209
  // rv32g | rv32*d -> ilp32d
210
  // rv32e -> ilp32e
211
  // rv32* -> ilp32
212
  // rv64g | rv64*d -> lp64d
213
  // rv64e -> lp64e
214
  // rv64* -> lp64
215
0
  StringRef Arch = getRISCVArch(Args, Triple);
216
217
0
  auto ParseResult = llvm::RISCVISAInfo::parseArchString(
218
0
      Arch, /* EnableExperimentalExtension */ true);
219
  // Ignore parsing error, just go 3rd step.
220
0
  if (!llvm::errorToBool(ParseResult.takeError()))
221
0
    return (*ParseResult)->computeDefaultABI();
222
223
  // 3. Choose a default based on the triple
224
  //
225
  // We deviate from GCC's defaults here:
226
  // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
227
  // - On all other OSs we use the double floating point calling convention.
228
0
  if (Triple.isRISCV32()) {
229
0
    if (Triple.getOS() == llvm::Triple::UnknownOS)
230
0
      return "ilp32";
231
0
    else
232
0
      return "ilp32d";
233
0
  } else {
234
0
    if (Triple.getOS() == llvm::Triple::UnknownOS)
235
0
      return "lp64";
236
0
    else
237
0
      return "lp64d";
238
0
  }
239
0
}
240
241
StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
242
0
                              const llvm::Triple &Triple) {
243
0
  assert(Triple.isRISCV() && "Unexpected triple");
244
245
  // GCC's logic around choosing a default `-march=` is complex. If GCC is not
246
  // configured using `--with-arch=`, then the logic for the default choice is
247
  // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We
248
  // deviate from GCC's default on additional `-mcpu` option (GCC does not
249
  // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`
250
  // nor `-mabi` is specified.
251
  //
252
  // The logic used in GCC 9.2.0 is the following, in order:
253
  // 1. Explicit choices using `--with-arch=`
254
  // 2. A default based on `--with-abi=`, if provided
255
  // 3. A default based on the target triple's arch
256
  //
257
  // The logic in config.gcc is a little circular but it is not inconsistent.
258
  //
259
  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`
260
  // and `-mabi=` respectively instead.
261
  //
262
  // Clang uses the following logic, in order:
263
  // 1. Explicit choices using `-march=`
264
  // 2. Based on `-mcpu` if the target CPU has a default ISA string
265
  // 3. A default based on `-mabi`, if provided
266
  // 4. A default based on the target triple's arch
267
  //
268
  // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`
269
  // instead of `rv{XLEN}gc` though they are (currently) equivalent.
270
271
  // 1. If `-march=` is specified, use it.
272
0
  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
273
0
    return A->getValue();
274
275
  // 2. Get march (isa string) based on `-mcpu=`
276
0
  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
277
0
    StringRef CPU = A->getValue();
278
0
    if (CPU == "native")
279
0
      CPU = llvm::sys::getHostCPUName();
280
0
    StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
281
    // Bypass if target cpu's default march is empty.
282
0
    if (MArch != "")
283
0
      return MArch;
284
0
  }
285
286
  // 3. Choose a default based on `-mabi=`
287
  //
288
  // ilp32e -> rv32e
289
  // lp64e -> rv64e
290
  // ilp32 | ilp32f | ilp32d -> rv32imafdc
291
  // lp64 | lp64f | lp64d -> rv64imafdc
292
0
  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
293
0
    StringRef MABI = A->getValue();
294
295
0
    if (MABI.equals_insensitive("ilp32e"))
296
0
      return "rv32e";
297
0
    else if (MABI.equals_insensitive("lp64e"))
298
0
      return "rv64e";
299
0
    else if (MABI.starts_with_insensitive("ilp32"))
300
0
      return "rv32imafdc";
301
0
    else if (MABI.starts_with_insensitive("lp64")) {
302
0
      if (Triple.isAndroid())
303
0
        return "rv64imafdcv_zba_zbb_zbs";
304
305
0
      return "rv64imafdc";
306
0
    }
307
0
  }
308
309
  // 4. Choose a default based on the triple
310
  //
311
  // We deviate from GCC's defaults here:
312
  // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
313
  // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
314
0
  if (Triple.isRISCV32()) {
315
0
    if (Triple.getOS() == llvm::Triple::UnknownOS)
316
0
      return "rv32imac";
317
0
    else
318
0
      return "rv32imafdc";
319
0
  } else {
320
0
    if (Triple.getOS() == llvm::Triple::UnknownOS)
321
0
      return "rv64imac";
322
0
    else if (Triple.isAndroid())
323
0
      return "rv64imafdcv_zba_zbb_zbs";
324
0
    else
325
0
      return "rv64imafdc";
326
0
  }
327
0
}
328
329
std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,
330
0
                                     const llvm::Triple &Triple) {
331
0
  std::string CPU;
332
  // If we have -mcpu, use that.
333
0
  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
334
0
    CPU = A->getValue();
335
336
  // Handle CPU name is 'native'.
337
0
  if (CPU == "native")
338
0
    CPU = llvm::sys::getHostCPUName();
339
340
0
  if (!CPU.empty())
341
0
    return CPU;
342
343
0
  return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";
344
0
}