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/2] [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 f83f1e4424dc524e67ca41d75b4a77616a0ead2d Mon Sep 17 00:00:00 2001 From: AdityaSinha149 <[email protected]> Date: Wed, 9 Sep 2026 14:59:13 +0530 Subject: [PATCH 2/2] removed optimizer and reloaded device libs fro 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. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
