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, 335ffd83dbSDimitry Andric options::OPT_fno_profile_generate, false) || 340b57cec5SDimitry Andric Args.hasFlag(options::OPT_fprofile_generate_EQ, 355ffd83dbSDimitry 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) || 405ffd83dbSDimitry Andric Args.hasFlag(options::OPT_fcs_profile_generate, 415ffd83dbSDimitry Andric options::OPT_fno_profile_generate, false) || 425ffd83dbSDimitry Andric Args.hasFlag(options::OPT_fcs_profile_generate_EQ, 435ffd83dbSDimitry 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*e8d8bef9SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, 70*e8d8bef9SDimitry Andric ResponseFileSupport::AtFileUTF8(), 71*e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output)); 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { 750b57cec5SDimitry Andric const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); 760b57cec5SDimitry Andric if (SanArgs.needsUbsanRt()) { 770b57cec5SDimitry Andric CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric if (SanArgs.needsAsanRt()) { 800b57cec5SDimitry Andric CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak"); 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, 850b57cec5SDimitry Andric ArgStringList &CmdArgs) { 860b57cec5SDimitry Andric const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); 870b57cec5SDimitry Andric if (SanArgs.needsUbsanRt()) 880b57cec5SDimitry Andric CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a"); 890b57cec5SDimitry Andric if (SanArgs.needsAsanRt()) 900b57cec5SDimitry Andric CmdArgs.push_back("--dependent-lib=libSceDbgAddressSanitizer_stub_weak.a"); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 935ffd83dbSDimitry Andric void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, 945ffd83dbSDimitry Andric const InputInfo &Output, 950b57cec5SDimitry Andric const InputInfoList &Inputs, 960b57cec5SDimitry Andric const ArgList &Args, 975ffd83dbSDimitry Andric const char *LinkingOutput) const { 980b57cec5SDimitry Andric const toolchains::FreeBSD &ToolChain = 995ffd83dbSDimitry Andric static_cast<const toolchains::FreeBSD &>(getToolChain()); 1000b57cec5SDimitry Andric const Driver &D = ToolChain.getDriver(); 1010b57cec5SDimitry Andric ArgStringList CmdArgs; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric // Silence warning for "clang -g foo.o -o foo" 1040b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_g_Group); 1050b57cec5SDimitry Andric // and "clang -emit-llvm foo.o -o foo" 1060b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_emit_llvm); 1070b57cec5SDimitry Andric // and for "clang -w foo.o -o foo". Other warning options are already 1080b57cec5SDimitry Andric // handled somewhere else. 1090b57cec5SDimitry Andric Args.ClaimAllArgs(options::OPT_w); 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric if (!D.SysRoot.empty()) 1120b57cec5SDimitry Andric CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric if (Args.hasArg(options::OPT_pie)) 1150b57cec5SDimitry Andric CmdArgs.push_back("-pie"); 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric if (Args.hasArg(options::OPT_rdynamic)) 1180b57cec5SDimitry Andric CmdArgs.push_back("-export-dynamic"); 1190b57cec5SDimitry Andric if (Args.hasArg(options::OPT_shared)) 1200b57cec5SDimitry Andric CmdArgs.push_back("--oformat=so"); 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric if (Output.isFilename()) { 1230b57cec5SDimitry Andric CmdArgs.push_back("-o"); 1240b57cec5SDimitry Andric CmdArgs.push_back(Output.getFilename()); 1250b57cec5SDimitry Andric } else { 1260b57cec5SDimitry Andric assert(Output.isNothing() && "Invalid output."); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) 1300b57cec5SDimitry Andric AddPS4SanitizerArgs(ToolChain, CmdArgs); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_L); 1330b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_T_Group); 1340b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_e); 1350b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_s); 1360b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_t); 1370b57cec5SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_r); 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) 1400b57cec5SDimitry Andric CmdArgs.push_back("--no-demangle"); 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric if (Args.hasArg(options::OPT_pthread)) { 1450b57cec5SDimitry Andric CmdArgs.push_back("-lpthread"); 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1485ffd83dbSDimitry Andric if (Args.hasArg(options::OPT_fuse_ld_EQ)) { 1495ffd83dbSDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target) 1505ffd83dbSDimitry Andric << "-fuse-ld" << getToolChain().getTriple().str(); 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric const char *Exec = 1540b57cec5SDimitry Andric Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); 1550b57cec5SDimitry Andric 156*e8d8bef9SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, 157*e8d8bef9SDimitry Andric ResponseFileSupport::AtFileUTF8(), 158*e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output)); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, 1620b57cec5SDimitry Andric const ArgList &Args) 1630b57cec5SDimitry Andric : Generic_ELF(D, Triple, Args) { 1640b57cec5SDimitry Andric if (Args.hasArg(clang::driver::options::OPT_static)) 1650b57cec5SDimitry Andric D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static" 1660b57cec5SDimitry Andric << "PS4"; 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR 1690b57cec5SDimitry Andric // if it exists; otherwise use the driver's installation path, which 1700b57cec5SDimitry Andric // should be <SDK_DIR>/host_tools/bin. 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric SmallString<512> PS4SDKDir; 1730b57cec5SDimitry Andric if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) { 1740b57cec5SDimitry Andric if (!llvm::sys::fs::exists(EnvValue)) 1750b57cec5SDimitry Andric getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; 1760b57cec5SDimitry Andric PS4SDKDir = EnvValue; 1770b57cec5SDimitry Andric } else { 1780b57cec5SDimitry Andric PS4SDKDir = getDriver().Dir; 1790b57cec5SDimitry Andric llvm::sys::path::append(PS4SDKDir, "/../../"); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric // By default, the driver won't report a warning if it can't find 1830b57cec5SDimitry Andric // PS4's include or lib directories. This behavior could be changed if 1840b57cec5SDimitry Andric // -Weverything or -Winvalid-or-nonexistent-directory options are passed. 1850b57cec5SDimitry Andric // If -isysroot was passed, use that as the SDK base path. 1860b57cec5SDimitry Andric std::string PrefixDir; 1870b57cec5SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { 1880b57cec5SDimitry Andric PrefixDir = A->getValue(); 1890b57cec5SDimitry Andric if (!llvm::sys::fs::exists(PrefixDir)) 1900b57cec5SDimitry Andric getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; 1910b57cec5SDimitry Andric } else 1925ffd83dbSDimitry Andric PrefixDir = std::string(PS4SDKDir.str()); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric SmallString<512> PS4SDKIncludeDir(PrefixDir); 1950b57cec5SDimitry Andric llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); 1960b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_nostdinc) && 1970b57cec5SDimitry Andric !Args.hasArg(options::OPT_nostdlibinc) && 1980b57cec5SDimitry Andric !Args.hasArg(options::OPT_isysroot) && 1990b57cec5SDimitry Andric !Args.hasArg(options::OPT__sysroot_EQ) && 2000b57cec5SDimitry Andric !llvm::sys::fs::exists(PS4SDKIncludeDir)) { 2010b57cec5SDimitry Andric getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) 2020b57cec5SDimitry Andric << "PS4 system headers" << PS4SDKIncludeDir; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric SmallString<512> PS4SDKLibDir(PS4SDKDir); 2060b57cec5SDimitry Andric llvm::sys::path::append(PS4SDKLibDir, "target/lib"); 2070b57cec5SDimitry Andric if (!Args.hasArg(options::OPT_nostdlib) && 2080b57cec5SDimitry Andric !Args.hasArg(options::OPT_nodefaultlibs) && 2090b57cec5SDimitry Andric !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && 2100b57cec5SDimitry Andric !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && 2110b57cec5SDimitry Andric !Args.hasArg(options::OPT_emit_ast) && 2120b57cec5SDimitry Andric !llvm::sys::fs::exists(PS4SDKLibDir)) { 2130b57cec5SDimitry Andric getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) 2140b57cec5SDimitry Andric << "PS4 system libraries" << PS4SDKLibDir; 2150b57cec5SDimitry Andric return; 2160b57cec5SDimitry Andric } 2175ffd83dbSDimitry Andric getFilePaths().push_back(std::string(PS4SDKLibDir.str())); 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric Tool *toolchains::PS4CPU::buildAssembler() const { 2210b57cec5SDimitry Andric return new tools::PS4cpu::Assemble(*this); 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric Tool *toolchains::PS4CPU::buildLinker() const { 2250b57cec5SDimitry Andric return new tools::PS4cpu::Link(*this); 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric bool toolchains::PS4CPU::isPICDefault() const { return true; } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { 2330b57cec5SDimitry Andric SanitizerMask Res = ToolChain::getSupportedSanitizers(); 2340b57cec5SDimitry Andric Res |= SanitizerKind::Address; 2350b57cec5SDimitry Andric Res |= SanitizerKind::PointerCompare; 2360b57cec5SDimitry Andric Res |= SanitizerKind::PointerSubtract; 2370b57cec5SDimitry Andric Res |= SanitizerKind::Vptr; 2380b57cec5SDimitry Andric return Res; 2390b57cec5SDimitry Andric } 2405ffd83dbSDimitry Andric 2415ffd83dbSDimitry Andric void toolchains::PS4CPU::addClangTargetOptions( 242*e8d8bef9SDimitry Andric const ArgList &DriverArgs, ArgStringList &CC1Args, 2435ffd83dbSDimitry Andric Action::OffloadKind DeviceOffloadingKind) const { 2445ffd83dbSDimitry Andric // PS4 does not use init arrays. 2455ffd83dbSDimitry Andric if (DriverArgs.hasArg(options::OPT_fuse_init_array)) { 2465ffd83dbSDimitry Andric Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array); 2475ffd83dbSDimitry Andric getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target) 2485ffd83dbSDimitry Andric << A->getAsString(DriverArgs) << getTriple().str(); 2495ffd83dbSDimitry Andric } 2505ffd83dbSDimitry Andric 2515ffd83dbSDimitry Andric CC1Args.push_back("-fno-use-init-array"); 252*e8d8bef9SDimitry Andric 253*e8d8bef9SDimitry Andric const Arg *A = 254*e8d8bef9SDimitry Andric DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass, 255*e8d8bef9SDimitry Andric options::OPT_fno_visibility_from_dllstorageclass); 256*e8d8bef9SDimitry Andric if (!A || 257*e8d8bef9SDimitry Andric A->getOption().matches(options::OPT_fvisibility_from_dllstorageclass)) { 258*e8d8bef9SDimitry Andric CC1Args.push_back("-fvisibility-from-dllstorageclass"); 259*e8d8bef9SDimitry Andric 260*e8d8bef9SDimitry Andric if (DriverArgs.hasArg(options::OPT_fvisibility_dllexport_EQ)) 261*e8d8bef9SDimitry Andric DriverArgs.AddLastArg(CC1Args, options::OPT_fvisibility_dllexport_EQ); 262*e8d8bef9SDimitry Andric else 263*e8d8bef9SDimitry Andric CC1Args.push_back("-fvisibility-dllexport=protected"); 264*e8d8bef9SDimitry Andric 265*e8d8bef9SDimitry Andric if (DriverArgs.hasArg(options::OPT_fvisibility_nodllstorageclass_EQ)) 266*e8d8bef9SDimitry Andric DriverArgs.AddLastArg(CC1Args, 267*e8d8bef9SDimitry Andric options::OPT_fvisibility_nodllstorageclass_EQ); 268*e8d8bef9SDimitry Andric else 269*e8d8bef9SDimitry Andric CC1Args.push_back("-fvisibility-nodllstorageclass=hidden"); 270*e8d8bef9SDimitry Andric 271*e8d8bef9SDimitry Andric if (DriverArgs.hasArg(options::OPT_fvisibility_externs_dllimport_EQ)) 272*e8d8bef9SDimitry Andric DriverArgs.AddLastArg(CC1Args, 273*e8d8bef9SDimitry Andric options::OPT_fvisibility_externs_dllimport_EQ); 274*e8d8bef9SDimitry Andric else 275*e8d8bef9SDimitry Andric CC1Args.push_back("-fvisibility-externs-dllimport=default"); 276*e8d8bef9SDimitry Andric 277*e8d8bef9SDimitry Andric if (DriverArgs.hasArg( 278*e8d8bef9SDimitry Andric options::OPT_fvisibility_externs_nodllstorageclass_EQ)) 279*e8d8bef9SDimitry Andric DriverArgs.AddLastArg( 280*e8d8bef9SDimitry Andric CC1Args, options::OPT_fvisibility_externs_nodllstorageclass_EQ); 281*e8d8bef9SDimitry Andric else 282*e8d8bef9SDimitry Andric CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default"); 283*e8d8bef9SDimitry Andric } 2845ffd83dbSDimitry Andric } 285