https://github.com/macurtis-amd created 
https://github.com/llvm/llvm-project/pull/215532

When linking with `-fopenmp`, `-fopenmp-implicit-rpath` records rpath entries 
for the libomp runtime, rather than relying on the runtime being on the default 
loader search path. Runtimes selected via `-fopenmp=` are unaffected, as they 
are not shipped alongside the compiler.

Feature is off by default (i.e. `-fno-openmp-implicit-rpath`).

`-fopenmp-runtimelib={lib,lib-perf,lib-debug}` is also added which selects an 
alternate runtime build and is reflected in the rpath. The selected directory 
is added unconditionally; if it is not present, `lib` is added as well, rather 
than in its place.

`-fopenmp-runtimelib` is ignored, and its argument is not validated, unless 
`-fopenmp-implicit-rpath` is also specified.

>From 32363d00d57c8ba50953e6cf90fae090b87bcc5e Mon Sep 17 00:00:00 2001
From: Matthew Curtis <[email protected]>
Date: Mon, 10 Aug 2026 14:11:59 -0500
Subject: [PATCH] [clang][Driver][OpenMP] Add -f[no-]openmp-implicit-rpath flag

When linking with `-fopenmp`, `-fopenmp-implicit-rpath` records rpath entries
for the libomp runtime, rather than relying on the runtime being on the default
loader search path. Runtimes selected via `-fopenmp=` are unaffected, as they
are not shipped alongside the compiler.

Feature is off by default (i.e. `-fno-openmp-implicit-rpath`).

`-fopenmp-runtimelib={lib,lib-perf,lib-debug}` is also added which selects an
alternate runtime build and is reflected in the rpath. The selected directory
is added unconditionally; if it is not present, `lib` is added as well, rather
than in its place.

`-fopenmp-runtimelib` is ignored, and its argument is not validated, unless
`-fopenmp-implicit-rpath` is also specified.

Co-authored-by: Cursor <[email protected]>
---
 clang/include/clang/Driver/CommonArgs.h    |  3 +
 clang/include/clang/Options/Options.td     |  8 +++
 clang/lib/Driver/ToolChains/CommonArgs.cpp | 79 ++++++++++++++++++++++
 clang/test/Driver/openmp-runtimelib.c      | 51 ++++++++++++++
 4 files changed, 141 insertions(+)
 create mode 100644 clang/test/Driver/openmp-runtimelib.c

diff --git a/clang/include/clang/Driver/CommonArgs.h 
b/clang/include/clang/Driver/CommonArgs.h
index 01e358a1d0717..166e093f3e5a4 100644
--- a/clang/include/clang/Driver/CommonArgs.h
+++ b/clang/include/clang/Driver/CommonArgs.h
@@ -143,6 +143,9 @@ void AddAssemblerKPIC(const ToolChain &ToolChain,
                       const llvm::opt::ArgList &Args,
                       llvm::opt::ArgStringList &CmdArgs);
 
