Skip to content

Commit 03fe7a8

Browse files
[PS4/PS5][NFC] Split PScpu::Linker into PS4/PS5 classes (#98884)
It has long been the case on PlayStation that the linker itself has taken on much of the responsibility that is traditionally the domain of the C language driver elsewhere: which linker script to use, selection of CRT objects, and so forth. This is changing on PS5. The driver will assume responsibility for such things. However, the situation on PS4 will remain as-is. To accommodate this divergence, we must first separate how linker Jobs are created. `clang/test/Driver/ps4-linker.c` has been similarly split for related reasons. In subsequent changes, PS5-specific linking behaviour can be moved from SIE private patches in the PS5 linker to the (upstream) driver without affecting the behaviour or implementation of PS4.
1 parent 903f6fc commit 03fe7a8

File tree

5 files changed

+185
-68
lines changed

5 files changed

+185
-68
lines changed

clang/lib/Driver/ToolChains/PS4CPU.cpp

Lines changed: 125 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ void toolchains::PS5CPU::addSanitizerArgs(const ArgList &Args,
118118
CmdArgs.push_back(arg("SceThreadSanitizer_nosubmission_stub_weak"));
119119
}
120120

121-
void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
122-
const InputInfo &Output,
123-
const InputInfoList &Inputs,
124-
const ArgList &Args,
125-
const char *LinkingOutput) const {
121+
void tools::PS4cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
122+
const InputInfo &Output,
123+
const InputInfoList &Inputs,
124+
const ArgList &Args,
125+
const char *LinkingOutput) const {
126126
auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
127127
const Driver &D = TC.getDriver();
128128
ArgStringList CmdArgs;
@@ -155,14 +155,120 @@ void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
155155
const bool UseLTO = D.isUsingLTO();
156156
const bool UseJMC =
157157
Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
158-
const bool IsPS4 = TC.getTriple().isPS4();
159158

160-
const char *PS4LTOArgs = "";
159+
const char *LTOArgs = "";
161160
auto AddCodeGenFlag = [&](Twine Flag) {
162-
if (IsPS4)
163-
PS4LTOArgs = Args.MakeArgString(Twine(PS4LTOArgs) + " " + Flag);
161+
LTOArgs = Args.MakeArgString(Twine(LTOArgs) + " " + Flag);
162+
};
163+
164+
if (UseLTO) {
165+
// We default to creating the arange section, but LTO does not. Enable it
166+
// here.
167+
AddCodeGenFlag("-generate-arange-section");
168+
169+
// This tells LTO to perform JustMyCode instrumentation.
170+
if (UseJMC)
171+
AddCodeGenFlag("-enable-jmc-instrument");
172+
173+
if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
174+
AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
175+
176+
StringRef Parallelism = getLTOParallelism(Args, D);
177+
if (!Parallelism.empty())
178+
AddCodeGenFlag(Twine("-threads=") + Parallelism);
179+
180+
const char *Prefix = nullptr;
181+
if (D.getLTOMode() == LTOK_Thin)
182+
Prefix = "-lto-thin-debug-options=";
183+
else if (D.getLTOMode() == LTOK_Full)
184+
Prefix = "-lto-debug-options=";
164185
else
165-
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag));
186+
llvm_unreachable("new LTO mode?");
187+
188+
CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + LTOArgs));
189+
}
190+
191+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
192+
TC.addSanitizerArgs(Args, CmdArgs, "-l", "");
193+
194+
if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) {
195+
if (D.getLTOMode() == LTOK_Thin)
196+
CmdArgs.push_back("--lto=thin");
197+
else if (D.getLTOMode() == LTOK_Full)
198+
CmdArgs.push_back("--lto=full");
199+
}
200+
201+
Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
202+
options::OPT_s, options::OPT_t});
203+
204+
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
205+
CmdArgs.push_back("--no-demangle");
206+
207+
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
208+
209+
if (Args.hasArg(options::OPT_pthread)) {
210+
CmdArgs.push_back("-lpthread");
211+
}
212+
213+
if (UseJMC) {
214+
CmdArgs.push_back("--whole-archive");
215+
CmdArgs.push_back("-lSceDbgJmc");
216+
CmdArgs.push_back("--no-whole-archive");
217+
}
218+
219+
if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
220+
D.Diag(diag::err_drv_unsupported_opt_for_target)
221+
<< "-fuse-ld" << TC.getTriple().str();
222+
}
223+
224+
std::string LdName = TC.qualifyPSCmdName(TC.getLinkerBaseName());
225+
const char *Exec = Args.MakeArgString(TC.GetProgramPath(LdName.c_str()));
226+
227+
C.addCommand(std::make_unique<Command>(JA, *this,
228+
ResponseFileSupport::AtFileUTF8(),
229+
Exec, CmdArgs, Inputs, Output));
230+
}
231+
232+
void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
233+
const InputInfo &Output,
234+
const InputInfoList &Inputs,
235+
const ArgList &Args,
236+
const char *LinkingOutput) const {
237+
auto &TC = static_cast<const toolchains::PS4PS5Base &>(getToolChain());
238+
const Driver &D = TC.getDriver();
239+
ArgStringList CmdArgs;
240+
241+
// Silence warning for "clang -g foo.o -o foo"
242+
Args.ClaimAllArgs(options::OPT_g_Group);
243+
// and "clang -emit-llvm foo.o -o foo"
244+
Args.ClaimAllArgs(options::OPT_emit_llvm);
245+
// and for "clang -w foo.o -o foo". Other warning options are already
246+
// handled somewhere else.
247+
Args.ClaimAllArgs(options::OPT_w);
248+
249+
if (!D.SysRoot.empty())
250+
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
251+
252+
if (Args.hasArg(options::OPT_pie))
253+
CmdArgs.push_back("-pie");
254+
255+
if (Args.hasArg(options::OPT_rdynamic))
256+
CmdArgs.push_back("-export-dynamic");
257+
if (Args.hasArg(options::OPT_shared))
258+
CmdArgs.push_back("--shared");
259+
260+
assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
261+
if (Output.isFilename()) {
262+
CmdArgs.push_back("-o");
263+
CmdArgs.push_back(Output.getFilename());
264+
}
265+
266+
const bool UseLTO = D.isUsingLTO();
267+
const bool UseJMC =
268+
Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
269+
270+
auto AddCodeGenFlag = [&](Twine Flag) {
271+
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag));
166272
};
167273

