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