17330f729Sjoerg //===--- PS4CPU.cpp - PS4CPU ToolChain Implementations ----------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
97330f729Sjoerg #include "PS4CPU.h"
107330f729Sjoerg #include "FreeBSD.h"
117330f729Sjoerg #include "CommonArgs.h"
127330f729Sjoerg #include "clang/Driver/Compilation.h"
137330f729Sjoerg #include "clang/Driver/Driver.h"
147330f729Sjoerg #include "clang/Driver/DriverDiagnostic.h"
157330f729Sjoerg #include "clang/Driver/Options.h"
167330f729Sjoerg #include "clang/Driver/SanitizerArgs.h"
177330f729Sjoerg #include "llvm/Option/ArgList.h"
187330f729Sjoerg #include "llvm/Support/FileSystem.h"
197330f729Sjoerg #include "llvm/Support/Path.h"
207330f729Sjoerg #include <cstdlib> // ::getenv
217330f729Sjoerg
227330f729Sjoerg using namespace clang::driver;
237330f729Sjoerg using namespace clang;
247330f729Sjoerg using namespace llvm::opt;
257330f729Sjoerg
267330f729Sjoerg using clang::driver::tools::AddLinkerInputs;
277330f729Sjoerg
addProfileRTArgs(const ToolChain & TC,const ArgList & Args,ArgStringList & CmdArgs)287330f729Sjoerg void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
297330f729Sjoerg ArgStringList &CmdArgs) {
307330f729Sjoerg if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
317330f729Sjoerg false) ||
327330f729Sjoerg Args.hasFlag(options::OPT_fprofile_generate,
33*e038c9c4Sjoerg options::OPT_fno_profile_generate, false) ||
347330f729Sjoerg Args.hasFlag(options::OPT_fprofile_generate_EQ,
35*e038c9c4Sjoerg options::OPT_fno_profile_generate, false) ||
367330f729Sjoerg Args.hasFlag(options::OPT_fprofile_instr_generate,
377330f729Sjoerg options::OPT_fno_profile_instr_generate, false) ||
387330f729Sjoerg Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
397330f729Sjoerg options::OPT_fno_profile_instr_generate, false) ||
40*e038c9c4Sjoerg Args.hasFlag(options::OPT_fcs_profile_generate,
41*e038c9c4Sjoerg options::OPT_fno_profile_generate, false) ||
42*e038c9c4Sjoerg Args.hasFlag(options::OPT_fcs_profile_generate_EQ,
43*e038c9c4Sjoerg options::OPT_fno_profile_generate, false) ||
447330f729Sjoerg Args.hasArg(options::OPT_fcreate_profile) ||
457330f729Sjoerg Args.hasArg(options::OPT_coverage)))
467330f729Sjoerg CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a");
477330f729Sjoerg }
487330f729Sjoerg
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const497330f729Sjoerg void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
507330f729Sjoerg const InputInfo &Output,
517330f729Sjoerg const InputInfoList &Inputs,
527330f729Sjoerg const ArgList &Args,
537330f729Sjoerg const char *LinkingOutput) const {
547330f729Sjoerg claimNoWarnArgs(Args);
557330f729Sjoerg ArgStringList CmdArgs;
567330f729Sjoerg
577330f729Sjoerg Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
587330f729Sjoerg
597330f729Sjoerg CmdArgs.push_back("-o");
607330f729Sjoerg CmdArgs.push_back(Output.getFilename());
617330f729Sjoerg
627330f729Sjoerg assert(Inputs.size() == 1 && "Unexpected number of inputs.");
637330f729Sjoerg const InputInfo &Input = Inputs[0];
647330f729Sjoerg assert(Input.isFilename() && "Invalid input.");
657330f729Sjoerg CmdArgs.push_back(Input.getFilename());
667330f729Sjoerg
677330f729Sjoerg const char *Exec =
687330f729Sjoerg Args.MakeArgString(getToolChain().GetProgramPath("orbis-as"));
69*e038c9c4Sjoerg C.addCommand(std::make_unique<Command>(JA, *this,
70*e038c9c4Sjoerg ResponseFileSupport::AtFileUTF8(),
71*e038c9c4Sjoerg Exec, CmdArgs, Inputs, Output));
727330f729Sjoerg }
737330f729Sjoerg
AddPS4SanitizerArgs(const ToolChain & TC,ArgStringList & CmdArgs)747330f729Sjoerg static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) {
757330f729Sjoerg const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
767330f729Sjoerg if (SanArgs.needsUbsanRt()) {
777330f729Sjoerg CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak");
787330f729Sjoerg }
797330f729Sjoerg if (SanArgs.needsAsanRt()) {
807330f729Sjoerg CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak");
817330f729Sjoerg }
827330f729Sjoerg }
837330f729Sjoerg
addSanitizerArgs(const ToolChain & TC,ArgStringList & CmdArgs)847330f729Sjoerg void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC,
857330f729Sjoerg ArgStringList &CmdArgs) {
867330f729Sjoerg const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
877330f729Sjoerg if (SanArgs.needsUbsanRt())
887330f729Sjoerg CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a");
897330f729Sjoerg if (SanArgs.needsAsanRt())
907330f729Sjoerg CmdArgs.push_back("--dependent-lib=libSceDbgAddressSanitizer_stub_weak.a");
917330f729Sjoerg }
927330f729Sjoerg
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const93*e038c9c4Sjoerg void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA,
94*e038c9c4Sjoerg const InputInfo &Output,
957330f729Sjoerg const InputInfoList &Inputs,
967330f729Sjoerg const ArgList &Args,
97*e038c9c4Sjoerg const char *LinkingOutput) const {
987330f729Sjoerg const toolchains::FreeBSD &ToolChain =
99*e038c9c4Sjoerg static_cast<const toolchains::FreeBSD &>(getToolChain());
1007330f729Sjoerg const Driver &D = ToolChain.getDriver();
1017330f729Sjoerg ArgStringList CmdArgs;
1027330f729Sjoerg
1037330f729Sjoerg // Silence warning for "clang -g foo.o -o foo"
1047330f729Sjoerg Args.ClaimAllArgs(options::OPT_g_Group);
1057330f729Sjoerg // and "clang -emit-llvm foo.o -o foo"
1067330f729Sjoerg Args.ClaimAllArgs(options::OPT_emit_llvm);
1077330f729Sjoerg // and for "clang -w foo.o -o foo". Other warning options are already
1087330f729Sjoerg // handled somewhere else.
1097330f729Sjoerg Args.ClaimAllArgs(options::OPT_w);
1107330f729Sjoerg
1117330f729Sjoerg if (!D.SysRoot.empty())
1127330f729Sjoerg CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
1137330f729Sjoerg
1147330f729Sjoerg if (Args.hasArg(options::OPT_pie))
1157330f729Sjoerg CmdArgs.push_back("-pie");
1167330f729Sjoerg
1177330f729Sjoerg if (Args.hasArg(options::OPT_rdynamic))
1187330f729Sjoerg CmdArgs.push_back("-export-dynamic");
1197330f729Sjoerg if (Args.hasArg(options::OPT_shared))
1207330f729Sjoerg CmdArgs.push_back("--oformat=so");
1217330f729Sjoerg
1227330f729Sjoerg if (Output.isFilename()) {
1237330f729Sjoerg CmdArgs.push_back("-o");
1247330f729Sjoerg CmdArgs.push_back(Output.getFilename());
1257330f729Sjoerg } else {
1267330f729Sjoerg assert(Output.isNothing() && "Invalid output.");
1277330f729Sjoerg }
1287330f729Sjoerg
1297330f729Sjoerg if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
1307330f729Sjoerg AddPS4SanitizerArgs(ToolChain, CmdArgs);
1317330f729Sjoerg
1327330f729Sjoerg Args.AddAllArgs(CmdArgs, options::OPT_L);
1337330f729Sjoerg Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
1347330f729Sjoerg Args.AddAllArgs(CmdArgs, options::OPT_e);
1357330f729Sjoerg Args.AddAllArgs(CmdArgs, options::OPT_s);
1367330f729Sjoerg Args.AddAllArgs(CmdArgs, options::OPT_t);
1377330f729Sjoerg Args.AddAllArgs(CmdArgs, options::OPT_r);
1387330f729Sjoerg
1397330f729Sjoerg if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
1407330f729Sjoerg CmdArgs.push_back("--no-demangle");
1417330f729Sjoerg
1427330f729Sjoerg AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
1437330f729Sjoerg
1447330f729Sjoerg if (Args.hasArg(options::OPT_pthread)) {
1457330f729Sjoerg CmdArgs.push_back("-lpthread");
1467330f729Sjoerg }
1477330f729Sjoerg
148*e038c9c4Sjoerg if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
149*e038c9c4Sjoerg D.Diag(diag::err_drv_unsupported_opt_for_target)
150*e038c9c4Sjoerg << "-fuse-ld" << getToolChain().getTriple().str();
1517330f729Sjoerg }
1527330f729Sjoerg
1537330f729Sjoerg const char *Exec =
1547330f729Sjoerg Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld"));
1557330f729Sjoerg
156*e038c9c4Sjoerg C.addCommand(std::make_unique<Command>(JA, *this,
157*e038c9c4Sjoerg ResponseFileSupport::AtFileUTF8(),
158*e038c9c4Sjoerg Exec, CmdArgs, Inputs, Output));
1597330f729Sjoerg }
1607330f729Sjoerg
PS4CPU(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)1617330f729Sjoerg toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple,
1627330f729Sjoerg const ArgList &Args)
1637330f729Sjoerg : Generic_ELF(D, Triple, Args) {
1647330f729Sjoerg if (Args.hasArg(clang::driver::options::OPT_static))
1657330f729Sjoerg D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static"
1667330f729Sjoerg << "PS4";
1677330f729Sjoerg
1687330f729Sjoerg // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR
1697330f729Sjoerg // if it exists; otherwise use the driver's installation path, which
1707330f729Sjoerg // should be <SDK_DIR>/host_tools/bin.
1717330f729Sjoerg
1727330f729Sjoerg SmallString<512> PS4SDKDir;
1737330f729Sjoerg if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) {
1747330f729Sjoerg if (!llvm::sys::fs::exists(EnvValue))
1757330f729Sjoerg getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue;
1767330f729Sjoerg PS4SDKDir = EnvValue;
1777330f729Sjoerg } else {
1787330f729Sjoerg PS4SDKDir = getDriver().Dir;
1797330f729Sjoerg llvm::sys::path::append(PS4SDKDir, "/../../");
1807330f729Sjoerg }
1817330f729Sjoerg
1827330f729Sjoerg // By default, the driver won't report a warning if it can't find
1837330f729Sjoerg // PS4's include or lib directories. This behavior could be changed if
1847330f729Sjoerg // -Weverything or -Winvalid-or-nonexistent-directory options are passed.
1857330f729Sjoerg // If -isysroot was passed, use that as the SDK base path.
1867330f729Sjoerg std::string PrefixDir;
1877330f729Sjoerg if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
1887330f729Sjoerg PrefixDir = A->getValue();
1897330f729Sjoerg if (!llvm::sys::fs::exists(PrefixDir))
1907330f729Sjoerg getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir;
1917330f729Sjoerg } else
192*e038c9c4Sjoerg PrefixDir = std::string(PS4SDKDir.str());
1937330f729Sjoerg
1947330f729Sjoerg SmallString<512> PS4SDKIncludeDir(PrefixDir);
1957330f729Sjoerg llvm::sys::path::append(PS4SDKIncludeDir, "target/include");
1967330f729Sjoerg if (!Args.hasArg(options::OPT_nostdinc) &&
1977330f729Sjoerg !Args.hasArg(options::OPT_nostdlibinc) &&
1987330f729Sjoerg !Args.hasArg(options::OPT_isysroot) &&
1997330f729Sjoerg !Args.hasArg(options::OPT__sysroot_EQ) &&
2007330f729Sjoerg !llvm::sys::fs::exists(PS4SDKIncludeDir)) {
2017330f729Sjoerg getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
2027330f729Sjoerg << "PS4 system headers" << PS4SDKIncludeDir;
2037330f729Sjoerg }
2047330f729Sjoerg
2057330f729Sjoerg SmallString<512> PS4SDKLibDir(PS4SDKDir);
2067330f729Sjoerg llvm::sys::path::append(PS4SDKLibDir, "target/lib");
2077330f729Sjoerg if (!Args.hasArg(options::OPT_nostdlib) &&
2087330f729Sjoerg !Args.hasArg(options::OPT_nodefaultlibs) &&
2097330f729Sjoerg !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) &&
2107330f729Sjoerg !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) &&
2117330f729Sjoerg !Args.hasArg(options::OPT_emit_ast) &&
2127330f729Sjoerg !llvm::sys::fs::exists(PS4SDKLibDir)) {
2137330f729Sjoerg getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
2147330f729Sjoerg << "PS4 system libraries" << PS4SDKLibDir;
2157330f729Sjoerg return;
2167330f729Sjoerg }
217*e038c9c4Sjoerg getFilePaths().push_back(std::string(PS4SDKLibDir.str()));
2187330f729Sjoerg }
2197330f729Sjoerg
buildAssembler() const2207330f729Sjoerg Tool *toolchains::PS4CPU::buildAssembler() const {
2217330f729Sjoerg return new tools::PS4cpu::Assemble(*this);
2227330f729Sjoerg }
2237330f729Sjoerg
buildLinker() const2247330f729Sjoerg Tool *toolchains::PS4CPU::buildLinker() const {
2257330f729Sjoerg return new tools::PS4cpu::Link(*this);
2267330f729Sjoerg }
2277330f729Sjoerg
isPICDefault() const2287330f729Sjoerg bool toolchains::PS4CPU::isPICDefault() const { return true; }
2297330f729Sjoerg
HasNativeLLVMSupport() const2307330f729Sjoerg bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; }
2317330f729Sjoerg
getSupportedSanitizers() const2327330f729Sjoerg SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const {
2337330f729Sjoerg SanitizerMask Res = ToolChain::getSupportedSanitizers();
2347330f729Sjoerg Res |= SanitizerKind::Address;
2357330f729Sjoerg Res |= SanitizerKind::PointerCompare;
2367330f729Sjoerg Res |= SanitizerKind::PointerSubtract;
2377330f729Sjoerg Res |= SanitizerKind::Vptr;
2387330f729Sjoerg return Res;
2397330f729Sjoerg }
240*e038c9c4Sjoerg
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind DeviceOffloadingKind) const241*e038c9c4Sjoerg void toolchains::PS4CPU::addClangTargetOptions(
242*e038c9c4Sjoerg const ArgList &DriverArgs, ArgStringList &CC1Args,
243*e038c9c4Sjoerg Action::OffloadKind DeviceOffloadingKind) const {
244*e038c9c4Sjoerg // PS4 does not use init arrays.
245*e038c9c4Sjoerg if (DriverArgs.hasArg(options::OPT_fuse_init_array)) {
246*e038c9c4Sjoerg Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array);
247*e038c9c4Sjoerg getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target)
248*e038c9c4Sjoerg << A->getAsString(DriverArgs) << getTriple().str();
249*e038c9c4Sjoerg }
250*e038c9c4Sjoerg
251*e038c9c4Sjoerg CC1Args.push_back("-fno-use-init-array");
252*e038c9c4Sjoerg
253*e038c9c4Sjoerg const Arg *A =
254*e038c9c4Sjoerg DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
255*e038c9c4Sjoerg options::OPT_fno_visibility_from_dllstorageclass);
256*e038c9c4Sjoerg if (!A ||
257*e038c9c4Sjoerg A->getOption().matches(options::OPT_fvisibility_from_dllstorageclass)) {
258*e038c9c4Sjoerg CC1Args.push_back("-fvisibility-from-dllstorageclass");
259*e038c9c4Sjoerg
260*e038c9c4Sjoerg if (DriverArgs.hasArg(options::OPT_fvisibility_dllexport_EQ))
261*e038c9c4Sjoerg DriverArgs.AddLastArg(CC1Args, options::OPT_fvisibility_dllexport_EQ);
262*e038c9c4Sjoerg else
263*e038c9c4Sjoerg CC1Args.push_back("-fvisibility-dllexport=protected");
264*e038c9c4Sjoerg
265*e038c9c4Sjoerg if (DriverArgs.hasArg(options::OPT_fvisibility_nodllstorageclass_EQ))
266*e038c9c4Sjoerg DriverArgs.AddLastArg(CC1Args,
267*e038c9c4Sjoerg options::OPT_fvisibility_nodllstorageclass_EQ);
268*e038c9c4Sjoerg else
269*e038c9c4Sjoerg CC1Args.push_back("-fvisibility-nodllstorageclass=hidden");
270*e038c9c4Sjoerg
271*e038c9c4Sjoerg if (DriverArgs.hasArg(options::OPT_fvisibility_externs_dllimport_EQ))
272*e038c9c4Sjoerg DriverArgs.AddLastArg(CC1Args,
273*e038c9c4Sjoerg options::OPT_fvisibility_externs_dllimport_EQ);
274*e038c9c4Sjoerg else
275*e038c9c4Sjoerg CC1Args.push_back("-fvisibility-externs-dllimport=default");
276*e038c9c4Sjoerg
277*e038c9c4Sjoerg if (DriverArgs.hasArg(
278*e038c9c4Sjoerg options::OPT_fvisibility_externs_nodllstorageclass_EQ))
279*e038c9c4Sjoerg DriverArgs.AddLastArg(
280*e038c9c4Sjoerg CC1Args, options::OPT_fvisibility_externs_nodllstorageclass_EQ);
281*e038c9c4Sjoerg else
282*e038c9c4Sjoerg CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default");
283*e038c9c4Sjoerg }
284*e038c9c4Sjoerg }
285