[clang] [clang-repl] Implement IncrementalHIPDeviceParser for HIP device compilation (PR #218337)
Aditya Sinha via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 10 00:34:25 PDT 2026
https://github.com/AdityaSinha149 updated https://github.com/llvm/llvm-project/pull/218337
>From 7dfaa1317187c56a7e31b89e6d9d5d807c68a8f3 Mon Sep 17 00:00:00 2001
From: AdityaSinha149 <adsinha at amd.com>
Date: Mon, 24 Aug 2026 12:58:31 +0530
Subject: [PATCH 1/8] [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 <adsinha at amd.com>
Date: Wed, 9 Sep 2026 14:59:13 +0530
Subject: [PATCH 2/8] 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 <adsinha at amd.com>
Date: Wed, 9 Sep 2026 15:41:39 +0530
Subject: [PATCH 3/8] 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 <adsinha at amd.com>
Date: Wed, 9 Sep 2026 16:17:10 +0530
Subject: [PATCH 4/8] 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 <adsinha at amd.com>
Date: Thu, 10 Sep 2026 11:54:10 +0530
Subject: [PATCH 5/8] 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 <adsinha at amd.com>
Date: Thu, 10 Sep 2026 11:59:34 +0530
Subject: [PATCH 6/8] 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 <adsinha at amd.com>
Date: Thu, 10 Sep 2026 12:59:57 +0530
Subject: [PATCH 7/8] 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 <adsinha at amd.com>
Date: Thu, 10 Sep 2026 13:04:09 +0530
Subject: [PATCH 8/8] 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());
More information about the cfe-commits
mailing list