Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- AMDGPUOpenMP.cpp - AMDGPUOpenMP ToolChain Implementation -*- 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 "AMDGPUOpenMP.h"
10
#include "AMDGPU.h"
11
#include "CommonArgs.h"
12
#include "ToolChains/ROCm.h"
13
#include "clang/Basic/DiagnosticDriver.h"
14
#include "clang/Driver/Compilation.h"
15
#include "clang/Driver/Driver.h"
16
#include "clang/Driver/DriverDiagnostic.h"
17
#include "clang/Driver/InputInfo.h"
18
#include "clang/Driver/Options.h"
19
#include "llvm/ADT/STLExtras.h"
20
#include "llvm/Support/FileSystem.h"
21
#include "llvm/Support/FormatAdapters.h"
22
#include "llvm/Support/FormatVariadic.h"
23
#include "llvm/Support/Path.h"
24
25
using namespace clang::driver;
26
using namespace clang::driver::toolchains;
27
using namespace clang::driver::tools;
28
using namespace clang;
29
using namespace llvm::opt;
30
31
namespace {
32
33
static const char *getOutputFileName(Compilation &C, StringRef Base,
34
                                     const char *Postfix,
35
0
                                     const char *Extension) {
36
0
  const char *OutputFileName;
37
0
  if (C.getDriver().isSaveTempsEnabled()) {
38
0
    OutputFileName =
39
0
        C.getArgs().MakeArgString(Base.str() + Postfix + "." + Extension);
40
0
  } else {
41
0
    std::string TmpName =
42
0
        C.getDriver().GetTemporaryPath(Base.str() + Postfix, Extension);
43
0
    OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName));
44
0
  }
45
0
  return OutputFileName;
46
0
}
47
48
static void addLLCOptArg(const llvm::opt::ArgList &Args,
49
0
                         llvm::opt::ArgStringList &CmdArgs) {
50
0
  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
51
0
    StringRef OOpt = "0";
52
0
    if (A->getOption().matches(options::OPT_O4) ||
53
0
        A->getOption().matches(options::OPT_Ofast))
54
0
      OOpt = "3";
55
0
    else if (A->getOption().matches(options::OPT_O0))
56
0
      OOpt = "0";
57
0
    else if (A->getOption().matches(options::OPT_O)) {
58
      // Clang and opt support -Os/-Oz; llc only supports -O0, -O1, -O2 and -O3
59
      // so we map -Os/-Oz to -O2.
60
      // Only clang supports -Og, and maps it to -O1.
61
      // We map anything else to -O2.
62
0
      OOpt = llvm::StringSwitch<const char *>(A->getValue())
63
0
                 .Case("1", "1")
64
0
                 .Case("2", "2")
65
0
                 .Case("3", "3")
66
0
                 .Case("s", "2")
67
0
                 .Case("z", "2")
68
0
                 .Case("g", "1")
69
0
                 .Default("0");
70
0
    }
71
0
    CmdArgs.push_back(Args.MakeArgString("-O" + OOpt));
72
0
  }
