Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Driver/ToolChains/ZOS.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- ZOS.cpp - z/OS 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 "ZOS.h"
10
#include "CommonArgs.h"
11
#include "clang/Driver/Compilation.h"
12
#include "clang/Driver/Options.h"
13
#include "llvm/Option/ArgList.h"
14
#include "llvm/Support/FileSystem.h"
15
#include "llvm/Support/VirtualFileSystem.h"
16
#include "llvm/Support/WithColor.h"
17
18
using namespace clang;
19
using namespace clang::driver;
20
using namespace clang::driver::tools;
21
using namespace clang::driver::toolchains;
22
using namespace llvm;
23
using namespace llvm::opt;
24
using namespace llvm::sys;
25
26
ZOS::ZOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
27
37
    : ToolChain(D, Triple, Args) {}
28
29
37
ZOS::~ZOS() {}
30
31
void ZOS::addClangTargetOptions(const ArgList &DriverArgs,
32
                                ArgStringList &CC1Args,
33
37
                                Action::OffloadKind DeviceOffloadKind) const {
34
  // Pass "-faligned-alloc-unavailable" only when the user hasn't manually
35
  // enabled or disabled aligned allocations.
36
37
  if (!DriverArgs.hasArgNoClaim(options::OPT_faligned_allocation,
37
37
                                options::OPT_fno_aligned_allocation))
38
35
    CC1Args.push_back("-faligned-alloc-unavailable");
39
37
}
40
41
void zos::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
42
                                  const InputInfo &Output,
43
                                  const InputInfoList &Inputs,
44
                                  const ArgList &Args,
45
0
                                  const char *LinkingOutput) const {
46
0
  ArgStringList CmdArgs;
47
48
0
  Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
49
50
  // Specify assembler output file.
51
0
  assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
52
0
  if (Output.isFilename()) {
53
0
    CmdArgs.push_back("-o");
54
0
    CmdArgs.push_back(Output.getFilename());
55
0
  }
56
57
  // Specify assembler input file.
58
  // The system assembler on z/OS takes exactly one input file. The driver is
59
  // expected to invoke as(1) separately for each assembler source input file.
60
0
  if (Inputs.size() != 1)
61
0
    llvm_unreachable("Invalid number of input files.");
62
0
  const InputInfo &II = Inputs[0];
63
0
  assert((II.isFilename() || II.isNothing()) && "Invalid input.");
64
0
  if (II.isFilename())
65
0
    CmdArgs.push_back(II.getFilename());
66
67
0
  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
68
0
  C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
69
0
                                         Exec, CmdArgs, Inputs));
