Coverage Report

Created: 2021-09-21 08:58

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/clang-nvlink-wrapper/ClangNvlinkWrapper.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- clang-nvlink-wrapper/ClangNvlinkWrapper.cpp - wrapper over nvlink-===//
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
/// \file
10
/// This tool works as a wrapper over nvlink program. It transparently passes
11
/// every input option and objects to nvlink except archive files. It reads
12
/// each input archive file to extract archived cubin files as temporary files.
13
/// These temp (*.cubin) files are passed to nvlink, because nvlink does not
14
/// support linking of archive files implicitly.
15
///
16
/// During linking of heterogeneous device archive libraries, the
17
/// clang-offload-bundler creates a device specific archive of cubin files.
18
/// Such an archive is then passed to this tool to extract cubin files before
19
/// passing to nvlink.
20
///
21
/// Example:
22
/// clang-nvlink-wrapper -o a.out-openmp-nvptx64 /tmp/libTest-nvptx-sm_50.a
23
///
24
/// 1. Extract (libTest-nvptx-sm_50.a) => /tmp/a.cubin /tmp/b.cubin
25
/// 2. nvlink -o a.out-openmp-nvptx64 /tmp/a.cubin /tmp/b.cubin
26
//===---------------------------------------------------------------------===//
27
28
#include "llvm/Object/Archive.h"
29
#include "llvm/Support/CommandLine.h"
30
#include "llvm/Support/Errc.h"
31
#include "llvm/Support/FileSystem.h"
32
#include "llvm/Support/MemoryBuffer.h"
33
#include "llvm/Support/Path.h"
34
#include "llvm/Support/Program.h"
35
#include "llvm/Support/Signals.h"
36
#include "llvm/Support/StringSaver.h"
37
#include "llvm/Support/WithColor.h"
38
#include "llvm/Support/raw_ostream.h"
39
40
using namespace llvm;
41
42
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
43
44
static Error runNVLink(std::string NVLinkPath,
45
0
                       SmallVectorImpl<std::string> &Args) {
46
0
  std::vector<StringRef> NVLArgs;
47
0
  NVLArgs.push_back(NVLinkPath);
48
0
  for (auto &Arg : Args) {
49
0
    NVLArgs.push_back(Arg);
50
0
  }
51
52
0
  if (sys::ExecuteAndWait(NVLinkPath.c_str(), NVLArgs))
53
0
    return createStringError(inconvertibleErrorCode(), "'nvlink' failed");
54
0
  return Error::success();
55
0
}
56
57
static Error extractArchiveFiles(StringRef Filename,
58
                                 SmallVectorImpl<std::string> &Args,
59
0
                                 SmallVectorImpl<std::string> &TmpFiles) {
60
0
  std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
61
62
0
  ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
63
0
      MemoryBuffer::getFileOrSTDIN(Filename, false, false);
64
0
  if (std::error_code EC = BufOrErr.getError())
65
0
    return createFileError(Filename, EC);
66
67
0
  ArchiveBuffers.push_back(std::move(*BufOrErr));
68
0
  Expected<std::unique_ptr<llvm::object::Archive>> LibOrErr =
69
0
      object::Archive::create(ArchiveBuffers.back()->getMemBufferRef());
70
0
  if (!LibOrErr)
71
0
    return LibOrErr.takeError();
72
73
0
  auto Archive = std::move(*LibOrErr);
74
75
0
  Error Err = Error::success();
76
0
  auto ChildEnd = Archive->child_end();
77
0
  for (auto ChildIter = Archive->child_begin(Err); ChildIter != ChildEnd;
78
0
       ++ChildIter) {
79
0
    if (Err)
80
0
      return Err;
81
0
    auto ChildNameOrErr = (*ChildIter).getName();
82
0
    if (!ChildNameOrErr)
83
0
      return ChildNameOrErr.takeError();
84
85
0
    StringRef ChildName = sys::path::filename(ChildNameOrErr.get());
86
87
0
    auto ChildBufferRefOrErr = (*ChildIter).getMemoryBufferRef();
88
0
    if (!ChildBufferRefOrErr)
89
0
      return ChildBufferRefOrErr.takeError();
90
91
0
    auto ChildBuffer =
92
0
        MemoryBuffer::getMemBuffer(ChildBufferRefOrErr.get(), false);
93
0
    auto ChildNameSplit = ChildName.split('.');
94
95
0
    SmallString<16> Path;
96
0
    int FileDesc;
97
0
    if (std::error_code EC = sys::fs::createTemporaryFile(
98
0
            (ChildNameSplit.first), (ChildNameSplit.second), FileDesc, Path))
99
0
      return createFileError(ChildName, EC);
100
101
0
    std::string TmpFileName(Path.str());
102
0
    Args.push_back(TmpFileName);
103
0
    TmpFiles.push_back(TmpFileName);
104
0
    std::error_code EC;
105
0
    raw_fd_ostream OS(Path.c_str(), EC, sys::fs::OF_None);
106
0
    if (EC)
107
0
      return createFileError(TmpFileName, errc::io_error);
108
0
    OS << ChildBuffer->getBuffer();
109
0
    OS.close();
110
0
  }
111
0
  return Err;
112
0
}
113
114
0
static Error cleanupTmpFiles(SmallVectorImpl<std::string> &TmpFiles) {
115
0
  for (auto &TmpFile : TmpFiles) {
116
0
    if (std::error_code EC = sys::fs::remove(TmpFile))
117
0
      return createFileError(TmpFile, errc::no_such_file_or_directory);
118
0
  }
119
0
  return Error::success();
120
0
}
121
122
int main(int argc, const char **argv) {
123
  sys::PrintStackTraceOnErrorSignal(argv[0]);
124
125
  if (Help) {
126
    cl::PrintHelpMessage();
127
    return 0;
128
  }
129
130
0
  auto reportError = [argv](Error E) {
131
0
    logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
132
0
    exit(1);
133
0
  };
134
135
  ErrorOr<std::string> NvlinkPath = sys::findProgramByName("nvlink");
136
  if (!NvlinkPath) {
137
    reportError(createStringError(NvlinkPath.getError(),
138
                                  "unable to find 'nvlink' in path"));
139
  }
140
141
  SmallVector<const char *, 0> Argv(argv, argv + argc);
142
  SmallVector<std::string, 0> ArgvSubst;
143
  SmallVector<std::string, 0> TmpFiles;
144
  BumpPtrAllocator Alloc;
145
  StringSaver Saver(Alloc);
146
  cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);
147
148
  for (size_t i = 1; i < Argv.size(); ++i) {
149
    std::string Arg = Argv[i];
150
    if (sys::path::extension(Arg) == ".a") {
151
      if (Error Err = extractArchiveFiles(Arg, ArgvSubst, TmpFiles))
152
        reportError(std::move(Err));
153
    } else {
154
      ArgvSubst.push_back(Arg);
155
    }
156
  }
157
158
  if (Error Err = runNVLink(NvlinkPath.get(), ArgvSubst))
159
    reportError(std::move(Err));
160
  if (Error Err = cleanupTmpFiles(TmpFiles))
161
    reportError(std::move(Err));
162
163
  return 0;
164
}