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
21
22#include "llvm/IR/LegacyPassManager.h"
23#include "llvm/IR/Module.h"
24#include "llvm/MC/TargetRegistry.h"
25#include "llvm/Target/TargetMachine.h"
26#include "llvm/TargetParser/Triple.h"
27
28namespace clang {
29
31 CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
32 IncrementalAction *DeviceAct,
34 llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs)
35 : IncrementalParser(DeviceInstance, DeviceAct, Err, PTUs), VFS(FS),
36 CodeGenOpts(HostInstance.getCodeGenOpts()),
37 TargetOpts(DeviceInstance.getTargetOpts()) {}
38
40
42 CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
43 IncrementalAction *DeviceAct,
45 llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs)
46 : IncrementalDeviceParser(DeviceInstance, HostInstance, DeviceAct, FS, Err,
47 PTUs),
48 DeviceCI(DeviceInstance) {
49 if (Err)
50 return;
51 if (!llvm::Triple(TargetOpts.Triple).isAMDGCN()) {
52 Err = llvm::joinErrors(
53 std::move(Err),
54 llvm::make_error<llvm::StringError>(
55 "Invalid HIP architecture for target '" + TargetOpts.Triple + "'",
56 llvm::inconvertibleErrorCode()));
57 return;
58 }
59}
60
62IncrementalHIPDeviceParser::GenerateDeviceObject() {
63 auto &PTU = PTUs.back();
64
65 CodeGenOptions CodeGenOptsForObj = DeviceCI.getCodeGenOpts();
66 CodeGenOptsForObj.DisableLLVMPasses = true;
67
68 ObjectContent.clear();
69 auto ObjOS = std::make_unique<llvm::raw_svector_ostream>(ObjectContent);
70 emitBackendOutput(DeviceCI, CodeGenOptsForObj, PTU.TheModule.get(),
72 std::move(ObjOS));
73
74 if (DeviceCI.getDiagnostics().hasErrorOccurred())
75 return llvm::make_error<llvm::StringError>(
76 "Backend code generation failed for HIP device code.",
77 llvm::inconvertibleErrorCode());
78
79 return llvm::StringRef(ObjectContent.data(), ObjectContent.size());
80}
81
83 llvm::Expected<llvm::StringRef> Object = GenerateDeviceObject();
84 if (!Object)
85 return Object.takeError();
86
87 // FIXME: Link the object into an HSACO and bundle it for the host
88 // compilation.
89 return llvm::make_error<llvm::StringError>(
90 "HIP offload binary generation is not supported yet.",
91 llvm::inconvertibleErrorCode());
92}
93
95
97 CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
98 IncrementalAction *DeviceAct,
100 llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs)
101 : IncrementalDeviceParser(DeviceInstance, HostInstance, DeviceAct, FS, Err,
102 PTUs) {
103 if (Err)
104 return;
105 StringRef Arch = TargetOpts.CPU;
106 if (!Arch.starts_with("sm_") || Arch.substr(3).getAsInteger(10, SMVersion)) {
107 Err = llvm::joinErrors(std::move(Err), llvm::make_error<llvm::StringError>(
108 "Invalid CUDA architecture",
109 llvm::inconvertibleErrorCode()));
110 return;
111 }
112}
113
114llvm::Expected<llvm::StringRef> IncrementalCUDADeviceParser::GeneratePTX() {
115 auto &PTU = PTUs.back();
116 std::string Error;
117
118 const llvm::Target *Target = llvm::TargetRegistry::lookupTarget(
119 PTU.TheModule->getTargetTriple(), Error);
120 if (!Target)
121 return llvm::make_error<llvm::StringError>(std::move(Error),
122 std::error_code());
123 llvm::TargetOptions TO = llvm::TargetOptions();
124 std::unique_ptr<llvm::TargetMachine> TM(Target->createTargetMachine(
125 PTU.TheModule->getTargetTriple(), TargetOpts.CPU, "", TO,
126 llvm::Reloc::Model::PIC_));
127
128 PTXCode.clear();
129 llvm::raw_svector_ostream dest(PTXCode);
130
131 llvm::legacy::PassManager PM;
132 if (TM->addPassesToEmitFile(PM, dest, nullptr,
133 llvm::CodeGenFileType::AssemblyFile)) {
134 return llvm::make_error<llvm::StringError>(
135 "NVPTX backend cannot produce PTX code.",
136 llvm::inconvertibleErrorCode());
137 }
138
139 PM.run(*PTU.TheModule);
140
141 PTXCode += '\0';
142 while (PTXCode.size() % 8)
143 PTXCode += '\0';
144 return PTXCode.str();
145}
146
147llvm::Error IncrementalCUDADeviceParser::GenerateFatbinary() {
148 enum FatBinFlags {
149 AddressSize64 = 0x01,
150 HasDebugInfo = 0x02,
151 ProducerCuda = 0x04,
152 HostLinux = 0x10,
153 HostMac = 0x20,
154 HostWindows = 0x40
155 };
156
157 struct FatBinInnerHeader {
158 uint16_t Kind; // 0x00
159 uint16_t unknown02; // 0x02
160 uint32_t HeaderSize; // 0x04
161 uint32_t DataSize; // 0x08
162 uint32_t unknown0c; // 0x0c
163 uint32_t CompressedSize; // 0x10
164 uint32_t SubHeaderSize; // 0x14
165 uint16_t VersionMinor; // 0x18
166 uint16_t VersionMajor; // 0x1a
167 uint32_t CudaArch; // 0x1c
168 uint32_t unknown20; // 0x20
169 uint32_t unknown24; // 0x24
170 uint32_t Flags; // 0x28
171 uint32_t unknown2c; // 0x2c
172 uint32_t unknown30; // 0x30
173 uint32_t unknown34; // 0x34
174 uint32_t UncompressedSize; // 0x38
175 uint32_t unknown3c; // 0x3c
176 uint32_t unknown40; // 0x40
177 uint32_t unknown44; // 0x44
178 FatBinInnerHeader(uint32_t DataSize, uint32_t CudaArch, uint32_t Flags)
179 : Kind(1 /*PTX*/), unknown02(0x0101), HeaderSize(sizeof(*this)),
180 DataSize(DataSize), unknown0c(0), CompressedSize(0),
181 SubHeaderSize(HeaderSize - 8), VersionMinor(2), VersionMajor(4),
182 CudaArch(CudaArch), unknown20(0), unknown24(0), Flags(Flags),
183 unknown2c(0), unknown30(0), unknown34(0), UncompressedSize(0),
184 unknown3c(0), unknown40(0), unknown44(0) {}
185 };
186
187 struct FatBinHeader {
188 uint32_t Magic; // 0x00
189 uint16_t Version; // 0x04
190 uint16_t HeaderSize; // 0x06
191 uint32_t DataSize; // 0x08
192 uint32_t unknown0c; // 0x0c
193 public:
194 FatBinHeader(uint32_t DataSize)
195 : Magic(0xba55ed50), Version(1), HeaderSize(sizeof(*this)),
196 DataSize(DataSize), unknown0c(0) {}
197 };
198
199 FatBinHeader OuterHeader(sizeof(FatBinInnerHeader) + PTXCode.size());
200 FatbinContent.append((char *)&OuterHeader,
201 ((char *)&OuterHeader) + OuterHeader.HeaderSize);
202
203 FatBinInnerHeader InnerHeader(PTXCode.size(), SMVersion,
204 FatBinFlags::AddressSize64 |
205 FatBinFlags::HostLinux);
206 FatbinContent.append((char *)&InnerHeader,
207 ((char *)&InnerHeader) + InnerHeader.HeaderSize);
208
209 FatbinContent.append(PTXCode.begin(), PTXCode.end());
210
211 const PartialTranslationUnit &PTU = PTUs.back();
212
213 std::string FatbinFileName = "/" + PTU.TheModule->getName().str() + ".fatbin";
214
215 VFS->addFile(FatbinFileName, 0,
216 llvm::MemoryBuffer::getMemBuffer(
217 llvm::StringRef(FatbinContent.data(), FatbinContent.size()),
218 "", false));
219
220 CodeGenOpts.OffloadBinaryToEmbedFile = std::move(FatbinFileName);
221
222 FatbinContent.clear();
223
224 return llvm::Error::success();
225}
226
228 llvm::Expected<llvm::StringRef> PTX = GeneratePTX();
229 if (!PTX)
230 return PTX.takeError();
231
232 return GenerateFatbinary();
233}
234
236
237} // namespace clang
llvm::json::Object Object
Defines the clang::TargetOptions class.
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
IntrusiveRefCntPtr< llvm::vfs::FileSystem > getVirtualFileSystemPtr() const
CodeGenOptions & getCodeGenOpts()
bool hasErrorOccurred() const
Definition Diagnostic.h:913
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
IncrementalHIPDeviceParser(CompilerInstance &DeviceInstance, CompilerInstance &HostInstance, IncrementalAction *DeviceAct, llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > VFS, llvm::Error &Err, std::list< PartialTranslationUnit > &PTUs)
llvm::Error GenerateOffloadBinary() override
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.
void emitBackendOutput(CompilerInstance &CI, CodeGenOptions &CGOpts, llvm::Module *M, BackendAction Action, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, std::unique_ptr< raw_pwrite_stream > OS, BackendConsumer *BC=nullptr)
@ Backend_EmitObj
Emit native object files.
Definition BackendUtil.h:37
__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 __builtin_riscv_mhacc_i32 __builtin_riscv_mhaccu_u32 __builtin_riscv_mhaccsu_i32 __builtin_riscv_mulq_i32 __builtin_riscv_mqwacc_i64 __packed_splat4 uint16_t