xref: /freebsd/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const29 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::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("-a32");
51   } else {
52     // Must be 64-bit, otherwise asserted already.
53     CmdArgs.push_back("-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("-many");
61 
62   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
63 
64   // Specify assembler output file.
65   assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
66   if (Output.isFilename()) {
67     CmdArgs.push_back("-o");
68     CmdArgs.push_back(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(II.getFilename());
80 
81   const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
82   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
83                                          Exec, CmdArgs, Inputs, 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.
hasExportListLinkerOpts(const ArgStringList & CmdArgs)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("-bE:") || ArgString.starts_with("-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("E:") ||
101           ArgNextString.starts_with("export:") || ArgNextString == "expall" ||
102           ArgNextString == "expfull")
103         return true;
104     }
105   }
106   return false;
107 }
108 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const109 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::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("-bnso");
131 
132   // Add options for shared libraries.
133   if (Args.hasArg(options::OPT_shared)) {
134     CmdArgs.push_back("-bM:SRE");
135     CmdArgs.push_back("-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::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("-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("-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(llvm::isHexDigit, 2) != StringRef::npos)
175       ToolChain.getDriver().Diag(diag::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(2).lower();
182       CmdArgs.push_back(Args.MakeArgString(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("-o");
190     CmdArgs.push_back(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("-b32");
197     CmdArgs.push_back("-bpT:0x10000000");
198     CmdArgs.push_back("-bpD:0x20000000");
199   } else {
200     // Must be 64-bit, otherwise asserted already.
201     CmdArgs.push_back("-b64");
202     CmdArgs.push_back("-bpT:0x100000000");
203     CmdArgs.push_back("-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::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         Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename())));
221 
222     CmdArgs.push_back(Args.MakeArgString(
223         ToolChain.GetFilePath(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("-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(Args.MakeArgString(Twine("-blibpath:") + BlibPathStr));
256   }
257 
258   // Specify linker input file(s).
259   AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
260 
261   if (D.isUsingLTO())
262     addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs,
263                   D.getLTOMode() == LTOK_Thin);
264 
265   if (Args.hasArg(options::OPT_shared) && !hasExportListLinkerOpts(CmdArgs)) {
266 
267     const char *CreateExportListExec = Args.MakeArgString(
268         path::parent_path(ToolChain.getDriver().ClangExecutable) +
269         "/llvm-nm");
270     ArgStringList CreateExportCmdArgs;
271 
272     std::string CreateExportListPath =
273         C.getDriver().GetTemporaryPath("CreateExportList", "exp");
274     const char *ExportList =
275         C.addTempFile(C.getArgs().MakeArgString(CreateExportListPath));
276 
277     for (const auto &II : Inputs)
278       if (II.isFilename())
279         CreateExportCmdArgs.push_back(II.getFilename());
280 
281     CreateExportCmdArgs.push_back("--export-symbols");
282     CreateExportCmdArgs.push_back("-X");
283     if (IsArch32Bit) {
284       CreateExportCmdArgs.push_back("32");
285     } else {
286       // Must be 64-bit, otherwise asserted already.
287       CreateExportCmdArgs.push_back("64");
288     }
289 
290     auto ExpCommand = std::make_unique<Command>(
291         JA, *this, ResponseFileSupport::None(), CreateExportListExec,
292         CreateExportCmdArgs, Inputs, Output);
293     ExpCommand->setRedirectFiles(
294         {std::nullopt, std::string(ExportList), std::nullopt});
295     C.addCommand(std::move(ExpCommand));
296     CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-bE:") + ExportList));
297   }
298 
299   // Add directory to library search path.
300   Args.AddAllArgs(CmdArgs, options::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(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("-lomp");
317           break;
318         case Driver::OMPRT_IOMP5:
319           CmdArgs.push_back("-liomp5");
320           break;
321         case Driver::OMPRT_GOMP:
322           CmdArgs.push_back("-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("-lpthreads");
333 
334       if (D.CCCIsCXX())
335         CmdArgs.push_back("-lm");
336 
337       CmdArgs.push_back("-lc");
338 
339       if (Args.hasArgNoClaim(options::OPT_p, options::OPT_pg)) {
340         CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
341                                              "/lib/profiled"));
342         CmdArgs.push_back(Args.MakeArgString((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("-lm");
353     CmdArgs.push_back("-lpthread");
354   }
355   const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
356   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
357                                          Exec, CmdArgs, Inputs, Output));
358 }
359 
360 /// AIX - AIX tool chain which can call as(1) and ld(1) directly.
AIX(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)361 AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
362     : ToolChain(D, Triple, Args) {
363   getProgramPaths().push_back(getDriver().Dir);
364 
365   ParseInlineAsmUsingAsmParser = Args.hasFlag(
366       options::OPT_fintegrated_as, options::OPT_fno_integrated_as, true);
367   getLibraryPaths().push_back(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
GetHeaderSysroot(const llvm::opt::ArgList & DriverArgs) const373 AIX::GetHeaderSysroot(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 
AddOpenMPIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const381 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(DriverArgs)) {
388     case Driver::OMPRT_OMP:
389       PathOpenMP = GetHeaderSysroot(DriverArgs);
390       llvm::sys::path::append(PathOpenMP, "opt/IBM/openxlCSDK", "include",
391                               "openmp");
392       addSystemInclude(DriverArgs, CC1Args, 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 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const403 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(P, "include", "ppc_wrappers");
416     addSystemInclude(DriverArgs, CC1Args, P);
417     // Add the Clang builtin headers (<resource>/include)
418     addSystemInclude(DriverArgs, CC1Args, path::parent_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(UP, "/usr/include");
433   addSystemInclude(DriverArgs, CC1Args, UP.str());
434 }
435 
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const436 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(DriverArgs)) {
446   case ToolChain::CST_Libstdcxx:
447     llvm::report_fatal_error(
448         "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(PathCPP, "opt/IBM/openxlCSDK", "include", "c++",
453                             "v1");
454     addSystemInclude(DriverArgs, CC1Args, 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("-D__LIBC_NO_CPP_MATH_OVERLOADS__");
458     return;
459   }
460   }
461 
462   llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
463 }
464 
AddCXXStdlibLibArgs(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CmdArgs) const465 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("linking libstdc++ unimplemented on AIX");
470   case ToolChain::CST_Libcxx:
471     CmdArgs.push_back("-lc++");
472     if (Args.hasArg(options::OPT_fexperimental_library))
473       CmdArgs.push_back("-lc++experimental");
474     CmdArgs.push_back("-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.
addTocDataOptions(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CC1Args,const Driver & D)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(TocDataGlobalOption);
547 
548   const char *TocDataListOption =
549       TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=";
550   if (!ExplicitlySpecifiedGlobals.empty())
551     CC1Args.push_back(Args.MakeArgString(llvm::Twine(
552         buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption))));
553 }
554 
addClangTargetOptions(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CC1Args,Action::OffloadKind DeviceOffloadingKind) const555 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, getDriver());
566 
567   if (Args.hasArg(options::OPT_msave_reg_params))
568     CC1Args.push_back("-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("-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("-fno-sized-deallocation");
579 }
580 
addProfileRTLibs(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CmdArgs) const581 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(Args.MakeArgString(
587         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("-latomic");
594     }
595   }
596 
597   ToolChain::addProfileRTLibs(Args, CmdArgs);
598 }
599 
GetDefaultCXXStdlibType() const600 ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const {
601   return ToolChain::CST_Libcxx;
602 }
603 
GetDefaultRuntimeLibType() const604 ToolChain::RuntimeLibType AIX::GetDefaultRuntimeLibType() const {
605   return ToolChain::RLT_CompilerRT;
606 }
607 
buildAssembler() const608 auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); }
609 
buildLinker() const610 auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); }
611