Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- PS4CPU.cpp - PS4CPU ToolChain Implementations ----------*- 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 "PS4CPU.h"
10
#include "CommonArgs.h"
11
#include "clang/Config/config.h"
12
#include "clang/Driver/Compilation.h"
13
#include "clang/Driver/Driver.h"
14
#include "clang/Driver/DriverDiagnostic.h"
15
#include "clang/Driver/Options.h"
16
#include "clang/Driver/SanitizerArgs.h"
17
#include "llvm/Option/ArgList.h"
18
#include "llvm/Support/FileSystem.h"
19
#include "llvm/Support/Path.h"
20
#include <cstdlib> // ::getenv
21
22
using namespace clang::driver;
23
using namespace clang;
24
using namespace llvm::opt;
25
26
// Helper to paste bits of an option together and return a saved string.
27
static const char *makeArgString(const ArgList &Args, const char *Prefix,
28
0
                                 const char *Base, const char *Suffix) {
29
  // Basically "Prefix + Base + Suffix" all converted to Twine then saved.
30
0
  return Args.MakeArgString(Twine(StringRef(Prefix), Base) + Suffix);
31
0
}
32
33
void tools::PScpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
34
0
                                    ArgStringList &CmdArgs) {
35
0
  assert(TC.getTriple().isPS());
36
0
  auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC);
37
38
0
  if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
39
0
                    false) ||
40
0
       Args.hasFlag(options::OPT_fprofile_generate,
41
0
                    options::OPT_fno_profile_generate, false) ||
42
0
       Args.hasFlag(options::OPT_fprofile_generate_EQ,
43
0
                    options::OPT_fno_profile_generate, false) ||
44
0
       Args.hasFlag(options::OPT_fprofile_instr_generate,
45
0
                    options::OPT_fno_profile_instr_generate, false) ||
46
0
       Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
47
0
                    options::OPT_fno_profile_instr_generate, false) ||
48
0
       Args.hasFlag(options::OPT_fcs_profile_generate,
49
0
                    options::OPT_fno_profile_generate, false) ||
50
0
       Args.hasFlag(options::OPT_fcs_profile_generate_EQ,
51
0
                    options::OPT_fno_profile_generate, false) ||
52
0
       Args.hasArg(options::OPT_fcreate_profile) ||
53
0
       Args.hasArg(options::OPT_coverage)))
54
0
    CmdArgs.push_back(makeArgString(
55
0
        Args, "--dependent-lib=", PSTC.getProfileRTLibName(), ""));
56
0
}
57
58
void tools::PScpu::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
59
                                           const InputInfo &Output,
60
                                           const InputInfoList &Inputs,
61
                                           const ArgList &Args,
62
0
                                           const char *LinkingOutput) const {
63
0
  auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
64
0
  claimNoWarnArgs(Args);
65
0
  ArgStringList CmdArgs;
66
67
0
  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
68
69
0
  CmdArgs.push_back("-o");
70
0
  CmdArgs.push_back(Output.getFilename());
71
72
0
  assert(Inputs.size() == 1 && "Unexpected number of inputs.");
73
0
  const InputInfo &Input = Inputs[0];
74
0
  assert(Input.isFilename() && "Invalid input.");
75
0
  CmdArgs.push_back(Input.getFilename());
76
77
0
  std::string AsName = TC.qualifyPSCmdName("as");
78
0
  const char *Exec = Args.MakeArgString(TC.GetProgramPath(AsName.c_str()));
79
0
  C.addCommand(std::make_unique<Command>(JA, *this,
80
0
                                         ResponseFileSupport::AtFileUTF8(),
81
0
                                         Exec, CmdArgs, Inputs, Output));
82
0
}
83
84
void tools::PScpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args,
85
0
                                    ArgStringList &CmdArgs) {
86
0
  assert(TC.getTriple().isPS());
87
0
  auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC);
88
0
  PSTC.addSanitizerArgs(Args, CmdArgs, "--dependent-lib=lib", ".a");
