Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp
Line
Count
Source (jump to first uncovered line)
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
using AIX = clang::driver::toolchains::AIX;
21
using namespace clang::driver;
22
using namespace clang::driver::tools;
23
using namespace clang::driver::toolchains;
24
25
using namespace llvm::opt;
26
using namespace llvm::sys;
27
28
void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
29
                                  const InputInfo &Output,
30
                                  const InputInfoList &Inputs,
31
                                  const ArgList &Args,
32
0
                                  const char *LinkingOutput) const {
33
0
  const Driver &D = getToolChain().getDriver();
34
0
  ArgStringList CmdArgs;
35
36
0
  const bool IsArch32Bit = getToolChain().getTriple().isArch32Bit();
37
0
  const bool IsArch64Bit = getToolChain().getTriple().isArch64Bit();
38
  // Only support 32 and 64 bit.
39
0
  if (!IsArch32Bit && !IsArch64Bit)
40
0
    llvm_unreachable("Unsupported bit width value.");
41
42
0
  if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) {
43
0
    D.Diag(diag::err_drv_unsupported_opt_for_target)
44
0
        << A->getSpelling() << D.getTargetTriple();
45
0
  }
46
47
  // Specify the mode in which the as(1) command operates.
48
0
  if (IsArch32Bit) {
49
0
    CmdArgs.push_back("-a32");
50
0
  } else {
51
    // Must be 64-bit, otherwise asserted already.
52
0
    CmdArgs.push_back("-a64");
53
0
  }
54
55
  // Accept any mixture of instructions.
56
  // On Power for AIX and Linux, this behaviour matches that of GCC for both the
57
  // user-provided assembler source case and the compiler-produced assembler
58
  // source case. Yet XL with user-provided assembler source would not add this.
59
0
  CmdArgs.push_back("-many");
60
61
0
  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
62
63
  // Specify assembler output file.
64
0
  assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
65
0
  if (Output.isFilename()) {
66
0
    CmdArgs.push_back("-o");
67
0
    CmdArgs.push_back(Output.getFilename());
68
0
  }
69
70
  // Specify assembler input file.
71
  // The system assembler on AIX takes exactly one input file. The driver is
72
  // expected to invoke as(1) separately for each assembler source input file.
73
0
  if (Inputs.size() != 1)
74
0
    llvm_unreachable("Invalid number of input files.");
75
0
  const InputInfo &II = Inputs[0];
76
0
  assert((II.isFilename() || II.isNothing()) && "Invalid input.");
77
0
  if (II.isFilename())
78
0
    CmdArgs.push_back(II.getFilename());
79
80
0
  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
81
0
  C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
82
0
                                         Exec, CmdArgs, Inputs, Output));
83
0
}
84
85
// Determine whether there are any linker options that supply an export list
86
// (or equivalent information about what to export) being sent to the linker.
87
0
static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) {
88
0
  for (size_t i = 0, Size = CmdArgs.size(); i < Size; ++i) {
89
0
    llvm::StringRef ArgString(CmdArgs[i]);
90
91
0
    if (ArgString.starts_with("-bE:") || ArgString.starts_with("-bexport:") ||
92
0
        ArgString == "-bexpall" || ArgString == "-bexpfull")
93
0
      return true;
94
95
    // If we split -b option, check the next opt.
96
0
    if (ArgString == "-b" && i + 1 < Size) {
97
0
      ++i;
98
0
      llvm::StringRef ArgNextString(CmdArgs[i]);
99
0
      if (ArgNextString.starts_with("E:") ||
100
0
          ArgNextString.starts_with("export:") || ArgNextString == "expall" ||
101
0
          ArgNextString == "expfull")
102
0
        return true;
103
0
    }
104
0
  }
105
0
  return false;
106
0
}
107
108
void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
109
                               const InputInfo &Output,
110
                               const InputInfoList &Inputs, const ArgList &Args,
