xref: /freebsd/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp (revision 62987288060ff68c817b7056815aa9fb8ba8ecd7)
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 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const30 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::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("-a32");
52   } else {
53     // Must be 64-bit, otherwise asserted already.
54     CmdArgs.push_back("-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("-many");
62 
63   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, 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("-o");
69     CmdArgs.push_back(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(II.getFilename());
81 
82   const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
83   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
84                                          Exec, CmdArgs, Inputs, 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.
hasExportListLinkerOpts(const ArgStringList & CmdArgs)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("-bE:") || ArgString.starts_with("-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("E:") ||
102           ArgNextString.starts_with("export:") || ArgNextString == "expall" ||
103           ArgNextString == "expfull")
104         return true;
105     }
106   }
107   return false;
108 }
109 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const110 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::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("-bnso");
132 
133   // Add options for shared libraries.
134   if (Args.hasArg(options::OPT_shared)) {
135     CmdArgs.push_back("-bM:SRE");
136     CmdArgs.push_back("-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::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("-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("-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(llvm::isHexDigit, 2) != StringRef::npos)
176       ToolChain.getDriver().Diag(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(2).lower();
183       CmdArgs.push_back(Args.MakeArgString(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("-o");
191     CmdArgs.push_back(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("-b32");
198     CmdArgs.push_back("-bpT:0x10000000");
199     CmdArgs.push_back("-bpD:0x20000000");
200   } else {
201     // Must be 64-bit, otherwise asserted already.
202     CmdArgs.push_back("-b64");
203     CmdArgs.push_back("-bpT:0x100000000");
204     CmdArgs.push_back("-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::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         Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename())));
222 
223     CmdArgs.push_back(Args.MakeArgString(
224         ToolChain.GetFilePath(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("-bcdtors:all:0:s");
232 
233   // Specify linker input file(s).
234   AddLinkerInputs(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         Inputs, [](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,
247                   D.getLTOMode() == LTOK_Thin);
248   }
249 
250   if (Args.hasArg(options::OPT_shared) && !hasExportListLinkerOpts(CmdArgs)) {
251 
252     const char *CreateExportListExec = Args.MakeArgString(
253         path::parent_path(ToolChain.getDriver().ClangExecutable) +
254         "/llvm-nm");
255     ArgStringList CreateExportCmdArgs;
256 
257     std::string CreateExportListPath =
258         C.getDriver().GetTemporaryPath("CreateExportList", "exp");
259     const char *ExportList =
260         C.addTempFile(C.getArgs().MakeArgString(CreateExportListPath));
261 
262     for (const auto &II : Inputs)
263       if (II.isFilename())
264         CreateExportCmdArgs.push_back(II.getFilename());
265 
266     CreateExportCmdArgs.push_back("--export-symbols");
267     CreateExportCmdArgs.push_back("-X");
268     if (IsArch32Bit) {
269       CreateExportCmdArgs.push_back("32");
270     } else {
271       // Must be 64-bit, otherwise asserted already.
272       CreateExportCmdArgs.push_back("64");
273     }
274 
275     auto ExpCommand = std::make_unique<Command>(
276         JA, *this, ResponseFileSupport::None(), CreateExportListExec,
277         CreateExportCmdArgs, Inputs, Output);
278     ExpCommand->setRedirectFiles(
279         {std::nullopt, std::string(ExportList), std::nullopt});
280     C.addCommand(std::move(ExpCommand));
281     CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-bE:") + ExportList));
282   }
283 
284   // Add directory to library search path.
285   Args.AddAllArgs(CmdArgs, options::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(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("-lomp");
302           break;
303         case Driver::OMPRT_IOMP5:
304           CmdArgs.push_back("-liomp5");
305           break;
306         case Driver::OMPRT_GOMP:
307           CmdArgs.push_back("-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("-lpthreads");
318 
319       if (D.CCCIsCXX())
320         CmdArgs.push_back("-lm");
321 
322       CmdArgs.push_back("-lc");
323 
324       if (Args.hasArgNoClaim(options::OPT_p, options::OPT_pg)) {
325         CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
326                                              "/lib/profiled"));
327         CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
328                                              "/usr/lib/profiled"));
329       }
330     }
331   }
332 
333   if (D.IsFlangMode()) {
334     addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
335     addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
336     CmdArgs.push_back("-lm");
337     CmdArgs.push_back("-lpthread");
338   }
339   const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
340   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
341                                          Exec, CmdArgs, Inputs, Output));
342 }
343 
344 /// AIX - AIX tool chain which can call as(1) and ld(1) directly.
AIX(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)345 AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
346     : ToolChain(D, Triple, Args) {
347   getProgramPaths().push_back(getDriver().Dir);
348 
349   ParseInlineAsmUsingAsmParser = Args.hasFlag(
350       options::OPT_fintegrated_as, options::OPT_fno_integrated_as, true);
351   getLibraryPaths().push_back(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
GetHeaderSysroot(const llvm::opt::ArgList & DriverArgs) const357 AIX::GetHeaderSysroot(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 
AddOpenMPIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const365 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(DriverArgs)) {
372     case Driver::OMPRT_OMP:
373       PathOpenMP = GetHeaderSysroot(DriverArgs);
374       llvm::sys::path::append(PathOpenMP, "opt/IBM/openxlCSDK", "include",
375                               "openmp");
376       addSystemInclude(DriverArgs, CC1Args, 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 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const387 void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
388                                     ArgStringList &CC1Args) const {
389   // Return if -nostdinc is specified as a driver option.
390   if (DriverArgs.hasArg(options::OPT_nostdinc))
391     return;
392 
393   llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
394   const Driver &D = getDriver();
395 
396   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
397     SmallString<128> P(D.ResourceDir);
398     // Add the PowerPC intrinsic headers (<resource>/include/ppc_wrappers)
399     path::append(P, "include", "ppc_wrappers");
400     addSystemInclude(DriverArgs, CC1Args, P);
401     // Add the Clang builtin headers (<resource>/include)
402     addSystemInclude(DriverArgs, CC1Args, path::parent_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(options::OPT_nostdlibinc))
412     return;
413 
414   // Add <sysroot>/usr/include.
415   SmallString<128> UP(Sysroot);
416   path::append(UP, "/usr/include");
417   addSystemInclude(DriverArgs, CC1Args, UP.str());
418 }
419 
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList & DriverArgs,llvm::opt::ArgStringList & CC1Args) const420 void AIX::AddClangCXXStdlibIncludeArgs(
421     const llvm::opt::ArgList &DriverArgs,
422     llvm::opt::ArgStringList &CC1Args) const {
423 
424   if (DriverArgs.hasArg(options::OPT_nostdinc) ||
425       DriverArgs.hasArg(options::OPT_nostdincxx) ||
426       DriverArgs.hasArg(options::OPT_nostdlibinc))
427     return;
428 
429   switch (GetCXXStdlibType(DriverArgs)) {
430   case ToolChain::CST_Libstdcxx:
431     llvm::report_fatal_error(
432         "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(PathCPP, "opt/IBM/openxlCSDK", "include", "c++",
437                             "v1");
438     addSystemInclude(DriverArgs, CC1Args, 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("-D__LIBC_NO_CPP_MATH_OVERLOADS__");
442     return;
443   }
444   }
445 
446   llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
447 }
448 
AddCXXStdlibLibArgs(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CmdArgs) const449 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("linking libstdc++ unimplemented on AIX");
454   case ToolChain::CST_Libcxx:
455     CmdArgs.push_back("-lc++");
456     if (Args.hasArg(options::OPT_fexperimental_library))
457       CmdArgs.push_back("-lc++experimental");
458     CmdArgs.push_back("-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.
addTocDataOptions(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CC1Args,const Driver & D)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(options::OPT_mtocdata, options::OPT_mno_tocdata))
477       return LastArg->getOption().matches(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(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ)) {
498     TOCDataSetting ArgTocDataSetting =
499         Arg->getOption().matches(options::OPT_mtocdata_EQ) ? DataInTOC
500                                                            : AddressInTOC;
501 
502     if (ArgTocDataSetting != DefaultTocDataSetting)
503       for (const char *Val : Arg->getValues())
504         ExplicitlySpecifiedGlobals.insert(Val);
505     else
506       for (const char *Val : Arg->getValues())
507         ExplicitlySpecifiedGlobals.erase(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(TocDataGlobalOption);
531 
532   const char *TocDataListOption =
533       TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=";
534   if (!ExplicitlySpecifiedGlobals.empty())
535     CC1Args.push_back(Args.MakeArgString(llvm::Twine(
536         buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption))));
537 }
538 
addClangTargetOptions(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CC1Args,Action::OffloadKind DeviceOffloadingKind) const539 void AIX::addClangTargetOptions(
540     const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args,
541     Action::OffloadKind DeviceOffloadingKind) const {
542   Args.AddLastArg(CC1Args, options::OPT_mignore_xcoff_visibility);
543   Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ);
544   Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr);
545 
546   // Forward last mtocdata/mno_tocdata options to -cc1.
547   if (Args.hasArg(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ,
548                   options::OPT_mtocdata))
549     addTocDataOptions(Args, CC1Args, getDriver());
550 
551   if (Args.hasFlag(options::OPT_fxl_pragma_pack,
552                    options::OPT_fno_xl_pragma_pack, true))
553     CC1Args.push_back("-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(options::OPT_fsized_deallocation,
558                               options::OPT_fno_sized_deallocation))
559     CC1Args.push_back("-fno-sized-deallocation");
560 }
561 
addProfileRTLibs(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CmdArgs) const562 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(Args.MakeArgString(
568         Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
569 
570     if (const auto *A =
571             Args.getLastArgNoClaim(options::OPT_fprofile_update_EQ)) {
572       StringRef Val = A->getValue();
573       if (Val == "atomic" || Val == "prefer-atomic")
574         CmdArgs.push_back("-latomic");
575     }
576   }
577 
578   ToolChain::addProfileRTLibs(Args, CmdArgs);
579 }
580 
GetDefaultCXXStdlibType() const581 ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const {
582   return ToolChain::CST_Libcxx;
583 }
584 
GetDefaultRuntimeLibType() const585 ToolChain::RuntimeLibType AIX::GetDefaultRuntimeLibType() const {
586   return ToolChain::RLT_CompilerRT;
587 }
588 
buildAssembler() const589 auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); }
590 
buildLinker() const591 auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); }
592