89
0
}
90
91
void toolchains::PS4CPU::addSanitizerArgs(const ArgList &Args,
92
                                          ArgStringList &CmdArgs,
93
                                          const char *Prefix,
94
0
                                          const char *Suffix) const {
95
0
  auto arg = [&](const char *Name) -> const char * {
96
0
    return makeArgString(Args, Prefix, Name, Suffix);
97
0
  };
98
0
  const SanitizerArgs &SanArgs = getSanitizerArgs(Args);
99
0
  if (SanArgs.needsUbsanRt())
100
0
    CmdArgs.push_back(arg("SceDbgUBSanitizer_stub_weak"));
101
0
  if (SanArgs.needsAsanRt())
102
0
    CmdArgs.push_back(arg("SceDbgAddressSanitizer_stub_weak"));
103
0
}
104
105
void toolchains::PS5CPU::addSanitizerArgs(const ArgList &Args,
106
                                          ArgStringList &CmdArgs,
107
                                          const char *Prefix,
108
0
                                          const char *Suffix) const {
109
0
  auto arg = [&](const char *Name) -> const char * {
110
0
    return makeArgString(Args, Prefix, Name, Suffix);
111
0
  };
112
0
  const SanitizerArgs &SanArgs = getSanitizerArgs(Args);
113
0
  if (SanArgs.needsUbsanRt())
114
0
    CmdArgs.push_back(arg("SceUBSanitizer_nosubmission_stub_weak"));
115
0
  if (SanArgs.needsAsanRt())
116
0
    CmdArgs.push_back(arg("SceAddressSanitizer_nosubmission_stub_weak"));
117
0
  if (SanArgs.needsTsanRt())
118
0
    CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_stub_weak"));
119
0
}
120
121
void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
122
                                        const InputInfo &Output,
123
                                        const InputInfoList &Inputs,
124
                                        const ArgList &Args,
125
0
                                        const char *LinkingOutput) const {
126
0
  auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
127
0
  const Driver &D = TC.getDriver();
128
0
  ArgStringList CmdArgs;
129
130
  // Silence warning for "clang -g foo.o -o foo"
131
0
  Args.ClaimAllArgs(options::OPT_g_Group);
132
  // and "clang -emit-llvm foo.o -o foo"
133
0
  Args.ClaimAllArgs(options::OPT_emit_llvm);
134
  // and for "clang -w foo.o -o foo". Other warning options are already
135
  // handled somewhere else.
136
0
  Args.ClaimAllArgs(options::OPT_w);
137
138
0
  if (!D.SysRoot.empty())
139
0
    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
140
141
0
  if (Args.hasArg(options::OPT_pie))
142
0
    CmdArgs.push_back("-pie");
143
144
0
  if (Args.hasArg(options::OPT_rdynamic))
145
0
    CmdArgs.push_back("-export-dynamic");
146
0
  if (Args.hasArg(options::OPT_shared))
147
0
    CmdArgs.push_back("--shared");
148
149
0
  assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
150
0
  if (Output.isFilename()) {
151
0
    CmdArgs.push_back("-o");
152
0
    CmdArgs.push_back(Output.getFilename());
153
0
  }
154
155
0
  const bool UseLTO = D.isUsingLTO();
156
0
  const bool UseJMC =
157
0
      Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
158
0
  const bool IsPS4 = TC.getTriple().isPS4();
159
160
0
  const char *PS4LTOArgs = "";
161
0
  auto AddCodeGenFlag = [&](Twine Flag) {
162
0
    if (IsPS4)
163
0
      PS4LTOArgs = Args.MakeArgString(Twine(PS4LTOArgs) + " " + Flag);
164
0
    else
165
0
      CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag));
166
0
  };
167
168
0
  if (UseLTO) {
169
    // We default to creating the arange section, but LTO does not. Enable it
170
    // here.
171
0
    AddCodeGenFlag("-generate-arange-section");
172
173
    // This tells LTO to perform JustMyCode instrumentation.
174
0
    if (UseJMC)
175
0
      AddCodeGenFlag("-enable-jmc-instrument");
176
177
0
    if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
178
0
      AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
179
180
0
    StringRef Parallelism = getLTOParallelism(Args, D);
181
0
    if (!Parallelism.empty()) {
182
0
      if (IsPS4)
183
0
        AddCodeGenFlag(Twine("-threads=") + Parallelism);
184
0
      else
185
0
        CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism));
186
0
    }
187
188
0
    if (IsPS4) {
189
0
      const char *Prefix = nullptr;
190
0
      if (D.getLTOMode() == LTOK_Thin)
191
0
        Prefix = "-lto-thin-debug-options=";
192
0
      else if (D.getLTOMode() == LTOK_Full)
193
0
        Prefix = "-lto-debug-options=";
194
0
      else
195
0
        llvm_unreachable("new LTO mode?");
196
197
0
      CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + PS4LTOArgs));
198
0
    }
199
0
  }
200
201
0
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
202
0
    TC.addSanitizerArgs(Args, CmdArgs, "-l", "");
203
204
0
  if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) {
205
0
    if (D.getLTOMode() == LTOK_Thin)
206
0
      CmdArgs.push_back("--lto=thin");
207
0
    else if (D.getLTOMode() == LTOK_Full)
208
0
      CmdArgs.push_back("--lto=full");
209
0
  }