111
0
                               const char *LinkingOutput) const {
112
0
  const AIX &ToolChain = static_cast<const AIX &>(getToolChain());
113
0
  const Driver &D = ToolChain.getDriver();
114
0
  ArgStringList CmdArgs;
115
116
0
  const bool IsArch32Bit = ToolChain.getTriple().isArch32Bit();
117
0
  const bool IsArch64Bit = ToolChain.getTriple().isArch64Bit();
118
  // Only support 32 and 64 bit.
119
0
  if (!(IsArch32Bit || IsArch64Bit))
120
0
    llvm_unreachable("Unsupported bit width value.");
121
122
0
  if (Arg *A = C.getArgs().getLastArg(options::OPT_G)) {
123
0
    D.Diag(diag::err_drv_unsupported_opt_for_target)
124
0
        << A->getSpelling() << D.getTargetTriple();
125
0
  }
126
127
  // Force static linking when "-static" is present.
128
0
  if (Args.hasArg(options::OPT_static))
129
0
    CmdArgs.push_back("-bnso");
130
131
  // Add options for shared libraries.
132
0
  if (Args.hasArg(options::OPT_shared)) {
133
0
    CmdArgs.push_back("-bM:SRE");
134
0
    CmdArgs.push_back("-bnoentry");
135
0
  }
136
137
0
  if (Args.hasFlag(options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr,
138
0
                   false)) {
139
0
    if (Args.hasArg(options::OPT_shared))
140
0
      D.Diag(diag::err_roptr_cannot_build_shared);
141
142
    // The `-mxcoff-roptr` option places constants in RO sections as much as
143
    // possible. Then `-bforceimprw` changes such sections to RW if they contain
144
    // imported symbols that need to be resolved.
145
0
    CmdArgs.push_back("-bforceimprw");
146
0
  }
147
148
  // PGO instrumentation generates symbols belonging to special sections, and
149
  // the linker needs to place all symbols in a particular section together in
150
  // memory; the AIX linker does that under an option.
151
0
  if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
152
0
                    false) ||
153
0
       Args.hasFlag(options::OPT_fprofile_generate,
154
0
                    options::OPT_fno_profile_generate, false) ||
155
0
       Args.hasFlag(options::OPT_fprofile_generate_EQ,
156
0
                    options::OPT_fno_profile_generate, false) ||
157
0
       Args.hasFlag(options::OPT_fprofile_instr_generate,
158
0
                    options::OPT_fno_profile_instr_generate, false) ||
159
0
       Args.hasFlag(options::OPT_fprofile_instr_generate_EQ,
160
0
                    options::OPT_fno_profile_instr_generate, false) ||
161
0
       Args.hasFlag(options::OPT_fcs_profile_generate,
162
0
                    options::OPT_fno_profile_generate, false) ||
163
0
       Args.hasFlag(options::OPT_fcs_profile_generate_EQ,
164
0
                    options::OPT_fno_profile_generate, false) ||
165
0
       Args.hasArg(options::OPT_fcreate_profile) ||
166
0
       Args.hasArg(options::OPT_coverage))
167
0
    CmdArgs.push_back("-bdbg:namedsects:ss");
168
169
0
  if (Arg *A =
170
0
          Args.getLastArg(clang::driver::options::OPT_mxcoff_build_id_EQ)) {
171
0
    StringRef BuildId = A->getValue();
172
0
    if (BuildId[0] != '0' || BuildId[1] != 'x' ||
173
0
        BuildId.find_if_not(llvm::isHexDigit, 2) != StringRef::npos)
174
0
      ToolChain.getDriver().Diag(diag::err_drv_unsupported_option_argument)
175
0
          << A->getSpelling() << BuildId;
176
0
    else {
177
0
      std::string LinkerFlag = "-bdbg:ldrinfo:xcoff_binary_id:0x";
178
0
      if (BuildId.size() % 2) // Prepend a 0 if odd number of digits.
179
0
        LinkerFlag += "0";
180
0
      LinkerFlag += BuildId.drop_front(2).lower();
181
0
      CmdArgs.push_back(Args.MakeArgString(LinkerFlag));
182
0
    }
183
0
  }
184
185
  // Specify linker output file.
186
0
  assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
187
0
  if (Output.isFilename()) {
188
0
    CmdArgs.push_back("-o");
189
0
    CmdArgs.push_back(Output.getFilename());
190
0
  }
191
192
  // Set linking mode (i.e., 32/64-bit) and the address of
193
  // text and data sections based on arch bit width.
