https://github.com/AdityaSinha149 updated 
https://github.com/llvm/llvm-project/pull/235614

>From f715b64512711d08976f7f6c6858d8fe3590d528 Mon Sep 17 00:00:00 2001
From: AdityaSinha149 <[email protected]>
Date: Mon, 26 Oct 2026 10:58:56 +0530
Subject: [PATCH] [clang-repl] Link HIP device object into an HSACO

---
 clang/include/clang/Interpreter/Interpreter.h |  3 +-
 clang/lib/Interpreter/DeviceOffload.cpp       | 99 ++++++++++++++++++-
 clang/lib/Interpreter/DeviceOffload.h         | 10 +-
 clang/lib/Interpreter/Interpreter.cpp         |  5 +-
 clang/tools/clang-repl/ClangRepl.cpp          |  2 +-
 .../Interpreter/DeviceOffloadTest.cpp         | 31 +++++-
 6 files changed, 140 insertions(+), 10 deletions(-)

diff --git a/clang/include/clang/Interpreter/Interpreter.h 
b/clang/include/clang/Interpreter/Interpreter.h
index 5228b7fe80bd32..644f6f6247b79f 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -158,7 +158,8 @@ class Interpreter {
   static llvm::Expected<std::unique_ptr<Interpreter>>
   createWithDevice(std::unique_ptr<CompilerInstance> CI,
                    std::unique_ptr<CompilerInstance> DCI,
-                   OffloadType Type = OffloadType::Detect);
+                   OffloadType Type = OffloadType::Detect,
+                   llvm::ArrayRef<const char *> DriverArgs = {});
 
   const ASTContext &getASTContext() const;
   ASTContext &getASTContext();
diff --git a/clang/lib/Interpreter/DeviceOffload.cpp 
b/clang/lib/Interpreter/DeviceOffload.cpp
index 94fec23b1c0b2f..ae254ed40aaabc 100644
--- a/clang/lib/Interpreter/DeviceOffload.cpp
+++ b/clang/lib/Interpreter/DeviceOffload.cpp
@@ -18,10 +18,18 @@
 #include "clang/CodeGen/ModuleBuilder.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Interpreter/PartialTranslationUnit.h"
+#include "clang/Options/Options.h"
 
 #include "llvm/IR/LegacyPassManager.h"
 #include "llvm/IR/Module.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/TargetParser/Triple.h"
 
@@ -42,7 +50,8 @@ IncrementalHIPDeviceParser::IncrementalHIPDeviceParser(
     CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
     IncrementalAction *DeviceAct,
     llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS,
-    llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs)
+    llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs,
+    llvm::ArrayRef<const char *> DriverArgs)
     : IncrementalDeviceParser(DeviceInstance, HostInstance, DeviceAct, FS, Err,
                               PTUs),
       DeviceCI(DeviceInstance) {
@@ -56,6 +65,33 @@ IncrementalHIPDeviceParser::IncrementalHIPDeviceParser(
             llvm::inconvertibleErrorCode()));
     return;
   }
+
+  unsigned MissingArgIndex, MissingArgCount;
+  llvm::opt::InputArgList Args = getDriverOptTable().ParseArgs(
+      DriverArgs, MissingArgIndex, MissingArgCount,
+      llvm::opt::Visibility(options::ClangOption));
+  PrefixDirs = Args.getAllArgValues(options::OPT_B);
+  LdPath = Args.getLastArgValue(options::OPT_ld_path_EQ).str();
+}
+
+static std::optional<std::string>
+findProgram(llvm::StringRef Name, llvm::ArrayRef<std::string> PrefixDirs) {
+  for (const std::string &Prefix : PrefixDirs) {
+    llvm::SmallString<128> P(Prefix);
+    if (llvm::sys::fs::is_directory(Prefix))
+      llvm::sys::path::append(P, Name);
+    else
+      P += Name;
+    if (llvm::sys::fs::can_execute(P))
+      return std::string(P);
+  }
+  std::string Exe = llvm::sys::fs::getMainExecutable(nullptr, nullptr);
+  if (llvm::ErrorOr<std::string> P = llvm::sys::findProgramByName(
+          Name, {llvm::sys::path::parent_path(Exe)}))
+    return *P;
+  if (llvm::ErrorOr<std::string> P = llvm::sys::findProgramByName(Name))
+    return *P;
+  return std::nullopt;
 }
 
 llvm::Expected<llvm::StringRef>