210
211
0
  Args.addAllArgs(CmdArgs,
212
0
                  {options::OPT_L, options::OPT_T_Group, options::OPT_s,
213
0
                   options::OPT_t, options::OPT_r});
214
215
0
  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
216
0
    CmdArgs.push_back("--no-demangle");
217
218
0
  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
219
220
0
  if (Args.hasArg(options::OPT_pthread)) {
221
0
    CmdArgs.push_back("-lpthread");
222
0
  }
223
224
0
  if (UseJMC) {
225
0
    CmdArgs.push_back("--whole-archive");
226
0
    if (IsPS4)
227
0
      CmdArgs.push_back("-lSceDbgJmc");
228
0
    else
229
0
      CmdArgs.push_back("-lSceJmc_nosubmission");
230
0
    CmdArgs.push_back("--no-whole-archive");
231
0
  }
232
233
0
  if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
234
0
    D.Diag(diag::err_drv_unsupported_opt_for_target)
235
0
        << "-fuse-ld" << TC.getTriple().str();
236
0
  }
237
238
0
  std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName());
239
0
  const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str()));
240
241
0
  C.addCommand(std::make_unique<Command>(JA, *this,
242
0
                                         ResponseFileSupport::AtFileUTF8(),
243
0
                                         Exec, CmdArgs, Inputs, Output));
244
0
}
245
246
toolchains::PS4PS5Base::PS4PS5Base(const Driver &D, const llvm::Triple &Triple,
247
                                   const ArgList &Args, StringRef Platform,
248
                                   const char *EnvVar)
249
0
    : Generic_ELF(D, Triple, Args) {
250
0
  if (Args.hasArg(clang::driver::options::OPT_static))
251
0
    D.Diag(clang::diag::err_drv_unsupported_opt_for_target)
252
0
        << "-static" << Platform;
253
254
  // Determine where to find the PS4/PS5 libraries.
255
  // If -isysroot was passed, use that as the SDK base path.
256
  // If not, we use the EnvVar if it exists; otherwise use the driver's
257
  // installation path, which should be <SDK_DIR>/host_tools/bin.
258
0
  SmallString<80> Whence;
259
0
  if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
260
0
    SDKRootDir = A->getValue();
261
0
    if (!llvm::sys::fs::exists(SDKRootDir))
262
0
      D.Diag(clang::diag::warn_missing_sysroot) << SDKRootDir;
263
0
    Whence = A->getSpelling();
264
0
  } else if (const char *EnvValue = getenv(EnvVar)) {
265
0
    SDKRootDir = EnvValue;
266
0
    Whence = { "environment variable '", EnvVar, "'" };
267
0
  } else {
268
0
    SDKRootDir = D.Dir + "/../../";
269
0
    Whence = "compiler's location";
270
0
  }
271
272
0
  SmallString<512> SDKIncludeDir(SDKRootDir);
273
0
  llvm::sys::path::append(SDKIncludeDir, "target/include");
274
0
  if (!Args.hasArg(options::OPT_nostdinc) &&
275
0
      !Args.hasArg(options::OPT_nostdlibinc) &&
276
0
      !Args.hasArg(options::OPT_isysroot) &&
277
0
      !Args.hasArg(options::OPT__sysroot_EQ) &&
278
0
      !llvm::sys::fs::exists(SDKIncludeDir)) {
279
0
    D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
280
0
        << Twine(Platform, " system headers").str() << SDKIncludeDir << Whence;
281
0
  }
282
283
0
  SmallString<512> SDKLibDir(SDKRootDir);
284
0
  llvm::sys::path::append(SDKLibDir, "target/lib");
285
0
  if (!Args.hasArg(options::OPT_nostdlib) &&
286
0
      !Args.hasArg(options::OPT_nodefaultlibs) &&
287
0
      !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) &&
288
0
      !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) &&
289
0
      !Args.hasArg(options::OPT_emit_ast) &&
290
0
      !llvm::sys::fs::exists(SDKLibDir)) {
291
0
    D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
292
0
        << Twine(Platform, " system libraries").str() << SDKLibDir << Whence;
293
0
    return;
294
0
  }
295
0
  getFilePaths().push_back(std::string(SDKLibDir.str()));
296
0
}
297
298
void toolchains::PS4PS5Base::AddClangSystemIncludeArgs(
299
    const ArgList &DriverArgs,
300
0
    ArgStringList &CC1Args) const {
301
0
  const Driver &D = getDriver();
302
303
0
  if (DriverArgs.hasArg(options::OPT_nostdinc))
304
0
    return;
305
306
0
  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
307
0
    SmallString<128> Dir(D.ResourceDir);
308
0
    llvm::sys::path::append(Dir, "include");
309
0
    addSystemInclude(DriverArgs, CC1Args, Dir.str());
310
0
  }
