clang  6.0.0svn
PS4CPU.cpp
Go to the documentation of this file.
1 //===--- PS4CPU.cpp - PS4CPU ToolChain Implementations ----------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "PS4CPU.h"
11 #include "FreeBSD.h"
12 #include "CommonArgs.h"
14 #include "clang/Driver/Driver.h"
16 #include "clang/Driver/Options.h"
18 #include "llvm/Option/ArgList.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/Path.h"
21 #include <cstdlib> // ::getenv
22 
23 using namespace clang::driver;
24 using namespace clang;
25 using namespace llvm::opt;
26 
28 
29 void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args,
30  ArgStringList &CmdArgs) {
31  if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
32  false) ||
33  Args.hasFlag(options::OPT_fprofile_generate,
34  options::OPT_fno_profile_instr_generate, false) ||
35  Args.hasFlag(options::OPT_fprofile_generate_EQ,
36  options::OPT_fno_profile_instr_generate, false) ||
37  Args.hasFlag(options::OPT_fprofile_instr_generate,
38  options::OPT_fno_profile_instr_generate, false) ||
39  Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
40  options::OPT_fno_profile_instr_generate, false) ||
41  Args.hasArg(options::OPT_fcreate_profile) ||
42  Args.hasArg(options::OPT_coverage)))
43  CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a");
44 }
45 
47  const InputInfo &Output,
48  const InputInfoList &Inputs,
49  const ArgList &Args,
50  const char *LinkingOutput) const {
51  claimNoWarnArgs(Args);
52  ArgStringList CmdArgs;
53 
54  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
55 
56  CmdArgs.push_back("-o");
57  CmdArgs.push_back(Output.getFilename());
58 
59  assert(Inputs.size() == 1 && "Unexpected number of inputs.");
60  const InputInfo &Input = Inputs[0];
61  assert(Input.isFilename() && "Invalid input.");
62  CmdArgs.push_back(Input.getFilename());
63 
64  const char *Exec =
65  Args.MakeArgString(getToolChain().GetProgramPath("orbis-as"));
66  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
67 }
68 
69 static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) {
70  const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
71  if (SanArgs.needsUbsanRt()) {
72  CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak");
73  }
74  if (SanArgs.needsAsanRt()) {
75  CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak");
76  }
77 }
78 
79 static void ConstructPS4LinkJob(const Tool &T, Compilation &C,
80  const JobAction &JA, const InputInfo &Output,
81  const InputInfoList &Inputs,
82  const ArgList &Args,
83  const char *LinkingOutput) {
85  static_cast<const toolchains::FreeBSD &>(T.getToolChain());
86  const Driver &D = ToolChain.getDriver();
87  ArgStringList CmdArgs;
88 
89  // Silence warning for "clang -g foo.o -o foo"
90  Args.ClaimAllArgs(options::OPT_g_Group);
91  // and "clang -emit-llvm foo.o -o foo"
92  Args.ClaimAllArgs(options::OPT_emit_llvm);
93  // and for "clang -w foo.o -o foo". Other warning options are already
94  // handled somewhere else.
95  Args.ClaimAllArgs(options::OPT_w);
96 
97  if (!D.SysRoot.empty())
98  CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
99 
100  if (Args.hasArg(options::OPT_pie))
101  CmdArgs.push_back("-pie");
102 
103  if (Args.hasArg(options::OPT_rdynamic))
104  CmdArgs.push_back("-export-dynamic");
105  if (Args.hasArg(options::OPT_shared))
106  CmdArgs.push_back("--oformat=so");
107 
108  if (Output.isFilename()) {
109  CmdArgs.push_back("-o");
110  CmdArgs.push_back(Output.getFilename());
111  } else {
112  assert(Output.isNothing() && "Invalid output.");
113  }
114 
115  AddPS4SanitizerArgs(ToolChain, CmdArgs);
116 
117  Args.AddAllArgs(CmdArgs, options::OPT_L);
118  Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
119  Args.AddAllArgs(CmdArgs, options::OPT_e);
120  Args.AddAllArgs(CmdArgs, options::OPT_s);
121  Args.AddAllArgs(CmdArgs, options::OPT_t);
122  Args.AddAllArgs(CmdArgs, options::OPT_r);
123 
124  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
125  CmdArgs.push_back("--no-demangle");
126 
127  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
128 
129  if (Args.hasArg(options::OPT_pthread)) {
130  CmdArgs.push_back("-lpthread");
131  }
132 
133  const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld"));
134 
135  C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
136 }
137 
138 static void ConstructGoldLinkJob(const Tool &T, Compilation &C,
139  const JobAction &JA, const InputInfo &Output,
140  const InputInfoList &Inputs,
141  const ArgList &Args,
142  const char *LinkingOutput) {
144  static_cast<const toolchains::FreeBSD &>(T.getToolChain());
145  const Driver &D = ToolChain.getDriver();
146  ArgStringList CmdArgs;
147 
148  // Silence warning for "clang -g foo.o -o foo"
149  Args.ClaimAllArgs(options::OPT_g_Group);
150  // and "clang -emit-llvm foo.o -o foo"
151  Args.ClaimAllArgs(options::OPT_emit_llvm);
152  // and for "clang -w foo.o -o foo". Other warning options are already
153  // handled somewhere else.
154  Args.ClaimAllArgs(options::OPT_w);
155 
156  if (!D.SysRoot.empty())
157  CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
158 
159  if (Args.hasArg(options::OPT_pie))
160  CmdArgs.push_back("-pie");
161 
162  if (Args.hasArg(options::OPT_static)) {
163  CmdArgs.push_back("-Bstatic");
164  } else {
165  if (Args.hasArg(options::OPT_rdynamic))
166  CmdArgs.push_back("-export-dynamic");
167  CmdArgs.push_back("--eh-frame-hdr");
168  if (Args.hasArg(options::OPT_shared)) {
169  CmdArgs.push_back("-Bshareable");
170  } else {
171  CmdArgs.push_back("-dynamic-linker");
172  CmdArgs.push_back("/libexec/ld-elf.so.1");
173  }
174  CmdArgs.push_back("--enable-new-dtags");
175  }
176 
177  if (Output.isFilename()) {
178  CmdArgs.push_back("-o");
179  CmdArgs.push_back(Output.getFilename());
180  } else {
181  assert(Output.isNothing() && "Invalid output.");
182  }
183 
184  AddPS4SanitizerArgs(ToolChain, CmdArgs);
185 
186  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
187  const char *crt1 = nullptr;
188  if (!Args.hasArg(options::OPT_shared)) {
189  if (Args.hasArg(options::OPT_pg))
190  crt1 = "gcrt1.o";
191  else if (Args.hasArg(options::OPT_pie))
192  crt1 = "Scrt1.o";
193  else
194  crt1 = "crt1.o";
195  }
196  if (crt1)
197  CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
198 
199  CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
200 
201  const char *crtbegin = nullptr;
202  if (Args.hasArg(options::OPT_static))
203  crtbegin = "crtbeginT.o";
204  else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
205  crtbegin = "crtbeginS.o";
206  else
207  crtbegin = "crtbegin.o";
208 
209  CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
210  }
211 
212  Args.AddAllArgs(CmdArgs, options::OPT_L);
213  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
214  Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
215  Args.AddAllArgs(CmdArgs, options::OPT_e);
216  Args.AddAllArgs(CmdArgs, options::OPT_s);
217  Args.AddAllArgs(CmdArgs, options::OPT_t);
218  Args.AddAllArgs(CmdArgs, options::OPT_r);
219 
220  if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
221  CmdArgs.push_back("--no-demangle");
222 
223  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
224 
225  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
226  // For PS4, we always want to pass libm, libstdc++ and libkernel
227  // libraries for both C and C++ compilations.
228  CmdArgs.push_back("-lkernel");
229  if (D.CCCIsCXX()) {
230  if (ToolChain.ShouldLinkCXXStdlib(Args))
231  ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
232  if (Args.hasArg(options::OPT_pg))
233  CmdArgs.push_back("-lm_p");
234  else
235  CmdArgs.push_back("-lm");
236  }
237  // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
238  // the default system libraries. Just mimic this for now.
239  if (Args.hasArg(options::OPT_pg))
240  CmdArgs.push_back("-lgcc_p");
241  else
242  CmdArgs.push_back("-lcompiler_rt");
243  if (Args.hasArg(options::OPT_static)) {
244  CmdArgs.push_back("-lstdc++");
245  } else if (Args.hasArg(options::OPT_pg)) {
246  CmdArgs.push_back("-lgcc_eh_p");
247  } else {
248  CmdArgs.push_back("--as-needed");
249  CmdArgs.push_back("-lstdc++");
250  CmdArgs.push_back("--no-as-needed");
251  }
252 
253  if (Args.hasArg(options::OPT_pthread)) {
254  if (Args.hasArg(options::OPT_pg))
255  CmdArgs.push_back("-lpthread_p");
256  else
257  CmdArgs.push_back("-lpthread");
258  }
259 
260  if (Args.hasArg(options::OPT_pg)) {
261  if (Args.hasArg(options::OPT_shared))
262  CmdArgs.push_back("-lc");
263  else {
264  if (Args.hasArg(options::OPT_static)) {
265  CmdArgs.push_back("--start-group");
266  CmdArgs.push_back("-lc_p");
267  CmdArgs.push_back("-lpthread_p");
268  CmdArgs.push_back("--end-group");
269  } else {
270  CmdArgs.push_back("-lc_p");
271  }
272  }
273  CmdArgs.push_back("-lgcc_p");
274  } else {
275  if (Args.hasArg(options::OPT_static)) {
276  CmdArgs.push_back("--start-group");
277  CmdArgs.push_back("-lc");
278  CmdArgs.push_back("-lpthread");
279  CmdArgs.push_back("--end-group");
280  } else {
281  CmdArgs.push_back("-lc");
282  }
283  CmdArgs.push_back("-lcompiler_rt");
284  }
285 
286  if (Args.hasArg(options::OPT_static)) {
287  CmdArgs.push_back("-lstdc++");
288  } else if (Args.hasArg(options::OPT_pg)) {
289  CmdArgs.push_back("-lgcc_eh_p");
290  } else {
291  CmdArgs.push_back("--as-needed");
292  CmdArgs.push_back("-lstdc++");
293  CmdArgs.push_back("--no-as-needed");
294  }
295  }
296 
297  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
298  if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie))
299  CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
300  else
301  CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
302  CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
303  }
304 
305  const char *Exec =
306 #ifdef LLVM_ON_WIN32
307  Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold"));
308 #else
309  Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld"));
310 #endif
311 
312  C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
313 }
314 
316  const InputInfo &Output,
317  const InputInfoList &Inputs,
318  const ArgList &Args,
319  const char *LinkingOutput) const {
321  static_cast<const toolchains::FreeBSD &>(getToolChain());
322  const Driver &D = ToolChain.getDriver();
323  bool PS4Linker;
324  StringRef LinkerOptName;
325  if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) {
326  LinkerOptName = A->getValue();
327  if (LinkerOptName != "ps4" && LinkerOptName != "gold")
328  D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName;
329  }
330 
331  if (LinkerOptName == "gold")
332  PS4Linker = false;
333  else if (LinkerOptName == "ps4")
334  PS4Linker = true;
335  else
336  PS4Linker = !Args.hasArg(options::OPT_shared);
337 
338  if (PS4Linker)
339  ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput);
340  else
341  ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput);
342 }
343 
344 toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple,
345  const ArgList &Args)
346  : Generic_ELF(D, Triple, Args) {
347  if (Args.hasArg(clang::driver::options::OPT_static))
348  D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static"
349  << "PS4";
350 
351  // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR
352  // if it exists; otherwise use the driver's installation path, which
353  // should be <SDK_DIR>/host_tools/bin.
354 
355  SmallString<512> PS4SDKDir;
356  if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) {
357  if (!llvm::sys::fs::exists(EnvValue))
358  getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue;
359  PS4SDKDir = EnvValue;
360  } else {
361  PS4SDKDir = getDriver().Dir;
362  llvm::sys::path::append(PS4SDKDir, "/../../");
363  }
364 
365  // By default, the driver won't report a warning if it can't find
366  // PS4's include or lib directories. This behavior could be changed if
367  // -Weverything or -Winvalid-or-nonexistent-directory options are passed.
368  // If -isysroot was passed, use that as the SDK base path.
369  std::string PrefixDir;
370  if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
371  PrefixDir = A->getValue();
372  if (!llvm::sys::fs::exists(PrefixDir))
373  getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir;
374  } else
375  PrefixDir = PS4SDKDir.str();
376 
377  SmallString<512> PS4SDKIncludeDir(PrefixDir);
378  llvm::sys::path::append(PS4SDKIncludeDir, "target/include");
379  if (!Args.hasArg(options::OPT_nostdinc) &&
380  !Args.hasArg(options::OPT_nostdlibinc) &&
381  !Args.hasArg(options::OPT_isysroot) &&
382  !Args.hasArg(options::OPT__sysroot_EQ) &&
383  !llvm::sys::fs::exists(PS4SDKIncludeDir)) {
384  getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
385  << "PS4 system headers" << PS4SDKIncludeDir;
386  }
387 
388  SmallString<512> PS4SDKLibDir(PS4SDKDir);
389  llvm::sys::path::append(PS4SDKLibDir, "target/lib");
390  if (!Args.hasArg(options::OPT_nostdlib) &&
391  !Args.hasArg(options::OPT_nodefaultlibs) &&
392  !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) &&
393  !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) &&
394  !Args.hasArg(options::OPT_emit_ast) &&
395  !llvm::sys::fs::exists(PS4SDKLibDir)) {
396  getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected)
397  << "PS4 system libraries" << PS4SDKLibDir;
398  return;
399  }
400  getFilePaths().push_back(PS4SDKLibDir.str());
401 }
402 
404  return new tools::PS4cpu::Assemble(*this);
405 }
406 
408  return new tools::PS4cpu::Link(*this);
409 }
410 
411 bool toolchains::PS4CPU::isPICDefault() const { return true; }
412 
413 bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; }
414 
417  Res |= SanitizerKind::Address;
418  Res |= SanitizerKind::Vptr;
419  return Res;
420 }
void addProfileRTArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs)
Tool * buildLinker() const override
Definition: PS4CPU.cpp:407
DiagnosticBuilder Diag(unsigned DiagID) const
Definition: Driver.h:116
const char * getFilename() const
Definition: InputInfo.h:84
PS4CPU(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
Definition: PS4CPU.cpp:344
std::string Dir
The path the driver executable was in, as invoked from the command line.
Definition: Driver.h:127
InputInfo - Wrapper for information about an input source.
Definition: InputInfo.h:23
std::string GetFilePath(const char *Name) const
Definition: ToolChain.cpp:391
path_list & getFilePaths()
Definition: ToolChain.h:202
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:65
static void ConstructPS4LinkJob(const Tool &T, Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput)
Definition: PS4CPU.cpp:79
Tool * buildAssembler() const override
Definition: PS4CPU.cpp:403
bool isPICDefault() const override
Test whether this toolchain defaults to PIC.
Definition: PS4CPU.cpp:411
const FunctionProtoType * T
void addCommand(std::unique_ptr< Command > C)
Definition: Compilation.h:189
void AddFilePathLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const
AddFilePathLibArgs - Add each thing in getFilePaths() as a "-L" option.
Definition: ToolChain.cpp:740
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override
AddCXXStdlibLibArgs - Add the system specific linker arguments to use for the given C++ standard libr...
Definition: FreeBSD.cpp:340
const Driver & getDriver() const
Definition: ToolChain.h:167
bool CCCIsCXX() const
Whether the driver should follow g++ like behavior.
Definition: Driver.h:174
bool HasNativeLLVMSupport() const override
HasNativeLTOLinker - Check whether the linker and related tools have native LLVM support.
Definition: PS4CPU.cpp:413
static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs)
Definition: PS4CPU.cpp:69
bool ShouldLinkCXXStdlib(const llvm::opt::ArgList &Args) const
Returns if the C++ standard library should be linked in.
Definition: ToolChain.cpp:717
Dataflow Directional Tag Classes.
uint64_t SanitizerMask
Definition: Sanitizers.h:24
void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const JobAction &JA)
std::string SysRoot
sysroot, if present
Definition: Driver.h:149
Tool - Information on a specific compilation tool.
Definition: Tool.h:34
const SanitizerArgs & getSanitizerArgs() const
Definition: ToolChain.cpp:105
void ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override
ConstructJob - Construct jobs to perform the action JA, writing to Output and with Inputs...
Definition: PS4CPU.cpp:46
SanitizerMask getSupportedSanitizers() const override
Return sanitizers which are available in this toolchain.
Definition: PS4CPU.cpp:415
void claimNoWarnArgs(const llvm::opt::ArgList &Args)
Compilation - A set of tasks to perform for a single driver invocation.
Definition: Compilation.h:34
static void ConstructGoldLinkJob(const Tool &T, Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput)
Definition: PS4CPU.cpp:138
virtual SanitizerMask getSupportedSanitizers() const
Return sanitizers which are available in this toolchain.
Definition: ToolChain.cpp:776
const ToolChain & getToolChain() const
Definition: Tool.h:84
bool isNothing() const
Definition: InputInfo.h:75
std::string GetProgramPath(const char *Name) const
Definition: ToolChain.cpp:395
bool isFilename() const
Definition: InputInfo.h:76
ToolChain - Access to tools for a single platform.
Definition: ToolChain.h:73