168274
if (UseLTO) {
@@ -178,24 +284,8 @@ void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
178284
AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
179285

180286
StringRef Parallelism = getLTOParallelism(Args, D);
181-
if (!Parallelism.empty()) {
182-
if (IsPS4)
183-
AddCodeGenFlag(Twine("-threads=") + Parallelism);
184-
else
185-
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism));
186-
}
187-
188-
if (IsPS4) {
189-
const char *Prefix = nullptr;
190-
if (D.getLTOMode() == LTOK_Thin)
191-
Prefix = "-lto-thin-debug-options=";
192-
else if (D.getLTOMode() == LTOK_Full)
193-
Prefix = "-lto-debug-options=";
194-
else
195-
llvm_unreachable("new LTO mode?");
196-
197-
CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + PS4LTOArgs));
198-
}
287+
if (!Parallelism.empty())
288+
CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism));
199289
}
200290

201291
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
@@ -222,10 +312,7 @@ void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
222312

223313
if (UseJMC) {
224314
CmdArgs.push_back("--whole-archive");
225-
if (IsPS4)
226-
CmdArgs.push_back("-lSceDbgJmc");
227-
else
228-
CmdArgs.push_back("-lSceJmc_nosubmission");
315+
CmdArgs.push_back("-lSceJmc_nosubmission");
229316
CmdArgs.push_back("--no-whole-archive");
230317
}
231318

@@ -321,14 +408,18 @@ Tool *toolchains::PS4CPU::buildAssembler() const {
321408
return new tools::PScpu::Assembler(*this);
322409
}
323410

411+
Tool *toolchains::PS4CPU::buildLinker() const {
412+
return new tools::PS4cpu::Linker(*this);
413+
}
414+
324415
Tool *toolchains::PS5CPU::buildAssembler() const {
325416
// PS5 does not support an external assembler.
326417
getDriver().Diag(clang::diag::err_no_external_assembler);
327418
return nullptr;
328419
}
329420

330-
Tool *toolchains::PS4PS5Base::buildLinker() const {
331-
return new tools::PScpu::Linker(*this);
421+
Tool *toolchains::PS5CPU::buildLinker() const {
422+
return new tools::PS5cpu::Linker(*this);
332423
}
333424

334425
SanitizerMask toolchains::PS4PS5Base::getSupportedSanitizers() const {

clang/lib/Driver/ToolChains/PS4CPU.h

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
3838
const llvm::opt::ArgList &TCArgs,
3939
const char *LinkingOutput) const override;
4040
};
41+
} // namespace PScpu
4142