311
312
0
  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
313
0
    return;
314
315
0
  addExternCSystemInclude(DriverArgs, CC1Args,
316
0
                          SDKRootDir + "/target/include");
317
0
  addExternCSystemInclude(DriverArgs, CC1Args,
318
0
                          SDKRootDir + "/target/include_common");
319
0
}
320
321
0
Tool *toolchains::PS4CPU::buildAssembler() const {
322
0
  return new tools::PScpu::Assembler(*this);
323
0
}
324
325
0
Tool *toolchains::PS5CPU::buildAssembler() const {
326
  // PS5 does not support an external assembler.
327
0
  getDriver().Diag(clang::diag::err_no_external_assembler);
328
0
  return nullptr;
329
0
}
330
331
0
Tool *toolchains::PS4PS5Base::buildLinker() const {
332
0
  return new tools::PScpu::Linker(*this);
333
0
}
334
335
0
SanitizerMask toolchains::PS4PS5Base::getSupportedSanitizers() const {
336
0
  SanitizerMask Res = ToolChain::getSupportedSanitizers();
337
0
  Res |= SanitizerKind::Address;
338
0
  Res |= SanitizerKind::PointerCompare;
339
0
  Res |= SanitizerKind::PointerSubtract;
340
0
  Res |= SanitizerKind::Vptr;
341
0
  return Res;
342
0
}
343
344
0
SanitizerMask toolchains::PS5CPU::getSupportedSanitizers() const {
345
0
  SanitizerMask Res = PS4PS5Base::getSupportedSanitizers();
346
0
  Res |= SanitizerKind::Thread;
347
0
  return Res;
348
0
}
349
350
void toolchains::PS4PS5Base::addClangTargetOptions(
351
    const ArgList &DriverArgs, ArgStringList &CC1Args,
352
0
    Action::OffloadKind DeviceOffloadingKind) const {
353
  // PS4/PS5 do not use init arrays.
354
0
  if (DriverArgs.hasArg(options::OPT_fuse_init_array)) {
355
0
    Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array);
356
0
    getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target)
357
0
        << A->getAsString(DriverArgs) << getTriple().str();
358
0
  }
359
360
0
  CC1Args.push_back("-fno-use-init-array");
361
362
0
  const Arg *A =
363
0
      DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
364
0
                            options::OPT_fno_visibility_from_dllstorageclass);
365
0
  if (!A ||
366
0
      A->getOption().matches(options::OPT_fvisibility_from_dllstorageclass)) {
367
0
    CC1Args.push_back("-fvisibility-from-dllstorageclass");
368
369
0
    if (DriverArgs.hasArg(options::OPT_fvisibility_dllexport_EQ))
370
0
      DriverArgs.AddLastArg(CC1Args, options::OPT_fvisibility_dllexport_EQ);
371
0
    else
372
0
      CC1Args.push_back("-fvisibility-dllexport=protected");
373
374
0
    if (DriverArgs.hasArg(options::OPT_fvisibility_nodllstorageclass_EQ))
375
0
      DriverArgs.AddLastArg(CC1Args,
376
0
                            options::OPT_fvisibility_nodllstorageclass_EQ);
377
0
    else
378
0
      CC1Args.push_back("-fvisibility-nodllstorageclass=hidden");
379
380
0
    if (DriverArgs.hasArg(options::OPT_fvisibility_externs_dllimport_EQ))
381
0
      DriverArgs.AddLastArg(CC1Args,
382
0
                            options::OPT_fvisibility_externs_dllimport_EQ);
383
0
    else
384
0
      CC1Args.push_back("-fvisibility-externs-dllimport=default");
385
386
0
    if (DriverArgs.hasArg(
387
0
            options::OPT_fvisibility_externs_nodllstorageclass_EQ))
388
0
      DriverArgs.AddLastArg(
389
0
          CC1Args, options::OPT_fvisibility_externs_nodllstorageclass_EQ);
390
0
    else
391
0
      CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default");
392
0
  }
393
0
}
394
395
// PS4 toolchain.
396
toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple,
397
                           const llvm::opt::ArgList &Args)
398
0
    : PS4PS5Base(D, Triple, Args, "PS4", "SCE_ORBIS_SDK_DIR") {}
399
400
// PS5 toolchain.
401
toolchains::PS5CPU::PS5CPU(const Driver &D, const llvm::Triple &Triple,
402
                           const llvm::opt::ArgList &Args)
403
0
    : PS4PS5Base(D, Triple, Args, "PS5", "SCE_PROSPERO_SDK_DIR") {}