clang 24.0.0git
DeviceOffload.cpp
Go to the documentation of this file.
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
10// This file implements offloading to devices.
11//
12//===----------------------------------------------------------------------===//
13
14#include "DeviceOffload.h"
15
20
21#include "llvm/IR/LegacyPassManager.h"
22#include "llvm/IR/Module.h"
23#include "llvm/MC/TargetRegistry.h"
24#include "llvm/Target/TargetMachine.h"
25
26namespace clang {
27
29 CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
30 IncrementalAction *DeviceAct,
32 llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs)
33 : IncrementalParser(DeviceInstance, DeviceAct, Err, PTUs), VFS(FS),
34 CodeGenOpts(HostInstance.getCodeGenOpts()),
35 TargetOpts(DeviceInstance.getTargetOpts()) {}
36
38
40 CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
41 IncrementalAction *DeviceAct,
43 llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs)
44 : IncrementalDeviceParser(DeviceInstance, HostInstance, DeviceAct, FS, Err,
45 PTUs) {
46 if (Err)
47 return;
48 StringRef Arch = TargetOpts.CPU;
49 if (!Arch.starts_with("sm_") || Arch.substr(3).getAsInteger(10, SMVersion)) {
50 Err = llvm::joinErrors(std::move(Err), llvm::make_error<llvm::StringError>(
51 "Invalid CUDA architecture",
52 llvm::inconvertibleErrorCode()));
53 return;
54 }
55}
56
57llvm::Expected<llvm::StringRef> IncrementalCUDADeviceParser::GeneratePTX() {
58 auto &PTU = PTUs.back();
59 std::string Error;
60
61 const llvm::Target *Target = llvm::TargetRegistry::lookupTarget(
62 PTU.TheModule->getTargetTriple(), Error);
63 if (!Target)
64 return llvm::make_error<llvm::StringError>(std::move(Error),
65 std::error_code());
66 llvm::TargetOptions TO = llvm::TargetOptions();
67 std::unique_ptr<llvm::TargetMachine> TM(Target->createTargetMachine(
68 PTU.TheModule->getTargetTriple(), TargetOpts.CPU, "", TO,
69 llvm::Reloc::Model::PIC_));
70
71 PTXCode.clear();
72 llvm::raw_svector_ostream dest(PTXCode);
73
74 llvm::legacy::PassManager PM;
75 if (TM->addPassesToEmitFile(PM, dest, nullptr,
76 llvm::CodeGenFileType::AssemblyFile)) {
77 return llvm::make_error<llvm::StringError>(
78 "NVPTX backend cannot produce PTX code.",
79 llvm::inconvertibleErrorCode());
80 }
81
82 PM.run(*PTU.TheModule);
83
84 PTXCode += '\0';
85 while (PTXCode.size() % 8)
86 PTXCode += '\0';
87 return PTXCode.str();
88}
89
90llvm::Error IncrementalCUDADeviceParser::GenerateFatbinary() {
91 enum FatBinFlags {
92 AddressSize64 = 0x01,
93 HasDebugInfo = 0x02,
94 ProducerCuda = 0x04,
95 HostLinux = 0x10,
96 HostMac = 0x20,
97 HostWindows = 0x40
98 };
99
100 struct FatBinInnerHeader {
101 uint16_t Kind; // 0x00
102 uint16_t unknown02; // 0x02
103 uint32_t HeaderSize; // 0x04
104 uint32_t DataSize; // 0x08
105 uint32_t unknown0c; // 0x0c
106 uint32_t CompressedSize; // 0x10
107 uint32_t SubHeaderSize; // 0x14
108 uint16_t VersionMinor; // 0x18
109 uint16_t VersionMajor; // 0x1a
110 uint32_t CudaArch; // 0x1c
111 uint32_t unknown20; // 0x20
112 uint32_t unknown24; // 0x24
113 uint32_t Flags; // 0x28
114 uint32_t unknown2c; // 0x2c
115 uint32_t unknown30; // 0x30
116 uint32_t unknown34; // 0x34
117 uint32_t UncompressedSize; // 0x38
118 uint32_t unknown3c; // 0x3c
119 uint32_t unknown40; // 0x40
120 uint32_t unknown44; // 0x44
121 FatBinInnerHeader(uint32_t DataSize, uint32_t CudaArch, uint32_t Flags)
122 : Kind(1 /*PTX*/), unknown02(0x0101), HeaderSize(sizeof(*this)),
123 DataSize(DataSize), unknown0c(0), CompressedSize(0),
124 SubHeaderSize(HeaderSize - 8), VersionMinor(2), VersionMajor(4),
125 CudaArch(CudaArch), unknown20(0), unknown24(0), Flags(Flags),
126 unknown2c(0), unknown30(0), unknown34(0), UncompressedSize(0),
127 unknown3c(0), unknown40(0), unknown44(0) {}
128 };
129
130 struct FatBinHeader {
131 uint32_t Magic; // 0x00
132 uint16_t Version; // 0x04
133 uint16_t HeaderSize; // 0x06
134 uint32_t DataSize; // 0x08
135 uint32_t unknown0c; // 0x0c
136 public:
137 FatBinHeader(uint32_t DataSize)
138 : Magic(0xba55ed50), Version(1), HeaderSize(sizeof(*this)),
139 DataSize(DataSize), unknown0c(0) {}
140 };
141
142 FatBinHeader OuterHeader(sizeof(FatBinInnerHeader) + PTXCode.size());
143 FatbinContent.append((char *)&OuterHeader,
144 ((char *)&OuterHeader) + OuterHeader.HeaderSize);
145
146 FatBinInnerHeader InnerHeader(PTXCode.size(), SMVersion,
147 FatBinFlags::AddressSize64 |
148 FatBinFlags::HostLinux);
149 FatbinContent.append((char *)&InnerHeader,
150 ((char *)&InnerHeader) + InnerHeader.HeaderSize);
151
152 FatbinContent.append(PTXCode.begin(), PTXCode.end());
153
154 const PartialTranslationUnit &PTU = PTUs.back();
155
156 std::string FatbinFileName = "/" + PTU.TheModule->getName().str() + ".fatbin";
157
158 VFS->addFile(FatbinFileName, 0,
159 llvm::MemoryBuffer::getMemBuffer(
160 llvm::StringRef(FatbinContent.data(), FatbinContent.size()),
161 "", false));
162
163 CodeGenOpts.OffloadBinaryToEmbedFile = std::move(FatbinFileName);
164
165 FatbinContent.clear();
166
167 return llvm::Error::success();
168}
169
171 llvm::Expected<llvm::StringRef> PTX = GeneratePTX();
172 if (!PTX)
173 return PTX.takeError();
174
175 return GenerateFatbinary();
176}
177
179
180} // namespace clang
Defines the clang::TargetOptions class.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
A custom action enabling the incremental processing functionality.
IncrementalCUDADeviceParser(CompilerInstance &DeviceInstance, CompilerInstance &HostInstance, IncrementalAction *DeviceAct, llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > VFS, llvm::Error &Err, std::list< PartialTranslationUnit > &PTUs)
llvm::Error GenerateOffloadBinary() override
IncrementalDeviceParser(CompilerInstance &DeviceInstance, CompilerInstance &HostInstance, IncrementalAction *DeviceAct, llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > VFS, llvm::Error &Err, std::list< PartialTranslationUnit > &PTUs)
llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > VFS
const TargetOptions & TargetOpts
IncrementalParser(CompilerInstance &Instance, IncrementalAction *Act, llvm::Error &Err, std::list< PartialTranslationUnit > &PTUs)
std::list< PartialTranslationUnit > & PTUs
std::string CPU
If given, the name of the target CPU to generate code for.
Top level wrappers for InstallAPI frontend operations.
__builtin_bitreverse32 uint32_t __builtin_riscv_aaddu_u32 __builtin_riscv_asubu_u32 __builtin_elementwise_add_sat __builtin_elementwise_sub_sat int32_t uint32_t uint32_t __packed_splat4 uint16_t