| 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(Ids: options::OPT_G)) { |
| 44 | D.Diag(DiagID: 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(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, Id0: options::OPT_Wa_COMMA, Id1: 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(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(Ids: options::OPT_G)) { |
| 124 | D.Diag(DiagID: 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(Ids: options::OPT_static)) |
| 130 | CmdArgs.push_back(Elt: "-bnso" ); |
| 131 | |
| 132 | // Add options for shared libraries. |
| 133 | if (Args.hasArg(Ids: options::OPT_shared)) { |
| 134 | CmdArgs.push_back(Elt: "-bM:SRE" ); |
| 135 | CmdArgs.push_back(Elt: "-bnoentry" ); |
| 136 | } |
| 137 | |
| 138 | if (Args.hasFlag(Pos: options::OPT_mxcoff_roptr, Neg: options::OPT_mno_xcoff_roptr, |
| 139 | Default: false)) { |
| 140 | if (Args.hasArg(Ids: options::OPT_shared)) |
| 141 | D.Diag(DiagID: 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(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(Pos: options::OPT_fprofile_arcs, Neg: options::OPT_fno_profile_arcs, |
| 153 | Default: false) || |
| 154 | Args.hasFlag(Pos: options::OPT_fprofile_generate, |
| 155 | Neg: options::OPT_fno_profile_generate, Default: false) || |
| 156 | Args.hasFlag(Pos: options::OPT_fprofile_generate_EQ, |
| 157 | Neg: options::OPT_fno_profile_generate, Default: false) || |
| 158 | Args.hasFlag(Pos: options::OPT_fprofile_instr_generate, |
| 159 | Neg: options::OPT_fno_profile_instr_generate, Default: false) || |
| 160 | Args.hasFlag(Pos: options::OPT_fprofile_instr_generate_EQ, |
| 161 | Neg: options::OPT_fno_profile_instr_generate, Default: false) || |
| 162 | Args.hasFlag(Pos: options::OPT_fcs_profile_generate, |
| 163 | Neg: options::OPT_fno_profile_generate, Default: false) || |
| 164 | Args.hasFlag(Pos: options::OPT_fcs_profile_generate_EQ, |
| 165 | Neg: options::OPT_fno_profile_generate, Default: false) || |
| 166 | Args.hasArg(Ids: options::OPT_fcreate_profile) || |
| 167 | Args.hasArg(Ids: options::OPT_coverage)) |
| 168 | CmdArgs.push_back(Elt: "-bdbg:namedsects:ss" ); |
| 169 | |
| 170 | if (Arg *A = |
| 171 | Args.getLastArg(Ids: 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(DiagID: 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(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(Ids: options::OPT_nostdlib, Ids: options::OPT_nostartfiles, |
| 207 | Ids: options::OPT_shared, Ids: options::OPT_r)) { |
| 208 | auto getCrt0Basename = [&Args, IsArch32Bit] { |
| 209 | if (Arg *A = Args.getLastArgNoClaim(Ids: options::OPT_p, Ids: options::OPT_pg)) { |
| 210 | // Enable gprofiling when "-pg" is specified. |
| 211 | if (A->getOption().matches(ID: 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 | 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(Ids: options::OPT_rpath)) { |
| 233 | for (const auto &bopt : Args.getAllArgValues(Id: options::OPT_b)) |
| 234 | // Check -b opts prefix for "libpath:" or exact match for "nolibpath" |
| 235 | if (!bopt.rfind(s: "libpath:" , pos: 0) || bopt == "nolibpath" ) |
| 236 | D.Diag(DiagID: diag::err_drv_cannot_mix_options) << "-rpath" << "-b" + bopt; |
| 237 | |
| 238 | for (const auto &wlopt : Args.getAllArgValues(Id: options::OPT_Wl_COMMA)) |
| 239 | // Check -Wl, opts prefix for "-blibpath:" or exact match for |
| 240 | // "-bnolibpath" |
| 241 | if (!wlopt.rfind(s: "-blibpath:" , pos: 0) || wlopt == "-bnolibpath" ) |
| 242 | D.Diag(DiagID: diag::err_drv_cannot_mix_options) << "-rpath" << "-Wl," + wlopt; |
| 243 | |
| 244 | for (const auto &xopt : Args.getAllArgValues(Id: options::OPT_Xlinker)) |
| 245 | // Check -Xlinker opts prefix for "-blibpath:" or exact match for |
| 246 | // "-bnolibpath" |
| 247 | if (!xopt.rfind(s: "-blibpath:" , pos: 0) || xopt == "-bnolibpath" ) |
| 248 | D.Diag(DiagID: diag::err_drv_cannot_mix_options) |
| 249 | << "-rpath" << "-Xlinker " + xopt; |
| 250 | |
| 251 | std::string BlibPathStr = "" ; |
| 252 | for (const auto &dir : Args.getAllArgValues(Id: 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(Ids: 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, Id0: options::OPT_L); |
| 301 | if (!Args.hasArg(Ids: 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(Ids: options::OPT_nostdlib, Ids: options::OPT_nodefaultlibs)) { |
| 309 | AddRunTimeLibs(TC: ToolChain, D, CmdArgs, Args); |
| 310 | |
| 311 | // Add OpenMP runtime if -fopenmp is specified. |
| 312 | if (Args.hasFlag(Pos: options::OPT_fopenmp, PosAlias: options::OPT_fopenmp_EQ, |
| 313 | Neg: options::OPT_fno_openmp, Default: 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(Ids: options::OPT_pthreads, Ids: 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(Ids: options::OPT_p, Ids: 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(Ids: options::OPT_nostdlib, Ids: 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 | Pos: options::OPT_fintegrated_as, Neg: options::OPT_fno_integrated_as, Default: 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(Ids: options::OPT_isysroot)) |
| 375 | return DriverArgs.getLastArgValue(Id: 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(Pos: options::OPT_fopenmp, PosAlias: options::OPT_fopenmp_EQ, |
| 385 | Neg: options::OPT_fno_openmp, Default: 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(Ids: options::OPT_nostdinc)) |
| 407 | return; |
| 408 | |
| 409 | llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); |
| 410 | const Driver &D = getDriver(); |
| 411 | |
| 412 | if (!DriverArgs.hasArg(Ids: 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(Ids: 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(Ids: options::OPT_nostdinc) || |
| 441 | DriverArgs.hasArg(Ids: options::OPT_nostdincxx) || |
| 442 | DriverArgs.hasArg(Ids: 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(Ids: 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(Ids: options::OPT_mtocdata, Ids: options::OPT_mno_tocdata)) |
| 493 | return LastArg->getOption().matches(ID: 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(Ids: options::OPT_mtocdata_EQ, Ids: options::OPT_mno_tocdata_EQ)) { |
| 514 | TOCDataSetting ArgTocDataSetting = |
| 515 | Arg->getOption().matches(ID: options::OPT_mtocdata_EQ) ? DataInTOC |
| 516 | : AddressInTOC; |
| 517 | |
| 518 | if (ArgTocDataSetting != DefaultTocDataSetting) |
| 519 | for (const char *Val : Arg->getValues()) |
| 520 | ExplicitlySpecifiedGlobals.insert(x: Val); |
| 521 | else |
| 522 | for (const char *Val : Arg->getValues()) |
| 523 | ExplicitlySpecifiedGlobals.erase(x: 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(Output&: CC1Args, Ids: options::OPT_mignore_xcoff_visibility); |
| 559 | Args.AddLastArg(Output&: CC1Args, Ids: options::OPT_mdefault_visibility_export_mapping_EQ); |
| 560 | Args.addOptInFlag(Output&: CC1Args, Pos: options::OPT_mxcoff_roptr, Neg: options::OPT_mno_xcoff_roptr); |
| 561 | |
| 562 | // Forward last mtocdata/mno_tocdata options to -cc1. |
| 563 | if (Args.hasArg(Ids: options::OPT_mtocdata_EQ, Ids: options::OPT_mno_tocdata_EQ, |
| 564 | Ids: options::OPT_mtocdata)) |
| 565 | addTocDataOptions(Args, CC1Args, D: getDriver()); |
| 566 | |
| 567 | if (Args.hasArg(Ids: options::OPT_msave_reg_params)) |
| 568 | CC1Args.push_back(Elt: "-msave-reg-params" ); |
| 569 | |
| 570 | if (Args.hasFlag(Pos: options::OPT_fxl_pragma_pack, |
| 571 | Neg: options::OPT_fno_xl_pragma_pack, Default: 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(Ids: options::OPT_fsized_deallocation, |
| 577 | Ids: 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(Ids: 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 | |