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