https://github.com/Meinersbur created 
https://github.com/llvm/llvm-project/pull/196558

Adds the version- and target-specific path

    ../lib/clang/<version>/finclude/flang/<target>

to the intrinsic module search path in addition to

    ../finclude/flang

with the former taking precedence if a module file should exist in both. The 
version/target-specific path is added by the driver by passing 
`-fintrinsic-modules-path` to the `-fc1` invocation. This is consistent with 
gfortran and the usual pattern that the driver resolves paths into the resource 
path, not the frontend.

This PR adds nothing into that directory, which will be done in #171515.

Extracted out of #171515 as requested by 
https://github.com/llvm/llvm-project/pull/171515#pullrequestreview-4179212219


>From 9a2dc9c9ab9db05fba11cd32a9457e89a3804402 Mon Sep 17 00:00:00 2001
From: Michael Kruse <[email protected]>
Date: Fri, 8 May 2026 17:12:13 +0200
Subject: [PATCH] [Flang][Driver] Add per-target search path for modules

---
 clang/include/clang/Driver/ToolChain.h        |  4 ++
 clang/lib/Driver/Driver.cpp                   | 11 ++++
 clang/lib/Driver/ToolChain.cpp                |  6 ++
 clang/lib/Driver/ToolChains/Flang.cpp         | 31 ++++++++++
 .../flang/Frontend/CompilerInvocation.h       |  7 +++
 flang/lib/Frontend/CompilerInvocation.cpp     | 14 +++++
 flang/test/Driver/Inputs/ieee_arithmetic.mod  |  1 +
 flang/test/Driver/Inputs/iso_fortran_env.mod  |  1 +
 .../basictestmoduleone.mod                    |  0
 .../flang/x86_64-unknown-linux-gnu/.keep      |  0
 .../intrinsic-module-path_per_target.f90      | 56 +++++++++++++++++++
 flang/test/Driver/use-module.f90              | 12 ++--
 flang/tools/bbc/bbc.cpp                       |  5 ++
 13 files changed, 142 insertions(+), 6 deletions(-)
 rename flang/test/Driver/Inputs/{ => module-dir-one}/basictestmoduleone.mod 
(100%)
 create mode 100644 
flang/test/Driver/Inputs/resource_dir_with_per_target_subdir/finclude/flang/x86_64-unknown-linux-gnu/.keep
 create mode 100644 flang/test/Driver/intrinsic-module-path_per_target.f90

