Author: Aditya Sinha
Date: 2026-10-21T10:01:42+03:00
New Revision: 657da1dee692fd43ba75bda19691b8ce96bbf91c

URL: 
https://github.com/llvm/llvm-project/commit/657da1dee692fd43ba75bda19691b8ce96bbf91c
DIFF: 
https://github.com/llvm/llvm-project/commit/657da1dee692fd43ba75bda19691b8ce96bbf91c.diff

LOG: [clang-repl] Added -hip option (#231783)

This PR adds a hidden `-hip` option to clang-repl, with `-rocm-path` for
the SDK location. It sets up the HIP host and device compilers and the
HIP device parser. HIP code doesn't execute yet, because binary
generation is still a stub that returns an unsupported error. That will
come in follow-up PRs.

I have also added a lit test in `clang/test/Interpreter/HIP` which runs
clang repl with the option hip and expects for not supported message for
now. This test will be removed in the future PR when the HIP kernel will
be built.

Prerequisite PR : #231391

Assisted by Claude Sonnet 5.5

Added: 
    clang/test/Interpreter/HIP/hip-not-supported.hip
    clang/test/Interpreter/HIP/lit.local.cfg

Modified: 
    clang/include/clang/Interpreter/Interpreter.h
    clang/lib/Interpreter/Interpreter.cpp
    clang/tools/clang-repl/ClangRepl.cpp
    clang/unittests/Interpreter/DeviceOffloadTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Interpreter/Interpreter.h 
b/clang/include/clang/Interpreter/Interpreter.h
index 64f02b797c204f..64dee1cf80db8d 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -69,28 +69,33 @@ class IncrementalCompilerBuilder {
   // Offload options
   void SetOffloadArch(llvm::StringRef Arch) { OffloadArch = Arch; };
 
-  // CUDA specific
-  void SetCudaSDK(llvm::StringRef path) { CudaSDKPath = path; };
+  // The SDK path (CUDA or ROCm) of the device language being offloaded to.
+  void SetDeviceSDK(llvm::StringRef Path) { DeviceSDKPath = Path; }
 
   // Hand over the compilation.
   void SetDriverCompilationCallback(std::function<DriverCompilationFn> C) {
     CompilationCB = C;
   }
 
-  llvm::Expected<std::unique_ptr<CompilerInstance>> CreateCudaHost();
-  llvm::Expected<std::unique_ptr<CompilerInstance>> CreateCudaDevice();
+  llvm::Expected<std::unique_ptr<CompilerInstance>>
+  CreateHost(OffloadType Type);
+  llvm::Expected<std::unique_ptr<CompilerInstance>>
+  CreateDevice(OffloadType Type);
 
 private:
   llvm::Expected<std::unique_ptr<CompilerInstance>>
   create(std::string TT, std::vector<const char *> &ClangArgv);
 
-  llvm::Expected<std::unique_ptr<CompilerInstance>> createCuda(bool device);
+  llvm::Expected<std::unique_ptr<CompilerInstance>>
+  createOffload(bool device, OffloadType Type = OffloadType::Detect);
 
   std::vector<const char *> UserArgs;
   std::optional<std::string> TargetTriple;
 
   llvm::StringRef OffloadArch;
-  llvm::StringRef CudaSDKPath;
+  llvm::StringRef DeviceSDKPath;
+
+  std::string OffloadCUID;
 
   std::optional<std::function<DriverCompilationFn>> CompilationCB;
 };
@@ -154,9 +159,6 @@ class Interpreter {
   createWithDevice(std::unique_ptr<CompilerInstance> CI,
                    std::unique_ptr<CompilerInstance> DCI,
                    OffloadType Type = OffloadType::Detect);
-  static llvm::Expected<std::unique_ptr<Interpreter>>
-  createWithCUDA(std::unique_ptr<CompilerInstance> CI,
-                 std::unique_ptr<CompilerInstance> DCI);
 
   const ASTContext &getASTContext() const;
   ASTContext &getASTContext();

diff  --git a/clang/lib/Interpreter/Interpreter.cpp 
b/clang/lib/Interpreter/Interpreter.cpp
index 9bd711c24be26d..40d7bb0e15f260 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -45,12 +45,14 @@
 #include "clang/Serialization/ASTReader.h"
 #include "clang/Serialization/ModuleCache.h"
 #include "clang/Serialization/ObjectFilePCHContainerReader.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ExecutionEngine/JITSymbol.h"
 #include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
 #include "llvm/ExecutionEngine/Orc/LLJIT.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Process.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/Host.h"
@@ -76,6 +78,19 @@ GetCC1Arguments(DiagnosticsEngine *Diagnostics,
                                    "Driver initialization failed. "
                                    "Unable to create a driver job");
 
+  // The driver creates one device compile job per architecture (for example if
+  // --offload-arch=native finds several GPUs). Only one can be used.
+  unsigned NumDeviceJobs = llvm::count_if(Jobs, [](const driver::Command &C) {
+    return llvm::StringRef(C.getCreator().getName()) == "clang" &&
+           llvm::is_contained(C.getArguments(),
+                              llvm::StringRef("-fcuda-is-device"));
+  });
+  if (NumDeviceJobs > 1)
+    return llvm::createStringError(
+        llvm::errc::not_supported,
+        "Multiple device architectures are not supported. Pass a single "
+        "--offload-arch");
+
   // The one job we find should be to invoke clang again.
   const driver::Command *Cmd = &*Jobs.begin();
   if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")
@@ -304,19 +319,21 @@ IncrementalCompilerBuilder::CreateCpp() {
 }
 
 llvm::Expected<std::unique_ptr<CompilerInstance>>
-IncrementalCompilerBuilder::createCuda(bool device) {
+IncrementalCompilerBuilder::createOffload(bool device, OffloadType Type) {
+  if (Type == OffloadType::Detect)
+    return llvm::make_error<llvm::StringError>(
+        "Detecting the device vendor is not supported yet.",
+        llvm::inconvertibleErrorCode());
+
+  const bool HipEnabled = Type == OffloadType::HIP;
   std::vector<const char *> Argv;
   Argv.reserve(5 + 4 + UserArgs.size());
+  Argv.push_back(HipEnabled ? "-xhip" : "-xcuda");
+  Argv.push_back(device ? "--cuda-device-only" : "--cuda-host-only");
 
-  Argv.push_back("-xcuda");
-  if (device)
-    Argv.push_back("--cuda-device-only");
-  else
-    Argv.push_back("--cuda-host-only");
-
-  std::string SDKPathArg = "--cuda-path=";
-  if (!CudaSDKPath.empty()) {
-    SDKPathArg += CudaSDKPath;
+  std::string SDKPathArg = HipEnabled ? "--rocm-path=" : "--cuda-path=";
+  if (!DeviceSDKPath.empty()) {
+    SDKPathArg += DeviceSDKPath;
     Argv.push_back(SDKPathArg.c_str());
   }
 
@@ -326,6 +343,12 @@ IncrementalCompilerBuilder::createCuda(bool device) {
     Argv.push_back(ArchArg.c_str());
   }
 
+  if (OffloadCUID.empty())
+    OffloadCUID = llvm::utohexstr(llvm::sys::Process::GetRandomNumber(),
+                                  /*LowerCase=*/true);
+  std::string CUIDArg = "-cuid=" + OffloadCUID;
+  Argv.push_back(CUIDArg.c_str());
+
   llvm::append_range(Argv, UserArgs);
 
   std::string TT = TargetTriple ? *TargetTriple : 
llvm::sys::getProcessTriple();
@@ -333,13 +356,13 @@ IncrementalCompilerBuilder::createCuda(bool device) {
 }
 
 llvm::Expected<std::unique_ptr<CompilerInstance>>
-IncrementalCompilerBuilder::CreateCudaDevice() {
-  return IncrementalCompilerBuilder::createCuda(true);
+IncrementalCompilerBuilder::CreateDevice(OffloadType Type) {
+  return IncrementalCompilerBuilder::createOffload(/*device=*/true, Type);
 }
 
 llvm::Expected<std::unique_ptr<CompilerInstance>>
-IncrementalCompilerBuilder::CreateCudaHost() {
-  return IncrementalCompilerBuilder::createCuda(false);
+IncrementalCompilerBuilder::CreateHost(OffloadType Type) {
+  return IncrementalCompilerBuilder::createOffload(/*device=*/false, Type);
 }
 
 Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
@@ -476,12 +499,6 @@ llvm::Expected<std::unique_ptr<Interpreter>> 
Interpreter::create(
   return std::move(Interp);
 }
 
-llvm::Expected<std::unique_ptr<Interpreter>>
-Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,
-                            std::unique_ptr<CompilerInstance> DCI) {
-  return createWithDevice(std::move(CI), std::move(DCI), OffloadType::CUDA);
-}
-
 llvm::Expected<std::unique_ptr<Interpreter>>
 Interpreter::createWithDevice(std::unique_ptr<CompilerInstance> CI,
                               std::unique_ptr<CompilerInstance> DCI,

diff  --git a/clang/test/Interpreter/HIP/hip-not-supported.hip 
b/clang/test/Interpreter/HIP/hip-not-supported.hip
new file mode 100644
index 00000000000000..5e6f7d9035b348
--- /dev/null
+++ b/clang/test/Interpreter/HIP/hip-not-supported.hip
@@ -0,0 +1,10 @@
+// Check that clang-repl sets up the HIP environment but reports that HIP
+// offload binary generation is not supported yet. An explicit --offload-arch
+// is passed so the test does not rely on GPU auto-detection. No device code
+// is run, so the architecture is arbitrary.
+// FIXME: Replace this with real HIP execution tests once the HIP device parser
+// can generate offload binaries.
+
+// RUN: not clang-repl -hip --offload-arch=gfx1100 "__attribute__((device)) 
void f() {}" 2>&1 | FileCheck %s --implicit-check-not=error:
+
+// CHECK: error: HIP offload binary generation is not supported yet.

diff  --git a/clang/test/Interpreter/HIP/lit.local.cfg 
b/clang/test/Interpreter/HIP/lit.local.cfg
new file mode 100644
index 00000000000000..cc84168b237130
--- /dev/null
+++ b/clang/test/Interpreter/HIP/lit.local.cfg
@@ -0,0 +1,12 @@
+import ctypes
+
+if "host-supports-jit" not in config.available_features:
+    config.unsupported = True
+elif "amdgpu-registered-target" not in config.available_features:
+    config.unsupported = True
+else:
+    # clang-repl loads the HIP runtime on startup, so it must be available.
+    try:
+        ctypes.CDLL("libamdhip64.so")
+    except OSError:
+        config.unsupported = True

diff  --git a/clang/tools/clang-repl/ClangRepl.cpp 
b/clang/tools/clang-repl/ClangRepl.cpp
index c9873540a5d66b..6d632a9e3e26a8 100644
--- a/clang/tools/clang-repl/ClangRepl.cpp
+++ b/clang/tools/clang-repl/ClangRepl.cpp
@@ -53,6 +53,8 @@ LLVM_ATTRIBUTE_USED int __lsan_is_turned_off() { return 1; }
 #define DEBUG_TYPE "clang-repl"
 
 static llvm::cl::opt<bool> CudaEnabled("cuda", llvm::cl::Hidden);
+static llvm::cl::opt<bool> HipEnabled("hip", llvm::cl::Hidden);
+static llvm::cl::opt<std::string> RocmPath("rocm-path", llvm::cl::Hidden);
 static llvm::cl::opt<std::string> CudaPath("cuda-path", llvm::cl::Hidden);
 static llvm::cl::opt<std::string> OffloadArch("offload-arch", 
llvm::cl::Hidden);
 static llvm::cl::OptionCategory OOPCategory("Out-of-process Execution 
Options");
@@ -310,24 +312,33 @@ int main(int argc, const char **argv) {
   IEB->SlabAllocateSize = *SizeOrErr;
   IEB->UseSharedMemory = UseSharedMemory;
 
-  std::unique_ptr<clang::CompilerInstance> DeviceCI;
-  if (CudaEnabled) {
-    if (!CudaPath.empty())
-      CB.SetCudaSDK(CudaPath);
+  // If both -cuda and -hip are passed, the one that appears later wins.
+  // FIXME: Support both CUDA and HIP setups at the same time, for example with
+  // one interpreter per device language in a multi-interpreter setup.
+  bool UseHip = HipEnabled && (!CudaEnabled || HipEnabled.getPosition() >
+                                                   CudaEnabled.getPosition());
+  bool DeviceEnabled = HipEnabled || CudaEnabled;
 
-    if (OffloadArch.empty()) {
-      OffloadArch = "sm_35";
-    }
-    CB.SetOffloadArch(OffloadArch);
+  clang::OffloadType OffloadKind =
+      UseHip ? clang::OffloadType::HIP : clang::OffloadType::CUDA;
+  std::string DevicePath = UseHip ? RocmPath : CudaPath;
+  llvm::StringRef DeviceOffloadArch = !OffloadArch.empty()
+                                          ? llvm::StringRef(OffloadArch)
+                                          : (UseHip ? "native" : "sm_35");
+
+  std::unique_ptr<clang::CompilerInstance> DeviceCI;
 
-    DeviceCI = ExitOnErr(CB.CreateCudaDevice());
+  if (DeviceEnabled) {
+    CB.SetDeviceSDK(DevicePath);
+    CB.SetOffloadArch(DeviceOffloadArch);
+    DeviceCI = ExitOnErr(CB.CreateDevice(OffloadKind));
   }
 
   // FIXME: Investigate if we could use runToolOnCodeWithArgs from tooling. It
   // can replace the boilerplate code for creation of the compiler instance.
   std::unique_ptr<clang::CompilerInstance> CI;
-  if (CudaEnabled) {
-    CI = ExitOnErr(CB.CreateCudaHost());
+  if (DeviceEnabled) {
+    CI = ExitOnErr(CB.CreateHost(OffloadKind));
   } else {
     CI = ExitOnErr(CB.CreateCpp());
   }
@@ -339,20 +350,21 @@ int main(int argc, const char **argv) {
 
   // Load any requested plugins.
   CI->LoadRequestedPlugins();
-  if (CudaEnabled)
+  if (DeviceEnabled)
     DeviceCI->LoadRequestedPlugins();
 
   std::unique_ptr<clang::Interpreter> Interp;
 
-  if (CudaEnabled) {
-    Interp = ExitOnErr(
-        clang::Interpreter::createWithCUDA(std::move(CI), 
std::move(DeviceCI)));
+  if (DeviceEnabled) {
+    Interp = ExitOnErr(clang::Interpreter::createWithDevice(
+        std::move(CI), std::move(DeviceCI), OffloadKind));
 
-    if (CudaPath.empty()) {
-      ExitOnErr(Interp->LoadDynamicLibrary("libcudart.so"));
+    const char *RuntimeLib = UseHip ? "libamdhip64.so" : "libcudart.so";
+    if (DevicePath.empty()) {
+      ExitOnErr(Interp->LoadDynamicLibrary(RuntimeLib));
     } else {
-      auto CudaRuntimeLibPath = CudaPath + "/lib/libcudart.so";
-      ExitOnErr(Interp->LoadDynamicLibrary(CudaRuntimeLibPath.c_str()));
+      std::string RuntimeLibPath = DevicePath + "/lib/" + RuntimeLib;
+      ExitOnErr(Interp->LoadDynamicLibrary(RuntimeLibPath.c_str()));
     }
   } else {
     Interp =

diff  --git a/clang/unittests/Interpreter/DeviceOffloadTest.cpp 
b/clang/unittests/Interpreter/DeviceOffloadTest.cpp
index 039c919fe1e1e0..f3b7ddf837cde7 100644
--- a/clang/unittests/Interpreter/DeviceOffloadTest.cpp
+++ b/clang/unittests/Interpreter/DeviceOffloadTest.cpp
@@ -62,10 +62,10 @@ TEST_F(DeviceOffloadTest, FirstDeviceModuleVerifies) {
         IncrementalCompilerBuilder CB;
         CB.SetCompilerArgs(
             {"-nocudainc", "-nocudalib", "-fverify-intermediate-code"});
-        auto DeviceCI = llvm::cantFail(CB.CreateCudaDevice());
-        auto HostCI = llvm::cantFail(CB.CreateCudaHost());
-        auto Interp = llvm::cantFail(Interpreter::createWithCUDA(
-            std::move(HostCI), std::move(DeviceCI)));
+        auto DeviceCI = llvm::cantFail(CB.CreateDevice(OffloadType::CUDA));
+        auto HostCI = llvm::cantFail(CB.CreateHost(OffloadType::CUDA));
+        auto Interp = llvm::cantFail(Interpreter::createWithDevice(
+            std::move(HostCI), std::move(DeviceCI), OffloadType::CUDA));
         llvm::cantFail(Interp->Parse("__attribute__((device)) void f() {}"));
         exit(0);
       },
@@ -79,12 +79,12 @@ TEST_F(DeviceOffloadTest, EmptyDeviceModule) {
   // Without the runtime headers and libdevice no CUDA toolkit is needed.
   IncrementalCompilerBuilder CB;
   CB.SetCompilerArgs({"-nocudainc", "-nocudalib"});
-  auto DeviceCI = CB.CreateCudaDevice();
+  auto DeviceCI = CB.CreateDevice(OffloadType::CUDA);
   ASSERT_THAT_EXPECTED(DeviceCI, llvm::Succeeded());
-  auto HostCI = CB.CreateCudaHost();
+  auto HostCI = CB.CreateHost(OffloadType::CUDA);
   ASSERT_THAT_EXPECTED(HostCI, llvm::Succeeded());
-  auto Interp =
-      Interpreter::createWithCUDA(std::move(*HostCI), std::move(*DeviceCI));
+  auto Interp = Interpreter::createWithDevice(
+      std::move(*HostCI), std::move(*DeviceCI), OffloadType::CUDA);
   ASSERT_THAT_EXPECTED(Interp, llvm::Succeeded());
 
   // A host-only input leaves the device module without a function. Its PTX
@@ -101,4 +101,17 @@ TEST_F(DeviceOffloadTest, EmptyDeviceModule) {
   EXPECT_TRUE((*Buf)->getBuffer().contains(".target"));
 }
 
+TEST(DeviceOffloadBuilderTest, MultipleOffloadArchsAreRejected) {
+  // The driver creates one compile job per architecture. Only one can be used,
+  // so this must be reported instead of silently using the first one.
+  IncrementalCompilerBuilder CB;
+  CB.SetCompilerArgs({"--offload-arch=gfx1100", "--offload-arch=gfx90a",
+                      "-nogpulib", "-nogpuinc"});
+  auto DeviceCI = CB.CreateDevice(OffloadType::HIP);
+  EXPECT_THAT_EXPECTED(
+      DeviceCI,
+      llvm::FailedWithMessage("Multiple device architectures are not "
+                              "supported. Pass a single --offload-arch"));
+}
+
 } // end anonymous namespace


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

Reply via email to