PS4CPU.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. //===--- PS4CPU.cpp - PS4CPU ToolChain Implementations ----------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "PS4CPU.h"
  9. #include "CommonArgs.h"
  10. #include "clang/Driver/Compilation.h"
  11. #include "clang/Driver/Driver.h"
  12. #include "clang/Driver/DriverDiagnostic.h"
  13. #include "clang/Driver/Options.h"
  14. #include "clang/Driver/SanitizerArgs.h"
  15. #include "llvm/Option/ArgList.h"
  16. #include "llvm/Support/FileSystem.h"
  17. #include "llvm/Support/Path.h"
  18. #include <cstdlib> // ::getenv
  19. using namespace clang::driver;
  20. using namespace clang;
  21. using namespace llvm::opt;
  22. // Helper to paste bits of an option together and return a saved string.
  23. static const char *makeArgString(const ArgList &Args, const char *Prefix,
  24. const char *Base, const char *Suffix) {
  25. // Basically "Prefix + Base + Suffix" all converted to Twine then saved.
  26. return Args.MakeArgString(Twine(StringRef(Prefix), Base) + Suffix);
  27. }
  28. void tools::PScpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
  29. ArgStringList &CmdArgs) {
  30. assert(TC.getTriple().isPS());
  31. auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC);
  32. if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
  33. false) ||
  34. Args.hasFlag(options::OPT_fprofile_generate,
  35. options::OPT_fno_profile_generate, false) ||
  36. Args.hasFlag(options::OPT_fprofile_generate_EQ,
  37. options::OPT_fno_profile_generate, false) ||
  38. Args.hasFlag(options::OPT_fprofile_instr_generate,
  39. options::OPT_fno_profile_instr_generate, false) ||
  40. Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
  41. options::OPT_fno_profile_instr_generate, false) ||
  42. Args.hasFlag(options::OPT_fcs_profile_generate,
  43. options::OPT_fno_profile_generate, false) ||
  44. Args.hasFlag(options::OPT_fcs_profile_generate_EQ,
  45. options::OPT_fno_profile_generate, false) ||
  46. Args.hasArg(options::OPT_fcreate_profile) ||
  47. Args.hasArg(options::OPT_coverage)))
  48. CmdArgs.push_back(makeArgString(
  49. Args, "--dependent-lib=", PSTC.getProfileRTLibName(), ""));
  50. }
  51. void tools::PScpu::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
  52. const InputInfo &Output,
  53. const InputInfoList &Inputs,
  54. const ArgList &Args,
  55. const char *LinkingOutput) const {
  56. auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
  57. claimNoWarnArgs(Args);
  58. ArgStringList CmdArgs;
  59. Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
  60. CmdArgs.push_back("-o");
  61. CmdArgs.push_back(Output.getFilename());
  62. assert(Inputs.size() == 1 && "Unexpected number of inputs.");
  63. const InputInfo &Input = Inputs[0];
  64. assert(Input.isFilename() && "Invalid input.");
  65. CmdArgs.push_back(Input.getFilename());
  66. std::string AsName = TC.qualifyPSCmdName("as");
  67. const char *Exec = Args.MakeArgString(TC.GetProgramPath(AsName.c_str()));
  68. C.addCommand(std::make_unique<Command>(JA, *this,
  69. ResponseFileSupport::AtFileUTF8(),
  70. Exec, CmdArgs, Inputs, Output));
  71. }
  72. void tools::PScpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args,
  73. ArgStringList &CmdArgs) {
  74. assert(TC.getTriple().isPS());
  75. auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC);
  76. PSTC.addSanitizerArgs(Args, CmdArgs, "--dependent-lib=lib", ".a");
  77. }
  78. void toolchains::PS4CPU::addSanitizerArgs(const ArgList &Args,
  79. ArgStringList &CmdArgs,
  80. const char *Prefix,
  81. const char *Suffix) const {
  82. auto arg = [&](const char *Name) -> const char * {
  83. return makeArgString(Args, Prefix, Name, Suffix);
  84. };
  85. const SanitizerArgs &SanArgs = getSanitizerArgs(Args);
  86. if (SanArgs.needsUbsanRt())
  87. CmdArgs.push_back(arg("SceDbgUBSanitizer_stub_weak"));
  88. if (SanArgs.needsAsanRt())
  89. CmdArgs.push_back(arg("SceDbgAddressSanitizer_stub_weak"));
  90. }
  91. void toolchains::PS5CPU::addSanitizerArgs(const ArgList &Args,
  92. ArgStringList &CmdArgs,
  93. const char *Prefix,
  94. const char *Suffix) const {
  95. auto arg = [&](const char *Name) -> const char * {
  96. return makeArgString(Args, Prefix, Name, Suffix);
  97. };
  98. const SanitizerArgs &SanArgs = getSanitizerArgs(Args);
  99. if (SanArgs.needsUbsanRt())
  100. CmdArgs.push_back(arg("SceUBSanitizer_nosubmission_stub_weak"));
  101. if (SanArgs.needsAsanRt())
  102. CmdArgs.push_back(arg("SceAddressSanitizer_nosubmission_stub_weak"));
  103. if (SanArgs.needsTsanRt())
  104. CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_stub_weak"));
  105. }
  106. void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
  107. const InputInfo &Output,
  108. const InputInfoList &Inputs,
  109. const ArgList &Args,
  110. const char *LinkingOutput) const {
  111. auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
  112. const Driver &D = TC.getDriver();
  113. ArgStringList CmdArgs;
  114. // Silence warning for "clang -g foo.o -o foo"
  115. Args.ClaimAllArgs(options::OPT_g_Group);
  116. // and "clang -emit-llvm foo.o -o foo"
  117. Args.ClaimAllArgs(options::OPT_emit_llvm);
  118. // and for "clang -w foo.o -o foo". Other warning options are already
  119. // handled somewhere else.
  120. Args.ClaimAllArgs(options::OPT_w);
  121. if (!D.SysRoot.empty())
  122. CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
  123. if (Args.hasArg(options::OPT_pie))
  124. CmdArgs.push_back("-pie");
  125. if (Args.hasArg(options::OPT_rdynamic))
  126. CmdArgs.push_back("-export-dynamic");
  127. if (Args.hasArg(options::OPT_shared))
  128. CmdArgs.push_back("--shared");
  129. if (Output.isFilename()) {
  130. CmdArgs.push_back("-o");
  131. CmdArgs.push_back(Output.getFilename());
  132. } else {
  133. assert(Output.isNothing() && "Invalid output.");
  134. }
  135. const bool UseLTO = D.isUsingLTO();
  136. const bool UseJMC =
  137. Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
  138. const bool IsPS4 = TC.getTriple().isPS4();
  139. const bool IsPS5 = TC.getTriple().isPS5();
  140. assert(IsPS4 || IsPS5);
  141. auto AddCodeGenFlag = [&](Twine Flag) {
  142. const char *Prefix = nullptr;
  143. if (IsPS4 && D.getLTOMode() == LTOK_Thin)
  144. Prefix = "-lto-thin-debug-options=";
  145. else if (IsPS4 && D.getLTOMode() == LTOK_Full)
  146. Prefix = "-lto-debug-options=";
  147. else if (IsPS5)
  148. Prefix = "-plugin-opt=";
  149. else
  150. llvm_unreachable("new LTO mode?");
  151. CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + Flag));
  152. };
  153. if (UseLTO) {
  154. // We default to creating the arange section, but LTO does not. Enable it
  155. // here.
  156. AddCodeGenFlag("-generate-arange-section");
  157. // This tells LTO to perform JustMyCode instrumentation.
  158. if (UseJMC)
  159. AddCodeGenFlag("-enable-jmc-instrument");
  160. if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
  161. AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
  162. }
  163. if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
  164. TC.addSanitizerArgs(Args, CmdArgs, "-l", "");
  165. Args.AddAllArgs(CmdArgs, options::OPT_L);
  166. Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
  167. Args.AddAllArgs(CmdArgs, options::OPT_e);
  168. Args.AddAllArgs(CmdArgs, options::OPT_s);
  169. Args.AddAllArgs(CmdArgs, options::OPT_t);
  170. Args.AddAllArgs(CmdArgs, options::OPT_r);
  171. if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
  172. CmdArgs.push_back("--no-demangle");
  173. AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
  174. if (Args.hasArg(options::OPT_pthread)) {
  175. CmdArgs.push_back("-lpthread");
  176. }
  177. if (UseJMC) {
  178. CmdArgs.push_back("--whole-archive");
  179. if (IsPS4)
  180. CmdArgs.push_back("-lSceDbgJmc");
  181. else
  182. CmdArgs.push_back("-lSceJmc_nosubmission");
  183. CmdArgs.push_back("--no-whole-archive");
  184. }
  185. if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
  186. D.Diag(diag::err_drv_unsupported_opt_for_target)
  187. << "-fuse-ld" << TC.getTriple().str();
  188. }
  189. std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName());
  190. const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str()));
  191. C.addCommand(std::make_unique<Command>(JA, *this,
  192. ResponseFileSupport::AtFileUTF8(),
  193. Exec, CmdArgs, Inputs, Output));
  194. }
  195. toolchains::PS4PS5Base::PS4PS5Base(const Driver &D, const llvm::Triple &Triple,
  196. const ArgList &Args, StringRef Platform,
  197. const char *EnvVar)
  198. : Generic_ELF(D, Triple, Args) {
  199. if (Args.hasArg(clang::driver::options::OPT_static))
  200. D.Diag(clang::diag::err_drv_unsupported_opt_for_target)
  201. << "-static" << Platform;
  202. // Determine where to find the PS4/PS5 libraries. We use the EnvVar
  203. // if it exists; otherwise use the driver's installation path, which
  204. // should be <SDK_DIR>/host_tools/bin.
  205. SmallString<512> SDKDir;
  206. if (const char *EnvValue = getenv(EnvVar)) {
  207. if (!llvm::sys::fs::exists(EnvValue))
  208. D.Diag(clang::diag::warn_drv_ps_sdk_dir) << EnvVar << EnvValue;
  209. SDKDir = EnvValue;
  210. } else {
  211. SDKDir = D.Dir;
  212. llvm::sys::path::append(SDKDir, "/../../");
  213. }
  214. // By default, the driver won't report a warning if it can't find the
  215. // SDK include or lib directories. This behavior could be changed if
  216. // -Weverything or -Winvalid-or-nonexistent-directory options are passed.
  217. // If -isysroot was passed, use that as the SDK base path.
  218. std::string PrefixDir;
  219. if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
  220. PrefixDir = A->getValue();
  221. if (!llvm::sys::fs::exists(PrefixDir))
  222. D.Diag(clang::diag::warn_missing_sysroot) << PrefixDir;
  223. } else
  224. PrefixDir = std::string(SDKDir.str());
  225. SmallString<512> SDKIncludeDir(PrefixDir);
  226. llvm::sys::path::append(SDKIncludeDir, "target/include");
  227. if (!Args.hasArg(options::OPT_nostdinc) &&
  228. !Args.hasArg(options::OPT_nostdlibinc) &&
  229. !Args.hasArg(options::OPT_isysroot) &&
  230. !Args.hasArg(options::OPT__sysroot_EQ) &&
  231. !llvm::sys::fs::exists(SDKIncludeDir)) {
  232. D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
  233. << Twine(Platform, " system headers").str() << SDKIncludeDir;
  234. }
  235. SmallString<512> SDKLibDir(SDKDir);
  236. llvm::sys::path::append(SDKLibDir, "target/lib");
  237. if (!Args.hasArg(options::OPT_nostdlib) &&
  238. !Args.hasArg(options::OPT_nodefaultlibs) &&
  239. !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) &&
  240. !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) &&
  241. !Args.hasArg(options::OPT_emit_ast) &&
  242. !llvm::sys::fs::exists(SDKLibDir)) {
  243. D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
  244. << Twine(Platform, " system libraries").str() << SDKLibDir;
  245. return;
  246. }
  247. getFilePaths().push_back(std::string(SDKLibDir.str()));
  248. }
  249. Tool *toolchains::PS4CPU::buildAssembler() const {
  250. return new tools::PScpu::Assembler(*this);
  251. }
  252. Tool *toolchains::PS5CPU::buildAssembler() const {
  253. // PS5 does not support an external assembler.
  254. getDriver().Diag(clang::diag::err_no_external_assembler);
  255. return nullptr;
  256. }
  257. Tool *toolchains::PS4PS5Base::buildLinker() const {
  258. return new tools::PScpu::Linker(*this);
  259. }
  260. SanitizerMask toolchains::PS4PS5Base::getSupportedSanitizers() const {
  261. SanitizerMask Res = ToolChain::getSupportedSanitizers();
  262. Res |= SanitizerKind::Address;
  263. Res |= SanitizerKind::PointerCompare;
  264. Res |= SanitizerKind::PointerSubtract;
  265. Res |= SanitizerKind::Vptr;
  266. return Res;
  267. }
  268. SanitizerMask toolchains::PS5CPU::getSupportedSanitizers() const {
  269. SanitizerMask Res = PS4PS5Base::getSupportedSanitizers();
  270. Res |= SanitizerKind::Thread;
  271. return Res;
  272. }
  273. void toolchains::PS4PS5Base::addClangTargetOptions(
  274. const ArgList &DriverArgs, ArgStringList &CC1Args,
  275. Action::OffloadKind DeviceOffloadingKind) const {
  276. // PS4/PS5 do not use init arrays.
  277. if (DriverArgs.hasArg(options::OPT_fuse_init_array)) {
  278. Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array);
  279. getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target)
  280. << A->getAsString(DriverArgs) << getTriple().str();
  281. }
  282. CC1Args.push_back("-fno-use-init-array");
  283. const Arg *A =
  284. DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
  285. options::OPT_fno_visibility_from_dllstorageclass);
  286. if (!A ||
  287. A->getOption().matches(options::OPT_fvisibility_from_dllstorageclass)) {
  288. CC1Args.push_back("-fvisibility-from-dllstorageclass");
  289. if (DriverArgs.hasArg(options::OPT_fvisibility_dllexport_EQ))
  290. DriverArgs.AddLastArg(CC1Args, options::OPT_fvisibility_dllexport_EQ);
  291. else
  292. CC1Args.push_back("-fvisibility-dllexport=protected");
  293. if (DriverArgs.hasArg(options::OPT_fvisibility_nodllstorageclass_EQ))
  294. DriverArgs.AddLastArg(CC1Args,
  295. options::OPT_fvisibility_nodllstorageclass_EQ);
  296. else
  297. CC1Args.push_back("-fvisibility-nodllstorageclass=hidden");
  298. if (DriverArgs.hasArg(options::OPT_fvisibility_externs_dllimport_EQ))
  299. DriverArgs.AddLastArg(CC1Args,
  300. options::OPT_fvisibility_externs_dllimport_EQ);
  301. else
  302. CC1Args.push_back("-fvisibility-externs-dllimport=default");
  303. if (DriverArgs.hasArg(
  304. options::OPT_fvisibility_externs_nodllstorageclass_EQ))
  305. DriverArgs.AddLastArg(
  306. CC1Args, options::OPT_fvisibility_externs_nodllstorageclass_EQ);
  307. else
  308. CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default");
  309. }
  310. }
  311. // PS4 toolchain.
  312. toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple,
  313. const llvm::opt::ArgList &Args)
  314. : PS4PS5Base(D, Triple, Args, "PS4", "SCE_ORBIS_SDK_DIR") {}
  315. // PS5 toolchain.
  316. toolchains::PS5CPU::PS5CPU(const Driver &D, const llvm::Triple &Triple,
  317. const llvm::opt::ArgList &Args)
  318. : PS4PS5Base(D, Triple, Args, "PS5", "SCE_PROSPERO_SDK_DIR") {}