Coverage Report

Created: 2023-09-12 09:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Interpreter/DeviceOffload.cpp
Line
Count
Source (jump to first uncovered line)
1
//===---------- DeviceOffload.cpp - Device Offloading------------*- 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
// This file implements offloading to CUDA devices.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "DeviceOffload.h"
14
15
#include "clang/Basic/TargetOptions.h"
16
#include "clang/CodeGen/ModuleBuilder.h"
17
#include "clang/Frontend/CompilerInstance.h"
18
19
#include "llvm/IR/LegacyPassManager.h"
20
#include "llvm/MC/TargetRegistry.h"
21
#include "llvm/Target/TargetMachine.h"
22
23
namespace clang {
24
25
IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
26
    Interpreter &Interp, std::unique_ptr<CompilerInstance> Instance,
27
    IncrementalParser &HostParser, llvm::LLVMContext &LLVMCtx,
28
    llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS,
29
    llvm::Error &Err)
30
    : IncrementalParser(Interp, std::move(Instance), LLVMCtx, Err),
31
7
      HostParser(HostParser), VFS(FS) {
32
7
  if (Err)
33
0
    return;
34
7
  StringRef Arch = CI->getTargetOpts().CPU;
35
7
  if (!Arch.starts_with("sm_") || Arch.substr(3).getAsInteger(10, SMVersion)) {
36
0
    Err = llvm::joinErrors(std::move(Err), llvm::make_error<llvm::StringError>(
37
0
                                               "Invalid CUDA architecture",
38
0
                                               llvm::inconvertibleErrorCode()));
39
0
    return;
40
0
  }
41
7
}
42
43
llvm::Expected<PartialTranslationUnit &>
44
0
IncrementalCUDADeviceParser::Parse(llvm::StringRef Input) {
45
0
  auto PTU = IncrementalParser::Parse(Input);
46
0
  if (!PTU)
47
0
    return PTU.takeError();
48
49
0
  auto PTX = GeneratePTX();
50
0
  if (!PTX)
51
0
    return PTX.takeError();
52
53
0
  auto Err = GenerateFatbinary();
54
0
  if (Err)
55
0
    return std::move(Err);
56
57
0
  std::string FatbinFileName =
58
0
      "/incr_module_" + std::to_string(PTUs.size()) + ".fatbin";
59
0
  VFS->addFile(FatbinFileName, 0,
60
0
               llvm::MemoryBuffer::getMemBuffer(
61
0
                   llvm::StringRef(FatbinContent.data(), FatbinContent.size()),
62
0
                   "", false));
63
64
0
  HostParser.getCI()->getCodeGenOpts().CudaGpuBinaryFileName = FatbinFileName;
65
66
0
  FatbinContent.clear();
67
68
0
  return PTU;
69
0
}
70
71
0
llvm::Expected<llvm::StringRef> IncrementalCUDADeviceParser::GeneratePTX() {
72
0
  auto &PTU = PTUs.back();
73
0
  std::string Error;
74
75
0
  const llvm::Target *Target = llvm::TargetRegistry::lookupTarget(
76
0
      PTU.TheModule->getTargetTriple(), Error);
77
0
  if (!Target)
78
0
    return llvm::make_error<llvm::StringError>(std::move(Error),
79
0
                                               std::error_code());
80
0
  llvm::TargetOptions TO = llvm::TargetOptions();
81
0
  llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
82
0
      PTU.TheModule->getTargetTriple(), getCI()->getTargetOpts().CPU, "", TO,
83
0
      llvm::Reloc::Model::PIC_);
84
0
  PTU.TheModule->setDataLayout(TargetMachine->createDataLayout());
85
86
0
  PTXCode.clear();
87
0
  llvm::raw_svector_ostream dest(PTXCode);
88
89
0
  llvm::legacy::PassManager PM;
90
0
  if (TargetMachine->addPassesToEmitFile(PM, dest, nullptr,
91
0
                                         llvm::CGFT_AssemblyFile)) {
92
0
    return llvm::make_error<llvm::StringError>(
93
0
        "NVPTX backend cannot produce PTX code.",
94
0
        llvm::inconvertibleErrorCode());
95
0
  }
96
97
0
  if (!PM.run(*PTU.TheModule))