70
0
}
71
72
9
static std::string getLEHLQ(const ArgList &Args) {
73
9
  if (Args.hasArg(options::OPT_mzos_hlq_le_EQ)) {
74
2
    Arg *LEHLQArg = Args.getLastArg(options::OPT_mzos_hlq_le_EQ);
75
2
    StringRef HLQ = LEHLQArg->getValue();
76
2
    if (!HLQ.empty())
77
2
      return HLQ.str();
78
2
  }
79
7
  return "CEE";
80
9
}
81
82
4
static std::string getClangHLQ(const ArgList &Args) {
83
4
  if (Args.hasArg(options::OPT_mzos_hlq_clang_EQ)) {
84
1
    Arg *ClangHLQArg = Args.getLastArg(options::OPT_mzos_hlq_clang_EQ);
85
1
    StringRef HLQ = ClangHLQArg->getValue();
86
1
    if (!HLQ.empty())
87
1
      return HLQ.str();
88
1
  }
89
3
  return getLEHLQ(Args);
90
4
}
91
92
6
static std::string getCSSHLQ(const ArgList &Args) {
93
6
  if (Args.hasArg(options::OPT_mzos_hlq_csslib_EQ)) {
94
1
    Arg *CsslibHLQArg = Args.getLastArg(options::OPT_mzos_hlq_csslib_EQ);
95
1
    StringRef HLQ = CsslibHLQArg->getValue();
96
1
    if (!HLQ.empty())
97
1
      return HLQ.str();
98
1
  }
99
5
  return "SYS1";
100
6
}
101
102
void zos::Linker::ConstructJob(Compilation &C, const JobAction &JA,
103
                               const InputInfo &Output,
104
                               const InputInfoList &Inputs, const ArgList &Args,
105
6
                               const char *LinkingOutput) const {
106
6
  const ZOS &ToolChain = static_cast<const ZOS &>(getToolChain());
107
6
  ArgStringList CmdArgs;
108
109
6
  const bool IsSharedLib =
110
6
      Args.hasFlag(options::OPT_shared, options::OPT_static, false);
111
112
6
  assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
113
6
  if (Output.isFilename()) {
114
6
    CmdArgs.push_back("-o");
115
6
    CmdArgs.push_back(Output.getFilename());
116
6
  }
117
118
6
  SmallString<128> LinkerOptions;
119
6
  LinkerOptions = "AMODE=";
120
6
  LinkerOptions += "64";
121
6
  LinkerOptions += ",LIST";
122
6
  LinkerOptions += ",DYNAM=DLL";
123
6
  LinkerOptions += ",MSGLEVEL=4";
124
6
  LinkerOptions += ",CASE=MIXED";
125
6
  LinkerOptions += ",REUS=RENT";
126
127
6
  CmdArgs.push_back("-b");
128
6
  CmdArgs.push_back(Args.MakeArgString(LinkerOptions));
129
130
6
  if (!IsSharedLib) {
131
4
    CmdArgs.push_back("-e");
132
4
    CmdArgs.push_back("CELQSTRT");
133
134
4
    CmdArgs.push_back("-O");
135
4
    CmdArgs.push_back("CELQSTRT");
136
137
4
    CmdArgs.push_back("-u");
138
4
    CmdArgs.push_back("CELQMAIN");
139
4
  }
140
141
  // Generate side file if -shared option is present.
142
6
  if (IsSharedLib) {
143
2
    StringRef OutputName = Output.getFilename();
144
    // Strip away the last file suffix in presence from output name and add
145
    // a new .x suffix.
146
2
    size_t Suffix = OutputName.find_last_of(".");
147
2
    const char *SideDeckName =
148
2
        Args.MakeArgString(OutputName.substr(0, Suffix) + ".x");
149
2
    CmdArgs.push_back("-x");
150
2
    CmdArgs.push_back(SideDeckName);
151
4
  } else {
152
    // We need to direct side file to /dev/null to suppress linker warning when
153
    // the object file contains exported symbols, and -shared or
154
    // -Wl,-x<sidedeck>.x is not specified.
155
4
    CmdArgs.push_back("-x");
156
4
    CmdArgs.push_back("/dev/null");
157
4
  }
158
159
6
  Args.AddAllArgs(CmdArgs, options::OPT_u);
160
161
  // Add archive library search paths.
162
6
  Args.AddAllArgs(CmdArgs, options::OPT_L);
163
6
  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
164
165
  // Specify linker input file(s)
166
6
  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
167
168
  //  z/OS tool chain depends on LE data sets and the CSSLIB data set.
169
  //  These data sets can have different high level qualifiers (HLQs)
170
  //  as each installation can define them differently.
171
172
6
  std::string LEHLQ = getLEHLQ(Args);
173
6
  std::string CsslibHLQ = getCSSHLQ(Args);
174
175
6
  StringRef ld_env_var = StringRef(getenv("_LD_SYSLIB")).trim();
176
6
  if (ld_env_var.empty()) {
177
6
    CmdArgs.push_back("-S");
178
6
    CmdArgs.push_back(Args.MakeArgString("//'" + LEHLQ + ".SCEEBND2'"));
179
6
    CmdArgs.push_back("-S");
180
6
    CmdArgs.push_back(Args.MakeArgString("//'" + CsslibHLQ + ".CSSLIB'"));
181
6
  }
182
183
6
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
184
6
    ld_env_var = StringRef(getenv("_LD_SIDE_DECKS")).trim();
185
6
    if (ld_env_var.empty()) {
186
6
      CmdArgs.push_back(
187
6
          Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS001)'"));
188
6
      CmdArgs.push_back(
189
6
          Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS003)'"));
190
6
    } else {
191
0
      SmallVector<StringRef> ld_side_deck;
192
0
      ld_env_var.split(ld_side_deck, ":");
193
0
      for (StringRef ld_loc : ld_side_deck) {
194
0
        CmdArgs.push_back((ld_loc.str()).c_str());
195
0
      }
196
0
    }
197
6
  }
198
  // Link libc++ library
199
6
  if (ToolChain.ShouldLinkCXXStdlib(Args)) {
200
4
    ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
201
4
  }
202
203
  // Specify compiler-rt library path for linker
204
6
  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
205
6
    AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args);
206
207
6
  const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
208
6
  C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
209
6
                                         Exec, CmdArgs, Inputs));