194
0
  if (IsArch32Bit) {
195
0
    CmdArgs.push_back("-b32");
196
0
    CmdArgs.push_back("-bpT:0x10000000");
197
0
    CmdArgs.push_back("-bpD:0x20000000");
198
0
  } else {
199
    // Must be 64-bit, otherwise asserted already.
200
0
    CmdArgs.push_back("-b64");
201
0
    CmdArgs.push_back("-bpT:0x100000000");
202
0
    CmdArgs.push_back("-bpD:0x110000000");
203
0
  }
204
205
0
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
206
0
                   options::OPT_shared, options::OPT_r)) {
207
0
    auto getCrt0Basename = [&Args, IsArch32Bit] {
208
0
      if (Arg *A = Args.getLastArgNoClaim(options::OPT_p, options::OPT_pg)) {
209
        // Enable gprofiling when "-pg" is specified.
210
0
        if (A->getOption().matches(options::OPT_pg))
211
0
          return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o";
212
        // Enable profiling when "-p" is specified.
213
0
        return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o";
214
0
      }
215
0
      return IsArch32Bit ? "crt0.o" : "crt0_64.o";
216
0
    };
217
218
0
    CmdArgs.push_back(
219
0
        Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename())));
220
221
0
    CmdArgs.push_back(Args.MakeArgString(
222
0
        ToolChain.GetFilePath(IsArch32Bit ? "crti.o" : "crti_64.o")));
223
0
  }
224
225
  // Collect all static constructor and destructor functions in both C and CXX
226
  // language link invocations. This has to come before AddLinkerInputs as the
227
  // implied option needs to precede any other '-bcdtors' settings or
228
  // '-bnocdtors' that '-Wl' might forward.
229
0
  CmdArgs.push_back("-bcdtors:all:0:s");
230
231
  // Specify linker input file(s).
232
0
  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
233
234
0
  if (D.isUsingLTO()) {
235
0
    assert(!Inputs.empty() && "Must have at least one input.");
236
    // Find the first filename InputInfo object.
237
0
    auto Input = llvm::find_if(
238
0
        Inputs, [](const InputInfo &II) -> bool { return II.isFilename(); });
239
0
    if (Input == Inputs.end())
240
      // For a very rare case, all of the inputs to the linker are
241
      // InputArg. If that happens, just use the first InputInfo.
242
0
      Input = Inputs.begin();
243
244
0
    addLTOOptions(ToolChain, Args, CmdArgs, Output, *Input,
245
0
                  D.getLTOMode() == LTOK_Thin);
246
0
  }
247
248
0
  if (Args.hasArg(options::OPT_shared) && !hasExportListLinkerOpts(CmdArgs)) {
249
250
0
    const char *CreateExportListExec = Args.MakeArgString(
251
0
        path::parent_path(ToolChain.getDriver().ClangExecutable) +
252
0
        "/llvm-nm");
253
0
    ArgStringList CreateExportCmdArgs;
254
255
0
    std::string CreateExportListPath =
256
0
        C.getDriver().GetTemporaryPath("CreateExportList", "exp");
257
0
    const char *ExportList =
258
0
        C.addTempFile(C.getArgs().MakeArgString(CreateExportListPath));
259
260
0
    for (const auto &II : Inputs)
261
0
      if (II.isFilename())
262
0
        CreateExportCmdArgs.push_back(II.getFilename());
263
264
0
    CreateExportCmdArgs.push_back("--export-symbols");
265
0
    CreateExportCmdArgs.push_back("-X");
266
0
    if (IsArch32Bit) {
267
0
      CreateExportCmdArgs.push_back("32");
268
0
    } else {
269
      // Must be 64-bit, otherwise asserted already.
270
0
      CreateExportCmdArgs.push_back("64");
271
0
    }
272
273
0
    auto ExpCommand = std::make_unique<Command>(
274
0
        JA, *this, ResponseFileSupport::None(), CreateExportListExec,
275
0
        CreateExportCmdArgs, Inputs, Output);
276
0
    ExpCommand->setRedirectFiles(
277
0
        {std::nullopt, std::string(ExportList), std::nullopt});
278
0
    C.addCommand(std::move(ExpCommand));
279
0
    CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-bE:") + ExportList));
280
0
  }
