xref: /llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp (revision 1df50e6245cbc04f3b28de3c40127ad61d46b43b)
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                                  const char *Base, const char *Suffix) {
29   // Basically "Prefix + Base + Suffix" all converted to Twine then saved.
30   return Args.MakeArgString(Twine(StringRef(Prefix), Base) + Suffix);
31 }
32 
33 void tools::PScpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
34                                     ArgStringList &CmdArgs) {
35   assert(TC.getTriple().isPS());
36   auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC);
37 
38   if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
39                     false) ||
40        Args.hasFlag(options::OPT_fprofile_generate,
41                     options::OPT_fno_profile_generate, false) ||
42        Args.hasFlag(options::OPT_fprofile_generate_EQ,
43                     options::OPT_fno_profile_generate, false) ||
44        Args.hasFlag(options::OPT_fprofile_instr_generate,
45                     options::OPT_fno_profile_instr_generate, false) ||
46        Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
47                     options::OPT_fno_profile_instr_generate, false) ||
48        Args.hasFlag(options::OPT_fcs_profile_generate,
49                     options::OPT_fno_profile_generate, false) ||
50        Args.hasFlag(options::OPT_fcs_profile_generate_EQ,
51                     options::OPT_fno_profile_generate, false) ||
52        Args.hasArg(options::OPT_fcreate_profile) ||
53        Args.hasArg(options::OPT_coverage)))
54     CmdArgs.push_back(makeArgString(
55         Args, "--dependent-lib=", PSTC.getProfileRTLibName(), ""));
56 }
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                                            const char *LinkingOutput) const {
63   auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
64   claimNoWarnArgs(Args);
65   ArgStringList CmdArgs;
66 
67   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
68 
69   CmdArgs.push_back("-o");
70   CmdArgs.push_back(Output.getFilename());
71 
72   assert(Inputs.size() == 1 && "Unexpected number of inputs.");
73   const InputInfo &Input = Inputs[0];
74   assert(Input.isFilename() && "Invalid input.");
75   CmdArgs.push_back(Input.getFilename());
76 
77   std::string AsName = TC.qualifyPSCmdName("as");
78   const char *Exec = Args.MakeArgString(TC.GetProgramPath(AsName.c_str()));
79   C.addCommand(std::make_unique<Command>(JA, *this,
80                                          ResponseFileSupport::AtFileUTF8(),
81                                          Exec, CmdArgs, Inputs, Output));
82 }
83 
84 void tools::PScpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args,
85                                     ArgStringList &CmdArgs) {
86   assert(TC.getTriple().isPS());
87   auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC);
88   PSTC.addSanitizerArgs(Args, CmdArgs, "--dependent-lib=lib", ".a");
89 }
90 
91 void toolchains::PS4CPU::addSanitizerArgs(const ArgList &Args,
92                                           ArgStringList &CmdArgs,
93                                           const char *Prefix,
94                                           const char *Suffix) const {
95   auto arg = [&](const char *Name) -> const char * {
96     return makeArgString(Args, Prefix, Name, Suffix);
97   };
98   const SanitizerArgs &SanArgs = getSanitizerArgs(Args);
99   if (SanArgs.needsUbsanRt())
100     CmdArgs.push_back(arg("SceDbgUBSanitizer_stub_weak"));
101   if (SanArgs.needsAsanRt())
102     CmdArgs.push_back(arg("SceDbgAddressSanitizer_stub_weak"));
103 }
104 
105 void toolchains::PS5CPU::addSanitizerArgs(const ArgList &Args,
106                                           ArgStringList &CmdArgs,
107                                           const char *Prefix,
108                                           const char *Suffix) const {
109   auto arg = [&](const char *Name) -> const char * {
110     return makeArgString(Args, Prefix, Name, Suffix);
111   };
112   const SanitizerArgs &SanArgs = getSanitizerArgs(Args);
113   if (SanArgs.needsUbsanRt())
114     CmdArgs.push_back(arg("SceUBSanitizer_nosubmission_stub_weak"));
115   if (SanArgs.needsAsanRt())
116     CmdArgs.push_back(arg("SceAddressSanitizer_nosubmission_stub_weak"));
117   if (SanArgs.needsTsanRt())
118     CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_stub_weak"));
119 }
120 
121 void tools::PS4cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
122                                          const InputInfo &Output,
123                                          const InputInfoList &Inputs,
124                                          const ArgList &Args,
125                                          const char *LinkingOutput) const {
126   auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
127   const Driver &D = TC.getDriver();
128   ArgStringList CmdArgs;
129 
130   // Silence warning for "clang -g foo.o -o foo"
131   Args.ClaimAllArgs(options::OPT_g_Group);
132   // and "clang -emit-llvm foo.o -o foo"
133   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   Args.ClaimAllArgs(options::OPT_w);
137 
138   CmdArgs.push_back(
139       Args.MakeArgString("--sysroot=" + TC.getSDKLibraryRootDir()));
140 
141   if (Args.hasArg(options::OPT_pie))
142     CmdArgs.push_back("-pie");
143 
144   if (Args.hasArg(options::OPT_static))
145     CmdArgs.push_back("-static");
146   if (Args.hasArg(options::OPT_rdynamic))
147     CmdArgs.push_back("-export-dynamic");
148   if (Args.hasArg(options::OPT_shared))
149     CmdArgs.push_back("--shared");
150 
151   assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
152   if (Output.isFilename()) {
153     CmdArgs.push_back("-o");
154     CmdArgs.push_back(Output.getFilename());
155   }
156 
157   const bool UseJMC =
158       Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
159 
160   const char *LTOArgs = "";
161   auto AddLTOFlag = [&](Twine Flag) {
162     LTOArgs = Args.MakeArgString(Twine(LTOArgs) + " " + Flag);
163   };
164 
165   // If the linker sees bitcode objects it will perform LTO. We can't tell
166   // whether or not that will be the case at this point. So, unconditionally
167   // pass LTO options to ensure proper codegen, metadata production, etc if
168   // LTO indeed occurs.
169   if (Args.hasFlag(options::OPT_funified_lto, options::OPT_fno_unified_lto,
170                    true))
171     CmdArgs.push_back(D.getLTOMode() == LTOK_Thin ? "--lto=thin"
172                                                   : "--lto=full");
173   if (UseJMC)
174     AddLTOFlag("-enable-jmc-instrument");
175 
176   if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
177     AddLTOFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
178 
179   if (StringRef Threads = getLTOParallelism(Args, D); !Threads.empty())
180     AddLTOFlag(Twine("-threads=") + Threads);
181 
182   if (*LTOArgs)
183     CmdArgs.push_back(
184         Args.MakeArgString(Twine("-lto-debug-options=") + LTOArgs));
185 
186   // Sanitizer runtimes must be supplied before all other objects and libs.
187   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
188     TC.addSanitizerArgs(Args, CmdArgs, "-l", "");
189 
190   // Other drivers typically add library search paths (`-L`) here via
191   // TC.AddFilePathLibArgs(). We don't do that on PS4 as the PS4 linker
192   // searches those locations by default.
193   Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
194                             options::OPT_s, options::OPT_t});
195 
196   if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
197     CmdArgs.push_back("--no-demangle");
198 
199   AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
200 
201   if (Args.hasArg(options::OPT_pthread)) {
202     CmdArgs.push_back("-lpthread");
203   }
204 
205   if (UseJMC) {
206     CmdArgs.push_back("--whole-archive");
207     CmdArgs.push_back("-lSceDbgJmc");
208     CmdArgs.push_back("--no-whole-archive");
209   }
210 
211   if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
212     D.Diag(diag::err_drv_unsupported_opt_for_target)
213         << "-fuse-ld" << TC.getTriple().str();
214   }
215 
216   std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName());
217   const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str()));
218 
219   C.addCommand(std::make_unique<Command>(JA, *this,
220                                          ResponseFileSupport::AtFileUTF8(),
221                                          Exec, CmdArgs, Inputs, Output));
222 }
223 
224 void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
225                                          const InputInfo &Output,
226                                          const InputInfoList &Inputs,
227                                          const ArgList &Args,
228                                          const char *LinkingOutput) const {
229   auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
230   const Driver &D = TC.getDriver();
231   ArgStringList CmdArgs;
232 
233   const bool Relocatable = Args.hasArg(options::OPT_r);
234   const bool Shared = Args.hasArg(options::OPT_shared);
235   const bool Static = Args.hasArg(options::OPT_static);
236 
237   // Silence warning for "clang -g foo.o -o foo"
238   Args.ClaimAllArgs(options::OPT_g_Group);
239   // and "clang -emit-llvm foo.o -o foo"
240   Args.ClaimAllArgs(options::OPT_emit_llvm);
241   // and for "clang -w foo.o -o foo". Other warning options are already
242   // handled somewhere else.
243   Args.ClaimAllArgs(options::OPT_w);
244 
245   CmdArgs.push_back("-m");
246   CmdArgs.push_back("elf_x86_64_fbsd");
247 
248   CmdArgs.push_back(
249       Args.MakeArgString("--sysroot=" + TC.getSDKLibraryRootDir()));
250 
251   // Default to PIE for non-static executables.
252   const bool PIE = Args.hasFlag(options::OPT_pie, options::OPT_no_pie,
253                                 !Relocatable && !Shared && !Static);
254   if (PIE)
255     CmdArgs.push_back("-pie");
256 
257   if (!Relocatable) {
258     CmdArgs.push_back("--eh-frame-hdr");
259     CmdArgs.push_back("--hash-style=sysv");
260 
261     // Add a build-id by default to allow the PlayStation symbol server to
262     // index the symbols. `uuid` is the cheapest fool-proof method.
263     // (The non-determinism and alternative methods are noted in the downstream
264     // PlayStation docs).
265     // Static executables are only used for a handful of specialized components,
266     // where the extra section is not wanted.
267     if (!Static)
268       CmdArgs.push_back("--build-id=uuid");
269 
270     // All references are expected to be resolved at static link time for both
271     // executables and dynamic libraries. This has been the default linking
272     // behaviour for numerous PlayStation generations.
273     CmdArgs.push_back("--unresolved-symbols=report-all");
274 
275     // Lazy binding of PLTs is not supported on PlayStation. They are placed in
276     // the RelRo segment.
277     CmdArgs.push_back("-z");
278     CmdArgs.push_back("now");
279 
280     // Don't export linker-generated __start/stop... section bookends.
281     CmdArgs.push_back("-z");
282     CmdArgs.push_back("start-stop-visibility=hidden");
283 
284     // DT_DEBUG is not supported on PlayStation.
285     CmdArgs.push_back("-z");
286     CmdArgs.push_back("rodynamic");
287 
288     CmdArgs.push_back("-z");
289     CmdArgs.push_back("common-page-size=0x4000");
290 
291     CmdArgs.push_back("-z");
292     CmdArgs.push_back("max-page-size=0x4000");
293 
294     // Patch relocated regions of DWARF whose targets are eliminated at link
295     // time with specific tombstones, such that they're recognisable by the
296     // PlayStation debugger.
297     CmdArgs.push_back("-z");
298     CmdArgs.push_back("dead-reloc-in-nonalloc=.debug_*=0xffffffffffffffff");
299     CmdArgs.push_back("-z");
300     CmdArgs.push_back(
301         "dead-reloc-in-nonalloc=.debug_ranges=0xfffffffffffffffe");
302     CmdArgs.push_back("-z");
303     CmdArgs.push_back("dead-reloc-in-nonalloc=.debug_loc=0xfffffffffffffffe");
304 
305     // The PlayStation loader expects linked objects to be laid out in a
306     // particular way. This is achieved by linker scripts that are supplied
307     // with the SDK. The scripts are inside <sdkroot>/target/lib, which is
308     // added as a search path elsewhere.
309     // "PRX" has long stood for "PlayStation Relocatable eXecutable".
310     if (!Args.hasArgNoClaim(options::OPT_T)) {
311       CmdArgs.push_back("--default-script");
312       CmdArgs.push_back(Static   ? "static.script"
313                         : Shared ? "prx.script"
314                                  : "main.script");
315     }
316   }
317 
318   if (Static)
319     CmdArgs.push_back("-static");
320   if (Args.hasArg(options::OPT_rdynamic))
321     CmdArgs.push_back("-export-dynamic");
322   if (Shared)
323     CmdArgs.push_back("--shared");
324 
325   // Provide a base address for non-PIE executables. This includes cases where
326   // -static is supplied without -pie.
327   if (!Relocatable && !Shared && !PIE)
328     CmdArgs.push_back("--image-base=0x400000");
329 
330   assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
331   if (Output.isFilename()) {
332     CmdArgs.push_back("-o");
333     CmdArgs.push_back(Output.getFilename());
334   }
335 
336   const bool UseJMC =
337       Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
338 
339   auto AddLTOFlag = [&](Twine Flag) {
340     CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag));
341   };
342 
343   // If the linker sees bitcode objects it will perform LTO. We can't tell
344   // whether or not that will be the case at this point. So, unconditionally
345   // pass LTO options to ensure proper codegen, metadata production, etc if
346   // LTO indeed occurs.
347   if (Args.hasFlag(options::OPT_funified_lto, options::OPT_fno_unified_lto,
348                    true))
349     CmdArgs.push_back(D.getLTOMode() == LTOK_Thin ? "--lto=thin"
350                                                   : "--lto=full");
351 
352   AddLTOFlag("-emit-jump-table-sizes-section");
353 
354   if (UseJMC)
355     AddLTOFlag("-enable-jmc-instrument");
356 
357   if (Args.hasFlag(options::OPT_fstack_size_section,
358                    options::OPT_fno_stack_size_section, false))
359     AddLTOFlag("-stack-size-section");
360 
361   if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
362     AddLTOFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
363 
364   if (StringRef Jobs = getLTOParallelism(Args, D); !Jobs.empty())
365     AddLTOFlag(Twine("jobs=") + Jobs);
366 
367   Args.AddAllArgs(CmdArgs, options::OPT_L);
368   TC.AddFilePathLibArgs(Args, CmdArgs);
369   Args.addAllArgs(CmdArgs,
370                   {options::OPT_T_Group, options::OPT_s, options::OPT_t});
371 
372   if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
373     CmdArgs.push_back("--no-demangle");
374 
375   // Sanitizer runtimes must be supplied before all other objects and libs.
376   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
377     TC.addSanitizerArgs(Args, CmdArgs, "-l", "");
378 
379   const bool AddStartFiles =
380       !Relocatable &&
381       !Args.hasArg(options::OPT_nostartfiles, options::OPT_nostdlib);
382 
383   auto AddCRTObject = [&](const char *Name) {
384     CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(Name)));
385   };
386 
387   if (AddStartFiles) {
388     if (!Shared)
389       AddCRTObject("crt1.o");
390     AddCRTObject("crti.o");
391     AddCRTObject(Shared   ? "crtbeginS.o"
392                  : Static ? "crtbeginT.o"
393                           : "crtbegin.o");
394   }
395 
396   AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
397 
398   if (!Relocatable &&
399       !Args.hasArg(options::OPT_nodefaultlibs, options::OPT_nostdlib)) {
400 
401     if (UseJMC) {
402       CmdArgs.push_back("--push-state");
403       CmdArgs.push_back("--whole-archive");
404       CmdArgs.push_back("-lSceJmc_nosubmission");
405       CmdArgs.push_back("--pop-state");
406     }
407 
408     if (Args.hasArg(options::OPT_pthread))
409       CmdArgs.push_back("-lpthread");
410 
411     if (Static) {
412       if (!Args.hasArg(options::OPT_nostdlibxx))
413         CmdArgs.push_back("-lstdc++");
414       if (!Args.hasArg(options::OPT_nolibc)) {
415         CmdArgs.push_back("-lm");
416         CmdArgs.push_back("-lc");
417       }
418 
419       CmdArgs.push_back("-lcompiler_rt");
420       CmdArgs.push_back("-lkernel");
421     } else {
422       // The C and C++ libraries are combined.
423       if (!Args.hasArg(options::OPT_nolibc, options::OPT_nostdlibxx))
424         CmdArgs.push_back("-lc_stub_weak");
425 
426       CmdArgs.push_back("-lkernel_stub_weak");
427     }
428   }
429   if (AddStartFiles) {
430     AddCRTObject(Shared ? "crtendS.o" : "crtend.o");
431     AddCRTObject("crtn.o");
432   }
433 
434   if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
435     D.Diag(diag::err_drv_unsupported_opt_for_target)
436         << "-fuse-ld" << TC.getTriple().str();
437   }
438 
439   std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName());
440   const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str()));
441 
442   C.addCommand(std::make_unique<Command>(JA, *this,
443                                          ResponseFileSupport::AtFileUTF8(),
444                                          Exec, CmdArgs, Inputs, Output));
445 }
446 
447 toolchains::PS4PS5Base::PS4PS5Base(const Driver &D, const llvm::Triple &Triple,
448                                    const ArgList &Args, StringRef Platform,
449                                    const char *EnvVar)
450     : Generic_ELF(D, Triple, Args) {
451   // Determine the baseline SDK directory from the environment, else
452   // the driver's location, which should be <SDK_DIR>/host_tools/bin.
453   SmallString<128> SDKRootDir;
454   SmallString<80> Whence;
455   if (const char *EnvValue = getenv(EnvVar)) {
456     SDKRootDir = EnvValue;
457     Whence = {"environment variable '", EnvVar, "'"};
458   } else {
459     SDKRootDir = D.Dir + "/../../";
460     Whence = "compiler's location";
461   }
462 
463   // Allow --sysroot= to override the root directory for header and library
464   // search, and -isysroot to override header search. If both are specified,
465   // -isysroot overrides --sysroot for header search.
466   auto OverrideRoot = [&](const options::ID &Opt, std::string &Root,
467                           StringRef Default) {
468     if (const Arg *A = Args.getLastArg(Opt)) {
469       Root = A->getValue();
470       if (!llvm::sys::fs::exists(Root))
471         D.Diag(clang::diag::warn_missing_sysroot) << Root;
472       return true;
473     }
474     Root = Default.str();
475     return false;
476   };
477 
478   bool CustomSysroot =
479       OverrideRoot(options::OPT__sysroot_EQ, SDKLibraryRootDir, SDKRootDir);
480   bool CustomISysroot =
481       OverrideRoot(options::OPT_isysroot, SDKHeaderRootDir, SDKLibraryRootDir);
482 
483   // Emit warnings if parts of the SDK are missing, unless the user has taken
484   // control of header or library search. If we're not linking, don't check
485   // for missing libraries.
486   auto CheckSDKPartExists = [&](StringRef Dir, StringRef Desc) {
487     if (llvm::sys::fs::exists(Dir))
488       return true;
489     D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
490         << (Twine(Platform) + " " + Desc).str() << Dir << Whence;
491     return false;
492   };
493 
494   bool Linking = !Args.hasArg(options::OPT_E, options::OPT_c, options::OPT_S,
495                               options::OPT_emit_ast);
496   if (Linking) {
497     SmallString<128> Dir(SDKLibraryRootDir);
498     llvm::sys::path::append(Dir, "target/lib");
499     if (CheckSDKPartExists(Dir, "system libraries"))
500       getFilePaths().push_back(std::string(Dir));
501   }
502   if (!CustomSysroot && !CustomISysroot &&
503       !Args.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc)) {
504     SmallString<128> Dir(SDKHeaderRootDir);
505     llvm::sys::path::append(Dir, "target/include");
506     CheckSDKPartExists(Dir, "system headers");
507   }
508 
509   getFilePaths().push_back(".");
510 }
511 
512 void toolchains::PS4PS5Base::AddClangSystemIncludeArgs(
513     const ArgList &DriverArgs, ArgStringList &CC1Args) const {
514   const Driver &D = getDriver();
515 
516   if (DriverArgs.hasArg(options::OPT_nostdinc))
517     return;
518 
519   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
520     SmallString<128> Dir(D.ResourceDir);
521     llvm::sys::path::append(Dir, "include");
522     addSystemInclude(DriverArgs, CC1Args, Dir.str());
523   }
524 
525   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
526     return;
527 
528   addExternCSystemInclude(DriverArgs, CC1Args,
529                           SDKHeaderRootDir + "/target/include");
530   addExternCSystemInclude(DriverArgs, CC1Args,
531                           SDKHeaderRootDir + "/target/include_common");
532 }
533 
534 Tool *toolchains::PS4CPU::buildAssembler() const {
535   return new tools::PScpu::Assembler(*this);
536 }
537 
538 Tool *toolchains::PS4CPU::buildLinker() const {
539   return new tools::PS4cpu::Linker(*this);
540 }
541 
542 Tool *toolchains::PS5CPU::buildAssembler() const {
543   // PS5 does not support an external assembler.
544   getDriver().Diag(clang::diag::err_no_external_assembler);
545   return nullptr;
546 }
547 
548 Tool *toolchains::PS5CPU::buildLinker() const {
549   return new tools::PS5cpu::Linker(*this);
550 }
551 
552 SanitizerMask toolchains::PS4PS5Base::getSupportedSanitizers() const {
553   SanitizerMask Res = ToolChain::getSupportedSanitizers();
554   Res |= SanitizerKind::Address;
555   Res |= SanitizerKind::PointerCompare;
556   Res |= SanitizerKind::PointerSubtract;
557   Res |= SanitizerKind::Vptr;
558   return Res;
559 }
560 
561 SanitizerMask toolchains::PS5CPU::getSupportedSanitizers() const {
562   SanitizerMask Res = PS4PS5Base::getSupportedSanitizers();
563   Res |= SanitizerKind::Thread;
564   return Res;
565 }
566 
567 void toolchains::PS4PS5Base::addClangTargetOptions(
568     const ArgList &DriverArgs, ArgStringList &CC1Args,
569     Action::OffloadKind DeviceOffloadingKind) const {
570   // PS4/PS5 do not use init arrays.
571   if (DriverArgs.hasArg(options::OPT_fuse_init_array)) {
572     Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array);
573     getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target)
574         << A->getAsString(DriverArgs) << getTriple().str();
575   }
576 
577   CC1Args.push_back("-fno-use-init-array");
578 
579   // Default to `hidden` visibility for PS5.
580   if (getTriple().isPS5() &&
581       !DriverArgs.hasArg(options::OPT_fvisibility_EQ,
582                          options::OPT_fvisibility_ms_compat))
583     CC1Args.push_back("-fvisibility=hidden");
584 
585   // Default to -fvisibility-global-new-delete=source for PS5.
586   if (getTriple().isPS5() &&
587       !DriverArgs.hasArg(options::OPT_fvisibility_global_new_delete_EQ,
588                          options::OPT_fvisibility_global_new_delete_hidden))
589     CC1Args.push_back("-fvisibility-global-new-delete=source");
590 
591   const Arg *A =
592       DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
593                             options::OPT_fno_visibility_from_dllstorageclass);
594   if (!A ||
595       A->getOption().matches(options::OPT_fvisibility_from_dllstorageclass)) {
596     CC1Args.push_back("-fvisibility-from-dllstorageclass");
597 
598     if (DriverArgs.hasArg(options::OPT_fvisibility_dllexport_EQ))
599       DriverArgs.AddLastArg(CC1Args, options::OPT_fvisibility_dllexport_EQ);
600     else
601       CC1Args.push_back("-fvisibility-dllexport=protected");
602 
603     // For PS4 we override the visibilty of globals definitions without
604     // dllimport or  dllexport annotations.
605     if (DriverArgs.hasArg(options::OPT_fvisibility_nodllstorageclass_EQ))
606       DriverArgs.AddLastArg(CC1Args,
607                             options::OPT_fvisibility_nodllstorageclass_EQ);
608     else if (getTriple().isPS4())
609       CC1Args.push_back("-fvisibility-nodllstorageclass=hidden");
610     else
611       CC1Args.push_back("-fvisibility-nodllstorageclass=keep");
612 
613     if (DriverArgs.hasArg(options::OPT_fvisibility_externs_dllimport_EQ))
614       DriverArgs.AddLastArg(CC1Args,
615                             options::OPT_fvisibility_externs_dllimport_EQ);
616     else
617       CC1Args.push_back("-fvisibility-externs-dllimport=default");
618 
619     // For PS4 we override the visibilty of external globals without
620     // dllimport or  dllexport annotations.
621     if (DriverArgs.hasArg(
622             options::OPT_fvisibility_externs_nodllstorageclass_EQ))
623       DriverArgs.AddLastArg(
624           CC1Args, options::OPT_fvisibility_externs_nodllstorageclass_EQ);
625     else if (getTriple().isPS4())
626       CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default");
627     else
628       CC1Args.push_back("-fvisibility-externs-nodllstorageclass=keep");
629   }
630 
631   // Enable jump table sizes section for PS5.
632   if (getTriple().isPS5()) {
633     CC1Args.push_back("-mllvm");
634     CC1Args.push_back("-emit-jump-table-sizes-section");
635   }
636 }
637 
638 // PS4 toolchain.
639 toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple,
640                            const llvm::opt::ArgList &Args)
641     : PS4PS5Base(D, Triple, Args, "PS4", "SCE_ORBIS_SDK_DIR") {}
642 
643 // PS5 toolchain.
644 toolchains::PS5CPU::PS5CPU(const Driver &D, const llvm::Triple &Triple,
645                            const llvm::opt::ArgList &Args)
646     : PS4PS5Base(D, Triple, Args, "PS5", "SCE_PROSPERO_SDK_DIR") {}
647