10b57cec5SDimitry Andric //===--- PS4CPU.cpp - PS4CPU ToolChain Implementations ----------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "PS4CPU.h"
100b57cec5SDimitry Andric #include "CommonArgs.h"
1106c3fb27SDimitry Andric #include "clang/Config/config.h"
120b57cec5SDimitry Andric #include "clang/Driver/Compilation.h"
130b57cec5SDimitry Andric #include "clang/Driver/Driver.h"
140b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
150b57cec5SDimitry Andric #include "clang/Driver/Options.h"
160b57cec5SDimitry Andric #include "clang/Driver/SanitizerArgs.h"
170b57cec5SDimitry Andric #include "llvm/Option/ArgList.h"
180b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
190b57cec5SDimitry Andric #include "llvm/Support/Path.h"
200b57cec5SDimitry Andric #include <cstdlib> // ::getenv
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric using namespace clang::driver;
230b57cec5SDimitry Andric using namespace clang;
240b57cec5SDimitry Andric using namespace llvm::opt;
250b57cec5SDimitry Andric
2681ad6265SDimitry Andric // Helper to paste bits of an option together and return a saved string.
makeArgString(const ArgList & Args,const char * Prefix,const char * Base,const char * Suffix)2781ad6265SDimitry Andric static const char *makeArgString(const ArgList &Args, const char *Prefix,
2881ad6265SDimitry Andric const char *Base, const char *Suffix) {
2981ad6265SDimitry Andric // Basically "Prefix + Base + Suffix" all converted to Twine then saved.
3081ad6265SDimitry Andric return Args.MakeArgString(Twine(StringRef(Prefix), Base) + Suffix);
3181ad6265SDimitry Andric }
3281ad6265SDimitry Andric
addProfileRTArgs(const ToolChain & TC,const ArgList & Args,ArgStringList & CmdArgs)3381ad6265SDimitry Andric void tools::PScpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
340b57cec5SDimitry Andric ArgStringList &CmdArgs) {
3581ad6265SDimitry Andric assert(TC.getTriple().isPS());
3681ad6265SDimitry Andric auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC);
3781ad6265SDimitry Andric
380b57cec5SDimitry Andric if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
390b57cec5SDimitry Andric false) ||
400b57cec5SDimitry Andric Args.hasFlag(options::OPT_fprofile_generate,
415ffd83dbSDimitry Andric options::OPT_fno_profile_generate, false) ||
420b57cec5SDimitry Andric Args.hasFlag(options::OPT_fprofile_generate_EQ,
435ffd83dbSDimitry Andric options::OPT_fno_profile_generate, false) ||
440b57cec5SDimitry Andric Args.hasFlag(options::OPT_fprofile_instr_generate,
450b57cec5SDimitry Andric options::OPT_fno_profile_instr_generate, false) ||
460b57cec5SDimitry Andric Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
470b57cec5SDimitry Andric options::OPT_fno_profile_instr_generate, false) ||
485ffd83dbSDimitry Andric Args.hasFlag(options::OPT_fcs_profile_generate,
495ffd83dbSDimitry Andric options::OPT_fno_profile_generate, false) ||
505ffd83dbSDimitry Andric Args.hasFlag(options::OPT_fcs_profile_generate_EQ,
515ffd83dbSDimitry Andric options::OPT_fno_profile_generate, false) ||
520b57cec5SDimitry Andric Args.hasArg(options::OPT_fcreate_profile) ||
530b57cec5SDimitry Andric Args.hasArg(options::OPT_coverage)))
5481ad6265SDimitry Andric CmdArgs.push_back(makeArgString(
5581ad6265SDimitry Andric Args, "--dependent-lib=", PSTC.getProfileRTLibName(), ""));
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const5881ad6265SDimitry Andric void tools::PScpu::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
590b57cec5SDimitry Andric const InputInfo &Output,
600b57cec5SDimitry Andric const InputInfoList &Inputs,
610b57cec5SDimitry Andric const ArgList &Args,
620b57cec5SDimitry Andric const char *LinkingOutput) const {
6381ad6265SDimitry Andric auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
640b57cec5SDimitry Andric claimNoWarnArgs(Args);
650b57cec5SDimitry Andric ArgStringList CmdArgs;
660b57cec5SDimitry Andric
670b57cec5SDimitry Andric Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric CmdArgs.push_back("-o");
700b57cec5SDimitry Andric CmdArgs.push_back(Output.getFilename());
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric assert(Inputs.size() == 1 && "Unexpected number of inputs.");
730b57cec5SDimitry Andric const InputInfo &Input = Inputs[0];
740b57cec5SDimitry Andric assert(Input.isFilename() && "Invalid input.");
750b57cec5SDimitry Andric CmdArgs.push_back(Input.getFilename());
760b57cec5SDimitry Andric
7781ad6265SDimitry Andric std::string AsName = TC.qualifyPSCmdName("as");
7881ad6265SDimitry Andric const char *Exec = Args.MakeArgString(TC.GetProgramPath(AsName.c_str()));
79e8d8bef9SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this,
80e8d8bef9SDimitry Andric ResponseFileSupport::AtFileUTF8(),
81e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output));
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric
addSanitizerArgs(const ToolChain & TC,const ArgList & Args,ArgStringList & CmdArgs)8481ad6265SDimitry Andric void tools::PScpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args,
85349cc55cSDimitry Andric ArgStringList &CmdArgs) {
8681ad6265SDimitry Andric assert(TC.getTriple().isPS());
8781ad6265SDimitry Andric auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC);
8881ad6265SDimitry Andric PSTC.addSanitizerArgs(Args, CmdArgs, "--dependent-lib=lib", ".a");
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric
addSanitizerArgs(const ArgList & Args,ArgStringList & CmdArgs,const char * Prefix,const char * Suffix) const9181ad6265SDimitry Andric void toolchains::PS4CPU::addSanitizerArgs(const ArgList &Args,
9281ad6265SDimitry Andric ArgStringList &CmdArgs,
9381ad6265SDimitry Andric const char *Prefix,
9481ad6265SDimitry Andric const char *Suffix) const {
9581ad6265SDimitry Andric auto arg = [&](const char *Name) -> const char * {
9681ad6265SDimitry Andric return makeArgString(Args, Prefix, Name, Suffix);
9781ad6265SDimitry Andric };
9881ad6265SDimitry Andric const SanitizerArgs &SanArgs = getSanitizerArgs(Args);
990b57cec5SDimitry Andric if (SanArgs.needsUbsanRt())
10081ad6265SDimitry Andric CmdArgs.push_back(arg("SceDbgUBSanitizer_stub_weak"));
1010b57cec5SDimitry Andric if (SanArgs.needsAsanRt())
10281ad6265SDimitry Andric CmdArgs.push_back(arg("SceDbgAddressSanitizer_stub_weak"));
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric
addSanitizerArgs(const ArgList & Args,ArgStringList & CmdArgs,const char * Prefix,const char * Suffix) const10581ad6265SDimitry Andric void toolchains::PS5CPU::addSanitizerArgs(const ArgList &Args,
10681ad6265SDimitry Andric ArgStringList &CmdArgs,
10781ad6265SDimitry Andric const char *Prefix,
10881ad6265SDimitry Andric const char *Suffix) const {
10981ad6265SDimitry Andric auto arg = [&](const char *Name) -> const char * {
11081ad6265SDimitry Andric return makeArgString(Args, Prefix, Name, Suffix);
11181ad6265SDimitry Andric };
11281ad6265SDimitry Andric const SanitizerArgs &SanArgs = getSanitizerArgs(Args);
11381ad6265SDimitry Andric if (SanArgs.needsUbsanRt())
11481ad6265SDimitry Andric CmdArgs.push_back(arg("SceUBSanitizer_nosubmission_stub_weak"));
11581ad6265SDimitry Andric if (SanArgs.needsAsanRt())
11681ad6265SDimitry Andric CmdArgs.push_back(arg("SceAddressSanitizer_nosubmission_stub_weak"));
11781ad6265SDimitry Andric if (SanArgs.needsTsanRt())
11881ad6265SDimitry Andric CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_stub_weak"));
11981ad6265SDimitry Andric }
12081ad6265SDimitry Andric
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const121*0fca6ea1SDimitry Andric void tools::PS4cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
1225ffd83dbSDimitry Andric const InputInfo &Output,
1230b57cec5SDimitry Andric const InputInfoList &Inputs,
1240b57cec5SDimitry Andric const ArgList &Args,
1255ffd83dbSDimitry Andric const char *LinkingOutput) const {
12681ad6265SDimitry Andric auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
12781ad6265SDimitry Andric const Driver &D = TC.getDriver();
1280b57cec5SDimitry Andric ArgStringList CmdArgs;
1290b57cec5SDimitry Andric
1300b57cec5SDimitry Andric // Silence warning for "clang -g foo.o -o foo"
1310b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_g_Group);
1320b57cec5SDimitry Andric // and "clang -emit-llvm foo.o -o foo"
1330b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_emit_llvm);
1340b57cec5SDimitry Andric // and for "clang -w foo.o -o foo". Other warning options are already
1350b57cec5SDimitry Andric // handled somewhere else.
1360b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_w);
1370b57cec5SDimitry Andric
1380b57cec5SDimitry Andric if (!D.SysRoot.empty())
1390b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric if (Args.hasArg(options::OPT_pie))
1420b57cec5SDimitry Andric CmdArgs.push_back("-pie");
1430b57cec5SDimitry Andric
1440b57cec5SDimitry Andric if (Args.hasArg(options::OPT_rdynamic))
1450b57cec5SDimitry Andric CmdArgs.push_back("-export-dynamic");
1460b57cec5SDimitry Andric if (Args.hasArg(options::OPT_shared))
14781ad6265SDimitry Andric CmdArgs.push_back("--shared");
1480b57cec5SDimitry Andric
1495f757f3fSDimitry Andric assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
1500b57cec5SDimitry Andric if (Output.isFilename()) {
1510b57cec5SDimitry Andric CmdArgs.push_back("-o");
1520b57cec5SDimitry Andric CmdArgs.push_back(Output.getFilename());
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric
155bdd1243dSDimitry Andric const bool UseLTO = D.isUsingLTO();
156bdd1243dSDimitry Andric const bool UseJMC =
157bdd1243dSDimitry Andric Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
158bdd1243dSDimitry Andric
159*0fca6ea1SDimitry Andric const char *LTOArgs = "";
160bdd1243dSDimitry Andric auto AddCodeGenFlag = [&](Twine Flag) {
161*0fca6ea1SDimitry Andric LTOArgs = Args.MakeArgString(Twine(LTOArgs) + " " + Flag);
162*0fca6ea1SDimitry Andric };
163*0fca6ea1SDimitry Andric
164*0fca6ea1SDimitry Andric if (UseLTO) {
165*0fca6ea1SDimitry Andric // We default to creating the arange section, but LTO does not. Enable it
166*0fca6ea1SDimitry Andric // here.
167*0fca6ea1SDimitry Andric AddCodeGenFlag("-generate-arange-section");
168*0fca6ea1SDimitry Andric
169*0fca6ea1SDimitry Andric // This tells LTO to perform JustMyCode instrumentation.
170*0fca6ea1SDimitry Andric if (UseJMC)
171*0fca6ea1SDimitry Andric AddCodeGenFlag("-enable-jmc-instrument");
172*0fca6ea1SDimitry Andric
173*0fca6ea1SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
174*0fca6ea1SDimitry Andric AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
175*0fca6ea1SDimitry Andric
176*0fca6ea1SDimitry Andric StringRef Parallelism = getLTOParallelism(Args, D);
177*0fca6ea1SDimitry Andric if (!Parallelism.empty())
178*0fca6ea1SDimitry Andric AddCodeGenFlag(Twine("-threads=") + Parallelism);
179*0fca6ea1SDimitry Andric
180*0fca6ea1SDimitry Andric const char *Prefix = nullptr;
181*0fca6ea1SDimitry Andric if (D.getLTOMode() == LTOK_Thin)
182*0fca6ea1SDimitry Andric Prefix = "-lto-thin-debug-options=";
183*0fca6ea1SDimitry Andric else if (D.getLTOMode() == LTOK_Full)
184*0fca6ea1SDimitry Andric Prefix = "-lto-debug-options=";
1855f757f3fSDimitry Andric else
186*0fca6ea1SDimitry Andric llvm_unreachable("new LTO mode?");
187*0fca6ea1SDimitry Andric
188*0fca6ea1SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + LTOArgs));
189*0fca6ea1SDimitry Andric }
190*0fca6ea1SDimitry Andric
191*0fca6ea1SDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
192*0fca6ea1SDimitry Andric TC.addSanitizerArgs(Args, CmdArgs, "-l", "");
193*0fca6ea1SDimitry Andric
194*0fca6ea1SDimitry Andric if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) {
195*0fca6ea1SDimitry Andric if (D.getLTOMode() == LTOK_Thin)
196*0fca6ea1SDimitry Andric CmdArgs.push_back("--lto=thin");
197*0fca6ea1SDimitry Andric else if (D.getLTOMode() == LTOK_Full)
198*0fca6ea1SDimitry Andric CmdArgs.push_back("--lto=full");
199*0fca6ea1SDimitry Andric }
200*0fca6ea1SDimitry Andric
201*0fca6ea1SDimitry Andric Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
202*0fca6ea1SDimitry Andric options::OPT_s, options::OPT_t});
203*0fca6ea1SDimitry Andric
204*0fca6ea1SDimitry Andric if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
205*0fca6ea1SDimitry Andric CmdArgs.push_back("--no-demangle");
206*0fca6ea1SDimitry Andric
207*0fca6ea1SDimitry Andric AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
208*0fca6ea1SDimitry Andric
209*0fca6ea1SDimitry Andric if (Args.hasArg(options::OPT_pthread)) {
210*0fca6ea1SDimitry Andric CmdArgs.push_back("-lpthread");
211*0fca6ea1SDimitry Andric }
212*0fca6ea1SDimitry Andric
213*0fca6ea1SDimitry Andric if (UseJMC) {
214*0fca6ea1SDimitry Andric CmdArgs.push_back("--whole-archive");
215*0fca6ea1SDimitry Andric CmdArgs.push_back("-lSceDbgJmc");
216*0fca6ea1SDimitry Andric CmdArgs.push_back("--no-whole-archive");
217*0fca6ea1SDimitry Andric }
218*0fca6ea1SDimitry Andric
219*0fca6ea1SDimitry Andric if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
220*0fca6ea1SDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target)
221*0fca6ea1SDimitry Andric << "-fuse-ld" << TC.getTriple().str();
222*0fca6ea1SDimitry Andric }
223*0fca6ea1SDimitry Andric
224*0fca6ea1SDimitry Andric std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName());
225*0fca6ea1SDimitry Andric const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str()));
226*0fca6ea1SDimitry Andric
227*0fca6ea1SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this,
228*0fca6ea1SDimitry Andric ResponseFileSupport::AtFileUTF8(),
229*0fca6ea1SDimitry Andric Exec, CmdArgs, Inputs, Output));
230*0fca6ea1SDimitry Andric }
231*0fca6ea1SDimitry Andric
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const232*0fca6ea1SDimitry Andric void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
233*0fca6ea1SDimitry Andric const InputInfo &Output,
234*0fca6ea1SDimitry Andric const InputInfoList &Inputs,
235*0fca6ea1SDimitry Andric const ArgList &Args,
236*0fca6ea1SDimitry Andric const char *LinkingOutput) const {
237*0fca6ea1SDimitry Andric auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
238*0fca6ea1SDimitry Andric const Driver &D = TC.getDriver();
239*0fca6ea1SDimitry Andric ArgStringList CmdArgs;
240*0fca6ea1SDimitry Andric
241*0fca6ea1SDimitry Andric // Silence warning for "clang -g foo.o -o foo"
242*0fca6ea1SDimitry Andric Args.ClaimAllArgs(options::OPT_g_Group);
243*0fca6ea1SDimitry Andric // and "clang -emit-llvm foo.o -o foo"
244*0fca6ea1SDimitry Andric Args.ClaimAllArgs(options::OPT_emit_llvm);
245*0fca6ea1SDimitry Andric // and for "clang -w foo.o -o foo". Other warning options are already
246*0fca6ea1SDimitry Andric // handled somewhere else.
247*0fca6ea1SDimitry Andric Args.ClaimAllArgs(options::OPT_w);
248*0fca6ea1SDimitry Andric
249*0fca6ea1SDimitry Andric if (!D.SysRoot.empty())
250*0fca6ea1SDimitry Andric CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
251*0fca6ea1SDimitry Andric
252*0fca6ea1SDimitry Andric if (Args.hasArg(options::OPT_pie))
253*0fca6ea1SDimitry Andric CmdArgs.push_back("-pie");
254*0fca6ea1SDimitry Andric
255*0fca6ea1SDimitry Andric if (Args.hasArg(options::OPT_rdynamic))
256*0fca6ea1SDimitry Andric CmdArgs.push_back("-export-dynamic");
257*0fca6ea1SDimitry Andric if (Args.hasArg(options::OPT_shared))
258*0fca6ea1SDimitry Andric CmdArgs.push_back("--shared");
259*0fca6ea1SDimitry Andric
260*0fca6ea1SDimitry Andric assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
261*0fca6ea1SDimitry Andric if (Output.isFilename()) {
262*0fca6ea1SDimitry Andric CmdArgs.push_back("-o");
263*0fca6ea1SDimitry Andric CmdArgs.push_back(Output.getFilename());
264*0fca6ea1SDimitry Andric }
265*0fca6ea1SDimitry Andric
266*0fca6ea1SDimitry Andric const bool UseLTO = D.isUsingLTO();
267*0fca6ea1SDimitry Andric const bool UseJMC =
268*0fca6ea1SDimitry Andric Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
269*0fca6ea1SDimitry Andric
270*0fca6ea1SDimitry Andric auto AddCodeGenFlag = [&](Twine Flag) {
27106c3fb27SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag));
272bdd1243dSDimitry Andric };
273bdd1243dSDimitry Andric
274bdd1243dSDimitry Andric if (UseLTO) {
275bdd1243dSDimitry Andric // We default to creating the arange section, but LTO does not. Enable it
276bdd1243dSDimitry Andric // here.
277bdd1243dSDimitry Andric AddCodeGenFlag("-generate-arange-section");
278bdd1243dSDimitry Andric
279bdd1243dSDimitry Andric // This tells LTO to perform JustMyCode instrumentation.
280bdd1243dSDimitry Andric if (UseJMC)
281bdd1243dSDimitry Andric AddCodeGenFlag("-enable-jmc-instrument");
282bdd1243dSDimitry Andric
283bdd1243dSDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
284bdd1243dSDimitry Andric AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
28506c3fb27SDimitry Andric
28606c3fb27SDimitry Andric StringRef Parallelism = getLTOParallelism(Args, D);
287*0fca6ea1SDimitry Andric if (!Parallelism.empty())
28806c3fb27SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism));
28906c3fb27SDimitry Andric }
29006c3fb27SDimitry Andric
2910b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
29281ad6265SDimitry Andric TC.addSanitizerArgs(Args, CmdArgs, "-l", "");
2930b57cec5SDimitry Andric
29406c3fb27SDimitry Andric if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) {
29506c3fb27SDimitry Andric if (D.getLTOMode() == LTOK_Thin)
29606c3fb27SDimitry Andric CmdArgs.push_back("--lto=thin");
29706c3fb27SDimitry Andric else if (D.getLTOMode() == LTOK_Full)
29806c3fb27SDimitry Andric CmdArgs.push_back("--lto=full");
29906c3fb27SDimitry Andric }
30006c3fb27SDimitry Andric
301*0fca6ea1SDimitry Andric Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
302*0fca6ea1SDimitry Andric options::OPT_s, options::OPT_t});
3030b57cec5SDimitry Andric
3040b57cec5SDimitry Andric if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
3050b57cec5SDimitry Andric CmdArgs.push_back("--no-demangle");
3060b57cec5SDimitry Andric
30781ad6265SDimitry Andric AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
3080b57cec5SDimitry Andric
3090b57cec5SDimitry Andric if (Args.hasArg(options::OPT_pthread)) {
3100b57cec5SDimitry Andric CmdArgs.push_back("-lpthread");
3110b57cec5SDimitry Andric }
3120b57cec5SDimitry Andric
313bdd1243dSDimitry Andric if (UseJMC) {
314bdd1243dSDimitry Andric CmdArgs.push_back("--whole-archive");
315bdd1243dSDimitry Andric CmdArgs.push_back("-lSceJmc_nosubmission");
316bdd1243dSDimitry Andric CmdArgs.push_back("--no-whole-archive");
317bdd1243dSDimitry Andric }
318bdd1243dSDimitry Andric
3195ffd83dbSDimitry Andric if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
3205ffd83dbSDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target)
32181ad6265SDimitry Andric << "-fuse-ld" << TC.getTriple().str();
3220b57cec5SDimitry Andric }
3230b57cec5SDimitry Andric
32481ad6265SDimitry Andric std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName());
32581ad6265SDimitry Andric const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str()));
3260b57cec5SDimitry Andric
327e8d8bef9SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this,
328e8d8bef9SDimitry Andric ResponseFileSupport::AtFileUTF8(),
329e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output));
3300b57cec5SDimitry Andric }
3310b57cec5SDimitry Andric
PS4PS5Base(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,StringRef Platform,const char * EnvVar)33281ad6265SDimitry Andric toolchains::PS4PS5Base::PS4PS5Base(const Driver &D, const llvm::Triple &Triple,
33381ad6265SDimitry Andric const ArgList &Args, StringRef Platform,
33481ad6265SDimitry Andric const char *EnvVar)
3350b57cec5SDimitry Andric : Generic_ELF(D, Triple, Args) {
3360b57cec5SDimitry Andric if (Args.hasArg(clang::driver::options::OPT_static))
33781ad6265SDimitry Andric D.Diag(clang::diag::err_drv_unsupported_opt_for_target)
33881ad6265SDimitry Andric << "-static" << Platform;
3390b57cec5SDimitry Andric
34006c3fb27SDimitry Andric // Determine where to find the PS4/PS5 libraries.
34106c3fb27SDimitry Andric // If -isysroot was passed, use that as the SDK base path.
34206c3fb27SDimitry Andric // If not, we use the EnvVar if it exists; otherwise use the driver's
34306c3fb27SDimitry Andric // installation path, which should be <SDK_DIR>/host_tools/bin.
34406c3fb27SDimitry Andric SmallString<80> Whence;
34506c3fb27SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
34606c3fb27SDimitry Andric SDKRootDir = A->getValue();
34706c3fb27SDimitry Andric if (!llvm::sys::fs::exists(SDKRootDir))
34806c3fb27SDimitry Andric D.Diag(clang::diag::warn_missing_sysroot) << SDKRootDir;
34906c3fb27SDimitry Andric Whence = A->getSpelling();
35006c3fb27SDimitry Andric } else if (const char *EnvValue = getenv(EnvVar)) {
35106c3fb27SDimitry Andric SDKRootDir = EnvValue;
35206c3fb27SDimitry Andric Whence = { "environment variable '", EnvVar, "'" };
3530b57cec5SDimitry Andric } else {
35406c3fb27SDimitry Andric SDKRootDir = D.Dir + "/../../";
35506c3fb27SDimitry Andric Whence = "compiler's location";
3560b57cec5SDimitry Andric }
3570b57cec5SDimitry Andric
35806c3fb27SDimitry Andric SmallString<512> SDKIncludeDir(SDKRootDir);
35981ad6265SDimitry Andric llvm::sys::path::append(SDKIncludeDir, "target/include");
3600b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_nostdinc) &&
3610b57cec5SDimitry Andric !Args.hasArg(options::OPT_nostdlibinc) &&
3620b57cec5SDimitry Andric !Args.hasArg(options::OPT_isysroot) &&
3630b57cec5SDimitry Andric !Args.hasArg(options::OPT__sysroot_EQ) &&
36481ad6265SDimitry Andric !llvm::sys::fs::exists(SDKIncludeDir)) {
36581ad6265SDimitry Andric D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
36606c3fb27SDimitry Andric << Twine(Platform, " system headers").str() << SDKIncludeDir << Whence;
3670b57cec5SDimitry Andric }
3680b57cec5SDimitry Andric
36906c3fb27SDimitry Andric SmallString<512> SDKLibDir(SDKRootDir);
37081ad6265SDimitry Andric llvm::sys::path::append(SDKLibDir, "target/lib");
3710b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_nostdlib) &&
3720b57cec5SDimitry Andric !Args.hasArg(options::OPT_nodefaultlibs) &&
3730b57cec5SDimitry Andric !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) &&
3740b57cec5SDimitry Andric !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) &&
3750b57cec5SDimitry Andric !Args.hasArg(options::OPT_emit_ast) &&
37681ad6265SDimitry Andric !llvm::sys::fs::exists(SDKLibDir)) {
37781ad6265SDimitry Andric D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
37806c3fb27SDimitry Andric << Twine(Platform, " system libraries").str() << SDKLibDir << Whence;
3790b57cec5SDimitry Andric return;
3800b57cec5SDimitry Andric }
3817a6dacacSDimitry Andric getFilePaths().push_back(std::string(SDKLibDir));
3820b57cec5SDimitry Andric }
3830b57cec5SDimitry Andric
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const38406c3fb27SDimitry Andric void toolchains::PS4PS5Base::AddClangSystemIncludeArgs(
38506c3fb27SDimitry Andric const ArgList &DriverArgs,
38606c3fb27SDimitry Andric ArgStringList &CC1Args) const {
38706c3fb27SDimitry Andric const Driver &D = getDriver();
38806c3fb27SDimitry Andric
38906c3fb27SDimitry Andric if (DriverArgs.hasArg(options::OPT_nostdinc))
39006c3fb27SDimitry Andric return;
39106c3fb27SDimitry Andric
39206c3fb27SDimitry Andric if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
39306c3fb27SDimitry Andric SmallString<128> Dir(D.ResourceDir);
39406c3fb27SDimitry Andric llvm::sys::path::append(Dir, "include");
39506c3fb27SDimitry Andric addSystemInclude(DriverArgs, CC1Args, Dir.str());
39606c3fb27SDimitry Andric }
39706c3fb27SDimitry Andric
39806c3fb27SDimitry Andric if (DriverArgs.hasArg(options::OPT_nostdlibinc))
39906c3fb27SDimitry Andric return;
40006c3fb27SDimitry Andric
40106c3fb27SDimitry Andric addExternCSystemInclude(DriverArgs, CC1Args,
40206c3fb27SDimitry Andric SDKRootDir + "/target/include");
40306c3fb27SDimitry Andric addExternCSystemInclude(DriverArgs, CC1Args,
40406c3fb27SDimitry Andric SDKRootDir + "/target/include_common");
40506c3fb27SDimitry Andric }
40606c3fb27SDimitry Andric
buildAssembler() const4070b57cec5SDimitry Andric Tool *toolchains::PS4CPU::buildAssembler() const {
40881ad6265SDimitry Andric return new tools::PScpu::Assembler(*this);
4090b57cec5SDimitry Andric }
4100b57cec5SDimitry Andric
buildLinker() const411*0fca6ea1SDimitry Andric Tool *toolchains::PS4CPU::buildLinker() const {
412*0fca6ea1SDimitry Andric return new tools::PS4cpu::Linker(*this);
413*0fca6ea1SDimitry Andric }
414*0fca6ea1SDimitry Andric
buildAssembler() const41581ad6265SDimitry Andric Tool *toolchains::PS5CPU::buildAssembler() const {
41681ad6265SDimitry Andric // PS5 does not support an external assembler.
41781ad6265SDimitry Andric getDriver().Diag(clang::diag::err_no_external_assembler);
41881ad6265SDimitry Andric return nullptr;
4190b57cec5SDimitry Andric }
4200b57cec5SDimitry Andric
buildLinker() const421*0fca6ea1SDimitry Andric Tool *toolchains::PS5CPU::buildLinker() const {
422*0fca6ea1SDimitry Andric return new tools::PS5cpu::Linker(*this);
42381ad6265SDimitry Andric }
4240b57cec5SDimitry Andric
getSupportedSanitizers() const42581ad6265SDimitry Andric SanitizerMask toolchains::PS4PS5Base::getSupportedSanitizers() const {
4260b57cec5SDimitry Andric SanitizerMask Res = ToolChain::getSupportedSanitizers();
4270b57cec5SDimitry Andric Res |= SanitizerKind::Address;
4280b57cec5SDimitry Andric Res |= SanitizerKind::PointerCompare;
4290b57cec5SDimitry Andric Res |= SanitizerKind::PointerSubtract;
4300b57cec5SDimitry Andric Res |= SanitizerKind::Vptr;
4310b57cec5SDimitry Andric return Res;
4320b57cec5SDimitry Andric }
4335ffd83dbSDimitry Andric
getSupportedSanitizers() const43481ad6265SDimitry Andric SanitizerMask toolchains::PS5CPU::getSupportedSanitizers() const {
43581ad6265SDimitry Andric SanitizerMask Res = PS4PS5Base::getSupportedSanitizers();
43681ad6265SDimitry Andric Res |= SanitizerKind::Thread;
43781ad6265SDimitry Andric return Res;
43881ad6265SDimitry Andric }
43981ad6265SDimitry Andric
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind DeviceOffloadingKind) const44081ad6265SDimitry Andric void toolchains::PS4PS5Base::addClangTargetOptions(
441e8d8bef9SDimitry Andric const ArgList &DriverArgs, ArgStringList &CC1Args,
4425ffd83dbSDimitry Andric Action::OffloadKind DeviceOffloadingKind) const {
44381ad6265SDimitry Andric // PS4/PS5 do not use init arrays.
4445ffd83dbSDimitry Andric if (DriverArgs.hasArg(options::OPT_fuse_init_array)) {
4455ffd83dbSDimitry Andric Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array);
4465ffd83dbSDimitry Andric getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target)
4475ffd83dbSDimitry Andric << A->getAsString(DriverArgs) << getTriple().str();
4485ffd83dbSDimitry Andric }
4495ffd83dbSDimitry Andric
4505ffd83dbSDimitry Andric CC1Args.push_back("-fno-use-init-array");
451e8d8bef9SDimitry Andric
452*0fca6ea1SDimitry Andric // Default to `hidden` visibility for PS5.
453*0fca6ea1SDimitry Andric if (getTriple().isPS5() &&
454*0fca6ea1SDimitry Andric !DriverArgs.hasArg(options::OPT_fvisibility_EQ,
455*0fca6ea1SDimitry Andric options::OPT_fvisibility_ms_compat))
456*0fca6ea1SDimitry Andric CC1Args.push_back("-fvisibility=hidden");
457*0fca6ea1SDimitry Andric
4587a6dacacSDimitry Andric // Default to -fvisibility-global-new-delete=source for PS5.
4597a6dacacSDimitry Andric if (getTriple().isPS5() &&
4607a6dacacSDimitry Andric !DriverArgs.hasArg(options::OPT_fvisibility_global_new_delete_EQ,
4617a6dacacSDimitry Andric options::OPT_fvisibility_global_new_delete_hidden))
4627a6dacacSDimitry Andric CC1Args.push_back("-fvisibility-global-new-delete=source");
4637a6dacacSDimitry Andric
464e8d8bef9SDimitry Andric const Arg *A =
465e8d8bef9SDimitry Andric DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
466e8d8bef9SDimitry Andric options::OPT_fno_visibility_from_dllstorageclass);
467e8d8bef9SDimitry Andric if (!A ||
468e8d8bef9SDimitry Andric A->getOption().matches(options::OPT_fvisibility_from_dllstorageclass)) {
469e8d8bef9SDimitry Andric CC1Args.push_back("-fvisibility-from-dllstorageclass");
470e8d8bef9SDimitry Andric
471e8d8bef9SDimitry Andric if (DriverArgs.hasArg(options::OPT_fvisibility_dllexport_EQ))
472e8d8bef9SDimitry Andric DriverArgs.AddLastArg(CC1Args, options::OPT_fvisibility_dllexport_EQ);
473e8d8bef9SDimitry Andric else
474e8d8bef9SDimitry Andric CC1Args.push_back("-fvisibility-dllexport=protected");
475e8d8bef9SDimitry Andric
476*0fca6ea1SDimitry Andric // For PS4 we override the visibilty of globals definitions without
477*0fca6ea1SDimitry Andric // dllimport or dllexport annotations.
478e8d8bef9SDimitry Andric if (DriverArgs.hasArg(options::OPT_fvisibility_nodllstorageclass_EQ))
479e8d8bef9SDimitry Andric DriverArgs.AddLastArg(CC1Args,
480e8d8bef9SDimitry Andric options::OPT_fvisibility_nodllstorageclass_EQ);
481*0fca6ea1SDimitry Andric else if (getTriple().isPS4())
482e8d8bef9SDimitry Andric CC1Args.push_back("-fvisibility-nodllstorageclass=hidden");
483*0fca6ea1SDimitry Andric else
484*0fca6ea1SDimitry Andric CC1Args.push_back("-fvisibility-nodllstorageclass=keep");
485e8d8bef9SDimitry Andric
486e8d8bef9SDimitry Andric if (DriverArgs.hasArg(options::OPT_fvisibility_externs_dllimport_EQ))
487e8d8bef9SDimitry Andric DriverArgs.AddLastArg(CC1Args,
488e8d8bef9SDimitry Andric options::OPT_fvisibility_externs_dllimport_EQ);
489e8d8bef9SDimitry Andric else
490e8d8bef9SDimitry Andric CC1Args.push_back("-fvisibility-externs-dllimport=default");
491e8d8bef9SDimitry Andric
492*0fca6ea1SDimitry Andric // For PS4 we override the visibilty of external globals without
493*0fca6ea1SDimitry Andric // dllimport or dllexport annotations.
494e8d8bef9SDimitry Andric if (DriverArgs.hasArg(
495e8d8bef9SDimitry Andric options::OPT_fvisibility_externs_nodllstorageclass_EQ))
496e8d8bef9SDimitry Andric DriverArgs.AddLastArg(
497e8d8bef9SDimitry Andric CC1Args, options::OPT_fvisibility_externs_nodllstorageclass_EQ);
498*0fca6ea1SDimitry Andric else if (getTriple().isPS4())
499e8d8bef9SDimitry Andric CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default");
500*0fca6ea1SDimitry Andric else
501*0fca6ea1SDimitry Andric CC1Args.push_back("-fvisibility-externs-nodllstorageclass=keep");
502e8d8bef9SDimitry Andric }
5035ffd83dbSDimitry Andric }
50481ad6265SDimitry Andric
50581ad6265SDimitry Andric // PS4 toolchain.
PS4CPU(const Driver & D,const llvm::Triple & Triple,const llvm::opt::ArgList & Args)50681ad6265SDimitry Andric toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple,
50781ad6265SDimitry Andric const llvm::opt::ArgList &Args)
50881ad6265SDimitry Andric : PS4PS5Base(D, Triple, Args, "PS4", "SCE_ORBIS_SDK_DIR") {}
50981ad6265SDimitry Andric
51081ad6265SDimitry Andric // PS5 toolchain.
PS5CPU(const Driver & D,const llvm::Triple & Triple,const llvm::opt::ArgList & Args)51181ad6265SDimitry Andric toolchains::PS5CPU::PS5CPU(const Driver &D, const llvm::Triple &Triple,
51281ad6265SDimitry Andric const llvm::opt::ArgList &Args)
51381ad6265SDimitry Andric : PS4PS5Base(D, Triple, Args, "PS5", "SCE_PROSPERO_SDK_DIR") {}
514