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(Ids: options::OPT_G)) { |
45 | D.Diag(DiagID: diag::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, Id0: options::OPT_Wa_COMMA, Id1: options::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(Ids: options::OPT_G)) { |
125 | D.Diag(DiagID: diag::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(Ids: options::OPT_static)) |
131 | CmdArgs.push_back(Elt: "-bnso" ); |
132 | |
133 | // Add options for shared libraries. |
134 | if (Args.hasArg(Ids: options::OPT_shared)) { |
135 | CmdArgs.push_back(Elt: "-bM:SRE" ); |
136 | CmdArgs.push_back(Elt: "-bnoentry" ); |
137 | } |
138 | |
139 | if (Args.hasFlag(Pos: options::OPT_mxcoff_roptr, Neg: options::OPT_mno_xcoff_roptr, |
140 | Default: false)) { |
141 | if (Args.hasArg(Ids: options::OPT_shared)) |
142 | D.Diag(DiagID: diag::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(Pos: options::OPT_fprofile_arcs, Neg: options::OPT_fno_profile_arcs, |
154 | Default: false) || |
155 | Args.hasFlag(Pos: options::OPT_fprofile_generate, |
156 | Neg: options::OPT_fno_profile_generate, Default: false) || |
157 | Args.hasFlag(Pos: options::OPT_fprofile_generate_EQ, |
158 | Neg: options::OPT_fno_profile_generate, Default: false) || |
159 | Args.hasFlag(Pos: options::OPT_fprofile_instr_generate, |
160 | Neg: options::OPT_fno_profile_instr_generate, Default: false) || |
161 | Args.hasFlag(Pos: options::OPT_fprofile_instr_generate_EQ, |
162 | Neg: options::OPT_fno_profile_instr_generate, Default: false) || |
163 | Args.hasFlag(Pos: options::OPT_fcs_profile_generate, |
164 | Neg: options::OPT_fno_profile_generate, Default: false) || |
165 | Args.hasFlag(Pos: options::OPT_fcs_profile_generate_EQ, |
166 | Neg: options::OPT_fno_profile_generate, Default: false) || |
167 | Args.hasArg(Ids: options::OPT_fcreate_profile) || |
168 | Args.hasArg(Ids: options::OPT_coverage)) |
169 | CmdArgs.push_back(Elt: "-bdbg:namedsects:ss" ); |
170 | |
171 | if (Arg *A = |
172 | Args.getLastArg(Ids: 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(DiagID: diag::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(Ids: options::OPT_nostdlib, Ids: options::OPT_nostartfiles, |
208 | Ids: options::OPT_shared, Ids: options::OPT_r)) { |
209 | auto getCrt0Basename = [&Args, IsArch32Bit] { |
210 | if (Arg *A = Args.getLastArgNoClaim(Ids: options::OPT_p, Ids: options::OPT_pg)) { |
211 | // Enable gprofiling when "-pg" is specified. |
212 | if (A->getOption().matches(ID: options::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(Ids: 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, Id0: options::OPT_L); |
286 | if (!Args.hasArg(Ids: 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(Ids: options::OPT_nostdlib, Ids: options::OPT_nodefaultlibs)) { |
294 | AddRunTimeLibs(TC: ToolChain, D, CmdArgs, Args); |
295 | |
296 | // Add OpenMP runtime if -fopenmp is specified. |
297 | if (Args.hasFlag(Pos: options::OPT_fopenmp, PosAlias: options::OPT_fopenmp_EQ, |
298 | Neg: options::OPT_fno_openmp, Default: 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(Ids: options::OPT_pthreads, Ids: 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(Ids: options::OPT_p, Ids: 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 | Pos: options::OPT_fintegrated_as, Neg: options::OPT_fno_integrated_as, Default: 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(Ids: options::OPT_isysroot)) |
359 | return DriverArgs.getLastArgValue(Id: 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(Pos: options::OPT_fopenmp, PosAlias: options::OPT_fopenmp_EQ, |
369 | Neg: options::OPT_fno_openmp, Default: 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 | case Driver::OMPRT_GOMP: |
380 | case Driver::OMPRT_Unknown: |
381 | // Unknown / unsupported include paths. |
382 | break; |
383 | } |
384 | } |
385 | } |
386 | |
387 | void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs, |
388 | ArgStringList &CC1Args) const { |
389 | // Return if -nostdinc is specified as a driver option. |
390 | if (DriverArgs.hasArg(Ids: options::OPT_nostdinc)) |
391 | return; |
392 | |
393 | llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); |
394 | const Driver &D = getDriver(); |
395 | |
396 | if (!DriverArgs.hasArg(Ids: options::OPT_nobuiltininc)) { |
397 | SmallString<128> P(D.ResourceDir); |
398 | // Add the PowerPC intrinsic headers (<resource>/include/ppc_wrappers) |
399 | path::append(path&: P, a: "include" , b: "ppc_wrappers" ); |
400 | addSystemInclude(DriverArgs, CC1Args, Path: P); |
401 | // Add the Clang builtin headers (<resource>/include) |
402 | addSystemInclude(DriverArgs, CC1Args, Path: path::parent_path(path: P.str())); |
403 | } |
404 | |
405 | // Add the include directory containing omp.h. This needs to be before |
406 | // adding the system include directory because other compilers put their |
407 | // omp.h in /usr/include. |
408 | AddOpenMPIncludeArgs(DriverArgs, CC1Args); |
409 | |
410 | // Return if -nostdlibinc is specified as a driver option. |
411 | if (DriverArgs.hasArg(Ids: options::OPT_nostdlibinc)) |
412 | return; |
413 | |
414 | // Add <sysroot>/usr/include. |
415 | SmallString<128> UP(Sysroot); |
416 | path::append(path&: UP, a: "/usr/include" ); |
417 | addSystemInclude(DriverArgs, CC1Args, Path: UP.str()); |
418 | } |
419 | |
420 | void AIX::AddClangCXXStdlibIncludeArgs( |
421 | const llvm::opt::ArgList &DriverArgs, |
422 | llvm::opt::ArgStringList &CC1Args) const { |
423 | |
424 | if (DriverArgs.hasArg(Ids: options::OPT_nostdinc) || |
425 | DriverArgs.hasArg(Ids: options::OPT_nostdincxx) || |
426 | DriverArgs.hasArg(Ids: options::OPT_nostdlibinc)) |
427 | return; |
428 | |
429 | switch (GetCXXStdlibType(Args: DriverArgs)) { |
430 | case ToolChain::CST_Libstdcxx: |
431 | llvm::report_fatal_error( |
432 | reason: "picking up libstdc++ headers is unimplemented on AIX" ); |
433 | case ToolChain::CST_Libcxx: { |
434 | llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); |
435 | SmallString<128> PathCPP(Sysroot); |
436 | llvm::sys::path::append(path&: PathCPP, a: "opt/IBM/openxlCSDK" , b: "include" , c: "c++" , |
437 | d: "v1" ); |
438 | addSystemInclude(DriverArgs, CC1Args, Path: PathCPP.str()); |
439 | // Required in order to suppress conflicting C++ overloads in the system |
440 | // libc headers that were used by XL C++. |
441 | CC1Args.push_back(Elt: "-D__LIBC_NO_CPP_MATH_OVERLOADS__" ); |
442 | return; |
443 | } |
444 | } |
445 | |
446 | llvm_unreachable("Unexpected C++ library type; only libc++ is supported." ); |
447 | } |
448 | |
449 | void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, |
450 | llvm::opt::ArgStringList &CmdArgs) const { |
451 | switch (GetCXXStdlibType(Args)) { |
452 | case ToolChain::CST_Libstdcxx: |
453 | llvm::report_fatal_error(reason: "linking libstdc++ unimplemented on AIX" ); |
454 | case ToolChain::CST_Libcxx: |
455 | CmdArgs.push_back(Elt: "-lc++" ); |
456 | if (Args.hasArg(Ids: options::OPT_fexperimental_library)) |
457 | CmdArgs.push_back(Elt: "-lc++experimental" ); |
458 | CmdArgs.push_back(Elt: "-lc++abi" ); |
459 | return; |
460 | } |
461 | |
462 | llvm_unreachable("Unexpected C++ library type; only libc++ is supported." ); |
463 | } |
464 | |
465 | // This function processes all the mtocdata options to build the final |
466 | // simplified toc data options to pass to CC1. |
467 | static void addTocDataOptions(const llvm::opt::ArgList &Args, |
468 | llvm::opt::ArgStringList &CC1Args, |
469 | const Driver &D) { |
470 | |
471 | // Check the global toc-data setting. The default is -mno-tocdata. |
472 | // To enable toc-data globally, -mtocdata must be specified. |
473 | // Additionally, it must be last to take effect. |
474 | const bool TOCDataGloballyinEffect = [&Args]() { |
475 | if (const Arg *LastArg = |
476 | Args.getLastArg(Ids: options::OPT_mtocdata, Ids: options::OPT_mno_tocdata)) |
477 | return LastArg->getOption().matches(ID: options::OPT_mtocdata); |
478 | else |
479 | return false; |
480 | }(); |
481 | |
482 | enum TOCDataSetting { |
483 | AddressInTOC = 0, // Address of the symbol stored in the TOC. |
484 | DataInTOC = 1 // Symbol defined in the TOC. |
485 | }; |
486 | |
487 | const TOCDataSetting DefaultTocDataSetting = |
488 | TOCDataGloballyinEffect ? DataInTOC : AddressInTOC; |
489 | |
490 | // Process the list of variables in the explicitly specified options |
491 | // -mtocdata= and -mno-tocdata= to see which variables are opposite to |
492 | // the global setting of tocdata in TOCDataGloballyinEffect. |
493 | // Those that have the opposite setting to TOCDataGloballyinEffect, are added |
494 | // to ExplicitlySpecifiedGlobals. |
495 | std::set<llvm::StringRef> ExplicitlySpecifiedGlobals; |
496 | for (const auto Arg : |
497 | Args.filtered(Ids: options::OPT_mtocdata_EQ, Ids: options::OPT_mno_tocdata_EQ)) { |
498 | TOCDataSetting ArgTocDataSetting = |
499 | Arg->getOption().matches(ID: options::OPT_mtocdata_EQ) ? DataInTOC |
500 | : AddressInTOC; |
501 | |
502 | if (ArgTocDataSetting != DefaultTocDataSetting) |
503 | for (const char *Val : Arg->getValues()) |
504 | ExplicitlySpecifiedGlobals.insert(x: Val); |
505 | else |
506 | for (const char *Val : Arg->getValues()) |
507 | ExplicitlySpecifiedGlobals.erase(x: Val); |
508 | } |
509 | |
510 | auto buildExceptionList = [](const std::set<llvm::StringRef> &ExplicitValues, |
511 | const char *OptionSpelling) { |
512 | std::string Option(OptionSpelling); |
513 | bool IsFirst = true; |
514 | for (const auto &E : ExplicitValues) { |
515 | if (!IsFirst) |
516 | Option += "," ; |
517 | |
518 | IsFirst = false; |
519 | Option += E.str(); |
520 | } |
521 | return Option; |
522 | }; |
523 | |
524 | // Pass the final tocdata options to CC1 consisting of the default |
525 | // tocdata option (-mtocdata/-mno-tocdata) along with the list |
526 | // option (-mno-tocdata=/-mtocdata=) if there are any explicitly specified |
527 | // variables which would be exceptions to the default setting. |
528 | const char *TocDataGlobalOption = |
529 | TOCDataGloballyinEffect ? "-mtocdata" : "-mno-tocdata" ; |
530 | CC1Args.push_back(Elt: TocDataGlobalOption); |
531 | |
532 | const char *TocDataListOption = |
533 | TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=" ; |
534 | if (!ExplicitlySpecifiedGlobals.empty()) |
535 | CC1Args.push_back(Elt: Args.MakeArgString(Str: llvm::Twine( |
536 | buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption)))); |
537 | } |
538 | |
539 | void AIX::addClangTargetOptions( |
540 | const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args, |
541 | Action::OffloadKind DeviceOffloadingKind) const { |
542 | Args.AddLastArg(Output&: CC1Args, Ids: options::OPT_mignore_xcoff_visibility); |
543 | Args.AddLastArg(Output&: CC1Args, Ids: options::OPT_mdefault_visibility_export_mapping_EQ); |
544 | Args.addOptInFlag(Output&: CC1Args, Pos: options::OPT_mxcoff_roptr, Neg: options::OPT_mno_xcoff_roptr); |
545 | |
546 | // Forward last mtocdata/mno_tocdata options to -cc1. |
547 | if (Args.hasArg(Ids: options::OPT_mtocdata_EQ, Ids: options::OPT_mno_tocdata_EQ, |
548 | Ids: options::OPT_mtocdata)) |
549 | addTocDataOptions(Args, CC1Args, D: getDriver()); |
550 | |
551 | if (Args.hasFlag(Pos: options::OPT_fxl_pragma_pack, |
552 | Neg: options::OPT_fno_xl_pragma_pack, Default: true)) |
553 | CC1Args.push_back(Elt: "-fxl-pragma-pack" ); |
554 | |
555 | // Pass "-fno-sized-deallocation" only when the user hasn't manually enabled |
556 | // or disabled sized deallocations. |
557 | if (!Args.getLastArgNoClaim(Ids: options::OPT_fsized_deallocation, |
558 | Ids: options::OPT_fno_sized_deallocation)) |
559 | CC1Args.push_back(Elt: "-fno-sized-deallocation" ); |
560 | } |
561 | |
562 | void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args, |
563 | llvm::opt::ArgStringList &CmdArgs) const { |
564 | if (needsProfileRT(Args)) { |
565 | // Add linker option -u__llvm_profile_runtime to cause runtime |
566 | // initialization to occur. |
567 | CmdArgs.push_back(Elt: Args.MakeArgString( |
568 | Str: Twine("-u" , llvm::getInstrProfRuntimeHookVarName()))); |
569 | |
570 | if (const auto *A = |
571 | Args.getLastArgNoClaim(Ids: options::OPT_fprofile_update_EQ)) { |
572 | StringRef Val = A->getValue(); |
573 | if (Val == "atomic" || Val == "prefer-atomic" ) |
574 | CmdArgs.push_back(Elt: "-latomic" ); |
575 | } |
576 | } |
577 | |
578 | ToolChain::addProfileRTLibs(Args, CmdArgs); |
579 | } |
580 | |
581 | ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const { |
582 | return ToolChain::CST_Libcxx; |
583 | } |
584 | |
585 | ToolChain::RuntimeLibType AIX::GetDefaultRuntimeLibType() const { |
586 | return ToolChain::RLT_CompilerRT; |
587 | } |
588 | |
589 | auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); } |
590 | |
591 | auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); } |
592 | |