https://github.com/AdityaSinha149 updated https://github.com/llvm/llvm-project/pull/218337
>From 7dfaa1317187c56a7e31b89e6d9d5d807c68a8f3 Mon Sep 17 00:00:00 2001 From: AdityaSinha149 <[email protected]> Date: Mon, 24 Aug 2026 12:58:31 +0530 Subject: [PATCH 1/9] [clang-repl] Made IncrementalHipDeviceParser class --- clang/lib/Interpreter/DeviceOffload.cpp | 244 ++++++++++++++++++++++-- clang/lib/Interpreter/DeviceOffload.h | 34 ++++ 2 files changed, 266 insertions(+), 12 deletions(-) diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index 38cecd142a8e6..b53d59d790042 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -11,19 +11,245 @@ //===----------------------------------------------------------------------===// #include "DeviceOffload.h" +#include "IncrementalAction.h" #include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Interpreter/PartialTranslationUnit.h" +#include "llvm/ADT/StringSet.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" +#include "llvm/Linker/Linker.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/Transforms/IPO/Internalize.h" namespace clang { +static llvm::Expected<llvm::TargetMachine *> +getOrCreateTargetMachine(std::unique_ptr<llvm::TargetMachine> &Cache, + llvm::Module &M, llvm::StringRef CPU) { + if (!Cache) { + std::string Error; + const llvm::Target *Target = + llvm::TargetRegistry::lookupTarget(M.getTargetTriple(), Error); + if (!Target) + return llvm::make_error<llvm::StringError>(std::move(Error), + std::error_code()); + llvm::TargetOptions TO = llvm::TargetOptions(); + Cache.reset(Target->createTargetMachine(M.getTargetTriple(), CPU, "", TO, + llvm::Reloc::Model::PIC_)); + } + M.setDataLayout(Cache->createDataLayout()); + return Cache.get(); +} + +IncrementalHIPDeviceParser::IncrementalHIPDeviceParser( + CompilerInstance &DeviceInstance, CompilerInstance &HostInstance, + IncrementalAction *DeviceAct, + llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS, + llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs) + : IncrementalParser(DeviceInstance, DeviceAct, Err, PTUs), VFS(FS), + CodeGenOpts(HostInstance.getCodeGenOpts()), + DeviceCodeGenOpts(DeviceInstance.getCodeGenOpts()), + TargetOpts(DeviceInstance.getTargetOpts()) { + if (Err) + return; + StringRef Arch = TargetOpts.CPU; + if (!Arch.starts_with("gfx")) { + Err = llvm::joinErrors(std::move(Err), llvm::make_error<llvm::StringError>( + "Invalid HIP architecture", + llvm::inconvertibleErrorCode())); + return; + } +} + +llvm::Error IncrementalHIPDeviceParser::optimize() { + auto &PTU = PTUs.back(); + + llvm::Expected<llvm::TargetMachine *> TMOrErr = + getOrCreateTargetMachine(TM, *PTU.TheModule, TargetOpts.CPU); + if (!TMOrErr) + return TMOrErr.takeError(); + + llvm::LoopAnalysisManager LAM; + llvm::FunctionAnalysisManager FAM; + llvm::CGSCCAnalysisManager CGAM; + llvm::ModuleAnalysisManager MAM; + + llvm::PassBuilder PB(*TMOrErr); + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + llvm::OptimizationLevel OptLevel; + switch (DeviceCodeGenOpts.OptimizationLevel) { + case 0: + OptLevel = llvm::OptimizationLevel::O0; + break; + case 1: + OptLevel = llvm::OptimizationLevel::O1; + break; + case 2: + OptLevel = llvm::OptimizationLevel::O2; + break; + default: + OptLevel = llvm::OptimizationLevel::O3; + break; + } + + llvm::ModulePassManager MPM = + OptLevel == llvm::OptimizationLevel::O0 + ? PB.buildO0DefaultPipeline(OptLevel) + : PB.buildPerModuleDefaultPipeline(OptLevel); + MPM.run(*PTU.TheModule, MAM); + return llvm::Error::success(); +} + +llvm::Expected<llvm::StringRef> IncrementalHIPDeviceParser::GenerateHSACO() { + auto &PTU = PTUs.back(); + + llvm::Expected<llvm::TargetMachine *> TMOrErr = + getOrCreateTargetMachine(TM, *PTU.TheModule, TargetOpts.CPU); + if (!TMOrErr) + return TMOrErr.takeError(); + llvm::TargetMachine *TargetMachine = *TMOrErr; + + llvm::SmallVector<char, 0> Object; + llvm::raw_svector_ostream ObjOS(Object); + + llvm::legacy::PassManager PM; + if (TargetMachine->addPassesToEmitFile(PM, ObjOS, nullptr, + llvm::CodeGenFileType::ObjectFile)) + return llvm::make_error<llvm::StringError>( + "AMDGPU backend cannot produce an object file.", + llvm::inconvertibleErrorCode()); + + if (!PM.run(*PTU.TheModule)) + return llvm::make_error<llvm::StringError>( + "Failed to emit the object file.", llvm::inconvertibleErrorCode()); + + // Link the object into a shared .hsaco code object with ld.lld. + std::string Exe = llvm::sys::fs::getMainExecutable(nullptr, nullptr); + llvm::StringRef ExeDir = llvm::sys::path::parent_path(Exe); + llvm::ErrorOr<std::string> LLDPath = + llvm::sys::findProgramByName("ld.lld", {ExeDir}); + if (!LLDPath) + LLDPath = llvm::sys::findProgramByName("ld.lld"); + if (!LLDPath) + return llvm::make_error<llvm::StringError>( + "Could not find ld.lld next to the executable or on PATH.", + llvm::inconvertibleErrorCode()); + + int ObjFD = -1; + llvm::SmallString<128> ObjFile; + if (llvm::sys::fs::createTemporaryFile("kernel", "o", ObjFD, ObjFile)) + return llvm::make_error<llvm::StringError>( + "Failed to create a temporary object file.", + llvm::inconvertibleErrorCode()); + llvm::FileRemover ObjRemover(ObjFile); + { + llvm::raw_fd_ostream OS(ObjFD, /*shouldClose=*/true); + OS << llvm::StringRef(Object.data(), Object.size()); + } + + llvm::SmallString<128> HsacoFile; + if (llvm::sys::fs::createTemporaryFile("kernel", "hsaco", HsacoFile)) + return llvm::make_error<llvm::StringError>( + "Failed to create a temporary code object file.", + llvm::inconvertibleErrorCode()); + llvm::FileRemover HsacoRemover(HsacoFile); + + llvm::StringRef Args[] = {"ld.lld", "-shared", ObjFile, "-o", HsacoFile}; + if (llvm::sys::ExecuteAndWait(*LLDPath, Args) != 0) + return llvm::make_error<llvm::StringError>("ld.lld invocation failed.", + llvm::inconvertibleErrorCode()); + + auto HsacoBuf = llvm::MemoryBuffer::getFile(HsacoFile, /*IsText=*/false); + if (!HsacoBuf) + return llvm::make_error<llvm::StringError>( + "Failed to read the code object.", llvm::inconvertibleErrorCode()); + + llvm::StringRef Buffer = (*HsacoBuf)->getBuffer(); + HSACOContent.assign(Buffer.begin(), Buffer.end()); + return llvm::StringRef(HSACOContent.data(), HSACOContent.size()); +} + +llvm::Error IncrementalHIPDeviceParser::GenerateOffloadBundle() { + // The host embeds this blob as __hip_fatbin; __hipRegisterFatBinary parses + // it as a clang-offload-bundle: + // char Magic["__CLANG_OFFLOAD_BUNDLE__"] (no NUL terminator) + // uint64_t NumberOfEntries + // for each entry: uint64_t Offset, Size, TripleSize; char Triple[] + // the code objects follow; HIP requires each to be page-aligned (4096). + static constexpr llvm::StringRef Magic = "__CLANG_OFFLOAD_BUNDLE__"; + static constexpr uint64_t CodeObjectAlign = 4096; + + const PartialTranslationUnit &PTU = PTUs.back(); + // Triples use the normalized 4-field form ending in a dash; the device entry + // additionally appends the offload arch, e.g. + // "hip-amdgcn-amd-amdhsa--gfx90a". + std::string HostTriple = "host-" + llvm::sys::getProcessTriple() + "-"; + std::string DeviceTriple = + "hip-" + PTU.TheModule->getTargetTriple().str() + "--" + TargetOpts.CPU; + + const uint64_t NumEntries = 2; + const uint64_t HeaderSize = Magic.size() + sizeof(uint64_t) + + NumEntries * (3 * sizeof(uint64_t)) + + HostTriple.size() + DeviceTriple.size(); + const uint64_t CodeObjectOffset = llvm::alignTo(HeaderSize, CodeObjectAlign); + + llvm::SmallVector<char, 4096> Bundle; + llvm::raw_svector_ostream OS(Bundle); + auto WriteU64 = [&OS](uint64_t V) { + OS.write(reinterpret_cast<const char *>(&V), sizeof(V)); + }; + + OS << Magic; + WriteU64(NumEntries); + + // Host entry: empty content. Not required (the runtime matches by triple and + // skips host entries); emitted only to mirror the canonical bundler layout, + // and free since page alignment keeps the bundle the same size regardless. + WriteU64(CodeObjectOffset); + WriteU64(/*Size=*/0); + WriteU64(HostTriple.size()); + OS << HostTriple; + + // Device entry: the page-aligned .hsaco content. + WriteU64(CodeObjectOffset); + WriteU64(HSACOContent.size()); + WriteU64(DeviceTriple.size()); + OS << DeviceTriple; + + // Zero-pad the header up to the aligned code-object offset. + OS << std::string(CodeObjectOffset - HeaderSize, '\0'); + OS << llvm::StringRef(HSACOContent.data(), HSACOContent.size()); + + std::string BundleFileName = "/" + PTU.TheModule->getName().str() + ".hipfb"; + VFS->addFile(BundleFileName, 0, + llvm::MemoryBuffer::getMemBufferCopy( + llvm::StringRef(Bundle.data(), Bundle.size()))); + + CodeGenOpts.OffloadBinaryToEmbedFile = std::move(BundleFileName); + return llvm::Error::success(); +} + +IncrementalHIPDeviceParser::~IncrementalHIPDeviceParser() {} + IncrementalCUDADeviceParser::IncrementalCUDADeviceParser( CompilerInstance &DeviceInstance, CompilerInstance &HostInstance, IncrementalAction *DeviceAct, @@ -45,18 +271,12 @@ IncrementalCUDADeviceParser::IncrementalCUDADeviceParser( llvm::Expected<llvm::StringRef> IncrementalCUDADeviceParser::GeneratePTX() { auto &PTU = PTUs.back(); - std::string Error; - - const llvm::Target *Target = llvm::TargetRegistry::lookupTarget( - PTU.TheModule->getTargetTriple(), Error); - if (!Target) - return llvm::make_error<llvm::StringError>(std::move(Error), - std::error_code()); - llvm::TargetOptions TO = llvm::TargetOptions(); - llvm::TargetMachine *TargetMachine = Target->createTargetMachine( - PTU.TheModule->getTargetTriple(), TargetOpts.CPU, "", TO, - llvm::Reloc::Model::PIC_); - PTU.TheModule->setDataLayout(TargetMachine->createDataLayout()); + + llvm::Expected<llvm::TargetMachine *> TMOrErr = + getOrCreateTargetMachine(TM, *PTU.TheModule, TargetOpts.CPU); + if (!TMOrErr) + return TMOrErr.takeError(); + llvm::TargetMachine *TargetMachine = *TMOrErr; PTXCode.clear(); llvm::raw_svector_ostream dest(PTXCode); diff --git a/clang/lib/Interpreter/DeviceOffload.h b/clang/lib/Interpreter/DeviceOffload.h index a31bd5a0499b8..ea1f48fe43a59 100644 --- a/clang/lib/Interpreter/DeviceOffload.h +++ b/clang/lib/Interpreter/DeviceOffload.h @@ -14,9 +14,16 @@ #define LLVM_CLANG_LIB_INTERPRETER_DEVICE_OFFLOAD_H #include "IncrementalParser.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/VirtualFileSystem.h" +#include <memory> + +namespace llvm { +class TargetMachine; +} // namespace llvm + namespace clang { struct PartialTranslationUnit; class CompilerInstance; @@ -24,6 +31,32 @@ class CodeGenOptions; class TargetOptions; class IncrementalAction; +class IncrementalHIPDeviceParser : public IncrementalParser { + +public: + IncrementalHIPDeviceParser( + CompilerInstance &DeviceInstance, CompilerInstance &HostInstance, + IncrementalAction *DeviceAct, + llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS, + llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs); + + llvm::Error optimize(); + + llvm::Expected<llvm::StringRef> GenerateHSACO(); + + llvm::Error GenerateOffloadBundle(); + + ~IncrementalHIPDeviceParser(); + +protected: + llvm::SmallVector<char, 1024> HSACOContent; + llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS; + CodeGenOptions &CodeGenOpts; // Host opts, intentionally a reference. + const CodeGenOptions &DeviceCodeGenOpts; + const TargetOptions &TargetOpts; + std::unique_ptr<llvm::TargetMachine> TM; +}; + class IncrementalCUDADeviceParser : public IncrementalParser { public: @@ -48,6 +81,7 @@ class IncrementalCUDADeviceParser : public IncrementalParser { llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS; CodeGenOptions &CodeGenOpts; // Intentionally a reference. const TargetOptions &TargetOpts; + std::unique_ptr<llvm::TargetMachine> TM; }; } // namespace clang >From 357d8894897ccdb9b1c306e945fe602e864ea7ad Mon Sep 17 00:00:00 2001 From: AdityaSinha149 <[email protected]> Date: Wed, 9 Sep 2026 14:59:13 +0530 Subject: [PATCH 2/9] removed optimizer and reloaded device libs for each module --- clang/include/clang/CodeGen/CodeGenAction.h | 5 ++ clang/lib/CodeGen/BackendConsumer.h | 8 ++++ clang/lib/CodeGen/CodeGenAction.cpp | 9 ++++ clang/lib/Interpreter/DeviceOffload.cpp | 52 ++++----------------- clang/lib/Interpreter/DeviceOffload.h | 3 +- 5 files changed, 34 insertions(+), 43 deletions(-) diff --git a/clang/include/clang/CodeGen/CodeGenAction.h b/clang/include/clang/CodeGen/CodeGenAction.h index 84fa4549d5033..319cc8f2b14a1 100644 --- a/clang/include/clang/CodeGen/CodeGenAction.h +++ b/clang/include/clang/CodeGen/CodeGenAction.h @@ -63,6 +63,11 @@ class CodeGenAction : public ASTFrontendAction { CodeGenerator *getCodeGenerator() const; + /// Reload the -mlink-builtin-bitcode modules into the backend consumer. + /// LinkInModules() consumes them, so incremental compilation must reload them + /// before each translation unit (e.g. to re-link HIP device libraries). + void reloadLinkModules(CompilerInstance &CI); + BackendConsumer *BEConsumer = nullptr; }; diff --git a/clang/lib/CodeGen/BackendConsumer.h b/clang/lib/CodeGen/BackendConsumer.h index 708658d206baf..d6d713844a195 100644 --- a/clang/lib/CodeGen/BackendConsumer.h +++ b/clang/lib/CodeGen/BackendConsumer.h @@ -92,6 +92,14 @@ class BackendConsumer : public ASTConsumer { // Links each entry in LinkModules into our module. Returns true on error. bool LinkInModules(llvm::Module *M); + /// Replace the set of modules to link in. LinkInModules() consumes the + /// modules, so incremental compilation (clang-repl) must reload and reseed + /// them before each translation unit; otherwise later inputs would miss the + /// linked-in bitcode (e.g. HIP device libraries). + void setLinkModules(SmallVector<LinkModule, 4> LMs) { + LinkModules = std::move(LMs); + } + /// Get the best possible source location to represent a diagnostic that /// may have associated debug info. const FullSourceLoc getBestLocationFromDebugLoc( diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 6911cab379fdc..c8b4b9de48983 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -984,6 +984,15 @@ CodeGenerator *CodeGenAction::getCodeGenerator() const { return BEConsumer->getCodeGenerator(); } +void CodeGenAction::reloadLinkModules(CompilerInstance &CI) { + if (!BEConsumer) + return; + SmallVector<LinkModule, 4> LMs; + if (clang::loadLinkModules(CI, *VMContext, LMs)) + return; + BEConsumer->setLinkModules(std::move(LMs)); +} + bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) { if (CI.getFrontendOpts().GenReducedBMI) CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index b53d59d790042..cf9fd361f57b5 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -14,8 +14,10 @@ #include "IncrementalAction.h" #include "clang/Basic/TargetOptions.h" +#include "clang/CodeGen/CodeGenAction.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" #include "clang/Interpreter/PartialTranslationUnit.h" #include "llvm/ADT/StringSet.h" @@ -60,7 +62,8 @@ IncrementalHIPDeviceParser::IncrementalHIPDeviceParser( IncrementalAction *DeviceAct, llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS, llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs) - : IncrementalParser(DeviceInstance, DeviceAct, Err, PTUs), VFS(FS), + : IncrementalParser(DeviceInstance, DeviceAct, Err, PTUs), + DeviceCI(DeviceInstance), VFS(FS), CodeGenOpts(HostInstance.getCodeGenOpts()), DeviceCodeGenOpts(DeviceInstance.getCodeGenOpts()), TargetOpts(DeviceInstance.getTargetOpts()) { @@ -75,48 +78,13 @@ IncrementalHIPDeviceParser::IncrementalHIPDeviceParser( } } -llvm::Error IncrementalHIPDeviceParser::optimize() { - auto &PTU = PTUs.back(); - - llvm::Expected<llvm::TargetMachine *> TMOrErr = - getOrCreateTargetMachine(TM, *PTU.TheModule, TargetOpts.CPU); - if (!TMOrErr) - return TMOrErr.takeError(); - - llvm::LoopAnalysisManager LAM; - llvm::FunctionAnalysisManager FAM; - llvm::CGSCCAnalysisManager CGAM; - llvm::ModuleAnalysisManager MAM; - - llvm::PassBuilder PB(*TMOrErr); - PB.registerModuleAnalyses(MAM); - PB.registerCGSCCAnalyses(CGAM); - PB.registerFunctionAnalyses(FAM); - PB.registerLoopAnalyses(LAM); - PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - - llvm::OptimizationLevel OptLevel; - switch (DeviceCodeGenOpts.OptimizationLevel) { - case 0: - OptLevel = llvm::OptimizationLevel::O0; - break; - case 1: - OptLevel = llvm::OptimizationLevel::O1; - break; - case 2: - OptLevel = llvm::OptimizationLevel::O2; - break; - default: - OptLevel = llvm::OptimizationLevel::O3; - break; - } +llvm::Expected<TranslationUnitDecl *> +IncrementalHIPDeviceParser::Parse(llvm::StringRef Input) { + if (FrontendAction *WrappedAct = Act->getWrapped()) + if (WrappedAct->hasIRSupport()) + static_cast<CodeGenAction *>(WrappedAct)->reloadLinkModules(DeviceCI); - llvm::ModulePassManager MPM = - OptLevel == llvm::OptimizationLevel::O0 - ? PB.buildO0DefaultPipeline(OptLevel) - : PB.buildPerModuleDefaultPipeline(OptLevel); - MPM.run(*PTU.TheModule, MAM); - return llvm::Error::success(); + return IncrementalParser::Parse(Input); } llvm::Expected<llvm::StringRef> IncrementalHIPDeviceParser::GenerateHSACO() { diff --git a/clang/lib/Interpreter/DeviceOffload.h b/clang/lib/Interpreter/DeviceOffload.h index ea1f48fe43a59..29a5530735eee 100644 --- a/clang/lib/Interpreter/DeviceOffload.h +++ b/clang/lib/Interpreter/DeviceOffload.h @@ -40,7 +40,7 @@ class IncrementalHIPDeviceParser : public IncrementalParser { llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS, llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs); - llvm::Error optimize(); + llvm::Expected<TranslationUnitDecl *> Parse(llvm::StringRef Input) override; llvm::Expected<llvm::StringRef> GenerateHSACO(); @@ -49,6 +49,7 @@ class IncrementalHIPDeviceParser : public IncrementalParser { ~IncrementalHIPDeviceParser(); protected: + CompilerInstance &DeviceCI; llvm::SmallVector<char, 1024> HSACOContent; llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS; CodeGenOptions &CodeGenOpts; // Host opts, intentionally a reference. >From 1f11a967a21c0875028726ad1826505040fd9d66 Mon Sep 17 00:00:00 2001 From: AdityaSinha149 <[email protected]> Date: Wed, 9 Sep 2026 15:41:39 +0530 Subject: [PATCH 3/9] changed comments to add HIP --- clang/lib/Interpreter/DeviceOffload.cpp | 2 +- clang/lib/Interpreter/DeviceOffload.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index cf9fd361f57b5..283a9ae6daa87 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements offloading to CUDA devices. +// This file implements offloading to HIP and CUDA devices. // //===----------------------------------------------------------------------===// diff --git a/clang/lib/Interpreter/DeviceOffload.h b/clang/lib/Interpreter/DeviceOffload.h index 29a5530735eee..db0edc620aed2 100644 --- a/clang/lib/Interpreter/DeviceOffload.h +++ b/clang/lib/Interpreter/DeviceOffload.h @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements classes required for offloading to CUDA devices. +// This file implements classes required for offloading to HIP and CUDA devices. // //===----------------------------------------------------------------------===// >From 7fd5e9187e275d04c3342314f2bd238508da7111 Mon Sep 17 00:00:00 2001 From: AdityaSinha149 <[email protected]> Date: Wed, 9 Sep 2026 16:17:10 +0530 Subject: [PATCH 4/9] removed target machine and used clang's backend --- clang/lib/Interpreter/DeviceOffload.cpp | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index 283a9ae6daa87..06fd76ba74dc0 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -14,6 +14,7 @@ #include "IncrementalAction.h" #include "clang/Basic/TargetOptions.h" +#include "clang/CodeGen/BackendUtil.h" #include "clang/CodeGen/CodeGenAction.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/CompilerInstance.h" @@ -90,27 +91,13 @@ IncrementalHIPDeviceParser::Parse(llvm::StringRef Input) { llvm::Expected<llvm::StringRef> IncrementalHIPDeviceParser::GenerateHSACO() { auto &PTU = PTUs.back(); - llvm::Expected<llvm::TargetMachine *> TMOrErr = - getOrCreateTargetMachine(TM, *PTU.TheModule, TargetOpts.CPU); - if (!TMOrErr) - return TMOrErr.takeError(); - llvm::TargetMachine *TargetMachine = *TMOrErr; - llvm::SmallVector<char, 0> Object; - llvm::raw_svector_ostream ObjOS(Object); - - llvm::legacy::PassManager PM; - if (TargetMachine->addPassesToEmitFile(PM, ObjOS, nullptr, - llvm::CodeGenFileType::ObjectFile)) - return llvm::make_error<llvm::StringError>( - "AMDGPU backend cannot produce an object file.", - llvm::inconvertibleErrorCode()); - - if (!PM.run(*PTU.TheModule)) - return llvm::make_error<llvm::StringError>( - "Failed to emit the object file.", llvm::inconvertibleErrorCode()); + auto ObjOS = std::make_unique<llvm::raw_svector_ostream>(Object); + clang::emitBackendOutput(DeviceCI, DeviceCI.getCodeGenOpts(), + DeviceCI.getTarget().getDataLayoutString(), + PTU.TheModule.get(), Backend_EmitObj, + DeviceCI.getVirtualFileSystemPtr(), std::move(ObjOS)); - // Link the object into a shared .hsaco code object with ld.lld. std::string Exe = llvm::sys::fs::getMainExecutable(nullptr, nullptr); llvm::StringRef ExeDir = llvm::sys::path::parent_path(Exe); llvm::ErrorOr<std::string> LLDPath = >From b5398749b12d9af02376570dd1d8bc962ab26162 Mon Sep 17 00:00:00 2001 From: AdityaSinha149 <[email protected]> Date: Thu, 10 Sep 2026 11:54:10 +0530 Subject: [PATCH 5/9] removed check from PassManager::run() --- clang/lib/Interpreter/DeviceOffload.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index 06fd76ba74dc0..9bc984f787e8b 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -21,7 +21,6 @@ #include "clang/Frontend/FrontendAction.h" #include "clang/Interpreter/PartialTranslationUnit.h" -#include "llvm/ADT/StringSet.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" @@ -244,9 +243,7 @@ llvm::Expected<llvm::StringRef> IncrementalCUDADeviceParser::GeneratePTX() { llvm::inconvertibleErrorCode()); } - if (!PM.run(*PTU.TheModule)) - return llvm::make_error<llvm::StringError>("Failed to emit PTX code.", - llvm::inconvertibleErrorCode()); + PM.run(*PTU.TheModule); PTXCode += '\0'; while (PTXCode.size() % 8) >From c65597e61c0176204a5e0497f0a4b5fd88ac3607 Mon Sep 17 00:00:00 2001 From: AdityaSinha149 <[email protected]> Date: Thu, 10 Sep 2026 11:59:34 +0530 Subject: [PATCH 6/9] added --no-undefined arg to the linker --- clang/lib/Interpreter/DeviceOffload.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index 9bc984f787e8b..77873dfbeaa1e 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -127,7 +127,8 @@ llvm::Expected<llvm::StringRef> IncrementalHIPDeviceParser::GenerateHSACO() { llvm::inconvertibleErrorCode()); llvm::FileRemover HsacoRemover(HsacoFile); - llvm::StringRef Args[] = {"ld.lld", "-shared", ObjFile, "-o", HsacoFile}; + llvm::StringRef Args[] = {"ld.lld", "-shared", "--no-undefined", + ObjFile, "-o", HsacoFile}; if (llvm::sys::ExecuteAndWait(*LLDPath, Args) != 0) return llvm::make_error<llvm::StringError>("ld.lld invocation failed.", llvm::inconvertibleErrorCode()); >From 4cfeb00b6f4d1f1f3fff77916d9cbe5a6dec033c Mon Sep 17 00:00:00 2001 From: AdityaSinha149 <[email protected]> Date: Thu, 10 Sep 2026 12:59:57 +0530 Subject: [PATCH 7/9] removed unused headers --- clang/lib/Interpreter/DeviceOffload.cpp | 3 --- clang/lib/Interpreter/DeviceOffload.h | 1 - 2 files changed, 4 deletions(-) diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index 77873dfbeaa1e..a422ceb7a10a9 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -23,10 +23,7 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" -#include "llvm/IRReader/IRReader.h" -#include "llvm/Linker/Linker.h" #include "llvm/MC/TargetRegistry.h" -#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/MathExtras.h" diff --git a/clang/lib/Interpreter/DeviceOffload.h b/clang/lib/Interpreter/DeviceOffload.h index db0edc620aed2..3e326e566a5bb 100644 --- a/clang/lib/Interpreter/DeviceOffload.h +++ b/clang/lib/Interpreter/DeviceOffload.h @@ -15,7 +15,6 @@ #include "IncrementalParser.h" #include "llvm/Support/Error.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/VirtualFileSystem.h" #include <memory> >From 0aeefb4c3fe227001d6981e07b6960b129b3486e Mon Sep 17 00:00:00 2001 From: AdityaSinha149 <[email protected]> Date: Thu, 10 Sep 2026 13:04:09 +0530 Subject: [PATCH 8/9] formatting --- clang/lib/Interpreter/DeviceOffload.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index a422ceb7a10a9..6fdd79045f411 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -89,10 +89,10 @@ llvm::Expected<llvm::StringRef> IncrementalHIPDeviceParser::GenerateHSACO() { llvm::SmallVector<char, 0> Object; auto ObjOS = std::make_unique<llvm::raw_svector_ostream>(Object); - clang::emitBackendOutput(DeviceCI, DeviceCI.getCodeGenOpts(), - DeviceCI.getTarget().getDataLayoutString(), - PTU.TheModule.get(), Backend_EmitObj, - DeviceCI.getVirtualFileSystemPtr(), std::move(ObjOS)); + clang::emitBackendOutput( + DeviceCI, DeviceCI.getCodeGenOpts(), + DeviceCI.getTarget().getDataLayoutString(), PTU.TheModule.get(), + Backend_EmitObj, DeviceCI.getVirtualFileSystemPtr(), std::move(ObjOS)); std::string Exe = llvm::sys::fs::getMainExecutable(nullptr, nullptr); llvm::StringRef ExeDir = llvm::sys::path::parent_path(Exe); @@ -124,8 +124,8 @@ llvm::Expected<llvm::StringRef> IncrementalHIPDeviceParser::GenerateHSACO() { llvm::inconvertibleErrorCode()); llvm::FileRemover HsacoRemover(HsacoFile); - llvm::StringRef Args[] = {"ld.lld", "-shared", "--no-undefined", - ObjFile, "-o", HsacoFile}; + llvm::StringRef Args[] = {"ld.lld", "-shared", "--no-undefined", + ObjFile, "-o", HsacoFile}; if (llvm::sys::ExecuteAndWait(*LLDPath, Args) != 0) return llvm::make_error<llvm::StringError>("ld.lld invocation failed.", llvm::inconvertibleErrorCode()); >From 2b81c36e342dc6264298567ef1234af1bc265135 Mon Sep 17 00:00:00 2001 From: AdityaSinha149 <[email protected]> Date: Thu, 10 Sep 2026 16:29:36 +0530 Subject: [PATCH 9/9] changed the code to use clang::offloadBundler --- clang/lib/Interpreter/DeviceOffload.cpp | 85 +++++++++++++------------ 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index 6fdd79045f411..bfa733585b2a9 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -17,6 +17,7 @@ #include "clang/CodeGen/BackendUtil.h" #include "clang/CodeGen/CodeGenAction.h" #include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Driver/OffloadBundler.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Interpreter/PartialTranslationUnit.h" @@ -26,7 +27,6 @@ #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" -#include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" @@ -141,16 +141,37 @@ llvm::Expected<llvm::StringRef> IncrementalHIPDeviceParser::GenerateHSACO() { } llvm::Error IncrementalHIPDeviceParser::GenerateOffloadBundle() { - // The host embeds this blob as __hip_fatbin; __hipRegisterFatBinary parses - // it as a clang-offload-bundle: - // char Magic["__CLANG_OFFLOAD_BUNDLE__"] (no NUL terminator) - // uint64_t NumberOfEntries - // for each entry: uint64_t Offset, Size, TripleSize; char Triple[] - // the code objects follow; HIP requires each to be page-aligned (4096). - static constexpr llvm::StringRef Magic = "__CLANG_OFFLOAD_BUNDLE__"; - static constexpr uint64_t CodeObjectAlign = 4096; + static constexpr unsigned CodeObjectAlign = 4096; const PartialTranslationUnit &PTU = PTUs.back(); + + llvm::SmallString<128> HostFile; + if (llvm::sys::fs::createTemporaryFile("hip-host", "", HostFile)) + return llvm::make_error<llvm::StringError>( + "Failed to create a temporary host bundle input.", + llvm::inconvertibleErrorCode()); + llvm::FileRemover HostRemover(HostFile); + + llvm::SmallString<128> DeviceFile; + int DeviceFD = -1; + if (llvm::sys::fs::createTemporaryFile("hip-device", "hsaco", DeviceFD, + DeviceFile)) + return llvm::make_error<llvm::StringError>( + "Failed to create a temporary code object file.", + llvm::inconvertibleErrorCode()); + llvm::FileRemover DeviceRemover(DeviceFile); + { + llvm::raw_fd_ostream OS(DeviceFD, /*shouldClose=*/true); + OS << llvm::StringRef(HSACOContent.data(), HSACOContent.size()); + } + + llvm::SmallString<128> BundleFile; + if (llvm::sys::fs::createTemporaryFile("hip-bundle", "hipfb", BundleFile)) + return llvm::make_error<llvm::StringError>( + "Failed to create a temporary offload bundle file.", + llvm::inconvertibleErrorCode()); + llvm::FileRemover BundleRemover(BundleFile); + // Triples use the normalized 4-field form ending in a dash; the device entry // additionally appends the offload arch, e.g. // "hip-amdgcn-amd-amdhsa--gfx90a". @@ -158,43 +179,25 @@ llvm::Error IncrementalHIPDeviceParser::GenerateOffloadBundle() { std::string DeviceTriple = "hip-" + PTU.TheModule->getTargetTriple().str() + "--" + TargetOpts.CPU; - const uint64_t NumEntries = 2; - const uint64_t HeaderSize = Magic.size() + sizeof(uint64_t) + - NumEntries * (3 * sizeof(uint64_t)) + - HostTriple.size() + DeviceTriple.size(); - const uint64_t CodeObjectOffset = llvm::alignTo(HeaderSize, CodeObjectAlign); + OffloadBundlerConfig Config; + Config.FilesType = "o"; + Config.BundleAlignment = CodeObjectAlign; + Config.HostInputIndex = 0; + Config.TargetNames = {HostTriple, DeviceTriple}; + Config.InputFileNames = {std::string(HostFile), std::string(DeviceFile)}; + Config.OutputFileNames = {std::string(BundleFile)}; - llvm::SmallVector<char, 4096> Bundle; - llvm::raw_svector_ostream OS(Bundle); - auto WriteU64 = [&OS](uint64_t V) { - OS.write(reinterpret_cast<const char *>(&V), sizeof(V)); - }; + if (llvm::Error Err = OffloadBundler(Config).BundleFiles()) + return Err; - OS << Magic; - WriteU64(NumEntries); - - // Host entry: empty content. Not required (the runtime matches by triple and - // skips host entries); emitted only to mirror the canonical bundler layout, - // and free since page alignment keeps the bundle the same size regardless. - WriteU64(CodeObjectOffset); - WriteU64(/*Size=*/0); - WriteU64(HostTriple.size()); - OS << HostTriple; - - // Device entry: the page-aligned .hsaco content. - WriteU64(CodeObjectOffset); - WriteU64(HSACOContent.size()); - WriteU64(DeviceTriple.size()); - OS << DeviceTriple; - - // Zero-pad the header up to the aligned code-object offset. - OS << std::string(CodeObjectOffset - HeaderSize, '\0'); - OS << llvm::StringRef(HSACOContent.data(), HSACOContent.size()); + auto BundleBuf = llvm::MemoryBuffer::getFile(BundleFile, /*IsText=*/false); + if (!BundleBuf) + return llvm::make_error<llvm::StringError>( + "Failed to read the offload bundle.", llvm::inconvertibleErrorCode()); std::string BundleFileName = "/" + PTU.TheModule->getName().str() + ".hipfb"; VFS->addFile(BundleFileName, 0, - llvm::MemoryBuffer::getMemBufferCopy( - llvm::StringRef(Bundle.data(), Bundle.size()))); + llvm::MemoryBuffer::getMemBufferCopy((*BundleBuf)->getBuffer())); CodeGenOpts.OffloadBinaryToEmbedFile = std::move(BundleFileName); return llvm::Error::success(); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