98
0
    return llvm::make_error<llvm::StringError>("Failed to emit PTX code.",
99
0
                                               llvm::inconvertibleErrorCode());
100
101
0
  PTXCode += '\0';
102
0
  while (PTXCode.size() % 8)
103
0
    PTXCode += '\0';
104
0
  return PTXCode.str();
105
0
}
106
107
0
llvm::Error IncrementalCUDADeviceParser::GenerateFatbinary() {
108
0
  enum FatBinFlags {
109
0
    AddressSize64 = 0x01,
110
0
    HasDebugInfo = 0x02,
111
0
    ProducerCuda = 0x04,
112
0
    HostLinux = 0x10,
113
0
    HostMac = 0x20,
114
0
    HostWindows = 0x40
115
0
  };
116
117
0
  struct FatBinInnerHeader {
118
0
    uint16_t Kind;             // 0x00
119
0
    uint16_t unknown02;        // 0x02
120
0
    uint32_t HeaderSize;       // 0x04
121
0
    uint32_t DataSize;         // 0x08
122
0
    uint32_t unknown0c;        // 0x0c
123
0
    uint32_t CompressedSize;   // 0x10
124
0
    uint32_t SubHeaderSize;    // 0x14
125
0
    uint16_t VersionMinor;     // 0x18
126
0
    uint16_t VersionMajor;     // 0x1a
127
0
    uint32_t CudaArch;         // 0x1c
128
0
    uint32_t unknown20;        // 0x20
129
0
    uint32_t unknown24;        // 0x24
130
0
    uint32_t Flags;            // 0x28
131
0
    uint32_t unknown2c;        // 0x2c
132
0
    uint32_t unknown30;        // 0x30
133
0
    uint32_t unknown34;        // 0x34
134
0
    uint32_t UncompressedSize; // 0x38
135
0
    uint32_t unknown3c;        // 0x3c
136
0
    uint32_t unknown40;        // 0x40
137
0
    uint32_t unknown44;        // 0x44
138
0
    FatBinInnerHeader(uint32_t DataSize, uint32_t CudaArch, uint32_t Flags)
139
0
        : Kind(1 /*PTX*/), unknown02(0x0101), HeaderSize(sizeof(*this)),
140
0
          DataSize(DataSize), unknown0c(0), CompressedSize(0),
141
0
          SubHeaderSize(HeaderSize - 8), VersionMinor(2), VersionMajor(4),
142
0
          CudaArch(CudaArch), unknown20(0), unknown24(0), Flags(Flags),
143
0
          unknown2c(0), unknown30(0), unknown34(0), UncompressedSize(0),
144
0
          unknown3c(0), unknown40(0), unknown44(0) {}
145
0
  };
146
147
0
  struct FatBinHeader {
148
0
    uint32_t Magic;      // 0x00
149
0
    uint16_t Version;    // 0x04
150
0
    uint16_t HeaderSize; // 0x06
151
0
    uint32_t DataSize;   // 0x08
152
0
    uint32_t unknown0c;  // 0x0c
153
0
  public:
154
0
    FatBinHeader(uint32_t DataSize)
155
0
        : Magic(0xba55ed50), Version(1), HeaderSize(sizeof(*this)),
156
0
          DataSize(DataSize), unknown0c(0) {}
157
0
  };
158
159
0
  FatBinHeader OuterHeader(sizeof(FatBinInnerHeader) + PTXCode.size());
160
0
  FatbinContent.append((char *)&OuterHeader,
161
0
                       ((char *)&OuterHeader) + OuterHeader.HeaderSize);
162
163
0
  FatBinInnerHeader InnerHeader(PTXCode.size(), SMVersion,
164
0
                                FatBinFlags::AddressSize64 |
165
0
                                    FatBinFlags::HostLinux);
166
0
  FatbinContent.append((char *)&InnerHeader,
167
0
                       ((char *)&InnerHeader) + InnerHeader.HeaderSize);
168
169
0
  FatbinContent.append(PTXCode.begin(), PTXCode.end());
170
171
0
  return llvm::Error::success();
172
0
}
173
174
0
IncrementalCUDADeviceParser::~IncrementalCUDADeviceParser() {}
175
176
} // namespace clang