+void addOpenMPRuntimeSpecificRPath(const ToolChain &TC,
+                                   const llvm::opt::ArgList &Args,
+                                   llvm::opt::ArgStringList &CmdArgs);
 void addArchSpecificRPath(const ToolChain &TC, const llvm::opt::ArgList &Args,
                           llvm::opt::ArgStringList &CmdArgs);
 void addOpenMPRuntimeLibraryPath(const ToolChain &TC,
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index b354a475346df..968d0402b5bf3 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4208,6 +4208,10 @@ def fopenmp_cuda_teams_reduction_recs_num_EQ : 
Joined<["-"], "fopenmp-cuda-teams
            "teams; this flag is accepted for backwards compatibility only "
            "and emits a deprecation warning when used.">;
 
+def fopenmp_runtimelib_EQ : Joined<["-"], "fopenmp-runtimelib=">, 
Group<f_Group>, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, 
Flags<[NoArgumentUnused]>,
+  HelpText<"Select lib, lib-perf, or lib-debug openmp runtime"
+           " <arg> must be: lib, lib-perf or lib-debug.">;
+
 
//===----------------------------------------------------------------------===//
 // Shared cc1 + fc1 OpenMP Target Options
 
//===----------------------------------------------------------------------===//
@@ -6742,6 +6746,10 @@ def no_offload_add_rpath: Flag<["--"], 
"no-offload-add-rpath">,
   Alias<frtlib_add_rpath>;
 def r : Flag<["-"], "r">, Flags<[LinkerInput, NoArgumentUnused]>,
         Group<Link_Group>;
+defm openmp_implicit_rpath : BoolOptionWithoutMarshalling<"f", 
"openmp-implicit-rpath",
+  PosFlag<SetTrue, [], [ClangOption], "Set rpath implicitly on OpenMP 
executables">,
+  NegFlag<SetFalse, [], [ClangOption], "Do not set rpath implicitly on OpenMP 
executables">,
+  BothFlags<[NoArgumentUnused]>>, Group<f_Group>;
 def regcall4 : Flag<["-"], "regcall4">, Group<m_Group>,
   Visibility<[ClangOption, CC1Option]>,
   HelpText<"Set __regcall4 as a default calling convention to respect 
__regcall ABI v.4">,
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp 
b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 883296e43111b..0e462b92a514f 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -68,6 +68,23 @@ using namespace clang::driver::tools;
 using namespace clang;
 using namespace llvm::opt;
 
+static bool addRPathCmdArg(const llvm::opt::ArgList &Args,
+                           ArgStringList &CmdArgs,
+                           const std::string pathCandidate,
+                           bool onlyIfPathExists = true) {
+  SmallString<0> simplifiedPathCandidate(pathCandidate);
+  llvm::sys::path::remove_dots(simplifiedPathCandidate, true);
+
+  bool pathExists = llvm::sys::fs::exists(simplifiedPathCandidate);
+
+  if (onlyIfPathExists && !pathExists)
+    return false;
+
+  CmdArgs.push_back("-rpath");
+  CmdArgs.push_back(Args.MakeArgString(simplifiedPathCandidate));
+  return pathExists;
+}
+
 OffloadJobsOpt tools::parseOffloadJobs(const ArgList &Args) {
   Arg *A = Args.getLastArg(options::OPT_offload_jobs_EQ);
   if (!A)
@@ -1452,6 +1469,65 @@ void tools::addLTOOptions(const ToolChain &ToolChain, 
const ArgList &Args,
   addDTLTOOptions(ToolChain, Args, CmdArgs);
 }
 
+void tools::addOpenMPRuntimeSpecificRPath(const ToolChain &TC,
+                                          const ArgList &Args,
+                                          ArgStringList &CmdArgs) {
+  if (!Args.hasFlag(options::OPT_fopenmp_implicit_rpath,
+                    options::OPT_fno_openmp_implicit_rpath, false))
+    return;
+
+  const Driver &D = TC.getDriver();
+  std::string LibSuffix = "lib";
+  if (TC.getSanitizerArgs(Args).needsAsanRt())
+    LibSuffix.append("/asan");
+  if (Arg *A = Args.getLastArg(options::OPT_fopenmp_runtimelib_EQ)) {
+    LibSuffix = A->getValue();
+    if (LibSuffix != "lib-perf" && LibSuffix != "lib-debug" &&
+        LibSuffix != "lib")
+      D.Diag(diag::err_drv_unsupported_option_argument)
+          << A->getSpelling() << LibSuffix;
+    if (TC.getSanitizerArgs(Args).needsAsanRt())
+      LibSuffix.append("/asan");
+  }
+
+  // Add an rpath entry for each existing LIBRARY_PATH directory.
+  ArgStringList EnvLibraryPaths;
+  addDirectoryList(Args, EnvLibraryPaths, "", "LIBRARY_PATH");
+  for (auto &EnvLibraryPath : EnvLibraryPaths)
+    addRPathCmdArg(Args, CmdArgs, EnvLibraryPath);
+
+  // Default to clang lib / lib64 folder, i.e. the same location as device
+  // runtime
+  SmallString<256> DefaultLibPath =
+      llvm::sys::path::parent_path(TC.getDriver().Dir);
+  llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
+  if (TC.getSanitizerArgs(Args).needsAsanRt())
+    addRPathCmdArg(Args, CmdArgs, TC.getCompilerRTPath(),
+                   /*onlyIfPathExists=*/false);
+
+  // In case LibSuffix was not built, try lib
+  std::string CandidateRPath_suf = D.Dir + "/../" + LibSuffix;
+  // Add lib directory in case LibSuffix does not exist
+  std::string CandidateRPath_lib = D.Dir + "/../lib";
+  if (!addRPathCmdArg(Args, CmdArgs, CandidateRPath_suf,
+                      /*onlyIfPathExists=*/false))
+    addRPathCmdArg(Args, CmdArgs, CandidateRPath_lib);
+
+  std::string rocmPath =
+      Args.getLastArgValue(clang::options::OPT_rocm_path_EQ).str();
+  if (rocmPath.size() != 0) {
+    std::string rocmPath_lib = rocmPath + "/lib";
+    std::string rocmPath_suf = rocmPath + "/" + LibSuffix;
+    if (!addRPathCmdArg(Args, CmdArgs, rocmPath_suf))
+      addRPathCmdArg(Args, CmdArgs, rocmPath_lib);
+  }
+
+  // Add Default lib path to ensure llvm dynamic library is picked up for
+  // lib-debug/lib-perf
+  if (LibSuffix != "lib")
+    addRPathCmdArg(Args, CmdArgs, DefaultLibPath.c_str());
+}
+
 void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC,
                                         const ArgList &Args,
                                         ArgStringList &CmdArgs) {
@@ -1538,6 +1614,9 @@ bool tools::addOpenMPRuntime(const Compilation &C, 
ArgStringList &CmdArgs,
 
   addArchSpecificRPath(TC, Args, CmdArgs);
 
+  if (RTKind == Driver::OMPRT_OMP)
+    addOpenMPRuntimeSpecificRPath(TC, Args, CmdArgs);
+
   addOpenMPRuntimeLibraryPath(TC, Args, CmdArgs);
 
   return true;
diff --git a/clang/test/Driver/openmp-runtimelib.c 
b/clang/test/Driver/openmp-runtimelib.c
new file mode 100644
index 0000000000000..2d7d09029d050
--- /dev/null
+++ b/clang/test/Driver/openmp-runtimelib.c
@@ -0,0 +1,51 @@
+// REQUIRES: amdgpu-registered-target
+
+// RUN:  %clang -### -fopenmp -nogpuinc -nogpulib  --offload-arch=gfx90a 
-fopenmp-implicit-rpath -fopenmp-runtimelib=lib-debug %s -O3 2>&1 \
+// RUN:   | FileCheck -check-prefixes=Debug,Debug-Rel %s
+
+// RUN: %clang -### -fopenmp -nogpuinc -nogpulib  --offload-arch=gfx90a 
-fopenmp-implicit-rpath -fopenmp-runtimelib=lib-perf %s -O3 2>&1 \
+// RUN:   | FileCheck -check-prefixes=Perf,Perf-Rel %s
+
+// RUN: %clang -### -fopenmp -nogpuinc -nogpulib  --offload-arch=gfx90a 
-fopenmp-implicit-rpath -fopenmp-runtimelib=lib %s -O3 2>&1 \
+// RUN:   | FileCheck -check-prefixes=Devel,Devel-Rel %s
+
+// RUN: not %clang -### -fopenmp -nogpuinc -nogpulib  --offload-arch=gfx90a 
-fopenmp-implicit-rpath -fopenmp-runtimelib=oopsy %s -O3 2>&1 \
+// RUN:   | FileCheck -check-prefixes=Error %s
+
+// RUN: %clang -### -fopenmp -nogpuinc -nogpulib  --offload-arch=gfx90a:xnack+ 
-fopenmp-implicit-rpath -fopenmp-runtimelib=lib-debug -fsanitize=address 
-shared-libasan %s -O3 2>&1 \
+// RUN:   | FileCheck -check-prefixes=Asan-Debug,Asan-Debug-Rel %s
+
+// RUN: %clang -### -fopenmp -nogpuinc -nogpulib  --offload-arch=gfx90a:xnack+ 
-fopenmp-implicit-rpath -fopenmp-runtimelib=lib -fsanitize=address 
-shared-libasan %s -O3 2>&1 \
+// RUN:   | FileCheck -check-prefixes=Asan-Devel,Asan-Devel-Rel %s
+
+// RUN: %clang -### -fopenmp -nogpuinc -nogpulib  --offload-arch=gfx90a:xnack+ 
-fopenmp-implicit-rpath -fopenmp-runtimelib=lib-perf -fsanitize=address 
-shared-libasan %s -O3 2>&1 \
+// RUN:   | FileCheck -check-prefixes=Asan-Perf,Asan-Perf-Rel %s
+
+// RUN: %clang -### -fopenmp -nogpuinc -nogpulib  --offload-arch=gfx90a 
-fno-openmp-implicit-rpath %s -O3 2>&1 \
+// RUN:   | FileCheck -check-prefixes=No-Rpath %s
+
+// Default is -fno-openmp-implicit-rpath
+// RUN: %clang -### -fopenmp -nogpuinc -nogpulib  --offload-arch=gfx90a %s -O3 
2>&1 \
+// RUN:   | FileCheck -check-prefixes=No-Rpath %s
+
+// Devel: "-rpath" "{{[^"]*}}[[LIB:(/|\\\\)lib]]"
+// Devel-Rel-NOT: "-rpath" "{{[^"]*(/|\\\\)\.\.}}[[LIB]]"
+
+// Debug: "-rpath" "{{[^"]*}}[[LIB:(/|\\\\)lib-debug]]"
+// Debug-Rel-NOT: "-rpath" "{{[^"]*(/|\\\\)\.\.}}[[LIB]]"
+
+// Perf: "-rpath" "{{[^"]*}}[[LIB:(/|\\\\)lib-perf]]"
+// Perf-Rel-NOT: "-rpath" "{{[^"]*(/|\\\\)\.\.}}[[LIB]]"
+
+// Asan-Devel: "-rpath" "{{[^"]*}}[[LIB:(/|\\\\)lib(/|\\\\)asan]]"
+// Asan-Devel-Rel-NOT: "-rpath" "{{[^"]*(/|\\\\)\.\.}}[[LIB]]"
+
+// Asan-Debug: "-rpath" "{{[^"]*}}[[LIB:(/|\\\\)lib-debug(/|\\\\)asan]]"
+// Asan-Debug-Rel-NOT: "-rpath" "{{[^"]*(/|\\\\)\.\.}}[[LIB]]"
+
+// Asan-Perf: "-rpath" "{{[^"]*}}[[LIB:(/|\\\\)lib-perf(/|\\\\)asan]]"
+// Asan-Perf-Rel-NOT: "-rpath" "{{[^"]*(/|\\\\)\.\.}}[[LIB]]"
+
+// No-Rpath-NOT: "-rpath"
+
+// Error: clang: error: unsupported argument 'oopsy' to option 
'-fopenmp-runtimelib='

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

Reply via email to