281
282
  // Add directory to library search path.
283
0
  Args.AddAllArgs(CmdArgs, options::OPT_L);
284
0
  if (!Args.hasArg(options::OPT_r)) {
285
0
    ToolChain.AddFilePathLibArgs(Args, CmdArgs);
286
0
    ToolChain.addProfileRTLibs(Args, CmdArgs);
287
288
0
    if (getToolChain().ShouldLinkCXXStdlib(Args))
289
0
      getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
290
291
0
    if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
292
0
      AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
293
294
      // Add OpenMP runtime if -fopenmp is specified.
295
0
      if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
296
0
                       options::OPT_fno_openmp, false)) {
297
0
        switch (ToolChain.getDriver().getOpenMPRuntime(Args)) {
298
0
        case Driver::OMPRT_OMP:
299
0
          CmdArgs.push_back("-lomp");
300
0
          break;
301
0
        case Driver::OMPRT_IOMP5:
302
0
          CmdArgs.push_back("-liomp5");
303
0
          break;
304
0
        case Driver::OMPRT_GOMP:
305
0
          CmdArgs.push_back("-lgomp");
306
0
          break;
307
0
        case Driver::OMPRT_Unknown:
308
          // Already diagnosed.
309
0
          break;
310
0
        }
311
0
      }
312
313
      // Support POSIX threads if "-pthreads" or "-pthread" is present.
314
0
      if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread))
315
0
        CmdArgs.push_back("-lpthreads");
316
317
0
      if (D.CCCIsCXX())
318
0
        CmdArgs.push_back("-lm");
319
320
0
      CmdArgs.push_back("-lc");
321
322
0
      if (Args.hasArgNoClaim(options::OPT_p, options::OPT_pg)) {
323
0
        CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
324
0
                                             "/lib/profiled"));
325
0
        CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
326
0
                                             "/usr/lib/profiled"));
327
0
      }
328
0
    }
329
0
  }
330
331
0
  if (D.IsFlangMode()) {
332
0
    addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
333
0
    addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
334
0
    CmdArgs.push_back("-lm");
335
0
    CmdArgs.push_back("-lpthread");
336
0
  }
337
0
  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
338
0
  C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
339
0
                                         Exec, CmdArgs, Inputs, Output));
340
0
}
341
342
/// AIX - AIX tool chain which can call as(1) and ld(1) directly.
343
AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
344
0
    : ToolChain(D, Triple, Args) {
345
0
  getProgramPaths().push_back(getDriver().getInstalledDir());
346
0
  if (getDriver().getInstalledDir() != getDriver().Dir)
347
0
    getProgramPaths().push_back(getDriver().Dir);
348
349
0
  ParseInlineAsmUsingAsmParser = Args.hasFlag(
350
0
      options::OPT_fintegrated_as, options::OPT_fno_integrated_as, true);
351
0
  getLibraryPaths().push_back(getDriver().SysRoot + "/usr/lib");
352
0
}
353
354
// Returns the effective header sysroot path to use.
355
// This comes from either -isysroot or --sysroot.
356
llvm::StringRef
357
0
AIX::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const {
358
0
  if (DriverArgs.hasArg(options::OPT_isysroot))
359
0
    return DriverArgs.getLastArgValue(options::OPT_isysroot);
360
0
  if (!getDriver().SysRoot.empty())
361
0
    return getDriver().SysRoot;
362
0
  return "/";
363
0
}
364
365
void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
366
0
                                    ArgStringList &CC1Args) const {
367
  // Return if -nostdinc is specified as a driver option.
368
0
  if (DriverArgs.hasArg(options::OPT_nostdinc))
369
0
    return;
370
371
0
  llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
372
0
  const Driver &D = getDriver();
373
374
0
  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
375
0
    SmallString<128> P(D.ResourceDir);
376
    // Add the PowerPC intrinsic headers (<resource>/include/ppc_wrappers)
377
0
    path::append(P, "include", "ppc_wrappers");
378
0
    addSystemInclude(DriverArgs, CC1Args, P);
379
    // Add the Clang builtin headers (<resource>/include)
380
0
    addSystemInclude(DriverArgs, CC1Args, path::parent_path(P.str()));
381
0
  }