diff --git a/clang/include/clang/Driver/ToolChain.h 
b/clang/include/clang/Driver/ToolChain.h
index 8bda212312aee..ff044722369cc 100644
--- a/clang/include/clang/Driver/ToolChain.h
+++ b/clang/include/clang/Driver/ToolChain.h
@@ -560,6 +560,10 @@ class ToolChain {
   // Returns Triple without the OSs version.
   llvm::Triple getTripleWithoutOSVersion() const;
 
+  /// Returns the target-specific path for Flang's intrinsic modules in the
+  /// resource directory if it exists.
+  std::optional<std::string> getDefaultIntrinsicModuleDir() const;
+
   // Returns the target specific runtime path if it exists.
   std::optional<std::string> getRuntimePath() const;
 
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index b9c072a0a0edb..279dc78309bef 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -6766,6 +6766,17 @@ std::string Driver::GetFilePath(StringRef Name, const 
ToolChain &TC) const {
   if (llvm::sys::fs::exists(Twine(P)))
     return std::string(P);
 
+  // With Flang, also look for intrinsic modules
+  if (IsFlangMode()) {
+    if (std::optional<std::string> IntrPath =
+            TC.getDefaultIntrinsicModuleDir()) {
+      SmallString<128> P(*IntrPath);
+      llvm::sys::path::append(P, Name);
+      if (llvm::sys::fs::exists(P))
+        return std::string(P);
+    }
+  }
+
   SmallString<128> D(Dir);
   llvm::sys::path::append(D, "..", Name);
   if (llvm::sys::fs::exists(Twine(D)))
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 996c4ab217c23..522dba348e444 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -1137,6 +1137,12 @@ ToolChain::getTargetSubDirPath(StringRef BaseDir) const {
   return {};
 }
 
+std::optional<std::string> ToolChain::getDefaultIntrinsicModuleDir() const {
+  SmallString<128> P(D.ResourceDir);
+  llvm::sys::path::append(P, "finclude", "flang");
+  return getTargetSubDirPath(P);
+}
+
 std::optional<std::string> ToolChain::getRuntimePath() const {
   SmallString<128> P(D.ResourceDir);
   llvm::sys::path::append(P, "lib");
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp 
b/clang/lib/Driver/ToolChains/Flang.cpp
index ce503b74295e4..f1204b4142163 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -1179,6 +1179,37 @@ void Flang::ConstructJob(Compilation &C, const JobAction 
&JA,
   CmdArgs.push_back("-resource-dir");
   CmdArgs.push_back(D.ResourceDir.c_str());
 
+  // Default intrinsic module dirs must be added after any user-provided
+  // -fintrinsic-modules-path to have lower precedence
+  if (std::optional<std::string> IntrModPath =
+          TC.getDefaultIntrinsicModuleDir()) {
+    CmdArgs.push_back("-fintrinsic-modules-path");
+    CmdArgs.push_back(Args.MakeArgString(*IntrModPath));
+  }
+
+  // Ideally, every target triple has its own set of builtin modules since they
+  // are compiled with platform-dependent conditionals such as `#if 
__x86_64__`.
+  // However, getting the builtin modules for offload targets requires building
+  // the flang-rt and openmp for those targets as well:
+  // -DLLVM_RUNTIME_TARGETS=default;amdgcn-amd-amdhsa;nvptx64-nvidia-cuda.
+  // To reduce friction when build systems have not yet been updated, we also
+  // add the host's builtin module to the search path (with lower priority), in
+  // case a module file has not been found for the offload targets itself.
+  // FIXME: This workaround may mix module files targeting different triples 
and
+  //        should eventually be removed.
+  auto &&HostTCs =
+      C.getOffloadToolChains<clang::driver::OffloadAction ::OFK_Host>();
+  for (auto [OKind, HostTC] : llvm::make_range(HostTCs.first, HostTCs.second)) 
{
+    if (HostTC == &TC)
+      continue;
+
+    if (std::optional<std::string> IntrModPath =
+            HostTC->getDefaultIntrinsicModuleDir()) {
+      CmdArgs.push_back("-fintrinsic-modules-path");
+      CmdArgs.push_back(Args.MakeArgString(*IntrModPath));
+    }
+  }
+
   // Offloading related options
   addOffloadOptions(C, Inputs, JA, Args, CmdArgs);
 
diff --git a/flang/include/flang/Frontend/CompilerInvocation.h 
b/flang/include/flang/Frontend/CompilerInvocation.h
index d294955af780e..feaee28a53349 100644
--- a/flang/include/flang/Frontend/CompilerInvocation.h
+++ b/flang/include/flang/Frontend/CompilerInvocation.h
@@ -92,6 +92,10 @@ class CompilerInvocation : public CompilerInvocationBase {
   // intrinsic of iso_fortran_env.
   std::string allCompilerInvocOpts;
 
+  /// Location of the resource directory containing files specific to this
+  /// instance/version of Flang.
+  std::string resourceDir;
+
   /// Semantic options
   // TODO: Merge with or translate to frontendOpts. We shouldn't need two sets
   // of options.
@@ -177,6 +181,9 @@ class CompilerInvocation : public CompilerInvocationBase {
   getSemanticsCtx(Fortran::parser::AllCookedSources &allCookedSources,
                   const llvm::TargetMachine &);
 
+  std::string &getResourceDir() { return resourceDir; }
+  const std::string &getResourceDir() const { return resourceDir; }
+
   std::string &getModuleDir() { return moduleDir; }
   const std::string &getModuleDir() const { return moduleDir; }
 
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp 
b/flang/lib/Frontend/CompilerInvocation.cpp
index e7f4762e167fb..4031cab6f6637 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1629,6 +1629,14 @@ bool CompilerInvocation::createFromArgs(
     success = false;
   }
 
+  // User-specified or default resource dir
+  if (const llvm::opt::Arg *a =
+          args.getLastArg(clang::options::OPT_resource_dir))
+    invoc.resourceDir = a->getValue();
+  else
+    invoc.resourceDir = clang::GetResourcesPath(
+        llvm::sys::fs::getMainExecutable(argv0, nullptr));
+
   // -flang-experimental-hlfir
   if (args.hasArg(clang::options::OPT_flang_experimental_hlfir) ||
       args.hasArg(clang::options::OPT_emit_hlfir)) {
@@ -1912,6 +1920,12 @@ void CompilerInvocation::setFortranOpts() {
       preprocessorOptions.searchDirectoriesFromIntrModPath.begin(),
       preprocessorOptions.searchDirectoriesFromIntrModPath.end());
 
+  // Add the ordered list of -fintrinsic-modules-path
+  fortranOptions.intrinsicModuleDirectories.insert(
+      fortranOptions.intrinsicModuleDirectories.end(),
+      preprocessorOptions.searchDirectoriesFromIntrModPath.begin(),
+      preprocessorOptions.searchDirectoriesFromIntrModPath.end());
+
   //  Add the default intrinsic module directory
   fortranOptions.intrinsicModuleDirectories.emplace_back(
       getIntrinsicDir(getArgv0()));
diff --git a/flang/test/Driver/Inputs/ieee_arithmetic.mod 
b/flang/test/Driver/Inputs/ieee_arithmetic.mod
index 30fd57801970b..264ff8d035628 100644
--- a/flang/test/Driver/Inputs/ieee_arithmetic.mod
+++ b/flang/test/Driver/Inputs/ieee_arithmetic.mod
@@ -1,5 +1,6 @@
 ! DUMMY module
 ! Added for testing purposes. The contents of this file are currently not 
relevant.
+! Using this file will cause an error because of missing checksum
 module ieee_arithmetic
 type::ieee_round_type
 integer(1),private::mode=0_1
diff --git a/flang/test/Driver/Inputs/iso_fortran_env.mod 
b/flang/test/Driver/Inputs/iso_fortran_env.mod
index 689297d52027b..c53375d78dec5 100644
--- a/flang/test/Driver/Inputs/iso_fortran_env.mod
+++ b/flang/test/Driver/Inputs/iso_fortran_env.mod
@@ -1,5 +1,6 @@
 ! DUMMY module
 ! Added for testing purposes. The contents of this file are currently not 
relevant.
+! Using this file will cause an error because of missing checksum
 module iso_fortran_env
 use __fortran_builtins,only:event_type=>__builtin_event_type
 use __fortran_builtins,only:lock_type=>__builtin_lock_type
diff --git a/flang/test/Driver/Inputs/basictestmoduleone.mod 
b/flang/test/Driver/Inputs/module-dir-one/basictestmoduleone.mod
similarity index 100%
rename from flang/test/Driver/Inputs/basictestmoduleone.mod
rename to flang/test/Driver/Inputs/module-dir-one/basictestmoduleone.mod
diff --git 
a/flang/test/Driver/Inputs/resource_dir_with_per_target_subdir/finclude/flang/x86_64-unknown-linux-gnu/.keep
 
b/flang/test/Driver/Inputs/resource_dir_with_per_target_subdir/finclude/flang/x86_64-unknown-linux-gnu/.keep
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/flang/test/Driver/intrinsic-module-path_per_target.f90 
b/flang/test/Driver/intrinsic-module-path_per_target.f90
new file mode 100644
index 0000000000000..e065508c41ba6
--- /dev/null
+++ b/flang/test/Driver/intrinsic-module-path_per_target.f90
@@ -0,0 +1,56 @@
+! Ensure argument -fintrinsic-modules-path works as expected.
+
+!-----------------------------------------
+! FLANG DRIVER
+!-----------------------------------------
+! NOTE: Depending on how Flang is built, the default intrinsics may have higher
+!       or lower priority than -fintrinsic-modules-path added here. Using
+!       basictestmoduleone.mod from Inputs/module-dir/ will trigger an error.
+
+! RUN:     %flang -fsyntax-only -resource-dir 
%S/Inputs/resource_dir_with_per_target_subdir %s -### 2>&1 | FileCheck %s 
--check-prefix=DEFAULTPATH
+
+! RUN:     %flang -fsyntax-only -resource-dir 
%S/Inputs/resource_dir_with_per_target_subdir %s -cpp -DINTRINSICS_DEFAULT
+! RUN: not %flang -fsyntax-only -resource-dir 
%S/Inputs/resource_dir_with_per_target_subdir %s -cpp -DINTRINSICS_INPUTONE 
2>&1 | FileCheck %s --check-prefix=NOINPUTONE
+! RUN: not %flang -fsyntax-only -resource-dir 
%S/Inputs/resource_dir_with_per_target_subdir %s -cpp -DINTRINSICS_INPUTTWO 
2>&1 | FileCheck %s --check-prefix=NOINPUTTWO
+! RUN:     %flang -fsyntax-only -resource-dir 
%S/Inputs/resource_dir_with_per_target_subdir %s -cpp -DINTRINSICS_DEFAULT 
-DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir/
+! RUN:     %flang -fsyntax-only -resource-dir 
%S/Inputs/resource_dir_with_per_target_subdir %s -cpp -DINTRINSICS_INPUTONE 
-fintrinsic-modules-path=%S/Inputs/module-dir-one/
+! RUN:     %flang -fsyntax-only -resource-dir 
%S/Inputs/resource_dir_with_per_target_subdir %s -cpp -DINTRINSICS_INPUTONE 
-DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir-one/ 
-fintrinsic-modules-path=%S/Inputs/module-dir/
+! RUN: not %flang -fsyntax-only -resource-dir 
%S/Inputs/resource_dir_with_per_target_subdir %s -cpp -DINTRINSICS_INPUTONE 
-DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir/ 
-fintrinsic-modules-path=%S/Inputs/module-dir-one/ 2>&1 | FileCheck %s 
--check-prefix=WRONGINPUTONE
+
+
+!-----------------------------------------
+! FLANG FRONTEND (flang -fc1)
+!-----------------------------------------
+! NOTE: %flang_cc1 the default intrinsics path always has higher priority than
+!       -fintrinsic-modules-path added here. Accidentally using
+!       ieee_arithmetic/iso_fortran_env from the Inputs/ directory will trigger
+!       an error (e.g. when the default intrinsics dir is empty).
+!       Requires the intrinsic modules to be available.
+
+! RUN:     %flang_fc1 -fsyntax-only -cpp %s -DINTRINSICS_DEFAULT
+! RUN: not %flang_fc1 -fsyntax-only -cpp %s -DINTRINSICS_DEFAULT 
-DINTRINSICS_INPUTONE 2>&1 | FileCheck %s --check-prefix=NOINPUTONE
+! RUN: not %flang_fc1 -fsyntax-only -cpp %s -DINTRINSICS_DEFAULT 
-DINTRINSICS_INPUTTWO 2>&1 | FileCheck %s --check-prefix=NOINPUTTWO
+! RUN:     %flang_fc1 -fsyntax-only -cpp %s -DINTRINSICS_DEFAULT 
-DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir/
+! RUN:     %flang_fc1 -fsyntax-only -cpp %s -DINTRINSICS_DEFAULT 
-DINTRINSICS_INPUTONE -fintrinsic-modules-path=%S/Inputs/module-dir-one/
+! RUN:     %flang_fc1 -fsyntax-only -cpp %s -DINTRINSICS_DEFAULT 
-DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO 
-fintrinsic-modules-path=%S/Inputs/module-dir-one/ 
-fintrinsic-modules-path=%S/Inputs/module-dir/
+! RUN: not %flang_fc1 -fsyntax-only -cpp %s -DINTRINSICS_DEFAULT 
-DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO 
-fintrinsic-modules-path=%S/Inputs/module-dir 
-fintrinsic-modules-path=%S/Inputs/module-dir-one/ 2>&1 | FileCheck %s 
--check-prefix=WRONGINPUTONE
+
+
+! DEFAULTPATH: flang{{.*}}-fc1{{.*}}-fintrinsic-modules-path 
+
+! NOINPUTONE: Source file 'basictestmoduleone.mod' was not found
+! NOINPUTTWO: Source file 'basictestmoduletwo.mod' was not found
+! WRONGINPUTONE: 't1' not found in module 'basictestmoduleone'
+
+program test_intrinsic_module_path
+#ifdef INTRINSICS_DEFAULT
+   use ieee_arithmetic, only: ieee_round_type
+   use iso_fortran_env, only: team_type, event_type, lock_type
+#endif
+#ifdef INTRINSICS_INPUTONE
+   use basictestmoduleone, only: t1
+#endif
+#ifdef INTRINSICS_INPUTTWO
+   use basictestmoduletwo, only: t2
+#endif
+end program
diff --git a/flang/test/Driver/use-module.f90 b/flang/test/Driver/use-module.f90
index ec650475f0b02..18ad63d2ed30f 100644
--- a/flang/test/Driver/use-module.f90
+++ b/flang/test/Driver/use-module.f90
@@ -3,9 +3,9 @@
 !--------------------------
 ! FLANG DRIVER (flang)
 !--------------------------
-! RUN: %flang -fsyntax-only -I %S/Inputs -I %S/Inputs/module-dir %s  2>&1 | 
FileCheck %s --check-prefix=INCLUDED --allow-empty
-! RUN: %flang -fsyntax-only -I %S/Inputs -J %S/Inputs/module-dir %s 2>&1 | 
FileCheck %s --check-prefix=INCLUDED --allow-empty
-! RUN: %flang -fsyntax-only -I %S/Inputs -module-dir %S/Inputs/module-dir %s  
2>&1 | FileCheck %s --check-prefix=INCLUDED --allow-empty
+! RUN: %flang -fsyntax-only -I %S/Inputs/module-dir-one -I 
%S/Inputs/module-dir %s  2>&1 | FileCheck %s --check-prefix=INCLUDED 
--allow-empty
+! RUN: %flang -fsyntax-only -I %S/Inputs/module-dir-one -J 
%S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED 
--allow-empty
+! RUN: %flang -fsyntax-only -I %S/Inputs/module-dir-one -module-dir 
%S/Inputs/module-dir %s  2>&1 | FileCheck %s --check-prefix=INCLUDED 
--allow-empty
 
 ! RUN: not %flang -fsyntax-only -I %S/Inputs %s  2>&1 | FileCheck %s 
--check-prefix=MISSING_MOD2
 ! RUN: not %flang -fsyntax-only -J %S/Inputs %s  2>&1 | FileCheck %s 
--check-prefix=MISSING_MOD2
@@ -18,9 +18,9 @@
 !-----------------------------------------
 ! FRONTEND FLANG DRIVER (flang -fc1)
 !-----------------------------------------
-! RUN: %flang_fc1 -fsyntax-only -I %S/Inputs -I %S/Inputs/module-dir %s  2>&1 
| FileCheck %s --check-prefix=INCLUDED --allow-empty
-! RUN: %flang_fc1 -fsyntax-only -I %S/Inputs -J %S/Inputs/module-dir %s 2>&1 | 
FileCheck %s --check-prefix=INCLUDED --allow-empty
-! RUN: %flang_fc1 -fsyntax-only -I %S/Inputs -module-dir %S/Inputs/module-dir 
%s  2>&1 | FileCheck %s --check-prefix=INCLUDED --allow-empty
+! RUN: %flang_fc1 -fsyntax-only -I %S/Inputs/module-dir-one -I 
%S/Inputs/module-dir %s  2>&1 | FileCheck %s --check-prefix=INCLUDED 
--allow-empty
+! RUN: %flang_fc1 -fsyntax-only -I %S/Inputs/module-dir-one -J 
%S/Inputs/module-dir %s 2>&1 | FileCheck %s --check-prefix=INCLUDED 
--allow-empty
+! RUN: %flang_fc1 -fsyntax-only -I %S/Inputs/module-dir-one -module-dir 
%S/Inputs/module-dir %s  2>&1 | FileCheck %s --check-prefix=INCLUDED 
--allow-empty
 
 ! RUN: not %flang_fc1 -fsyntax-only -I %S/Inputs %s  2>&1 | FileCheck %s 
--check-prefix=MISSING_MOD2
 ! RUN: not %flang_fc1 -fsyntax-only -J %S/Inputs %s  2>&1 | FileCheck %s 
--check-prefix=MISSING_MOD2
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index a21865f9c5ffe..227f09a4d0367 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -100,6 +100,11 @@ static llvm::cl::alias
                           llvm::cl::desc("intrinsic module directory"),
                           llvm::cl::aliasopt(intrinsicIncludeDirs));
 
+static llvm::cl::alias
+    intrinsicModulePath("fintrinsic-modules-path",
+                        llvm::cl::desc("intrinsic module search paths"),
+                        llvm::cl::aliasopt(intrinsicIncludeDirs));
+
 static llvm::cl::opt<std::string>
     moduleDir("module", llvm::cl::desc("module output directory (default .)"),
               llvm::cl::init("."));

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

Reply via email to