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 "FreeBSD.h" 110b57cec5SDimitry Andric #include "CommonArgs.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 260b57cec5SDimitry Andric using clang::driver::tools::AddLinkerInputs; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, 290b57cec5SDimitry Andric ArgStringList &CmdArgs) { 300b57cec5SDimitry Andric if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, 310b57cec5SDimitry Andric false) || 320b57cec5SDimitry Andric Args.hasFlag(options::OPT_fprofile_generate, 33*5ffd83dbSDimitry Andric options::OPT_fno_profile_generate, false) || 340b57cec5SDimitry Andric Args.hasFlag(options::OPT_fprofile_generate_EQ, 35*5ffd83dbSDimitry Andric options::OPT_fno_profile_generate, false) || 360b57cec5SDimitry Andric Args.hasFlag(options::OPT_fprofile_instr_generate, 370b57cec5SDimitry Andric options::OPT_fno_profile_instr_generate, false) || 380b57cec5SDimitry Andric Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, 390b57cec5SDimitry Andric options::OPT_fno_profile_instr_generate, false) || 40*5ffd83dbSDimitry Andric Args.hasFlag(options::OPT_fcs_profile_generate, 41*5ffd83dbSDimitry Andric options::OPT_fno_profile_generate, false) || 42*5ffd83dbSDimitry Andric Args.hasFlag(options::OPT_fcs_profile_generate_EQ, 43*5ffd83dbSDimitry Andric options::OPT_fno_profile_generate, false) || 440b57cec5SDimitry Andric Args.hasArg(options::OPT_fcreate_profile) || 450b57cec5SDimitry Andric Args.hasArg(options::OPT_coverage))) 460b57cec5SDimitry Andric CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a"); 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, 500b57cec5SDimitry Andric const InputInfo &Output, 510b57cec5SDimitry Andric const InputInfoList &Inputs, 520b57cec5SDimitry Andric const ArgList &Args, 530b57cec5SDimitry Andric const char *LinkingOutput) const { 540b57cec5SDimitry Andric claimNoWarnArgs(Args); 550b57cec5SDimitry Andric ArgStringList CmdArgs; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric CmdArgs.push_back("-o"); 600b57cec5SDimitry Andric CmdArgs.push_back(Output.getFilename()); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric assert(Inputs.size() == 1 && "Unexpected number of inputs."); 630b57cec5SDimitry Andric const InputInfo &Input = Inputs[0]; 640b57cec5SDimitry Andric assert(Input.isFilename() && "Invalid input."); 650b57cec5SDimitry Andric CmdArgs.push_back(Input.getFilename()); 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric const char *Exec = 680b57cec5SDimitry Andric Args.MakeArgString(getToolChain().GetProgramPath("orbis-as")); 69*5ffd83dbSDimitry Andric C.addCommand(std::make_unique<Command>( 70*5ffd83dbSDimitry Andric JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { 740b57cec5SDimitry Andric const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); 750b57cec5SDimitry Andric if (SanArgs.needsUbsanRt()) { 760b57cec5SDimitry Andric CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric if (SanArgs.needsAsanRt()) { 790b57cec5SDimitry Andric CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak"); 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, 840b57cec5SDimitry Andric ArgStringList &CmdArgs) { 850b57cec5SDimitry Andric const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); 860b57cec5SDimitry Andric if (SanArgs.needsUbsanRt()) 870b57cec5SDimitry Andric CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a"); 880b57cec5SDimitry Andric if (SanArgs.needsAsanRt()) 890b57cec5SDimitry Andric CmdArgs.push_back("--dependent-lib=libSceDbgAddressSanitizer_stub_weak.a"); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 92*5ffd83dbSDimitry Andric void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, 93*5ffd83dbSDimitry Andric const InputInfo &Output, 940b57cec5SDimitry Andric const InputInfoList &Inputs, 950b57cec5SDimitry Andric const ArgList &Args, 96*5ffd83dbSDimitry Andric const char *LinkingOutput) const { 970b57cec5SDimitry Andric const toolchains::FreeBSD &ToolChain = 98*5ffd83dbSDimitry Andric static_cast<const toolchains::FreeBSD &>(getToolChain()); 990b57cec5SDimitry Andric const Driver &D = ToolChain.getDriver(); 1000b57cec5SDimitry Andric ArgStringList CmdArgs; 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric // Silence warning for "clang -g foo.o -o foo" 1030b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_g_Group); 1040b57cec5SDimitry Andric // and "clang -emit-llvm foo.o -o foo" 1050b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_emit_llvm); 1060b57cec5SDimitry Andric // and for "clang -w foo.o -o foo". Other warning options are already 1070b57cec5SDimitry Andric // handled somewhere else. 1080b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_w); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric if (!D.SysRoot.empty()) 1110b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric if (Args.hasArg(options::OPT_pie)) 1140b57cec5SDimitry Andric CmdArgs.push_back("-pie"); 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric if (Args.hasArg(options::OPT_rdynamic)) 1170b57cec5SDimitry Andric CmdArgs.push_back("-export-dynamic"); 1180b57cec5SDimitry Andric if (Args.hasArg(options::OPT_shared)) 1190b57cec5SDimitry Andric CmdArgs.push_back("--oformat=so"); 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric if (Output.isFilename()) { 1220b57cec5SDimitry Andric CmdArgs.push_back("-o"); 1230b57cec5SDimitry Andric CmdArgs.push_back(Output.getFilename()); 1240b57cec5SDimitry Andric } else { 1250b57cec5SDimitry Andric assert(Output.isNothing() && "Invalid output."); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) 1290b57cec5SDimitry Andric AddPS4SanitizerArgs(ToolChain, CmdArgs); 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_L); 1320b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_T_Group); 1330b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_e); 1340b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_s); 1350b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_t); 1360b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_r); 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) 1390b57cec5SDimitry Andric CmdArgs.push_back("--no-demangle"); 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric if (Args.hasArg(options::OPT_pthread)) { 1440b57cec5SDimitry Andric CmdArgs.push_back("-lpthread"); 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 147*5ffd83dbSDimitry Andric if (Args.hasArg(options::OPT_fuse_ld_EQ)) { 148*5ffd83dbSDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target) 149*5ffd83dbSDimitry Andric << "-fuse-ld" << getToolChain().getTriple().str(); 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric const char *Exec = 1530b57cec5SDimitry Andric Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); 1540b57cec5SDimitry Andric 155*5ffd83dbSDimitry Andric C.addCommand(std::make_unique<Command>( 156*5ffd83dbSDimitry Andric JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs)); 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, 1600b57cec5SDimitry Andric const ArgList &Args) 1610b57cec5SDimitry Andric : Generic_ELF(D, Triple, Args) { 1620b57cec5SDimitry Andric if (Args.hasArg(clang::driver::options::OPT_static)) 1630b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static" 1640b57cec5SDimitry Andric << "PS4"; 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR 1670b57cec5SDimitry Andric // if it exists; otherwise use the driver's installation path, which 1680b57cec5SDimitry Andric // should be <SDK_DIR>/host_tools/bin. 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric SmallString<512> PS4SDKDir; 1710b57cec5SDimitry Andric if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) { 1720b57cec5SDimitry Andric if (!llvm::sys::fs::exists(EnvValue)) 1730b57cec5SDimitry Andric getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; 1740b57cec5SDimitry Andric PS4SDKDir = EnvValue; 1750b57cec5SDimitry Andric } else { 1760b57cec5SDimitry Andric PS4SDKDir = getDriver().Dir; 1770b57cec5SDimitry Andric llvm::sys::path::append(PS4SDKDir, "/../../"); 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric // By default, the driver won't report a warning if it can't find 1810b57cec5SDimitry Andric // PS4's include or lib directories. This behavior could be changed if 1820b57cec5SDimitry Andric // -Weverything or -Winvalid-or-nonexistent-directory options are passed. 1830b57cec5SDimitry Andric // If -isysroot was passed, use that as the SDK base path. 1840b57cec5SDimitry Andric std::string PrefixDir; 1850b57cec5SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { 1860b57cec5SDimitry Andric PrefixDir = A->getValue(); 1870b57cec5SDimitry Andric if (!llvm::sys::fs::exists(PrefixDir)) 1880b57cec5SDimitry Andric getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; 1890b57cec5SDimitry Andric } else 190*5ffd83dbSDimitry Andric PrefixDir = std::string(PS4SDKDir.str()); 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric SmallString<512> PS4SDKIncludeDir(PrefixDir); 1930b57cec5SDimitry Andric llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); 1940b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_nostdinc) && 1950b57cec5SDimitry Andric !Args.hasArg(options::OPT_nostdlibinc) && 1960b57cec5SDimitry Andric !Args.hasArg(options::OPT_isysroot) && 1970b57cec5SDimitry Andric !Args.hasArg(options::OPT__sysroot_EQ) && 1980b57cec5SDimitry Andric !llvm::sys::fs::exists(PS4SDKIncludeDir)) { 1990b57cec5SDimitry Andric getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) 2000b57cec5SDimitry Andric << "PS4 system headers" << PS4SDKIncludeDir; 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric SmallString<512> PS4SDKLibDir(PS4SDKDir); 2040b57cec5SDimitry Andric llvm::sys::path::append(PS4SDKLibDir, "target/lib"); 2050b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_nostdlib) && 2060b57cec5SDimitry Andric !Args.hasArg(options::OPT_nodefaultlibs) && 2070b57cec5SDimitry Andric !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && 2080b57cec5SDimitry Andric !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && 2090b57cec5SDimitry Andric !Args.hasArg(options::OPT_emit_ast) && 2100b57cec5SDimitry Andric !llvm::sys::fs::exists(PS4SDKLibDir)) { 2110b57cec5SDimitry Andric getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) 2120b57cec5SDimitry Andric << "PS4 system libraries" << PS4SDKLibDir; 2130b57cec5SDimitry Andric return; 2140b57cec5SDimitry Andric } 215*5ffd83dbSDimitry Andric getFilePaths().push_back(std::string(PS4SDKLibDir.str())); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric Tool *toolchains::PS4CPU::buildAssembler() const { 2190b57cec5SDimitry Andric return new tools::PS4cpu::Assemble(*this); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric Tool *toolchains::PS4CPU::buildLinker() const { 2230b57cec5SDimitry Andric return new tools::PS4cpu::Link(*this); 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric bool toolchains::PS4CPU::isPICDefault() const { return true; } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { 2310b57cec5SDimitry Andric SanitizerMask Res = ToolChain::getSupportedSanitizers(); 2320b57cec5SDimitry Andric Res |= SanitizerKind::Address; 2330b57cec5SDimitry Andric Res |= SanitizerKind::PointerCompare; 2340b57cec5SDimitry Andric Res |= SanitizerKind::PointerSubtract; 2350b57cec5SDimitry Andric Res |= SanitizerKind::Vptr; 2360b57cec5SDimitry Andric return Res; 2370b57cec5SDimitry Andric } 238*5ffd83dbSDimitry Andric 239*5ffd83dbSDimitry Andric void toolchains::PS4CPU::addClangTargetOptions( 240*5ffd83dbSDimitry Andric const ArgList &DriverArgs, 241*5ffd83dbSDimitry Andric ArgStringList &CC1Args, 242*5ffd83dbSDimitry Andric Action::OffloadKind DeviceOffloadingKind) const { 243*5ffd83dbSDimitry Andric // PS4 does not use init arrays. 244*5ffd83dbSDimitry Andric if (DriverArgs.hasArg(options::OPT_fuse_init_array)) { 245*5ffd83dbSDimitry Andric Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array); 246*5ffd83dbSDimitry Andric getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target) 247*5ffd83dbSDimitry Andric << A->getAsString(DriverArgs) << getTriple().str(); 248*5ffd83dbSDimitry Andric } 249*5ffd83dbSDimitry Andric 250*5ffd83dbSDimitry Andric CC1Args.push_back("-fno-use-init-array"); 251*5ffd83dbSDimitry Andric } 252