3939#include " llvm/Transforms/Utils/ValueMapper.h"
4040#include < iostream>
4141
42+ // Some of the functions below rely on LLVM modules that may not always be
43+ // available. As such, we only try to build it in the first place, if
44+ // llvm.offload is enabled.
45+ #ifdef OFFLOAD
46+ #include " llvm/Object/OffloadBinary.h"
47+ #include " llvm/Target/TargetMachine.h"
48+ #endif
49+
4250// for raw `write` in the bad-alloc handler
4351#ifdef _MSC_VER
4452#include < io.h>
@@ -144,6 +152,55 @@ extern "C" void LLVMRustPrintStatistics(RustStringRef OutBuf) {
144152 llvm::PrintStatistics (OS);
145153}
146154
155+ // Some of the functions here rely on LLVM modules that may not always be
156+ // available. As such, we only try to build it in the first place, if
157+ // llvm.offload is enabled.
158+ #ifdef OFFLOAD
159+ static Error writeFile (StringRef Filename, StringRef Data) {
160+ Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr =
161+ FileOutputBuffer::create (Filename, Data.size ());
162+ if (!OutputOrErr)
163+ return OutputOrErr.takeError ();
164+ std::unique_ptr<FileOutputBuffer> Output = std::move (*OutputOrErr);
165+ llvm::copy (Data, Output->getBufferStart ());
166+ if (Error E = Output->commit ())
167+ return E;
168+ return Error::success ();
169+ }
170+
171+ // This is the first of many steps in creating a binary using llvm offload,
172+ // to run code on the gpu. Concrete, it replaces the following binary use:
173+ // clang-offload-packager -o host.out
174+ // --image=file=device.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp
175+ // The input module is the rust code compiled for a gpu target like amdgpu.
176+ // Based on clang/tools/clang-offload-packager/ClangOffloadPackager.cpp
177+ extern " C" bool LLVMRustBundleImages (LLVMModuleRef M, TargetMachine &TM) {
178+ std::string Storage;
179+ llvm::raw_string_ostream OS1 (Storage);
180+ llvm::WriteBitcodeToFile (*unwrap (M), OS1);
181+ OS1.flush ();
182+ auto MB = llvm::MemoryBuffer::getMemBufferCopy (Storage, " module.bc" );
183+
184+ SmallVector<char , 1024 > BinaryData;
185+ raw_svector_ostream OS2 (BinaryData);
186+
187+ OffloadBinary::OffloadingImage ImageBinary{};
188+ ImageBinary.TheImageKind = object::IMG_Bitcode;
189+ ImageBinary.Image = std::move (MB);
190+ ImageBinary.TheOffloadKind = object::OFK_OpenMP;
191+ ImageBinary.StringData [" triple" ] = TM.getTargetTriple ().str ();
192+ ImageBinary.StringData [" arch" ] = TM.getTargetCPU ();
193+ llvm::SmallString<0 > Buffer = OffloadBinary::write (ImageBinary);
194+ if (Buffer.size () % OffloadBinary::getAlignment () != 0 )
195+ // Offload binary has invalid size alignment
196+ return false ;
197+ OS2 << Buffer;
198+ if (Error E = writeFile (" host.out" ,
199+ StringRef (BinaryData.begin (), BinaryData.size ())))
200+ return false ;
201+ return true ;
202+ }
203+
147204extern " C" void LLVMRustOffloadMapper (LLVMValueRef OldFn, LLVMValueRef NewFn) {
148205 llvm::Function *oldFn = llvm::unwrap<llvm::Function>(OldFn);
149206 llvm::Function *newFn = llvm::unwrap<llvm::Function>(NewFn);
@@ -163,6 +220,7 @@ extern "C" void LLVMRustOffloadMapper(LLVMValueRef OldFn, LLVMValueRef NewFn) {
163220 llvm::CloneFunctionChangeType::LocalChangesOnly,
164221 returns);
165222}
223+ #endif
166224
167225extern " C" LLVMValueRef LLVMRustGetNamedValue (LLVMModuleRef M, const char *Name,
168226 size_t NameLen) {
0 commit comments