43+
namespace PS4cpu {
4244
class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
4345
public:
44-
Linker(const ToolChain &TC) : Tool("PScpu::Linker", "linker", TC) {}
46+
Linker(const ToolChain &TC) : Tool("PS4cpu::Linker", "linker", TC) {}
4547

4648
bool hasIntegratedCPP() const override { return false; }
4749
bool isLinkJob() const override { return true; }
@@ -51,7 +53,23 @@ class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
5153
const llvm::opt::ArgList &TCArgs,
5254
const char *LinkingOutput) const override;
5355
};
54-
} // namespace PScpu
56+
} // namespace PS4cpu
57+
58+
namespace PS5cpu {
59+
class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
60+
public:
61+
Linker(const ToolChain &TC) : Tool("PS5cpu::Linker", "linker", TC) {}
62+
63+
bool hasIntegratedCPP() const override { return false; }
64+
bool isLinkJob() const override { return true; }
65+
66+
void ConstructJob(Compilation &C, const JobAction &JA,
67+
const InputInfo &Output, const InputInfoList &Inputs,
68+
const llvm::opt::ArgList &TCArgs,
69+
const char *LinkingOutput) const override;
70+
};
71+
} // namespace PS5cpu
72+
5573
} // namespace tools
5674

5775
namespace toolchains {
@@ -110,9 +128,6 @@ class LLVM_LIBRARY_VISIBILITY PS4PS5Base : public Generic_ELF {
110128
const char *Suffix) const = 0;
111129
virtual const char *getProfileRTLibName() const = 0;
112130

113-
protected:
114-
Tool *buildLinker() const override;
115-
116131
private:
117132
// We compute the SDK root dir in the ctor, and use it later.
118133
std::string SDKRootDir;
@@ -143,6 +158,7 @@ class LLVM_LIBRARY_VISIBILITY PS4CPU : public PS4PS5Base {
143158

144159
protected:
145160
Tool *buildAssembler() const override;
161+
Tool *buildLinker() const override;
146162
};
147163

148164
// PS5-specific Toolchain class.
@@ -168,6 +184,7 @@ class LLVM_LIBRARY_VISIBILITY PS5CPU : public PS4PS5Base {
168184

169185
protected:
170186
Tool *buildAssembler() const override;
187+
Tool *buildLinker() const override;
171188
};
172189

173190
} // end namespace toolchains

clang/test/Driver/ps4-linker.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Test the driver's control over the JustMyCode behavior with linker flags.
2+
3+
// RUN: %clang --target=x86_64-scei-ps4 -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-LIB %s
4+
// RUN: %clang --target=x86_64-scei-ps4 -flto=thin -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-THIN-LTO,CHECK-LIB %s
5+
// RUN: %clang --target=x86_64-scei-ps4 -flto=full -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-FULL-LTO,CHECK-LIB %s
6+
7+
// CHECK-NOT: -enable-jmc-instrument
8+
// CHECK-THIN-LTO: "-lto-thin-debug-options= -generate-arange-section -enable-jmc-instrument"
9+
// CHECK-FULL-LTO: "-lto-debug-options= -generate-arange-section -enable-jmc-instrument"
10+
11+
// Check the default library name.
12+
// CHECK-LIB: "--whole-archive" "-lSceDbgJmc" "--no-whole-archive"
13+
14+
// Test the driver's control over the -fcrash-diagnostics-dir behavior with linker flags.
15+
16+
// RUN: %clang --target=x86_64-scei-ps4 -flto=thin -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-THIN-LTO %s
17+
// RUN: %clang --target=x86_64-scei-ps4 -flto=full -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-FULL-LTO %s
18+
19+
// CHECK-DIAG-THIN-LTO: "-lto-thin-debug-options= -generate-arange-section -crash-diagnostics-dir=mydumps"
20+
// CHECK-DIAG-FULL-LTO: "-lto-debug-options= -generate-arange-section -crash-diagnostics-dir=mydumps"

clang/test/Driver/ps4-ps5-linker.c

Lines changed: 0 additions & 29 deletions
This file was deleted.

clang/test/Driver/ps5-linker.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Test the driver's control over the JustMyCode behavior with linker flags.
2+
3+
// RUN: %clang --target=x86_64-scei-ps5 -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-LIB %s
4+
// RUN: %clang --target=x86_64-scei-ps5 -flto -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LTO,CHECK-LIB %s
5+
6+
// CHECK-NOT: -plugin-opt=-enable-jmc-instrument
7+
// CHECK-LTO: -plugin-opt=-enable-jmc-instrument
8+
9+
// Check the default library name.
10+
// CHECK-LIB: "--whole-archive" "-lSceJmc_nosubmission" "--no-whole-archive"
11+
12+
// Test the driver's control over the -fcrash-diagnostics-dir behavior with linker flags.
13+
14+
// RUN: %clang --target=x86_64-scei-ps5 -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG %s
15+
// RUN: %clang --target=x86_64-scei-ps5 -flto -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-LTO %s
16+
17+
// CHECK-DIAG-NOT: -plugin-opt=-crash-diagnostics-dir=mydumps
18+
// CHECK-DIAG-LTO: -plugin-opt=-crash-diagnostics-dir=mydumps

0 commit comments

Comments
 (0)