1 | //===--- AIX.cpp - AIX 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 "AIX.h" |
10 | #include "Arch/PPC.h" |
11 | #include "CommonArgs.h" |
12 | #include "clang/Driver/Compilation.h" |
13 | #include "clang/Driver/Options.h" |
14 | #include "clang/Driver/SanitizerArgs.h" |
15 | #include "llvm/ADT/StringExtras.h" |
16 | #include "llvm/Option/ArgList.h" |
17 | #include "llvm/ProfileData/InstrProf.h" |
18 | #include "llvm/Support/Path.h" |
19 | |
20 | #include <set> |
21 | |
22 | using AIX = clang::driver::toolchains::AIX; |
23 | using namespace clang::driver; |
24 | using namespace clang::driver::tools; |
25 | using namespace clang::driver::toolchains; |
26 | |
27 | using namespace llvm::opt; |
28 | using namespace llvm::sys; |
29 | |
30 | void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, |
31 | const InputInfo &Output, |
32 | const InputInfoList &Inputs, |
33 | const ArgList &Args, |
34 | const char *LinkingOutput) const { |
35 | const Driver &D = getToolChain().getDriver(); |
36 | ArgStringList CmdArgs; |
37 | |
38 | const bool IsArch32Bit = getToolChain().getTriple().isArch32Bit(); |
39 | const bool IsArch64Bit = getToolChain().getTriple().isArch64Bit(); |
40 | // Only support 32 and 64 bit. |
41 | if (!IsArch32Bit && !IsArch64Bit) |
42 | llvm_unreachable("Unsupported bit width value." ); |
43 | |
44 | if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) { |
45 | D.Diag(diag::DiagID: err_drv_unsupported_opt_for_target) |
46 | << A->getSpelling() << D.getTargetTriple(); |
47 | } |
48 | |
49 | // Specify the mode in which the as(1) command operates. |
50 | if (IsArch32Bit) { |
51 | CmdArgs.push_back(Elt: "-a32" ); |
52 | } else { |
53 | // Must be 64-bit, otherwise asserted already. |
54 | CmdArgs.push_back(Elt: "-a64" ); |
55 | } |
56 | |
57 | // Accept any mixture of instructions. |
58 | // On Power for AIX and Linux, this behaviour matches that of GCC for both the |
59 | // user-provided assembler source case and the compiler-produced assembler |
60 | // source case. Yet XL with user-provided assembler source would not add this. |
61 | CmdArgs.push_back(Elt: "-many" ); |
62 | |
63 | Args.AddAllArgValues(Output&: CmdArgs, options::Id0: OPT_Wa_COMMA, options::Id1: OPT_Xassembler); |
64 | |
65 | // Specify assembler output file. |
66 | assert((Output.isFilename() || Output.isNothing()) && "Invalid output." ); |
67 | if (Output.isFilename()) { |
68 | CmdArgs.push_back(Elt: "-o" ); |
69 | CmdArgs.push_back(Elt: Output.getFilename()); |
70 | } |
71 | |
72 | // Specify assembler input file. |
73 | // The system assembler on AIX takes exactly one input file. The driver is |
74 | // expected to invoke as(1) separately for each assembler source input file. |
75 | if (Inputs.size() != 1) |
76 | llvm_unreachable("Invalid number of input files." ); |
77 | const InputInfo &II = Inputs[0]; |
78 | assert((II.isFilename() || II.isNothing()) && "Invalid input." ); |
79 | if (II.isFilename()) |
80 | CmdArgs.push_back(Elt: II.getFilename()); |
81 | |
82 | const char *Exec = Args.MakeArgString(Str: getToolChain().GetProgramPath(Name: "as" )); |
83 | C.addCommand(C: std::make_unique<Command>(args: JA, args: *this, args: ResponseFileSupport::None(), |
84 | args&: Exec, args&: CmdArgs, args: Inputs, args: Output)); |
85 | } |
86 | |
87 | // Determine whether there are any linker options that supply an export list |
88 | // (or equivalent information about what to export) being sent to the linker. |
89 | static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) { |
90 | for (size_t i = 0, Size = CmdArgs.size(); i < Size; ++i) { |
91 | llvm::StringRef ArgString(CmdArgs[i]); |
92 | |
93 | if (ArgString.starts_with(Prefix: "-bE:" ) || ArgString.starts_with(Prefix: "-bexport:" ) || |
94 | ArgString == "-bexpall" || ArgString == "-bexpfull" ) |
95 | return true; |
96 | |
97 | // If we split -b option, check the next opt. |
98 | if (ArgString == "-b" && i + 1 < Size) { |
99 | ++i; |
100 | llvm::StringRef ArgNextString(CmdArgs[i]); |
101 | if (ArgNextString.starts_with(Prefix: "E:" ) || |
102 | ArgNextString.starts_with(Prefix: "export:" ) || ArgNextString == "expall" || |
103 | ArgNextString == "expfull" ) |
104 | return true; |
105 | } |
106 | } |
107 | return false; |
108 | } |
109 | |
110 | void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, |
111 | const InputInfo &Output, |
112 | const InputInfoList &Inputs, const ArgList &Args, |
113 | const char *LinkingOutput) const { |
114 | const AIX &ToolChain = static_cast<const AIX &>(getToolChain()); |
115 | const Driver &D = ToolChain.getDriver(); |
116 | ArgStringList CmdArgs; |
117 | |
118 | const bool IsArch32Bit = ToolChain.getTriple().isArch32Bit(); |
119 | const bool IsArch64Bit = ToolChain.getTriple().isArch64Bit(); |
120 | // Only support 32 and 64 bit. |
121 | if (!(IsArch32Bit || IsArch64Bit)) |
122 | llvm_unreachable("Unsupported bit width value." ); |
123 | |
124 | if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) { |
125 | D.Diag(diag::DiagID: err_drv_unsupported_opt_for_target) |
126 | << A->getSpelling() << D.getTargetTriple(); |
127 | } |
128 | |
129 | // Force static linking when "-static" is present. |
130 | if (Args.hasArg(options::OPT_static)) |
131 | CmdArgs.push_back(Elt: "-bnso" ); |
132 | |
133 | // Add options for shared libraries. |
134 | if (Args.hasArg(options::OPT_shared)) { |
135 | CmdArgs.push_back(Elt: "-bM:SRE" ); |
136 | CmdArgs.push_back(Elt: "-bnoentry" ); |
137 | } |
138 | |
139 | if (Args.hasFlag(options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr, |
140 | false)) { |
141 | if (Args.hasArg(options::OPT_shared)) |
142 | D.Diag(diag::DiagID: err_roptr_cannot_build_shared); |
143 | |
144 | // The `-mxcoff-roptr` option places constants in RO sections as much as |
145 | // possible. Then `-bforceimprw` changes such sections to RW if they contain |
146 | // imported symbols that need to be resolved. |
147 | CmdArgs.push_back(Elt: "-bforceimprw" ); |
148 | } |
149 | |
150 | // PGO instrumentation generates symbols belonging to special sections, and |
151 | // the linker needs to place all symbols in a particular section together in |
152 | // memory; the AIX linker does that under an option. |
153 | if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, |
154 | false) || |
155 | Args.hasFlag(options::OPT_fprofile_generate, |
156 | options::OPT_fno_profile_generate, false) || |
157 | Args.hasFlag(options::OPT_fprofile_generate_EQ, |
158 | options::OPT_fno_profile_generate, false) || |
159 | Args.hasFlag(options::OPT_fprofile_instr_generate, |
160 | options::OPT_fno_profile_instr_generate, false) || |
161 | Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, |
162 | options::OPT_fno_profile_instr_generate, false) || |
163 | Args.hasFlag(options::OPT_fcs_profile_generate, |
164 | options::OPT_fno_profile_generate, false) || |
165 | Args.hasFlag(options::OPT_fcs_profile_generate_EQ, |
166 | options::OPT_fno_profile_generate, false) || |
167 | Args.hasArg(options::OPT_fcreate_profile) || |
168 | Args.hasArg(options::OPT_coverage)) |
169 | CmdArgs.push_back(Elt: "-bdbg:namedsects:ss" ); |
170 | |
171 | if (Arg *A = |
172 | Args.getLastArg(clang::driver::options::OPT_mxcoff_build_id_EQ)) { |
173 | StringRef BuildId = A->getValue(); |
174 | if (BuildId[0] != '0' || BuildId[1] != 'x' || |
175 | BuildId.find_if_not(F: llvm::isHexDigit, From: 2) != StringRef::npos) |
176 | ToolChain.getDriver().Diag(diag::DiagID: err_drv_unsupported_option_argument) |
177 | << A->getSpelling() << BuildId; |
178 | else { |
179 | std::string LinkerFlag = "-bdbg:ldrinfo:xcoff_binary_id:0x" ; |
180 | if (BuildId.size() % 2) // Prepend a 0 if odd number of digits. |
181 | LinkerFlag += "0" ; |
182 | LinkerFlag += BuildId.drop_front(N: 2).lower(); |
183 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: LinkerFlag)); |
184 | } |
185 | } |
186 | |
187 | // Specify linker output file. |
188 | assert((Output.isFilename() || Output.isNothing()) && "Invalid output." ); |
189 | if (Output.isFilename()) { |
190 | CmdArgs.push_back(Elt: "-o" ); |
191 | CmdArgs.push_back(Elt: Output.getFilename()); |
192 | } |
193 | |
194 | // Set linking mode (i.e., 32/64-bit) and the address of |
195 | // text and data sections based on arch bit width. |
196 | if (IsArch32Bit) { |
197 | CmdArgs.push_back(Elt: "-b32" ); |
198 | CmdArgs.push_back(Elt: "-bpT:0x10000000" ); |
199 | CmdArgs.push_back(Elt: "-bpD:0x20000000" ); |
200 | } else { |
201 | // Must be 64-bit, otherwise asserted already. |
202 | CmdArgs.push_back(Elt: "-b64" ); |
203 | CmdArgs.push_back(Elt: "-bpT:0x100000000" ); |
204 | CmdArgs.push_back(Elt: "-bpD:0x110000000" ); |
205 | } |
206 | |
207 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, |
208 | options::OPT_shared, options::OPT_r)) { |
209 | auto getCrt0Basename = [&Args, IsArch32Bit] { |
210 | if (Arg *A = Args.getLastArgNoClaim(options::OPT_p, options::OPT_pg)) { |
211 | // Enable gprofiling when "-pg" is specified. |
212 | if (A->getOption().matches(options::ID: OPT_pg)) |
213 | return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o" ; |
214 | // Enable profiling when "-p" is specified. |
215 | return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o" ; |
216 | } |
217 | return IsArch32Bit ? "crt0.o" : "crt0_64.o" ; |
218 | }; |
219 | |
220 | CmdArgs.push_back( |
221 | Elt: Args.MakeArgString(Str: ToolChain.GetFilePath(Name: getCrt0Basename()))); |
222 | |
223 | CmdArgs.push_back(Elt: Args.MakeArgString( |
224 | Str: ToolChain.GetFilePath(Name: IsArch32Bit ? "crti.o" : "crti_64.o" ))); |
225 | } |
226 | |
227 | // Collect all static constructor and destructor functions in both C and CXX |
228 | // language link invocations. This has to come before AddLinkerInputs as the |
229 | // implied option needs to precede any other '-bcdtors' settings or |
230 | // '-bnocdtors' that '-Wl' might forward. |
231 | CmdArgs.push_back(Elt: "-bcdtors:all:0:s" ); |
232 | |
233 | // Specify linker input file(s). |
234 | AddLinkerInputs(TC: ToolChain, Inputs, Args, CmdArgs, JA); |
235 | |
236 | if (D.isUsingLTO()) { |
237 | assert(!Inputs.empty() && "Must have at least one input." ); |
238 | // Find the first filename InputInfo object. |
239 | auto Input = llvm::find_if( |
240 | Range: Inputs, P: [](const InputInfo &II) -> bool { return II.isFilename(); }); |
241 | if (Input == Inputs.end()) |
242 | // For a very rare case, all of the inputs to the linker are |
243 | // InputArg. If that happens, just use the first InputInfo. |
244 | Input = Inputs.begin(); |
245 | |
246 | addLTOOptions(ToolChain, Args, CmdArgs, Output, Input: *Input, |
247 | IsThinLTO: D.getLTOMode() == LTOK_Thin); |
248 | } |
249 | |
250 | if (Args.hasArg(options::OPT_shared) && !hasExportListLinkerOpts(CmdArgs)) { |
251 | |
252 | const char *CreateExportListExec = Args.MakeArgString( |
253 | Str: path::parent_path(path: ToolChain.getDriver().ClangExecutable) + |
254 | "/llvm-nm" ); |
255 | ArgStringList CreateExportCmdArgs; |
256 | |
257 | std::string CreateExportListPath = |
258 | C.getDriver().GetTemporaryPath(Prefix: "CreateExportList" , Suffix: "exp" ); |
259 | const char *ExportList = |
260 | C.addTempFile(Name: C.getArgs().MakeArgString(Str: CreateExportListPath)); |
261 | |
262 | for (const auto &II : Inputs) |
263 | if (II.isFilename()) |
264 | CreateExportCmdArgs.push_back(Elt: II.getFilename()); |
265 | |
266 | CreateExportCmdArgs.push_back(Elt: "--export-symbols" ); |
267 | CreateExportCmdArgs.push_back(Elt: "-X" ); |
268 | if (IsArch32Bit) { |
269 | CreateExportCmdArgs.push_back(Elt: "32" ); |
270 | } else { |
271 | // Must be 64-bit, otherwise asserted already. |
272 | CreateExportCmdArgs.push_back(Elt: "64" ); |
273 | } |
274 | |
275 | auto ExpCommand = std::make_unique<Command>( |
276 | args: JA, args: *this, args: ResponseFileSupport::None(), args&: CreateExportListExec, |
277 | args&: CreateExportCmdArgs, args: Inputs, args: Output); |
278 | ExpCommand->setRedirectFiles( |
279 | {std::nullopt, std::string(ExportList), std::nullopt}); |
280 | C.addCommand(C: std::move(ExpCommand)); |
281 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: llvm::Twine("-bE:" ) + ExportList)); |
282 | } |
283 | |
284 | // Add directory to library search path. |
285 | Args.AddAllArgs(Output&: CmdArgs, options::Id0: OPT_L); |
286 | if (!Args.hasArg(options::OPT_r)) { |
287 | ToolChain.AddFilePathLibArgs(Args, CmdArgs); |
288 | ToolChain.addProfileRTLibs(Args, CmdArgs); |
289 | |
290 | if (getToolChain().ShouldLinkCXXStdlib(Args)) |
291 | getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); |
292 | |
293 | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { |
294 | AddRunTimeLibs(TC: ToolChain, D, CmdArgs, Args); |
295 | |
296 | // Add OpenMP runtime if -fopenmp is specified. |
297 | if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, |
298 | options::OPT_fno_openmp, false)) { |
299 | switch (ToolChain.getDriver().getOpenMPRuntime(Args)) { |
300 | case Driver::OMPRT_OMP: |
301 | CmdArgs.push_back(Elt: "-lomp" ); |
302 | break; |
303 | case Driver::OMPRT_IOMP5: |
304 | CmdArgs.push_back(Elt: "-liomp5" ); |
305 | break; |
306 | case Driver::OMPRT_GOMP: |
307 | CmdArgs.push_back(Elt: "-lgomp" ); |
308 | break; |
309 | case Driver::OMPRT_Unknown: |
310 | // Already diagnosed. |
311 | break; |
312 | } |
313 | } |
314 | |
315 | // Support POSIX threads if "-pthreads" or "-pthread" is present. |
316 | if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread)) |
317 | CmdArgs.push_back(Elt: "-lpthreads" ); |
318 | |
319 | if (D.CCCIsCXX()) |
320 | CmdArgs.push_back(Elt: "-lm" ); |
321 | |
322 | CmdArgs.push_back(Elt: "-lc" ); |
323 | |
324 | if (Args.hasArgNoClaim(options::OPT_p, options::OPT_pg)) { |
325 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: (llvm::Twine("-L" ) + D.SysRoot) + |
326 | "/lib/profiled" )); |
327 | CmdArgs.push_back(Elt: Args.MakeArgString(Str: (llvm::Twine("-L" ) + D.SysRoot) + |
328 | "/usr/lib/profiled" )); |
329 | } |
330 | } |
331 | } |
332 | |
333 | if (D.IsFlangMode()) { |
334 | addFortranRuntimeLibraryPath(TC: ToolChain, Args, CmdArgs); |
335 | addFortranRuntimeLibs(TC: ToolChain, Args, CmdArgs); |
336 | CmdArgs.push_back(Elt: "-lm" ); |
337 | CmdArgs.push_back(Elt: "-lpthread" ); |
338 | } |
339 | const char *Exec = Args.MakeArgString(Str: ToolChain.GetLinkerPath()); |
340 | C.addCommand(C: std::make_unique<Command>(args: JA, args: *this, args: ResponseFileSupport::None(), |
341 | args&: Exec, args&: CmdArgs, args: Inputs, args: Output)); |
342 | } |
343 | |
344 | /// AIX - AIX tool chain which can call as(1) and ld(1) directly. |
345 | AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) |
346 | : ToolChain(D, Triple, Args) { |
347 | getProgramPaths().push_back(Elt: getDriver().Dir); |
348 | |
349 | ParseInlineAsmUsingAsmParser = Args.hasFlag( |
350 | options::OPT_fintegrated_as, options::OPT_fno_integrated_as, true); |
351 | getLibraryPaths().push_back(Elt: getDriver().SysRoot + "/usr/lib" ); |
352 | } |
353 | |
354 | // Returns the effective header sysroot path to use. |
355 | // This comes from either -isysroot or --sysroot. |
356 | llvm::StringRef |
357 | AIX::(const llvm::opt::ArgList &DriverArgs) const { |
358 | if (DriverArgs.hasArg(options::OPT_isysroot)) |
359 | return DriverArgs.getLastArgValue(options::OPT_isysroot); |
360 | if (!getDriver().SysRoot.empty()) |
361 | return getDriver().SysRoot; |
362 | return "/" ; |
363 | } |
364 | |
365 | void AIX::AddOpenMPIncludeArgs(const ArgList &DriverArgs, |
366 | ArgStringList &CC1Args) const { |
367 | // Add OpenMP include paths if -fopenmp is specified. |
368 | if (DriverArgs.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, |
369 | options::OPT_fno_openmp, false)) { |
370 | SmallString<128> PathOpenMP; |
371 | switch (getDriver().getOpenMPRuntime(Args: DriverArgs)) { |
372 | case Driver::OMPRT_OMP: |
373 | PathOpenMP = GetHeaderSysroot(DriverArgs); |
374 | llvm::sys::path::append(path&: PathOpenMP, a: "opt/IBM/openxlCSDK" , b: "include" , |
375 | c: "openmp" ); |
376 | addSystemInclude(DriverArgs, CC1Args, Path: PathOpenMP.str()); |
377 | break; |
378 | case Driver::OMPRT_IOMP5: |
379 | LLVM_FALLTHROUGH; |
380 | case Driver::OMPRT_GOMP: |
381 | LLVM_FALLTHROUGH; |
382 | case Driver::OMPRT_Unknown: |
383 | // Unknown / unsupported include paths. |
384 | break; |
385 | } |
386 | } |
387 | } |
388 | |
389 | void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs, |
390 | ArgStringList &CC1Args) const { |
391 | // Return if -nostdinc is specified as a driver option. |
392 | if (DriverArgs.hasArg(options::OPT_nostdinc)) |
393 | return; |
394 | |
395 | llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); |
396 | const Driver &D = getDriver(); |
397 | |
398 | if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { |
399 | SmallString<128> P(D.ResourceDir); |
400 | // Add the PowerPC intrinsic headers (<resource>/include/ppc_wrappers) |
401 | path::append(path&: P, a: "include" , b: "ppc_wrappers" ); |
402 | addSystemInclude(DriverArgs, CC1Args, Path: P); |
403 | // Add the Clang builtin headers (<resource>/include) |
404 | addSystemInclude(DriverArgs, CC1Args, Path: path::parent_path(path: P.str())); |
405 | } |
406 | |
407 | // Add the include directory containing omp.h. This needs to be before |
408 | // adding the system include directory because other compilers put their |
409 | // omp.h in /usr/include. |
410 | AddOpenMPIncludeArgs(DriverArgs, CC1Args); |
411 | |
412 | // Return if -nostdlibinc is specified as a driver option. |
413 | if (DriverArgs.hasArg(options::OPT_nostdlibinc)) |
414 | return; |
415 | |
416 | // Add <sysroot>/usr/include. |
417 | SmallString<128> UP(Sysroot); |
418 | path::append(path&: UP, a: "/usr/include" ); |
419 | addSystemInclude(DriverArgs, CC1Args, Path: UP.str()); |
420 | } |
421 | |
422 | void AIX::AddClangCXXStdlibIncludeArgs( |
423 | const llvm::opt::ArgList &DriverArgs, |
424 | llvm::opt::ArgStringList &CC1Args) const { |
425 | |
426 | if (DriverArgs.hasArg(options::OPT_nostdinc) || |
427 | DriverArgs.hasArg(options::OPT_nostdincxx) || |
428 | DriverArgs.hasArg(options::OPT_nostdlibinc)) |
429 | return; |
430 | |
431 | switch (GetCXXStdlibType(Args: DriverArgs)) { |
432 | case ToolChain::CST_Libstdcxx: |
433 | llvm::report_fatal_error( |
434 | reason: "picking up libstdc++ headers is unimplemented on AIX" ); |
435 | case ToolChain::CST_Libcxx: { |
436 | llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); |
437 | SmallString<128> PathCPP(Sysroot); |
438 | llvm::sys::path::append(path&: PathCPP, a: "opt/IBM/openxlCSDK" , b: "include" , c: "c++" , |
439 | d: "v1" ); |
440 | addSystemInclude(DriverArgs, CC1Args, Path: PathCPP.str()); |
441 | // Required in order to suppress conflicting C++ overloads in the system |
442 | // libc headers that were used by XL C++. |
443 | CC1Args.push_back(Elt: "-D__LIBC_NO_CPP_MATH_OVERLOADS__" ); |
444 | return; |
445 | } |
446 | } |
447 | |
448 | llvm_unreachable("Unexpected C++ library type; only libc++ is supported." ); |
449 | } |
450 | |
451 | void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, |
452 | llvm::opt::ArgStringList &CmdArgs) const { |
453 | switch (GetCXXStdlibType(Args)) { |
454 | case ToolChain::CST_Libstdcxx: |
455 | llvm::report_fatal_error(reason: "linking libstdc++ unimplemented on AIX" ); |
456 | case ToolChain::CST_Libcxx: |
457 | CmdArgs.push_back(Elt: "-lc++" ); |
458 | if (Args.hasArg(options::OPT_fexperimental_library)) |
459 | CmdArgs.push_back(Elt: "-lc++experimental" ); |
460 | CmdArgs.push_back(Elt: "-lc++abi" ); |
461 | return; |
462 | } |
463 | |
464 | llvm_unreachable("Unexpected C++ library type; only libc++ is supported." ); |
465 | } |
466 | |
467 | // This function processes all the mtocdata options to build the final |
468 | // simplified toc data options to pass to CC1. |
469 | static void addTocDataOptions(const llvm::opt::ArgList &Args, |
470 | llvm::opt::ArgStringList &CC1Args, |
471 | const Driver &D) { |
472 | |
473 | // Check the global toc-data setting. The default is -mno-tocdata. |
474 | // To enable toc-data globally, -mtocdata must be specified. |
475 | // Additionally, it must be last to take effect. |
476 | const bool TOCDataGloballyinEffect = [&Args]() { |
477 | if (const Arg *LastArg = |
478 | Args.getLastArg(options::OPT_mtocdata, options::OPT_mno_tocdata)) |
479 | return LastArg->getOption().matches(options::OPT_mtocdata); |
480 | else |
481 | return false; |
482 | }(); |
483 | |
484 | // Currently only supported for small code model. |
485 | if (TOCDataGloballyinEffect && |
486 | (Args.getLastArgValue(options::OPT_mcmodel_EQ).equals("large" ) || |
487 | Args.getLastArgValue(options::OPT_mcmodel_EQ).equals("medium" ))) { |
488 | D.Diag(clang::diag::warn_drv_unsupported_tocdata); |
489 | return; |
490 | } |
491 | |
492 | enum TOCDataSetting { |
493 | AddressInTOC = 0, // Address of the symbol stored in the TOC. |
494 | DataInTOC = 1 // Symbol defined in the TOC. |
495 | }; |
496 | |
497 | const TOCDataSetting DefaultTocDataSetting = |
498 | TOCDataGloballyinEffect ? DataInTOC : AddressInTOC; |
499 | |
500 | // Process the list of variables in the explicitly specified options |
501 | // -mtocdata= and -mno-tocdata= to see which variables are opposite to |
502 | // the global setting of tocdata in TOCDataGloballyinEffect. |
503 | // Those that have the opposite setting to TOCDataGloballyinEffect, are added |
504 | // to ExplicitlySpecifiedGlobals. |
505 | std::set<llvm::StringRef> ExplicitlySpecifiedGlobals; |
506 | for (const auto Arg : |
507 | Args.filtered(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ)) { |
508 | TOCDataSetting ArgTocDataSetting = |
509 | Arg->getOption().matches(options::OPT_mtocdata_EQ) ? DataInTOC |
510 | : AddressInTOC; |
511 | |
512 | if (ArgTocDataSetting != DefaultTocDataSetting) |
513 | for (const char *Val : Arg->getValues()) |
514 | ExplicitlySpecifiedGlobals.insert(Val); |
515 | else |
516 | for (const char *Val : Arg->getValues()) |
517 | ExplicitlySpecifiedGlobals.erase(Val); |
518 | } |
519 | |
520 | auto buildExceptionList = [](const std::set<llvm::StringRef> &ExplicitValues, |
521 | const char *OptionSpelling) { |
522 | std::string Option(OptionSpelling); |
523 | bool IsFirst = true; |
524 | for (const auto &E : ExplicitValues) { |
525 | if (!IsFirst) |
526 | Option += "," ; |
527 | |
528 | IsFirst = false; |
529 | Option += E.str(); |
530 | } |
531 | return Option; |
532 | }; |
533 | |
534 | // Pass the final tocdata options to CC1 consisting of the default |
535 | // tocdata option (-mtocdata/-mno-tocdata) along with the list |
536 | // option (-mno-tocdata=/-mtocdata=) if there are any explicitly specified |
537 | // variables which would be exceptions to the default setting. |
538 | const char *TocDataGlobalOption = |
539 | TOCDataGloballyinEffect ? "-mtocdata" : "-mno-tocdata" ; |
540 | CC1Args.push_back(Elt: TocDataGlobalOption); |
541 | |
542 | const char *TocDataListOption = |
543 | TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=" ; |
544 | if (!ExplicitlySpecifiedGlobals.empty()) |
545 | CC1Args.push_back(Elt: Args.MakeArgString(Str: llvm::Twine( |
546 | buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption)))); |
547 | } |
548 | |
549 | void AIX::addClangTargetOptions( |
550 | const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args, |
551 | Action::OffloadKind DeviceOffloadingKind) const { |
552 | Args.AddLastArg(CC1Args, options::OPT_mignore_xcoff_visibility); |
553 | Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ); |
554 | Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr); |
555 | |
556 | // Forward last mtocdata/mno_tocdata options to -cc1. |
557 | if (Args.hasArg(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ, |
558 | options::OPT_mtocdata)) |
559 | addTocDataOptions(Args, CC1Args, D: getDriver()); |
560 | |
561 | if (Args.hasFlag(options::OPT_fxl_pragma_pack, |
562 | options::OPT_fno_xl_pragma_pack, true)) |
563 | CC1Args.push_back(Elt: "-fxl-pragma-pack" ); |
564 | } |
565 | |
566 | void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args, |
567 | llvm::opt::ArgStringList &CmdArgs) const { |
568 | if (needsProfileRT(Args)) { |
569 | // Add linker option -u__llvm_profile_runtime to cause runtime |
570 | // initialization to occur. |
571 | CmdArgs.push_back(Elt: Args.MakeArgString( |
572 | Str: Twine("-u" , llvm::getInstrProfRuntimeHookVarName()))); |
573 | |
574 | if (const auto *A = |
575 | Args.getLastArgNoClaim(options::OPT_fprofile_update_EQ)) { |
576 | StringRef Val = A->getValue(); |
577 | if (Val == "atomic" || Val == "prefer-atomic" ) |
578 | CmdArgs.push_back(Elt: "-latomic" ); |
579 | } |
580 | } |
581 | |
582 | ToolChain::addProfileRTLibs(Args, CmdArgs); |
583 | } |
584 | |
585 | ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const { |
586 | return ToolChain::CST_Libcxx; |
587 | } |
588 | |
589 | ToolChain::RuntimeLibType AIX::GetDefaultRuntimeLibType() const { |
590 | return ToolChain::RLT_CompilerRT; |
591 | } |
592 | |
593 | auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); } |
594 | |
595 | auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); } |
596 | |