@@ -79,13 +115,70 @@ IncrementalHIPDeviceParser::GenerateDeviceObject() {
   return llvm::StringRef(ObjectContent.data(), ObjectContent.size());
 }
 
+llvm::Expected<llvm::StringRef>
+IncrementalHIPDeviceParser::GenerateHSACO(llvm::StringRef Object) {
+  std::optional<std::string> Linker;
+  if (LdPath.empty())
+    Linker = findProgram("lld", PrefixDirs);
+  else if (llvm::sys::path::parent_path(LdPath).empty())
+    Linker = findProgram(LdPath, PrefixDirs);
+  else if (llvm::sys::fs::can_execute(LdPath))
+    Linker = LdPath;
+  if (!Linker)
+    return llvm::make_error<llvm::StringError>(
+        LdPath.empty() ? "Could not find lld."
+                       : "Invalid linker name in argument '--ld-path=" +
+                             LdPath + "'.",
+        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 << Object;
+  }
+
+  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);
+
+  // These match the driver's HIP device link (AMDGCN::Linker) for an object.
+  llvm::StringRef Args[] = {*Linker,         "-flavor",        "gnu",
+                            "-m",            "elf64_amdgpu",   
"--no-undefined",
+                            "-shared",       "--whole-archive", "-o",
+                            HSACOFile,       ObjFile,          
"--no-whole-archive"};
+  if (llvm::sys::ExecuteAndWait(*Linker, Args) != 0)
+    return llvm::make_error<llvm::StringError>("The linker 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::GenerateOffloadBinary() {
   llvm::Expected<llvm::StringRef> Object = GenerateDeviceObject();
   if (!Object)
     return Object.takeError();
 
-  // FIXME: Link the object into an HSACO and bundle it for the host
-  // compilation.
+  llvm::Expected<llvm::StringRef> HSACO = GenerateHSACO(*Object);
+  if (!HSACO)
+    return HSACO.takeError();
+
+  // FIXME: Bundle the HSACO and embed it into the host compilation.
   return llvm::make_error<llvm::StringError>(
       "HIP offload binary generation is not supported yet.",
       llvm::inconvertibleErrorCode());
diff --git a/clang/lib/Interpreter/DeviceOffload.h 
b/clang/lib/Interpreter/DeviceOffload.h
index c01e373d5a2f94..0ed618c15893cf 100644
--- a/clang/lib/Interpreter/DeviceOffload.h
+++ b/clang/lib/Interpreter/DeviceOffload.h
@@ -47,16 +47,24 @@ class IncrementalDeviceParser : public IncrementalParser {
 class IncrementalHIPDeviceParser : public IncrementalDeviceParser {
   CompilerInstance &DeviceCI;
   llvm::SmallVector<char, 0> ObjectContent;
+  llvm::SmallVector<char, 0> HSACOContent;
+  // The -B prefixes and --ld-path value from the driver arguments.
+  std::vector<std::string> PrefixDirs;
+  std::string LdPath;
 
   // Generate the AMDGPU object file for the last PTU.
   llvm::Expected<llvm::StringRef> GenerateDeviceObject();
 
+  // Link the object file into a loadable AMDGPU code object (HSACO).
+  llvm::Expected<llvm::StringRef> GenerateHSACO(llvm::StringRef Object);
+
 public:
   IncrementalHIPDeviceParser(
       CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
       IncrementalAction *DeviceAct,
       llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS,
-      llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs);
+      llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs,
+      llvm::ArrayRef<const char *> DriverArgs);
 
   llvm::Error GenerateOffloadBinary() override;
 
diff --git a/clang/lib/Interpreter/Interpreter.cpp 
b/clang/lib/Interpreter/Interpreter.cpp
index 1fa0456f6b4ee8..c956292956cbc2 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -572,7 +572,8 @@ llvm::Expected<std::unique_ptr<Interpreter>> 
Interpreter::create(
 llvm::Expected<std::unique_ptr<Interpreter>>
 Interpreter::createWithDevice(std::unique_ptr<CompilerInstance> CI,
                               std::unique_ptr<CompilerInstance> DCI,
-                              OffloadType Type) {
+                              OffloadType Type,
+                              llvm::ArrayRef<const char *> DriverArgs) {
   if (Type == OffloadType::Detect)
     return llvm::make_error<llvm::StringError>(
         "Detecting the device vendor is not supported yet.",
@@ -618,7 +619,7 @@ 
Interpreter::createWithDevice(std::unique_ptr<CompilerInstance> CI,
   if (Type == OffloadType::HIP)
     DeviceParser = std::make_unique<IncrementalHIPDeviceParser>(
         *Interp->DeviceCI, *Interp->getCompilerInstance(),
-        Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
+        Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs, DriverArgs);
   else
     DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
         *Interp->DeviceCI, *Interp->getCompilerInstance(),
diff --git a/clang/tools/clang-repl/ClangRepl.cpp 
b/clang/tools/clang-repl/ClangRepl.cpp
index df0786796cb8ca..8fc30f874444e8 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -349,7 +349,7 @@ int main(int argc, const char **argv) {
 
   if (DeviceEnabled) {
     Interp = ExitOnErr(clang::Interpreter::createWithDevice(
-        std::move(CI), std::move(DeviceCI), OffloadKind));
+        std::move(CI), std::move(DeviceCI), OffloadKind, ClangArgv));
 
     const char *RuntimeLib = UseHip ? "libamdhip64.so" : "libcudart.so";
     if (DevicePath.empty()) {
diff --git a/clang/unittests/Interpreter/DeviceOffloadTest.cpp 
b/clang/unittests/Interpreter/DeviceOffloadTest.cpp
index fa624f23f435b7..ff3096d1f786e4 100644
--- a/clang/unittests/Interpreter/DeviceOffloadTest.cpp
+++ b/clang/unittests/Interpreter/DeviceOffloadTest.cpp
@@ -27,6 +27,8 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Support/raw_ostream.h"
@@ -156,10 +158,35 @@ TEST_F(DeviceOffloadHIPTest, DeviceObjectIsGenerated) {
 
   // FIXME: Replace this with a check of the embedded bundle once the offload
   // binary is generated.
+  std::string Exe = llvm::sys::fs::getMainExecutable(nullptr, nullptr);
+  bool HasLLD =
+      llvm::sys::findProgramByName("lld",
+                                   {llvm::sys::path::parent_path(Exe)}) ||
+      llvm::sys::findProgramByName("lld");
   auto PTU = (*Interp)->Parse("__attribute__((device)) void f() {}");
   EXPECT_THAT_EXPECTED(
-      PTU, llvm::FailedWithMessage("HIP offload binary generation is not "
-                                   "supported yet."));
+      PTU, llvm::FailedWithMessage(
+               HasLLD ? "HIP offload binary generation is not supported yet."
+                      : "Could not find lld."));
+}
+
+TEST_F(DeviceOffloadHIPTest, LdPathSelectsTheLinker) {
+  std::vector<const char *> Args = {"--offload-arch=gfx1100", "-nogpulib",
+                                    "-nogpuinc", "--ld-path=/nonexistent/lld"};
+  IncrementalCompilerBuilder CB;
+  CB.SetCompilerArgs(Args);
+  auto DeviceCI = CB.CreateDevice(OffloadType::HIP);
+  ASSERT_THAT_EXPECTED(DeviceCI, llvm::Succeeded());
+  auto HostCI = CB.CreateHost(OffloadType::HIP);
+  ASSERT_THAT_EXPECTED(HostCI, llvm::Succeeded());
+  auto Interp = Interpreter::createWithDevice(
+      std::move(*HostCI), std::move(*DeviceCI), OffloadType::HIP, Args);
+  ASSERT_THAT_EXPECTED(Interp, llvm::Succeeded());
+
+  auto PTU = (*Interp)->Parse("__attribute__((device)) void f() {}");
+  EXPECT_THAT_EXPECTED(
+      PTU, llvm::FailedWithMessage("Invalid linker name in argument "
+                                   "'--ld-path=/nonexistent/lld'."));
 }
 
 // A bitcode library with one float(float) function that doubles its argument,

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to