73
0
}
74
75
static bool checkSystemForAMDGPU(const ArgList &Args, const AMDGPUToolChain &TC,
76
0
                                 std::string &GPUArch) {
77
0
  if (auto Err = TC.getSystemGPUArch(Args, GPUArch)) {
78
0
    std::string ErrMsg =
79
0
        llvm::formatv("{0}", llvm::fmt_consume(std::move(Err)));
80
0
    TC.getDriver().Diag(diag::err_drv_undetermined_amdgpu_arch) << ErrMsg;
81
0
    return false;
82
0
  }
83
84
0
  return true;
85
0
}
86
} // namespace
87
88
const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand(
89
    const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C,
90
    const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args,
91
0
    StringRef SubArchName, StringRef OutputFilePrefix) const {
92
0
  ArgStringList CmdArgs;
93
94
0
  for (const auto &II : Inputs)
95
0
    if (II.isFilename())
96
0
      CmdArgs.push_back(II.getFilename());
97
98
0
  if (Args.hasArg(options::OPT_l)) {
99
0
    auto Lm = Args.getAllArgValues(options::OPT_l);
100
0
    bool HasLibm = false;
101
0
    for (auto &Lib : Lm) {
102
0
      if (Lib == "m") {
103
0
        HasLibm = true;
104
0
        break;
105
0
      }
106
0
    }
107
108
0
    if (HasLibm) {
109
      // This is not certain to work. The device libs added here, and passed to
110
      // llvm-link, are missing attributes that they expect to be inserted when
111
      // passed to mlink-builtin-bitcode. The amdgpu backend does not generate
112
      // conservatively correct code when attributes are missing, so this may
113
      // be the root cause of miscompilations. Passing via mlink-builtin-bitcode
114
      // ultimately hits CodeGenModule::addDefaultFunctionDefinitionAttributes
115
      // on each function, see D28538 for context.
116
      // Potential workarounds:
117
      //  - unconditionally link all of the device libs to every translation
118
      //    unit in clang via mlink-builtin-bitcode
119
      //  - build a libm bitcode file as part of the DeviceRTL and explictly
120
      //    mlink-builtin-bitcode the rocm device libs components at build time
121
      //  - drop this llvm-link fork in favour or some calls into LLVM, chosen
122
      //    to do basically the same work as llvm-link but with that call first
123
      //  - write an opt pass that sets that on every function it sees and pipe
124
      //    the device-libs bitcode through that on the way to this llvm-link
125
0
      SmallVector<std::string, 12> BCLibs =
126
0
          AMDGPUOpenMPTC.getCommonDeviceLibNames(Args, SubArchName.str());
127
0
      llvm::for_each(BCLibs, [&](StringRef BCFile) {
128
0
        CmdArgs.push_back(Args.MakeArgString(BCFile));
129
0
      });
130
0
    }
131
0
  }
132
133
0
  AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "amdgcn",
134
0
                             SubArchName, /*isBitCodeSDL=*/true,
135
0
                             /*postClangLink=*/false);
136
  // Add an intermediate output file.
137
0
  CmdArgs.push_back("-o");
138
0
  const char *OutputFileName =
139
0
      getOutputFileName(C, OutputFilePrefix, "-linked", "bc");
140
0
  CmdArgs.push_back(OutputFileName);
141
0
  const char *Exec =
142
0
      Args.MakeArgString(getToolChain().GetProgramPath("llvm-link"));
143
0
  C.addCommand(std::make_unique<Command>(
144
0
      JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs,
145
0
      InputInfo(&JA, Args.MakeArgString(OutputFileName))));
146
0
  return OutputFileName;
147
0
}
148
149
const char *AMDGCN::OpenMPLinker::constructLlcCommand(
150
    Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
151
    const llvm::opt::ArgList &Args, llvm::StringRef SubArchName,
152
    llvm::StringRef OutputFilePrefix, const char *InputFileName,
153
0
    bool OutputIsAsm) const {
154
  // Construct llc command.
155
0
  ArgStringList LlcArgs;
156
  // The input to llc is the output from opt.
157
0
  LlcArgs.push_back(InputFileName);
158
  // Pass optimization arg to llc.
159
0
  addLLCOptArg(Args, LlcArgs);
160
0
  LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa");
161
0
  LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName));
162
0
  LlcArgs.push_back(
163
0
      Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj")));
164
165
0
  for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
166
0
    LlcArgs.push_back(A->getValue(0));
167
0
  }
168
169
  // Add output filename
170
0
  LlcArgs.push_back("-o");
171
0
  const char *LlcOutputFile =
172
0
      getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o");
173
0
  LlcArgs.push_back(LlcOutputFile);
174
0
  const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc"));
