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