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