|
25 | 25 | #include "llvm/IR/Module.h" |
26 | 26 | #include "llvm/IR/Value.h" |
27 | 27 | #include "llvm/Object/COFFImportFile.h" |
| 28 | +#include "llvm/Object/OffloadBinary.h" |
28 | 29 | #include "llvm/Remarks/RemarkFormat.h" |
29 | 30 | #include "llvm/Remarks/RemarkSerializer.h" |
30 | 31 | #include "llvm/Remarks/RemarkStreamer.h" |
|
35 | 36 | #include "llvm/Support/Signals.h" |
36 | 37 | #include "llvm/Support/Timer.h" |
37 | 38 | #include "llvm/Support/ToolOutputFile.h" |
| 39 | +#include "llvm/Target/TargetMachine.h" |
38 | 40 | #include "llvm/Transforms/Utils/Cloning.h" |
39 | 41 | #include "llvm/Transforms/Utils/ValueMapper.h" |
40 | 42 | #include <iostream> |
@@ -144,6 +146,51 @@ extern "C" void LLVMRustPrintStatistics(RustStringRef OutBuf) { |
144 | 146 | llvm::PrintStatistics(OS); |
145 | 147 | } |
146 | 148 |
|
| 149 | +static Error writeFile(StringRef Filename, StringRef Data) { |
| 150 | + Expected<std::unique_ptr<FileOutputBuffer>> OutputOrErr = |
| 151 | + FileOutputBuffer::create(Filename, Data.size()); |
| 152 | + if (!OutputOrErr) |
| 153 | + return OutputOrErr.takeError(); |
| 154 | + std::unique_ptr<FileOutputBuffer> Output = std::move(*OutputOrErr); |
| 155 | + llvm::copy(Data, Output->getBufferStart()); |
| 156 | + if (Error E = Output->commit()) |
| 157 | + return E; |
| 158 | + return Error::success(); |
| 159 | +} |
| 160 | + |
| 161 | +// This is the first of many steps in creating a binary using llvm offload, |
| 162 | +// to run code on the gpu. Concrete, it replaces the following binary use: |
| 163 | +// clang-offload-packager -o host.out |
| 164 | +// --image=file=device.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp |
| 165 | +// The input module is the rust code compiled for a gpu target like amdgpu. |
| 166 | +// Based on clang/tools/clang-offload-packager/ClangOffloadPackager.cpp |
| 167 | +extern "C" bool LLVMRustBundleImages(LLVMModuleRef M, TargetMachine &TM) { |
| 168 | + std::string Storage; |
| 169 | + llvm::raw_string_ostream OS1(Storage); |
| 170 | + llvm::WriteBitcodeToFile(*unwrap(M), OS1); |
| 171 | + OS1.flush(); |
| 172 | + auto MB = llvm::MemoryBuffer::getMemBufferCopy(Storage, "module.bc"); |
| 173 | + |
| 174 | + SmallVector<char, 1024> BinaryData; |
| 175 | + raw_svector_ostream OS2(BinaryData); |
| 176 | + |
| 177 | + OffloadBinary::OffloadingImage ImageBinary{}; |
| 178 | + ImageBinary.TheImageKind = object::IMG_Bitcode; |
| 179 | + ImageBinary.Image = std::move(MB); |
| 180 | + ImageBinary.TheOffloadKind = object::OFK_OpenMP; |
| 181 | + ImageBinary.StringData["triple"] = TM.getTargetTriple().str(); |
| 182 | + ImageBinary.StringData["arch"] = TM.getTargetCPU(); |
| 183 | + llvm::SmallString<0> Buffer = OffloadBinary::write(ImageBinary); |
| 184 | + if (Buffer.size() % OffloadBinary::getAlignment() != 0) |
| 185 | + // Offload binary has invalid size alignment |
| 186 | + return false; |
| 187 | + OS2 << Buffer; |
| 188 | + if (Error E = writeFile("host.out", |
| 189 | + StringRef(BinaryData.begin(), BinaryData.size()))) |
| 190 | + return false; |
| 191 | + return true; |
| 192 | +} |
| 193 | + |
147 | 194 | extern "C" void LLVMRustOffloadMapper(LLVMValueRef OldFn, LLVMValueRef NewFn) { |
148 | 195 | llvm::Function *oldFn = llvm::unwrap<llvm::Function>(OldFn); |
149 | 196 | llvm::Function *newFn = llvm::unwrap<llvm::Function>(NewFn); |
|
0 commit comments