175
0
  C.addCommand(std::make_unique<Command>(
176
0
      JA, *this, ResponseFileSupport::AtFileCurCP(), Llc, LlcArgs, Inputs,
177
0
      InputInfo(&JA, Args.MakeArgString(LlcOutputFile))));
178
0
  return LlcOutputFile;
179
0
}
180
181
void AMDGCN::OpenMPLinker::constructLldCommand(
182
    Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
183
    const InputInfo &Output, const llvm::opt::ArgList &Args,
184
0
    const char *InputFileName) const {
185
  // Construct lld command.
186
  // The output from ld.lld is an HSA code object file.
187
0
  ArgStringList LldArgs{"-flavor",    "gnu", "--no-undefined",
188
0
                        "-shared",    "-o",  Output.getFilename(),
189
0
                        InputFileName};
190
191
0
  const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));
192
0
  C.addCommand(std::make_unique<Command>(
193
0
      JA, *this, ResponseFileSupport::AtFileCurCP(), Lld, LldArgs, Inputs,
194
0
      InputInfo(&JA, Args.MakeArgString(Output.getFilename()))));
195
0
}
196
197
// For amdgcn the inputs of the linker job are device bitcode and output is
198
// object file. It calls llvm-link, opt, llc, then lld steps.
199
void AMDGCN::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
200
                                        const InputInfo &Output,
201
                                        const InputInfoList &Inputs,
202
                                        const ArgList &Args,
203
0
                                        const char *LinkingOutput) const {
204
0
  const ToolChain &TC = getToolChain();
205
0
  assert(getToolChain().getTriple().isAMDGCN() && "Unsupported target");
206
207
0
  const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC =
208
0
      static_cast<const toolchains::AMDGPUOpenMPToolChain &>(TC);
209
210
0
  std::string GPUArch = Args.getLastArgValue(options::OPT_march_EQ).str();
211
0
  if (GPUArch.empty()) {
212
0
    if (!checkSystemForAMDGPU(Args, AMDGPUOpenMPTC, GPUArch))
213
0
      return;
214
0
  }
215
216
  // Prefix for temporary file name.
217
0
  std::string Prefix;
218
0
  for (const auto &II : Inputs)
219
0
    if (II.isFilename())
220
0
      Prefix = llvm::sys::path::stem(II.getFilename()).str() + "-" + GPUArch;
221
0
  assert(Prefix.length() && "no linker inputs are files ");
222
223
  // Each command outputs different files.
224
0
  const char *LLVMLinkCommand = constructLLVMLinkCommand(
225
0
      AMDGPUOpenMPTC, C, JA, Inputs, Args, GPUArch, Prefix);
226
227
  // Produce readable assembly if save-temps is enabled.
228
0
  if (C.getDriver().isSaveTempsEnabled())
229
0
    constructLlcCommand(C, JA, Inputs, Args, GPUArch, Prefix, LLVMLinkCommand,
230
0
                        /*OutputIsAsm=*/true);
231
0
  const char *LlcCommand = constructLlcCommand(C, JA, Inputs, Args, GPUArch,
232
0
                                               Prefix, LLVMLinkCommand);
233
0
  constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand);
234
0
}
235
236
AMDGPUOpenMPToolChain::AMDGPUOpenMPToolChain(const Driver &D,
237
                                             const llvm::Triple &Triple,
238
                                             const ToolChain &HostTC,
239
                                             const ArgList &Args)
240
0
    : ROCMToolChain(D, Triple, Args), HostTC(HostTC) {
241
  // Lookup binaries into the driver directory, this is used to
242
  // discover the clang-offload-bundler executable.
243
0
  getProgramPaths().push_back(getDriver().Dir);
244
0
}
245
246
void AMDGPUOpenMPToolChain::addClangTargetOptions(
247
    const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
248
0
    Action::OffloadKind DeviceOffloadingKind) const {
249
0
  HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
250
251
0
  std::string GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ).str();
