/src/llvm-project/clang/lib/Driver/ToolChains/PS4CPU.cpp
Line | Count | Source (jump to first uncovered line) |
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/Config/config.h" |
12 | | #include "clang/Driver/Compilation.h" |
13 | | #include "clang/Driver/Driver.h" |
14 | | #include "clang/Driver/DriverDiagnostic.h" |
15 | | #include "clang/Driver/Options.h" |
16 | | #include "clang/Driver/SanitizerArgs.h" |
17 | | #include "llvm/Option/ArgList.h" |
18 | | #include "llvm/Support/FileSystem.h" |
19 | | #include "llvm/Support/Path.h" |
20 | | #include <cstdlib> // ::getenv |
21 | | |
22 | | using namespace clang::driver; |
23 | | using namespace clang; |
24 | | using namespace llvm::opt; |
25 | | |
26 | | // Helper to paste bits of an option together and return a saved string. |
27 | | static const char *makeArgString(const ArgList &Args, const char *Prefix, |
28 | 0 | const char *Base, const char *Suffix) { |
29 | | // Basically "Prefix + Base + Suffix" all converted to Twine then saved. |
30 | 0 | return Args.MakeArgString(Twine(StringRef(Prefix), Base) + Suffix); |
31 | 0 | } |
32 | | |
33 | | void tools::PScpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, |
34 | 0 | ArgStringList &CmdArgs) { |
35 | 0 | assert(TC.getTriple().isPS()); |
36 | 0 | auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC); |
37 | |
|
38 | 0 | if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, |
39 | 0 | false) || |
40 | 0 | Args.hasFlag(options::OPT_fprofile_generate, |
41 | 0 | options::OPT_fno_profile_generate, false) || |
42 | 0 | Args.hasFlag(options::OPT_fprofile_generate_EQ, |
43 | 0 | options::OPT_fno_profile_generate, false) || |
44 | 0 | Args.hasFlag(options::OPT_fprofile_instr_generate, |
45 | 0 | options::OPT_fno_profile_instr_generate, false) || |
46 | 0 | Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, |
47 | 0 | options::OPT_fno_profile_instr_generate, false) || |
48 | 0 | Args.hasFlag(options::OPT_fcs_profile_generate, |
49 | 0 | options::OPT_fno_profile_generate, false) || |
50 | 0 | Args.hasFlag(options::OPT_fcs_profile_generate_EQ, |
51 | 0 | options::OPT_fno_profile_generate, false) || |
52 | 0 | Args.hasArg(options::OPT_fcreate_profile) || |
53 | 0 | Args.hasArg(options::OPT_coverage))) |
54 | 0 | CmdArgs.push_back(makeArgString( |
55 | 0 | Args, "--dependent-lib=", PSTC.getProfileRTLibName(), "")); |
56 | 0 | } |
57 | | |
58 | | void tools::PScpu::Assembler::ConstructJob(Compilation &C, const JobAction &JA, |
59 | | const InputInfo &Output, |
60 | | const InputInfoList &Inputs, |
61 | | const ArgList &Args, |
62 | 0 | const char *LinkingOutput) const { |
63 | 0 | auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain()); |
64 | 0 | claimNoWarnArgs(Args); |
65 | 0 | ArgStringList CmdArgs; |
66 | |
|
67 | 0 | Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); |
68 | |
|
69 | 0 | CmdArgs.push_back("-o"); |
70 | 0 | CmdArgs.push_back(Output.getFilename()); |
71 | |
|
72 | 0 | assert(Inputs.size() == 1 && "Unexpected number of inputs."); |
73 | 0 | const InputInfo &Input = Inputs[0]; |
74 | 0 | assert(Input.isFilename() && "Invalid input."); |
75 | 0 | CmdArgs.push_back(Input.getFilename()); |
76 | |
|
77 | 0 | std::string AsName = TC.qualifyPSCmdName("as"); |
78 | 0 | const char *Exec = Args.MakeArgString(TC.GetProgramPath(AsName.c_str())); |
79 | 0 | C.addCommand(std::make_unique<Command>(JA, *this, |
80 | 0 | ResponseFileSupport::AtFileUTF8(), |
81 | 0 | Exec, CmdArgs, Inputs, Output)); |
82 | 0 | } |
83 | | |
84 | | void tools::PScpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args, |
85 | 0 | ArgStringList &CmdArgs) { |
86 | 0 | assert(TC.getTriple().isPS()); |
87 | 0 | auto &PSTC = static_cast<const toolchains::PS4PS5Base &>(TC); |
88 | 0 | PSTC.addSanitizerArgs(Args, CmdArgs, "--dependent-lib=lib", ".a"); |
89 | 0 | } |
90 | | |
91 | | void toolchains::PS4CPU::addSanitizerArgs(const ArgList &Args, |
92 | | ArgStringList &CmdArgs, |
93 | | const char *Prefix, |
94 | 0 | const char *Suffix) const { |
95 | 0 | auto arg = [&](const char *Name) -> const char * { |
96 | 0 | return makeArgString(Args, Prefix, Name, Suffix); |
97 | 0 | }; |
98 | 0 | const SanitizerArgs &SanArgs = getSanitizerArgs(Args); |
99 | 0 | if (SanArgs.needsUbsanRt()) |
100 | 0 | CmdArgs.push_back(arg("SceDbgUBSanitizer_stub_weak")); |
101 | 0 | if (SanArgs.needsAsanRt()) |
102 | 0 | CmdArgs.push_back(arg("SceDbgAddressSanitizer_stub_weak")); |
103 | 0 | } |
104 | | |
105 | | void toolchains::PS5CPU::addSanitizerArgs(const ArgList &Args, |
106 | | ArgStringList &CmdArgs, |
107 | | const char *Prefix, |
108 | 0 | const char *Suffix) const { |
109 | 0 | auto arg = [&](const char *Name) -> const char * { |
110 | 0 | return makeArgString(Args, Prefix, Name, Suffix); |
111 | 0 | }; |
112 | 0 | const SanitizerArgs &SanArgs = getSanitizerArgs(Args); |
113 | 0 | if (SanArgs.needsUbsanRt()) |
114 | 0 | CmdArgs.push_back(arg("SceUBSanitizer_nosubmission_stub_weak")); |
115 | 0 | if (SanArgs.needsAsanRt()) |
116 | 0 | CmdArgs.push_back(arg("SceAddressSanitizer_nosubmission_stub_weak")); |
117 | 0 | if (SanArgs.needsTsanRt()) |
118 | 0 | CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_stub_weak")); |
119 | 0 | } |
120 | | |
121 | | void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, |
122 | | const InputInfo &Output, |
123 | | const InputInfoList &Inputs, |
124 | | const ArgList &Args, |
125 | 0 | const char *LinkingOutput) const { |
126 | 0 | auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain()); |
127 | 0 | const Driver &D = TC.getDriver(); |
128 | 0 | ArgStringList CmdArgs; |
129 | | |
130 | | // Silence warning for "clang -g foo.o -o foo" |
131 | 0 | Args.ClaimAllArgs(options::OPT_g_Group); |
132 | | // and "clang -emit-llvm foo.o -o foo" |
133 | 0 | Args.ClaimAllArgs(options::OPT_emit_llvm); |
134 | | // and for "clang -w foo.o -o foo". Other warning options are already |
135 | | // handled somewhere else. |
136 | 0 | Args.ClaimAllArgs(options::OPT_w); |
137 | |
|
138 | 0 | if (!D.SysRoot.empty()) |
139 | 0 | CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); |
140 | |
|
141 | 0 | if (Args.hasArg(options::OPT_pie)) |
142 | 0 | CmdArgs.push_back("-pie"); |
143 | |
|
144 | 0 | if (Args.hasArg(options::OPT_rdynamic)) |
145 | 0 | CmdArgs.push_back("-export-dynamic"); |
146 | 0 | if (Args.hasArg(options::OPT_shared)) |
147 | 0 | CmdArgs.push_back("--shared"); |
148 | |
|
149 | 0 | assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); |
150 | 0 | if (Output.isFilename()) { |
151 | 0 | CmdArgs.push_back("-o"); |
152 | 0 | CmdArgs.push_back(Output.getFilename()); |
153 | 0 | } |
154 | |
|
155 | 0 | const bool UseLTO = D.isUsingLTO(); |
156 | 0 | const bool UseJMC = |
157 | 0 | Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false); |
158 | 0 | const bool IsPS4 = TC.getTriple().isPS4(); |
159 | |
|
160 | 0 | const char *PS4LTOArgs = ""; |
161 | 0 | auto AddCodeGenFlag = [&](Twine Flag) { |
162 | 0 | if (IsPS4) |
163 | 0 | PS4LTOArgs = Args.MakeArgString(Twine(PS4LTOArgs) + " " + Flag); |
164 | 0 | else |
165 | 0 | CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag)); |
166 | 0 | }; |
167 | |
|
168 | 0 | if (UseLTO) { |
169 | | // We default to creating the arange section, but LTO does not. Enable it |
170 | | // here. |
171 | 0 | AddCodeGenFlag("-generate-arange-section"); |
172 | | |
173 | | // This tells LTO to perform JustMyCode instrumentation. |
174 | 0 | if (UseJMC) |
175 | 0 | AddCodeGenFlag("-enable-jmc-instrument"); |
176 | |
|
177 | 0 | if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir)) |
178 | 0 | AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue()); |
179 | |
|
180 | 0 | StringRef Parallelism = getLTOParallelism(Args, D); |
181 | 0 | if (!Parallelism.empty()) { |
182 | 0 | if (IsPS4) |
183 | 0 | AddCodeGenFlag(Twine("-threads=") + Parallelism); |
184 | 0 | else |
185 | 0 | CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism)); |
186 | 0 | } |
187 | |
|
188 | 0 | if (IsPS4) { |
189 | 0 | const char *Prefix = nullptr; |
190 | 0 | if (D.getLTOMode() == LTOK_Thin) |
191 | 0 | Prefix = "-lto-thin-debug-options="; |
192 | 0 | else if (D.getLTOMode() == LTOK_Full) |
193 | 0 | Prefix = "-lto-debug-options="; |
194 | 0 | else |
195 | 0 | llvm_unreachable("new LTO mode?"); |
196 | |
|
197 | 0 | CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + PS4LTOArgs)); |
198 | 0 | } |
199 | 0 | } |
200 | |
|
201 | 0 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) |
202 | 0 | TC.addSanitizerArgs(Args, CmdArgs, "-l", ""); |
203 | |
|
204 | 0 | if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) { |
205 | 0 | if (D.getLTOMode() == LTOK_Thin) |
206 | 0 | CmdArgs.push_back("--lto=thin"); |
207 | 0 | else if (D.getLTOMode() == LTOK_Full) |
208 | 0 | CmdArgs.push_back("--lto=full"); |
209 | 0 | } |
210 | |
|
211 | 0 | Args.addAllArgs(CmdArgs, |
212 | 0 | {options::OPT_L, options::OPT_T_Group, options::OPT_s, |
213 | 0 | options::OPT_t, options::OPT_r}); |
214 | |
|
215 | 0 | if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) |
216 | 0 | CmdArgs.push_back("--no-demangle"); |
217 | |
|
218 | 0 | AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); |
219 | |
|
220 | 0 | if (Args.hasArg(options::OPT_pthread)) { |
221 | 0 | CmdArgs.push_back("-lpthread"); |
222 | 0 | } |
223 | |
|
224 | 0 | if (UseJMC) { |
225 | 0 | CmdArgs.push_back("--whole-archive"); |
226 | 0 | if (IsPS4) |
227 | 0 | CmdArgs.push_back("-lSceDbgJmc"); |
228 | 0 | else |
229 | 0 | CmdArgs.push_back("-lSceJmc_nosubmission"); |
230 | 0 | CmdArgs.push_back("--no-whole-archive"); |
231 | 0 | } |
232 | |
|
233 | 0 | if (Args.hasArg(options::OPT_fuse_ld_EQ)) { |
234 | 0 | D.Diag(diag::err_drv_unsupported_opt_for_target) |
235 | 0 | << "-fuse-ld" << TC.getTriple().str(); |
236 | 0 | } |
237 | |
|
238 | 0 | std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName()); |
239 | 0 | const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str())); |
240 | |
|
241 | 0 | C.addCommand(std::make_unique<Command>(JA, *this, |
242 | 0 | ResponseFileSupport::AtFileUTF8(), |
243 | 0 | Exec, CmdArgs, Inputs, Output)); |
244 | 0 | } |
245 | | |
246 | | toolchains::PS4PS5Base::PS4PS5Base(const Driver &D, const llvm::Triple &Triple, |
247 | | const ArgList &Args, StringRef Platform, |
248 | | const char *EnvVar) |
249 | 0 | : Generic_ELF(D, Triple, Args) { |
250 | 0 | if (Args.hasArg(clang::driver::options::OPT_static)) |
251 | 0 | D.Diag(clang::diag::err_drv_unsupported_opt_for_target) |
252 | 0 | << "-static" << Platform; |
253 | | |
254 | | // Determine where to find the PS4/PS5 libraries. |
255 | | // If -isysroot was passed, use that as the SDK base path. |
256 | | // If not, we use the EnvVar if it exists; otherwise use the driver's |
257 | | // installation path, which should be <SDK_DIR>/host_tools/bin. |
258 | 0 | SmallString<80> Whence; |
259 | 0 | if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { |
260 | 0 | SDKRootDir = A->getValue(); |
261 | 0 | if (!llvm::sys::fs::exists(SDKRootDir)) |
262 | 0 | D.Diag(clang::diag::warn_missing_sysroot) << SDKRootDir; |
263 | 0 | Whence = A->getSpelling(); |
264 | 0 | } else if (const char *EnvValue = getenv(EnvVar)) { |
265 | 0 | SDKRootDir = EnvValue; |
266 | 0 | Whence = { "environment variable '", EnvVar, "'" }; |
267 | 0 | } else { |
268 | 0 | SDKRootDir = D.Dir + "/../../"; |
269 | 0 | Whence = "compiler's location"; |
270 | 0 | } |
271 | |
|
272 | 0 | SmallString<512> SDKIncludeDir(SDKRootDir); |
273 | 0 | llvm::sys::path::append(SDKIncludeDir, "target/include"); |
274 | 0 | if (!Args.hasArg(options::OPT_nostdinc) && |
275 | 0 | !Args.hasArg(options::OPT_nostdlibinc) && |
276 | 0 | !Args.hasArg(options::OPT_isysroot) && |
277 | 0 | !Args.hasArg(options::OPT__sysroot_EQ) && |
278 | 0 | !llvm::sys::fs::exists(SDKIncludeDir)) { |
279 | 0 | D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected) |
280 | 0 | << Twine(Platform, " system headers").str() << SDKIncludeDir << Whence; |
281 | 0 | } |
282 | |
|
283 | 0 | SmallString<512> SDKLibDir(SDKRootDir); |
284 | 0 | llvm::sys::path::append(SDKLibDir, "target/lib"); |
285 | 0 | if (!Args.hasArg(options::OPT_nostdlib) && |
286 | 0 | !Args.hasArg(options::OPT_nodefaultlibs) && |
287 | 0 | !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && |
288 | 0 | !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && |
289 | 0 | !Args.hasArg(options::OPT_emit_ast) && |
290 | 0 | !llvm::sys::fs::exists(SDKLibDir)) { |
291 | 0 | D.Diag(clang::diag::warn_drv_unable_to_find_directory_expected) |
292 | 0 | << Twine(Platform, " system libraries").str() << SDKLibDir << Whence; |
293 | 0 | return; |
294 | 0 | } |
295 | 0 | getFilePaths().push_back(std::string(SDKLibDir.str())); |
296 | 0 | } |
297 | | |
298 | | void toolchains::PS4PS5Base::AddClangSystemIncludeArgs( |
299 | | const ArgList &DriverArgs, |
300 | 0 | ArgStringList &CC1Args) const { |
301 | 0 | const Driver &D = getDriver(); |
302 | |
|
303 | 0 | if (DriverArgs.hasArg(options::OPT_nostdinc)) |
304 | 0 | return; |
305 | | |
306 | 0 | if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { |
307 | 0 | SmallString<128> Dir(D.ResourceDir); |
308 | 0 | llvm::sys::path::append(Dir, "include"); |
309 | 0 | addSystemInclude(DriverArgs, CC1Args, Dir.str()); |
310 | 0 | } |
311 | |
|
312 | 0 | if (DriverArgs.hasArg(options::OPT_nostdlibinc)) |
313 | 0 | return; |
314 | | |
315 | 0 | addExternCSystemInclude(DriverArgs, CC1Args, |
316 | 0 | SDKRootDir + "/target/include"); |
317 | 0 | addExternCSystemInclude(DriverArgs, CC1Args, |
318 | 0 | SDKRootDir + "/target/include_common"); |
319 | 0 | } |
320 | | |
321 | 0 | Tool *toolchains::PS4CPU::buildAssembler() const { |
322 | 0 | return new tools::PScpu::Assembler(*this); |
323 | 0 | } |
324 | | |
325 | 0 | Tool *toolchains::PS5CPU::buildAssembler() const { |
326 | | // PS5 does not support an external assembler. |
327 | 0 | getDriver().Diag(clang::diag::err_no_external_assembler); |
328 | 0 | return nullptr; |
329 | 0 | } |
330 | | |
331 | 0 | Tool *toolchains::PS4PS5Base::buildLinker() const { |
332 | 0 | return new tools::PScpu::Linker(*this); |
333 | 0 | } |
334 | | |
335 | 0 | SanitizerMask toolchains::PS4PS5Base::getSupportedSanitizers() const { |
336 | 0 | SanitizerMask Res = ToolChain::getSupportedSanitizers(); |
337 | 0 | Res |= SanitizerKind::Address; |
338 | 0 | Res |= SanitizerKind::PointerCompare; |
339 | 0 | Res |= SanitizerKind::PointerSubtract; |
340 | 0 | Res |= SanitizerKind::Vptr; |
341 | 0 | return Res; |
342 | 0 | } |
343 | | |
344 | 0 | SanitizerMask toolchains::PS5CPU::getSupportedSanitizers() const { |
345 | 0 | SanitizerMask Res = PS4PS5Base::getSupportedSanitizers(); |
346 | 0 | Res |= SanitizerKind::Thread; |
347 | 0 | return Res; |
348 | 0 | } |
349 | | |
350 | | void toolchains::PS4PS5Base::addClangTargetOptions( |
351 | | const ArgList &DriverArgs, ArgStringList &CC1Args, |
352 | 0 | Action::OffloadKind DeviceOffloadingKind) const { |
353 | | // PS4/PS5 do not use init arrays. |
354 | 0 | if (DriverArgs.hasArg(options::OPT_fuse_init_array)) { |
355 | 0 | Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array); |
356 | 0 | getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target) |
357 | 0 | << A->getAsString(DriverArgs) << getTriple().str(); |
358 | 0 | } |
359 | |
|
360 | 0 | CC1Args.push_back("-fno-use-init-array"); |
361 | |
|
362 | 0 | const Arg *A = |
363 | 0 | DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass, |
364 | 0 | options::OPT_fno_visibility_from_dllstorageclass); |
365 | 0 | if (!A || |
366 | 0 | A->getOption().matches(options::OPT_fvisibility_from_dllstorageclass)) { |
367 | 0 | CC1Args.push_back("-fvisibility-from-dllstorageclass"); |
368 | |
|
369 | 0 | if (DriverArgs.hasArg(options::OPT_fvisibility_dllexport_EQ)) |
370 | 0 | DriverArgs.AddLastArg(CC1Args, options::OPT_fvisibility_dllexport_EQ); |
371 | 0 | else |
372 | 0 | CC1Args.push_back("-fvisibility-dllexport=protected"); |
373 | |
|
374 | 0 | if (DriverArgs.hasArg(options::OPT_fvisibility_nodllstorageclass_EQ)) |
375 | 0 | DriverArgs.AddLastArg(CC1Args, |
376 | 0 | options::OPT_fvisibility_nodllstorageclass_EQ); |
377 | 0 | else |
378 | 0 | CC1Args.push_back("-fvisibility-nodllstorageclass=hidden"); |
379 | |
|
380 | 0 | if (DriverArgs.hasArg(options::OPT_fvisibility_externs_dllimport_EQ)) |
381 | 0 | DriverArgs.AddLastArg(CC1Args, |
382 | 0 | options::OPT_fvisibility_externs_dllimport_EQ); |
383 | 0 | else |
384 | 0 | CC1Args.push_back("-fvisibility-externs-dllimport=default"); |
385 | |
|
386 | 0 | if (DriverArgs.hasArg( |
387 | 0 | options::OPT_fvisibility_externs_nodllstorageclass_EQ)) |
388 | 0 | DriverArgs.AddLastArg( |
389 | 0 | CC1Args, options::OPT_fvisibility_externs_nodllstorageclass_EQ); |
390 | 0 | else |
391 | 0 | CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default"); |
392 | 0 | } |
393 | 0 | } |
394 | | |
395 | | // PS4 toolchain. |
396 | | toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, |
397 | | const llvm::opt::ArgList &Args) |
398 | 0 | : PS4PS5Base(D, Triple, Args, "PS4", "SCE_ORBIS_SDK_DIR") {} |
399 | | |
400 | | // PS5 toolchain. |
401 | | toolchains::PS5CPU::PS5CPU(const Driver &D, const llvm::Triple &Triple, |
402 | | const llvm::opt::ArgList &Args) |
403 | 0 | : PS4PS5Base(D, Triple, Args, "PS5", "SCE_PROSPERO_SDK_DIR") {} |