210
6
}
211
212
6
ToolChain::RuntimeLibType ZOS::GetDefaultRuntimeLibType() const {
213
6
  return ToolChain::RLT_CompilerRT;
214
6
}
215
216
22
ToolChain::CXXStdlibType ZOS::GetDefaultCXXStdlibType() const {
217
22
  return ToolChain::CST_Libcxx;
218
22
}
219
220
void ZOS::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
221
4
                              llvm::opt::ArgStringList &CmdArgs) const {
222
4
  switch (GetCXXStdlibType(Args)) {
223
0
  case ToolChain::CST_Libstdcxx:
224
0
    llvm::report_fatal_error("linking libstdc++ is unimplemented on z/OS");
225
0
    break;
226
4
  case ToolChain::CST_Libcxx: {
227
4
    std::string ClangHLQ = getClangHLQ(Args);
228
4
    CmdArgs.push_back(
229
4
        Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXE)'"));
230
4
    CmdArgs.push_back(
231
4
        Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXS)'"));
232
4
    CmdArgs.push_back(
233
4
        Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXP)'"));
234
4
    CmdArgs.push_back(
235
4
        Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXA)'"));
236
4
    CmdArgs.push_back(
237
4
        Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQXLA)'"));
238
4
    CmdArgs.push_back(
239
4
        Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQUNW)'"));
240
4
  } break;
241
4
  }
242
4
}
243
244
0
auto ZOS::buildAssembler() const -> Tool * { return new zos::Assembler(*this); }
245
246
6
auto ZOS::buildLinker() const -> Tool * { return new zos::Linker(*this); }
247
248
void ZOS::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
249
37
                                    ArgStringList &CC1Args) const {
250
37
  if (DriverArgs.hasArg(options::OPT_nostdinc))
251
2
    return;
252
253
35
  const Driver &D = getDriver();
254
255
  // resolve ResourceDir
256
35
  std::string ResourceDir(D.ResourceDir);
257
258
  // zos_wrappers must take highest precedence
259
260
  // - <clang>/lib/clang/<ver>/include/zos_wrappers
261
35
  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
262
33
    SmallString<128> P(ResourceDir);
263
33
    path::append(P, "include", "zos_wrappers");
264
33
    addSystemInclude(DriverArgs, CC1Args, P.str());
265
266
    // - <clang>/lib/clang/<ver>/include
267
33
    SmallString<128> P2(ResourceDir);
268
33
    path::append(P2, "include");
269
33
    addSystemInclude(DriverArgs, CC1Args, P2.str());
270
33
  }
271
272
  // - /usr/include
273
35
  if (Arg *SysIncludeArg =
274
35
          DriverArgs.getLastArg(options::OPT_mzos_sys_include_EQ)) {
275
3
    StringRef SysInclude = SysIncludeArg->getValue();
276
277
    // fall back to the default include path
278
3
    if (!SysInclude.empty()) {
279
280
      // -mzos-sys-include opton can have colon separated
281
      // list of paths, so we need to parse the value.
282
3
      StringRef PathLE(SysInclude);
283
3
      size_t Colon = PathLE.find(':');
284
3
      if (Colon == StringRef::npos) {
285
2
        addSystemInclude(DriverArgs, CC1Args, PathLE.str());
286
2
        return;
287
2
      }
288
289
2
      
while (1
Colon != StringRef::npos) {
290
1
        SmallString<128> P = PathLE.substr(0, Colon);
291
1
        addSystemInclude(DriverArgs, CC1Args, P.str());
292
1
        PathLE = PathLE.substr(Colon + 1);
293
1
        Colon = PathLE.find(':');
294
1
      }
295
1
      if (PathLE.size())
296
1
        addSystemInclude(DriverArgs, CC1Args, PathLE.str());
297
298
1
      return;
299
3
    }
300
3
  }
301
302
32
  addSystemInclude(DriverArgs, CC1Args, "/usr/include");
303
32
}
304
305
void ZOS::TryAddIncludeFromPath(llvm::SmallString<128> Path,
306
                                const llvm::opt::ArgList &DriverArgs,
307
22
                                llvm::opt::ArgStringList &CC1Args) const {
308
22
  if (!getVFS().exists(Path)) {
309
9
    if (DriverArgs.hasArg(options::OPT_v))
310
0
      WithColor::warning(errs(), "Clang")
311
0
          << "ignoring nonexistent directory \"" << Path << "\"\n";
312
9
    if (!DriverArgs.hasArg(options::OPT__HASH_HASH_HASH))
313
9
      return;
314
9
  }
315
13
  addSystemInclude(DriverArgs, CC1Args, Path);
316
13
}
317
318
void ZOS::AddClangCXXStdlibIncludeArgs(
319
    const llvm::opt::ArgList &DriverArgs,
320
25
    llvm::opt::ArgStringList &CC1Args) const {
321
25
  if (DriverArgs.hasArg(options::OPT_nostdinc) ||
322
25
      
DriverArgs.hasArg(options::OPT_nostdincxx)24
||
323
25
      
DriverArgs.hasArg(options::OPT_nostdlibinc)23
)
324
3
    return;
325
326
22
  switch (GetCXXStdlibType(DriverArgs)) {
327
22
  case ToolChain::CST_Libcxx: {
328
    // <install>/bin/../include/c++/v1
329
22
    llvm::SmallString<128> InstallBin =
330
22
        llvm::StringRef(getDriver().getInstalledDir());
331
22
    llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1");
332
22
    TryAddIncludeFromPath(InstallBin, DriverArgs, CC1Args);
333
22
    break;
334
0
  }
335
0
  case ToolChain::CST_Libstdcxx:
336
0
    llvm::report_fatal_error(
337
0
        "picking up libstdc++ headers is unimplemented on z/OS");
338
0
    break;
339
22
  }
340
22
}