252
0
  if (GPUArch.empty()) {
253
0
    if (!checkSystemForAMDGPU(DriverArgs, *this, GPUArch))
254
0
      return;
255
0
  }
256
257
0
  assert(DeviceOffloadingKind == Action::OFK_OpenMP &&
258
0
         "Only OpenMP offloading kinds are supported.");
259
260
0
  CC1Args.push_back("-target-cpu");
261
0
  CC1Args.push_back(DriverArgs.MakeArgStringRef(GPUArch));
262
0
  CC1Args.push_back("-fcuda-is-device");
263
264
0
  if (DriverArgs.hasArg(options::OPT_nogpulib))
265
0
    return;
266
267
0
  std::string BitcodeSuffix;
268
0
  if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime,
269
0
                         options::OPT_fno_openmp_target_new_runtime, true))
270
0
    BitcodeSuffix = "new-amdgpu-" + GPUArch;
271
0
  else
272
0
    BitcodeSuffix = "amdgcn-" + GPUArch;
273
274
0
  addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix,
275
0
                     getTriple());
276
0
}
277
278
llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
279
    const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
280
0
    Action::OffloadKind DeviceOffloadKind) const {
281
0
  DerivedArgList *DAL =
282
0
      HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
283
0
  if (!DAL)
284
0
    DAL = new DerivedArgList(Args.getBaseArgs());
285
286
0
  const OptTable &Opts = getDriver().getOpts();
287
288
0
  if (DeviceOffloadKind != Action::OFK_OpenMP) {
289
0
    for (Arg *A : Args) {
290
0
      DAL->append(A);
291
0
    }
292
0
  }
293
294
0
  if (!BoundArch.empty()) {
295
0
    DAL->eraseArg(options::OPT_march_EQ);
296
0
    DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
297
0
                      BoundArch);
298
0
  }
299
300
0
  return DAL;
301
0
}
302
303
0
Tool *AMDGPUOpenMPToolChain::buildLinker() const {
304
0
  assert(getTriple().isAMDGCN());
305
0
  return new tools::AMDGCN::OpenMPLinker(*this);
306
0
}
307
308
void AMDGPUOpenMPToolChain::addClangWarningOptions(
309
0
    ArgStringList &CC1Args) const {
310
0
  HostTC.addClangWarningOptions(CC1Args);
311
0
}
312
313
ToolChain::CXXStdlibType
314
0
AMDGPUOpenMPToolChain::GetCXXStdlibType(const ArgList &Args) const {
315
0
  return HostTC.GetCXXStdlibType(Args);
316
0
}
317
318
void AMDGPUOpenMPToolChain::AddClangSystemIncludeArgs(
319
0
    const ArgList &DriverArgs, ArgStringList &CC1Args) const {
320
0
  HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
321
0
}
322
323
void AMDGPUOpenMPToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
324
0
                                                ArgStringList &CC1Args) const {
325
0
  HostTC.AddIAMCUIncludeArgs(Args, CC1Args);
326
0
}
327
328
0
SanitizerMask AMDGPUOpenMPToolChain::getSupportedSanitizers() const {
329
  // The AMDGPUOpenMPToolChain only supports sanitizers in the sense that it
330
  // allows sanitizer arguments on the command line if they are supported by the
331
  // host toolchain. The AMDGPUOpenMPToolChain will actually ignore any command
332
  // line arguments for any of these "supported" sanitizers. That means that no
333
  // sanitization of device code is actually supported at this time.
334
  //
335
  // This behavior is necessary because the host and device toolchains
336
  // invocations often share the command line, so the device toolchain must
337
  // tolerate flags meant only for the host toolchain.
338
0
  return HostTC.getSupportedSanitizers();
339
0
}
340
341
VersionTuple
342
AMDGPUOpenMPToolChain::computeMSVCVersion(const Driver *D,
343
0
                                          const ArgList &Args) const {
344
0
  return HostTC.computeMSVCVersion(D, Args);
345
0
}