382
383
  // Return if -nostdlibinc is specified as a driver option.
384
0
  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
385
0
    return;
386
387
  // Add <sysroot>/usr/include.
388
0
  SmallString<128> UP(Sysroot);
389
0
  path::append(UP, "/usr/include");
390
0
  addSystemInclude(DriverArgs, CC1Args, UP.str());
391
0
}
392
393
void AIX::AddClangCXXStdlibIncludeArgs(
394
    const llvm::opt::ArgList &DriverArgs,
395
0
    llvm::opt::ArgStringList &CC1Args) const {
396
397
0
  if (DriverArgs.hasArg(options::OPT_nostdinc) ||
398
0
      DriverArgs.hasArg(options::OPT_nostdincxx) ||
399
0
      DriverArgs.hasArg(options::OPT_nostdlibinc))
400
0
    return;
401
402
0
  switch (GetCXXStdlibType(DriverArgs)) {
403
0
  case ToolChain::CST_Libstdcxx:
404
0
    llvm::report_fatal_error(
405
0
        "picking up libstdc++ headers is unimplemented on AIX");
406
0
  case ToolChain::CST_Libcxx: {
407
0
    llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
408
0
    SmallString<128> PathCPP(Sysroot);
409
0
    llvm::sys::path::append(PathCPP, "opt/IBM/openxlCSDK", "include", "c++",
410
0
                            "v1");
411
0
    addSystemInclude(DriverArgs, CC1Args, PathCPP.str());
412
    // Required in order to suppress conflicting C++ overloads in the system
413
    // libc headers that were used by XL C++.
414
0
    CC1Args.push_back("-D__LIBC_NO_CPP_MATH_OVERLOADS__");
415
0
    return;
416
0
  }
417
0
  }
418
419
0
  llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
420
0
}
421
422
void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
423
0
                              llvm::opt::ArgStringList &CmdArgs) const {
424
0
  switch (GetCXXStdlibType(Args)) {
425
0
  case ToolChain::CST_Libstdcxx:
426
0
    llvm::report_fatal_error("linking libstdc++ unimplemented on AIX");
427
0
  case ToolChain::CST_Libcxx:
428
0
    CmdArgs.push_back("-lc++");
429
0
    if (Args.hasArg(options::OPT_fexperimental_library))
430
0
      CmdArgs.push_back("-lc++experimental");
431
0
    CmdArgs.push_back("-lc++abi");
432
0
    return;
433
0
  }
434
435
0
  llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
436
0
}
437
438
void AIX::addClangTargetOptions(
439
    const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args,
440
0
    Action::OffloadKind DeviceOffloadingKind) const {
441
0
  Args.AddLastArg(CC1Args, options::OPT_mignore_xcoff_visibility);
442
0
  Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ);
443
0
  Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr);
444
445
0
  if (Args.hasFlag(options::OPT_fxl_pragma_pack,
446
0
                   options::OPT_fno_xl_pragma_pack, true))
447
0
    CC1Args.push_back("-fxl-pragma-pack");
448
0
}
449
450
void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args,
451
0
                           llvm::opt::ArgStringList &CmdArgs) const {
452
0
  if (needsProfileRT(Args)) {
453
    // Add linker option -u__llvm_profile_runtime to cause runtime
454
    // initialization to occur.
455
0
    CmdArgs.push_back(Args.MakeArgString(
456
0
        Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
457
458
0
    if (const auto *A =
459
0
            Args.getLastArgNoClaim(options::OPT_fprofile_update_EQ)) {
460
0
      StringRef Val = A->getValue();
461
0
      if (Val == "atomic" || Val == "prefer-atomic")
462
0
        CmdArgs.push_back("-latomic");
463
0
    }
464
0
  }
465
466
0
  ToolChain::addProfileRTLibs(Args, CmdArgs);
467
0
}
468
469
0
ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const {
470
0
  return ToolChain::CST_Libcxx;
471
0
}
472
473
0
ToolChain::RuntimeLibType AIX::GetDefaultRuntimeLibType() const {
474
0
  return ToolChain::RLT_CompilerRT;
475
0
}
476
477
0
auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); }
478
479
0
auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); }