Coverage Report

Created: 2023-09-30 09:22

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