From 89d50591c06f084b80a5ce527781e07f8dc32be6 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Fri, 21 Nov 2025 00:14:03 -0800 Subject: [PATCH] Replace the first of 4 binary invocations for offload --- compiler/rustc_codegen_llvm/src/back/write.rs | 7 +++ compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3 ++ .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 47 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index fde7dd6ef7a8..78b11c458d5a 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -765,6 +765,13 @@ pub(crate) unsafe fn llvm_optimize( llvm_plugins.len(), ) }; + + if cgcx.target_is_like_gpu && config.offload.contains(&config::Offload::Enable) { + unsafe { + llvm::LLVMRustBundleImages(module.module_llvm.llmod(), module.module_llvm.tm.raw()); + } + } + result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::RunLlvmPasses)) } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index ca64d96c2a33..34f0e4b95338 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1641,6 +1641,9 @@ unsafe extern "C" { Name: *const c_char, ) -> &'a Value; + /// Processes the module and writes it in an offload compatible way into a "host.out" file. + pub(crate) fn LLVMRustBundleImages<'a>(M: &'a Module, TM: &'a TargetMachine) -> bool; + /// Writes a module to the specified path. Returns 0 on success. pub(crate) fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 8823c8392282..ba17aef92d0d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/Value.h" #include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/OffloadBinary.h" #include "llvm/Remarks/RemarkFormat.h" #include "llvm/Remarks/RemarkSerializer.h" #include "llvm/Remarks/RemarkStreamer.h" @@ -35,6 +36,7 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/ValueMapper.h" #include @@ -144,6 +146,51 @@ extern "C" void LLVMRustPrintStatistics(RustStringRef OutBuf) { llvm::PrintStatistics(OS); } +static Error writeFile(StringRef Filename, StringRef Data) { + Expected> OutputOrErr = + FileOutputBuffer::create(Filename, Data.size()); + if (!OutputOrErr) + return OutputOrErr.takeError(); + std::unique_ptr Output = std::move(*OutputOrErr); + llvm::copy(Data, Output->getBufferStart()); + if (Error E = Output->commit()) + return E; + return Error::success(); +} + +// This is the first of many steps in creating a binary using llvm offload, +// to run code on the gpu. Concrete, it replaces the following binary use: +// clang-offload-packager -o host.out +// --image=file=device.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp +// The input module is the rust code compiled for a gpu target like amdgpu. +// Based on clang/tools/clang-offload-packager/ClangOffloadPackager.cpp +extern "C" bool LLVMRustBundleImages(LLVMModuleRef M, TargetMachine &TM) { + std::string Storage; + llvm::raw_string_ostream OS1(Storage); + llvm::WriteBitcodeToFile(*unwrap(M), OS1); + OS1.flush(); + auto MB = llvm::MemoryBuffer::getMemBufferCopy(Storage, "module.bc"); + + SmallVector BinaryData; + raw_svector_ostream OS2(BinaryData); + + OffloadBinary::OffloadingImage ImageBinary{}; + ImageBinary.TheImageKind = object::IMG_Bitcode; + ImageBinary.Image = std::move(MB); + ImageBinary.TheOffloadKind = object::OFK_OpenMP; + ImageBinary.StringData["triple"] = TM.getTargetTriple().str(); + ImageBinary.StringData["arch"] = TM.getTargetCPU(); + llvm::SmallString<0> Buffer = OffloadBinary::write(ImageBinary); + if (Buffer.size() % OffloadBinary::getAlignment() != 0) + // Offload binary has invalid size alignment + return false; + OS2 << Buffer; + if (Error E = writeFile("host.out", + StringRef(BinaryData.begin(), BinaryData.size()))) + return false; + return true; +} + extern "C" void LLVMRustOffloadMapper(LLVMValueRef OldFn, LLVMValueRef NewFn) { llvm::Function *oldFn = llvm::unwrap(OldFn); llvm::Function *newFn = llvm::unwrap(NewFn);