diff options
Diffstat (limited to 'clang/lib/Driver/ToolChains/PS4CPU.cpp')
| -rw-r--r-- | clang/lib/Driver/ToolChains/PS4CPU.cpp | 432 | 
1 files changed, 432 insertions, 0 deletions
| diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp new file mode 100644 index 000000000000..4e8840296205 --- /dev/null +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -0,0 +1,432 @@ +//===--- PS4CPU.cpp - PS4CPU ToolChain Implementations ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PS4CPU.h" +#include "FreeBSD.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include <cstdlib> // ::getenv + +using namespace clang::driver; +using namespace clang; +using namespace llvm::opt; + +using clang::driver::tools::AddLinkerInputs; + +void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, +                                     ArgStringList &CmdArgs) { +  if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, +                    false) || +       Args.hasFlag(options::OPT_fprofile_generate, +                    options::OPT_fno_profile_instr_generate, false) || +       Args.hasFlag(options::OPT_fprofile_generate_EQ, +                    options::OPT_fno_profile_instr_generate, false) || +       Args.hasFlag(options::OPT_fprofile_instr_generate, +                    options::OPT_fno_profile_instr_generate, false) || +       Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, +                    options::OPT_fno_profile_instr_generate, false) || +       Args.hasArg(options::OPT_fcreate_profile) || +       Args.hasArg(options::OPT_coverage))) +    CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a"); +} + +void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, +                                           const InputInfo &Output, +                                           const InputInfoList &Inputs, +                                           const ArgList &Args, +                                           const char *LinkingOutput) const { +  claimNoWarnArgs(Args); +  ArgStringList CmdArgs; + +  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  assert(Inputs.size() == 1 && "Unexpected number of inputs."); +  const InputInfo &Input = Inputs[0]; +  assert(Input.isFilename() && "Invalid input."); +  CmdArgs.push_back(Input.getFilename()); + +  const char *Exec = +      Args.MakeArgString(getToolChain().GetProgramPath("orbis-as")); +  C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { +  const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); +  if (SanArgs.needsUbsanRt()) { +    CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); +  } +  if (SanArgs.needsAsanRt()) { +    CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak"); +  } +} + +void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, +                                     ArgStringList &CmdArgs) { +  const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); +  if (SanArgs.needsUbsanRt()) +    CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a"); +  if (SanArgs.needsAsanRt()) +    CmdArgs.push_back("--dependent-lib=libSceDbgAddressSanitizer_stub_weak.a"); +} + +static void ConstructPS4LinkJob(const Tool &T, Compilation &C, +                                const JobAction &JA, const InputInfo &Output, +                                const InputInfoList &Inputs, +                                const ArgList &Args, +                                const char *LinkingOutput) { +  const toolchains::FreeBSD &ToolChain = +      static_cast<const toolchains::FreeBSD &>(T.getToolChain()); +  const Driver &D = ToolChain.getDriver(); +  ArgStringList CmdArgs; + +  // Silence warning for "clang -g foo.o -o foo" +  Args.ClaimAllArgs(options::OPT_g_Group); +  // and "clang -emit-llvm foo.o -o foo" +  Args.ClaimAllArgs(options::OPT_emit_llvm); +  // and for "clang -w foo.o -o foo". Other warning options are already +  // handled somewhere else. +  Args.ClaimAllArgs(options::OPT_w); + +  if (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (Args.hasArg(options::OPT_pie)) +    CmdArgs.push_back("-pie"); + +  if (Args.hasArg(options::OPT_rdynamic)) +    CmdArgs.push_back("-export-dynamic"); +  if (Args.hasArg(options::OPT_shared)) +    CmdArgs.push_back("--oformat=so"); + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) +    AddPS4SanitizerArgs(ToolChain, CmdArgs); + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  Args.AddAllArgs(CmdArgs, options::OPT_T_Group); +  Args.AddAllArgs(CmdArgs, options::OPT_e); +  Args.AddAllArgs(CmdArgs, options::OPT_s); +  Args.AddAllArgs(CmdArgs, options::OPT_t); +  Args.AddAllArgs(CmdArgs, options::OPT_r); + +  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) +    CmdArgs.push_back("--no-demangle"); + +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (Args.hasArg(options::OPT_pthread)) { +    CmdArgs.push_back("-lpthread"); +  } + +  const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); + +  C.addCommand(std::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); +} + +static void ConstructGoldLinkJob(const Tool &T, Compilation &C, +                                 const JobAction &JA, const InputInfo &Output, +                                 const InputInfoList &Inputs, +                                 const ArgList &Args, +                                 const char *LinkingOutput) { +  const toolchains::FreeBSD &ToolChain = +      static_cast<const toolchains::FreeBSD &>(T.getToolChain()); +  const Driver &D = ToolChain.getDriver(); +  ArgStringList CmdArgs; + +  // Silence warning for "clang -g foo.o -o foo" +  Args.ClaimAllArgs(options::OPT_g_Group); +  // and "clang -emit-llvm foo.o -o foo" +  Args.ClaimAllArgs(options::OPT_emit_llvm); +  // and for "clang -w foo.o -o foo". Other warning options are already +  // handled somewhere else. +  Args.ClaimAllArgs(options::OPT_w); + +  if (!D.SysRoot.empty()) +    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + +  if (Args.hasArg(options::OPT_pie)) +    CmdArgs.push_back("-pie"); + +  if (Args.hasArg(options::OPT_static)) { +    CmdArgs.push_back("-Bstatic"); +  } else { +    if (Args.hasArg(options::OPT_rdynamic)) +      CmdArgs.push_back("-export-dynamic"); +    CmdArgs.push_back("--eh-frame-hdr"); +    if (Args.hasArg(options::OPT_shared)) { +      CmdArgs.push_back("-Bshareable"); +    } else { +      CmdArgs.push_back("-dynamic-linker"); +      CmdArgs.push_back("/libexec/ld-elf.so.1"); +    } +    CmdArgs.push_back("--enable-new-dtags"); +  } + +  if (Output.isFilename()) { +    CmdArgs.push_back("-o"); +    CmdArgs.push_back(Output.getFilename()); +  } else { +    assert(Output.isNothing() && "Invalid output."); +  } + +  if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) +    AddPS4SanitizerArgs(ToolChain, CmdArgs); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    const char *crt1 = nullptr; +    if (!Args.hasArg(options::OPT_shared)) { +      if (Args.hasArg(options::OPT_pg)) +        crt1 = "gcrt1.o"; +      else if (Args.hasArg(options::OPT_pie)) +        crt1 = "Scrt1.o"; +      else +        crt1 = "crt1.o"; +    } +    if (crt1) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + +    const char *crtbegin = nullptr; +    if (Args.hasArg(options::OPT_static)) +      crtbegin = "crtbeginT.o"; +    else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) +      crtbegin = "crtbeginS.o"; +    else +      crtbegin = "crtbegin.o"; + +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); +  } + +  Args.AddAllArgs(CmdArgs, options::OPT_L); +  ToolChain.AddFilePathLibArgs(Args, CmdArgs); +  Args.AddAllArgs(CmdArgs, options::OPT_T_Group); +  Args.AddAllArgs(CmdArgs, options::OPT_e); +  Args.AddAllArgs(CmdArgs, options::OPT_s); +  Args.AddAllArgs(CmdArgs, options::OPT_t); +  Args.AddAllArgs(CmdArgs, options::OPT_r); + +  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) +    CmdArgs.push_back("--no-demangle"); + +  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    // For PS4, we always want to pass libm, libstdc++ and libkernel +    // libraries for both C and C++ compilations. +    CmdArgs.push_back("-lkernel"); +    if (D.CCCIsCXX()) { +      if (ToolChain.ShouldLinkCXXStdlib(Args)) +        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); +      if (Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back("-lm_p"); +      else +        CmdArgs.push_back("-lm"); +    } +    // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding +    // the default system libraries. Just mimic this for now. +    if (Args.hasArg(options::OPT_pg)) +      CmdArgs.push_back("-lgcc_p"); +    else +      CmdArgs.push_back("-lcompiler_rt"); +    if (Args.hasArg(options::OPT_static)) { +      CmdArgs.push_back("-lstdc++"); +    } else if (Args.hasArg(options::OPT_pg)) { +      CmdArgs.push_back("-lgcc_eh_p"); +    } else { +      CmdArgs.push_back("--as-needed"); +      CmdArgs.push_back("-lstdc++"); +      CmdArgs.push_back("--no-as-needed"); +    } + +    if (Args.hasArg(options::OPT_pthread)) { +      if (Args.hasArg(options::OPT_pg)) +        CmdArgs.push_back("-lpthread_p"); +      else +        CmdArgs.push_back("-lpthread"); +    } + +    if (Args.hasArg(options::OPT_pg)) { +      if (Args.hasArg(options::OPT_shared)) +        CmdArgs.push_back("-lc"); +      else { +        if (Args.hasArg(options::OPT_static)) { +          CmdArgs.push_back("--start-group"); +          CmdArgs.push_back("-lc_p"); +          CmdArgs.push_back("-lpthread_p"); +          CmdArgs.push_back("--end-group"); +        } else { +          CmdArgs.push_back("-lc_p"); +        } +      } +      CmdArgs.push_back("-lgcc_p"); +    } else { +      if (Args.hasArg(options::OPT_static)) { +        CmdArgs.push_back("--start-group"); +        CmdArgs.push_back("-lc"); +        CmdArgs.push_back("-lpthread"); +        CmdArgs.push_back("--end-group"); +      } else { +        CmdArgs.push_back("-lc"); +      } +      CmdArgs.push_back("-lcompiler_rt"); +    } + +    if (Args.hasArg(options::OPT_static)) { +      CmdArgs.push_back("-lstdc++"); +    } else if (Args.hasArg(options::OPT_pg)) { +      CmdArgs.push_back("-lgcc_eh_p"); +    } else { +      CmdArgs.push_back("--as-needed"); +      CmdArgs.push_back("-lstdc++"); +      CmdArgs.push_back("--no-as-needed"); +    } +  } + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { +    if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); +    else +      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); +    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); +  } + +  const char *Exec = +#ifdef _WIN32 +      Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold")); +#else +      Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); +#endif + +  C.addCommand(std::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); +} + +void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, +                                       const InputInfo &Output, +                                       const InputInfoList &Inputs, +                                       const ArgList &Args, +                                       const char *LinkingOutput) const { +  const toolchains::FreeBSD &ToolChain = +      static_cast<const toolchains::FreeBSD &>(getToolChain()); +  const Driver &D = ToolChain.getDriver(); +  bool PS4Linker; +  StringRef LinkerOptName; +  if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { +    LinkerOptName = A->getValue(); +    if (LinkerOptName != "ps4" && LinkerOptName != "gold") +      D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName; +  } + +  if (LinkerOptName == "gold") +    PS4Linker = false; +  else if (LinkerOptName == "ps4") +    PS4Linker = true; +  else +    PS4Linker = !Args.hasArg(options::OPT_shared); + +  if (PS4Linker) +    ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); +  else +    ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); +} + +toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, +                           const ArgList &Args) +    : Generic_ELF(D, Triple, Args) { +  if (Args.hasArg(clang::driver::options::OPT_static)) +    D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static" +                                                            << "PS4"; + +  // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR +  // if it exists; otherwise use the driver's installation path, which +  // should be <SDK_DIR>/host_tools/bin. + +  SmallString<512> PS4SDKDir; +  if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) { +    if (!llvm::sys::fs::exists(EnvValue)) +      getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; +    PS4SDKDir = EnvValue; +  } else { +    PS4SDKDir = getDriver().Dir; +    llvm::sys::path::append(PS4SDKDir, "/../../"); +  } + +  // By default, the driver won't report a warning if it can't find +  // PS4's include or lib directories. This behavior could be changed if +  // -Weverything or -Winvalid-or-nonexistent-directory options are passed. +  // If -isysroot was passed, use that as the SDK base path. +  std::string PrefixDir; +  if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { +    PrefixDir = A->getValue(); +    if (!llvm::sys::fs::exists(PrefixDir)) +      getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; +  } else +    PrefixDir = PS4SDKDir.str(); + +  SmallString<512> PS4SDKIncludeDir(PrefixDir); +  llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); +  if (!Args.hasArg(options::OPT_nostdinc) && +      !Args.hasArg(options::OPT_nostdlibinc) && +      !Args.hasArg(options::OPT_isysroot) && +      !Args.hasArg(options::OPT__sysroot_EQ) && +      !llvm::sys::fs::exists(PS4SDKIncludeDir)) { +    getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) +        << "PS4 system headers" << PS4SDKIncludeDir; +  } + +  SmallString<512> PS4SDKLibDir(PS4SDKDir); +  llvm::sys::path::append(PS4SDKLibDir, "target/lib"); +  if (!Args.hasArg(options::OPT_nostdlib) && +      !Args.hasArg(options::OPT_nodefaultlibs) && +      !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && +      !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && +      !Args.hasArg(options::OPT_emit_ast) && +      !llvm::sys::fs::exists(PS4SDKLibDir)) { +    getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) +        << "PS4 system libraries" << PS4SDKLibDir; +    return; +  } +  getFilePaths().push_back(PS4SDKLibDir.str()); +} + +Tool *toolchains::PS4CPU::buildAssembler() const { +  return new tools::PS4cpu::Assemble(*this); +} + +Tool *toolchains::PS4CPU::buildLinker() const { +  return new tools::PS4cpu::Link(*this); +} + +bool toolchains::PS4CPU::isPICDefault() const { return true; } + +bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; } + +SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { +  SanitizerMask Res = ToolChain::getSupportedSanitizers(); +  Res |= SanitizerKind::Address; +  Res |= SanitizerKind::PointerCompare; +  Res |= SanitizerKind::PointerSubtract; +  Res |= SanitizerKind::Vptr; +  return Res; +} | 
