[libcxx-commits] [clang] [compiler-rt] [flang] [libc] [libcxx] [libcxxabi] [libunwind] [llvm] [openmp] [Flang] Move builtin .mod generation into runtimes (Reapply #137828) (PR #171515)

Michael Kruse via libcxx-commits libcxx-commits at lists.llvm.org
Fri Apr 24 15:01:15 PDT 2026


https://github.com/Meinersbur updated https://github.com/llvm/llvm-project/pull/171515

>From 53fadc278a219bf616dfe3f9ef23651938f70891 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Tue, 9 Dec 2025 22:51:48 +0100
Subject: [PATCH 01/53] Reapply "[Flang] Move builtin .mod generation into
 runtimes (Reapply #137828)"

This reverts commit d233e787f0adfa2acd2e6c67aa2c362f9cf47ab4.
---
 clang/include/clang/Driver/ToolChain.h        |   4 +
 clang/include/clang/Options/Options.td        |   2 +-
 clang/lib/Driver/Driver.cpp                   |  11 +
 clang/lib/Driver/ToolChain.cpp                |   6 +
 clang/lib/Driver/ToolChains/AMDGPU.cpp        |   3 +-
 clang/lib/Driver/ToolChains/Flang.cpp         |   8 +
 clang/lib/Driver/ToolChains/HIPAMD.cpp        |   3 +-
 clang/lib/Driver/ToolChains/HIPSPV.cpp        |   3 +-
 .../Modules}/GetToolchainDirs.cmake           |  11 +
 flang-rt/CMakeLists.txt                       | 122 ++-----
 flang-rt/cmake/modules/AddFlangRT.cmake       |  38 ++-
 .../cmake/modules/AddFlangRTOffload.cmake     |  15 +-
 .../cmake/modules/FlangRTIntrospection.cmake  |  36 +++
 flang-rt/lib/CMakeLists.txt                   |  15 +-
 flang-rt/lib/runtime/CMakeLists.txt           | 173 +++++++---
 .../lib/runtime}/__cuda_builtins.f90          |   0
 .../lib/runtime}/__cuda_device.f90            |   0
 .../lib/runtime}/__fortran_builtins.f90       |   2 +-
 .../runtime}/__fortran_ieee_exceptions.f90    |   2 +-
 .../lib/runtime}/__fortran_type_info.f90      |   0
 .../lib/runtime}/__ppc_intrinsics.f90         |   0
 .../lib/runtime}/__ppc_types.f90              |   0
 .../lib/runtime}/cooperative_groups.f90       |   1 +
 .../lib/runtime}/cudadevice.f90               |   0
 .../lib/runtime}/flang_debug.f90              |   0
 .../lib/runtime}/ieee_arithmetic.f90          |   2 +-
 .../lib/runtime}/ieee_exceptions.f90          |   0
 .../lib/runtime}/ieee_features.f90            |   0
 .../lib/runtime}/iso_c_binding.f90            |   0
 .../lib/runtime}/iso_fortran_env.f90          |   2 +-
 .../lib/runtime}/iso_fortran_env_impl.f90     |   0
 .../module => flang-rt/lib/runtime}/mma.f90   |   0
 flang-rt/test/lit.site.cfg.py.in              |   2 +-
 flang-rt/unittests/CMakeLists.txt             |   5 +-
 flang/CMakeLists.txt                          |   1 -
 .../flang/Frontend/CompilerInvocation.h       |   7 +
 flang/lib/Frontend/CompilerInvocation.cpp     |  26 +-
 flang/lib/Semantics/semantics.cpp             |  13 +-
 flang/module/.clang-format                    |   1 -
 flang/test/CMakeLists.txt                     |  31 +-
 flang/test/Driver/Inputs/ieee_arithmetic.mod  |   1 +
 flang/test/Driver/Inputs/iso_fortran_env.mod  |   1 +
 flang/test/Driver/intrinsic-module-path.F90   |  55 ++++
 flang/test/Driver/intrinsic-module-path.f90   |  23 --
 flang/test/Driver/lto-fatlto.f90              |   4 +-
 flang/test/Driver/pp-fixed-form.f90           |   4 +-
 .../Lower/HLFIR/type-bound-call-mismatch.f90  |   2 +-
 flang/test/Lower/OpenMP/simd_aarch64.f90      |   7 +-
 .../target-enter-data-default-openmp52.f90    |   4 +-
 flang/test/Preprocessing/fixed-free.f         |   2 +-
 flang/test/Preprocessing/no-pp-if.f90         |   2 +-
 flang/test/Semantics/bug163242.f90            |   2 +-
 flang/test/Semantics/bug164303.f90            |   2 +-
 flang/test/lit.cfg.py                         |  94 +++++-
 flang/test/lit.site.cfg.py.in                 |   9 +-
 flang/tools/CMakeLists.txt                    |   1 -
 flang/tools/bbc/bbc.cpp                       |  13 +-
 flang/tools/f18/CMakeLists.txt                | 171 ----------
 flang/tools/f18/dump.cpp                      |  42 ---
 llvm/runtimes/CMakeLists.txt                  |  24 +-
 openmp/CMakeLists.txt                         |  11 +-
 openmp/README.rst                             |   7 +-
 .../modules/LibompCheckFortranFlag.cmake      |  29 --
 openmp/cmake/modules/LibompHandleFlags.cmake  |  11 -
 openmp/module/CMakeLists.txt                  |  89 ++---
 openmp/runtime/CMakeLists.txt                 |   2 +-
 openmp/runtime/cmake/LibompExports.cmake      |  10 +-
 openmp/runtime/test/lit.cfg                   |   1 +
 openmp/runtime/test/lit.site.cfg.in           |   1 +
 runtimes/CMakeLists.txt                       | 303 +++++++++++++++++-
 70 files changed, 877 insertions(+), 595 deletions(-)
 rename {flang-rt/cmake/modules => cmake/Modules}/GetToolchainDirs.cmake (94%)
 create mode 100644 flang-rt/cmake/modules/FlangRTIntrospection.cmake
 rename {flang/module => flang-rt/lib/runtime}/__cuda_builtins.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/__cuda_device.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/__fortran_builtins.f90 (99%)
 rename {flang/module => flang-rt/lib/runtime}/__fortran_ieee_exceptions.f90 (98%)
 rename {flang/module => flang-rt/lib/runtime}/__fortran_type_info.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/__ppc_intrinsics.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/__ppc_types.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/cooperative_groups.f90 (96%)
 rename {flang/module => flang-rt/lib/runtime}/cudadevice.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/flang_debug.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/ieee_arithmetic.f90 (99%)
 rename {flang/module => flang-rt/lib/runtime}/ieee_exceptions.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/ieee_features.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/iso_c_binding.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/iso_fortran_env.f90 (98%)
 rename {flang/module => flang-rt/lib/runtime}/iso_fortran_env_impl.f90 (100%)
 rename {flang/module => flang-rt/lib/runtime}/mma.f90 (100%)
 delete mode 100644 flang/module/.clang-format
 create mode 100644 flang/test/Driver/intrinsic-module-path.F90
 delete mode 100644 flang/test/Driver/intrinsic-module-path.f90
 delete mode 100644 flang/tools/f18/CMakeLists.txt
 delete mode 100644 flang/tools/f18/dump.cpp
 delete mode 100644 openmp/cmake/modules/LibompCheckFortranFlag.cmake

diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h
index 1425714d34110..26af88242eb3e 100644
--- a/clang/include/clang/Driver/ToolChain.h
+++ b/clang/include/clang/Driver/ToolChain.h
@@ -538,6 +538,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/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index cac122d296624..90fc78db45d05 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -6124,7 +6124,7 @@ def prebind : Flag<["-"], "prebind">;
 def preload : Flag<["-"], "preload">;
 def print_file_name_EQ : Joined<["-", "--"], "print-file-name=">,
   HelpText<"Print the full library path of <file>">, MetaVarName<"<file>">,
-  Visibility<[ClangOption, CLOption]>;
+  Visibility<[ClangOption, FlangOption, CLOption]>;
 def print_ivar_layout : Flag<["-"], "print-ivar-layout">,
   Visibility<[ClangOption, CC1Option]>,
   HelpText<"Enable Objective-C Ivar layout bitmap print trace">,
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 8644a271a04b5..6f0d8078825de 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -6607,6 +6607,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 instrinsic 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(Twine(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 77a2c73f0d446..f8520725b9b03 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -1020,6 +1020,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/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp
index 87ccd40372681..d3515c8fa2362 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -858,7 +858,8 @@ void AMDGPUToolChain::addClangTargetOptions(
   // Default to "hidden" visibility, as object level linking will not be
   // supported for the foreseeable future.
   if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
-                         options::OPT_fvisibility_ms_compat)) {
+                         options::OPT_fvisibility_ms_compat) &&
+      !getDriver().IsFlangMode()) {
     CC1Args.push_back("-fvisibility=hidden");
     CC1Args.push_back("-fapply-global-visibility-to-externs");
   }
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 2f5e93d139858..2c7a06f2893b9 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -1069,6 +1069,14 @@ 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));
+  }
+
   // Offloading related options
   addOffloadOptions(C, Inputs, JA, Args, CmdArgs);
 
diff --git a/clang/lib/Driver/ToolChains/HIPAMD.cpp b/clang/lib/Driver/ToolChains/HIPAMD.cpp
index f2f64922cb404..8bfd3c887452c 100644
--- a/clang/lib/Driver/ToolChains/HIPAMD.cpp
+++ b/clang/lib/Driver/ToolChains/HIPAMD.cpp
@@ -274,7 +274,8 @@ void HIPAMDToolChain::addClangTargetOptions(
   // Default to "hidden" visibility, as object level linking will not be
   // supported for the foreseeable future.
   if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
-                         options::OPT_fvisibility_ms_compat)) {
+                         options::OPT_fvisibility_ms_compat) &&
+      !getDriver().IsFlangMode()) {
     CC1Args.append({"-fvisibility=hidden"});
     CC1Args.push_back("-fapply-global-visibility-to-externs");
   }
diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp
index be0f49d8e1497..261adc2b1c440 100644
--- a/clang/lib/Driver/ToolChains/HIPSPV.cpp
+++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp
@@ -143,7 +143,8 @@ void HIPSPVToolChain::addClangTargetOptions(
   // Default to "hidden" visibility, as object level linking will not be
   // supported for the foreseeable future.
   if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
-                         options::OPT_fvisibility_ms_compat))
+                         options::OPT_fvisibility_ms_compat) &&
+      !getDriver().IsFlangMode())
     CC1Args.append(
         {"-fvisibility=hidden", "-fapply-global-visibility-to-externs"});
 
diff --git a/flang-rt/cmake/modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
similarity index 94%
rename from flang-rt/cmake/modules/GetToolchainDirs.cmake
rename to cmake/Modules/GetToolchainDirs.cmake
index fba12502b5946..ce2f8c294b2bc 100644
--- a/flang-rt/cmake/modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -47,6 +47,17 @@ function (get_toolchain_library_subdir outvar)
 endfunction ()
 
 
+# Corresponds to Flang's ToolChain::getDefaultIntrinsicModuleDir().
+function (get_toolchain_module_subdir outvar)
+  set(outval "finclude/flang")
+
+  get_toolchain_arch_dirname(arch_dirname)
+  set(outval "${outval}/${arch_dirname}")
+
+  set(${outvar} "${outval}" PARENT_SCOPE)
+endfunction ()
+
+
 # Corresponds to Clang's ToolChain::getOSLibName(). Adapted from Compiler-RT.
 function (get_toolchain_os_dirname outvar)
   if (ANDROID)
diff --git a/flang-rt/CMakeLists.txt b/flang-rt/CMakeLists.txt
index 50b8e834776fb..20ca6dc7124bc 100644
--- a/flang-rt/CMakeLists.txt
+++ b/flang-rt/CMakeLists.txt
@@ -23,40 +23,6 @@ set(FLANG_RT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
 set(FLANG_RT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
 set(FLANG_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../flang")
 
-# CMake 3.24 is the first version of CMake that directly recognizes Flang.
-# LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang.
-if (CMAKE_VERSION VERSION_LESS "3.24")
-  cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
-  if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
-    include(CMakeForceCompiler)
-    CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
-
-    set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
-    set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
-
-    set(CMAKE_Fortran_SUBMODULE_SEP "-")
-    set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
-
-    set(CMAKE_Fortran_PREPROCESS_SOURCE
-      "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
-
-    set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
-    set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
-
-    set(CMAKE_Fortran_MODDIR_FLAG "-module-dir")
-
-    set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
-    set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
-    set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
-
-    set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
-
-    set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
-    set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
-  endif ()
-endif ()
-enable_language(Fortran)
-
 
 list(APPEND CMAKE_MODULE_PATH
     "${FLANG_RT_SOURCE_DIR}/cmake/modules"
@@ -65,69 +31,22 @@ list(APPEND CMAKE_MODULE_PATH
 include(AddFlangRT)
 include(GetToolchainDirs)
 include(FlangCommon)
+include(FlangRTIntrospection)
 include(HandleCompilerRT)
 include(ExtendPath)
+include(CheckFortranSourceCompiles)
+include(CMakePushCheckState)
 
 
 ############################
 # Build Mode Introspection #
 ############################
 
-# Determine whether we are in the runtimes/runtimes-bins directory of a
-# bootstrap build.
-set(LLVM_TREE_AVAILABLE OFF)
-if (LLVM_LIBRARY_OUTPUT_INTDIR AND LLVM_RUNTIME_OUTPUT_INTDIR AND PACKAGE_VERSION)
-  set(LLVM_TREE_AVAILABLE ON)
-endif()
-
 # Path to LLVM development tools (FileCheck, llvm-lit, not, ...)
 set(LLVM_TOOLS_DIR "${LLVM_BINARY_DIR}/bin")
 
-# Determine build and install paths.
-# The build path is absolute, but the install dir is relative, CMake's install
-# command has to apply CMAKE_INSTALL_PREFIX itself.
-get_toolchain_library_subdir(toolchain_lib_subdir)
-if (LLVM_TREE_AVAILABLE)
-  # In a bootstrap build emit the libraries into a default search path in the
-  # build directory of the just-built compiler. This allows using the
-  # just-built compiler without specifying paths to runtime libraries.
-  #
-  # Despite Clang in the name, get_clang_resource_dir does not depend on Clang
-  # being added to the build. Flang uses the same resource dir as clang.
-  include(GetClangResourceDir)
-  get_clang_resource_dir(FLANG_RT_OUTPUT_RESOURCE_DIR PREFIX "${LLVM_LIBRARY_OUTPUT_INTDIR}/..")
-  get_clang_resource_dir(FLANG_RT_INSTALL_RESOURCE_PATH_DEFAULT)
-
-  extend_path(FLANG_RT_OUTPUT_RESOURCE_LIB_DIR "${FLANG_RT_OUTPUT_RESOURCE_DIR}" "${toolchain_lib_subdir}")
-else ()
-  # In a standalone runtimes build, do not write into LLVM_BINARY_DIR. It may be
-  # read-only and/or shared by multiple runtimes with different build
-  # configurations (e.g. Debug/Release). Use the runtime's own lib dir like any
-  # non-toolchain library.
-  # For the install prefix, still use the resource dir assuming that Flang will
-  # be installed there using the same prefix. This is to not have a difference
-  # between bootstrap and standalone runtimes builds.
-  set(FLANG_RT_OUTPUT_RESOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
-  set(FLANG_RT_INSTALL_RESOURCE_PATH_DEFAULT "lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
-
-  extend_path(FLANG_RT_OUTPUT_RESOURCE_LIB_DIR "${FLANG_RT_OUTPUT_RESOURCE_DIR}" "lib${LLVM_LIBDIR_SUFFIX}")
-endif ()
-set(FLANG_RT_INSTALL_RESOURCE_PATH "${FLANG_RT_INSTALL_RESOURCE_PATH_DEFAULT}"
-    CACHE PATH "Path to install runtime libraries to (default: clang resource dir)")
-extend_path(FLANG_RT_INSTALL_RESOURCE_LIB_PATH "${FLANG_RT_INSTALL_RESOURCE_PATH}" "${toolchain_lib_subdir}")
-cmake_path(NORMAL_PATH FLANG_RT_OUTPUT_RESOURCE_DIR)
-cmake_path(NORMAL_PATH FLANG_RT_INSTALL_RESOURCE_PATH)
-# FIXME: For the libflang_rt.so, the toolchain resource lib dir is not a good
-#        destination because it is not a ld.so default search path.
-#        The machine where the executable is eventually executed may not be the
-#        machine where the Flang compiler and its resource dir is installed, so
-#        setting RPath by the driver is not an solution. It should belong into
-#        /usr/lib/<triple>/libflang_rt.so, like e.g. libgcc_s.so.
-#        But the linker as invoked by the Flang driver also requires
-#        libflang_rt.so to be found when linking and the resource lib dir is
-#        the only reliable location.
-cmake_path(NORMAL_PATH FLANG_RT_OUTPUT_RESOURCE_LIB_DIR)
-cmake_path(NORMAL_PATH FLANG_RT_INSTALL_RESOURCE_LIB_PATH)
+# Fortran compiler not optional for building Flang-RT
+enable_language(Fortran)
 
 
 #################
@@ -137,8 +56,6 @@ cmake_path(NORMAL_PATH FLANG_RT_INSTALL_RESOURCE_LIB_PATH)
 # Important: flang-rt user options must be prefixed with "FLANG_RT_". Variables
 # with this prefix will be forwarded in bootstrap builds.
 
-option(FLANG_RT_INCLUDE_TESTS "Generate build targets for the flang-rt unit and regression-tests." "${LLVM_INCLUDE_TESTS}")
-
 # Provide an interface to link against the LLVM libc/libc++ projects directly.
 set(FLANG_RT_SUPPORTED_PROVIDERS system llvm)
 set(FLANG_RT_LIBC_PROVIDER "system" CACHE STRING "Specify C library to use. Supported values are ${FLANG_RT_SUPPORTED_PROVIDERS}.")
@@ -151,7 +68,14 @@ if (NOT "${FLANG_RT_LIBCXX_PROVIDER}" IN_LIST FLANG_RT_SUPPORTED_PROVIDERS)
   message(FATAL_ERROR "Unsupported library: '${FLANG_RT_LIBCXX_PROVIDER}'. Supported values are ${FLANG_RT_SUPPORTED_PROVIDERS}.")
 endif ()
 
-option(FLANG_RT_ENABLE_STATIC "Build Flang-RT as a static library." ON)
+if (LLVM_RUNTIMES_TARGET MATCHES "^amdgcn|^nvptx")
+  # Compiling libraries for offload targets is currently experimental;
+  # Only build the builtin modules by default.
+  set(FLANG_RT_ENABLE_STATIC_default OFF)
+else ()
+  set(FLANG_RT_ENABLE_STATIC_default ON)
+endif ()
+option(FLANG_RT_ENABLE_STATIC "Build Flang-RT as a static library." "${FLANG_RT_ENABLE_STATIC_default}")
 if (WIN32)
   # Windows DLL currently not implemented.
   set(FLANG_RT_ENABLE_SHARED OFF)
@@ -164,11 +88,14 @@ else ()
   #       breaking change unless the driver is changed.
   option(FLANG_RT_ENABLE_SHARED "Build Flang-RT as a shared library." OFF)
 endif ()
-if (NOT FLANG_RT_ENABLE_STATIC AND NOT FLANG_RT_ENABLE_SHARED)
-  message(FATAL_ERROR "
-      Must build at least one type of library
-      (FLANG_RT_ENABLE_STATIC=ON, FLANG_RT_ENABLE_SHARED=ON, or both)
-    ")
+
+
+if (FLANG_RT_ENABLE_STATIC OR FLANG_RT_ENABLE_SHARED)
+  option(FLANG_RT_INCLUDE_TESTS "Generate build targets for the flang-rt unit and regression-tests." "${LLVM_INCLUDE_TESTS}")
+else ()
+  # Tests require at least one of the libraries
+  message(STATUS "Flang-RT testing disabled without either FLANG_RT_ENABLE_STATIC OR FLANG_RT_ENABLE_SHARED")
+  set(FLANG_RT_INCLUDE_TESTS OFF)
 endif ()
 
 
@@ -186,7 +113,7 @@ elseif (FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT STREQUAL "CUDA")
   option(FLANG_RT_CUDA_RUNTIME_PTX_WITHOUT_GLOBAL_VARS "Do not compile global variables' definitions when producing PTX library" OFF)
 elseif (FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT STREQUAL "OpenMP")
   # Support for OpenMP offloading
-  set(FLANG_RT_DEVICE_ARCHITECTURES "all" CACHE STRING
+  set(FLANG_RT_DEVICE_ARCHITECTURES "${RUNTIMES_DEVICE_ARCHITECTURES}" CACHE STRING
       "List of OpenMP device architectures to be used to compile the Fortran runtime (e.g. 'gfx1103;sm_90')"
     )
 
@@ -234,6 +161,10 @@ check_cxx_source_compiles(
   "
   HAVE_DECL_STRERROR_S)
 
+# Look for support of REAL(16), if not already defined via command
+# line via -DFORTRAN_SUPPORTS_REAL16=YES/NO
+check_fortran_quadmath_support()
+
 # Search for clang_rt.builtins library. Need in addition to msvcrt.
 if (WIN32)
   find_compiler_rt_library(builtins FLANG_RT_BUILTINS_LIBRARY)
@@ -331,6 +262,7 @@ else ()
   add_custom_target(check-flang-rt)
 endif()
 
+
 ###################
 # Install headers #
 ###################
diff --git a/flang-rt/cmake/modules/AddFlangRT.cmake b/flang-rt/cmake/modules/AddFlangRT.cmake
index 923507764d691..0ba485a79beb8 100644
--- a/flang-rt/cmake/modules/AddFlangRT.cmake
+++ b/flang-rt/cmake/modules/AddFlangRT.cmake
@@ -94,6 +94,10 @@ function (add_flangrt_library name)
     set(build_object ON)
   elseif (build_static AND build_shared)
     set(build_object ON)
+  elseif (NOT build_static AND NOT build_shared)
+    # If not building a library, still build the object files
+    # Needed to generate the .mod files as byproduct
+    set(build_object ON)
   endif ()
 
   # srctargets: targets that contain source files
@@ -168,14 +172,18 @@ function (add_flangrt_library name)
     if (BUILD_SHARED_LIBS)
       if (build_shared)
         set(default_target "${name_shared}")
-      else ()
+      elseif (build_static)
         set(default_target "${name_static}")
+      else ()
+        set(default_target "${name_object}")
       endif ()
     else ()
       if (build_static)
         set(default_target "${name_static}")
-      else ()
+      elseif (build_shared)
         set(default_target "${name_shared}")
+      else ()
+        set(default_target "${name_object}")
       endif ()
     endif ()
     add_library(${name}.default ALIAS "${default_target}")
@@ -190,6 +198,12 @@ function (add_flangrt_library name)
     endif ()
   endif ()
 
+  if (build_object)
+    add_library(${name}.compile ALIAS "${name_object}")
+  else ()
+    add_library(${name}.compile ALIAS "${default_target}")
+  endif ()
+
   foreach (tgtname IN LISTS libtargets)
     if (NOT WIN32)
       # Use same stem name for .a and .so. Common in UNIX environments.
@@ -219,6 +233,14 @@ function (add_flangrt_library name)
     # Minimum required C++ version for Flang-RT, even if CMAKE_CXX_STANDARD is defined to something else.
     target_compile_features(${tgtname} PRIVATE cxx_std_17)
 
+    target_compile_options(${tgtname} PRIVATE
+      # Always enable preprocessor regardless of file extension
+      "$<$<COMPILE_LANGUAGE:Fortran>:-cpp>"
+
+      # Missing type descriptors are expected for intrinsic modules
+      "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-mmlir;SHELL:-ignore-missing-type-desc>"
+    )
+
     # When building the flang runtime if LTO is enabled the archive file
     # contains LLVM IR rather than object code. Currently flang is not
     # LTO aware so cannot link this file to compiled Fortran code.
@@ -226,6 +248,10 @@ function (add_flangrt_library name)
       target_compile_options(${tgtname} PRIVATE -fno-lto)
     endif ()
 
+    if (FORTRAN_SUPPORTS_REAL16)
+      target_compile_definitions(${tgtname} PRIVATE FLANG_SUPPORT_R16=1)
+    endif ()
+
     # Use compiler-specific options to disable exceptions and RTTI.
     if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
       target_compile_options(${tgtname} PRIVATE
@@ -344,13 +370,13 @@ function (add_flangrt_library name)
     if (ARG_INSTALL_WITH_TOOLCHAIN)
       set_target_properties(${tgtname}
         PROPERTIES
-          ARCHIVE_OUTPUT_DIRECTORY "${FLANG_RT_OUTPUT_RESOURCE_LIB_DIR}"
-          LIBRARY_OUTPUT_DIRECTORY "${FLANG_RT_OUTPUT_RESOURCE_LIB_DIR}"
+          ARCHIVE_OUTPUT_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_LIB_DIR}"
+          LIBRARY_OUTPUT_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_LIB_DIR}"
         )
 
       install(TARGETS ${tgtname}
-          ARCHIVE DESTINATION "${FLANG_RT_INSTALL_RESOURCE_LIB_PATH}"
-          LIBRARY DESTINATION "${FLANG_RT_INSTALL_RESOURCE_LIB_PATH}"
+          ARCHIVE DESTINATION "${RUNTIMES_INSTALL_RESOURCE_LIB_PATH}"
+          LIBRARY DESTINATION "${RUNTIMES_INSTALL_RESOURCE_LIB_PATH}"
         )
     endif ()
 
diff --git a/flang-rt/cmake/modules/AddFlangRTOffload.cmake b/flang-rt/cmake/modules/AddFlangRTOffload.cmake
index cbc69f3a9656a..5b6464741c9c9 100644
--- a/flang-rt/cmake/modules/AddFlangRTOffload.cmake
+++ b/flang-rt/cmake/modules/AddFlangRTOffload.cmake
@@ -88,16 +88,16 @@ macro(enable_omp_offload_compilation name files)
         "${FLANG_RT_DEVICE_ARCHITECTURES}"
         )
 
-      set(OMP_COMPILE_OPTIONS
+      set(OMP_COMPILE_OPTIONS $<$<COMPILE_LANGUAGE:C,CXX>:
         -fopenmp
         -fvisibility=hidden
         -fopenmp-cuda-mode
         --offload-arch=${compile_for_architectures}
         # Force LTO for the device part.
         -foffload-lto
-        )
-      set_source_files_properties(${files} PROPERTIES COMPILE_OPTIONS
-        "${OMP_COMPILE_OPTIONS}"
+        >)
+      set_property(SOURCE ${files} APPEND
+        PROPERTY COMPILE_DEFINITIONS ${OMP_COMPILE_OPTIONS}
         )
       target_link_options(${name}.static PUBLIC ${OMP_COMPILE_OPTIONS})
 
@@ -105,6 +105,13 @@ macro(enable_omp_offload_compilation name files)
       set_source_files_properties(${files}
         PROPERTIES COMPILE_DEFINITIONS OMP_OFFLOAD_BUILD
         )
+
+     # If building flang-rt together with libomp, ensure that libomp is built
+     # first and found because -fopenmp will try to link it.
+     if (TARGET omp)
+       add_dependencies(${name} omp)
+       target_link_options(${name}.static PUBLIC "-L$<TARGET_FILE_DIR:omp>")
+     endif ()
     else()
       message(FATAL_ERROR
         "Flang-rt build with OpenMP offload is not supported for these compilers:\n"
diff --git a/flang-rt/cmake/modules/FlangRTIntrospection.cmake b/flang-rt/cmake/modules/FlangRTIntrospection.cmake
new file mode 100644
index 0000000000000..10830ff1ac57e
--- /dev/null
+++ b/flang-rt/cmake/modules/FlangRTIntrospection.cmake
@@ -0,0 +1,36 @@
+#===-- cmake/modules/FlangRTIntrospection.cmake ----------------------------===#
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+#===------------------------------------------------------------------------===#
+
+include(CMakePushCheckState)
+
+# Check whether the Fortran compiler supports real(16)/quadmath types
+#
+# Implementation notes:
+#
+#  * FORTRAN_SUPPORTS_REAL16 can be set externally in a bootstrapping-runtimes
+#    build to ensure consistency of real(16) support between compiler and
+#    runtime.
+#
+#  * cmake_push_check_state/cmake_pop_check_state is insufficient to isolate
+#    a compiler introspection environment, see
+#    https://gitlab.kitware.com/cmake/cmake/-/issues/27419
+#    Additionally wrap it in a function namespace.
+function (check_fortran_quadmath_support)
+  cmake_push_check_state(RESET)
+  set(CMAKE_REQUIRED_FLAGS "-ffree-form")
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") # Skip link step
+  check_fortran_source_compiles([[
+      subroutine test_quadmath
+        real(16) :: var1
+      end
+    ]]
+    FORTRAN_SUPPORTS_REAL16
+  )
+  cmake_pop_check_state()
+endfunction ()
+
diff --git a/flang-rt/lib/CMakeLists.txt b/flang-rt/lib/CMakeLists.txt
index aee51dcc9fa24..8738ae7b9c4b6 100644
--- a/flang-rt/lib/CMakeLists.txt
+++ b/flang-rt/lib/CMakeLists.txt
@@ -6,11 +6,16 @@
 #
 #===------------------------------------------------------------------------===#
 
-add_subdirectory(quadmath)
-add_subdirectory(runtime)
-if (FLANG_RT_INCLUDE_CUF)
-  add_subdirectory(cuda)
-endif()
+if (FLANG_RT_ENABLE_STATIC OR FLANG_RT_ENABLE_SHARED)
+  add_subdirectory(quadmath)
+  add_subdirectory(runtime)
+  if (FLANG_RT_INCLUDE_CUF)
+    add_subdirectory(cuda)
+  endif()
+else ()
+  # Generate modules files only, skip the libraries
+  add_subdirectory(runtime)
+endif ()
 
 if (FLANG_RT_INCLUDE_TESTS)
   add_subdirectory(Testing)
diff --git a/flang-rt/lib/runtime/CMakeLists.txt b/flang-rt/lib/runtime/CMakeLists.txt
index e8f70bd544e0b..4be679d1ca8ac 100644
--- a/flang-rt/lib/runtime/CMakeLists.txt
+++ b/flang-rt/lib/runtime/CMakeLists.txt
@@ -12,6 +12,30 @@ find_package(Backtrace)
 set(HAVE_BACKTRACE ${Backtrace_FOUND})
 set(BACKTRACE_HEADER ${Backtrace_HEADER})
 
+# Module sources that are required by other modules
+set(intrinsics_sources
+  __fortran_builtins.f90
+  __cuda_builtins.f90
+)
+
+# Fortran sources for builtin .mod files
+set(module_sources
+  __fortran_ieee_exceptions.f90
+  __fortran_type_info.f90
+  flang_debug.f90
+  iso_fortran_env.f90
+  ieee_arithmetic.f90
+  ieee_exceptions.f90
+  ieee_features.f90
+  iso_c_binding.f90
+  iso_fortran_env.f90
+  iso_fortran_env_impl.f90
+
+  __cuda_device.f90
+  cooperative_groups.f90
+  cudadevice.f90
+)
+
 # List of files that are buildable for all devices.
 set(supported_sources
   ${FLANG_SOURCE_DIR}/lib/Decimal/binary-to-decimal.cpp
@@ -73,7 +97,6 @@ set(supported_sources
 
 # List of source not used for GPU offloading.
 set(host_sources
-  ${FLANG_SOURCE_DIR}/module/iso_fortran_env_impl.f90
   command.cpp
   complex-powi.cpp
   complex-reduction.c
@@ -149,45 +172,91 @@ file(GLOB_RECURSE private_headers
   "${FLANG_SOURCE_DIR}/lib/Common/*.h"
   )
 
+if (LLVM_TARGET_TRIPLE MATCHES "^ppc|^powerpc")
+  list(APPEND intrinsics_sources
+    __ppc_types.f90
+  )
+  list(APPEND module_sources
+    __ppc_intrinsics.f90
+    mma.f90
+  )
+endif ()
+
+# Compile as CUDA-Fortran, not directly supported by CMake
+set_property(SOURCE
+    __cuda_device.f90
+    cooperative_groups.f90
+    cudadevice.f90
+  APPEND PROPERTY
+    COMPILE_OPTIONS --offload-host-only -xcuda
+)
 
 # Import changes from flang_rt.quadmath
-get_target_property(f128_sources
-  FortranFloat128MathILib INTERFACE_SOURCES
-  )
-if (f128_sources)
-  # The interface may define special macros for Float128Math files,
-  # so we need to propagate them.
-  get_target_property(f128_defs
-    FortranFloat128MathILib INTERFACE_COMPILE_DEFINITIONS
-    )
-  set_property(SOURCE ${f128_sources}
-    APPEND PROPERTY COMPILE_DEFINITIONS
-    ${f128_defs}
-    )
-  get_target_property(f128_include_dirs
-    FortranFloat128MathILib INTERFACE_INCLUDE_DIRECTORIES
-    )
-  set_property(SOURCE ${f128_sources}
-    APPEND PROPERTY INCLUDE_DIRECTORIES
-    ${f128_include_dirs}
+set(f128_sources "")
+if (TARGET FortranFloat128MathILib)
+  get_target_property(_propval
+    FortranFloat128MathILib INTERFACE_SOURCES
     )
-else ()
-  set(f128_sources "")
+  if (_propval)
+    set(f128_sources "${_propval}")
+    # The interface may define special macros for Float128Math files,
+    # so we need to propagate them.
+    get_target_property(f128_defs
+      FortranFloat128MathILib INTERFACE_COMPILE_DEFINITIONS
+      )
+    set_property(SOURCE ${f128_sources}
+      APPEND PROPERTY COMPILE_DEFINITIONS
+      ${f128_defs}
+      )
+    get_target_property(f128_include_dirs
+      FortranFloat128MathILib INTERFACE_INCLUDE_DIRECTORIES
+      )
+    set_property(SOURCE ${f128_sources}
+      APPEND PROPERTY INCLUDE_DIRECTORIES
+      ${f128_include_dirs}
+      )
+  endif ()
 endif ()
 
-if ("${LLVM_RUNTIMES_TARGET}" MATCHES "^amdgcn|^nvptx")
-  set(sources ${gpu_sources})
-elseif(FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT STREQUAL "CUDA")
-  set(sources ${supported_sources})
+if (NOT FLANG_RT_ENABLE_STATIC AND NOT FLANG_RT_ENABLE_SHARED)
+  # If not compiling the library, only build the modules.
+  set(sources ${module_sources})
+elseif (LLVM_RUNTIMES_TARGET MATCHES "^amdgcn|^nvptx")
+  set(sources ${gpu_sources} ${module_sources})
 else ()
-  set(sources ${supported_sources} ${host_sources} ${f128_sources})
+  set(sources ${supported_sources} ${host_sources} ${module_sources} ${f128_sources})
 endif ()
 
 
+# check-flang depends on flang-rt-mod to build intrinsic modules
+if (NOT TARGET flang-rt-mod)
+  add_custom_target(flang-rt-mod)
+endif ()
+
 if (NOT WIN32)
+  # CMake ignores intrinsic USE dependencies
+  # CMake has an option Fortran_BUILDING_INSTRINSIC_MODULES/Fortran_BUILDING_INTRINSIC_MODULES
+  # to disable this behavior, unfortunately it does not work with Ninja
+  # (https://gitlab.kitware.com/cmake/cmake/-/issues/26803)
+  # As a workaround, we build those intrinsic modules first such that the main
+  # runtime can depend on it.
+  add_flangrt_library(flang_rt.intrinsics.obj OBJECT
+    ${intrinsics_sources}
+  )
+
+  # This barrier exists to force all of the intrinsic modules of
+  # flang_rt.intrinsics.obj to be built before anything that depends on it.
+  # Without it, CMake/Ninja seem to think that the modules of
+  # flang_rt.intrinsics.obj can be built concurrently to those in
+  # flang_rt.runtime.
+  add_custom_target(flang_rt.intrinsics
+    COMMENT "Intrinsic module dependency barrier"
+  )
+  add_dependencies(flang_rt.intrinsics flang_rt.intrinsics.obj)
+
   add_flangrt_library(flang_rt.runtime STATIC SHARED
-    ${sources}
-    LINK_LIBRARIES ${Backtrace_LIBRARY}
+    ${sources} $<TARGET_OBJECTS:flang_rt.intrinsics.obj>
+    LINK_LIBRARIES flang_rt.intrinsics.obj ${Backtrace_LIBRARY}
     INSTALL_WITH_TOOLCHAIN
     ADDITIONAL_HEADERS ${public_headers} ${private_headers}
   )
@@ -196,8 +265,17 @@ if (NOT WIN32)
   enable_omp_offload_compilation(flang_rt.runtime "${supported_sources}")
 
   # Select a default runtime, which is used for unit and regression tests.
-  get_target_property(default_target flang_rt.runtime.default ALIASED_TARGET)
-  add_library(flang_rt.runtime.unittest ALIAS "${default_target}")
+  if (FLANG_RT_INCLUDE_TESTS)
+    get_target_property(default_target flang_rt.runtime.default ALIASED_TARGET)
+    add_library(flang_rt.runtime.unittest ALIAS "${default_target}")
+  endif ()
+
+  # Select a target that compiles the sources to build the public module files.
+  get_target_property(compile_target flang_rt.runtime.compile ALIASED_TARGET)
+  flang_module_target(flang_rt.intrinsics.obj PUBLIC)
+  flang_module_target(${compile_target} PUBLIC)
+  add_dependencies(${compile_target} flang_rt.intrinsics)
+  add_dependencies(flang-rt-mod flang_rt.intrinsics ${compile_target})
 else()
   # Target for building all versions of the runtime
   add_custom_target(flang_rt.runtime)
@@ -205,12 +283,23 @@ else()
 
   function (add_win_flangrt_runtime libtype suffix msvc_lib)
     set(name "flang_rt.runtime.${suffix}")
+
+    add_flangrt_library(${name}.intrinsics.obj OBJECT
+      ${intrinsics_sources}
+    )
+    add_custom_target(${name}.intrinsics
+      COMMAND echo "${name} Dependency barrier"
+      COMMENT "Intrinsic module dependency barrier"
+    )
+    add_dependencies(${name}.intrinsics ${name}.intrinsics.obj)
+
     add_flangrt_library(${name} ${libtype}
-        ${sources}
+        ${sources} $<TARGET_OBJECTS:${name}.intrinsics.obj>
         ${ARGN}
-        LINK_LIBRARIES ${Backtrace_LIBRARY}
+        LINK_LIBRARIES ${name}.intrinsics.obj ${Backtrace_LIBRARY}
         ADDITIONAL_HEADERS ${public_headers} ${private_headers}
       )
+    get_target_property(compile_target ${name}.compile ALIASED_TARGET)
 
     if (msvc_lib)
       set_target_properties(${name}
@@ -220,11 +309,19 @@ else()
     endif ()
 
     # Setting an unique Fortran_MODULE_DIRECTORY is required for each variant to
-    # write a different .mod file.
-    set_target_properties(${name}
-        PROPERTIES
-          Fortran_MODULE_DIRECTORY "module.${suffix}"
-      )
+    # write a different .mod file. One of them has to be selected to be the
+    # public module that is to be installed. We select the first.
+    if (_has_public_intrinsics)
+      set(is_public "")
+    else ()
+      set(is_public PUBLIC)
+      add_dependencies(flang-rt-mod ${name}.intrinsics ${compile_target})
+      set(_has_public_intrinsics "YES" PARENT_SCOPE)
+    endif ()
+
+    flang_module_target(${name}.intrinsics.obj ${is_public})
+    flang_module_target(${compile_target} ${is_public})
+    add_dependencies(${compile_target} ${name}.intrinsics)
 
     enable_cuda_compilation(${name} "${supported_sources}")
     enable_omp_offload_compilation(${name} "${supported_sources}")
diff --git a/flang/module/__cuda_builtins.f90 b/flang-rt/lib/runtime/__cuda_builtins.f90
similarity index 100%
rename from flang/module/__cuda_builtins.f90
rename to flang-rt/lib/runtime/__cuda_builtins.f90
diff --git a/flang/module/__cuda_device.f90 b/flang-rt/lib/runtime/__cuda_device.f90
similarity index 100%
rename from flang/module/__cuda_device.f90
rename to flang-rt/lib/runtime/__cuda_device.f90
diff --git a/flang/module/__fortran_builtins.f90 b/flang-rt/lib/runtime/__fortran_builtins.f90
similarity index 99%
rename from flang/module/__fortran_builtins.f90
rename to flang-rt/lib/runtime/__fortran_builtins.f90
index a9b60508785db..cede255de7c2c 100644
--- a/flang/module/__fortran_builtins.f90
+++ b/flang-rt/lib/runtime/__fortran_builtins.f90
@@ -6,7 +6,7 @@
 !
 !===------------------------------------------------------------------------===!
 
-#include '../include/flang/Runtime/magic-numbers.h'
+#include '../../../flang/include/flang/Runtime/magic-numbers.h'
 
 ! These naming shenanigans prevent names from Fortran intrinsic modules
 ! from being usable on INTRINSIC statements, and force the program
diff --git a/flang/module/__fortran_ieee_exceptions.f90 b/flang-rt/lib/runtime/__fortran_ieee_exceptions.f90
similarity index 98%
rename from flang/module/__fortran_ieee_exceptions.f90
rename to flang-rt/lib/runtime/__fortran_ieee_exceptions.f90
index 3ac9b993186aa..ff5c6b44317f8 100644
--- a/flang/module/__fortran_ieee_exceptions.f90
+++ b/flang-rt/lib/runtime/__fortran_ieee_exceptions.f90
@@ -11,7 +11,7 @@
 ! here under another name so that IEEE_ARITHMETIC can USE it and export its
 ! declarations without clashing with a non-intrinsic module in a program.
 
-#include '../include/flang/Runtime/magic-numbers.h'
+#include '../../../flang/include/flang/Runtime/magic-numbers.h'
 
 module __fortran_ieee_exceptions
   use __fortran_builtins, only: &
diff --git a/flang/module/__fortran_type_info.f90 b/flang-rt/lib/runtime/__fortran_type_info.f90
similarity index 100%
rename from flang/module/__fortran_type_info.f90
rename to flang-rt/lib/runtime/__fortran_type_info.f90
diff --git a/flang/module/__ppc_intrinsics.f90 b/flang-rt/lib/runtime/__ppc_intrinsics.f90
similarity index 100%
rename from flang/module/__ppc_intrinsics.f90
rename to flang-rt/lib/runtime/__ppc_intrinsics.f90
diff --git a/flang/module/__ppc_types.f90 b/flang-rt/lib/runtime/__ppc_types.f90
similarity index 100%
rename from flang/module/__ppc_types.f90
rename to flang-rt/lib/runtime/__ppc_types.f90
diff --git a/flang/module/cooperative_groups.f90 b/flang-rt/lib/runtime/cooperative_groups.f90
similarity index 96%
rename from flang/module/cooperative_groups.f90
rename to flang-rt/lib/runtime/cooperative_groups.f90
index 8bb4af3afa791..5ca0c3aa1f3a5 100644
--- a/flang/module/cooperative_groups.f90
+++ b/flang-rt/lib/runtime/cooperative_groups.f90
@@ -11,6 +11,7 @@
 module cooperative_groups
 
 use, intrinsic :: __fortran_builtins, only: c_devptr => __builtin_c_devptr
+use :: cudadevice ! implicit dependency, made explicit for CMake
 
 implicit none
 
diff --git a/flang/module/cudadevice.f90 b/flang-rt/lib/runtime/cudadevice.f90
similarity index 100%
rename from flang/module/cudadevice.f90
rename to flang-rt/lib/runtime/cudadevice.f90
diff --git a/flang/module/flang_debug.f90 b/flang-rt/lib/runtime/flang_debug.f90
similarity index 100%
rename from flang/module/flang_debug.f90
rename to flang-rt/lib/runtime/flang_debug.f90
diff --git a/flang/module/ieee_arithmetic.f90 b/flang-rt/lib/runtime/ieee_arithmetic.f90
similarity index 99%
rename from flang/module/ieee_arithmetic.f90
rename to flang-rt/lib/runtime/ieee_arithmetic.f90
index 4e938a2daaa91..02cfae2dc6b18 100644
--- a/flang/module/ieee_arithmetic.f90
+++ b/flang-rt/lib/runtime/ieee_arithmetic.f90
@@ -8,7 +8,7 @@
 
 ! Fortran 2018 Clause 17
 
-#include '../include/flang/Runtime/magic-numbers.h'
+#include '../../../flang/include/flang/Runtime/magic-numbers.h'
 
 module ieee_arithmetic
   ! F18 Clause 17.1p1:
diff --git a/flang/module/ieee_exceptions.f90 b/flang-rt/lib/runtime/ieee_exceptions.f90
similarity index 100%
rename from flang/module/ieee_exceptions.f90
rename to flang-rt/lib/runtime/ieee_exceptions.f90
diff --git a/flang/module/ieee_features.f90 b/flang-rt/lib/runtime/ieee_features.f90
similarity index 100%
rename from flang/module/ieee_features.f90
rename to flang-rt/lib/runtime/ieee_features.f90
diff --git a/flang/module/iso_c_binding.f90 b/flang-rt/lib/runtime/iso_c_binding.f90
similarity index 100%
rename from flang/module/iso_c_binding.f90
rename to flang-rt/lib/runtime/iso_c_binding.f90
diff --git a/flang/module/iso_fortran_env.f90 b/flang-rt/lib/runtime/iso_fortran_env.f90
similarity index 98%
rename from flang/module/iso_fortran_env.f90
rename to flang-rt/lib/runtime/iso_fortran_env.f90
index 3729b95a339f3..2dc38bd1acfe5 100644
--- a/flang/module/iso_fortran_env.f90
+++ b/flang-rt/lib/runtime/iso_fortran_env.f90
@@ -8,7 +8,7 @@
 
 ! See Fortran 2023, subclause 16.10.2
 
-#include '../include/flang/Runtime/magic-numbers.h'
+#include '../../../flang/include/flang/Runtime/magic-numbers.h'
 
 module iso_fortran_env
 
diff --git a/flang/module/iso_fortran_env_impl.f90 b/flang-rt/lib/runtime/iso_fortran_env_impl.f90
similarity index 100%
rename from flang/module/iso_fortran_env_impl.f90
rename to flang-rt/lib/runtime/iso_fortran_env_impl.f90
diff --git a/flang/module/mma.f90 b/flang-rt/lib/runtime/mma.f90
similarity index 100%
rename from flang/module/mma.f90
rename to flang-rt/lib/runtime/mma.f90
diff --git a/flang-rt/test/lit.site.cfg.py.in b/flang-rt/test/lit.site.cfg.py.in
index 662d076b1fe24..0e9dc08b59925 100644
--- a/flang-rt/test/lit.site.cfg.py.in
+++ b/flang-rt/test/lit.site.cfg.py.in
@@ -6,7 +6,7 @@ config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
 config.flang_source_dir = "@FLANG_SOURCE_DIR@"
 config.flang_rt_source_dir = "@FLANG_RT_SOURCE_DIR@"
 config.flang_rt_binary_test_dir = os.path.dirname(__file__)
-config.flang_rt_output_resource_lib_dir = "@FLANG_RT_OUTPUT_RESOURCE_LIB_DIR@"
+config.flang_rt_output_resource_lib_dir = "@RUNTIMES_OUTPUT_RESOURCE_LIB_DIR@"
 config.flang_rt_experimental_offload_support = "@FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT@"
 config.cc = "@CMAKE_C_COMPILER@"
 config.flang = "@CMAKE_Fortran_COMPILER@"
diff --git a/flang-rt/unittests/CMakeLists.txt b/flang-rt/unittests/CMakeLists.txt
index e1ab73d7d9301..75b76e93cb56d 100644
--- a/flang-rt/unittests/CMakeLists.txt
+++ b/flang-rt/unittests/CMakeLists.txt
@@ -49,9 +49,8 @@ function(add_flangrt_unittest_offload_properties target)
   # FIXME: replace 'native' in --offload-arch option with the list
   #        of targets that Fortran Runtime was built for.
   if (FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT STREQUAL "OpenMP")
-    set_target_properties(${target}
-      PROPERTIES LINK_OPTIONS
-      "-fopenmp;--offload-arch=native"
+    set_property(TARGET ${target} APPEND
+      PROPERTY LINK_OPTIONS -fopenmp --offload-arch=native
       )
   endif()
 endfunction()
diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt
index c01eb56d5e496..df38846998b9e 100644
--- a/flang/CMakeLists.txt
+++ b/flang/CMakeLists.txt
@@ -273,7 +273,6 @@ set(FLANG_TOOLS_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}" CACHE PATH
     "Path for binary subdirectory (defaults to '${CMAKE_INSTALL_BINDIR}')")
 mark_as_advanced(FLANG_TOOLS_INSTALL_DIR)
 
-set(FLANG_INTRINSIC_MODULES_DIR ${CMAKE_BINARY_DIR}/include/flang)
 set(FLANG_INCLUDE_DIR ${FLANG_BINARY_DIR}/include)
 
 # TODO: Remove when libclangDriver is lifted out of Clang
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 b6c4e6303cdac..ace24e09d86ec 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -884,16 +884,6 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
   return diags.getNumErrors() == numErrorsBefore;
 }
 
-// Generate the path to look for intrinsic modules
-static std::string getIntrinsicDir(const char *argv) {
-  // TODO: Find a system independent API
-  llvm::SmallString<128> driverPath;
-  driverPath.assign(llvm::sys::fs::getMainExecutable(argv, nullptr));
-  llvm::sys::path::remove_filename(driverPath);
-  driverPath.append("/../include/flang/");
-  return std::string(driverPath);
-}
-
 // Generate the path to look for OpenMP headers
 static std::string getOpenMPHeadersDir(const char *argv) {
   llvm::SmallString<128> includePath;
@@ -1567,6 +1557,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)) {
@@ -1833,9 +1831,11 @@ void CompilerInvocation::setFortranOpts() {
       preprocessorOptions.searchDirectoriesFromIntrModPath.begin(),
       preprocessorOptions.searchDirectoriesFromIntrModPath.end());
 
-  //  Add the default intrinsic module directory
-  fortranOptions.intrinsicModuleDirectories.emplace_back(
-      getIntrinsicDir(getArgv0()));
+  // Add the ordered list of -fintrinsic-modules-path
+  fortranOptions.intrinsicModuleDirectories.insert(
+      fortranOptions.intrinsicModuleDirectories.end(),
+      preprocessorOptions.searchDirectoriesFromIntrModPath.begin(),
+      preprocessorOptions.searchDirectoriesFromIntrModPath.end());
 
   // Add the directory supplied through -J/-module-dir to the list of search
   // directories
diff --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp
index 2606d997b1cd7..f4b90bf01abe3 100644
--- a/flang/lib/Semantics/semantics.cpp
+++ b/flang/lib/Semantics/semantics.cpp
@@ -621,12 +621,15 @@ bool Semantics::Perform() {
     const auto *frontModule{std::get_if<common::Indirection<parser::Module>>(
         &program_.v.front().u)};
     if (frontModule &&
-        (std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)
-                    .statement.v.source == "__fortran_builtins" ||
-            std::get<parser::Statement<parser::ModuleStmt>>(
-                frontModule->value().t)
-                    .statement.v.source == "__ppc_types")) {
+        std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)
+                .statement.v.source == "__fortran_builtins") {
       // Don't try to read the builtins module when we're actually building it.
+    } else if (frontModule &&
+        std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)
+                .statement.v.source == "__ppc_types") {
+      // Don't try to read the UsePPCBuiltinTypesModule() we are currently
+      // building, but __fortran_builtins is needed to build it.
+      context_.UseFortranBuiltinsModule();
     } else if (frontModule &&
         (std::get<parser::Statement<parser::ModuleStmt>>(frontModule->value().t)
                     .statement.v.source == "__ppc_intrinsics" ||
diff --git a/flang/module/.clang-format b/flang/module/.clang-format
deleted file mode 100644
index e3845288a2aec..0000000000000
--- a/flang/module/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-DisableFormat: true
diff --git a/flang/test/CMakeLists.txt b/flang/test/CMakeLists.txt
index 8c8e92faa787a..c43ef8b29b30d 100644
--- a/flang/test/CMakeLists.txt
+++ b/flang/test/CMakeLists.txt
@@ -2,11 +2,31 @@
 # for use by Lit, and delegates to LLVM's lit test handlers.
 add_subdirectory(lib)
 
+set(FLANG_TEST_Fortran_FLAGS "" CACHE STRING "Additional Fortran flags for running tests, such as -fintrinsic-modules-path=<path>")
+
+if ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
+  set(FLANG_TEST_ENABLE_MODULES_default ON)
+else ()
+  set(FLANG_TEST_ENABLE_MODULES_default OFF)
+endif ()
+option(FLANG_TEST_ENABLE_MODULES "Force-enable tests that require intrinsic modules from Flang-RT" "${FLANG_TEST_ENABLE_MODULES_default}")
+
+
+if ("openmp" IN_LIST LLVM_ENABLE_RUNTIMES AND FLANG_TEST_ENABLE_MODULES AND NOT FLANG_STANDALONE_BUILD)
+  set(FLANG_TEST_ENABLE_OPENMP_default ON)
+else ()
+  set(FLANG_TEST_ENABLE_OPENMP_default OFF)
+endif ()
+option(FLANG_TEST_ENABLE_OPENMP "Force-enable tests that require modules from OpenMP" "${FLANG_TEST_ENABLE_OPENMP_default}")
+
+
 llvm_canonicalize_cmake_booleans(
   FLANG_STANDALONE_BUILD
   LLVM_BUILD_EXAMPLES
   LLVM_BYE_LINK_INTO_TOOLS
   LLVM_ENABLE_PLUGINS
+  FLANG_TEST_ENABLE_MODULES
+  FLANG_TEST_ENABLE_OPENMP
 )
 
 set(FLANG_TOOLS_DIR ${FLANG_BINARY_DIR}/bin)
@@ -59,7 +79,6 @@ set(FLANG_TEST_PARAMS
 
 set(FLANG_TEST_DEPENDS
   flang
-  module_files
   fir-opt
   tco
   bbc
@@ -101,8 +120,14 @@ if (LLVM_BUILD_EXAMPLES)
     )
 endif ()
 
-if ("openmp" IN_LIST LLVM_ENABLE_RUNTIMES AND NOT FLANG_STANDALONE_BUILD)
-  list(APPEND FLANG_TEST_DEPENDS "libomp-mod")
+if ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES AND NOT FLANG_STANDALONE_BUILD)
+  # For intrinsic module files (in flang-rt/)
+  list(APPEND FLANG_TEST_DEPENDS "flang-rt-mod")
+
+  if ("openmp" IN_LIST LLVM_ENABLE_RUNTIMES)
+    # For omplib.mod and omplib_kinds.mod (in openmp/)
+    list(APPEND FLANG_TEST_DEPENDS "libomp-mod")
+  endif ()
 endif ()
 
 add_custom_target(flang-test-depends DEPENDS ${FLANG_TEST_DEPENDS})
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/intrinsic-module-path.F90 b/flang/test/Driver/intrinsic-module-path.F90
new file mode 100644
index 0000000000000..3317eb776f0a1
--- /dev/null
+++ b/flang/test/Driver/intrinsic-module-path.F90
@@ -0,0 +1,55 @@
+! 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 -### %s 2>&1 | FileCheck %s --check-prefix=DEFAULTPATH
+
+! RUN:     %flang -fsyntax-only -DINTRINSICS_DEFAULT %s
+! RUN: not %flang -fsyntax-only -DINTRINSICS_INPUTONE %s 2>&1 | FileCheck %s --check-prefix=NOINPUTONE
+! RUN: not %flang -fsyntax-only -DINTRINSICS_INPUTTWO %s 2>&1 | FileCheck %s --check-prefix=NOINPUTTWO
+! RUN:     %flang -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir/ %s
+! RUN:     %flang -fsyntax-only -DINTRINSICS_INPUTONE -fintrinsic-modules-path=%S/Inputs/ %s
+! RUN:     %flang -fsyntax-only -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/ -fintrinsic-modules-path=%S/Inputs/module-dir/ %s
+! RUN: not %flang -fsyntax-only -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir/ -fintrinsic-modules-path=%S/Inputs/ %s 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).
+
+! RUN:     %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT %s
+! RUN: not %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE %s 2>&1 | FileCheck %s --check-prefix=NOINPUTONE
+! RUN: not %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTTWO %s 2>&1 | FileCheck %s --check-prefix=NOINPUTTWO
+! RUN:     %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir %s
+! RUN:     %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE -fintrinsic-modules-path=%S/Inputs/ %s
+! RUN:     %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/ -fintrinsic-modules-path=%S/Inputs/module-dir/ %s
+! RUN: not %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir -fintrinsic-modules-path=%S/Inputs/ %s 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/intrinsic-module-path.f90 b/flang/test/Driver/intrinsic-module-path.f90
deleted file mode 100644
index 615d8f9a1730a..0000000000000
--- a/flang/test/Driver/intrinsic-module-path.f90
+++ /dev/null
@@ -1,23 +0,0 @@
-! Ensure argument -fintrinsic-modules-path works as expected.
-! WITHOUT the option, the default location for the module is checked and no error generated.
-! With the option GIVEN, the module with the same name is PREPENDED, and considered over the
-! default one, causing a CHECKSUM error.
-
-!-----------------------------------------
-! FRONTEND FLANG DRIVER (flang -fc1)
-!-----------------------------------------
-! RUN: %flang_fc1 -fsyntax-only %s  2>&1 | FileCheck %s --allow-empty --check-prefix=WITHOUT
-! RUN: not %flang_fc1 -fsyntax-only -fintrinsic-modules-path %S/Inputs/ %s  2>&1 | FileCheck %s --check-prefix=GIVEN
-! RUN: not %flang_fc1 -fsyntax-only -fintrinsic-modules-path=%S/Inputs/ %s  2>&1 | FileCheck %s --check-prefix=GIVEN
-
-! WITHOUT-NOT: 'ieee_arithmetic.mod' was not found
-! WITHOUT-NOT: 'iso_fortran_env.mod' was not found
-
-! GIVEN: error: Cannot use module file for module 'ieee_arithmetic': File has invalid checksum
-! GIVEN: error: Cannot use module file for module 'iso_fortran_env': File has invalid checksum
-
-
-program test_intrinsic_module_path
-   use ieee_arithmetic, only: ieee_round_type
-   use iso_fortran_env, only: team_type, event_type, lock_type
-end program
diff --git a/flang/test/Driver/lto-fatlto.f90 b/flang/test/Driver/lto-fatlto.f90
index 2ea251eafacbf..9adf264f114dc 100644
--- a/flang/test/Driver/lto-fatlto.f90
+++ b/flang/test/Driver/lto-fatlto.f90
@@ -1,7 +1,7 @@
 ! REQUIRES: x86-registered-target
 ! checks fatlto objects: that valid bitcode is included in the object file generated.
 
-! RUN: %flang -fc1 -triple x86_64-unknown-linux-gnu -flto -ffat-lto-objects -emit-obj %s -o %t.o
+! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -flto -ffat-lto-objects -emit-obj %s -o %t.o
 ! RUN: llvm-readelf -S %t.o | FileCheck %s --check-prefixes=ELF
 ! RUN: llvm-objcopy --dump-section=.llvm.lto=%t.bc %t.o
 ! RUN: llvm-dis %t.bc -o - | FileCheck %s --check-prefixes=DIS
@@ -11,7 +11,7 @@
 ! DIS-NEXT:  ret void
 ! DIS-NEXT: }
 
-! RUN: %flang -fc1 -triple x86_64-unknown-linux-gnu -flto -ffat-lto-objects -S %s -o - | FileCheck %s --check-prefixes=ASM
+! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -flto -ffat-lto-objects -S %s -o - | FileCheck %s --check-prefixes=ASM
 
 !      ASM: .section        .llvm.lto,"e", at llvm_lto
 ! ASM-NEXT: .Lllvm.embedded.object:
diff --git a/flang/test/Driver/pp-fixed-form.f90 b/flang/test/Driver/pp-fixed-form.f90
index bb869cd3341a7..fb9e1dd0d1e6b 100644
--- a/flang/test/Driver/pp-fixed-form.f90
+++ b/flang/test/Driver/pp-fixed-form.f90
@@ -8,12 +8,12 @@
 
 !RUN: %flang -save-temps -### -ffree-form %S/Inputs/free-form-test.f90  2>&1 | FileCheck %s --check-prefix=FREE-FLAG
 FREE-FLAG:           "-fc1" {{.*}} "-o" "free-form-test.i" {{.*}} "-x" "f95" "{{.*}}/free-form-test.f90"
-FREE-FLAG-NEXT:      "-fc1" {{.*}} "-emit-llvm-bc" "-ffree-form"
+FREE-FLAG-NEXT:      "-fc1" {{.*}} "-emit-llvm-bc" {{.*}}"-ffree-form"
 FREE-FLAG-NOT:       "-ffixed-form"
 FREE-FLAG-SAME:      "-x" "f95-cpp-input" "free-form-test.i"
 
 !RUN: %flang -save-temps -### -ffixed-form %S/Inputs/fixed-form-test.f  2>&1 | FileCheck %s --check-prefix=FIXED-FLAG
 FIXED-FLAG:          "-fc1" {{.*}} "-o" "fixed-form-test.i" {{.*}} "-x" "f95" "{{.*}}/fixed-form-test.f"
-FIXED-FLAG-NEXT:     "-fc1" {{.*}} "-emit-llvm-bc" "-ffixed-form"
+FIXED-FLAG-NEXT:     "-fc1" {{.*}} "-emit-llvm-bc" {{.*}}"-ffixed-form"
 FIXED-FLAG-NOT:      "-ffixed-form"
 FIXED-FLAG-SAME:     "-x" "f95-cpp-input" "fixed-form-test.i"
diff --git a/flang/test/Lower/HLFIR/type-bound-call-mismatch.f90 b/flang/test/Lower/HLFIR/type-bound-call-mismatch.f90
index 2e0c72ccfe048..29a9784b984b6 100644
--- a/flang/test/Lower/HLFIR/type-bound-call-mismatch.f90
+++ b/flang/test/Lower/HLFIR/type-bound-call-mismatch.f90
@@ -1,6 +1,6 @@
 ! Test interface that lowering handles small interface mismatch with
 ! type bound procedures.
-! RUN: bbc -emit-hlfir %s -o - -I nw | FileCheck %s
+! RUN: %bbc_bare -emit-hlfir %s -o - -I nw | FileCheck %s
 
 module dispatch_mismatch
 type t
diff --git a/flang/test/Lower/OpenMP/simd_aarch64.f90 b/flang/test/Lower/OpenMP/simd_aarch64.f90
index 735237223bcb5..2e4136273c75b 100644
--- a/flang/test/Lower/OpenMP/simd_aarch64.f90
+++ b/flang/test/Lower/OpenMP/simd_aarch64.f90
@@ -1,6 +1,11 @@
-! Tests for 2.9.3.1 Simd and target dependent defult alignment for AArch64
+! Tests for 2.9.3.1 Simd and target dependent default alignment for AArch64
 ! The default alignment for AARCH64 is 0 so we do not emit aligned clause
 ! REQUIRES: aarch64-registered-target
+
+! Requires aarch64 iso_c_binding.mod which currently is only available if your host is also aarch64
+! FIXME: Make flang a cross-compiler
+! UNSUPPORTED: true
+
 ! RUN: %flang_fc1 -triple aarch64-unknown-linux-gnu -emit-hlfir -fopenmp %s -o - | FileCheck  %s
 subroutine simdloop_aligned_cptr(A)
     use iso_c_binding
diff --git a/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90 b/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90
index a717b38a76593..df3f88eabbfc1 100644
--- a/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90
+++ b/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90
@@ -1,7 +1,7 @@
 ! This test checks the lowering and application of default map types for the target enter/exit data constructs and map clauses
 
-!RUN: %flang -fc1 -emit-fir -fopenmp -fopenmp-version=52 -o - %s | FileCheck %s --check-prefix=CHECK-52
-!RUN: not %flang -fc1 -emit-fir -fopenmp -fopenmp-version=51 -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-51
+!RUN: %flang_fc1 -emit-fir -fopenmp -fopenmp-version=52 -o - %s | FileCheck %s --check-prefix=CHECK-52
+!RUN: not %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-51
 
 module test
   real, allocatable :: A
diff --git a/flang/test/Preprocessing/fixed-free.f b/flang/test/Preprocessing/fixed-free.f
index 95f63a4d71e4c..7140bc6aec360 100644
--- a/flang/test/Preprocessing/fixed-free.f
+++ b/flang/test/Preprocessing/fixed-free.f
@@ -1,5 +1,5 @@
 !RUN: %flang -E %s 2>&1 | FileCheck %s
-!RUN: %flang -fc1 -fsyntax-only %s 2>&1 | FileCheck --allow-empty %s
+!RUN: %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck --allow-empty %s
 !CHECK-NOT: dir$
 !CHECK-NOT: error:
 !dir$ fixed
diff --git a/flang/test/Preprocessing/no-pp-if.f90 b/flang/test/Preprocessing/no-pp-if.f90
index 3e49df3deb251..ab08a4f838a90 100644
--- a/flang/test/Preprocessing/no-pp-if.f90
+++ b/flang/test/Preprocessing/no-pp-if.f90
@@ -1,4 +1,4 @@
-!RUN: %flang -fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
+!RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
 !CHECK-NOT: ERROR STOP
 !CHECK: CONTINUE
 #if defined UNDEFINED
diff --git a/flang/test/Semantics/bug163242.f90 b/flang/test/Semantics/bug163242.f90
index 5e020aeb4dc0d..3c0a2b6b32229 100644
--- a/flang/test/Semantics/bug163242.f90
+++ b/flang/test/Semantics/bug163242.f90
@@ -1,4 +1,4 @@
-!RUN: %flang -fc1 -fsyntax-only %s | FileCheck --allow-empty %s
+!RUN: %flang_fc1 -fsyntax-only %s | FileCheck --allow-empty %s
 !CHECK-NOT: error:
 character(0), allocatable :: ch
 allocate(character(-1) :: ch)
diff --git a/flang/test/Semantics/bug164303.f90 b/flang/test/Semantics/bug164303.f90
index c356c07392577..39af27e914248 100644
--- a/flang/test/Semantics/bug164303.f90
+++ b/flang/test/Semantics/bug164303.f90
@@ -1,4 +1,4 @@
-!RUN: %flang -fc1 -fsyntax-only %s 2>&1 | FileCheck --allow-empty %s
+!RUN: %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck --allow-empty %s
 module foo_mod
   use, intrinsic :: iso_fortran_env
   use, intrinsic :: iso_c_binding
diff --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py
index 4221354df34a2..c3050dc876ec7 100644
--- a/flang/test/lit.cfg.py
+++ b/flang/test/lit.cfg.py
@@ -139,18 +139,95 @@
 if config.default_sysroot:
     config.available_features.add("default_sysroot")
 
+
+flang_exe = lit.util.which("flang", config.flang_llvm_tools_dir)
+if not flang_exe:
+    lit_config.fatal(f"Could not identify flang executable")
+
+# Intrinsic paths that are added implicitly by the `flang` driver, but have to be added manually when invoking the frontend `flang -fc1`.
+flang_driver_search_args = []
+
+# Intrinsic paths that are added to `flang` as well as `flang -fc1`.
+flang_extra_search_args = list(config.flang_test_fortran_flags)
+
+
+def get_resource_module_intrinsic_dir(modfile):
+    # Determine the intrinsic module search path that is added by the driver. If
+    # skipping the driver using -fc1, we need to append the path manually.
+    flang_intrinsics_dir = subprocess.check_output(
+        [flang_exe, *config.flang_test_fortran_flags, f"-print-file-name={modfile}"],
+        text=True,
+    ).strip()
+    flang_intrinsics_dir = os.path.dirname(flang_intrinsics_dir)
+    return flang_intrinsics_dir or None
+
+
+intrinsics_mod_path = get_resource_module_intrinsic_dir("__fortran_builtins.mod")
+if intrinsics_mod_path:
+    flang_driver_search_args += [f"-fintrinsic-modules-path={intrinsics_mod_path}"]
+
+openmp_mod_path = get_resource_module_intrinsic_dir("omp_lib.mod")
+if openmp_mod_path and openmp_mod_path != intrinsics_mod_path:
+    flang_driver_search_args += [f"-fintrinsic-modules-path={openmp_mod_path}"]
+
+
+# If intrinsic modules are not available, disable tests unless they are marked as 'module-independent'.
+config.available_features.add("module-independent")
+if config.flang_test_enable_modules or intrinsics_mod_path:
+    config.available_features.add("flangrt-modules")
+else:
+    lit_config.warning(
+        f"Intrinsic modules not in driver default paths: disabling most tests; Use FLANG_TEST_ENABLE_MODULES=ON to force-enable"
+    )
+    config.limit_to_features.add("module-independent")
+
+# Determine if OpenMP runtime was built (enable OpenMP tests via REQUIRES in test file)
+if config.flang_test_enable_openmp or openmp_mod_path:
+    config.available_features.add("openmp_runtime")
+
+    # Search path for omp_lib.h with LLVM_ENABLE_RUNTIMES=openmp
+    # FIXME: openmp should write this file into the resource directory
+    flang_extra_search_args += [
+        "-I",
+        f"{config.flang_obj_root}/../../runtimes/runtimes-bins/openmp/runtime/src",
+    ]
+else:
+    lit_config.warning(
+        f"OpenMP modules found not in driver default paths: OpenMP tests disabled; Use FLANG_TEST_ENABLE_OPENMP=ON to force-enable"
+    )
+
+
+lit_config.note(f"using flang: {flang_exe}")
+lit_config.note(
+    f"using flang implicit search paths: {' '.join(flang_driver_search_args)}"
+)
+lit_config.note(f"using flang extra search paths: {' '.join(flang_extra_search_args)}")
+
 # For each occurrence of a flang tool name, replace it with the full path to
 # the build directory holding that tool.
 tools = [
+    ToolSubst(
+        "bbc",
+        command=FindTool("bbc"),
+        extra_args=flang_driver_search_args + flang_extra_search_args,
+        unresolved="fatal",
+    ),
     ToolSubst(
         "%flang",
-        command=FindTool("flang"),
+        command=flang_exe,
+        extra_args=flang_extra_search_args,
         unresolved="fatal",
     ),
     ToolSubst(
         "%flang_fc1",
-        command=FindTool("flang"),
-        extra_args=["-fc1"],
+        command=flang_exe,
+        extra_args=["-fc1"] + flang_driver_search_args + flang_extra_search_args,
+        unresolved="fatal",
+    ),
+    # Variant that does not implicitly add intrinsic search paths
+    ToolSubst(
+        "%bbc_bare",
+        command=FindTool("bbc"),
         unresolved="fatal",
     ),
 ]
@@ -193,16 +270,7 @@
 if result:
     config.environment["LIBPGMATH"] = True
 
-# Determine if OpenMP runtime was built (enable OpenMP tests via REQUIRES in test file)
-openmp_flags_substitution = "-fopenmp"
-if config.have_openmp_rtl:
-    config.available_features.add("openmp_runtime")
-    # For the enabled OpenMP tests, add a substitution that is needed in the tests to find
-    # the omp_lib.{h,mod} files, depending on whether the OpenMP runtime was built as a
-    # project or runtime.
-    if config.openmp_module_dir:
-        openmp_flags_substitution += f" -J {config.openmp_module_dir}"
-config.substitutions.append(("%openmp_flags", openmp_flags_substitution))
+config.substitutions.append(("%openmp_flags", "-fopenmp"))
 
 # Add features and substitutions to test F128 math support.
 # %f128-lib substitution may be used to generate check prefixes
diff --git a/flang/test/lit.site.cfg.py.in b/flang/test/lit.site.cfg.py.in
index cc1f4fa6cc9c5..25f2a88d068d7 100644
--- a/flang/test/lit.site.cfg.py.in
+++ b/flang/test/lit.site.cfg.py.in
@@ -13,10 +13,12 @@ config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
 config.errc_messages = "@LLVM_LIT_ERRC_MESSAGES@"
 config.flang_obj_root = "@FLANG_BINARY_DIR@"
 config.flang_tools_dir = lit_config.substitute("@FLANG_TOOLS_DIR@")
-config.flang_intrinsic_modules_dir = "@FLANG_INTRINSIC_MODULES_DIR@"
 config.flang_headers_dir = "@HEADER_BINARY_DIR@"
 config.flang_llvm_tools_dir = "@CMAKE_BINARY_DIR@/bin"
 config.flang_test_triple = "@FLANG_TEST_TARGET_TRIPLE@"
+config.flang_test_fortran_flags = "@FLANG_TEST_Fortran_FLAGS@".split()
+config.flang_test_enable_modules = @FLANG_TEST_ENABLE_MODULES@
+config.flang_test_enable_openmp = @FLANG_TEST_ENABLE_OPENMP@
 config.flang_examples = @LLVM_BUILD_EXAMPLES@
 config.python_executable = "@PYTHON_EXECUTABLE@"
 config.flang_standalone_build = @FLANG_STANDALONE_BUILD@
@@ -25,11 +27,6 @@ config.linked_bye_extension = @LLVM_BYE_LINK_INTO_TOOLS@
 config.osx_sysroot = path(r"@CMAKE_OSX_SYSROOT@")
 config.targets_to_build = "@TARGETS_TO_BUILD@"
 config.default_sysroot = "@DEFAULT_SYSROOT@"
-config.have_openmp_rtl = ("@LLVM_TOOL_OPENMP_BUILD@" == "TRUE") or ("openmp" in "@LLVM_ENABLE_RUNTIMES@".lower().split(";"))
-if "openmp" in "@LLVM_ENABLE_RUNTIMES@".lower().split(";"):
-    config.openmp_module_dir = "@CMAKE_BINARY_DIR@/runtimes/runtimes-bins/openmp/runtime/src"
-else:
-    config.openmp_module_dir = None
 config.flang_runtime_f128_math_lib = "@FLANG_RUNTIME_F128_MATH_LIB@"
 config.have_ldbl_mant_dig_113 = "@HAVE_LDBL_MANT_DIG_113@"
 
diff --git a/flang/tools/CMakeLists.txt b/flang/tools/CMakeLists.txt
index 1d2d2c608faf9..1b297af74cae7 100644
--- a/flang/tools/CMakeLists.txt
+++ b/flang/tools/CMakeLists.txt
@@ -7,7 +7,6 @@
 #===------------------------------------------------------------------------===#
 
 add_subdirectory(bbc)
-add_subdirectory(f18)
 add_subdirectory(flang-driver)
 add_subdirectory(tco)
 add_subdirectory(f18-parse-demo)
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 8b12da3a7b50a..ab35fb3af6c2a 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -98,6 +98,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("."));
@@ -574,14 +579,6 @@ int main(int argc, char **argv) {
 
   if (includeDirs.size() == 0) {
     includeDirs.push_back(".");
-    // Default Fortran modules should be installed in include/flang (a sibling
-    // to the bin) directory.
-    intrinsicIncludeDirs.push_back(
-        llvm::sys::path::parent_path(
-            llvm::sys::path::parent_path(
-                llvm::sys::fs::getMainExecutable(argv[0], nullptr)))
-            .str() +
-        "/include/flang");
   }
 
   Fortran::parser::Options options;
diff --git a/flang/tools/f18/CMakeLists.txt b/flang/tools/f18/CMakeLists.txt
deleted file mode 100644
index 58ea782ce213e..0000000000000
--- a/flang/tools/f18/CMakeLists.txt
+++ /dev/null
@@ -1,171 +0,0 @@
-set(LLVM_LINK_COMPONENTS
-  FrontendOpenACC
-  FrontendOpenMP
-  Support
-  )
-
-# Define the list of Fortran module files for which it is
-# sufficient to generate the module file via -fsyntax-only.
-set(MODULES
-  "__fortran_builtins"
-  "__fortran_ieee_exceptions"
-  "__fortran_type_info"
-  "__ppc_types"
-  "__ppc_intrinsics"
-  "mma"
-  "__cuda_builtins"
-  "__cuda_device"
-  "cooperative_groups"
-  "cudadevice"
-  "ieee_arithmetic"
-  "ieee_exceptions"
-  "ieee_features"
-  "iso_c_binding"
-  "iso_fortran_env"
-  "iso_fortran_env_impl"
-  "flang_debug"
-)
-
-# Check if 128-bit float computations can be done via long double.
-check_cxx_source_compiles(
-  "#include <cfloat>
-   #if LDBL_MANT_DIG != 113
-   #error LDBL_MANT_DIG != 113
-   #endif
-   int main() { return 0; }
-  "
-  HAVE_LDBL_MANT_DIG_113)
-
-# Figure out whether we can support REAL(KIND=16)
-if (FLANG_RUNTIME_F128_MATH_LIB)
-  set(FLANG_SUPPORT_R16 "1")
-elseif (HAVE_LDBL_MANT_DIG_113)
-  set(FLANG_SUPPORT_R16 "1")
-else()
-  set(FLANG_SUPPORT_R16 "0")
-endif()
-
-# Init variable to hold extra object files coming from the Fortran modules;
-# these module files will be contributed from the CMakeLists in flang/tools/f18.
-set(module_objects "")
-
-# Create module files directly from the top-level module source directory.
-# If CMAKE_CROSSCOMPILING, then the newly built flang executable was
-# cross compiled, and thus can't be executed on the build system and thus
-# can't be used for generating module files.
-if (NOT CMAKE_CROSSCOMPILING)
-  foreach(filename ${MODULES})
-    set(depends "")
-    set(opts "")
-    if(${filename} STREQUAL "__fortran_builtins" OR
-       ${filename} STREQUAL "__ppc_types")
-    elseif(${filename} STREQUAL "__ppc_intrinsics" OR
-           ${filename} STREQUAL "mma")
-      set(depends ${FLANG_INTRINSIC_MODULES_DIR}/__ppc_types.mod)
-    elseif(${filename} STREQUAL "__cuda_device" OR
-           ${filename} STREQUAL "cudadevice" OR
-           ${filename} STREQUAL "cooperative_groups")
-      set(opts -fc1 -xcuda)
-      if(${filename} STREQUAL "__cuda_device")
-        set(depends ${FLANG_INTRINSIC_MODULES_DIR}/__cuda_builtins.mod)
-      elseif(${filename} STREQUAL "cudadevice")
-        set(depends ${FLANG_INTRINSIC_MODULES_DIR}/__cuda_device.mod)
-      elseif(${filename} STREQUAL "cooperative_groups")
-        set(depends ${FLANG_INTRINSIC_MODULES_DIR}/cudadevice.mod)
-      endif()
-    else()
-      set(depends ${FLANG_INTRINSIC_MODULES_DIR}/__fortran_builtins.mod)
-      if(${filename} STREQUAL "iso_fortran_env")
-        set(depends ${depends} ${FLANG_INTRINSIC_MODULES_DIR}/iso_fortran_env_impl.mod)
-      endif()
-      if(${filename} STREQUAL "ieee_arithmetic" OR
-         ${filename} STREQUAL "ieee_exceptions")
-        set(depends ${depends} ${FLANG_INTRINSIC_MODULES_DIR}/__fortran_ieee_exceptions.mod)
-      endif()
-    endif()
-    if(NOT ${filename} STREQUAL "__fortran_type_info" AND NOT ${filename} STREQUAL "__fortran_builtins")
-      set(depends ${depends} ${FLANG_INTRINSIC_MODULES_DIR}/__fortran_type_info.mod)
-    endif()
-
-    # The module contains PPC vector types that needs the PPC target.
-    if(${filename} STREQUAL "__ppc_intrinsics" OR
-       ${filename} STREQUAL "mma")
-      if (PowerPC IN_LIST LLVM_TARGETS_TO_BUILD)
-        set(opts "--target=ppc64le")
-      else()
-        # Do not compile PPC module if the target is not available.
-        continue()
-      endif()
-    endif()
-
-    set(decls "")
-    if (FLANG_SUPPORT_R16)
-      set(decls "-DFLANG_SUPPORT_R16")
-    endif()
-
-    # Some modules have an implementation part that needs to be added to the
-    # flang_rt.runtime library.
-    set(compile_with "-fsyntax-only")
-    set(object_output "")
-    set(include_in_link FALSE)
-
-    set(base ${FLANG_INTRINSIC_MODULES_DIR}/${filename})
-    # TODO: We may need to flag this with conditional, in case Flang is built w/o OpenMP support
-    add_custom_command(OUTPUT ${base}.mod ${object_output}
-      COMMAND ${CMAKE_COMMAND} -E make_directory ${FLANG_INTRINSIC_MODULES_DIR}
-      COMMAND flang ${opts} ${decls} -cpp ${compile_with} -module-dir ${FLANG_INTRINSIC_MODULES_DIR}
-        ${FLANG_SOURCE_DIR}/module/${filename}.f90
-      DEPENDS flang ${FLANG_SOURCE_DIR}/module/${filename}.f90 ${FLANG_SOURCE_DIR}/module/__fortran_builtins.f90 ${depends}
-    )
-    list(APPEND MODULE_FILES ${base}.mod)
-    install(FILES ${base}.mod DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/flang" COMPONENT flang-module-interfaces)
-
-    # If a module has been compiled into an object file, add the file to
-    # the link line for the flang_rt.runtime library.
-    if(include_in_link)
-      list(APPEND module_objects ${object_output})
-    endif()
-  endforeach()
-
-  # Set a CACHE variable that is visible to the CMakeLists.txt in runtime/, so that
-  # the compiled Fortran modules can be added to the link line of the flang_rt.runtime
-  # library.
-  set(FORTRAN_MODULE_OBJECTS ${module_objects} CACHE INTERNAL "" FORCE)
-
-  # Special case for omp_lib.mod, because its source comes from openmp/runtime/src/include.
-  # It also produces two module files: omp_lib.mod and omp_lib_kinds.mod.  Compile these
-  # files only if OpenMP support has been configured.
-  if (LLVM_TOOL_OPENMP_BUILD)
-    message(STATUS "OpenMP runtime support enabled via LLVM_ENABLE_PROJECTS, building omp_lib.mod")
-    set(base ${FLANG_INTRINSIC_MODULES_DIR}/omp_lib)
-    add_custom_command(OUTPUT ${base}.mod ${base}_kinds.mod
-      COMMAND ${CMAKE_COMMAND} -E make_directory ${FLANG_INTRINSIC_MODULES_DIR}
-      COMMAND flang -cpp -fsyntax-only ${opts} -module-dir ${FLANG_INTRINSIC_MODULES_DIR}
-        ${CMAKE_BINARY_DIR}/projects/openmp/runtime/src/omp_lib.F90
-      DEPENDS flang ${FLANG_INTRINSIC_MODULES_DIR}/iso_c_binding.mod ${CMAKE_BINARY_DIR}/projects/openmp/runtime/src/omp_lib.F90 ${depends}
-    )
-    list(APPEND MODULE_FILES ${base}.mod ${base}_kinds.mod)
-    install(FILES ${base}.mod ${base}_kinds.mod DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/flang" COMPONENT flang-module-interfaces)
-  elseif ("openmp" IN_LIST LLVM_ENABLE_RUNTIMES)
-    message(STATUS "OpenMP runtime support enabled via LLVM_ENABLE_RUNTIMES, assuming omp_lib.mod is built there")
-  else()
-    message(WARNING "Not building omp_lib.mod, no OpenMP runtime in either LLVM_ENABLE_PROJECTS or LLVM_ENABLE_RUNTIMES")
-  endif()
-  add_llvm_install_targets(install-flang-module-interfaces
-    COMPONENT flang-module-interfaces)
-endif()
-
-add_custom_target(module_files ALL DEPENDS ${MODULE_FILES})
-set_target_properties(module_files PROPERTIES FOLDER "Flang/Resources")
-
-# TODO Move this to a more suitable location
-# Copy the generated omp_lib.h header file, if OpenMP support has been configured.
-if (LLVM_TOOL_OPENMP_BUILD)
-  message(STATUS "OpenMP runtime support enabled via LLVM_ENABLE_PROJECTS, building omp_lib.h")
-  file(COPY ${CMAKE_BINARY_DIR}/projects/openmp/runtime/src/omp_lib.h DESTINATION "${CMAKE_BINARY_DIR}/include/flang/OpenMP/" FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
-  install(FILES ${CMAKE_BINARY_DIR}/include/flang/OpenMP/omp_lib.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/flang/OpenMP")
-elseif ("openmp" IN_LIST LLVM_ENABLE_RUNTIMES)
-  message(STATUS "OpenMP runtime support enabled via LLVM_ENABLE_RUNTIMES, assuming omp_lib.h is built there")
-else()
-  message(STATUS "Not copying omp_lib.h, no OpenMP runtime in either LLVM_ENABLE_PROJECTS or LLVM_ENABLE_RUNTIMES")
-endif()
diff --git a/flang/tools/f18/dump.cpp b/flang/tools/f18/dump.cpp
deleted file mode 100644
index f11b5aedf4c6a..0000000000000
--- a/flang/tools/f18/dump.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-//===-- tools/f18/dump.cpp ------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// This file defines Dump routines available for calling from the debugger.
-// Each is based on operator<< for that type. There are overloadings for
-// reference and pointer, and for dumping to a provided raw_ostream or errs().
-
-#ifdef DEBUGF18
-
-#include "llvm/Support/raw_ostream.h"
-
-#define DEFINE_DUMP(ns, name) \
-  namespace ns { \
-  class name; \
-  llvm::raw_ostream &operator<<(llvm::raw_ostream &, const name &); \
-  } \
-  void Dump(llvm::raw_ostream &os, const ns::name &x) { os << x << '\n'; } \
-  void Dump(llvm::raw_ostream &os, const ns::name *x) { \
-    if (x == nullptr) \
-      os << "null\n"; \
-    else \
-      Dump(os, *x); \
-  } \
-  void Dump(const ns::name &x) { Dump(llvm::errs(), x); } \
-  void Dump(const ns::name *x) { Dump(llvm::errs(), *x); }
-
-namespace Fortran {
-DEFINE_DUMP(parser, Name)
-DEFINE_DUMP(parser, CharBlock)
-DEFINE_DUMP(semantics, Symbol)
-DEFINE_DUMP(semantics, Scope)
-DEFINE_DUMP(semantics, IntrinsicTypeSpec)
-DEFINE_DUMP(semantics, DerivedTypeSpec)
-DEFINE_DUMP(semantics, DeclTypeSpec)
-} // namespace Fortran
-
-#endif
diff --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt
index 88fb323e5e449..7f8f239efbe68 100644
--- a/llvm/runtimes/CMakeLists.txt
+++ b/llvm/runtimes/CMakeLists.txt
@@ -252,6 +252,11 @@ function(runtime_default_target)
     # OpenMP tests
     list(APPEND extra_targets "libomp-mod")
   endif ()
+  if ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
+    # The target flang-rt-mod is a dependee of check-flang needed to run its
+    # tests.
+    list(APPEND extra_targets "flang-rt-mod")
+  endif ()
 
   if(LLVM_INCLUDE_TESTS)
     set_property(GLOBAL APPEND PROPERTY LLVM_ALL_LIT_TESTSUITES "@${LLVM_BINARY_DIR}/runtimes/runtimes-bins/lit.tests")
@@ -551,18 +556,15 @@ if(build_runtimes)
   if ("openmp" IN_LIST LLVM_ENABLE_RUNTIMES AND "flang" IN_LIST LLVM_ENABLE_PROJECTS)
     list(APPEND extra_args ENABLE_FORTRAN)
   endif()
-  if("openmp" IN_LIST LLVM_ENABLE_RUNTIMES OR "offload" IN_LIST LLVM_ENABLE_RUNTIMES)
-    if (${LLVM_TOOL_FLANG_BUILD})
-      message(STATUS "Configuring build of omp_lib.mod and omp_lib_kinds.mod via flang")
-      set(LIBOMP_FORTRAN_MODULES_COMPILER "${CMAKE_BINARY_DIR}/bin/flang")
-      set(LIBOMP_MODULES_INSTALL_PATH "${CMAKE_INSTALL_INCLUDEDIR}/flang")
-      # TODO: This is a workaround until flang becomes a first-class project
-      # in llvm/CMakeList.txt.  Until then, this line ensures that flang is
-      # built before "openmp" is built as a runtime project.  Besides "flang"
-      # to build the compiler, we also need to add "module_files" to make sure
-      # that all .mod files are also properly build.
-      list(APPEND extra_deps "flang" "module_files")
+  if("flang" IN_LIST LLVM_ENABLE_PROJECTS)
+    # Ensure REAL(16) support in runtimes to be consistent with compiler
+    if(FLANG_RUNTIME_F128_MATH_LIB OR HAVE_LDBL_MANT_DIG_113)
+      list(APPEND extra_cmake_args "-DFORTRAN_SUPPORTS_REAL16=TRUE")
+    else()
+      list(APPEND extra_cmake_args "-DFORTRAN_SUPPORTS_REAL16=FALSE")
     endif()
+  endif()
+  if("openmp" IN_LIST LLVM_ENABLE_RUNTIMES OR "offload" IN_LIST LLVM_ENABLE_RUNTIMES)
     foreach(dep opt llvm-link llvm-extract clang llvm-offload-binary clang-nvlink-wrapper)
       if(TARGET ${dep})
         list(APPEND extra_deps ${dep})
diff --git a/openmp/CMakeLists.txt b/openmp/CMakeLists.txt
index df568419824a6..44d831623014c 100644
--- a/openmp/CMakeLists.txt
+++ b/openmp/CMakeLists.txt
@@ -134,6 +134,8 @@ set(OPENMP_TEST_FLAGS "" CACHE STRING
   "Extra compiler flags to send to the test compiler.")
 set(OPENMP_TEST_OPENMP_FLAGS ${OPENMP_TEST_COMPILER_OPENMP_FLAGS} CACHE STRING
   "OpenMP compiler flag to use for testing OpenMP runtime libraries.")
+set(OPENMP_TEST_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" CACHE STRING
+  "Additional compiler flags to use for testing Fortran programs (e.g. additional module search paths via -fintrinsic-modules-path )")
 
 set(ENABLE_LIBOMPTARGET ON)
 # Currently libomptarget cannot be compiled on Windows or MacOS X.
@@ -157,13 +159,18 @@ else()
   get_clang_resource_dir(LIBOMP_HEADERS_INSTALL_PATH SUBDIR include)
 endif()
 
+if(RUNTIMES_FLANG_MODULES_ENABLED)
+  add_subdirectory(module)
+else()
+  message(STATUS "Building omp_lib.mod disabled by RUNTIMES_FLANG_MODULES_ENABLED='${RUNTIMES_FLANG_MODULES_ENABLED}'; libomp-mod does nothing")
+  add_custom_target(libomp-mod)
+endif()
+
 # Use the current compiler target to determine the appropriate runtime to build.
 if("${LLVM_DEFAULT_TARGET_TRIPLE}" MATCHES "^amdgcn|^nvptx" OR
    "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "^amdgcn|^nvptx")
   add_subdirectory(device)
 else()
-  add_subdirectory(module)
-
   # Build host runtime library, after LIBOMPTARGET variables are set since they
   # are needed to enable time profiling support in the OpenMP runtime.
   add_subdirectory(runtime)
diff --git a/openmp/README.rst b/openmp/README.rst
index cc485f9a56ce0..e16cfa6583082 100644
--- a/openmp/README.rst
+++ b/openmp/README.rst
@@ -96,7 +96,7 @@ variable.
 
 **CMAKE_Fortran_COMPILER** = <Fortran compiler name>
   Specify the Fortran compiler. This option is only needed when
-  **LIBOMP_FORTRAN_MODULES** is ``ON`` (see below).  So typically, a Fortran
+  **RUNTIMES_FLANG_MODULES_ENABLED** is ``ON``.  So typically, a Fortran
   compiler is not needed during the build.
 
 **CMAKE_ASM_MASM_COMPILER** = ``ml|ml64``
@@ -166,9 +166,6 @@ Options for ``libomp``
 
     Static libraries are not supported on Windows*.
 
-**LIBOMP_FORTRAN_MODULES** = ``OFF|ON``
-  Create the Fortran modules (requires Fortran compiler).
-
 macOS* Fat Libraries
 """"""""""""""""""""
 On macOS* machines, it is possible to build universal (or fat) libraries which
@@ -343,7 +340,7 @@ Advanced Builds with Various Options
 
   .. code-block:: console
 
-    $ cmake -DCMAKE_C_COMPILER=icc -DCMAKE_CXX_COMPILER=icpc -DCMAKE_Fortran_COMPILER=ifort -DLIBOMP_FORTRAN_MODULES=on ..
+    $ cmake -DCMAKE_C_COMPILER=icc -DCMAKE_CXX_COMPILER=icpc -DCMAKE_Fortran_COMPILER=ifort -DRUNTIMES_FLANG_MODULES_ENABLED=on ..
 
 - Have CMake find the C/C++ compiler and specify additional flags for the
   preprocessor and C++ compiler.
diff --git a/openmp/cmake/modules/LibompCheckFortranFlag.cmake b/openmp/cmake/modules/LibompCheckFortranFlag.cmake
deleted file mode 100644
index 344389f989388..0000000000000
--- a/openmp/cmake/modules/LibompCheckFortranFlag.cmake
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-#//===----------------------------------------------------------------------===//
-#//
-#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-#// See https://llvm.org/LICENSE.txt for license information.
-#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#//
-#//===----------------------------------------------------------------------===//
-#
-
-# Checking a fortran compiler flag
-# There is no real trivial way to do this in CMake, so we implement it here
-# this will have ${boolean} = TRUE if the flag succeeds, otherwise false.
-function(libomp_check_fortran_flag flag boolean)
-  if(NOT DEFINED "${boolean}")
-    set(retval TRUE)
-    set(fortran_source
-"      program hello
-           print *, \"Hello World!\"
-      end program hello")
-
-    # Compiling as a part of runtimes introduces ARCH-unknown-linux-gnu as a
-    # part of a working directory.  So adding a guard for unknown.
-    set(failed_regexes "[Ee]rror;[Uu]nknown[^-];[Ss]kipping")
-    include(CheckFortranSourceCompiles)
-    check_fortran_source_compiles("${fortran_source}" ${boolean} FAIL_REGEX "${failed_regexes}")
-    set(${boolean} ${${boolean}} PARENT_SCOPE)
-  endif()
-endfunction()
diff --git a/openmp/cmake/modules/LibompHandleFlags.cmake b/openmp/cmake/modules/LibompHandleFlags.cmake
index c36a88fb862ae..a27c8cc407e11 100644
--- a/openmp/cmake/modules/LibompHandleFlags.cmake
+++ b/openmp/cmake/modules/LibompHandleFlags.cmake
@@ -156,17 +156,6 @@ function(libomp_get_libflags libflags)
   set(${libflags} ${libflags_local_list} PARENT_SCOPE)
 endfunction()
 
-# Fortran flags
-function(libomp_get_fflags fflags)
-  set(fflags_local)
-  if(CMAKE_SIZEOF_VOID_P EQUAL 4)
-    libomp_append(fflags_local -m32 LIBOMP_HAVE_M32_FORTRAN_FLAG)
-  endif()
-  set(fflags_local ${fflags_local} ${LIBOMP_FFLAGS})
-  libomp_setup_flags(fflags_local)
-  set(${fflags} ${fflags_local} PARENT_SCOPE)
-endfunction()
-
 # Python generate-defs.py flags (For Windows only)
 function(libomp_get_gdflags gdflags)
   set(gdflags_local)
diff --git a/openmp/module/CMakeLists.txt b/openmp/module/CMakeLists.txt
index 48f5b0f7a2e86..5a54546fcd285 100644
--- a/openmp/module/CMakeLists.txt
+++ b/openmp/module/CMakeLists.txt
@@ -6,71 +6,38 @@
 #//
 #//===----------------------------------------------------------------------===//
 
-include(LibompCheckFortranFlag)
+# Build the module files if a Fortran compiler is available.
+# Only LLVM_ENABLE_RUNTIMES=openmp is supported, LLVM_ENABLE_PROJECTS=openmp
+# has been deprecated.
 
-set(LIBOMP_FFLAGS "" CACHE STRING
-  "Appended user specified Fortran compiler flags.  These are only used if LIBOMP_FORTRAN_MODULES==TRUE.")
-
-# Enabling Fortran if it is needed
-if (LIBOMP_FORTRAN_MODULES)
-  enable_language(Fortran)
-
-  libomp_check_fortran_flag(-m32 LIBOMP_HAVE_M32_FORTRAN_FLAG)
-endif ()
-
-# Building the Fortran module files
-# One compilation step creates both omp_lib.mod and omp_lib_kinds.mod
-configure_file(omp_lib.F90.var omp_lib.F90 @ONLY)
+configure_file(omp_lib.F90.var "{CMAKE_CURRENT_BINARY_DIR}/omp_lib.F90" @ONLY)
 configure_file(omp_lib.h.var "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.h" @ONLY)
 
-set(BUILD_FORTRAN_MODULES False)
-if (LIBOMP_FORTRAN_MODULES_COMPILER)
-  # If libomp is built as an LLVM runtime and the flang compiler is available,
-  # compile the Fortran module files.
-  message(STATUS "configuring openmp to build Fortran module files using '${LIBOMP_FORTRAN_MODULES_COMPILER}'")
-  set(LIBOMP_FORTRAN_SOURCE_FILE omp_lib.F90)
-  add_custom_target(libomp-mod ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.mod" "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib_kinds.mod")
-  add_custom_command(
-    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.mod" "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib_kinds.mod"
-    COMMAND ${LIBOMP_FORTRAN_MODULES_COMPILER} -cpp -fsyntax-only ${LIBOMP_FORTRAN_SOURCE_FILE} "-J${CMAKE_CURRENT_BINARY_DIR}/../runtime/src"
-    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${LIBOMP_FORTRAN_SOURCE_FILE}"
-  )
-  set(BUILD_FORTRAN_MODULES True)
-elseif (LIBOMP_FORTRAN_MODULES)
-  # The following requests explicit building of the Fortran module files
-  # Workaround for gfortran to build modules with the
-  # omp_sched_monotonic integer parameter
-  if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
-    set(ADDITIONAL_Fortran_FLAGS "-fno-range-check")
-  endif ()
-  add_custom_target(libomp-mod ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.mod" "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib_kinds.mod")
-  set_target_properties(libomp-mod PROPERTIES FOLDER "OpenMP/Misc")
-  libomp_get_fflags(LIBOMP_CONFIGURED_FFLAGS)
-  if (CMAKE_Fortran_COMPILER_SUPPORTS_F90)
-    set(LIBOMP_FORTRAN_SOURCE_FILE omp_lib.F90)
-  else ()
-    message(FATAL_ERROR "Fortran module build requires Fortran 90 compiler")
-  endif ()
-  add_custom_command(
-    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.mod" "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib_kinds.mod"
-    COMMAND ${CMAKE_Fortran_COMPILER} -c ${ADDITIONAL_Fortran_FLAGS}
-            ${LIBOMP_CONFIGURED_FFLAGS} ${LIBOMP_FORTRAN_SOURCE_FILE} "-J${CMAKE_CURRENT_BINARY_DIR}/../runtime/src"
-    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${LIBOMP_FORTRAN_SOURCE_FILE}"
-  )
-  set_property(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src" PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "omp_lib${CMAKE_C_OUTPUT_EXTENSION}")
-  set(BUILD_FORTRAN_MODULES True)
+# One compilation step creates both omp_lib.mod and omp_lib_kinds.mod. Only
+# these files are used, the object file itself can be discarded.
+# FIXME: Adding it to libomp.so would allow implementing Fortran API in Fortran
+add_library(libomp-mod OBJECT
+  "{CMAKE_CURRENT_BINARY_DIR}/omp_lib.F90"
+)
+set_target_properties(libomp-mod PROPERTIES FOLDER "OpenMP/Fortran Modules")
+
+# The following requests explicit building of the Fortran module files
+# Workaround for gfortran to build modules with the
+# omp_sched_monotonic integer parameter
+if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
+  target_compile_options(libomp-mod PRIVATE -fno-range-check)
 endif ()
 
+flang_module_target(libomp-mod PUBLIC)
+if (FORTRAN_MODULE_DEPS)
+  add_dependencies(libomp-mod ${FORTRAN_MODULE_DEPS})
+endif ()
 
-if (BUILD_FORTRAN_MODULES)
-  set(destination "${LIBOMP_HEADERS_INSTALL_PATH}")
-  if (LIBOMP_MODULES_INSTALL_PATH)
-    set(destination "${LIBOMP_MODULES_INSTALL_PATH}")
-  endif ()
-  install(FILES
-    "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.mod"
-    "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib_kinds.mod"
-    "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.h"
-    DESTINATION ${destination}
-  )
+set(destination "${LIBOMP_HEADERS_INSTALL_PATH}")
+if (LIBOMP_MODULES_INSTALL_PATH)
+  set(destination "${LIBOMP_MODULES_INSTALL_PATH}")
 endif ()
+install(FILES
+  "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.h"
+  DESTINATION ${destination}
+)
diff --git a/openmp/runtime/CMakeLists.txt b/openmp/runtime/CMakeLists.txt
index 93948b941f0dc..1917af595288f 100644
--- a/openmp/runtime/CMakeLists.txt
+++ b/openmp/runtime/CMakeLists.txt
@@ -422,7 +422,7 @@ if(${OPENMP_STANDALONE_BUILD})
   libomp_say("Build Type           -- ${CMAKE_BUILD_TYPE}")
   libomp_say("Library Kind         -- ${LIBOMP_LIBRARY_KIND}")
   libomp_say("Library Type         -- ${LIBOMP_LIB_TYPE}")
-  libomp_say("Fortran Modules      -- ${LIBOMP_FORTRAN_MODULES}")
+  libomp_say("Fortran Modules      -- ${RUNTIMES_FLANG_MODULES_ENABLED}")
   # will say development if all zeros
   if(${LIBOMP_VERSION_BUILD} STREQUAL 00000000)
     set(LIBOMP_BUILD Development)
diff --git a/openmp/runtime/cmake/LibompExports.cmake b/openmp/runtime/cmake/LibompExports.cmake
index 6dfe4f4569aa1..39bc8cebbe178 100644
--- a/openmp/runtime/cmake/LibompExports.cmake
+++ b/openmp/runtime/cmake/LibompExports.cmake
@@ -56,21 +56,21 @@ set(LIBOMP_EXPORTS_LIB_DIR "${LIBOMP_EXPORTS_DIR}/${libomp_platform}${libomp_suf
 # Put headers in exports/ directory post build
 add_custom_command(TARGET omp POST_BUILD
   COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBOMP_EXPORTS_CMN_DIR}
-  COMMAND ${CMAKE_COMMAND} -E copy omp.h ${LIBOMP_EXPORTS_CMN_DIR}
-  COMMAND ${CMAKE_COMMAND} -E copy ompx.h ${LIBOMP_EXPORTS_CMN_DIR}
+  COMMAND ${CMAKE_COMMAND} -E copy ${LIBOMP_HEADERS_INTDIR}/omp.h ${LIBOMP_EXPORTS_CMN_DIR}
+  COMMAND ${CMAKE_COMMAND} -E copy ${LIBOMP_HEADERS_INTDIR}/ompx.h ${LIBOMP_EXPORTS_CMN_DIR}
 )
 if(${LIBOMP_OMPT_SUPPORT})
   add_custom_command(TARGET omp POST_BUILD
     COMMAND ${CMAKE_COMMAND} -E copy omp-tools.h ${LIBOMP_EXPORTS_CMN_DIR}
   )
 endif()
-if(${LIBOMP_FORTRAN_MODULES})
+if(RUNTIMES_FLANG_MODULES_ENABLED)
   # We cannot attach a POST_BUILD command to libomp-mod, so instead attach it
   # to omp and ensure that libomp-mod is built before by adding a dependency
   add_custom_command(TARGET omp POST_BUILD
     COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBOMP_EXPORTS_MOD_DIR}
-    COMMAND ${CMAKE_COMMAND} -E copy omp_lib.mod ${LIBOMP_EXPORTS_MOD_DIR}
-    COMMAND ${CMAKE_COMMAND} -E copy omp_lib_kinds.mod ${LIBOMP_EXPORTS_MOD_DIR}
+    COMMAND ${CMAKE_COMMAND} -E copy ${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}/omp_lib.mod ${LIBOMP_EXPORTS_MOD_DIR}
+    COMMAND ${CMAKE_COMMAND} -E copy ${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}/omp_lib_kinds.mod ${LIBOMP_EXPORTS_MOD_DIR}
   )
   add_dependencies(omp libomp-mod)
   add_custom_command(TARGET omp POST_BUILD
diff --git a/openmp/runtime/test/lit.cfg b/openmp/runtime/test/lit.cfg
index 72da1ba1411f8..a4e3aa505638a 100644
--- a/openmp/runtime/test/lit.cfg
+++ b/openmp/runtime/test/lit.cfg
@@ -48,6 +48,7 @@ if config.test_fortran_compiler:
         ToolSubst(
             "%flang",
             command=config.test_fortran_compiler,
+            extra_args=config.test_fortran_flags.split(),
             unresolved="fatal",
         ),
     ], [config.llvm_tools_dir])
diff --git a/openmp/runtime/test/lit.site.cfg.in b/openmp/runtime/test/lit.site.cfg.in
index cc8b3b252d7d1..fd0ad30228026 100644
--- a/openmp/runtime/test/lit.site.cfg.in
+++ b/openmp/runtime/test/lit.site.cfg.in
@@ -8,6 +8,7 @@ config.test_compiler_has_omp_h = @OPENMP_TEST_COMPILER_HAS_OMP_H@
 config.test_filecheck = "@OPENMP_FILECHECK_EXECUTABLE@"
 config.test_not = "@OPENMP_NOT_EXECUTABLE@"
 config.test_openmp_flags = "@OPENMP_TEST_OPENMP_FLAGS@"
+config.test_fortran_flags = "@OPENMP_TEST_Fortran_FLAGS@"
 config.test_extra_flags = "@OPENMP_TEST_FLAGS@"
 config.libomp_obj_root = "@CMAKE_CURRENT_BINARY_DIR@"
 config.library_dir = "@LIBOMP_LIBRARY_DIR@"
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 5220b9353fed7..a5bb2d975272e 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -85,6 +85,195 @@ include(CheckLibraryExists)
 include(LLVMCheckCompilerLinkerFlag)
 include(CheckCCompilerFlag)
 include(CheckCXXCompilerFlag)
+include(GetToolchainDirs)
+include(ExtendPath)
+
+# Check whether the Fortran compiler already access to builtin modules. Sets
+# HAVE_FORTRAN_INTRINSIC_MODS when returning.
+#
+# This must be wrapped in a function because
+# cmake_push_check_state/cmake_pop_check_state is insufficient to isolate
+# a compiler introspection environment, see
+# https://gitlab.kitware.com/cmake/cmake/-/issues/27419
+function (check_fortran_builtins_available)
+  if (CMAKE_Fortran_COMPILER_FORCED AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+    # CMake's try_compile does not take a user-defined
+    # CMAKE_Fortran_PREPROCESS_SOURCE into account. Instead of test-compiling,
+    # ask Flang directly for the builtin module files.
+    if (NOT DEFINED HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD)
+      message(STATUS "Performing Test ISO_C_BINDING_PATH")
+      execute_process(
+        COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_FLAGS} "-print-file-name=iso_c_binding.mod"
+        OUTPUT_VARIABLE ISO_C_BINDING_PATH
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+        ERROR_QUIET
+      )
+      set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD "" )
+      if (EXISTS "${ISO_C_BINDING_PATH}")
+        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Success")
+        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD TRUE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
+      else ()
+        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Failed")
+        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD FALSE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
+      endif ()
+    endif ()
+  else ()
+    cmake_push_check_state(RESET)
+    set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+    check_fortran_source_compiles("
+      subroutine testroutine
+        use iso_c_binding
+      end subroutine
+      " HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD SRC_EXT F90)
+    cmake_pop_check_state()
+  endif ()
+  set(HAVE_FORTRAN_INTRINSIC_MODS "${HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD}" PARENT_SCOPE)
+endfunction ()
+
+
+# Set options to compile Fortran module files.
+#
+# Usage:
+#
+# flang_module_target(name
+#   PUBLIC
+#     Modules files are to be used by other Fortran sources. If a library is
+#     compiled multiple times (e.g. static/shared, or msvcrt variants), only
+#     one of those can be public module files; non-public modules are still
+#     generated but to be forgotten deep inside the build directory to not
+#     conflict with each other.
+#     Also, installs the module with the toolchain.
+# )
+function (flang_module_target tgtname)
+  set(options PUBLIC)
+  cmake_parse_arguments(ARG
+    "${options}"
+    ""
+    ""
+    ${ARGN})
+
+  if (NOT RUNTIMES_FLANG_MODULES_ENABLED)
+    message(WARNING "Cannot build module files for ${tgtname} when RUNTIMES_FLANG_MODULES_ENABLED is ${RUNTIMES_FLANG_MODULES_ENABLED}")
+    return ()
+  endif ()
+
+  target_compile_options(${tgtname} PRIVATE
+      # Let non-public modules find the public module files
+      "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
+
+      # Flang bug workaround: Reformating of cooked token buffer causes identifier to be split between lines
+      "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-Xflang;SHELL:-fno-reformat>"
+    )
+
+  if (LLVM_RUNTIMES_TARGET MATCHES "^nvptx")
+    foreach (_arch IN LISTS RUNTIMES_DEVICE_ARCHITECTURES)
+      target_compile_options(${tgtname} PRIVATE
+       "$<$<COMPILE_LANGUAGE:Fortran>:-march=${_arch}>"
+      )
+    endforeach()
+  endif ()
+
+  if (ARG_PUBLIC)
+    set_target_properties(${tgtname}
+      PROPERTIES
+        Fortran_MODULE_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+      )
+  else ()
+    set_target_properties(${tgtname}
+      PROPERTIES
+        Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${tgtname}.mod"
+      )
+  endif ()
+endfunction ()
+
+# Check whether the build environment supports building Fortran modules
+# flang-rt and openmp are the only runtimes that contain Fortran modules.
+set(FORTRAN_MODULE_DEPS "")
+if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES))
+  cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
+
+  if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
+    # CMake 3.24 is the first version of CMake that directly recognizes Flang.
+    # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
+    if (CMAKE_VERSION VERSION_LESS "3.24")
+      include(CMakeForceCompiler)
+      CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
+
+      set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
+      set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
+
+      set(CMAKE_Fortran_SUBMODULE_SEP "-")
+      set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
+
+      set(CMAKE_Fortran_PREPROCESS_SOURCE
+        "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+
+      set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
+      set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
+
+      set(CMAKE_Fortran_MODDIR_FLAG "-J")
+
+      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
+      set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
+
+      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
+      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
+
+      set(CMAKE_Fortran_VERBOSE_FLAG "-v")
+
+      set(CMAKE_Fortran_LINK_MODE DRIVER)
+    endif ()
+
+    # Optimization flags are only passed after CMake 3.27.4
+    # https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
+    if (CMAKE_VERSION VERSION_LESS "3.27.4")
+      string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
+      string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+      string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
+    endif ()
+
+    # Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
+    # to nvptx amd amdgpu targets, passing the target triple is essential.
+    # https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
+    if (CMAKE_VERSION VERSION_LESS "3.28")
+      set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
+    endif ()
+  endif ()
+
+  include(CheckFortranSourceCompiles)
+  include(CheckLanguage)
+
+  set(RUNTIMES_FLANG_MODULES_ENABLED_default OFF)
+  check_language(Fortran)
+  if (CMAKE_Fortran_COMPILER)
+    enable_language(Fortran)
+
+    if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
+      # In a bootstrapping build (or any runtimes-build that includes flang-rt),
+      # the intrinsic modules are not built yet. Targets can depend on
+      # flang-rt-mod to ensure that flang-rt's modules are built first.
+      set(FORTRAN_MODULE_DEPS flang-rt-mod)
+      set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+    else ()
+      # Check whether building modules works, avoid causing the entire build to
+      # fail because of Fortran. The primary situation we want to support here
+      # is Flang, or its intrinsic modules were built separately in a
+      # non-bootstrapping build.
+      check_fortran_builtins_available()
+      if (HAVE_FORTRAN_INTRINSIC_MODS)
+        set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+        message(STATUS "${LLVM_SUBPROJECT_TITLE}: Non-bootstrapping Fortran modules build (${CMAKE_Fortran_COMPILER_ID} located at ${CMAKE_Fortran_COMPILER})")
+      else ()
+        message(STATUS "Not compiling Flang modules: Not passing smoke check")
+      endif ()
+    endif ()
+  endif ()
+
+  option(RUNTIMES_FLANG_MODULES_ENABLED "Build Fortran modules" "${RUNTIMES_FLANG_MODULES_ENABLED_default}")
+else ()
+  set(RUNTIMES_FLANG_MODULES_ENABLED NO)
+endif ()
 
 
 # Determine whether we are in the runtimes/runtimes-bins directory of a
@@ -94,17 +283,6 @@ if (LLVM_LIBRARY_DIR AND LLVM_TOOLS_BINARY_DIR AND PACKAGE_VERSION)
   set(LLVM_TREE_AVAILABLE ON)
 endif()
 
-if(LLVM_TREE_AVAILABLE)
-  # Setting these variables will allow the sub-build to put their outputs into
-  # the library and bin directories of the top-level build.
-  set(LLVM_LIBRARY_OUTPUT_INTDIR ${LLVM_LIBRARY_DIR})
-  set(LLVM_RUNTIME_OUTPUT_INTDIR ${LLVM_TOOLS_BINARY_DIR})
-else()
-  # Use own build directory for artifact output.
-  set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}")
-  set(LLVM_RUNTIME_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin")
-endif()
-
 # CMake omits default compiler include paths, but in runtimes build, we use
 # -nostdinc and -nostdinc++ and control include paths manually so this behavior
 # is undesirable. Filtering CMAKE_{LANG}_IMPLICIT_INCLUDE_DIRECTORIES to remove
@@ -236,6 +414,109 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
   endif()
 endif()
 
+# Determine output and install paths based on LLVM_TARGET_TRIPLE
+if(LLVM_TREE_AVAILABLE)
+  # In a bootstrap build emit the libraries into a default search path in the
+  # build directory of the just-built compiler. This allows using the
+  # just-built compiler without specifying paths to runtime libraries.
+  # LLVM_LIBRARY_OUTPUT_INTDIR/LLVM_RUNTIME_OUTPUT_INTDIR is used by
+  # AddLLVM.cmake as artifact output locations.
+  set(LLVM_LIBRARY_OUTPUT_INTDIR ${LLVM_LIBRARY_DIR})
+  set(LLVM_RUNTIME_OUTPUT_INTDIR ${LLVM_TOOLS_BINARY_DIR})
+
+  # Despite Clang in the name, get_clang_resource_dir does not depend on Clang
+  # being added to the build. Flang uses the same resource dir as Clang.
+  include(GetClangResourceDir)
+  get_clang_resource_dir(RUNTIMES_OUTPUT_RESOURCE_DIR PREFIX "${LLVM_LIBRARY_OUTPUT_INTDIR}/..")
+  get_clang_resource_dir(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT)
+else()
+  # In a standalone runtimes build, do not write into LLVM_BINARY_DIR. It may be
+  # read-only and/or shared by multiple runtimes with different build
+  # configurations (e.g. Debug/Release). Use the runtime's own lib dir like any
+  # non-toolchain library. Use own build directory for artifact output.
+  set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}")
+  set(LLVM_RUNTIME_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin")
+
+  # For the install prefix, still use the resource dir assuming that Flang will
+  # be installed there using the same prefix. This is to not have a difference
+  # between bootstrap and standalone runtimes builds.
+  set(RUNTIMES_OUTPUT_RESOURCE_DIR "${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
+  set(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT "lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
+endif()
+
+# Determine build and install paths.
+# The build path is absolute, but the install dir is relative, CMake's install
+# command has to apply CMAKE_INSTALL_PREFIX itself.
+# FIXME: For shared libraries, the toolchain resource lib dir is not a good
+#        destination because it is not a ld.so default search path.
+#        The machine where the executable is eventually executed may not be the
+#        machine where the Flang compiler and its resource dir is installed, so
+#        setting RPath by the driver is not an solution. It should belong into
+#        /usr/lib/<triple>/lib<name>.so, like e.g. libgcc_s.so.
+#        But the linker as invoked by the Flang driver also requires
+#        libflang_rt.so to be found when linking and the resource lib dir is
+#        the only reliable location.
+get_toolchain_library_subdir(toolchain_lib_subdir)
+extend_path(RUNTIMES_OUTPUT_RESOURCE_LIB_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_lib_subdir}")
+
+set(RUNTIMES_INSTALL_RESOURCE_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT}" CACHE PATH "Path to install headers, runtime libraries, and Fortran modules to (default: Clang resource dir)")
+extend_path(RUNTIMES_INSTALL_RESOURCE_LIB_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_lib_subdir}")
+
+cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_DIR)
+cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_PATH)
+cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_LIB_DIR)
+cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
+
+
+if (RUNTIMES_FLANG_MODULES_ENABLED)
+  if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+    # Flang expects its builtin modules in Clang's resource directory
+    get_toolchain_module_subdir(toolchain_mod_subdir)
+    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
+    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
+  else ()
+    # For non-Flang compilers, avoid the risk of Flang accidentally picking them up.
+    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+  endif ()
+  cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
+  cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
+
+  # No way to find out which mod files are built by a target, so install the
+  # entire output directory
+  # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
+  set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
+  cmake_path(NORMAL_PATH destination)
+    install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+      DESTINATION "${destination}"
+    )
+endif ()
+
+
+if (RUNTIMES_FLANG_MODULES_ENABLED)
+  set(RUNTIMES_DEVICE_ARCHITECTURES "all" CACHE STRING
+      "List of offload device architectures to be used to compile the Fortran offload code (e.g. 'gfx1103;sm_90')"
+    )
+
+  if (RUNTIMES_DEVICE_ARCHITECTURES STREQUAL "all")
+    # TODO: support auto detection on the build system.
+    set(all_amdgpu_architectures
+      "gfx700;gfx701;gfx801;gfx803;gfx900;gfx902;gfx906"
+      "gfx908;gfx90a;gfx90c;gfx940;gfx1010;gfx1030"
+      "gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036"
+      "gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151"
+      "gfx1152;gfx1153")
+    set(all_nvptx_architectures
+      "sm_35;sm_37;sm_50;sm_52;sm_53;sm_60;sm_61;sm_62"
+      "sm_70;sm_72;sm_75;sm_80;sm_86;sm_89;sm_90")
+    set(all_gpu_architectures
+      "${all_amdgpu_architectures};${all_nvptx_architectures}")
+      set(RUNTIMES_DEVICE_ARCHITECTURES ${all_gpu_architectures})
+  endif()
+  list(REMOVE_DUPLICATES RUNTIMES_DEVICE_ARCHITECTURES)
+endif ()
+
+
 option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
 option(LLVM_INCLUDE_DOCS "Generate build targets for the runtimes documentation." ON)
 option(LLVM_ENABLE_SPHINX "Use Sphinx to generate the runtimes documentation." OFF)

>From cc7a3242e91940b0bb304917fb03655599e55974 Mon Sep 17 00:00:00 2001
From: Michael Kruse <michael.kruse at amd.com>
Date: Wed, 10 Dec 2025 06:10:43 -0600
Subject: [PATCH 02/53] Move GetToolchainDirs.cmake

---
 {flang-rt/cmake/modules => cmake/Modules}/GetToolchainDirs.cmake | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename {flang-rt/cmake/modules => cmake/Modules}/GetToolchainDirs.cmake (100%)

diff --git a/flang-rt/cmake/modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
similarity index 100%
rename from flang-rt/cmake/modules/GetToolchainDirs.cmake
rename to cmake/Modules/GetToolchainDirs.cmake

>From 4ff6d124565cac0975951e5b310266543de66fa3 Mon Sep 17 00:00:00 2001
From: Michael Kruse <michael.kruse at amd.com>
Date: Wed, 10 Dec 2025 06:27:32 -0600
Subject: [PATCH 03/53] Backport runtimes files

---
 cmake/Modules/GetToolchainDirs.cmake |  11 +
 runtimes/CMakeLists.txt              | 303 ++++++++++++++++++++++++++-
 2 files changed, 303 insertions(+), 11 deletions(-)

diff --git a/cmake/Modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
index fba12502b5946..ce2f8c294b2bc 100644
--- a/cmake/Modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -47,6 +47,17 @@ function (get_toolchain_library_subdir outvar)
 endfunction ()
 
 
+# Corresponds to Flang's ToolChain::getDefaultIntrinsicModuleDir().
+function (get_toolchain_module_subdir outvar)
+  set(outval "finclude/flang")
+
+  get_toolchain_arch_dirname(arch_dirname)
+  set(outval "${outval}/${arch_dirname}")
+
+  set(${outvar} "${outval}" PARENT_SCOPE)
+endfunction ()
+
+
 # Corresponds to Clang's ToolChain::getOSLibName(). Adapted from Compiler-RT.
 function (get_toolchain_os_dirname outvar)
   if (ANDROID)
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 5220b9353fed7..a5bb2d975272e 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -85,6 +85,195 @@ include(CheckLibraryExists)
 include(LLVMCheckCompilerLinkerFlag)
 include(CheckCCompilerFlag)
 include(CheckCXXCompilerFlag)
+include(GetToolchainDirs)
+include(ExtendPath)
+
+# Check whether the Fortran compiler already access to builtin modules. Sets
+# HAVE_FORTRAN_INTRINSIC_MODS when returning.
+#
+# This must be wrapped in a function because
+# cmake_push_check_state/cmake_pop_check_state is insufficient to isolate
+# a compiler introspection environment, see
+# https://gitlab.kitware.com/cmake/cmake/-/issues/27419
+function (check_fortran_builtins_available)
+  if (CMAKE_Fortran_COMPILER_FORCED AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+    # CMake's try_compile does not take a user-defined
+    # CMAKE_Fortran_PREPROCESS_SOURCE into account. Instead of test-compiling,
+    # ask Flang directly for the builtin module files.
+    if (NOT DEFINED HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD)
+      message(STATUS "Performing Test ISO_C_BINDING_PATH")
+      execute_process(
+        COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_FLAGS} "-print-file-name=iso_c_binding.mod"
+        OUTPUT_VARIABLE ISO_C_BINDING_PATH
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+        ERROR_QUIET
+      )
+      set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD "" )
+      if (EXISTS "${ISO_C_BINDING_PATH}")
+        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Success")
+        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD TRUE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
+      else ()
+        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Failed")
+        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD FALSE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
+      endif ()
+    endif ()
+  else ()
+    cmake_push_check_state(RESET)
+    set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+    check_fortran_source_compiles("
+      subroutine testroutine
+        use iso_c_binding
+      end subroutine
+      " HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD SRC_EXT F90)
+    cmake_pop_check_state()
+  endif ()
+  set(HAVE_FORTRAN_INTRINSIC_MODS "${HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD}" PARENT_SCOPE)
+endfunction ()
+
+
+# Set options to compile Fortran module files.
+#
+# Usage:
+#
+# flang_module_target(name
+#   PUBLIC
+#     Modules files are to be used by other Fortran sources. If a library is
+#     compiled multiple times (e.g. static/shared, or msvcrt variants), only
+#     one of those can be public module files; non-public modules are still
+#     generated but to be forgotten deep inside the build directory to not
+#     conflict with each other.
+#     Also, installs the module with the toolchain.
+# )
+function (flang_module_target tgtname)
+  set(options PUBLIC)
+  cmake_parse_arguments(ARG
+    "${options}"
+    ""
+    ""
+    ${ARGN})
+
+  if (NOT RUNTIMES_FLANG_MODULES_ENABLED)
+    message(WARNING "Cannot build module files for ${tgtname} when RUNTIMES_FLANG_MODULES_ENABLED is ${RUNTIMES_FLANG_MODULES_ENABLED}")
+    return ()
+  endif ()
+
+  target_compile_options(${tgtname} PRIVATE
+      # Let non-public modules find the public module files
+      "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
+
+      # Flang bug workaround: Reformating of cooked token buffer causes identifier to be split between lines
+      "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-Xflang;SHELL:-fno-reformat>"
+    )
+
+  if (LLVM_RUNTIMES_TARGET MATCHES "^nvptx")
+    foreach (_arch IN LISTS RUNTIMES_DEVICE_ARCHITECTURES)
+      target_compile_options(${tgtname} PRIVATE
+       "$<$<COMPILE_LANGUAGE:Fortran>:-march=${_arch}>"
+      )
+    endforeach()
+  endif ()
+
+  if (ARG_PUBLIC)
+    set_target_properties(${tgtname}
+      PROPERTIES
+        Fortran_MODULE_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+      )
+  else ()
+    set_target_properties(${tgtname}
+      PROPERTIES
+        Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${tgtname}.mod"
+      )
+  endif ()
+endfunction ()
+
+# Check whether the build environment supports building Fortran modules
+# flang-rt and openmp are the only runtimes that contain Fortran modules.
+set(FORTRAN_MODULE_DEPS "")
+if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES))
+  cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
+
+  if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
+    # CMake 3.24 is the first version of CMake that directly recognizes Flang.
+    # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
+    if (CMAKE_VERSION VERSION_LESS "3.24")
+      include(CMakeForceCompiler)
+      CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
+
+      set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
+      set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
+
+      set(CMAKE_Fortran_SUBMODULE_SEP "-")
+      set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
+
+      set(CMAKE_Fortran_PREPROCESS_SOURCE
+        "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+
+      set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
+      set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
+
+      set(CMAKE_Fortran_MODDIR_FLAG "-J")
+
+      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
+      set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
+
+      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
+      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
+
+      set(CMAKE_Fortran_VERBOSE_FLAG "-v")
+
+      set(CMAKE_Fortran_LINK_MODE DRIVER)
+    endif ()
+
+    # Optimization flags are only passed after CMake 3.27.4
+    # https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
+    if (CMAKE_VERSION VERSION_LESS "3.27.4")
+      string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
+      string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+      string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
+    endif ()
+
+    # Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
+    # to nvptx amd amdgpu targets, passing the target triple is essential.
+    # https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
+    if (CMAKE_VERSION VERSION_LESS "3.28")
+      set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
+    endif ()
+  endif ()
+
+  include(CheckFortranSourceCompiles)
+  include(CheckLanguage)
+
+  set(RUNTIMES_FLANG_MODULES_ENABLED_default OFF)
+  check_language(Fortran)
+  if (CMAKE_Fortran_COMPILER)
+    enable_language(Fortran)
+
+    if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
+      # In a bootstrapping build (or any runtimes-build that includes flang-rt),
+      # the intrinsic modules are not built yet. Targets can depend on
+      # flang-rt-mod to ensure that flang-rt's modules are built first.
+      set(FORTRAN_MODULE_DEPS flang-rt-mod)
+      set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+    else ()
+      # Check whether building modules works, avoid causing the entire build to
+      # fail because of Fortran. The primary situation we want to support here
+      # is Flang, or its intrinsic modules were built separately in a
+      # non-bootstrapping build.
+      check_fortran_builtins_available()
+      if (HAVE_FORTRAN_INTRINSIC_MODS)
+        set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+        message(STATUS "${LLVM_SUBPROJECT_TITLE}: Non-bootstrapping Fortran modules build (${CMAKE_Fortran_COMPILER_ID} located at ${CMAKE_Fortran_COMPILER})")
+      else ()
+        message(STATUS "Not compiling Flang modules: Not passing smoke check")
+      endif ()
+    endif ()
+  endif ()
+
+  option(RUNTIMES_FLANG_MODULES_ENABLED "Build Fortran modules" "${RUNTIMES_FLANG_MODULES_ENABLED_default}")
+else ()
+  set(RUNTIMES_FLANG_MODULES_ENABLED NO)
+endif ()
 
 
 # Determine whether we are in the runtimes/runtimes-bins directory of a
@@ -94,17 +283,6 @@ if (LLVM_LIBRARY_DIR AND LLVM_TOOLS_BINARY_DIR AND PACKAGE_VERSION)
   set(LLVM_TREE_AVAILABLE ON)
 endif()
 
-if(LLVM_TREE_AVAILABLE)
-  # Setting these variables will allow the sub-build to put their outputs into
-  # the library and bin directories of the top-level build.
-  set(LLVM_LIBRARY_OUTPUT_INTDIR ${LLVM_LIBRARY_DIR})
-  set(LLVM_RUNTIME_OUTPUT_INTDIR ${LLVM_TOOLS_BINARY_DIR})
-else()
-  # Use own build directory for artifact output.
-  set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}")
-  set(LLVM_RUNTIME_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin")
-endif()
-
 # CMake omits default compiler include paths, but in runtimes build, we use
 # -nostdinc and -nostdinc++ and control include paths manually so this behavior
 # is undesirable. Filtering CMAKE_{LANG}_IMPLICIT_INCLUDE_DIRECTORIES to remove
@@ -236,6 +414,109 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
   endif()
 endif()
 
+# Determine output and install paths based on LLVM_TARGET_TRIPLE
+if(LLVM_TREE_AVAILABLE)
+  # In a bootstrap build emit the libraries into a default search path in the
+  # build directory of the just-built compiler. This allows using the
+  # just-built compiler without specifying paths to runtime libraries.
+  # LLVM_LIBRARY_OUTPUT_INTDIR/LLVM_RUNTIME_OUTPUT_INTDIR is used by
+  # AddLLVM.cmake as artifact output locations.
+  set(LLVM_LIBRARY_OUTPUT_INTDIR ${LLVM_LIBRARY_DIR})
+  set(LLVM_RUNTIME_OUTPUT_INTDIR ${LLVM_TOOLS_BINARY_DIR})
+
+  # Despite Clang in the name, get_clang_resource_dir does not depend on Clang
+  # being added to the build. Flang uses the same resource dir as Clang.
+  include(GetClangResourceDir)
+  get_clang_resource_dir(RUNTIMES_OUTPUT_RESOURCE_DIR PREFIX "${LLVM_LIBRARY_OUTPUT_INTDIR}/..")
+  get_clang_resource_dir(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT)
+else()
+  # In a standalone runtimes build, do not write into LLVM_BINARY_DIR. It may be
+  # read-only and/or shared by multiple runtimes with different build
+  # configurations (e.g. Debug/Release). Use the runtime's own lib dir like any
+  # non-toolchain library. Use own build directory for artifact output.
+  set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}")
+  set(LLVM_RUNTIME_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin")
+
+  # For the install prefix, still use the resource dir assuming that Flang will
+  # be installed there using the same prefix. This is to not have a difference
+  # between bootstrap and standalone runtimes builds.
+  set(RUNTIMES_OUTPUT_RESOURCE_DIR "${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
+  set(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT "lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
+endif()
+
+# Determine build and install paths.
+# The build path is absolute, but the install dir is relative, CMake's install
+# command has to apply CMAKE_INSTALL_PREFIX itself.
+# FIXME: For shared libraries, the toolchain resource lib dir is not a good
+#        destination because it is not a ld.so default search path.
+#        The machine where the executable is eventually executed may not be the
+#        machine where the Flang compiler and its resource dir is installed, so
+#        setting RPath by the driver is not an solution. It should belong into
+#        /usr/lib/<triple>/lib<name>.so, like e.g. libgcc_s.so.
+#        But the linker as invoked by the Flang driver also requires
+#        libflang_rt.so to be found when linking and the resource lib dir is
+#        the only reliable location.
+get_toolchain_library_subdir(toolchain_lib_subdir)
+extend_path(RUNTIMES_OUTPUT_RESOURCE_LIB_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_lib_subdir}")
+
+set(RUNTIMES_INSTALL_RESOURCE_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT}" CACHE PATH "Path to install headers, runtime libraries, and Fortran modules to (default: Clang resource dir)")
+extend_path(RUNTIMES_INSTALL_RESOURCE_LIB_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_lib_subdir}")
+
+cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_DIR)
+cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_PATH)
+cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_LIB_DIR)
+cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
+
+
+if (RUNTIMES_FLANG_MODULES_ENABLED)
+  if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+    # Flang expects its builtin modules in Clang's resource directory
+    get_toolchain_module_subdir(toolchain_mod_subdir)
+    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
+    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
+  else ()
+    # For non-Flang compilers, avoid the risk of Flang accidentally picking them up.
+    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+  endif ()
+  cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
+  cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
+
+  # No way to find out which mod files are built by a target, so install the
+  # entire output directory
+  # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
+  set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
+  cmake_path(NORMAL_PATH destination)
+    install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+      DESTINATION "${destination}"
+    )
+endif ()
+
+
+if (RUNTIMES_FLANG_MODULES_ENABLED)
+  set(RUNTIMES_DEVICE_ARCHITECTURES "all" CACHE STRING
+      "List of offload device architectures to be used to compile the Fortran offload code (e.g. 'gfx1103;sm_90')"
+    )
+
+  if (RUNTIMES_DEVICE_ARCHITECTURES STREQUAL "all")
+    # TODO: support auto detection on the build system.
+    set(all_amdgpu_architectures
+      "gfx700;gfx701;gfx801;gfx803;gfx900;gfx902;gfx906"
+      "gfx908;gfx90a;gfx90c;gfx940;gfx1010;gfx1030"
+      "gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036"
+      "gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151"
+      "gfx1152;gfx1153")
+    set(all_nvptx_architectures
+      "sm_35;sm_37;sm_50;sm_52;sm_53;sm_60;sm_61;sm_62"
+      "sm_70;sm_72;sm_75;sm_80;sm_86;sm_89;sm_90")
+    set(all_gpu_architectures
+      "${all_amdgpu_architectures};${all_nvptx_architectures}")
+      set(RUNTIMES_DEVICE_ARCHITECTURES ${all_gpu_architectures})
+  endif()
+  list(REMOVE_DUPLICATES RUNTIMES_DEVICE_ARCHITECTURES)
+endif ()
+
+
 option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
 option(LLVM_INCLUDE_DOCS "Generate build targets for the runtimes documentation." ON)
 option(LLVM_ENABLE_SPHINX "Use Sphinx to generate the runtimes documentation." OFF)

>From d4b194d6ce7e11fb565a41a78bbe0d459bea09fd Mon Sep 17 00:00:00 2001
From: Michael Kruse <michael.kruse at amd.com>
Date: Wed, 10 Dec 2025 06:45:31 -0600
Subject: [PATCH 04/53] Avoid redundancies in flang-rt CMakeLists.txt

---
 flang-rt/CMakeLists.txt                 | 90 +------------------------
 flang-rt/cmake/modules/AddFlangRT.cmake |  8 +--
 flang-rt/test/lit.site.cfg.py.in        |  2 +-
 3 files changed, 6 insertions(+), 94 deletions(-)

diff --git a/flang-rt/CMakeLists.txt b/flang-rt/CMakeLists.txt
index 50b8e834776fb..1e492d9c4feb8 100644
--- a/flang-rt/CMakeLists.txt
+++ b/flang-rt/CMakeLists.txt
@@ -23,41 +23,6 @@ set(FLANG_RT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
 set(FLANG_RT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
 set(FLANG_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../flang")
 
-# CMake 3.24 is the first version of CMake that directly recognizes Flang.
-# LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang.
-if (CMAKE_VERSION VERSION_LESS "3.24")
-  cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
-  if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
-    include(CMakeForceCompiler)
-    CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
-
-    set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
-    set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
-
-    set(CMAKE_Fortran_SUBMODULE_SEP "-")
-    set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
-
-    set(CMAKE_Fortran_PREPROCESS_SOURCE
-      "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
-
-    set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
-    set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
-
-    set(CMAKE_Fortran_MODDIR_FLAG "-module-dir")
-
-    set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
-    set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
-    set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
-
-    set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
-
-    set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
-    set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
-  endif ()
-endif ()
-enable_language(Fortran)
-
-
 list(APPEND CMAKE_MODULE_PATH
     "${FLANG_RT_SOURCE_DIR}/cmake/modules"
     "${FLANG_SOURCE_DIR}/cmake/modules"
@@ -73,62 +38,9 @@ include(ExtendPath)
 # Build Mode Introspection #
 ############################
 
-# Determine whether we are in the runtimes/runtimes-bins directory of a
-# bootstrap build.
-set(LLVM_TREE_AVAILABLE OFF)
-if (LLVM_LIBRARY_OUTPUT_INTDIR AND LLVM_RUNTIME_OUTPUT_INTDIR AND PACKAGE_VERSION)
-  set(LLVM_TREE_AVAILABLE ON)
-endif()
-
 # Path to LLVM development tools (FileCheck, llvm-lit, not, ...)
 set(LLVM_TOOLS_DIR "${LLVM_BINARY_DIR}/bin")
 
-# Determine build and install paths.
-# The build path is absolute, but the install dir is relative, CMake's install
-# command has to apply CMAKE_INSTALL_PREFIX itself.
-get_toolchain_library_subdir(toolchain_lib_subdir)
-if (LLVM_TREE_AVAILABLE)
-  # In a bootstrap build emit the libraries into a default search path in the
-  # build directory of the just-built compiler. This allows using the
-  # just-built compiler without specifying paths to runtime libraries.
-  #
-  # Despite Clang in the name, get_clang_resource_dir does not depend on Clang
-  # being added to the build. Flang uses the same resource dir as clang.
-  include(GetClangResourceDir)
-  get_clang_resource_dir(FLANG_RT_OUTPUT_RESOURCE_DIR PREFIX "${LLVM_LIBRARY_OUTPUT_INTDIR}/..")
-  get_clang_resource_dir(FLANG_RT_INSTALL_RESOURCE_PATH_DEFAULT)
-
-  extend_path(FLANG_RT_OUTPUT_RESOURCE_LIB_DIR "${FLANG_RT_OUTPUT_RESOURCE_DIR}" "${toolchain_lib_subdir}")
-else ()
-  # In a standalone runtimes build, do not write into LLVM_BINARY_DIR. It may be
-  # read-only and/or shared by multiple runtimes with different build
-  # configurations (e.g. Debug/Release). Use the runtime's own lib dir like any
-  # non-toolchain library.
-  # For the install prefix, still use the resource dir assuming that Flang will
-  # be installed there using the same prefix. This is to not have a difference
-  # between bootstrap and standalone runtimes builds.
-  set(FLANG_RT_OUTPUT_RESOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
-  set(FLANG_RT_INSTALL_RESOURCE_PATH_DEFAULT "lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
-
-  extend_path(FLANG_RT_OUTPUT_RESOURCE_LIB_DIR "${FLANG_RT_OUTPUT_RESOURCE_DIR}" "lib${LLVM_LIBDIR_SUFFIX}")
-endif ()
-set(FLANG_RT_INSTALL_RESOURCE_PATH "${FLANG_RT_INSTALL_RESOURCE_PATH_DEFAULT}"
-    CACHE PATH "Path to install runtime libraries to (default: clang resource dir)")
-extend_path(FLANG_RT_INSTALL_RESOURCE_LIB_PATH "${FLANG_RT_INSTALL_RESOURCE_PATH}" "${toolchain_lib_subdir}")
-cmake_path(NORMAL_PATH FLANG_RT_OUTPUT_RESOURCE_DIR)
-cmake_path(NORMAL_PATH FLANG_RT_INSTALL_RESOURCE_PATH)
-# FIXME: For the libflang_rt.so, the toolchain resource lib dir is not a good
-#        destination because it is not a ld.so default search path.
-#        The machine where the executable is eventually executed may not be the
-#        machine where the Flang compiler and its resource dir is installed, so
-#        setting RPath by the driver is not an solution. It should belong into
-#        /usr/lib/<triple>/libflang_rt.so, like e.g. libgcc_s.so.
-#        But the linker as invoked by the Flang driver also requires
-#        libflang_rt.so to be found when linking and the resource lib dir is
-#        the only reliable location.
-cmake_path(NORMAL_PATH FLANG_RT_OUTPUT_RESOURCE_LIB_DIR)
-cmake_path(NORMAL_PATH FLANG_RT_INSTALL_RESOURCE_LIB_PATH)
-
 
 #################
 # Build Options #
@@ -186,7 +98,7 @@ elseif (FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT STREQUAL "CUDA")
   option(FLANG_RT_CUDA_RUNTIME_PTX_WITHOUT_GLOBAL_VARS "Do not compile global variables' definitions when producing PTX library" OFF)
 elseif (FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT STREQUAL "OpenMP")
   # Support for OpenMP offloading
-  set(FLANG_RT_DEVICE_ARCHITECTURES "all" CACHE STRING
+  set(FLANG_RT_DEVICE_ARCHITECTURES "${RUNTIMES_DEVICE_ARCHITECTURES}" CACHE STRING
       "List of OpenMP device architectures to be used to compile the Fortran runtime (e.g. 'gfx1103;sm_90')"
     )
 
diff --git a/flang-rt/cmake/modules/AddFlangRT.cmake b/flang-rt/cmake/modules/AddFlangRT.cmake
index 923507764d691..e960e79473cbb 100644
--- a/flang-rt/cmake/modules/AddFlangRT.cmake
+++ b/flang-rt/cmake/modules/AddFlangRT.cmake
@@ -344,13 +344,13 @@ function (add_flangrt_library name)
     if (ARG_INSTALL_WITH_TOOLCHAIN)
       set_target_properties(${tgtname}
         PROPERTIES
-          ARCHIVE_OUTPUT_DIRECTORY "${FLANG_RT_OUTPUT_RESOURCE_LIB_DIR}"
-          LIBRARY_OUTPUT_DIRECTORY "${FLANG_RT_OUTPUT_RESOURCE_LIB_DIR}"
+          ARCHIVE_OUTPUT_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_LIB_DIR}"
+          LIBRARY_OUTPUT_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_LIB_DIR}"
         )
 
       install(TARGETS ${tgtname}
-          ARCHIVE DESTINATION "${FLANG_RT_INSTALL_RESOURCE_LIB_PATH}"
-          LIBRARY DESTINATION "${FLANG_RT_INSTALL_RESOURCE_LIB_PATH}"
+          ARCHIVE DESTINATION "${RUNTIMES_INSTALL_RESOURCE_LIB_PATH}"
+          LIBRARY DESTINATION "${RUNTIMES_INSTALL_RESOURCE_LIB_PATH}"
         )
     endif ()
 
diff --git a/flang-rt/test/lit.site.cfg.py.in b/flang-rt/test/lit.site.cfg.py.in
index 662d076b1fe24..0e9dc08b59925 100644
--- a/flang-rt/test/lit.site.cfg.py.in
+++ b/flang-rt/test/lit.site.cfg.py.in
@@ -6,7 +6,7 @@ config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
 config.flang_source_dir = "@FLANG_SOURCE_DIR@"
 config.flang_rt_source_dir = "@FLANG_RT_SOURCE_DIR@"
 config.flang_rt_binary_test_dir = os.path.dirname(__file__)
-config.flang_rt_output_resource_lib_dir = "@FLANG_RT_OUTPUT_RESOURCE_LIB_DIR@"
+config.flang_rt_output_resource_lib_dir = "@RUNTIMES_OUTPUT_RESOURCE_LIB_DIR@"
 config.flang_rt_experimental_offload_support = "@FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT@"
 config.cc = "@CMAKE_C_COMPILER@"
 config.flang = "@CMAKE_Fortran_COMPILER@"

>From a6b65149438917cf5ea695c421eb42648f1ce040 Mon Sep 17 00:00:00 2001
From: Michael Kruse <michael.kruse at amd.com>
Date: Wed, 10 Dec 2025 07:12:46 -0600
Subject: [PATCH 05/53] Avoid whitespace-only change

---
 flang-rt/CMakeLists.txt | 1 -
 1 file changed, 1 deletion(-)

diff --git a/flang-rt/CMakeLists.txt b/flang-rt/CMakeLists.txt
index 20ca6dc7124bc..ece2fc669a08f 100644
--- a/flang-rt/CMakeLists.txt
+++ b/flang-rt/CMakeLists.txt
@@ -262,7 +262,6 @@ else ()
   add_custom_target(check-flang-rt)
 endif()
 
-
 ###################
 # Install headers #
 ###################

>From 9e7ab487945a04468469e82aab81cbf86a2da0d7 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Wed, 17 Dec 2025 14:48:46 +0100
Subject: [PATCH 06/53] [Driver] Fallback to host builtin modules

---
 clang/lib/Driver/ToolChains/Flang.cpp | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 2c7a06f2893b9..d6c16b3653111 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -15,6 +15,7 @@
 #include "clang/Options/Options.h"
 #include "llvm/Frontend/Debug/Options.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/TargetParser/Host.h"
 #include "llvm/TargetParser/RISCVISAInfo.h"
 #include "llvm/TargetParser/RISCVTargetParser.h"
@@ -1077,6 +1078,29 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
     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);
 

>From 99b86b92e0f7066ccf56d5fc91d5620e09a2e99a Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Wed, 17 Dec 2025 17:10:15 +0100
Subject: [PATCH 07/53] Avoid general references to Flang

---
 runtimes/CMakeLists.txt | 25 ++++++++-----------------
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index a5bb2d975272e..368a048a4a691 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -430,32 +430,23 @@ if(LLVM_TREE_AVAILABLE)
   get_clang_resource_dir(RUNTIMES_OUTPUT_RESOURCE_DIR PREFIX "${LLVM_LIBRARY_OUTPUT_INTDIR}/..")
   get_clang_resource_dir(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT)
 else()
-  # In a standalone runtimes build, do not write into LLVM_BINARY_DIR. It may be
+  # In a default runtimes build, do not write into LLVM_BINARY_DIR. It may be
   # read-only and/or shared by multiple runtimes with different build
   # configurations (e.g. Debug/Release). Use the runtime's own lib dir like any
   # non-toolchain library. Use own build directory for artifact output.
   set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}")
   set(LLVM_RUNTIME_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin")
 
-  # For the install prefix, still use the resource dir assuming that Flang will
-  # be installed there using the same prefix. This is to not have a difference
-  # between bootstrap and standalone runtimes builds.
+  # For the install prefix, still use the resource dir assuming the compilers
+  # looking for it (Clang, Flang) will be installed there using the same prefix.
+  # This is to not have a difference between bootstrapping and default runtimes
+  # builds.
   set(RUNTIMES_OUTPUT_RESOURCE_DIR "${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
   set(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT "lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
 endif()
 
-# Determine build and install paths.
-# The build path is absolute, but the install dir is relative, CMake's install
-# command has to apply CMAKE_INSTALL_PREFIX itself.
-# FIXME: For shared libraries, the toolchain resource lib dir is not a good
-#        destination because it is not a ld.so default search path.
-#        The machine where the executable is eventually executed may not be the
-#        machine where the Flang compiler and its resource dir is installed, so
-#        setting RPath by the driver is not an solution. It should belong into
-#        /usr/lib/<triple>/lib<name>.so, like e.g. libgcc_s.so.
-#        But the linker as invoked by the Flang driver also requires
-#        libflang_rt.so to be found when linking and the resource lib dir is
-#        the only reliable location.
+# Determine build and install paths. The ouptut paths are absolute, but the
+# install dirs are relative to CMAKE_INSTALL_PREFIX to be resolved by CMake.
 get_toolchain_library_subdir(toolchain_lib_subdir)
 extend_path(RUNTIMES_OUTPUT_RESOURCE_LIB_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_lib_subdir}")
 
@@ -483,7 +474,7 @@ if (RUNTIMES_FLANG_MODULES_ENABLED)
   cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
 
   # No way to find out which mod files are built by a target, so install the
-  # entire output directory
+  # entire output directory.
   # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
   set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
   cmake_path(NORMAL_PATH destination)

>From 45f446837f002861c18d92275cfec1e67952fdf0 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Wed, 17 Dec 2025 17:11:01 +0100
Subject: [PATCH 08/53] Re-add fixme removed from runtimes/CMakeLists.txt

---
 flang-rt/cmake/modules/AddFlangRT.cmake | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/flang-rt/cmake/modules/AddFlangRT.cmake b/flang-rt/cmake/modules/AddFlangRT.cmake
index e960e79473cbb..fdeb5a273c590 100644
--- a/flang-rt/cmake/modules/AddFlangRT.cmake
+++ b/flang-rt/cmake/modules/AddFlangRT.cmake
@@ -342,6 +342,20 @@ function (add_flangrt_library name)
     # directory. Otherwise it is part of testing and is not installed at all.
     # TODO: Consider multi-configuration builds (MSVC_IDE, "Ninja Multi-Config")
     if (ARG_INSTALL_WITH_TOOLCHAIN)
+      # FIXME: RUNTIMES_OUTPUT_RESOURCE_LIB_DIR is not a good location for
+      #        shared libraries because it is not a ld.so default search path.
+      #        Also, the machine where the executable is eventually executed may
+      #        not be one where the compiler is installed, so even RPATH/RUNPATH
+      #        will not help. The most appropriate location for shared libraries
+      #        is /usr/lib/<triple>/lib<name>.so, like e.g. libgcc_s.so.
+      #        Flang-RT also would require a library versioning scheme so
+      #        executables compiled with different versions of Flang either use
+      #        matching versions of Flang-RT, or use a newer backward-compatble
+      #        versions. Currently, Flang-RT has no ABI backwards-compatibility
+      #        policy.
+      #        Currently, we just emit it into RUNTIMES_OUTPUT_RESOURCE_LIB_DIR
+      #        like the static library, which is already in the driver's and
+      #        linker's search path.
       set_target_properties(${tgtname}
         PROPERTIES
           ARCHIVE_OUTPUT_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_LIB_DIR}"

>From 18a4930a39f287c0ed2328aac5ee2623e9451ec6 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 18 Dec 2025 11:40:24 +0100
Subject: [PATCH 09/53] Remove unused include again

---
 clang/lib/Driver/ToolChains/Flang.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index d6c16b3653111..bb13acc353fb9 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -15,7 +15,6 @@
 #include "clang/Options/Options.h"
 #include "llvm/Frontend/Debug/Options.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/TargetParser/Host.h"
 #include "llvm/TargetParser/RISCVISAInfo.h"
 #include "llvm/TargetParser/RISCVTargetParser.h"

>From ac11614f458506faaec1e35f340b80f135ba26db Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Wed, 14 Jan 2026 14:17:42 +0100
Subject: [PATCH 10/53] Address Petr Hosek's review

---
 cmake/Modules/GetToolchainDirs.cmake       |   9 -
 runtimes/CMakeLists.txt                    | 289 +++------------------
 runtimes/cmake/Modules/HandleFortran.cmake | 226 ++++++++++++++++
 3 files changed, 265 insertions(+), 259 deletions(-)
 create mode 100644 runtimes/cmake/Modules/HandleFortran.cmake

diff --git a/cmake/Modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
index ce2f8c294b2bc..ccc815c91d05f 100644
--- a/cmake/Modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -1,12 +1,3 @@
-#===-- cmake/modules/GetToolchainDirs.cmake --------------------------------===#
-#
-# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#
-#===------------------------------------------------------------------------===#
-
-
 # Determine the subdirectory relative to Clang's resource dir/sysroot where to
 # install target-specific libraries, to be found by Clang/Flang driver. This was
 # adapted from Compiler-RT's mechanism to find the path for
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 368a048a4a691..768fddb8b4dd7 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -87,194 +87,10 @@ include(CheckCCompilerFlag)
 include(CheckCXXCompilerFlag)
 include(GetToolchainDirs)
 include(ExtendPath)
+include(HandleFortran)
 
-# Check whether the Fortran compiler already access to builtin modules. Sets
-# HAVE_FORTRAN_INTRINSIC_MODS when returning.
-#
-# This must be wrapped in a function because
-# cmake_push_check_state/cmake_pop_check_state is insufficient to isolate
-# a compiler introspection environment, see
-# https://gitlab.kitware.com/cmake/cmake/-/issues/27419
-function (check_fortran_builtins_available)
-  if (CMAKE_Fortran_COMPILER_FORCED AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
-    # CMake's try_compile does not take a user-defined
-    # CMAKE_Fortran_PREPROCESS_SOURCE into account. Instead of test-compiling,
-    # ask Flang directly for the builtin module files.
-    if (NOT DEFINED HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD)
-      message(STATUS "Performing Test ISO_C_BINDING_PATH")
-      execute_process(
-        COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_FLAGS} "-print-file-name=iso_c_binding.mod"
-        OUTPUT_VARIABLE ISO_C_BINDING_PATH
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-        ERROR_QUIET
-      )
-      set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD "" )
-      if (EXISTS "${ISO_C_BINDING_PATH}")
-        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Success")
-        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD TRUE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
-      else ()
-        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Failed")
-        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD FALSE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
-      endif ()
-    endif ()
-  else ()
-    cmake_push_check_state(RESET)
-    set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
-    check_fortran_source_compiles("
-      subroutine testroutine
-        use iso_c_binding
-      end subroutine
-      " HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD SRC_EXT F90)
-    cmake_pop_check_state()
-  endif ()
-  set(HAVE_FORTRAN_INTRINSIC_MODS "${HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD}" PARENT_SCOPE)
-endfunction ()
-
-
-# Set options to compile Fortran module files.
-#
-# Usage:
-#
-# flang_module_target(name
-#   PUBLIC
-#     Modules files are to be used by other Fortran sources. If a library is
-#     compiled multiple times (e.g. static/shared, or msvcrt variants), only
-#     one of those can be public module files; non-public modules are still
-#     generated but to be forgotten deep inside the build directory to not
-#     conflict with each other.
-#     Also, installs the module with the toolchain.
-# )
-function (flang_module_target tgtname)
-  set(options PUBLIC)
-  cmake_parse_arguments(ARG
-    "${options}"
-    ""
-    ""
-    ${ARGN})
-
-  if (NOT RUNTIMES_FLANG_MODULES_ENABLED)
-    message(WARNING "Cannot build module files for ${tgtname} when RUNTIMES_FLANG_MODULES_ENABLED is ${RUNTIMES_FLANG_MODULES_ENABLED}")
-    return ()
-  endif ()
-
-  target_compile_options(${tgtname} PRIVATE
-      # Let non-public modules find the public module files
-      "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
-
-      # Flang bug workaround: Reformating of cooked token buffer causes identifier to be split between lines
-      "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-Xflang;SHELL:-fno-reformat>"
-    )
-
-  if (LLVM_RUNTIMES_TARGET MATCHES "^nvptx")
-    foreach (_arch IN LISTS RUNTIMES_DEVICE_ARCHITECTURES)
-      target_compile_options(${tgtname} PRIVATE
-       "$<$<COMPILE_LANGUAGE:Fortran>:-march=${_arch}>"
-      )
-    endforeach()
-  endif ()
-
-  if (ARG_PUBLIC)
-    set_target_properties(${tgtname}
-      PROPERTIES
-        Fortran_MODULE_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
-      )
-  else ()
-    set_target_properties(${tgtname}
-      PROPERTIES
-        Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${tgtname}.mod"
-      )
-  endif ()
-endfunction ()
-
-# Check whether the build environment supports building Fortran modules
-# flang-rt and openmp are the only runtimes that contain Fortran modules.
-set(FORTRAN_MODULE_DEPS "")
-if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES))
-  cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
-
-  if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
-    # CMake 3.24 is the first version of CMake that directly recognizes Flang.
-    # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
-    if (CMAKE_VERSION VERSION_LESS "3.24")
-      include(CMakeForceCompiler)
-      CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
-
-      set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
-      set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
-
-      set(CMAKE_Fortran_SUBMODULE_SEP "-")
-      set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
-
-      set(CMAKE_Fortran_PREPROCESS_SOURCE
-        "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
-
-      set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
-      set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
-
-      set(CMAKE_Fortran_MODDIR_FLAG "-J")
-
-      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
-      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
-      set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
-
-      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
-      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
-
-      set(CMAKE_Fortran_VERBOSE_FLAG "-v")
-
-      set(CMAKE_Fortran_LINK_MODE DRIVER)
-    endif ()
-
-    # Optimization flags are only passed after CMake 3.27.4
-    # https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
-    if (CMAKE_VERSION VERSION_LESS "3.27.4")
-      string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
-      string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
-      string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
-    endif ()
-
-    # Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
-    # to nvptx amd amdgpu targets, passing the target triple is essential.
-    # https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
-    if (CMAKE_VERSION VERSION_LESS "3.28")
-      set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
-    endif ()
-  endif ()
-
-  include(CheckFortranSourceCompiles)
-  include(CheckLanguage)
-
-  set(RUNTIMES_FLANG_MODULES_ENABLED_default OFF)
-  check_language(Fortran)
-  if (CMAKE_Fortran_COMPILER)
-    enable_language(Fortran)
-
-    if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
-      # In a bootstrapping build (or any runtimes-build that includes flang-rt),
-      # the intrinsic modules are not built yet. Targets can depend on
-      # flang-rt-mod to ensure that flang-rt's modules are built first.
-      set(FORTRAN_MODULE_DEPS flang-rt-mod)
-      set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
-    else ()
-      # Check whether building modules works, avoid causing the entire build to
-      # fail because of Fortran. The primary situation we want to support here
-      # is Flang, or its intrinsic modules were built separately in a
-      # non-bootstrapping build.
-      check_fortran_builtins_available()
-      if (HAVE_FORTRAN_INTRINSIC_MODS)
-        set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
-        message(STATUS "${LLVM_SUBPROJECT_TITLE}: Non-bootstrapping Fortran modules build (${CMAKE_Fortran_COMPILER_ID} located at ${CMAKE_Fortran_COMPILER})")
-      else ()
-        message(STATUS "Not compiling Flang modules: Not passing smoke check")
-      endif ()
-    endif ()
-  endif ()
-
-  option(RUNTIMES_FLANG_MODULES_ENABLED "Build Fortran modules" "${RUNTIMES_FLANG_MODULES_ENABLED_default}")
-else ()
-  set(RUNTIMES_FLANG_MODULES_ENABLED NO)
-endif ()
-
+# Determine wither we can compile Fortran code.
+init_fortran_support()
 
 # Determine whether we are in the runtimes/runtimes-bins directory of a
 # bootstrap build.
@@ -283,6 +99,17 @@ if (LLVM_LIBRARY_DIR AND LLVM_TOOLS_BINARY_DIR AND PACKAGE_VERSION)
   set(LLVM_TREE_AVAILABLE ON)
 endif()
 
+if(LLVM_TREE_AVAILABLE)
+  # Setting these variables will allow the sub-build to put their outputs into
+  # the library and bin directories of the top-level build.
+  set(LLVM_LIBRARY_OUTPUT_INTDIR ${LLVM_LIBRARY_DIR})
+  set(LLVM_RUNTIME_OUTPUT_INTDIR ${LLVM_TOOLS_BINARY_DIR})
+else()
+  # Use own build directory for artifact output.
+  set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}")
+  set(LLVM_RUNTIME_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin")
+endif()
+
 # CMake omits default compiler include paths, but in runtimes build, we use
 # -nostdinc and -nostdinc++ and control include paths manually so this behavior
 # is undesirable. Filtering CMAKE_{LANG}_IMPLICIT_INCLUDE_DIRECTORIES to remove
@@ -416,30 +243,15 @@ endif()
 
 # Determine output and install paths based on LLVM_TARGET_TRIPLE
 if(LLVM_TREE_AVAILABLE)
-  # In a bootstrap build emit the libraries into a default search path in the
-  # build directory of the just-built compiler. This allows using the
-  # just-built compiler without specifying paths to runtime libraries.
-  # LLVM_LIBRARY_OUTPUT_INTDIR/LLVM_RUNTIME_OUTPUT_INTDIR is used by
-  # AddLLVM.cmake as artifact output locations.
-  set(LLVM_LIBRARY_OUTPUT_INTDIR ${LLVM_LIBRARY_DIR})
-  set(LLVM_RUNTIME_OUTPUT_INTDIR ${LLVM_TOOLS_BINARY_DIR})
-
   # Despite Clang in the name, get_clang_resource_dir does not depend on Clang
   # being added to the build. Flang uses the same resource dir as Clang.
   include(GetClangResourceDir)
   get_clang_resource_dir(RUNTIMES_OUTPUT_RESOURCE_DIR PREFIX "${LLVM_LIBRARY_OUTPUT_INTDIR}/..")
   get_clang_resource_dir(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT)
 else()
-  # In a default runtimes build, do not write into LLVM_BINARY_DIR. It may be
-  # read-only and/or shared by multiple runtimes with different build
-  # configurations (e.g. Debug/Release). Use the runtime's own lib dir like any
-  # non-toolchain library. Use own build directory for artifact output.
-  set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}")
-  set(LLVM_RUNTIME_OUTPUT_INTDIR "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin")
-
   # For the install prefix, still use the resource dir assuming the compilers
   # looking for it (Clang, Flang) will be installed there using the same prefix.
-  # This is to not have a difference between bootstrapping and default runtimes
+  # This is to not have a difference between bootstrapping and default/standalone runtimes
   # builds.
   set(RUNTIMES_OUTPUT_RESOURCE_DIR "${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
   set(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT "lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
@@ -459,53 +271,30 @@ cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_LIB_DIR)
 cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
 
 
-if (RUNTIMES_FLANG_MODULES_ENABLED)
-  if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
-    # Flang expects its builtin modules in Clang's resource directory
-    get_toolchain_module_subdir(toolchain_mod_subdir)
-    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
-    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
-  else ()
-    # For non-Flang compilers, avoid the risk of Flang accidentally picking them up.
-    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
-    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
-  endif ()
-  cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
-  cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
-
-  # No way to find out which mod files are built by a target, so install the
-  # entire output directory.
-  # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
-  set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
-  cmake_path(NORMAL_PATH destination)
-    install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
-      DESTINATION "${destination}"
-    )
-endif ()
-
-
-if (RUNTIMES_FLANG_MODULES_ENABLED)
-  set(RUNTIMES_DEVICE_ARCHITECTURES "all" CACHE STRING
-      "List of offload device architectures to be used to compile the Fortran offload code (e.g. 'gfx1103;sm_90')"
-    )
-
-  if (RUNTIMES_DEVICE_ARCHITECTURES STREQUAL "all")
-    # TODO: support auto detection on the build system.
-    set(all_amdgpu_architectures
-      "gfx700;gfx701;gfx801;gfx803;gfx900;gfx902;gfx906"
-      "gfx908;gfx90a;gfx90c;gfx940;gfx1010;gfx1030"
-      "gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036"
-      "gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151"
-      "gfx1152;gfx1153")
-    set(all_nvptx_architectures
-      "sm_35;sm_37;sm_50;sm_52;sm_53;sm_60;sm_61;sm_62"
-      "sm_70;sm_72;sm_75;sm_80;sm_86;sm_89;sm_90")
-    set(all_gpu_architectures
-      "${all_amdgpu_architectures};${all_nvptx_architectures}")
-      set(RUNTIMES_DEVICE_ARCHITECTURES ${all_gpu_architectures})
-  endif()
-  list(REMOVE_DUPLICATES RUNTIMES_DEVICE_ARCHITECTURES)
-endif ()
+fortran_output_and_install_paths()
+
+
+# For subprojects supporting offloading targets (offload, flang-rt, ..) specify
+# which architectures should be included in the fat binaries.
+set(RUNTIMES_DEVICE_ARCHITECTURES "all" CACHE STRING
+    "List of offload device architectures to be used to compile the offload code (e.g. 'gfx1103;sm_90')"
+  )
+if (RUNTIMES_DEVICE_ARCHITECTURES STREQUAL "all")
+  # TODO: support auto detection on the build system.
+  set(all_amdgpu_architectures
+    "gfx700;gfx701;gfx801;gfx803;gfx900;gfx902;gfx906"
+    "gfx908;gfx90a;gfx90c;gfx940;gfx1010;gfx1030"
+    "gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036"
+    "gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151"
+    "gfx1152;gfx1153")
+  set(all_nvptx_architectures
+    "sm_35;sm_37;sm_50;sm_52;sm_53;sm_60;sm_61;sm_62"
+    "sm_70;sm_72;sm_75;sm_80;sm_86;sm_89;sm_90")
+  set(all_gpu_architectures
+    "${all_amdgpu_architectures};${all_nvptx_architectures}")
+  set(RUNTIMES_DEVICE_ARCHITECTURES ${all_gpu_architectures})
+endif()
+list(REMOVE_DUPLICATES RUNTIMES_DEVICE_ARCHITECTURES)
 
 
 option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
diff --git a/runtimes/cmake/Modules/HandleFortran.cmake b/runtimes/cmake/Modules/HandleFortran.cmake
new file mode 100644
index 0000000000000..9ebf69c88a333
--- /dev/null
+++ b/runtimes/cmake/Modules/HandleFortran.cmake
@@ -0,0 +1,226 @@
+
+# Check whether the build environment supports building Fortran modules
+# flang-rt and openmp are the only runtimes that contain Fortran modules.
+#
+# Sets:
+#  * RUNTIMES_FLANG_MODULES_ENABLED Whether .mod files can be created
+#  * CMAKE_Fortran_*                CMake Fortran toolchain info for older versions of CMake
+macro (init_fortran_support)
+  set(FORTRAN_MODULE_DEPS "")
+  if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES))
+    cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
+
+    if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
+      # CMake 3.24 is the first version of CMake that directly recognizes Flang.
+      # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
+      if (CMAKE_VERSION VERSION_LESS "3.24")
+        include(CMakeForceCompiler)
+        CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
+
+        set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
+        set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
+
+        set(CMAKE_Fortran_SUBMODULE_SEP "-")
+        set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
+
+        set(CMAKE_Fortran_PREPROCESS_SOURCE
+            "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+
+        set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
+        set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
+
+        set(CMAKE_Fortran_MODDIR_FLAG "-J")
+
+        set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+        set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
+        set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
+
+        set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
+        set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
+
+        set(CMAKE_Fortran_VERBOSE_FLAG "-v")
+
+        set(CMAKE_Fortran_LINK_MODE DRIVER)
+      endif ()
+
+      # Optimization flags are only passed after CMake 3.27.4
+      # https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
+      if (CMAKE_VERSION VERSION_LESS "3.27.4")
+        string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
+        string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+        string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
+      endif ()
+
+      # Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
+      # to nvptx amd amdgpu targets, passing the target triple is essential.
+      # https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
+      if (CMAKE_VERSION VERSION_LESS "3.28")
+        set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
+      endif ()
+    endif ()
+
+    include(CheckFortranSourceCompiles)
+    include(CheckLanguage)
+
+    set(RUNTIMES_FLANG_MODULES_ENABLED_default OFF)
+    check_language(Fortran)
+    if (CMAKE_Fortran_COMPILER)
+        enable_language(Fortran)
+
+        if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
+          # In a bootstrapping build (or any runtimes-build that includes flang-rt),
+          # the intrinsic modules are not built yet. Targets can depend on
+          # flang-rt-mod to ensure that flang-rt's modules are built first.
+          set(FORTRAN_MODULE_DEPS flang-rt-mod)
+          set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+        else ()
+          # Check whether building modules works, avoid causing the entire build to
+          # fail because of Fortran. The primary situation we want to support here
+          # is Flang, or its intrinsic modules were built separately in a
+          # non-bootstrapping build.
+          check_fortran_builtins_available()
+          if (HAVE_FORTRAN_INTRINSIC_MODS)
+            set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+            message(STATUS "${LLVM_SUBPROJECT_TITLE}: Non-bootstrapping Fortran modules build (${CMAKE_Fortran_COMPILER_ID} located at ${CMAKE_Fortran_COMPILER})")
+          else ()
+            message(STATUS "Not compiling Flang modules: Not passing smoke check")
+          endif ()
+        endif ()
+    endif ()
+
+    option(RUNTIMES_FLANG_MODULES_ENABLED "Build Fortran modules" "${RUNTIMES_FLANG_MODULES_ENABLED_default}")
+  else ()
+    set(RUNTIMES_FLANG_MODULES_ENABLED NO)
+  endif ()
+endmacro ()
+
+
+# Determine the paths for Fortran .mod files.
+#
+# Sets:
+#  * RUNTIMES_OUTPUT_RESOURCE_MOD_DIR   Path for .mod files in build dir
+#  * RUNTIMES_INSTALL_RESOURCE_MOD_PATH Path for .mod files in install dir, relative to CMAKE_INSTALL_PREFIX
+macro (fortran_output_and_install_paths)
+  if (RUNTIMES_FLANG_MODULES_ENABLED)
+    if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+      # Flang expects its builtin modules in Clang's resource directory.
+      get_toolchain_module_subdir(toolchain_mod_subdir)
+      extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
+      extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
+    else ()
+      # For non-Flang compilers, avoid the risk of Flang accidentally picking them up.
+      extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+      extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+    endif ()
+    cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
+    cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
+
+    # No way to find out which mod files are built by a target, so install the
+    # entire output directory.
+    # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
+    set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
+    cmake_path(NORMAL_PATH destination)
+      install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+        DESTINATION "${destination}"
+      )
+  endif ()
+endmacro ()
+
+
+# Check whether the Fortran compiler already access to builtin modules. Sets
+# HAVE_FORTRAN_INTRINSIC_MODS when returning.
+#
+# This must be wrapped in a function because
+# cmake_push_check_state/cmake_pop_check_state is insufficient to isolate
+# a compiler introspection environment, see
+# https://gitlab.kitware.com/cmake/cmake/-/issues/27419
+function (check_fortran_builtins_available)
+  if (CMAKE_Fortran_COMPILER_FORCED AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+    # CMake's check_fortran_source_compiles/try_compile does not take a
+    # user-defined CMAKE_Fortran_PREPROCESS_SOURCE into account. Instead of
+    # test-compiling, ask Flang directly for the builtin module files.
+    if (NOT DEFINED HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD)
+      message(STATUS "Performing Test ISO_C_BINDING_PATH")
+      execute_process(
+        COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_FLAGS} "-print-file-name=iso_c_binding.mod"
+        OUTPUT_VARIABLE ISO_C_BINDING_PATH
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+        ERROR_QUIET
+      )
+      set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD "")
+      if (EXISTS "${ISO_C_BINDING_PATH}")
+        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Success")
+        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD TRUE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
+      else ()
+        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Failed")
+        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD FALSE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
+      endif ()
+    endif ()
+  else ()
+    cmake_push_check_state(RESET)
+    set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+    check_fortran_source_compiles("
+      subroutine testroutine
+        use iso_c_binding
+      end subroutine
+      " HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD SRC_EXT F90)
+    cmake_pop_check_state()
+  endif ()
+  set(HAVE_FORTRAN_INTRINSIC_MODS "${HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD}" PARENT_SCOPE)
+endfunction ()
+
+
+# Set options to compile Fortran module files.
+#
+# Usage:
+#
+# flang_module_target(name
+#   PUBLIC
+#     Modules files are to be used by other Fortran sources. If a library is
+#     compiled multiple times (e.g. static/shared, or msvcrt variants), only
+#     one of those can be public module files; non-public modules are still
+#     generated but to be forgotten deep inside the build directory to not
+#     conflict with each other.
+#     Also, installs the module with the toolchain.
+# )
+function (flang_module_target tgtname)
+  set(options PUBLIC)
+  cmake_parse_arguments(ARG
+    "${options}"
+    ""
+    ""
+    ${ARGN})
+
+  if (NOT RUNTIMES_FLANG_MODULES_ENABLED)
+    message(WARNING "Cannot build module files for ${tgtname} when RUNTIMES_FLANG_MODULES_ENABLED is ${RUNTIMES_FLANG_MODULES_ENABLED}")
+    return ()
+  endif ()
+
+  target_compile_options(${tgtname} PRIVATE
+      # Let non-public modules find the public module files
+      "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
+
+      # Flang bug workaround: Reformating of cooked token buffer causes identifier to be split between lines
+      "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-Xflang;SHELL:-fno-reformat>"
+    )
+
+  if (LLVM_RUNTIMES_TARGET MATCHES "^nvptx")
+    foreach (_arch IN LISTS RUNTIMES_DEVICE_ARCHITECTURES)
+      target_compile_options(${tgtname} PRIVATE
+       "$<$<COMPILE_LANGUAGE:Fortran>:-march=${_arch}>"
+      )
+    endforeach()
+  endif ()
+
+  if (ARG_PUBLIC)
+    set_target_properties(${tgtname}
+      PROPERTIES
+        Fortran_MODULE_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+      )
+  else ()
+    set_target_properties(${tgtname}
+      PROPERTIES
+        Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${tgtname}.mod"
+      )
+  endif ()
+endfunction ()

>From 675e8ae5b677ba4cdc2f727ad53936b2df6af743 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 19 Jan 2026 11:28:14 +0100
Subject: [PATCH 11/53] Fix bug2021.f90

---
 flang/test/Semantics/bug2021.f90 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang/test/Semantics/bug2021.f90 b/flang/test/Semantics/bug2021.f90
index f5214bce946a9..4d914f34e9a53 100644
--- a/flang/test/Semantics/bug2021.f90
+++ b/flang/test/Semantics/bug2021.f90
@@ -1,4 +1,4 @@
-!RUN: %flang -fc1 -fsyntax-only -pedantic %s 2>&1 | FileCheck %s
+!RUN: %flang_fc1 -fsyntax-only -pedantic %s 2>&1 | FileCheck %s
 !CHECK-NOT: warning: Value of uninitialized local variable 'b' is used but never defined [-Wused-undefined-variable]
 real :: a, b
 pointer(p,a)

>From a6e27b28cf1d408db543cf53bf9cf445ae9454ef Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 19 Jan 2026 12:44:40 +0100
Subject: [PATCH 12/53] Fix dir name case

---
 runtimes/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 768fddb8b4dd7..4254e33ad7655 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -26,7 +26,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 list(INSERT CMAKE_MODULE_PATH 0
   "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
-  "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules"
+  "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
   "${LLVM_COMMON_CMAKE_UTILS}"
   "${LLVM_COMMON_CMAKE_UTILS}/Modules"
   "${CMAKE_CURRENT_SOURCE_DIR}/../llvm/cmake"

>From 419570d06d2b42ef831cbcc8b62c324c5433c1b5 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 19 Jan 2026 12:57:15 +0100
Subject: [PATCH 13/53] Try fixing libcxx-ci build issue

---
 runtimes/CMakeLists.txt                       |   5 +-
 ...an.cmake => config-runtimes-Fortran.cmake} | 230 +++++++++---------
 2 files changed, 118 insertions(+), 117 deletions(-)
 rename runtimes/cmake/{Modules/HandleFortran.cmake => config-runtimes-Fortran.cmake} (57%)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 4254e33ad7655..04899ca4583f7 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -89,8 +89,9 @@ include(GetToolchainDirs)
 include(ExtendPath)
 include(HandleFortran)
 
-# Determine wither we can compile Fortran code.
-init_fortran_support()
+# Handle Fortran code. Sets RUNTIMES_FLANG_MODULES_ENABLED when a Fortran
+# toolchain is available and required by one or more of the LLVM_ENABLED_RUNTIMES.
+include(config-runtimes-Fortran)
 
 # Determine whether we are in the runtimes/runtimes-bins directory of a
 # bootstrap build.
diff --git a/runtimes/cmake/Modules/HandleFortran.cmake b/runtimes/cmake/config-runtimes-Fortran.cmake
similarity index 57%
rename from runtimes/cmake/Modules/HandleFortran.cmake
rename to runtimes/cmake/config-runtimes-Fortran.cmake
index 9ebf69c88a333..5a8b03602acd2 100644
--- a/runtimes/cmake/Modules/HandleFortran.cmake
+++ b/runtimes/cmake/config-runtimes-Fortran.cmake
@@ -1,98 +1,140 @@
-
 # Check whether the build environment supports building Fortran modules
 # flang-rt and openmp are the only runtimes that contain Fortran modules.
 #
 # Sets:
 #  * RUNTIMES_FLANG_MODULES_ENABLED Whether .mod files can be created
 #  * CMAKE_Fortran_*                CMake Fortran toolchain info for older versions of CMake
-macro (init_fortran_support)
-  set(FORTRAN_MODULE_DEPS "")
-  if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES))
-    cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
 
-    if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
-      # CMake 3.24 is the first version of CMake that directly recognizes Flang.
-      # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
-      if (CMAKE_VERSION VERSION_LESS "3.24")
-        include(CMakeForceCompiler)
-        CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
 
-        set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
-        set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
+# Check whether the Fortran compiler already has access to builtin modules. Sets
+# HAVE_FORTRAN_INTRINSIC_MODS when returning.
+#
+# This must be wrapped in a function because
+# cmake_push_check_state/cmake_pop_check_state is insufficient to isolate
+# a compiler introspection environment, see
+# https://gitlab.kitware.com/cmake/cmake/-/issues/27419
+function (check_fortran_builtins_available)
+  if (CMAKE_Fortran_COMPILER_FORCED AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+    # CMake's check_fortran_source_compiles/try_compile does not take a
+    # user-defined CMAKE_Fortran_PREPROCESS_SOURCE into account. Instead of
+    # test-compiling, ask Flang directly for the builtin module files.
+    if (NOT DEFINED HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD)
+      message(STATUS "Performing Test ISO_C_BINDING_PATH")
+      execute_process(
+        COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_FLAGS} "-print-file-name=iso_c_binding.mod"
+        OUTPUT_VARIABLE ISO_C_BINDING_PATH
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+        ERROR_QUIET
+      )
+      set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD "")
+      if (EXISTS "${ISO_C_BINDING_PATH}")
+        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Success")
+        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD TRUE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
+      else ()
+        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Failed")
+        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD FALSE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
+      endif ()
+    endif ()
+  else ()
+    cmake_push_check_state(RESET)
+    set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+    check_fortran_source_compiles("
+      subroutine testroutine
+        use iso_c_binding
+      end subroutine
+      " HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD SRC_EXT F90)
+    cmake_pop_check_state()
+  endif ()
+  set(HAVE_FORTRAN_INTRINSIC_MODS "${HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD}" PARENT_SCOPE)
+endfunction ()
+
+
+set(FORTRAN_MODULE_DEPS "")
+if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES))
+  cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
 
-        set(CMAKE_Fortran_SUBMODULE_SEP "-")
-        set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
+  if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
+    # CMake 3.24 is the first version of CMake that directly recognizes Flang.
+    # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
+    if (CMAKE_VERSION VERSION_LESS "3.24")
+      include(CMakeForceCompiler)
+      CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
 
-        set(CMAKE_Fortran_PREPROCESS_SOURCE
-            "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+      set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
+      set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
 
-        set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
-        set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
+      set(CMAKE_Fortran_SUBMODULE_SEP "-")
+      set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
 
-        set(CMAKE_Fortran_MODDIR_FLAG "-J")
+      set(CMAKE_Fortran_PREPROCESS_SOURCE
+          "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
 
-        set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
-        set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
-        set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
+      set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
+      set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
 
-        set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
-        set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
+      set(CMAKE_Fortran_MODDIR_FLAG "-J")
 
-        set(CMAKE_Fortran_VERBOSE_FLAG "-v")
+      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
+      set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
 
-        set(CMAKE_Fortran_LINK_MODE DRIVER)
-      endif ()
+      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
+      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
 
-      # Optimization flags are only passed after CMake 3.27.4
-      # https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
-      if (CMAKE_VERSION VERSION_LESS "3.27.4")
-        string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
-        string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
-        string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
-      endif ()
+      set(CMAKE_Fortran_VERBOSE_FLAG "-v")
 
-      # Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
-      # to nvptx amd amdgpu targets, passing the target triple is essential.
-      # https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
-      if (CMAKE_VERSION VERSION_LESS "3.28")
-        set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
-      endif ()
+      set(CMAKE_Fortran_LINK_MODE DRIVER)
+    endif ()
+
+    # Optimization flags are only passed after CMake 3.27.4
+    # https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
+    if (CMAKE_VERSION VERSION_LESS "3.27.4")
+      string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
+      string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+      string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
+    endif ()
+
+    # Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
+    # to nvptx amd amdgpu targets, passing the target triple is essential.
+    # https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
+    if (CMAKE_VERSION VERSION_LESS "3.28")
+      set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
     endif ()
+  endif ()
 
-    include(CheckFortranSourceCompiles)
-    include(CheckLanguage)
+  include(CheckFortranSourceCompiles)
+  include(CheckLanguage)
 
-    set(RUNTIMES_FLANG_MODULES_ENABLED_default OFF)
-    check_language(Fortran)
-    if (CMAKE_Fortran_COMPILER)
-        enable_language(Fortran)
+  set(RUNTIMES_FLANG_MODULES_ENABLED_default OFF)
+  check_language(Fortran)
+  if (CMAKE_Fortran_COMPILER)
+      enable_language(Fortran)
 
-        if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
-          # In a bootstrapping build (or any runtimes-build that includes flang-rt),
-          # the intrinsic modules are not built yet. Targets can depend on
-          # flang-rt-mod to ensure that flang-rt's modules are built first.
-          set(FORTRAN_MODULE_DEPS flang-rt-mod)
+      if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
+        # In a bootstrapping build (or any runtimes-build that includes flang-rt),
+        # the intrinsic modules are not built yet. Targets can depend on
+        # flang-rt-mod to ensure that flang-rt's modules are built first.
+        set(FORTRAN_MODULE_DEPS flang-rt-mod)
+        set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+      else ()
+        # Check whether building modules works, avoid causing the entire build to
+        # fail because of Fortran. The primary situation we want to support here
+        # is Flang, or its intrinsic modules were built separately in a
+        # non-bootstrapping build.
+        check_fortran_builtins_available()
+        if (HAVE_FORTRAN_INTRINSIC_MODS)
           set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+          message(STATUS "${LLVM_SUBPROJECT_TITLE}: Non-bootstrapping Fortran modules build (${CMAKE_Fortran_COMPILER_ID} located at ${CMAKE_Fortran_COMPILER})")
         else ()
-          # Check whether building modules works, avoid causing the entire build to
-          # fail because of Fortran. The primary situation we want to support here
-          # is Flang, or its intrinsic modules were built separately in a
-          # non-bootstrapping build.
-          check_fortran_builtins_available()
-          if (HAVE_FORTRAN_INTRINSIC_MODS)
-            set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
-            message(STATUS "${LLVM_SUBPROJECT_TITLE}: Non-bootstrapping Fortran modules build (${CMAKE_Fortran_COMPILER_ID} located at ${CMAKE_Fortran_COMPILER})")
-          else ()
-            message(STATUS "Not compiling Flang modules: Not passing smoke check")
-          endif ()
+          message(STATUS "Not compiling Flang modules: Not passing smoke check")
         endif ()
-    endif ()
-
-    option(RUNTIMES_FLANG_MODULES_ENABLED "Build Fortran modules" "${RUNTIMES_FLANG_MODULES_ENABLED_default}")
-  else ()
-    set(RUNTIMES_FLANG_MODULES_ENABLED NO)
+      endif ()
   endif ()
-endmacro ()
+
+  option(RUNTIMES_FLANG_MODULES_ENABLED "Build Fortran modules" "${RUNTIMES_FLANG_MODULES_ENABLED_default}")
+else ()
+  set(RUNTIMES_FLANG_MODULES_ENABLED NO)
+endif ()
 
 
 # Determine the paths for Fortran .mod files.
@@ -116,7 +158,8 @@ macro (fortran_output_and_install_paths)
     cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
 
     # No way to find out which mod files are built by a target, so install the
-    # entire output directory.
+    # entire output directory. flang_module_target() will copy (only) the PUBLIC
+    # .mod file into the output directory.
     # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
     set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
     cmake_path(NORMAL_PATH destination)
@@ -127,50 +170,7 @@ macro (fortran_output_and_install_paths)
 endmacro ()
 
 
-# Check whether the Fortran compiler already access to builtin modules. Sets
-# HAVE_FORTRAN_INTRINSIC_MODS when returning.
-#
-# This must be wrapped in a function because
-# cmake_push_check_state/cmake_pop_check_state is insufficient to isolate
-# a compiler introspection environment, see
-# https://gitlab.kitware.com/cmake/cmake/-/issues/27419
-function (check_fortran_builtins_available)
-  if (CMAKE_Fortran_COMPILER_FORCED AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
-    # CMake's check_fortran_source_compiles/try_compile does not take a
-    # user-defined CMAKE_Fortran_PREPROCESS_SOURCE into account. Instead of
-    # test-compiling, ask Flang directly for the builtin module files.
-    if (NOT DEFINED HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD)
-      message(STATUS "Performing Test ISO_C_BINDING_PATH")
-      execute_process(
-        COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_FLAGS} "-print-file-name=iso_c_binding.mod"
-        OUTPUT_VARIABLE ISO_C_BINDING_PATH
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-        ERROR_QUIET
-      )
-      set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD "")
-      if (EXISTS "${ISO_C_BINDING_PATH}")
-        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Success")
-        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD TRUE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
-      else ()
-        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Failed")
-        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD FALSE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
-      endif ()
-    endif ()
-  else ()
-    cmake_push_check_state(RESET)
-    set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
-    check_fortran_source_compiles("
-      subroutine testroutine
-        use iso_c_binding
-      end subroutine
-      " HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD SRC_EXT F90)
-    cmake_pop_check_state()
-  endif ()
-  set(HAVE_FORTRAN_INTRINSIC_MODS "${HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD}" PARENT_SCOPE)
-endfunction ()
-
-
-# Set options to compile Fortran module files.
+# Set options to compile Fortran module files. Assumes the code above has run.
 #
 # Usage:
 #
@@ -207,7 +207,7 @@ function (flang_module_target tgtname)
   if (LLVM_RUNTIMES_TARGET MATCHES "^nvptx")
     foreach (_arch IN LISTS RUNTIMES_DEVICE_ARCHITECTURES)
       target_compile_options(${tgtname} PRIVATE
-       "$<$<COMPILE_LANGUAGE:Fortran>:-march=${_arch}>"
+        "$<$<COMPILE_LANGUAGE:Fortran>:-march=${_arch}>"
       )
     endforeach()
   endif ()

>From 774bd7e582ca2115165865c367f505986bee0f4d Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 19 Jan 2026 13:33:44 +0100
Subject: [PATCH 14/53] Build fix

---
 runtimes/CMakeLists.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 04899ca4583f7..8aae896536af0 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -87,10 +87,10 @@ include(CheckCCompilerFlag)
 include(CheckCXXCompilerFlag)
 include(GetToolchainDirs)
 include(ExtendPath)
-include(HandleFortran)
 
 # Handle Fortran code. Sets RUNTIMES_FLANG_MODULES_ENABLED when a Fortran
-# toolchain is available and required by one or more of the LLVM_ENABLED_RUNTIMES.
+# toolchain is available and required by one or more of the
+# runtimes.
 include(config-runtimes-Fortran)
 
 # Determine whether we are in the runtimes/runtimes-bins directory of a

>From f828f3c2d856a7e6f670c972a5169db85c5b770e Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 19 Jan 2026 17:59:53 +0100
Subject: [PATCH 15/53] Address review comments

---
 runtimes/cmake/config-runtimes-Fortran.cmake | 459 ++++++++++---------
 1 file changed, 233 insertions(+), 226 deletions(-)

diff --git a/runtimes/cmake/config-runtimes-Fortran.cmake b/runtimes/cmake/config-runtimes-Fortran.cmake
index 5a8b03602acd2..0db329ed09e4c 100644
--- a/runtimes/cmake/config-runtimes-Fortran.cmake
+++ b/runtimes/cmake/config-runtimes-Fortran.cmake
@@ -1,226 +1,233 @@
-# Check whether the build environment supports building Fortran modules
-# flang-rt and openmp are the only runtimes that contain Fortran modules.
-#
-# Sets:
-#  * RUNTIMES_FLANG_MODULES_ENABLED Whether .mod files can be created
-#  * CMAKE_Fortran_*                CMake Fortran toolchain info for older versions of CMake
-
-
-# Check whether the Fortran compiler already has access to builtin modules. Sets
-# HAVE_FORTRAN_INTRINSIC_MODS when returning.
-#
-# This must be wrapped in a function because
-# cmake_push_check_state/cmake_pop_check_state is insufficient to isolate
-# a compiler introspection environment, see
-# https://gitlab.kitware.com/cmake/cmake/-/issues/27419
-function (check_fortran_builtins_available)
-  if (CMAKE_Fortran_COMPILER_FORCED AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
-    # CMake's check_fortran_source_compiles/try_compile does not take a
-    # user-defined CMAKE_Fortran_PREPROCESS_SOURCE into account. Instead of
-    # test-compiling, ask Flang directly for the builtin module files.
-    if (NOT DEFINED HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD)
-      message(STATUS "Performing Test ISO_C_BINDING_PATH")
-      execute_process(
-        COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_FLAGS} "-print-file-name=iso_c_binding.mod"
-        OUTPUT_VARIABLE ISO_C_BINDING_PATH
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-        ERROR_QUIET
-      )
-      set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD "")
-      if (EXISTS "${ISO_C_BINDING_PATH}")
-        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Success")
-        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD TRUE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
-      else ()
-        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Failed")
-        set(HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD FALSE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
-      endif ()
-    endif ()
-  else ()
-    cmake_push_check_state(RESET)
-    set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
-    check_fortran_source_compiles("
-      subroutine testroutine
-        use iso_c_binding
-      end subroutine
-      " HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD SRC_EXT F90)
-    cmake_pop_check_state()
-  endif ()
-  set(HAVE_FORTRAN_INTRINSIC_MODS "${HAVE_FORTRAN_HAS_ISO_C_BINDING_MOD}" PARENT_SCOPE)
-endfunction ()
-
-
-set(FORTRAN_MODULE_DEPS "")
-if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES))
-  cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
-
-  if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
-    # CMake 3.24 is the first version of CMake that directly recognizes Flang.
-    # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
-    if (CMAKE_VERSION VERSION_LESS "3.24")
-      include(CMakeForceCompiler)
-      CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
-
-      set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
-      set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
-
-      set(CMAKE_Fortran_SUBMODULE_SEP "-")
-      set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
-
-      set(CMAKE_Fortran_PREPROCESS_SOURCE
-          "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
-
-      set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
-      set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
-
-      set(CMAKE_Fortran_MODDIR_FLAG "-J")
-
-      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
-      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
-      set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
-
-      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
-      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
-
-      set(CMAKE_Fortran_VERBOSE_FLAG "-v")
-
-      set(CMAKE_Fortran_LINK_MODE DRIVER)
-    endif ()
-
-    # Optimization flags are only passed after CMake 3.27.4
-    # https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
-    if (CMAKE_VERSION VERSION_LESS "3.27.4")
-      string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
-      string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
-      string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
-    endif ()
-
-    # Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
-    # to nvptx amd amdgpu targets, passing the target triple is essential.
-    # https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
-    if (CMAKE_VERSION VERSION_LESS "3.28")
-      set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
-    endif ()
-  endif ()
-
-  include(CheckFortranSourceCompiles)
-  include(CheckLanguage)
-
-  set(RUNTIMES_FLANG_MODULES_ENABLED_default OFF)
-  check_language(Fortran)
-  if (CMAKE_Fortran_COMPILER)
-      enable_language(Fortran)
-
-      if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
-        # In a bootstrapping build (or any runtimes-build that includes flang-rt),
-        # the intrinsic modules are not built yet. Targets can depend on
-        # flang-rt-mod to ensure that flang-rt's modules are built first.
-        set(FORTRAN_MODULE_DEPS flang-rt-mod)
-        set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
-      else ()
-        # Check whether building modules works, avoid causing the entire build to
-        # fail because of Fortran. The primary situation we want to support here
-        # is Flang, or its intrinsic modules were built separately in a
-        # non-bootstrapping build.
-        check_fortran_builtins_available()
-        if (HAVE_FORTRAN_INTRINSIC_MODS)
-          set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
-          message(STATUS "${LLVM_SUBPROJECT_TITLE}: Non-bootstrapping Fortran modules build (${CMAKE_Fortran_COMPILER_ID} located at ${CMAKE_Fortran_COMPILER})")
-        else ()
-          message(STATUS "Not compiling Flang modules: Not passing smoke check")
-        endif ()
-      endif ()
-  endif ()
-
-  option(RUNTIMES_FLANG_MODULES_ENABLED "Build Fortran modules" "${RUNTIMES_FLANG_MODULES_ENABLED_default}")
-else ()
-  set(RUNTIMES_FLANG_MODULES_ENABLED NO)
-endif ()
-
-
-# Determine the paths for Fortran .mod files.
-#
-# Sets:
-#  * RUNTIMES_OUTPUT_RESOURCE_MOD_DIR   Path for .mod files in build dir
-#  * RUNTIMES_INSTALL_RESOURCE_MOD_PATH Path for .mod files in install dir, relative to CMAKE_INSTALL_PREFIX
-macro (fortran_output_and_install_paths)
-  if (RUNTIMES_FLANG_MODULES_ENABLED)
-    if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
-      # Flang expects its builtin modules in Clang's resource directory.
-      get_toolchain_module_subdir(toolchain_mod_subdir)
-      extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
-      extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
-    else ()
-      # For non-Flang compilers, avoid the risk of Flang accidentally picking them up.
-      extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
-      extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
-    endif ()
-    cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
-    cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
-
-    # No way to find out which mod files are built by a target, so install the
-    # entire output directory. flang_module_target() will copy (only) the PUBLIC
-    # .mod file into the output directory.
-    # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
-    set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
-    cmake_path(NORMAL_PATH destination)
-      install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
-        DESTINATION "${destination}"
-      )
-  endif ()
-endmacro ()
-
-
-# Set options to compile Fortran module files. Assumes the code above has run.
-#
-# Usage:
-#
-# flang_module_target(name
-#   PUBLIC
-#     Modules files are to be used by other Fortran sources. If a library is
-#     compiled multiple times (e.g. static/shared, or msvcrt variants), only
-#     one of those can be public module files; non-public modules are still
-#     generated but to be forgotten deep inside the build directory to not
-#     conflict with each other.
-#     Also, installs the module with the toolchain.
-# )
-function (flang_module_target tgtname)
-  set(options PUBLIC)
-  cmake_parse_arguments(ARG
-    "${options}"
-    ""
-    ""
-    ${ARGN})
-
-  if (NOT RUNTIMES_FLANG_MODULES_ENABLED)
-    message(WARNING "Cannot build module files for ${tgtname} when RUNTIMES_FLANG_MODULES_ENABLED is ${RUNTIMES_FLANG_MODULES_ENABLED}")
-    return ()
-  endif ()
-
-  target_compile_options(${tgtname} PRIVATE
-      # Let non-public modules find the public module files
-      "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
-
-      # Flang bug workaround: Reformating of cooked token buffer causes identifier to be split between lines
-      "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-Xflang;SHELL:-fno-reformat>"
-    )
-
-  if (LLVM_RUNTIMES_TARGET MATCHES "^nvptx")
-    foreach (_arch IN LISTS RUNTIMES_DEVICE_ARCHITECTURES)
-      target_compile_options(${tgtname} PRIVATE
-        "$<$<COMPILE_LANGUAGE:Fortran>:-march=${_arch}>"
-      )
-    endforeach()
-  endif ()
-
-  if (ARG_PUBLIC)
-    set_target_properties(${tgtname}
-      PROPERTIES
-        Fortran_MODULE_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
-      )
-  else ()
-    set_target_properties(${tgtname}
-      PROPERTIES
-        Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${tgtname}.mod"
-      )
-  endif ()
-endfunction ()
+# Check whether the build environment supports building Fortran modules
+# flang-rt and openmp are the only runtimes that contain Fortran modules.
+#
+# Sets:
+#  * RUNTIMES_FLANG_MODULES_ENABLED Whether .mod files can be created
+#  * CMAKE_Fortran_*                CMake Fortran toolchain info for older versions of CMake
+
+
+# Check whether the Fortran compiler already has access to builtin modules. Sets
+# HAVE_FORTRAN_INTRINSIC_MODS when returning.
+#
+# This must be wrapped in a function because
+# cmake_push_check_state/cmake_pop_check_state is insufficient to isolate
+# a compiler introspection environment, see
+# https://gitlab.kitware.com/cmake/cmake/-/issues/27419
+function (check_fortran_builtins_available)
+  if (CMAKE_Fortran_COMPILER_FORCED AND CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+    # CMake's check_fortran_source_compiles/try_compile does not take a
+    # user-defined CMAKE_Fortran_PREPROCESS_SOURCE into account. Instead of
+    # test-compiling, ask Flang directly for the builtin module files.
+    # CMAKE_Fortran_PREPROCESS_SOURCE is defined for CMake < 3.24 because it
+    # does not natively recognize Flang (see below). Once we bump the required
+    # CMake version, and because setting CMAKE_Fortran_PREPROCESS_SOURCE has
+    # been deprecated by CMake, this workaround can be removed.
+    if (NOT DEFINED FORTRAN_HAS_ISO_C_BINDING_MOD)
+      message(STATUS "Performing Test ISO_C_BINDING_PATH")
+      execute_process(
+        COMMAND ${CMAKE_Fortran_COMPILER} ${CMAKE_Fortran_FLAGS} "-print-file-name=iso_c_binding.mod"
+        OUTPUT_VARIABLE ISO_C_BINDING_PATH
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+        ERROR_QUIET
+      )
+      set(FORTRAN_HAS_ISO_C_BINDING_MOD "")
+      if (EXISTS "${ISO_C_BINDING_PATH}")
+        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Success")
+        set(FORTRAN_HAS_ISO_C_BINDING_MOD TRUE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
+      else ()
+        message(STATUS "Performing Test ISO_C_BINDING_PATH -- Failed")
+        set(FORTRAN_HAS_ISO_C_BINDING_MOD FALSE CACHE INTERNAL "Existence result of ${CMAKE_Fortran_COMPILER} -print-file-name=iso_c_binding.mod")
+      endif ()
+    endif ()
+  else ()
+    cmake_push_check_state(RESET)
+    set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+    check_fortran_source_compiles("
+      subroutine testroutine
+        use iso_c_binding
+      end subroutine
+      " FORTRAN_HAS_ISO_C_BINDING_MOD SRC_EXT F90)
+    cmake_pop_check_state()
+  endif ()
+  set(HAVE_FORTRAN_INTRINSIC_MODS "${FORTRAN_HAS_ISO_C_BINDING_MOD}" PARENT_SCOPE)
+endfunction ()
+
+
+set(FORTRAN_MODULE_DEPS "")
+if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES))
+  cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
+
+  if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
+    # CMake 3.24 is the first version of CMake that directly recognizes Flang.
+    # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
+    if (CMAKE_VERSION VERSION_LESS "3.24")
+      include(CMakeForceCompiler)
+      CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
+
+      set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
+      set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
+
+      set(CMAKE_Fortran_SUBMODULE_SEP "-")
+      set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
+
+      set(CMAKE_Fortran_PREPROCESS_SOURCE
+          "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+
+      set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
+      set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
+
+      set(CMAKE_Fortran_MODDIR_FLAG "-J")
+
+      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
+      set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
+
+      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
+      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
+
+      set(CMAKE_Fortran_VERBOSE_FLAG "-v")
+
+      set(CMAKE_Fortran_LINK_MODE DRIVER)
+    endif ()
+
+    # Optimization flags are only passed after CMake 3.27.4
+    # https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
+    if (CMAKE_VERSION VERSION_LESS "3.27.4")
+      string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
+      string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+      string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
+    endif ()
+
+    # Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
+    # to nvptx amd amdgpu targets, passing the target triple is essential.
+    # https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
+    if (CMAKE_VERSION VERSION_LESS "3.28")
+      set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
+    endif ()
+  endif ()
+
+  include(CheckFortranSourceCompiles)
+  include(CheckLanguage)
+
+  set(RUNTIMES_FLANG_MODULES_ENABLED_default OFF)
+  check_language(Fortran)
+  if (CMAKE_Fortran_COMPILER)
+    enable_language(Fortran)
+
+    if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
+      # In a bootstrapping build (or any runtimes-build that includes flang-rt),
+      # the intrinsic modules are not built yet. Targets can depend on
+      # flang-rt-mod to ensure that flang-rt's modules are built first.
+      set(FORTRAN_MODULE_DEPS flang-rt-mod)
+      set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+    else ()
+      # Check whether building modules works, avoid causing the entire build to
+      # fail because of Fortran. The primary situation we want to support here
+      # is Flang, or its intrinsic modules were built separately in a
+      # non-bootstrapping build.
+      check_fortran_builtins_available()
+      if (HAVE_FORTRAN_INTRINSIC_MODS)
+        set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+        message(STATUS "${LLVM_SUBPROJECT_TITLE}: Non-bootstrapping Fortran modules build (${CMAKE_Fortran_COMPILER_ID} located at ${CMAKE_Fortran_COMPILER})")
+      else ()
+        message(STATUS "Not compiling Flang modules: Not passing smoke check")
+      endif ()
+    endif ()
+  endif ()
+
+  option(RUNTIMES_FLANG_MODULES_ENABLED "Build Fortran modules" "${RUNTIMES_FLANG_MODULES_ENABLED_default}")
+else ()
+  set(RUNTIMES_FLANG_MODULES_ENABLED NO)
+endif ()
+
+
+# Determine the paths for Fortran .mod files.
+#
+# Sets:
+#  * RUNTIMES_OUTPUT_RESOURCE_MOD_DIR   Path for .mod files in build dir
+#  * RUNTIMES_INSTALL_RESOURCE_MOD_PATH Path for .mod files in install dir, relative to CMAKE_INSTALL_PREFIX
+macro (fortran_output_and_install_paths)
+  if (RUNTIMES_FLANG_MODULES_ENABLED)
+    if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+      # Flang expects its builtin modules in Clang's resource directory.
+      get_toolchain_module_subdir(toolchain_mod_subdir)
+      extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
+      extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
+    else ()
+      # For non-Flang compilers, avoid the risk of Flang accidentally picking them up.
+      extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+      extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+    endif ()
+    cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
+    cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
+
+    # No way to find out which mod files are built by a target, so install the
+    # entire output directory. flang_module_target() will copy (only) the PUBLIC
+    # .mod file into the output directory.
+    # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
+    set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
+    cmake_path(NORMAL_PATH destination)
+      install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+        DESTINATION "${destination}"
+      )
+  endif ()
+endmacro ()
+
+
+# Set options to compile Fortran module files. Assumes the code above has run.
+#
+# Usage:
+#
+# flang_module_target(name
+#   PUBLIC
+#     Modules files are to be used by other Fortran sources. If a library is
+#     compiled multiple times (e.g. static/shared, or msvcrt variants), only
+#     one of those can be public module files; non-public modules are still
+#     generated but to be forgotten deep inside the build directory to not
+#     conflict with each other.
+#     Also, installs the module with the toolchain.
+# )
+function (flang_module_target tgtname)
+  set(options PUBLIC)
+  cmake_parse_arguments(ARG
+    "${options}"
+    ""
+    ""
+    ${ARGN})
+
+  if (NOT RUNTIMES_FLANG_MODULES_ENABLED)
+    message(WARNING "Cannot build module files for ${tgtname} when RUNTIMES_FLANG_MODULES_ENABLED is ${RUNTIMES_FLANG_MODULES_ENABLED}")
+    return ()
+  endif ()
+
+  target_compile_options(${tgtname} PRIVATE
+      # Let non-public modules find the public module files
+      "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
+
+      # Flang bug workaround: Reformating of cooked token buffer causes
+      # identifier to be split between lines
+      "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-Xflang;SHELL:-fno-reformat>"
+    )
+
+  # `flang --target=nvptx64` fails when not specifying `-march`, even when only
+  # emitting .mod files. Ensure that we pass `-march`.
+  if (LLVM_RUNTIMES_TARGET MATCHES "^nvptx")
+    foreach (_arch IN LISTS RUNTIMES_DEVICE_ARCHITECTURES)
+      target_compile_options(${tgtname} PRIVATE
+        "$<$<COMPILE_LANGUAGE:Fortran>:-march=${_arch}>"
+      )
+    endforeach()
+  endif ()
+
+  if (ARG_PUBLIC)
+    set_target_properties(${tgtname}
+      PROPERTIES
+        Fortran_MODULE_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+      )
+  else ()
+    set_target_properties(${tgtname}
+      PROPERTIES
+        Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${tgtname}.mod"
+      )
+  endif ()
+endfunction ()

>From e632eab10f75c5ea82b37dc076683776311e5dc1 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Fri, 23 Jan 2026 15:13:45 +0100
Subject: [PATCH 16/53] rename config-runtimes-Fortran.cmake ->
 config-Fortran.cmake

---
 runtimes/CMakeLists.txt                                         | 2 +-
 .../{config-runtimes-Fortran.cmake => config-Fortran.cmake}     | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename runtimes/cmake/{config-runtimes-Fortran.cmake => config-Fortran.cmake} (100%)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 8aae896536af0..86b7bccb14a35 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -91,7 +91,7 @@ include(ExtendPath)
 # Handle Fortran code. Sets RUNTIMES_FLANG_MODULES_ENABLED when a Fortran
 # toolchain is available and required by one or more of the
 # runtimes.
-include(config-runtimes-Fortran)
+include(config-Fortran)
 
 # Determine whether we are in the runtimes/runtimes-bins directory of a
 # bootstrap build.
diff --git a/runtimes/cmake/config-runtimes-Fortran.cmake b/runtimes/cmake/config-Fortran.cmake
similarity index 100%
rename from runtimes/cmake/config-runtimes-Fortran.cmake
rename to runtimes/cmake/config-Fortran.cmake

>From 51c04af7d7465dc374eed3736c13e70cfbf5ee42 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Fri, 23 Jan 2026 16:22:49 +0100
Subject: [PATCH 17/53] Consecutive Fortran-handling cmake code

---
 runtimes/CMakeLists.txt             | 14 ++++-----
 runtimes/cmake/config-Fortran.cmake | 48 ++++++++++++++---------------
 2 files changed, 30 insertions(+), 32 deletions(-)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 86b7bccb14a35..78d194aea3cdb 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -88,11 +88,6 @@ include(CheckCXXCompilerFlag)
 include(GetToolchainDirs)
 include(ExtendPath)
 
-# Handle Fortran code. Sets RUNTIMES_FLANG_MODULES_ENABLED when a Fortran
-# toolchain is available and required by one or more of the
-# runtimes.
-include(config-Fortran)
-
 # Determine whether we are in the runtimes/runtimes-bins directory of a
 # bootstrap build.
 set(LLVM_TREE_AVAILABLE OFF)
@@ -258,7 +253,7 @@ else()
   set(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT "lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
 endif()
 
-# Determine build and install paths. The ouptut paths are absolute, but the
+# Determine build and install paths. The output paths are absolute, but the
 # install dirs are relative to CMAKE_INSTALL_PREFIX to be resolved by CMake.
 get_toolchain_library_subdir(toolchain_lib_subdir)
 extend_path(RUNTIMES_OUTPUT_RESOURCE_LIB_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_lib_subdir}")
@@ -272,7 +267,12 @@ cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_LIB_DIR)
 cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
 
 
-fortran_output_and_install_paths()
+# Handle Fortran code. When a Fortran  toolchain is available and required by
+# one or more of the runtimes, enables CMake's Fortran support and sets
+# RUNTIMES_FLANG_MODULES_ENABLED.
+# Makes use of RUNTIMES_OUTPUT_RESOURCE_DIR, RUNTIMES_INSTALL_RESOURCE_PATH,
+# hence must be included their those variables are defined.
+include(config-Fortran)
 
 
 # For subprojects supporting offloading targets (offload, flang-rt, ..) specify
diff --git a/runtimes/cmake/config-Fortran.cmake b/runtimes/cmake/config-Fortran.cmake
index 0db329ed09e4c..a36003655d25a 100644
--- a/runtimes/cmake/config-Fortran.cmake
+++ b/runtimes/cmake/config-Fortran.cmake
@@ -146,32 +146,30 @@ endif ()
 # Sets:
 #  * RUNTIMES_OUTPUT_RESOURCE_MOD_DIR   Path for .mod files in build dir
 #  * RUNTIMES_INSTALL_RESOURCE_MOD_PATH Path for .mod files in install dir, relative to CMAKE_INSTALL_PREFIX
-macro (fortran_output_and_install_paths)
-  if (RUNTIMES_FLANG_MODULES_ENABLED)
-    if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
-      # Flang expects its builtin modules in Clang's resource directory.
-      get_toolchain_module_subdir(toolchain_mod_subdir)
-      extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
-      extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
-    else ()
-      # For non-Flang compilers, avoid the risk of Flang accidentally picking them up.
-      extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
-      extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
-    endif ()
-    cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
-    cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
-
-    # No way to find out which mod files are built by a target, so install the
-    # entire output directory. flang_module_target() will copy (only) the PUBLIC
-    # .mod file into the output directory.
-    # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
-    set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
-    cmake_path(NORMAL_PATH destination)
-      install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
-        DESTINATION "${destination}"
-      )
+if (RUNTIMES_FLANG_MODULES_ENABLED)
+  if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+    # Flang expects its builtin modules in Clang's resource directory.
+    get_toolchain_module_subdir(toolchain_mod_subdir)
+    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
+    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
+  else ()
+    # For non-Flang compilers, avoid the risk of Flang accidentally picking them up.
+    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
   endif ()
-endmacro ()
+  cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
+  cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
+
+  # No way to find out which mod files are built by a target, so install the
+  # entire output directory. flang_module_target() will copy (only) the PUBLIC
+  # .mod file into the output directory.
+  # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
+  set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
+  cmake_path(NORMAL_PATH destination)
+    install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+      DESTINATION "${destination}"
+    )
+endif ()
 
 
 # Set options to compile Fortran module files. Assumes the code above has run.

>From 161298fa144aecb27d960ce8d610f743ca84e6f2 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 26 Jan 2026 13:01:10 +0100
Subject: [PATCH 18/53] avoid unrelated change

---
 runtimes/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 78d194aea3cdb..027b90da9b17d 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -26,7 +26,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 list(INSERT CMAKE_MODULE_PATH 0
   "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
-  "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+  "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules"
   "${LLVM_COMMON_CMAKE_UTILS}"
   "${LLVM_COMMON_CMAKE_UTILS}/Modules"
   "${CMAKE_CURRENT_SOURCE_DIR}/../llvm/cmake"

>From a0d722cd08c21515e8ad52f44824a26bec12d212 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 26 Jan 2026 13:09:30 +0100
Subject: [PATCH 19/53] Introduce RUNTIMES_*_PATH/DIR logic for all runtimes

---
 .../Modules}/GetToolchainDirs.cmake           | 20 +++----
 flang-rt/CMakeLists.txt                       | 53 -------------------
 flang-rt/cmake/modules/AddFlangRT.cmake       |  8 +--
 runtimes/CMakeLists.txt                       | 33 +++++++++++-
 4 files changed, 47 insertions(+), 67 deletions(-)
 rename {flang-rt/cmake/modules => cmake/Modules}/GetToolchainDirs.cmake (92%)

diff --git a/flang-rt/cmake/modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
similarity index 92%
rename from flang-rt/cmake/modules/GetToolchainDirs.cmake
rename to cmake/Modules/GetToolchainDirs.cmake
index 476d35790d559..21dffb40bf2ac 100644
--- a/flang-rt/cmake/modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -1,12 +1,3 @@
-#===-- cmake/modules/GetToolchainDirs.cmake --------------------------------===#
-#
-# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#
-#===------------------------------------------------------------------------===#
-
-
 # Determine the subdirectory relative to Clang's resource dir/sysroot where to
 # install target-specific libraries, to be found by Clang/Flang driver. This was
 # adapted from Compiler-RT's mechanism to find the path for
@@ -47,6 +38,17 @@ function (get_toolchain_library_subdir outvar)
 endfunction ()
 
 
+# Corresponds to Flang's ToolChain::getDefaultIntrinsicModuleDir().
+function (get_toolchain_module_subdir outvar)
+  set(outval "finclude/flang")
+
+  get_toolchain_arch_dirname(arch_dirname)
+  set(outval "${outval}/${arch_dirname}")
+
+  set(${outvar} "${outval}" PARENT_SCOPE)
+endfunction ()
+
+
 # Corresponds to Clang's ToolChain::getOSLibName(). Adapted from Compiler-RT.
 function (get_toolchain_os_dirname outvar)
   if (ANDROID)
diff --git a/flang-rt/CMakeLists.txt b/flang-rt/CMakeLists.txt
index 174974884fd41..7e964989d43e8 100644
--- a/flang-rt/CMakeLists.txt
+++ b/flang-rt/CMakeLists.txt
@@ -73,62 +73,9 @@ include(ExtendPath)
 # Build Mode Introspection #
 ############################
 
-# Determine whether we are in the runtimes/runtimes-bins directory of a
-# bootstrap build.
-set(LLVM_TREE_AVAILABLE OFF)
-if (LLVM_LIBRARY_OUTPUT_INTDIR AND LLVM_RUNTIME_OUTPUT_INTDIR AND PACKAGE_VERSION)
-  set(LLVM_TREE_AVAILABLE ON)
-endif()
-
 # Path to LLVM development tools (FileCheck, llvm-lit, not, ...)
 set(LLVM_TOOLS_DIR "${LLVM_BINARY_DIR}/bin")
 
-# Determine build and install paths.
-# The build path is absolute, but the install dir is relative, CMake's install
-# command has to apply CMAKE_INSTALL_PREFIX itself.
-get_toolchain_library_subdir(toolchain_lib_subdir)
-if (LLVM_TREE_AVAILABLE)
-  # In a bootstrap build emit the libraries into a default search path in the
-  # build directory of the just-built compiler. This allows using the
-  # just-built compiler without specifying paths to runtime libraries.
-  #
-  # Despite Clang in the name, get_clang_resource_dir does not depend on Clang
-  # being added to the build. Flang uses the same resource dir as clang.
-  include(GetClangResourceDir)
-  get_clang_resource_dir(FLANG_RT_OUTPUT_RESOURCE_DIR PREFIX "${LLVM_LIBRARY_OUTPUT_INTDIR}/..")
-  get_clang_resource_dir(FLANG_RT_INSTALL_RESOURCE_PATH_DEFAULT)
-
-  extend_path(FLANG_RT_OUTPUT_RESOURCE_LIB_DIR "${FLANG_RT_OUTPUT_RESOURCE_DIR}" "${toolchain_lib_subdir}")
-else ()
-  # In a standalone runtimes build, do not write into LLVM_BINARY_DIR. It may be
-  # read-only and/or shared by multiple runtimes with different build
-  # configurations (e.g. Debug/Release). Use the runtime's own lib dir like any
-  # non-toolchain library.
-  # For the install prefix, still use the resource dir assuming that Flang will
-  # be installed there using the same prefix. This is to not have a difference
-  # between bootstrap and standalone runtimes builds.
-  set(FLANG_RT_OUTPUT_RESOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
-  set(FLANG_RT_INSTALL_RESOURCE_PATH_DEFAULT "lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
-
-  extend_path(FLANG_RT_OUTPUT_RESOURCE_LIB_DIR "${FLANG_RT_OUTPUT_RESOURCE_DIR}" "lib${LLVM_LIBDIR_SUFFIX}")
-endif ()
-set(FLANG_RT_INSTALL_RESOURCE_PATH "${FLANG_RT_INSTALL_RESOURCE_PATH_DEFAULT}"
-    CACHE PATH "Path to install runtime libraries to (default: clang resource dir)")
-extend_path(FLANG_RT_INSTALL_RESOURCE_LIB_PATH "${FLANG_RT_INSTALL_RESOURCE_PATH}" "${toolchain_lib_subdir}")
-cmake_path(NORMAL_PATH FLANG_RT_OUTPUT_RESOURCE_DIR)
-cmake_path(NORMAL_PATH FLANG_RT_INSTALL_RESOURCE_PATH)
-# FIXME: For the libflang_rt.so, the toolchain resource lib dir is not a good
-#        destination because it is not a ld.so default search path.
-#        The machine where the executable is eventually executed may not be the
-#        machine where the Flang compiler and its resource dir is installed, so
-#        setting RPath by the driver is not an solution. It should belong into
-#        /usr/lib/<triple>/libflang_rt.so, like e.g. libgcc_s.so.
-#        But the linker as invoked by the Flang driver also requires
-#        libflang_rt.so to be found when linking and the resource lib dir is
-#        the only reliable location.
-cmake_path(NORMAL_PATH FLANG_RT_OUTPUT_RESOURCE_LIB_DIR)
-cmake_path(NORMAL_PATH FLANG_RT_INSTALL_RESOURCE_LIB_PATH)
-
 
 #################
 # Build Options #
diff --git a/flang-rt/cmake/modules/AddFlangRT.cmake b/flang-rt/cmake/modules/AddFlangRT.cmake
index 923507764d691..e960e79473cbb 100644
--- a/flang-rt/cmake/modules/AddFlangRT.cmake
+++ b/flang-rt/cmake/modules/AddFlangRT.cmake
@@ -344,13 +344,13 @@ function (add_flangrt_library name)
     if (ARG_INSTALL_WITH_TOOLCHAIN)
       set_target_properties(${tgtname}
         PROPERTIES
-          ARCHIVE_OUTPUT_DIRECTORY "${FLANG_RT_OUTPUT_RESOURCE_LIB_DIR}"
-          LIBRARY_OUTPUT_DIRECTORY "${FLANG_RT_OUTPUT_RESOURCE_LIB_DIR}"
+          ARCHIVE_OUTPUT_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_LIB_DIR}"
+          LIBRARY_OUTPUT_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_LIB_DIR}"
         )
 
       install(TARGETS ${tgtname}
-          ARCHIVE DESTINATION "${FLANG_RT_INSTALL_RESOURCE_LIB_PATH}"
-          LIBRARY DESTINATION "${FLANG_RT_INSTALL_RESOURCE_LIB_PATH}"
+          ARCHIVE DESTINATION "${RUNTIMES_INSTALL_RESOURCE_LIB_PATH}"
+          LIBRARY DESTINATION "${RUNTIMES_INSTALL_RESOURCE_LIB_PATH}"
         )
     endif ()
 
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 5220b9353fed7..f76a3162c6eea 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -85,7 +85,8 @@ include(CheckLibraryExists)
 include(LLVMCheckCompilerLinkerFlag)
 include(CheckCCompilerFlag)
 include(CheckCXXCompilerFlag)
-
+include(GetToolchainDirs)
+include(ExtendPath)
 
 # Determine whether we are in the runtimes/runtimes-bins directory of a
 # bootstrap build.
@@ -236,6 +237,36 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
   endif()
 endif()
 
+# Determine output and install paths based on LLVM_TARGET_TRIPLE
+if(LLVM_TREE_AVAILABLE)
+  # Despite Clang in the name, get_clang_resource_dir does not depend on Clang
+  # being added to the build. Flang uses the same resource dir as Clang.
+  include(GetClangResourceDir)
+  get_clang_resource_dir(RUNTIMES_OUTPUT_RESOURCE_DIR PREFIX "${LLVM_LIBRARY_OUTPUT_INTDIR}/..")
+  get_clang_resource_dir(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT)
+else()
+  # For the install prefix, still use the resource dir assuming the compilers
+  # looking for it (Clang, Flang) will be installed there using the same prefix.
+  # This is to not have a difference between bootstrapping and default/standalone runtimes
+  # builds.
+  set(RUNTIMES_OUTPUT_RESOURCE_DIR "${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
+  set(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT "lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
+endif()
+
+# Determine build and install paths. The output paths are absolute, but the
+# install dirs are relative to CMAKE_INSTALL_PREFIX to be resolved by CMake.
+get_toolchain_library_subdir(toolchain_lib_subdir)
+extend_path(RUNTIMES_OUTPUT_RESOURCE_LIB_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_lib_subdir}")
+
+set(RUNTIMES_INSTALL_RESOURCE_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT}" CACHE PATH "Path to install headers, runtime libraries, and Fortran modules to (default: Clang resource dir)")
+extend_path(RUNTIMES_INSTALL_RESOURCE_LIB_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_lib_subdir}")
+
+cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_DIR)
+cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_PATH)
+cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_LIB_DIR)
+cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
+
+
 option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
 option(LLVM_INCLUDE_DOCS "Generate build targets for the runtimes documentation." ON)
 option(LLVM_ENABLE_SPHINX "Use Sphinx to generate the runtimes documentation." OFF)

>From a3d2009626c9656721e6ad938dee0c25f9029281 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 26 Jan 2026 13:30:07 +0100
Subject: [PATCH 20/53] extract common code

---
 cmake/Modules/GetToolchainDirs.cmake          | 42 ++++++++++------
 .../cmake/Modules/CompilerRTUtils.cmake       | 50 ++-----------------
 2 files changed, 31 insertions(+), 61 deletions(-)

diff --git a/cmake/Modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
index 21dffb40bf2ac..e7955e334cfe6 100644
--- a/cmake/Modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -62,22 +62,17 @@ function (get_toolchain_os_dirname outvar)
 endfunction ()
 
 
-# Corresponds to Clang's ToolChain::getRuntimePath(). Adapted from Compiler-RT.
-function (get_toolchain_arch_dirname outvar)
-  string(FIND ${LLVM_TARGET_TRIPLE} "-" dash_index)
-  string(SUBSTRING ${LLVM_TARGET_TRIPLE} ${dash_index} -1 triple_suffix)
-  string(SUBSTRING ${LLVM_TARGET_TRIPLE} 0 ${dash_index} triple_cpu)
-  set(arch "${triple_cpu}")
-  if("${arch}" MATCHES "^i.86$")
-    # Android uses i686, but that's remapped at a later stage.
-    set(arch "i386")
-  endif()
-
-  if(ANDROID AND ${arch} STREQUAL "i386")
+# Internal function extracted from compiler-rt. Use get_toolchain_arch_dirname
+# instead for new code.
+function(get_runtimes_target_libdir_common default_target_triple arch variable)
+  string(FIND "${default_target_triple}" "-" dash_index)
+  string(SUBSTRING "${default_target_triple}" ${dash_index} -1 triple_suffix)
+  string(SUBSTRING "${default_target_triple}" 0 ${dash_index} triple_cpu)
+  if(ANDROID AND "${arch}" STREQUAL "i386")
     set(target "i686${triple_suffix}")
-  elseif(${arch} STREQUAL "amd64")
+  elseif("${arch}" STREQUAL "amd64")
     set(target "x86_64${triple_suffix}")
-  elseif(${arch} STREQUAL "sparc64")
+  elseif("${arch}" STREQUAL "sparc64")
     set(target "sparcv9${triple_suffix}")
   elseif("${arch}" MATCHES "mips64|mips64el")
     string(REGEX REPLACE "-gnu.*" "-gnuabi64" triple_suffix_gnu "${triple_suffix}")
@@ -91,7 +86,8 @@ function (get_toolchain_arch_dirname outvar)
     string(REGEX REPLACE "mips64" "mips" triple_cpu_mips "${triple_cpu_mips}")
     set(target "${triple_cpu_mips}${triple_suffix_gnu}")
   elseif("${arch}" MATCHES "^arm")
-    # FIXME: Handle arch other than arm, armhf, armv6m
+    # Arch is arm, armhf, armv6m (anything else would come from using
+    # COMPILER_RT_DEFAULT_TARGET_ONLY, which is checked above).
     if (${arch} STREQUAL "armhf")
       # If we are building for hard float but our ABI is soft float.
       if ("${triple_suffix}" MATCHES ".*eabi$")
@@ -115,5 +111,19 @@ function (get_toolchain_arch_dirname outvar)
   else()
     set(target "${arch}${triple_suffix}")
   endif()
-  set(${outvar} "${target}" PARENT_SCOPE)
+  set("${variable}" "${target}" PARENT_SCOPE)
+endfunction()
+
+
+# Corresponds to Clang's ToolChain::getRuntimePath().
+function (get_toolchain_arch_dirname outvar)
+  string(FIND "${LLVM_TARGET_TRIPLE}" "-" dash_index)
+  string(SUBSTRING "${LLVM_TARGET_TRIPLE}" 0 ${dash_index} triple_cpu)
+  set(arch "${triple_cpu}")
+  if("${arch}" MATCHES "^i.86$")
+    # Android uses i686, but that's remapped at a later stage.
+    set(arch "i386")
+  endif()
+  get_runtimes_target_libdir("${LLVM_TARGET_TRIPLE}" "${arch}" target)
+  set("${outvar}" "${target}" PARENT_SCOPE)
 endfunction()
diff --git a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
index cbd18d26c0b93..f97208430c855 100644
--- a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
+++ b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
@@ -460,56 +460,16 @@ function(filter_builtin_sources inout_var name)
 endfunction()
 
 function(get_compiler_rt_target arch variable)
-  string(FIND ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} "-" dash_index)
-  string(SUBSTRING ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} ${dash_index} -1 triple_suffix)
-  string(SUBSTRING ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} 0 ${dash_index} triple_cpu)
   if(COMPILER_RT_DEFAULT_TARGET_ONLY)
     # Use exact spelling when building only for the target specified to CMake.
     set(target "${COMPILER_RT_DEFAULT_TARGET_TRIPLE}")
-  elseif(ANDROID AND ${arch} STREQUAL "i386")
-    set(target "i686${triple_suffix}")
-  elseif(${arch} STREQUAL "amd64")
-    set(target "x86_64${triple_suffix}")
-  elseif(${arch} STREQUAL "sparc64")
-    set(target "sparcv9${triple_suffix}")
-  elseif("${arch}" MATCHES "mips64|mips64el")
-    string(REGEX REPLACE "-gnu.*" "-gnuabi64" triple_suffix_gnu "${triple_suffix}")
-    string(REGEX REPLACE "mipsisa32" "mipsisa64" triple_cpu_mips "${triple_cpu}")
-    string(REGEX REPLACE "^mips$" "mips64" triple_cpu_mips "${triple_cpu_mips}")
-    string(REGEX REPLACE "^mipsel$" "mips64el" triple_cpu_mips "${triple_cpu_mips}")
-    set(target "${triple_cpu_mips}${triple_suffix_gnu}")
-  elseif("${arch}" MATCHES "mips|mipsel")
-    string(REGEX REPLACE "-gnuabi.*" "-gnu" triple_suffix_gnu "${triple_suffix}")
-    string(REGEX REPLACE "mipsisa64" "mipsisa32" triple_cpu_mips "${triple_cpu}")
-    string(REGEX REPLACE "mips64" "mips" triple_cpu_mips "${triple_cpu_mips}")
-    set(target "${triple_cpu_mips}${triple_suffix_gnu}")
-  elseif("${arch}" MATCHES "^arm")
-    # Arch is arm, armhf, armv6m (anything else would come from using
-    # COMPILER_RT_DEFAULT_TARGET_ONLY, which is checked above).
-    if (${arch} STREQUAL "armhf")
-      # If we are building for hard float but our ABI is soft float.
-      if ("${triple_suffix}" MATCHES ".*eabi$")
-        # Change "eabi" -> "eabihf"
-        set(triple_suffix "${triple_suffix}hf")
-      endif()
-      # ABI is already set in the triple, don't repeat it in the architecture.
-      set(arch "arm")
-    else ()
-      # If we are building for soft float, but the triple's ABI is hard float.
-      if ("${triple_suffix}" MATCHES ".*eabihf$")
-        # Change "eabihf" -> "eabi"
-        string(REGEX REPLACE "hf$" "" triple_suffix "${triple_suffix}")
-      endif()
-    endif()
-    set(target "${arch}${triple_suffix}")
-  elseif("${arch}" MATCHES "^amdgcn")
-    set(target "amdgcn-amd-amdhsa")
-  elseif("${arch}" MATCHES "^nvptx")
-    set(target "nvptx64-nvidia-cuda")
   else()
-    set(target "${arch}${triple_suffix}")
+    string(FIND ${default_target_triple} "-" dash_index)
+    string(SUBSTRING ${default_target_triple} ${dash_index} -1 triple_suffix)
+    string(SUBSTRING ${default_target_triple} 0 ${dash_index} triple_cpu)
+    get_runtimes_target_libdir_common("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" "${arch}" result)
   endif()
-  set(${variable} ${target} PARENT_SCOPE)
+  set(${variable} "${result}" PARENT_SCOPE)
 endfunction()
 
 function(get_compiler_rt_install_dir arch install_dir)

>From a675c9aa2f847877e7a430a59ec28ece56896189 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 26 Jan 2026 14:02:18 +0100
Subject: [PATCH 21/53] Add TODO comments

---
 compiler-rt/cmake/Modules/CompilerRTUtils.cmake | 2 ++
 compiler-rt/cmake/base-config-ix.cmake          | 2 ++
 libc/CMakeLists.txt                             | 2 ++
 libcxx/CMakeLists.txt                           | 1 +
 libcxxabi/CMakeLists.txt                        | 1 +
 libsycl/CMakeLists.txt                          | 1 +
 libunwind/CMakeLists.txt                        | 1 +
 llvm-libgcc/CMakeLists.txt                      | 1 +
 offload/CMakeLists.txt                          | 3 +++
 openmp/CMakeLists.txt                           | 1 +
 orc-rt/lib/executor/CMakeLists.txt              | 1 +
 third-party/benchmark/src/CMakeLists.txt        | 1 +
 12 files changed, 17 insertions(+)

diff --git a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
index f97208430c855..80bd14597a642 100644
--- a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
+++ b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
@@ -473,6 +473,7 @@ function(get_compiler_rt_target arch variable)
 endfunction()
 
 function(get_compiler_rt_install_dir arch install_dir)
+  # TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
   if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
     get_compiler_rt_target(${arch} target)
     set(${install_dir} ${COMPILER_RT_INSTALL_LIBRARY_DIR}/${target} PARENT_SCOPE)
@@ -482,6 +483,7 @@ function(get_compiler_rt_install_dir arch install_dir)
 endfunction()
 
 function(get_compiler_rt_output_dir arch output_dir)
+  # TODO: Use RUNTIMES_OUTPUT_RESOURCE_LIB_DIR instead
   if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
     get_compiler_rt_target(${arch} target)
     set(${output_dir} ${COMPILER_RT_OUTPUT_LIBRARY_DIR}/${target} PARENT_SCOPE)
diff --git a/compiler-rt/cmake/base-config-ix.cmake b/compiler-rt/cmake/base-config-ix.cmake
index 37dfa5534dfef..845f999192079 100644
--- a/compiler-rt/cmake/base-config-ix.cmake
+++ b/compiler-rt/cmake/base-config-ix.cmake
@@ -103,6 +103,8 @@ if(NOT DEFINED COMPILER_RT_OS_DIR)
     string(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_OS_DIR)
   endif()
 endif()
+
+# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(COMPILER_RT_OUTPUT_LIBRARY_DIR
     ${COMPILER_RT_OUTPUT_DIR}/lib)
diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt
index 4e6b4195a9c5e..334717d68d4ec 100644
--- a/libc/CMakeLists.txt
+++ b/libc/CMakeLists.txt
@@ -234,6 +234,7 @@ if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
   cmake_path(NORMAL_PATH LIBC_TARGET_SUBDIR)
 endif()
 
+# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND (LIBC_ENABLE_USE_BY_CLANG OR LIBC_TARGET_OS_IS_GPU))
   set(LIBC_INCLUDE_DIR ${LLVM_BINARY_DIR}/include/${LLVM_DEFAULT_TARGET_TRIPLE})
   set(LIBC_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR}/${LLVM_DEFAULT_TARGET_TRIPLE})
@@ -260,6 +261,7 @@ else()
   endif()
 endif()
 
+# TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
 if(LIBC_TARGET_TRIPLE)
   set(LIBC_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LIBC_TARGET_TRIPLE})
 elseif(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 56b346415c1c6..98fdd3e35ddf0 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -421,6 +421,7 @@ set(LIBCXX_INSTALL_MODULES_DIR "share/libc++/v1" CACHE STRING
 set(LIBCXX_SHARED_OUTPUT_NAME "c++" CACHE STRING "Output name for the shared libc++ runtime library.")
 set(LIBCXX_STATIC_OUTPUT_NAME "c++" CACHE STRING "Output name for the static libc++ runtime library.")
 
+# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBCXX_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBCXX_LIBDIR_SUBDIR)
diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt
index 2b67c5972339e..246c2ad97eacf 100644
--- a/libcxxabi/CMakeLists.txt
+++ b/libcxxabi/CMakeLists.txt
@@ -185,6 +185,7 @@ set(CMAKE_MODULE_PATH
 set(LIBCXXABI_INSTALL_RUNTIME_DIR "${CMAKE_INSTALL_BINDIR}" CACHE STRING
     "Path where built libc++abi runtime libraries should be installed.")
 
+# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBCXXABI_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBCXXABI_LIBDIR_SUBDIR)
diff --git a/libsycl/CMakeLists.txt b/libsycl/CMakeLists.txt
index fe08a4249bada..c96095a39dc92 100644
--- a/libsycl/CMakeLists.txt
+++ b/libsycl/CMakeLists.txt
@@ -39,6 +39,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 set(LIBSYCL_SHARED_OUTPUT_NAME "sycl" CACHE STRING "Output name for the shared libsycl runtime library.")
 
+# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBSYCL_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBSYCL_LIBDIR_SUBDIR)
diff --git a/libunwind/CMakeLists.txt b/libunwind/CMakeLists.txt
index fbef71f3f7446..cf7b43d7d8276 100644
--- a/libunwind/CMakeLists.txt
+++ b/libunwind/CMakeLists.txt
@@ -140,6 +140,7 @@ set(LIBUNWIND_INSTALL_RUNTIME_DIR "${CMAKE_INSTALL_BINDIR}" CACHE STRING
 set(LIBUNWIND_SHARED_OUTPUT_NAME "unwind" CACHE STRING "Output name for the shared libunwind runtime library.")
 set(LIBUNWIND_STATIC_OUTPUT_NAME "unwind" CACHE STRING "Output name for the static libunwind runtime library.")
 
+# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBUNWIND_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBUNWIND_LIBDIR_SUBDIR)
diff --git a/llvm-libgcc/CMakeLists.txt b/llvm-libgcc/CMakeLists.txt
index 47208fc198692..ef4b9060e6d74 100644
--- a/llvm-libgcc/CMakeLists.txt
+++ b/llvm-libgcc/CMakeLists.txt
@@ -61,6 +61,7 @@ endif()
 # Configure System
 #===============================================================================
 
+# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LLVM_LIBGCC_LIBDIR_SUBDIR)
diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index 81e246d9f8892..a6e3234a22938 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -26,6 +26,7 @@ endif()
 
 set(OFFLOAD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
+# TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
 if(OPENMP_STANDALONE_BUILD)
   set(OFFLOAD_LIBDIR_SUFFIX "" CACHE STRING
     "Suffix of lib installation directory, e.g. 64 => lib64")
@@ -87,6 +88,7 @@ if (OPENMP_STANDALONE_BUILD)
 else()
   set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
   # If building in tree, we honor the same install suffix LLVM uses.
+  # TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
   set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
 
   if (NOT MSVC)
@@ -376,6 +378,7 @@ if(LIBOMP_OMP_TOOLS_INCLUDE_DIR)
   include_directories(${LIBOMP_OMP_TOOLS_INCLUDE_DIR})
 endif()
 
+# TODO: Use RUNTIMES_OUTPUT_RESOURCE_LIB_DIR instead
 set(LIBOMPTARGET_LLVM_LIBRARY_DIR "${LLVM_LIBRARY_DIR}" CACHE STRING
   "Path to folder containing llvm library libomptarget.so")
 set(LIBOMPTARGET_LLVM_LIBRARY_INTDIR "${LIBOMPTARGET_INTDIR}" CACHE STRING
diff --git a/openmp/CMakeLists.txt b/openmp/CMakeLists.txt
index df568419824a6..8be4bb5d190f9 100644
--- a/openmp/CMakeLists.txt
+++ b/openmp/CMakeLists.txt
@@ -63,6 +63,7 @@ else()
   set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
 
   # When building in tree we install the runtime according to the LLVM settings.
+  # TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
   if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
     set(OPENMP_INSTALL_LIBDIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE} CACHE STRING
         "Path where built openmp libraries should be installed.")
diff --git a/orc-rt/lib/executor/CMakeLists.txt b/orc-rt/lib/executor/CMakeLists.txt
index cca5246b4d127..ba070af21e0c4 100644
--- a/orc-rt/lib/executor/CMakeLists.txt
+++ b/orc-rt/lib/executor/CMakeLists.txt
@@ -16,6 +16,7 @@ target_link_libraries(orc-rt-executor
   )
 
 # Apply RTTI and exceptions compile flags
+# TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
 target_compile_options(orc-rt-executor PRIVATE ${ORC_RT_COMPILE_FLAGS})
 install(TARGETS orc-rt-executor
   ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
diff --git a/third-party/benchmark/src/CMakeLists.txt b/third-party/benchmark/src/CMakeLists.txt
index 0357dcce3f831..a291f1f904043 100644
--- a/third-party/benchmark/src/CMakeLists.txt
+++ b/third-party/benchmark/src/CMakeLists.txt
@@ -114,6 +114,7 @@ export (
 
 if (BENCHMARK_ENABLE_INSTALL)
   # Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable)
+  # TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
   install(
     TARGETS ${targets_to_export}
     EXPORT ${targets_export_name}

>From fcdc6b40d0b55ba02de128f11185ec53d673ea22 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 26 Jan 2026 14:57:47 +0100
Subject: [PATCH 22/53] Add include for standalone build

---
 cmake/Modules/GetToolchainDirs.cmake            | 4 +++-
 compiler-rt/cmake/Modules/CompilerRTUtils.cmake | 4 +---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/cmake/Modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
index e7955e334cfe6..a16492fda0146 100644
--- a/cmake/Modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -65,7 +65,9 @@ endfunction ()
 # Internal function extracted from compiler-rt. Use get_toolchain_arch_dirname
 # instead for new code.
 function(get_runtimes_target_libdir_common default_target_triple arch variable)
+message("  string(FIND "${default_target_triple}" "-" dash_index)")
   string(FIND "${default_target_triple}" "-" dash_index)
+message("string(SUBSTRING "${default_target_triple}" ${dash_index} -1 triple_suffix)")
   string(SUBSTRING "${default_target_triple}" ${dash_index} -1 triple_suffix)
   string(SUBSTRING "${default_target_triple}" 0 ${dash_index} triple_cpu)
   if(ANDROID AND "${arch}" STREQUAL "i386")
@@ -124,6 +126,6 @@ function (get_toolchain_arch_dirname outvar)
     # Android uses i686, but that's remapped at a later stage.
     set(arch "i386")
   endif()
-  get_runtimes_target_libdir("${LLVM_TARGET_TRIPLE}" "${arch}" target)
+  get_runtimes_target_libdir_common("${LLVM_TARGET_TRIPLE}" "${arch}" target)
   set("${outvar}" "${target}" PARENT_SCOPE)
 endfunction()
diff --git a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
index 80bd14597a642..5d0ce55e44a6d 100644
--- a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
+++ b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
@@ -1,5 +1,6 @@
 include(CMakePushCheckState)
 include(CheckSymbolExists)
+include(GetToolchainDirs)
 
 # Because compiler-rt spends a lot of time setting up custom compile flags,
 # define a handy helper function for it. The compile flags setting in CMake
@@ -464,9 +465,6 @@ function(get_compiler_rt_target arch variable)
     # Use exact spelling when building only for the target specified to CMake.
     set(target "${COMPILER_RT_DEFAULT_TARGET_TRIPLE}")
   else()
-    string(FIND ${default_target_triple} "-" dash_index)
-    string(SUBSTRING ${default_target_triple} ${dash_index} -1 triple_suffix)
-    string(SUBSTRING ${default_target_triple} 0 ${dash_index} triple_cpu)
     get_runtimes_target_libdir_common("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" "${arch}" result)
   endif()
   set(${variable} "${result}" PARENT_SCOPE)

>From 4ff5e85c395a11299f33cf9ef9756c616f5b0116 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 26 Jan 2026 23:20:06 +0100
Subject: [PATCH 23/53] typos

---
 flang-rt/cmake/modules/AddFlangRT.cmake | 4 ++--
 runtimes/CMakeLists.txt                 | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/flang-rt/cmake/modules/AddFlangRT.cmake b/flang-rt/cmake/modules/AddFlangRT.cmake
index 73a77e09847fe..8acd147ad87b7 100644
--- a/flang-rt/cmake/modules/AddFlangRT.cmake
+++ b/flang-rt/cmake/modules/AddFlangRT.cmake
@@ -376,8 +376,8 @@ function (add_flangrt_library name)
       #        is /usr/lib/<triple>/lib<name>.so, like e.g. libgcc_s.so.
       #        Flang-RT also would require a library versioning scheme so
       #        executables compiled with different versions of Flang either use
-      #        matching versions of Flang-RT, or use a newer backward-compatble
-      #        versions. Currently, Flang-RT has no ABI backwards-compatibility
+      #        matching versions of Flang-RT, or use a newer backward-compatible
+      #        version. Currently, Flang-RT has no ABI backwards-compatibility
       #        policy.
       #        Currently, we just emit it into RUNTIMES_OUTPUT_RESOURCE_LIB_DIR
       #        like the static library, which is already in the driver's and
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 8aae896536af0..5a70407cd94f2 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -258,7 +258,7 @@ else()
   set(RUNTIMES_INSTALL_RESOURCE_PATH_DEFAULT "lib${LLVM_LIBDIR_SUFFIX}/clang/${LLVM_VERSION_MAJOR}")
 endif()
 
-# Determine build and install paths. The ouptut paths are absolute, but the
+# Determine build and install paths. The output paths are absolute, but the
 # install dirs are relative to CMAKE_INSTALL_PREFIX to be resolved by CMake.
 get_toolchain_library_subdir(toolchain_lib_subdir)
 extend_path(RUNTIMES_OUTPUT_RESOURCE_LIB_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_lib_subdir}")

>From d51726e19752c1ac9436d85daf693a0de2c42cd8 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 26 Jan 2026 23:28:17 +0100
Subject: [PATCH 24/53] Try fix PR

---
 compiler-rt/cmake/Modules/CompilerRTUtils.cmake | 4 ++--
 compiler-rt/cmake/base-config-ix.cmake          | 2 +-
 libc/CMakeLists.txt                             | 4 ++--
 libcxx/CMakeLists.txt                           | 2 +-
 libcxxabi/CMakeLists.txt                        | 2 +-
 libsycl/CMakeLists.txt                          | 2 +-
 libunwind/CMakeLists.txt                        | 2 +-
 llvm-libgcc/CMakeLists.txt                      | 2 +-
 offload/CMakeLists.txt                          | 4 ++--
 openmp/CMakeLists.txt                           | 3 ++-
 orc-rt/lib/executor/CMakeLists.txt              | 2 +-
 third-party/benchmark/src/CMakeLists.txt        | 1 -
 12 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
index 5d0ce55e44a6d..8c27c4585f73b 100644
--- a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
+++ b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
@@ -465,9 +465,9 @@ function(get_compiler_rt_target arch variable)
     # Use exact spelling when building only for the target specified to CMake.
     set(target "${COMPILER_RT_DEFAULT_TARGET_TRIPLE}")
   else()
-    get_runtimes_target_libdir_common("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" "${arch}" result)
+    get_runtimes_target_libdir_common("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" "${arch}" target)
   endif()
-  set(${variable} "${result}" PARENT_SCOPE)
+  set(${variable} "${target}" PARENT_SCOPE)
 endfunction()
 
 function(get_compiler_rt_install_dir arch install_dir)
diff --git a/compiler-rt/cmake/base-config-ix.cmake b/compiler-rt/cmake/base-config-ix.cmake
index 845f999192079..d4abf80faa73a 100644
--- a/compiler-rt/cmake/base-config-ix.cmake
+++ b/compiler-rt/cmake/base-config-ix.cmake
@@ -104,7 +104,7 @@ if(NOT DEFINED COMPILER_RT_OS_DIR)
   endif()
 endif()
 
-# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(COMPILER_RT_OUTPUT_LIBRARY_DIR
     ${COMPILER_RT_OUTPUT_DIR}/lib)
diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt
index 334717d68d4ec..2988a42b5d3a3 100644
--- a/libc/CMakeLists.txt
+++ b/libc/CMakeLists.txt
@@ -234,7 +234,7 @@ if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
   cmake_path(NORMAL_PATH LIBC_TARGET_SUBDIR)
 endif()
 
-# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND (LIBC_ENABLE_USE_BY_CLANG OR LIBC_TARGET_OS_IS_GPU))
   set(LIBC_INCLUDE_DIR ${LLVM_BINARY_DIR}/include/${LLVM_DEFAULT_TARGET_TRIPLE})
   set(LIBC_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR}/${LLVM_DEFAULT_TARGET_TRIPLE})
@@ -261,7 +261,7 @@ else()
   endif()
 endif()
 
-# TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LIBC_TARGET_TRIPLE)
   set(LIBC_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LIBC_TARGET_TRIPLE})
 elseif(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 98fdd3e35ddf0..4d7e3a69e3ae9 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -421,7 +421,7 @@ set(LIBCXX_INSTALL_MODULES_DIR "share/libc++/v1" CACHE STRING
 set(LIBCXX_SHARED_OUTPUT_NAME "c++" CACHE STRING "Output name for the shared libc++ runtime library.")
 set(LIBCXX_STATIC_OUTPUT_NAME "c++" CACHE STRING "Output name for the static libc++ runtime library.")
 
-# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBCXX_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBCXX_LIBDIR_SUBDIR)
diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt
index 246c2ad97eacf..e1a1587fb6283 100644
--- a/libcxxabi/CMakeLists.txt
+++ b/libcxxabi/CMakeLists.txt
@@ -185,7 +185,7 @@ set(CMAKE_MODULE_PATH
 set(LIBCXXABI_INSTALL_RUNTIME_DIR "${CMAKE_INSTALL_BINDIR}" CACHE STRING
     "Path where built libc++abi runtime libraries should be installed.")
 
-# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBCXXABI_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBCXXABI_LIBDIR_SUBDIR)
diff --git a/libsycl/CMakeLists.txt b/libsycl/CMakeLists.txt
index c96095a39dc92..8611814baa3b1 100644
--- a/libsycl/CMakeLists.txt
+++ b/libsycl/CMakeLists.txt
@@ -39,7 +39,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 set(LIBSYCL_SHARED_OUTPUT_NAME "sycl" CACHE STRING "Output name for the shared libsycl runtime library.")
 
-# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBSYCL_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBSYCL_LIBDIR_SUBDIR)
diff --git a/libunwind/CMakeLists.txt b/libunwind/CMakeLists.txt
index cf7b43d7d8276..1681b90b31cdb 100644
--- a/libunwind/CMakeLists.txt
+++ b/libunwind/CMakeLists.txt
@@ -140,7 +140,7 @@ set(LIBUNWIND_INSTALL_RUNTIME_DIR "${CMAKE_INSTALL_BINDIR}" CACHE STRING
 set(LIBUNWIND_SHARED_OUTPUT_NAME "unwind" CACHE STRING "Output name for the shared libunwind runtime library.")
 set(LIBUNWIND_STATIC_OUTPUT_NAME "unwind" CACHE STRING "Output name for the static libunwind runtime library.")
 
-# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBUNWIND_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBUNWIND_LIBDIR_SUBDIR)
diff --git a/llvm-libgcc/CMakeLists.txt b/llvm-libgcc/CMakeLists.txt
index ef4b9060e6d74..55c052165dbd1 100644
--- a/llvm-libgcc/CMakeLists.txt
+++ b/llvm-libgcc/CMakeLists.txt
@@ -61,7 +61,7 @@ endif()
 # Configure System
 #===============================================================================
 
-# TODO: Use RUNTIMES_OUTPUT_RESOURCE_*_DIR/RUNTIMES_INSTALL_RESOURCE_*_PATH instead
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LLVM_LIBGCC_LIBDIR_SUBDIR)
diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index a6e3234a22938..4012f356fa746 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -26,7 +26,7 @@ endif()
 
 set(OFFLOAD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
-# TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
+# TODO: Use common runtimes infrastructure for output and install paths
 if(OPENMP_STANDALONE_BUILD)
   set(OFFLOAD_LIBDIR_SUFFIX "" CACHE STRING
     "Suffix of lib installation directory, e.g. 64 => lib64")
@@ -88,7 +88,7 @@ if (OPENMP_STANDALONE_BUILD)
 else()
   set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
   # If building in tree, we honor the same install suffix LLVM uses.
-  # TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
+  # TODO: Use common runtimes infrastructure for output and install paths
   set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
 
   if (NOT MSVC)
diff --git a/openmp/CMakeLists.txt b/openmp/CMakeLists.txt
index 8be4bb5d190f9..332d9c1d5ce03 100644
--- a/openmp/CMakeLists.txt
+++ b/openmp/CMakeLists.txt
@@ -35,6 +35,7 @@ if (OPENMP_STANDALONE_BUILD)
   set(OPENMP_LIBDIR_SUFFIX "" CACHE STRING
     "Suffix of lib installation directory, e.g. 64 => lib64")
   # Do not use OPENMP_LIBDIR_SUFFIX directly, use OPENMP_INSTALL_LIBDIR.
+  # TODO: Use common runtimes infrastructure for output and install paths
   set(OPENMP_INSTALL_LIBDIR "lib${OPENMP_LIBDIR_SUFFIX}" CACHE STRING
       "Path where built OpenMP libraries should be installed.")
 
@@ -63,7 +64,7 @@ else()
   set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
 
   # When building in tree we install the runtime according to the LLVM settings.
-  # TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
+  # TODO: Use common runtimes infrastructure for output and install paths
   if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
     set(OPENMP_INSTALL_LIBDIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE} CACHE STRING
         "Path where built openmp libraries should be installed.")
diff --git a/orc-rt/lib/executor/CMakeLists.txt b/orc-rt/lib/executor/CMakeLists.txt
index ba070af21e0c4..b7db13b3d2b47 100644
--- a/orc-rt/lib/executor/CMakeLists.txt
+++ b/orc-rt/lib/executor/CMakeLists.txt
@@ -16,7 +16,7 @@ target_link_libraries(orc-rt-executor
   )
 
 # Apply RTTI and exceptions compile flags
-# TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
+# TODO: Use common runtimes infrastructure for output and install paths
 target_compile_options(orc-rt-executor PRIVATE ${ORC_RT_COMPILE_FLAGS})
 install(TARGETS orc-rt-executor
   ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
diff --git a/third-party/benchmark/src/CMakeLists.txt b/third-party/benchmark/src/CMakeLists.txt
index a291f1f904043..0357dcce3f831 100644
--- a/third-party/benchmark/src/CMakeLists.txt
+++ b/third-party/benchmark/src/CMakeLists.txt
@@ -114,7 +114,6 @@ export (
 
 if (BENCHMARK_ENABLE_INSTALL)
   # Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable)
-  # TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
   install(
     TARGETS ${targets_to_export}
     EXPORT ${targets_export_name}

>From 443e4e8cd80e35ad13b34798eccc21485c8ef458 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Tue, 27 Jan 2026 10:42:51 +0100
Subject: [PATCH 25/53] Address review comments by @petrhosek

---
 cmake/Modules/GetToolchainDirs.cmake | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/cmake/Modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
index a16492fda0146..cdc00f6867dd8 100644
--- a/cmake/Modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -39,7 +39,7 @@ endfunction ()
 
 
 # Corresponds to Flang's ToolChain::getDefaultIntrinsicModuleDir().
-function (get_toolchain_module_subdir outvar)
+function (get_toolchain_fortran_module_subdir outvar)
   set(outval "finclude/flang")
 
   get_toolchain_arch_dirname(arch_dirname)
@@ -65,11 +65,9 @@ endfunction ()
 # Internal function extracted from compiler-rt. Use get_toolchain_arch_dirname
 # instead for new code.
 function(get_runtimes_target_libdir_common default_target_triple arch variable)
-message("  string(FIND "${default_target_triple}" "-" dash_index)")
   string(FIND "${default_target_triple}" "-" dash_index)
-message("string(SUBSTRING "${default_target_triple}" ${dash_index} -1 triple_suffix)")
-  string(SUBSTRING "${default_target_triple}" ${dash_index} -1 triple_suffix)
-  string(SUBSTRING "${default_target_triple}" 0 ${dash_index} triple_cpu)
+  string(SUBSTRING "${default_target_triple}" "${dash_index}" -1 triple_suffix)
+  string(SUBSTRING "${default_target_triple}" 0 "${dash_index}" triple_cpu)
   if(ANDROID AND "${arch}" STREQUAL "i386")
     set(target "i686${triple_suffix}")
   elseif("${arch}" STREQUAL "amd64")
@@ -120,10 +118,9 @@ endfunction()
 # Corresponds to Clang's ToolChain::getRuntimePath().
 function (get_toolchain_arch_dirname outvar)
   string(FIND "${LLVM_TARGET_TRIPLE}" "-" dash_index)
-  string(SUBSTRING "${LLVM_TARGET_TRIPLE}" 0 ${dash_index} triple_cpu)
+  string(SUBSTRING "${LLVM_TARGET_TRIPLE}" 0 "${dash_index}" triple_cpu)
   set(arch "${triple_cpu}")
   if("${arch}" MATCHES "^i.86$")
-    # Android uses i686, but that's remapped at a later stage.
     set(arch "i386")
   endif()
   get_runtimes_target_libdir_common("${LLVM_TARGET_TRIPLE}" "${arch}" target)

>From 4282e1654be2cc36a479d3da3dbecfe167f5b29b Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Tue, 27 Jan 2026 12:47:42 +0100
Subject: [PATCH 26/53] Unbreak test

---
 flang-rt/test/lit.site.cfg.py.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang-rt/test/lit.site.cfg.py.in b/flang-rt/test/lit.site.cfg.py.in
index 662d076b1fe24..0e9dc08b59925 100644
--- a/flang-rt/test/lit.site.cfg.py.in
+++ b/flang-rt/test/lit.site.cfg.py.in
@@ -6,7 +6,7 @@ config.llvm_tools_dir = "@LLVM_TOOLS_DIR@"
 config.flang_source_dir = "@FLANG_SOURCE_DIR@"
 config.flang_rt_source_dir = "@FLANG_RT_SOURCE_DIR@"
 config.flang_rt_binary_test_dir = os.path.dirname(__file__)
-config.flang_rt_output_resource_lib_dir = "@FLANG_RT_OUTPUT_RESOURCE_LIB_DIR@"
+config.flang_rt_output_resource_lib_dir = "@RUNTIMES_OUTPUT_RESOURCE_LIB_DIR@"
 config.flang_rt_experimental_offload_support = "@FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT@"
 config.cc = "@CMAKE_C_COMPILER@"
 config.flang = "@CMAKE_Fortran_COMPILER@"

>From 6e51372b954cd30d6e2b080c5ad409b5471e894d Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Wed, 11 Mar 2026 15:58:32 +0100
Subject: [PATCH 27/53] Address some of @petrhosek's review remarks

---
 cmake/Modules/GetToolchainDirs.cmake | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/cmake/Modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
index cdc00f6867dd8..944dc943eb2bf 100644
--- a/cmake/Modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -5,8 +5,8 @@
 #
 # Compiler-RT has two mechanisms for the path (simplified):
 #
-# * LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=0: lib/${oslibname}/libclang_rt.builtins-${arch}.a
-# * LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=1: lib/${triple}/libclang_rt.builtins.a
+# * LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF: lib/${oslibname}/libclang_rt.builtins-${arch}.a
+# * LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON : lib/${triple}/libclang_rt.builtins.a
 #
 # LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON is the newer scheme, but the old one is
 # currently still used for some platforms such as Windows. Clang looks for which
@@ -30,8 +30,8 @@ function (get_toolchain_library_subdir outvar)
     get_toolchain_os_dirname(os_dirname)
     set(outval "${outval}/${os_dirname}")
   else ()
-    get_toolchain_arch_dirname(arch_dirname)
-    set(outval "${outval}/${arch_dirname}")
+    get_toolchain_target_dirname(target_dirname)
+    set(outval "${outval}/${target_dirname}")
   endif ()
 
   set(${outvar} "${outval}" PARENT_SCOPE)
@@ -42,8 +42,8 @@ endfunction ()
 function (get_toolchain_fortran_module_subdir outvar)
   set(outval "finclude/flang")
 
-  get_toolchain_arch_dirname(arch_dirname)
-  set(outval "${outval}/${arch_dirname}")
+  get_toolchain_target_dirname(target_dirname)
+  set(outval "${outval}/${target_dirname}")
 
   set(${outvar} "${outval}" PARENT_SCOPE)
 endfunction ()
@@ -62,7 +62,7 @@ function (get_toolchain_os_dirname outvar)
 endfunction ()
 
 
-# Internal function extracted from compiler-rt. Use get_toolchain_arch_dirname
+# Internal function extracted from compiler-rt. Use get_toolchain_target_dirname
 # instead for new code.
 function(get_runtimes_target_libdir_common default_target_triple arch variable)
   string(FIND "${default_target_triple}" "-" dash_index)
@@ -116,7 +116,7 @@ endfunction()
 
 
 # Corresponds to Clang's ToolChain::getRuntimePath().
-function (get_toolchain_arch_dirname outvar)
+function (get_toolchain_target_dirname outvar)
   string(FIND "${LLVM_TARGET_TRIPLE}" "-" dash_index)
   string(SUBSTRING "${LLVM_TARGET_TRIPLE}" 0 "${dash_index}" triple_cpu)
   set(arch "${triple_cpu}")

>From 0ffc0c76d6f97264183ba24643647c82c51cd40e Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 12 Mar 2026 16:30:57 +0100
Subject: [PATCH 28/53] Update file documentation

---
 cmake/Modules/GetToolchainDirs.cmake | 30 ++++++++++++++--------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/cmake/Modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
index 944dc943eb2bf..4cabf95311c5c 100644
--- a/cmake/Modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -1,7 +1,7 @@
-# Determine the subdirectory relative to Clang's resource dir/sysroot where to
-# install target-specific libraries, to be found by Clang/Flang driver. This was
-# adapted from Compiler-RT's mechanism to find the path for
-# libclang_rt.builtins.a.
+# Determine the subdirectory relative to Clang's resource dir/installation
+# prefix where to install target-specific libraries, to be found by the
+# Clang/Flang driver. This was adapted from Compiler-RT's mechanism to find the
+# path for libclang_rt.builtins.a.
 #
 # Compiler-RT has two mechanisms for the path (simplified):
 #
@@ -9,19 +9,19 @@
 # * LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON : lib/${triple}/libclang_rt.builtins.a
 #
 # LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON is the newer scheme, but the old one is
-# currently still used for some platforms such as Windows. Clang looks for which
-# of the files exist before passing the path to the linker. Hence, the
-# directories have to match what Clang is looking for, which is done in
-# ToolChain::getArchSpecificLibPaths(..), ToolChain::getRuntimePath(),
+# currently still used by default for some platforms such as Windows. Clang
+# looks for which of the files exist before passing the path to the linker.
+# Hence, the directories have to match what Clang is looking for, which is done
+# in ToolChain::getArchSpecificLibPaths(..), ToolChain::getRuntimePath(),
 # ToolChain::getCompilerRTPath(), and ToolChain::getCompilerRT(..), not entirely
-# consistent between these functions, Compiler-RT's CMake code, and overrides
-# in different toolchains.
+# consistent between these functions, overrides in different toolchains, and
+# Compiler-RT's CMake code.
 #
-# For Fortran, Flang always assumes the library name libflang_rt.a without
-# architecture suffix. Hence, we always use the second scheme even as if
-# LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON, even if it actually set to OFF. It as
-# added unconditionally to the library search path by
-# ToolChain::getArchSpecificLibPaths(...).
+# For simplicity, we always use the second scheme even as if
+# LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON, even if it actually set to OFF.
+# The driver's lookup does not take the build-time
+# LLVM_ENABLE_PER_TARGET_RUNTIME_DIR setting into account anyway
+# and will always find its files using either scheme.
 function (get_toolchain_library_subdir outvar)
   set(outval "lib")
 

>From e27dbf81e43f5048456c7f3fcb549fb45357f04b Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 19 Mar 2026 16:59:44 +0100
Subject: [PATCH 29/53] Reapply c4170461d7fc5ddd0423c5f7325abd0a7dfc6277

---
 flang-rt/lib/runtime/CMakeLists.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/flang-rt/lib/runtime/CMakeLists.txt b/flang-rt/lib/runtime/CMakeLists.txt
index a0728cb4cad12..4d0c27f85a156 100644
--- a/flang-rt/lib/runtime/CMakeLists.txt
+++ b/flang-rt/lib/runtime/CMakeLists.txt
@@ -33,6 +33,7 @@ set(module_sources
 
   __cuda_device.f90
   cooperative_groups.f90
+  cuda_runtime_api.f90
   cudadevice.f90
 )
 
@@ -190,6 +191,7 @@ endif ()
 set_property(SOURCE
     __cuda_device.f90
     cooperative_groups.f90
+    cuda_runtime_api.f90
     cudadevice.f90
   APPEND PROPERTY
     COMPILE_OPTIONS --offload-host-only -xcuda

>From e06ac0472ea0ad211a401e364243389acc6dc05b Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 19 Mar 2026 17:43:06 +0100
Subject: [PATCH 30/53] Remove unused LIBOMP_FORTRAN_MODULES

---
 openmp/CMakeLists.txt | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/openmp/CMakeLists.txt b/openmp/CMakeLists.txt
index 2690f9d77afd8..37c1fb4a8b6c4 100644
--- a/openmp/CMakeLists.txt
+++ b/openmp/CMakeLists.txt
@@ -93,9 +93,6 @@ endif ()
 set(OPENMP_TEST_Fortran_COMPILER "${OPENMP_TEST_Fortran_COMPILER_default}" CACHE STRING
   "Fortran compiler to use for testing OpenMP runtime libraries.")
 
-set(LIBOMP_FORTRAN_MODULES FALSE CACHE BOOL
-  "Create Fortran module files? (requires fortran compiler)")
-
 # Set up testing infrastructure.
 include(OpenMPTesting)
 

>From a682f069da4cce98c37c7d4305f597d2beb4fbb2 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Fri, 20 Mar 2026 01:31:36 +0100
Subject: [PATCH 31/53] Use -cpp

---
 flang/test/Driver/intrinsic-module-path.F90 | 55 ---------------------
 flang/test/Driver/intrinsic-module-path.f90 | 54 +++++++++++++++-----
 2 files changed, 43 insertions(+), 66 deletions(-)
 delete mode 100644 flang/test/Driver/intrinsic-module-path.F90

diff --git a/flang/test/Driver/intrinsic-module-path.F90 b/flang/test/Driver/intrinsic-module-path.F90
deleted file mode 100644
index 3317eb776f0a1..0000000000000
--- a/flang/test/Driver/intrinsic-module-path.F90
+++ /dev/null
@@ -1,55 +0,0 @@
-! 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 -### %s 2>&1 | FileCheck %s --check-prefix=DEFAULTPATH
-
-! RUN:     %flang -fsyntax-only -DINTRINSICS_DEFAULT %s
-! RUN: not %flang -fsyntax-only -DINTRINSICS_INPUTONE %s 2>&1 | FileCheck %s --check-prefix=NOINPUTONE
-! RUN: not %flang -fsyntax-only -DINTRINSICS_INPUTTWO %s 2>&1 | FileCheck %s --check-prefix=NOINPUTTWO
-! RUN:     %flang -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir/ %s
-! RUN:     %flang -fsyntax-only -DINTRINSICS_INPUTONE -fintrinsic-modules-path=%S/Inputs/ %s
-! RUN:     %flang -fsyntax-only -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/ -fintrinsic-modules-path=%S/Inputs/module-dir/ %s
-! RUN: not %flang -fsyntax-only -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir/ -fintrinsic-modules-path=%S/Inputs/ %s 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).
-
-! RUN:     %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT %s
-! RUN: not %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE %s 2>&1 | FileCheck %s --check-prefix=NOINPUTONE
-! RUN: not %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTTWO %s 2>&1 | FileCheck %s --check-prefix=NOINPUTTWO
-! RUN:     %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir %s
-! RUN:     %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE -fintrinsic-modules-path=%S/Inputs/ %s
-! RUN:     %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/ -fintrinsic-modules-path=%S/Inputs/module-dir/ %s
-! RUN: not %flang_fc1 -fsyntax-only -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir -fintrinsic-modules-path=%S/Inputs/ %s 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/intrinsic-module-path.f90 b/flang/test/Driver/intrinsic-module-path.f90
index c8b848f3efa9a..4c21572c5f133 100644
--- a/flang/test/Driver/intrinsic-module-path.f90
+++ b/flang/test/Driver/intrinsic-module-path.f90
@@ -1,23 +1,55 @@
 ! Ensure argument -fintrinsic-modules-path works as expected.
-! WITHOUT the option, the default location for the module is checked and no error generated.
-! With the option GIVEN, the module with the same name is PREPENDED, and considered over the
-! default one, causing an error.
 
 !-----------------------------------------
-! FRONTEND FLANG DRIVER (flang -fc1)
+! FLANG DRIVER
 !-----------------------------------------
-! RUN: %flang_fc1 -fsyntax-only %s  2>&1 | FileCheck %s --allow-empty --check-prefix=WITHOUT
-! RUN: not %flang_fc1 -fsyntax-only -fintrinsic-modules-path %S/Inputs/ %s  2>&1 | FileCheck %s --check-prefix=GIVEN
-! RUN: not %flang_fc1 -fsyntax-only -fintrinsic-modules-path=%S/Inputs/ %s  2>&1 | FileCheck %s --check-prefix=GIVEN
+! 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.
 
-! WITHOUT-NOT: 'ieee_arithmetic.mod' was not found
-! WITHOUT-NOT: 'iso_fortran_env.mod' was not found
+! RUN:     %flang -fsyntax-only -### %s 2>&1 | FileCheck %s --check-prefix=DEFAULTPATH
 
-! GIVEN: error: Cannot read module file for module 'ieee_arithmetic': 'ieee_arithmetic.mod' is not a module file for this compiler
-! GIVEN: error: Cannot read module file for module 'iso_fortran_env': 'iso_fortran_env.mod' is not a module file for this compiler
+! RUN:     %flang -fsyntax-only -cpp -DINTRINSICS_DEFAULT %s
+! RUN: not %flang -fsyntax-only -cpp -DINTRINSICS_INPUTONE %s 2>&1 | FileCheck %s --check-prefix=NOINPUTONE
+! RUN: not %flang -fsyntax-only -cpp -DINTRINSICS_INPUTTWO %s 2>&1 | FileCheck %s --check-prefix=NOINPUTTWO
+! RUN:     %flang -fsyntax-only -cpp -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir/ %s
+! RUN:     %flang -fsyntax-only -cpp -DINTRINSICS_INPUTONE -fintrinsic-modules-path=%S/Inputs/ %s
+! RUN:     %flang -fsyntax-only -cpp -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/ -fintrinsic-modules-path=%S/Inputs/module-dir/ %s
+! RUN: not %flang -fsyntax-only -cpp -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir/ -fintrinsic-modules-path=%S/Inputs/ %s 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).
+
+! RUN:     %flang_fc1 -fsyntax-only -cpp -DINTRINSICS_DEFAULT %s
+! RUN: not %flang_fc1 -fsyntax-only -cpp -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE %s 2>&1 | FileCheck %s --check-prefix=NOINPUTONE
+! RUN: not %flang_fc1 -fsyntax-only -cpp -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTTWO %s 2>&1 | FileCheck %s --check-prefix=NOINPUTTWO
+! RUN:     %flang_fc1 -fsyntax-only -cpp -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir %s
+! RUN:     %flang_fc1 -fsyntax-only -cpp -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE -fintrinsic-modules-path=%S/Inputs/ %s
+! RUN:     %flang_fc1 -fsyntax-only -cpp -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/ -fintrinsic-modules-path=%S/Inputs/module-dir/ %s
+! RUN: not %flang_fc1 -fsyntax-only -cpp -DINTRINSICS_DEFAULT -DINTRINSICS_INPUTONE -DINTRINSICS_INPUTTWO -fintrinsic-modules-path=%S/Inputs/module-dir -fintrinsic-modules-path=%S/Inputs/ %s 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

>From c5a340cfb77d2fe5b1fca52edad5cf2ecc528695 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Fri, 20 Mar 2026 01:46:04 +0100
Subject: [PATCH 32/53] Test fix

---
 flang/test/Parser/bug2280.f90 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang/test/Parser/bug2280.f90 b/flang/test/Parser/bug2280.f90
index d24b26ddeb0d8..2de644e159bda 100644
--- a/flang/test/Parser/bug2280.f90
+++ b/flang/test/Parser/bug2280.f90
@@ -1,4 +1,4 @@
-!RUN: %flang -fc1 -fdebug-unparse %s | FileCheck %s
+!RUN: %flang_fc1 -fdebug-unparse %s | FileCheck %s
 !CHECK: 1 FORMAT(1X)
 1 format(1x)
 !CHECK: 2 FORMAT(1X)

>From 840fa81c691449823422552c4bf65a2d336ac2d1 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Sat, 21 Mar 2026 01:57:36 +0100
Subject: [PATCH 33/53] Post-merge fixes

---
 offload/CMakeLists.txt | 116 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index 0795d3c296aa8..508739f99e419 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -23,6 +23,7 @@ endif()
 set(OFFLOAD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
 # When building in tree we install the runtime according to the LLVM settings.
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(OFFLOAD_INSTALL_LIBDIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE} CACHE STRING
     "Path where built offload libraries should be installed.")
@@ -48,12 +49,127 @@ set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
 # If building in tree, we honor the same install suffix LLVM uses.
 set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
 
+<<<<<<< HEAD
+  # Group common settings.
+  set(OPENMP_ENABLE_WERROR FALSE CACHE BOOL
+    "Enable -Werror flags to turn warnings into errors for supporting compilers.")
+  set(OPENMP_LIBDIR_SUFFIX "" CACHE STRING
+    "Suffix of lib installation directory, e.g. 64 => lib64")
+  # Do not use OPENMP_LIBDIR_SUFFIX directly, use OPENMP_INSTALL_LIBDIR.
+  set(OPENMP_INSTALL_LIBDIR "lib${OPENMP_LIBDIR_SUFFIX}")
+
+  # Used by llvm_add_tool() and tests.
+  set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR})
+
+  # Group test settings.
+  set(OPENMP_TEST_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING
+    "C compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING
+    "C++ compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_TEST_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} CACHE STRING
+    "FORTRAN compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_LLVM_TOOLS_DIR "" CACHE PATH "Path to LLVM tools for testing.")
+
+  set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
+  set(CMAKE_CXX_STANDARD_REQUIRED NO)
+  set(CMAKE_CXX_EXTENSIONS NO)
+else()
+  set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
+  # If building in tree, we honor the same install suffix LLVM uses.
+  # TODO: Use common runtimes infrastructure for output and install paths
+  set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
+
+  if (NOT MSVC)
+    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang)
+    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++)
+  else()
+    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang.exe)
+    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++.exe)
+  endif()
+
+  # Check for flang
+  if (NOT MSVC)
+    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang)
+  else()
+    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang.exe)
+  endif()
+
+  # Set fortran test compiler if flang is found
+  if (EXISTS "${OPENMP_TEST_Fortran_COMPILER}")
+    message("Using local flang build at ${OPENMP_TEST_Fortran_COMPILER}")
+  else()
+    unset(OPENMP_TEST_Fortran_COMPILER)
+  endif()
+
+  # If not standalone, set CMAKE_CXX_STANDARD but don't set the global cache value,
+  # only set it locally for OpenMP.
+  set(CMAKE_CXX_STANDARD 17)
+  set(CMAKE_CXX_STANDARD_REQUIRED NO)
+  set(CMAKE_CXX_EXTENSIONS NO)
+||||||| 23af867e6d93
+  # Group common settings.
+  set(OPENMP_ENABLE_WERROR FALSE CACHE BOOL
+    "Enable -Werror flags to turn warnings into errors for supporting compilers.")
+  set(OPENMP_LIBDIR_SUFFIX "" CACHE STRING
+    "Suffix of lib installation directory, e.g. 64 => lib64")
+  # Do not use OPENMP_LIBDIR_SUFFIX directly, use OPENMP_INSTALL_LIBDIR.
+  set(OPENMP_INSTALL_LIBDIR "lib${OPENMP_LIBDIR_SUFFIX}")
+
+  # Used by llvm_add_tool() and tests.
+  set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR})
+
+  # Group test settings.
+  set(OPENMP_TEST_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING
+    "C compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING
+    "C++ compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_TEST_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} CACHE STRING
+    "FORTRAN compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_LLVM_TOOLS_DIR "" CACHE PATH "Path to LLVM tools for testing.")
+
+  set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
+  set(CMAKE_CXX_STANDARD_REQUIRED NO)
+  set(CMAKE_CXX_EXTENSIONS NO)
+else()
+  set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
+  # If building in tree, we honor the same install suffix LLVM uses.
+  set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
+
+  if (NOT MSVC)
+    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang)
+    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++)
+  else()
+    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang.exe)
+    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++.exe)
+  endif()
+
+  # Check for flang
+  if (NOT MSVC)
+    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang)
+  else()
+    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang.exe)
+  endif()
+
+  # Set fortran test compiler if flang is found
+  if (EXISTS "${OPENMP_TEST_Fortran_COMPILER}")
+    message("Using local flang build at ${OPENMP_TEST_Fortran_COMPILER}")
+  else()
+    unset(OPENMP_TEST_Fortran_COMPILER)
+  endif()
+
+  # If not standalone, set CMAKE_CXX_STANDARD but don't set the global cache value,
+  # only set it locally for OpenMP.
+  set(CMAKE_CXX_STANDARD 17)
+  set(CMAKE_CXX_STANDARD_REQUIRED NO)
+  set(CMAKE_CXX_EXTENSIONS NO)
+=======
 set(OPENMP_TEST_C_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
 set(OPENMP_TEST_CXX_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}")
 set(OPENMP_TEST_Fortran_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/flang${CMAKE_EXECUTABLE_SUFFIX}")
 if (NOT TARGET "clang")
   set(OPENMP_TEST_C_COMPILER_default "${CMAKE_C_COMPILER}")
   set(OPENMP_TEST_CXX_COMPILER_default "${CMAKE_CXX_COMPILER}")
+>>>>>>> main
 endif()
 if (NOT TARGET "flang")
   if (CMAKE_Fortran_COMPILER)

>From c8280ddb02dab6df5897bc965a5fd95f382d31b2 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Sat, 21 Mar 2026 01:58:40 +0100
Subject: [PATCH 34/53] Apply changes from runtimes_resource-dir

---
 cmake/Modules/GetToolchainDirs.cmake          | 85 ++++++++++---------
 .../cmake/Modules/CompilerRTUtils.cmake       | 50 ++---------
 compiler-rt/cmake/base-config-ix.cmake        |  2 +
 libc/CMakeLists.txt                           |  2 +
 libcxx/CMakeLists.txt                         |  1 +
 libcxxabi/CMakeLists.txt                      |  1 +
 libsycl/CMakeLists.txt                        |  1 +
 libunwind/CMakeLists.txt                      |  1 +
 llvm-libgcc/CMakeLists.txt                    |  1 +
 openmp/CMakeLists.txt                         |  1 +
 orc-rt/lib/executor/CMakeLists.txt            |  1 +
 11 files changed, 63 insertions(+), 83 deletions(-)

diff --git a/cmake/Modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
index 21dffb40bf2ac..4cabf95311c5c 100644
--- a/cmake/Modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -1,27 +1,27 @@
-# Determine the subdirectory relative to Clang's resource dir/sysroot where to
-# install target-specific libraries, to be found by Clang/Flang driver. This was
-# adapted from Compiler-RT's mechanism to find the path for
-# libclang_rt.builtins.a.
+# Determine the subdirectory relative to Clang's resource dir/installation
+# prefix where to install target-specific libraries, to be found by the
+# Clang/Flang driver. This was adapted from Compiler-RT's mechanism to find the
+# path for libclang_rt.builtins.a.
 #
 # Compiler-RT has two mechanisms for the path (simplified):
 #
-# * LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=0: lib/${oslibname}/libclang_rt.builtins-${arch}.a
-# * LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=1: lib/${triple}/libclang_rt.builtins.a
+# * LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF: lib/${oslibname}/libclang_rt.builtins-${arch}.a
+# * LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON : lib/${triple}/libclang_rt.builtins.a
 #
 # LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON is the newer scheme, but the old one is
-# currently still used for some platforms such as Windows. Clang looks for which
-# of the files exist before passing the path to the linker. Hence, the
-# directories have to match what Clang is looking for, which is done in
-# ToolChain::getArchSpecificLibPaths(..), ToolChain::getRuntimePath(),
+# currently still used by default for some platforms such as Windows. Clang
+# looks for which of the files exist before passing the path to the linker.
+# Hence, the directories have to match what Clang is looking for, which is done
+# in ToolChain::getArchSpecificLibPaths(..), ToolChain::getRuntimePath(),
 # ToolChain::getCompilerRTPath(), and ToolChain::getCompilerRT(..), not entirely
-# consistent between these functions, Compiler-RT's CMake code, and overrides
-# in different toolchains.
+# consistent between these functions, overrides in different toolchains, and
+# Compiler-RT's CMake code.
 #
-# For Fortran, Flang always assumes the library name libflang_rt.a without
-# architecture suffix. Hence, we always use the second scheme even as if
-# LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON, even if it actually set to OFF. It as
-# added unconditionally to the library search path by
-# ToolChain::getArchSpecificLibPaths(...).
+# For simplicity, we always use the second scheme even as if
+# LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON, even if it actually set to OFF.
+# The driver's lookup does not take the build-time
+# LLVM_ENABLE_PER_TARGET_RUNTIME_DIR setting into account anyway
+# and will always find its files using either scheme.
 function (get_toolchain_library_subdir outvar)
   set(outval "lib")
 
@@ -30,8 +30,8 @@ function (get_toolchain_library_subdir outvar)
     get_toolchain_os_dirname(os_dirname)
     set(outval "${outval}/${os_dirname}")
   else ()
-    get_toolchain_arch_dirname(arch_dirname)
-    set(outval "${outval}/${arch_dirname}")
+    get_toolchain_target_dirname(target_dirname)
+    set(outval "${outval}/${target_dirname}")
   endif ()
 
   set(${outvar} "${outval}" PARENT_SCOPE)
@@ -39,11 +39,11 @@ endfunction ()
 
 
 # Corresponds to Flang's ToolChain::getDefaultIntrinsicModuleDir().
-function (get_toolchain_module_subdir outvar)
+function (get_toolchain_fortran_module_subdir outvar)
   set(outval "finclude/flang")
 
-  get_toolchain_arch_dirname(arch_dirname)
-  set(outval "${outval}/${arch_dirname}")
+  get_toolchain_target_dirname(target_dirname)
+  set(outval "${outval}/${target_dirname}")
 
   set(${outvar} "${outval}" PARENT_SCOPE)
 endfunction ()
@@ -62,22 +62,17 @@ function (get_toolchain_os_dirname outvar)
 endfunction ()
 
 
-# Corresponds to Clang's ToolChain::getRuntimePath(). Adapted from Compiler-RT.
-function (get_toolchain_arch_dirname outvar)
-  string(FIND ${LLVM_TARGET_TRIPLE} "-" dash_index)
-  string(SUBSTRING ${LLVM_TARGET_TRIPLE} ${dash_index} -1 triple_suffix)
-  string(SUBSTRING ${LLVM_TARGET_TRIPLE} 0 ${dash_index} triple_cpu)
-  set(arch "${triple_cpu}")
-  if("${arch}" MATCHES "^i.86$")
-    # Android uses i686, but that's remapped at a later stage.
-    set(arch "i386")
-  endif()
-
-  if(ANDROID AND ${arch} STREQUAL "i386")
+# Internal function extracted from compiler-rt. Use get_toolchain_target_dirname
+# instead for new code.
+function(get_runtimes_target_libdir_common default_target_triple arch variable)
+  string(FIND "${default_target_triple}" "-" dash_index)
+  string(SUBSTRING "${default_target_triple}" "${dash_index}" -1 triple_suffix)
+  string(SUBSTRING "${default_target_triple}" 0 "${dash_index}" triple_cpu)
+  if(ANDROID AND "${arch}" STREQUAL "i386")
     set(target "i686${triple_suffix}")
-  elseif(${arch} STREQUAL "amd64")
+  elseif("${arch}" STREQUAL "amd64")
     set(target "x86_64${triple_suffix}")
-  elseif(${arch} STREQUAL "sparc64")
+  elseif("${arch}" STREQUAL "sparc64")
     set(target "sparcv9${triple_suffix}")
   elseif("${arch}" MATCHES "mips64|mips64el")
     string(REGEX REPLACE "-gnu.*" "-gnuabi64" triple_suffix_gnu "${triple_suffix}")
@@ -91,7 +86,8 @@ function (get_toolchain_arch_dirname outvar)
     string(REGEX REPLACE "mips64" "mips" triple_cpu_mips "${triple_cpu_mips}")
     set(target "${triple_cpu_mips}${triple_suffix_gnu}")
   elseif("${arch}" MATCHES "^arm")
-    # FIXME: Handle arch other than arm, armhf, armv6m
+    # Arch is arm, armhf, armv6m (anything else would come from using
+    # COMPILER_RT_DEFAULT_TARGET_ONLY, which is checked above).
     if (${arch} STREQUAL "armhf")
       # If we are building for hard float but our ABI is soft float.
       if ("${triple_suffix}" MATCHES ".*eabi$")
@@ -115,5 +111,18 @@ function (get_toolchain_arch_dirname outvar)
   else()
     set(target "${arch}${triple_suffix}")
   endif()
-  set(${outvar} "${target}" PARENT_SCOPE)
+  set("${variable}" "${target}" PARENT_SCOPE)
+endfunction()
+
+
+# Corresponds to Clang's ToolChain::getRuntimePath().
+function (get_toolchain_target_dirname outvar)
+  string(FIND "${LLVM_TARGET_TRIPLE}" "-" dash_index)
+  string(SUBSTRING "${LLVM_TARGET_TRIPLE}" 0 "${dash_index}" triple_cpu)
+  set(arch "${triple_cpu}")
+  if("${arch}" MATCHES "^i.86$")
+    set(arch "i386")
+  endif()
+  get_runtimes_target_libdir_common("${LLVM_TARGET_TRIPLE}" "${arch}" target)
+  set("${outvar}" "${target}" PARENT_SCOPE)
 endfunction()
diff --git a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
index cbd18d26c0b93..8c27c4585f73b 100644
--- a/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
+++ b/compiler-rt/cmake/Modules/CompilerRTUtils.cmake
@@ -1,5 +1,6 @@
 include(CMakePushCheckState)
 include(CheckSymbolExists)
+include(GetToolchainDirs)
 
 # Because compiler-rt spends a lot of time setting up custom compile flags,
 # define a handy helper function for it. The compile flags setting in CMake
@@ -460,59 +461,17 @@ function(filter_builtin_sources inout_var name)
 endfunction()
 
 function(get_compiler_rt_target arch variable)
-  string(FIND ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} "-" dash_index)
-  string(SUBSTRING ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} ${dash_index} -1 triple_suffix)
-  string(SUBSTRING ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} 0 ${dash_index} triple_cpu)
   if(COMPILER_RT_DEFAULT_TARGET_ONLY)
     # Use exact spelling when building only for the target specified to CMake.
     set(target "${COMPILER_RT_DEFAULT_TARGET_TRIPLE}")
-  elseif(ANDROID AND ${arch} STREQUAL "i386")
-    set(target "i686${triple_suffix}")
-  elseif(${arch} STREQUAL "amd64")
-    set(target "x86_64${triple_suffix}")
-  elseif(${arch} STREQUAL "sparc64")
-    set(target "sparcv9${triple_suffix}")
-  elseif("${arch}" MATCHES "mips64|mips64el")
-    string(REGEX REPLACE "-gnu.*" "-gnuabi64" triple_suffix_gnu "${triple_suffix}")
-    string(REGEX REPLACE "mipsisa32" "mipsisa64" triple_cpu_mips "${triple_cpu}")
-    string(REGEX REPLACE "^mips$" "mips64" triple_cpu_mips "${triple_cpu_mips}")
-    string(REGEX REPLACE "^mipsel$" "mips64el" triple_cpu_mips "${triple_cpu_mips}")
-    set(target "${triple_cpu_mips}${triple_suffix_gnu}")
-  elseif("${arch}" MATCHES "mips|mipsel")
-    string(REGEX REPLACE "-gnuabi.*" "-gnu" triple_suffix_gnu "${triple_suffix}")
-    string(REGEX REPLACE "mipsisa64" "mipsisa32" triple_cpu_mips "${triple_cpu}")
-    string(REGEX REPLACE "mips64" "mips" triple_cpu_mips "${triple_cpu_mips}")
-    set(target "${triple_cpu_mips}${triple_suffix_gnu}")
-  elseif("${arch}" MATCHES "^arm")
-    # Arch is arm, armhf, armv6m (anything else would come from using
-    # COMPILER_RT_DEFAULT_TARGET_ONLY, which is checked above).
-    if (${arch} STREQUAL "armhf")
-      # If we are building for hard float but our ABI is soft float.
-      if ("${triple_suffix}" MATCHES ".*eabi$")
-        # Change "eabi" -> "eabihf"
-        set(triple_suffix "${triple_suffix}hf")
-      endif()
-      # ABI is already set in the triple, don't repeat it in the architecture.
-      set(arch "arm")
-    else ()
-      # If we are building for soft float, but the triple's ABI is hard float.
-      if ("${triple_suffix}" MATCHES ".*eabihf$")
-        # Change "eabihf" -> "eabi"
-        string(REGEX REPLACE "hf$" "" triple_suffix "${triple_suffix}")
-      endif()
-    endif()
-    set(target "${arch}${triple_suffix}")
-  elseif("${arch}" MATCHES "^amdgcn")
-    set(target "amdgcn-amd-amdhsa")
-  elseif("${arch}" MATCHES "^nvptx")
-    set(target "nvptx64-nvidia-cuda")
   else()
-    set(target "${arch}${triple_suffix}")
+    get_runtimes_target_libdir_common("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" "${arch}" target)
   endif()
-  set(${variable} ${target} PARENT_SCOPE)
+  set(${variable} "${target}" PARENT_SCOPE)
 endfunction()
 
 function(get_compiler_rt_install_dir arch install_dir)
+  # TODO: Use RUNTIMES_INSTALL_RESOURCE_LIB_PATH instead
   if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
     get_compiler_rt_target(${arch} target)
     set(${install_dir} ${COMPILER_RT_INSTALL_LIBRARY_DIR}/${target} PARENT_SCOPE)
@@ -522,6 +481,7 @@ function(get_compiler_rt_install_dir arch install_dir)
 endfunction()
 
 function(get_compiler_rt_output_dir arch output_dir)
+  # TODO: Use RUNTIMES_OUTPUT_RESOURCE_LIB_DIR instead
   if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
     get_compiler_rt_target(${arch} target)
     set(${output_dir} ${COMPILER_RT_OUTPUT_LIBRARY_DIR}/${target} PARENT_SCOPE)
diff --git a/compiler-rt/cmake/base-config-ix.cmake b/compiler-rt/cmake/base-config-ix.cmake
index 6a6e2a88217fc..038cc191983f1 100644
--- a/compiler-rt/cmake/base-config-ix.cmake
+++ b/compiler-rt/cmake/base-config-ix.cmake
@@ -120,6 +120,8 @@ if(NOT DEFINED COMPILER_RT_OS_DIR)
     string(TOLOWER ${CMAKE_SYSTEM_NAME} COMPILER_RT_OS_DIR)
   endif()
 endif()
+
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(COMPILER_RT_OUTPUT_LIBRARY_DIR
     ${COMPILER_RT_OUTPUT_DIR}/lib)
diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt
index 7a5ed88ef054c..6be26a1f6b174 100644
--- a/libc/CMakeLists.txt
+++ b/libc/CMakeLists.txt
@@ -234,6 +234,7 @@ if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
   cmake_path(NORMAL_PATH LIBC_TARGET_SUBDIR)
 endif()
 
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND (LIBC_ENABLE_USE_BY_CLANG OR LIBC_TARGET_OS_IS_GPU))
   set(LIBC_INCLUDE_DIR ${LLVM_BINARY_DIR}/include/${LLVM_DEFAULT_TARGET_TRIPLE})
   set(LIBC_INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR}/${LLVM_DEFAULT_TARGET_TRIPLE})
@@ -260,6 +261,7 @@ else()
   endif()
 endif()
 
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LIBC_TARGET_TRIPLE)
   set(LIBC_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LIBC_TARGET_TRIPLE})
 elseif(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index e1620f91a453c..4b39c2c78a365 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -425,6 +425,7 @@ set(LIBCXX_INSTALL_MODULES_DIR "share/libc++/v1" CACHE STRING
 set(LIBCXX_SHARED_OUTPUT_NAME "c++" CACHE STRING "Output name for the shared libc++ runtime library.")
 set(LIBCXX_STATIC_OUTPUT_NAME "c++" CACHE STRING "Output name for the static libc++ runtime library.")
 
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBCXX_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBCXX_LIBDIR_SUBDIR)
diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt
index 2b67c5972339e..e1a1587fb6283 100644
--- a/libcxxabi/CMakeLists.txt
+++ b/libcxxabi/CMakeLists.txt
@@ -185,6 +185,7 @@ set(CMAKE_MODULE_PATH
 set(LIBCXXABI_INSTALL_RUNTIME_DIR "${CMAKE_INSTALL_BINDIR}" CACHE STRING
     "Path where built libc++abi runtime libraries should be installed.")
 
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBCXXABI_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBCXXABI_LIBDIR_SUBDIR)
diff --git a/libsycl/CMakeLists.txt b/libsycl/CMakeLists.txt
index f75216978f69a..d2b0d79ea8e65 100644
--- a/libsycl/CMakeLists.txt
+++ b/libsycl/CMakeLists.txt
@@ -37,6 +37,7 @@ option(LIBSYCL_ENABLE_PEDANTIC "Compile with pedantic enabled." OFF)
 
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBSYCL_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBSYCL_LIBDIR_SUBDIR)
diff --git a/libunwind/CMakeLists.txt b/libunwind/CMakeLists.txt
index fbef71f3f7446..1681b90b31cdb 100644
--- a/libunwind/CMakeLists.txt
+++ b/libunwind/CMakeLists.txt
@@ -140,6 +140,7 @@ set(LIBUNWIND_INSTALL_RUNTIME_DIR "${CMAKE_INSTALL_BINDIR}" CACHE STRING
 set(LIBUNWIND_SHARED_OUTPUT_NAME "unwind" CACHE STRING "Output name for the shared libunwind runtime library.")
 set(LIBUNWIND_STATIC_OUTPUT_NAME "unwind" CACHE STRING "Output name for the static libunwind runtime library.")
 
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBUNWIND_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBUNWIND_LIBDIR_SUBDIR)
diff --git a/llvm-libgcc/CMakeLists.txt b/llvm-libgcc/CMakeLists.txt
index 47208fc198692..55c052165dbd1 100644
--- a/llvm-libgcc/CMakeLists.txt
+++ b/llvm-libgcc/CMakeLists.txt
@@ -61,6 +61,7 @@ endif()
 # Configure System
 #===============================================================================
 
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LLVM_LIBGCC_LIBDIR_SUBDIR)
diff --git a/openmp/CMakeLists.txt b/openmp/CMakeLists.txt
index 7c0d3b222ddc0..ff5d475f7cf54 100644
--- a/openmp/CMakeLists.txt
+++ b/openmp/CMakeLists.txt
@@ -35,6 +35,7 @@ endif ()
 set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
 
 # When building in tree we install the runtime according to the LLVM settings.
+# TODO: Use common runtimes infrastructure for output and install paths
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(OPENMP_INSTALL_LIBDIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE} CACHE STRING
       "Path where built openmp libraries should be installed.")
diff --git a/orc-rt/lib/executor/CMakeLists.txt b/orc-rt/lib/executor/CMakeLists.txt
index eebf142e5d868..cf0f2a1d39942 100644
--- a/orc-rt/lib/executor/CMakeLists.txt
+++ b/orc-rt/lib/executor/CMakeLists.txt
@@ -21,6 +21,7 @@ target_link_libraries(orc-rt-executor
   )
 
 # Apply RTTI and exceptions compile flags
+# TODO: Use common runtimes infrastructure for output and install paths
 target_compile_options(orc-rt-executor PRIVATE ${ORC_RT_COMPILE_FLAGS})
 install(TARGETS orc-rt-executor
   ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}

>From b2bd3f5293b90a1c493ef257acc05e5bafc2f390 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Sat, 21 Mar 2026 01:59:29 +0100
Subject: [PATCH 35/53] Avoid unnecessary changes

Apply changes from runtimes_resource-dir

Forward-port

cleanup

cleanup

Remove RUNTIMES_DEVICE_ARCHITECTURES
---
 clang/lib/Driver/ToolChains/AMDGPU.cpp   |   3 +-
 clang/lib/Driver/ToolChains/HIPAMD.cpp   |   3 +-
 clang/lib/Driver/ToolChains/HIPSPV.cpp   |   3 +-
 cmake/Modules/GetToolchainDirs.cmake     |  11 +++
 flang/test/Lower/OpenMP/simd_aarch64.f90 |   4 +-
 flang/test/lit.cfg.py                    |   4 +-
 offload/CMakeLists.txt                   | 116 +----------------------
 openmp/runtime/cmake/LibompExports.cmake |   8 +-
 runtimes/CMakeLists.txt                  |  24 -----
 runtimes/cmake/config-Fortran.cmake      |  10 --
 10 files changed, 25 insertions(+), 161 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp
index 5161ccfcbad4c..8eaa3365bb301 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -844,8 +844,7 @@ void AMDGPUToolChain::addClangTargetOptions(
   // Default to "hidden" visibility, as object level linking will not be
   // supported for the foreseeable future.
   if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
-                         options::OPT_fvisibility_ms_compat) &&
-      !getDriver().IsFlangMode()) {
+                         options::OPT_fvisibility_ms_compat)) {
     CC1Args.push_back("-fvisibility=hidden");
     CC1Args.push_back("-fapply-global-visibility-to-externs");
   }
diff --git a/clang/lib/Driver/ToolChains/HIPAMD.cpp b/clang/lib/Driver/ToolChains/HIPAMD.cpp
index c4b03a4799014..b08f610b21a16 100644
--- a/clang/lib/Driver/ToolChains/HIPAMD.cpp
+++ b/clang/lib/Driver/ToolChains/HIPAMD.cpp
@@ -261,8 +261,7 @@ void HIPAMDToolChain::addClangTargetOptions(
   // Default to "hidden" visibility, as object level linking will not be
   // supported for the foreseeable future.
   if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
-                         options::OPT_fvisibility_ms_compat) &&
-      !getDriver().IsFlangMode()) {
+                         options::OPT_fvisibility_ms_compat)) {
     CC1Args.append({"-fvisibility=hidden"});
     CC1Args.push_back("-fapply-global-visibility-to-externs");
   }
diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp
index bacca6ff696f1..8bdb7ab042b2b 100644
--- a/clang/lib/Driver/ToolChains/HIPSPV.cpp
+++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp
@@ -174,8 +174,7 @@ void HIPSPVToolChain::addClangTargetOptions(
   // Default to "hidden" visibility, as object level linking will not be
   // supported for the foreseeable future.
   if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
-                         options::OPT_fvisibility_ms_compat) &&
-      !getDriver().IsFlangMode())
+                         options::OPT_fvisibility_ms_compat))
     CC1Args.append(
         {"-fvisibility=hidden", "-fapply-global-visibility-to-externs"});
 
diff --git a/cmake/Modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
index 4cabf95311c5c..af3e8da730eaa 100644
--- a/cmake/Modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -49,6 +49,17 @@ function (get_toolchain_fortran_module_subdir outvar)
 endfunction ()
 
 
+# Corresponds to Flang's ToolChain::getDefaultIntrinsicModuleDir().
+function (get_toolchain_module_subdir outvar)
+  set(outval "finclude/flang")
+
+  get_toolchain_target_dirname(arch_dirname)
+  set(outval "${outval}/${arch_dirname}")
+
+  set(${outvar} "${outval}" PARENT_SCOPE)
+endfunction ()
+
+
 # Corresponds to Clang's ToolChain::getOSLibName(). Adapted from Compiler-RT.
 function (get_toolchain_os_dirname outvar)
   if (ANDROID)
diff --git a/flang/test/Lower/OpenMP/simd_aarch64.f90 b/flang/test/Lower/OpenMP/simd_aarch64.f90
index 2e4136273c75b..99bd6cb2d815c 100644
--- a/flang/test/Lower/OpenMP/simd_aarch64.f90
+++ b/flang/test/Lower/OpenMP/simd_aarch64.f90
@@ -3,8 +3,8 @@
 ! REQUIRES: aarch64-registered-target
 
 ! Requires aarch64 iso_c_binding.mod which currently is only available if your host is also aarch64
-! FIXME: Make flang a cross-compiler
-! UNSUPPORTED: true
+! FIXME: Make flang a proper cross-compiler
+! REQUIRES: aarch64-host
 
 ! RUN: %flang_fc1 -triple aarch64-unknown-linux-gnu -emit-hlfir -fopenmp %s -o - | FileCheck  %s
 subroutine simdloop_aligned_cptr(A)
diff --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py
index ac75f6341e478..4f790021dccdd 100644
--- a/flang/test/lit.cfg.py
+++ b/flang/test/lit.cfg.py
@@ -140,6 +140,8 @@
 if config.default_sysroot:
     config.available_features.add("default_sysroot")
 
+host_triple = config.host_triple.split("-")
+config.available_features.add(f'{host_triple[0]}-host')
 
 flang_exe = lit.util.which("flang", config.flang_llvm_tools_dir)
 if not flang_exe:
@@ -187,7 +189,7 @@ def get_resource_module_intrinsic_dir(modfile):
     config.available_features.add("openmp_runtime")
 
     # Search path for omp_lib.h with LLVM_ENABLE_RUNTIMES=openmp
-    # FIXME: openmp should write this file into the resource directory
+    # FIXME: In a bootstrpping build, openmp should write this file into a shared directory
     flang_extra_search_args += [
         "-I",
         f"{config.flang_obj_root}/../../runtimes/runtimes-bins/openmp/runtime/src",
diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index 38e05bbdb0987..64cdf39d098c1 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -49,126 +49,12 @@ set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
 # If building in tree, we honor the same install suffix LLVM uses.
 set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
 
-<<<<<<< HEAD
-  # Group common settings.
-  set(OPENMP_ENABLE_WERROR FALSE CACHE BOOL
-    "Enable -Werror flags to turn warnings into errors for supporting compilers.")
-  set(OPENMP_LIBDIR_SUFFIX "" CACHE STRING
-    "Suffix of lib installation directory, e.g. 64 => lib64")
-  # Do not use OPENMP_LIBDIR_SUFFIX directly, use OPENMP_INSTALL_LIBDIR.
-  set(OPENMP_INSTALL_LIBDIR "lib${OPENMP_LIBDIR_SUFFIX}")
-
-  # Used by llvm_add_tool() and tests.
-  set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR})
-
-  # Group test settings.
-  set(OPENMP_TEST_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING
-    "C compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING
-    "C++ compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_TEST_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} CACHE STRING
-    "FORTRAN compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_LLVM_TOOLS_DIR "" CACHE PATH "Path to LLVM tools for testing.")
-
-  set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
-  set(CMAKE_CXX_STANDARD_REQUIRED NO)
-  set(CMAKE_CXX_EXTENSIONS NO)
-else()
-  set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
-  # If building in tree, we honor the same install suffix LLVM uses.
-  set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
-
-  if (NOT MSVC)
-    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang)
-    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++)
-  else()
-    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang.exe)
-    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++.exe)
-  endif()
-
-  # Check for flang
-  if (NOT MSVC)
-    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang)
-  else()
-    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang.exe)
-  endif()
-
-  # Set fortran test compiler if flang is found
-  if (EXISTS "${OPENMP_TEST_Fortran_COMPILER}")
-    message("Using local flang build at ${OPENMP_TEST_Fortran_COMPILER}")
-  else()
-    unset(OPENMP_TEST_Fortran_COMPILER)
-  endif()
-
-  # If not standalone, set CMAKE_CXX_STANDARD but don't set the global cache value,
-  # only set it locally for OpenMP.
-  set(CMAKE_CXX_STANDARD 17)
-  set(CMAKE_CXX_STANDARD_REQUIRED NO)
-  set(CMAKE_CXX_EXTENSIONS NO)
-||||||| 23af867e6d93
-  # Group common settings.
-  set(OPENMP_ENABLE_WERROR FALSE CACHE BOOL
-    "Enable -Werror flags to turn warnings into errors for supporting compilers.")
-  set(OPENMP_LIBDIR_SUFFIX "" CACHE STRING
-    "Suffix of lib installation directory, e.g. 64 => lib64")
-  # Do not use OPENMP_LIBDIR_SUFFIX directly, use OPENMP_INSTALL_LIBDIR.
-  set(OPENMP_INSTALL_LIBDIR "lib${OPENMP_LIBDIR_SUFFIX}")
-
-  # Used by llvm_add_tool() and tests.
-  set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR})
-
-  # Group test settings.
-  set(OPENMP_TEST_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING
-    "C compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING
-    "C++ compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_TEST_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} CACHE STRING
-    "FORTRAN compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_LLVM_TOOLS_DIR "" CACHE PATH "Path to LLVM tools for testing.")
-
-  set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
-  set(CMAKE_CXX_STANDARD_REQUIRED NO)
-  set(CMAKE_CXX_EXTENSIONS NO)
-else()
-  set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
-  # If building in tree, we honor the same install suffix LLVM uses.
-  set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
-
-  if (NOT MSVC)
-    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang)
-    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++)
-  else()
-    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang.exe)
-    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++.exe)
-  endif()
-
-  # Check for flang
-  if (NOT MSVC)
-    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang)
-  else()
-    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang.exe)
-  endif()
-
-  # Set fortran test compiler if flang is found
-  if (EXISTS "${OPENMP_TEST_Fortran_COMPILER}")
-    message("Using local flang build at ${OPENMP_TEST_Fortran_COMPILER}")
-  else()
-    unset(OPENMP_TEST_Fortran_COMPILER)
-  endif()
-
-  # If not standalone, set CMAKE_CXX_STANDARD but don't set the global cache value,
-  # only set it locally for OpenMP.
-  set(CMAKE_CXX_STANDARD 17)
-  set(CMAKE_CXX_STANDARD_REQUIRED NO)
-  set(CMAKE_CXX_EXTENSIONS NO)
-=======
 set(OPENMP_TEST_C_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
 set(OPENMP_TEST_CXX_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}")
 set(OPENMP_TEST_Fortran_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/flang${CMAKE_EXECUTABLE_SUFFIX}")
 if (NOT TARGET "clang")
   set(OPENMP_TEST_C_COMPILER_default "${CMAKE_C_COMPILER}")
   set(OPENMP_TEST_CXX_COMPILER_default "${CMAKE_CXX_COMPILER}")
->>>>>>> main
 endif()
 if (NOT TARGET "flang")
   if (CMAKE_Fortran_COMPILER)
@@ -200,6 +86,7 @@ set(CMAKE_CXX_EXTENSIONS NO)
 
 # Set the path of all resulting libraries to a unified location so that it can
 # be used for testing.
+# TODO: Use common runtimes infrastructure for output and install paths
 set(LIBOMPTARGET_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBOMPTARGET_LIBRARY_DIR})
 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBOMPTARGET_LIBRARY_DIR})
@@ -398,6 +285,7 @@ if(LIBOMP_OMP_TOOLS_INCLUDE_DIR)
   include_directories(${LIBOMP_OMP_TOOLS_INCLUDE_DIR})
 endif()
 
+# TODO: Use RUNTIMES_OUTPUT_RESOURCE_LIB_DIR instead
 set(LIBOMPTARGET_LLVM_LIBRARY_DIR "${LLVM_LIBRARY_DIR}" CACHE STRING
   "Path to folder containing llvm library libomptarget.so")
 set(LIBOMPTARGET_LLVM_LIBRARY_INTDIR "${LIBOMPTARGET_INTDIR}" CACHE STRING
diff --git a/openmp/runtime/cmake/LibompExports.cmake b/openmp/runtime/cmake/LibompExports.cmake
index 4822d3bed2516..8944899df2631 100644
--- a/openmp/runtime/cmake/LibompExports.cmake
+++ b/openmp/runtime/cmake/LibompExports.cmake
@@ -56,8 +56,8 @@ set(LIBOMP_EXPORTS_LIB_DIR "${LIBOMP_EXPORTS_DIR}/${libomp_platform}${libomp_suf
 # Put headers in exports/ directory post build
 add_custom_command(TARGET omp POST_BUILD
   COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBOMP_EXPORTS_CMN_DIR}
-  COMMAND ${CMAKE_COMMAND} -E copy ${LIBOMP_HEADERS_INTDIR}/omp.h ${LIBOMP_EXPORTS_CMN_DIR}
-  COMMAND ${CMAKE_COMMAND} -E copy ${LIBOMP_HEADERS_INTDIR}/ompx.h ${LIBOMP_EXPORTS_CMN_DIR}
+  COMMAND ${CMAKE_COMMAND} -E copy "${LIBOMP_HEADERS_INTDIR}/omp.h" ${LIBOMP_EXPORTS_CMN_DIR}
+  COMMAND ${CMAKE_COMMAND} -E copy "${LIBOMP_HEADERS_INTDIR}/ompx.h" ${LIBOMP_EXPORTS_CMN_DIR}
 )
 if(LIBOMP_OMPT_SUPPORT)
   add_custom_command(TARGET omp POST_BUILD
@@ -69,8 +69,8 @@ if(RUNTIMES_FLANG_MODULES_ENABLED)
   # to omp and ensure that libomp-mod is built before by adding a dependency
   add_custom_command(TARGET omp POST_BUILD
     COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBOMP_EXPORTS_MOD_DIR}
-    COMMAND ${CMAKE_COMMAND} -E copy ${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}/omp_lib.mod ${LIBOMP_EXPORTS_MOD_DIR}
-    COMMAND ${CMAKE_COMMAND} -E copy ${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}/omp_lib_kinds.mod ${LIBOMP_EXPORTS_MOD_DIR}
+    COMMAND ${CMAKE_COMMAND} -E copy "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}/omp_lib.mod" ${LIBOMP_EXPORTS_MOD_DIR}
+    COMMAND ${CMAKE_COMMAND} -E copy "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}/omp_lib_kinds.mod" ${LIBOMP_EXPORTS_MOD_DIR}
   )
   add_dependencies(omp libomp-mod)
   add_custom_command(TARGET omp POST_BUILD
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index f31b256a74f0f..08155dca0a6c7 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -277,30 +277,6 @@ cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
 # hence must be included their those variables are defined.
 include(config-Fortran)
 
-
-# For subprojects supporting offloading targets (offload, flang-rt, ..) specify
-# which architectures should be included in the fat binaries.
-set(RUNTIMES_DEVICE_ARCHITECTURES "all" CACHE STRING
-    "List of offload device architectures to be used to compile the offload code (e.g. 'gfx1103;sm_90')"
-  )
-if (RUNTIMES_DEVICE_ARCHITECTURES STREQUAL "all")
-  # TODO: support auto detection on the build system.
-  set(all_amdgpu_architectures
-    "gfx700;gfx701;gfx801;gfx803;gfx900;gfx902;gfx906"
-    "gfx908;gfx90a;gfx90c;gfx940;gfx1010;gfx1030"
-    "gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036"
-    "gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151"
-    "gfx1152;gfx1153")
-  set(all_nvptx_architectures
-    "sm_35;sm_37;sm_50;sm_52;sm_53;sm_60;sm_61;sm_62"
-    "sm_70;sm_72;sm_75;sm_80;sm_86;sm_89;sm_90")
-  set(all_gpu_architectures
-    "${all_amdgpu_architectures};${all_nvptx_architectures}")
-  set(RUNTIMES_DEVICE_ARCHITECTURES ${all_gpu_architectures})
-endif()
-list(REMOVE_DUPLICATES RUNTIMES_DEVICE_ARCHITECTURES)
-
-
 option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
 option(LLVM_INCLUDE_DOCS "Generate build targets for the runtimes documentation." ON)
 option(LLVM_ENABLE_SPHINX "Use Sphinx to generate the runtimes documentation." OFF)
diff --git a/runtimes/cmake/config-Fortran.cmake b/runtimes/cmake/config-Fortran.cmake
index a36003655d25a..4acc26c404174 100644
--- a/runtimes/cmake/config-Fortran.cmake
+++ b/runtimes/cmake/config-Fortran.cmake
@@ -207,16 +207,6 @@ function (flang_module_target tgtname)
       "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-Xflang;SHELL:-fno-reformat>"
     )
 
-  # `flang --target=nvptx64` fails when not specifying `-march`, even when only
-  # emitting .mod files. Ensure that we pass `-march`.
-  if (LLVM_RUNTIMES_TARGET MATCHES "^nvptx")
-    foreach (_arch IN LISTS RUNTIMES_DEVICE_ARCHITECTURES)
-      target_compile_options(${tgtname} PRIVATE
-        "$<$<COMPILE_LANGUAGE:Fortran>:-march=${_arch}>"
-      )
-    endforeach()
-  endif ()
-
   if (ARG_PUBLIC)
     set_target_properties(${tgtname}
       PROPERTIES

>From 33b7fb189abea80844c8ef0445b85e8fb2c8a719 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 26 Mar 2026 13:40:37 +0100
Subject: [PATCH 36/53] Cleanup

gfortran compatibility
---
 flang-rt/cmake/modules/AddFlangRT.cmake       | 27 +++++++++++--------
 .../cmake/modules/FlangRTIntrospection.cmake  |  8 ------
 flang-rt/lib/runtime/CMakeLists.txt           | 18 +++++++------
 flang-rt/lib/runtime/__fortran_builtins.f90   |  2 +-
 flang/test/lit.cfg.py                         |  2 +-
 openmp/module/CMakeLists.txt                  |  4 +--
 runtimes/cmake/config-Fortran.cmake           |  9 ++++---
 7 files changed, 35 insertions(+), 35 deletions(-)

diff --git a/flang-rt/cmake/modules/AddFlangRT.cmake b/flang-rt/cmake/modules/AddFlangRT.cmake
index 8985a1f7bb18c..7b0ac920b2d29 100644
--- a/flang-rt/cmake/modules/AddFlangRT.cmake
+++ b/flang-rt/cmake/modules/AddFlangRT.cmake
@@ -204,11 +204,14 @@ function (add_flangrt_library name)
     endif ()
   endif ()
 
-  if (build_object)
-    add_library(${name}.compile ALIAS "${name_object}")
-  else ()
-    add_library(${name}.compile ALIAS "${default_target}")
-  endif ()
+  # An alias for the target that compiles the sources. When building a shared
+  # and static library at the same time, the sources are compiled in an object
+  # library, so there can be only one.
+  # Can be used to introspect and change the real target's properties, like:
+  #
+  # get_target_property(compile_target ${name}.compile ALIASED_TARGET)
+  # target_sources(${compile_target} more_sources.c)
+  add_library(${name}.compile ALIAS "${srctargets}")
 
   foreach (tgtname IN LISTS libtargets)
     if (NOT WIN32)
@@ -239,13 +242,15 @@ function (add_flangrt_library name)
     # Minimum required C++ version for Flang-RT, even if CMAKE_CXX_STANDARD is defined to something else.
     target_compile_features(${tgtname} PRIVATE cxx_std_17)
 
-    target_compile_options(${tgtname} PRIVATE
-      # Always enable preprocessor regardless of file extension
-      "$<$<COMPILE_LANGUAGE:Fortran>:-cpp>"
+    if (CMAKE_Fortran_COMPILER_ID MATCHES "LLVM")
+      target_compile_options(${tgtname} PRIVATE
+        # Always enable preprocessor regardless of file extension
+        "$<$<COMPILE_LANGUAGE:Fortran>:-cpp>"
 
-      # Missing type descriptors are expected for intrinsic modules
-      "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-mmlir;SHELL:-ignore-missing-type-desc>"
-    )
+        # Missing type descriptors are expected for intrinsic modules
+        "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-mmlir;SHELL:-ignore-missing-type-desc>"
+      )
+    endif ()
 
     # When building the flang runtime if LTO is enabled the archive file
     # contains LLVM IR rather than object code. Currently flang is not
diff --git a/flang-rt/cmake/modules/FlangRTIntrospection.cmake b/flang-rt/cmake/modules/FlangRTIntrospection.cmake
index 10830ff1ac57e..6b48dd33806fa 100644
--- a/flang-rt/cmake/modules/FlangRTIntrospection.cmake
+++ b/flang-rt/cmake/modules/FlangRTIntrospection.cmake
@@ -1,11 +1,3 @@
-#===-- cmake/modules/FlangRTIntrospection.cmake ----------------------------===#
-#
-# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#
-#===------------------------------------------------------------------------===#
-
 include(CMakePushCheckState)
 
 # Check whether the Fortran compiler supports real(16)/quadmath types
diff --git a/flang-rt/lib/runtime/CMakeLists.txt b/flang-rt/lib/runtime/CMakeLists.txt
index ebd3d8e75eefe..c0385a83a28c4 100644
--- a/flang-rt/lib/runtime/CMakeLists.txt
+++ b/flang-rt/lib/runtime/CMakeLists.txt
@@ -241,9 +241,7 @@ endif ()
 
 
 # check-flang depends on flang-rt-mod to build intrinsic modules
-if (NOT TARGET flang-rt-mod)
-  add_custom_target(flang-rt-mod)
-endif ()
+add_custom_target(flang-rt-mod)
 
 if (NOT WIN32)
   # CMake ignores intrinsic USE dependencies
@@ -261,9 +259,7 @@ if (NOT WIN32)
   # Without it, CMake/Ninja seem to think that the modules of
   # flang_rt.intrinsics.obj can be built concurrently to those in
   # flang_rt.runtime.
-  add_custom_target(flang_rt.intrinsics
-    COMMENT "Intrinsic module dependency barrier"
-  )
+  add_custom_target(flang_rt.intrinsics)
   add_dependencies(flang_rt.intrinsics flang_rt.intrinsics.obj)
 
   add_flangrt_library(flang_rt.runtime STATIC SHARED
@@ -276,10 +272,17 @@ if (NOT WIN32)
   enable_cuda_compilation(flang_rt.runtime "${supported_sources}")
 
   # Select a default runtime, which is used for unit and regression tests.
-  if (TARGET flang_rt.runtime.default)
+  if (FLANG_RT_INCLUDE_TESTS)
     get_target_property(default_target flang_rt.runtime.default ALIASED_TARGET)
     add_library(flang_rt.runtime.unittest ALIAS "${default_target}")
   endif ()
+
+  # Select a target that compiles the sources to build the public module files.
+  get_target_property(compile_target flang_rt.runtime.compile ALIASED_TARGET)
+  flang_module_target(flang_rt.intrinsics.obj PUBLIC)
+  flang_module_target(${compile_target} PUBLIC)
+  add_dependencies(${compile_target} flang_rt.intrinsics)
+  add_dependencies(flang-rt-mod flang_rt.intrinsics ${compile_target})
 else()
   # Target for building all versions of the runtime
   add_custom_target(flang_rt.runtime)
@@ -293,7 +296,6 @@ else()
     )
     add_custom_target(${name}.intrinsics
       COMMAND echo "${name} Dependency barrier"
-      COMMENT "Intrinsic module dependency barrier"
     )
     add_dependencies(${name}.intrinsics ${name}.intrinsics.obj)
 
diff --git a/flang-rt/lib/runtime/__fortran_builtins.f90 b/flang-rt/lib/runtime/__fortran_builtins.f90
index d45efc60369fb..efb9438d104dc 100644
--- a/flang-rt/lib/runtime/__fortran_builtins.f90
+++ b/flang-rt/lib/runtime/__fortran_builtins.f90
@@ -6,7 +6,7 @@
 !
 !===------------------------------------------------------------------------===!
 
-#include '../../../flang/include/flang/Runtime/magic-numbers.h'
+#include "../../../flang/include/flang/Runtime/magic-numbers.h"
 
 ! These naming shenanigans prevent names from Fortran intrinsic modules
 ! from being usable on INTRINSIC statements, and force the program
diff --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py
index 4f790021dccdd..6f592d11e90f3 100644
--- a/flang/test/lit.cfg.py
+++ b/flang/test/lit.cfg.py
@@ -141,7 +141,7 @@
     config.available_features.add("default_sysroot")
 
 host_triple = config.host_triple.split("-")
-config.available_features.add(f'{host_triple[0]}-host')
+config.available_features.add(f"{host_triple[0]}-host")
 
 flang_exe = lit.util.which("flang", config.flang_llvm_tools_dir)
 if not flang_exe:
diff --git a/openmp/module/CMakeLists.txt b/openmp/module/CMakeLists.txt
index 5a54546fcd285..91a452dcc98c3 100644
--- a/openmp/module/CMakeLists.txt
+++ b/openmp/module/CMakeLists.txt
@@ -7,13 +7,11 @@
 #//===----------------------------------------------------------------------===//
 
 # Build the module files if a Fortran compiler is available.
-# Only LLVM_ENABLE_RUNTIMES=openmp is supported, LLVM_ENABLE_PROJECTS=openmp
-# has been deprecated.
 
 configure_file(omp_lib.F90.var "{CMAKE_CURRENT_BINARY_DIR}/omp_lib.F90" @ONLY)
 configure_file(omp_lib.h.var "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.h" @ONLY)
 
-# One compilation step creates both omp_lib.mod and omp_lib_kinds.mod. Only
+# One compilation step creates both, omp_lib.mod and omp_lib_kinds.mod. Only
 # these files are used, the object file itself can be discarded.
 # FIXME: Adding it to libomp.so would allow implementing Fortran API in Fortran
 add_library(libomp-mod OBJECT
diff --git a/runtimes/cmake/config-Fortran.cmake b/runtimes/cmake/config-Fortran.cmake
index 4acc26c404174..5b566321fe75a 100644
--- a/runtimes/cmake/config-Fortran.cmake
+++ b/runtimes/cmake/config-Fortran.cmake
@@ -199,13 +199,16 @@ function (flang_module_target tgtname)
   endif ()
 
   target_compile_options(${tgtname} PRIVATE
-      # Let non-public modules find the public module files
-      "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
-
+    # Let non-public modules find the public module files
+    "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
+  )
+  if (CMAKE_Fortran_COMPILER_ID MATCHES "LLVM")
+    target_compile_options(${tgtname} PRIVATE
       # Flang bug workaround: Reformating of cooked token buffer causes
       # identifier to be split between lines
       "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-Xflang;SHELL:-fno-reformat>"
     )
+  endif ()
 
   if (ARG_PUBLIC)
     set_target_properties(${tgtname}

>From a6d6fd770db8f3cf5baedbaacc9785d868cc922a Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Sat, 28 Mar 2026 03:28:58 +0100
Subject: [PATCH 37/53] Post-merge fixes

---
 flang-rt/lib/runtime/CMakeLists.txt | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/flang-rt/lib/runtime/CMakeLists.txt b/flang-rt/lib/runtime/CMakeLists.txt
index 71f54277532d1..80fccabaf563f 100644
--- a/flang-rt/lib/runtime/CMakeLists.txt
+++ b/flang-rt/lib/runtime/CMakeLists.txt
@@ -231,10 +231,11 @@ if (TARGET FortranFloat128MathILib)
   endif ()
 endif ()
 
-if ("${LLVM_DEFAULT_TARGET_TRIPLE}" MATCHES "^amdgcn|^nvptx")
-  set(sources ${gpu_sources})
-elseif(FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT STREQUAL "CUDA")
-  set(sources ${supported_sources})
+if (NOT FLANG_RT_ENABLE_STATIC AND NOT FLANG_RT_ENABLE_SHARED)
+  # If not compiling the library, only build the modules.
+  set(sources ${module_sources})
+elseif ("${LLVM_DEFAULT_TARGET_TRIPLE}" MATCHES "^amdgcn|^nvptx")
+  set(sources ${gpu_sources} ${module_sources})
 else ()
   set(sources ${supported_sources} ${host_sources} ${module_sources} ${f128_sources})
 endif ()

>From cf88eb4fd4f341cc81159ea61b63c4cc2fb293b4 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Wed, 1 Apr 2026 14:46:40 +0200
Subject: [PATCH 38/53] Avoid change noise

---
 offload/CMakeLists.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index d5429ede81c3d..60e5832bbf282 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -81,6 +81,7 @@ set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
 else()
   set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
   # If building in tree, we honor the same install suffix LLVM uses.
+  # TODO: Use common runtimes infrastructure for output and install paths
   set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
 
   if (NOT MSVC)
@@ -403,6 +404,7 @@ if(LIBOMP_OMP_TOOLS_INCLUDE_DIR)
   include_directories(${LIBOMP_OMP_TOOLS_INCLUDE_DIR})
 endif()
 
+# TODO: Use RUNTIMES_OUTPUT_RESOURCE_LIB_DIR instead
 set(LIBOMPTARGET_LLVM_LIBRARY_DIR "${LLVM_LIBRARY_DIR}" CACHE STRING
   "Path to folder containing llvm library libomptarget.so")
 set(LIBOMPTARGET_LLVM_LIBRARY_INTDIR "${LIBOMPTARGET_INTDIR}" CACHE STRING

>From 15c8e0ff82a79a92fac56f4f64ddfe735af1e65d Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Wed, 1 Apr 2026 14:55:49 +0200
Subject: [PATCH 39/53] More change noise avoidance

---
 runtimes/CMakeLists.txt | 23 -----------------------
 1 file changed, 23 deletions(-)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 2bafe5247ec32..86573451ccd97 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -278,29 +278,6 @@ cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
 include(config-Fortran)
 
 
-# For subprojects supporting offloading targets (offload, flang-rt, ..) specify
-# which architectures should be included in the fat binaries.
-set(RUNTIMES_DEVICE_ARCHITECTURES "all" CACHE STRING
-    "List of offload device architectures to be used to compile the offload code (e.g. 'gfx1103;sm_90')"
-  )
-if (RUNTIMES_DEVICE_ARCHITECTURES STREQUAL "all")
-  # TODO: support auto detection on the build system.
-  set(all_amdgpu_architectures
-    "gfx700;gfx701;gfx801;gfx803;gfx900;gfx902;gfx906"
-    "gfx908;gfx90a;gfx90c;gfx940;gfx1010;gfx1030"
-    "gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036"
-    "gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151"
-    "gfx1152;gfx1153")
-  set(all_nvptx_architectures
-    "sm_35;sm_37;sm_50;sm_52;sm_53;sm_60;sm_61;sm_62"
-    "sm_70;sm_72;sm_75;sm_80;sm_86;sm_89;sm_90")
-  set(all_gpu_architectures
-    "${all_amdgpu_architectures};${all_nvptx_architectures}")
-  set(RUNTIMES_DEVICE_ARCHITECTURES ${all_gpu_architectures})
-endif()
-list(REMOVE_DUPLICATES RUNTIMES_DEVICE_ARCHITECTURES)
-
-
 option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
 option(LLVM_INCLUDE_DOCS "Generate build targets for the runtimes documentation." ON)
 option(LLVM_ENABLE_SPHINX "Use Sphinx to generate the runtimes documentation." OFF)

>From 100c020e455aaba88b24693d215b6f62d82c6ace Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Wed, 1 Apr 2026 21:47:45 +0200
Subject: [PATCH 40/53] Post-merge fixes

---
 offload/CMakeLists.txt | 114 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index 01c17b3dacc81..6dedcbdf37842 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -50,6 +50,120 @@ list(INSERT CMAKE_MODULE_PATH 0
   "${LLVM_COMMON_CMAKE_UTILS}/Modules"
   )
 
+<<<<<<< HEAD
+  # Group common settings.
+  set(OPENMP_ENABLE_WERROR FALSE CACHE BOOL
+    "Enable -Werror flags to turn warnings into errors for supporting compilers.")
+  set(OPENMP_LIBDIR_SUFFIX "" CACHE STRING
+    "Suffix of lib installation directory, e.g. 64 => lib64")
+  # Do not use OPENMP_LIBDIR_SUFFIX directly, use OPENMP_INSTALL_LIBDIR.
+  set(OPENMP_INSTALL_LIBDIR "lib${OPENMP_LIBDIR_SUFFIX}")
+
+  # Used by llvm_add_tool() and tests.
+  set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR})
+
+  # Group test settings.
+  set(OPENMP_TEST_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING
+    "C compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING
+    "C++ compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_TEST_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} CACHE STRING
+    "FORTRAN compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_LLVM_TOOLS_DIR "" CACHE PATH "Path to LLVM tools for testing.")
+
+  set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
+  set(CMAKE_CXX_STANDARD_REQUIRED NO)
+  set(CMAKE_CXX_EXTENSIONS NO)
+else()
+  set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
+  # If building in tree, we honor the same install suffix LLVM uses.
+  # TODO: Use common runtimes infrastructure for output and install paths
+  set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
+
+  if (NOT MSVC)
+    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang)
+    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++)
+  else()
+    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang.exe)
+    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++.exe)
+  endif()
+
+  # Check for flang
+  if (NOT MSVC)
+    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang)
+  else()
+    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang.exe)
+  endif()
+
+  # Set fortran test compiler if flang is found
+  if (EXISTS "${OPENMP_TEST_Fortran_COMPILER}")
+    message("Using local flang build at ${OPENMP_TEST_Fortran_COMPILER}")
+  else()
+    unset(OPENMP_TEST_Fortran_COMPILER)
+  endif()
+
+  # If not standalone, set CMAKE_CXX_STANDARD but don't set the global cache value,
+  # only set it locally for OpenMP.
+  set(CMAKE_CXX_STANDARD 17)
+  set(CMAKE_CXX_STANDARD_REQUIRED NO)
+  set(CMAKE_CXX_EXTENSIONS NO)
+||||||| 23af867e6d93
+  # Group common settings.
+  set(OPENMP_ENABLE_WERROR FALSE CACHE BOOL
+    "Enable -Werror flags to turn warnings into errors for supporting compilers.")
+  set(OPENMP_LIBDIR_SUFFIX "" CACHE STRING
+    "Suffix of lib installation directory, e.g. 64 => lib64")
+  # Do not use OPENMP_LIBDIR_SUFFIX directly, use OPENMP_INSTALL_LIBDIR.
+  set(OPENMP_INSTALL_LIBDIR "lib${OPENMP_LIBDIR_SUFFIX}")
+
+  # Used by llvm_add_tool() and tests.
+  set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR})
+
+  # Group test settings.
+  set(OPENMP_TEST_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING
+    "C compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING
+    "C++ compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_TEST_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} CACHE STRING
+    "FORTRAN compiler to use for testing OpenMP runtime libraries.")
+  set(OPENMP_LLVM_TOOLS_DIR "" CACHE PATH "Path to LLVM tools for testing.")
+
+  set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
+  set(CMAKE_CXX_STANDARD_REQUIRED NO)
+  set(CMAKE_CXX_EXTENSIONS NO)
+else()
+  set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
+  # If building in tree, we honor the same install suffix LLVM uses.
+  set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
+
+  if (NOT MSVC)
+    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang)
+    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++)
+  else()
+    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang.exe)
+    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++.exe)
+  endif()
+
+  # Check for flang
+  if (NOT MSVC)
+    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang)
+  else()
+    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang.exe)
+  endif()
+
+  # Set fortran test compiler if flang is found
+  if (EXISTS "${OPENMP_TEST_Fortran_COMPILER}")
+    message("Using local flang build at ${OPENMP_TEST_Fortran_COMPILER}")
+  else()
+    unset(OPENMP_TEST_Fortran_COMPILER)
+  endif()
+
+  # If not standalone, set CMAKE_CXX_STANDARD but don't set the global cache value,
+  # only set it locally for OpenMP.
+  set(CMAKE_CXX_STANDARD 17)
+  set(CMAKE_CXX_STANDARD_REQUIRED NO)
+  set(CMAKE_CXX_EXTENSIONS NO)
+=======
 set(OPENMP_TEST_C_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
 set(OPENMP_TEST_CXX_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}")
 set(OPENMP_TEST_Fortran_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/flang${CMAKE_EXECUTABLE_SUFFIX}")

>From 2141991c5180f88aff515434a1aaf838f4a59ea6 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Wed, 1 Apr 2026 21:50:08 +0200
Subject: [PATCH 41/53] Post-merge fixes

---
 runtimes/CMakeLists.txt | 1 -
 1 file changed, 1 deletion(-)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 86573451ccd97..09762acb0ba8e 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -277,7 +277,6 @@ cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
 # hence must be included their those variables are defined.
 include(config-Fortran)
 
-
 option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
 option(LLVM_INCLUDE_DOCS "Generate build targets for the runtimes documentation." ON)
 option(LLVM_ENABLE_SPHINX "Use Sphinx to generate the runtimes documentation." OFF)

>From 1e19b4364dd3f827e4110b0bc14ec31bf5bbaf59 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Wed, 1 Apr 2026 22:53:56 +0200
Subject: [PATCH 42/53] Fix incomplete merge

---
 offload/CMakeLists.txt | 115 -----------------------------------------
 1 file changed, 115 deletions(-)

diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index 6dedcbdf37842..0069b7186d6a5 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -50,127 +50,12 @@ list(INSERT CMAKE_MODULE_PATH 0
   "${LLVM_COMMON_CMAKE_UTILS}/Modules"
   )
 
-<<<<<<< HEAD
-  # Group common settings.
-  set(OPENMP_ENABLE_WERROR FALSE CACHE BOOL
-    "Enable -Werror flags to turn warnings into errors for supporting compilers.")
-  set(OPENMP_LIBDIR_SUFFIX "" CACHE STRING
-    "Suffix of lib installation directory, e.g. 64 => lib64")
-  # Do not use OPENMP_LIBDIR_SUFFIX directly, use OPENMP_INSTALL_LIBDIR.
-  set(OPENMP_INSTALL_LIBDIR "lib${OPENMP_LIBDIR_SUFFIX}")
-
-  # Used by llvm_add_tool() and tests.
-  set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR})
-
-  # Group test settings.
-  set(OPENMP_TEST_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING
-    "C compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING
-    "C++ compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_TEST_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} CACHE STRING
-    "FORTRAN compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_LLVM_TOOLS_DIR "" CACHE PATH "Path to LLVM tools for testing.")
-
-  set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
-  set(CMAKE_CXX_STANDARD_REQUIRED NO)
-  set(CMAKE_CXX_EXTENSIONS NO)
-else()
-  set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
-  # If building in tree, we honor the same install suffix LLVM uses.
-  # TODO: Use common runtimes infrastructure for output and install paths
-  set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
-
-  if (NOT MSVC)
-    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang)
-    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++)
-  else()
-    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang.exe)
-    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++.exe)
-  endif()
-
-  # Check for flang
-  if (NOT MSVC)
-    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang)
-  else()
-    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang.exe)
-  endif()
-
-  # Set fortran test compiler if flang is found
-  if (EXISTS "${OPENMP_TEST_Fortran_COMPILER}")
-    message("Using local flang build at ${OPENMP_TEST_Fortran_COMPILER}")
-  else()
-    unset(OPENMP_TEST_Fortran_COMPILER)
-  endif()
-
-  # If not standalone, set CMAKE_CXX_STANDARD but don't set the global cache value,
-  # only set it locally for OpenMP.
-  set(CMAKE_CXX_STANDARD 17)
-  set(CMAKE_CXX_STANDARD_REQUIRED NO)
-  set(CMAKE_CXX_EXTENSIONS NO)
-||||||| 23af867e6d93
-  # Group common settings.
-  set(OPENMP_ENABLE_WERROR FALSE CACHE BOOL
-    "Enable -Werror flags to turn warnings into errors for supporting compilers.")
-  set(OPENMP_LIBDIR_SUFFIX "" CACHE STRING
-    "Suffix of lib installation directory, e.g. 64 => lib64")
-  # Do not use OPENMP_LIBDIR_SUFFIX directly, use OPENMP_INSTALL_LIBDIR.
-  set(OPENMP_INSTALL_LIBDIR "lib${OPENMP_LIBDIR_SUFFIX}")
-
-  # Used by llvm_add_tool() and tests.
-  set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR})
-
-  # Group test settings.
-  set(OPENMP_TEST_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING
-    "C compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING
-    "C++ compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_TEST_Fortran_COMPILER ${CMAKE_Fortran_COMPILER} CACHE STRING
-    "FORTRAN compiler to use for testing OpenMP runtime libraries.")
-  set(OPENMP_LLVM_TOOLS_DIR "" CACHE PATH "Path to LLVM tools for testing.")
-
-  set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
-  set(CMAKE_CXX_STANDARD_REQUIRED NO)
-  set(CMAKE_CXX_EXTENSIONS NO)
-else()
-  set(OPENMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
-  # If building in tree, we honor the same install suffix LLVM uses.
-  set(OPENMP_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
-
-  if (NOT MSVC)
-    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang)
-    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++)
-  else()
-    set(OPENMP_TEST_C_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang.exe)
-    set(OPENMP_TEST_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang++.exe)
-  endif()
-
-  # Check for flang
-  if (NOT MSVC)
-    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang)
-  else()
-    set(OPENMP_TEST_Fortran_COMPILER ${LLVM_TOOLS_BINARY_DIR}/flang.exe)
-  endif()
-
-  # Set fortran test compiler if flang is found
-  if (EXISTS "${OPENMP_TEST_Fortran_COMPILER}")
-    message("Using local flang build at ${OPENMP_TEST_Fortran_COMPILER}")
-  else()
-    unset(OPENMP_TEST_Fortran_COMPILER)
-  endif()
-
-  # If not standalone, set CMAKE_CXX_STANDARD but don't set the global cache value,
-  # only set it locally for OpenMP.
-  set(CMAKE_CXX_STANDARD 17)
-  set(CMAKE_CXX_STANDARD_REQUIRED NO)
-  set(CMAKE_CXX_EXTENSIONS NO)
-=======
 set(OPENMP_TEST_C_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
 set(OPENMP_TEST_CXX_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}")
 set(OPENMP_TEST_Fortran_COMPILER_default "${LLVM_TOOLS_BINARY_DIR}/flang${CMAKE_EXECUTABLE_SUFFIX}")
 if (NOT TARGET "clang")
   set(OPENMP_TEST_C_COMPILER_default "${CMAKE_C_COMPILER}")
   set(OPENMP_TEST_CXX_COMPILER_default "${CMAKE_CXX_COMPILER}")
->>>>>>> main
 endif()
 if (NOT TARGET "flang")
   if (CMAKE_Fortran_COMPILER)

>From 4214705219b0632304ab25b1b1cf9d6ebff6a589 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 2 Apr 2026 12:08:31 +0200
Subject: [PATCH 43/53] Backport TODO comment

---
 offload/CMakeLists.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/offload/CMakeLists.txt b/offload/CMakeLists.txt
index 0069b7186d6a5..e319bb036b4b8 100644
--- a/offload/CMakeLists.txt
+++ b/offload/CMakeLists.txt
@@ -87,6 +87,7 @@ set(CMAKE_CXX_EXTENSIONS NO)
 
 # Set the path of all resulting libraries to a unified location so that it can
 # be used for testing.
+# TODO: Use common runtimes infrastructure for output and install paths
 set(LIBOMPTARGET_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBOMPTARGET_LIBRARY_DIR})
 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBOMPTARGET_LIBRARY_DIR})

>From 7c4e03a06bcfd80c6946217032a7509d797ee9ea Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 2 Apr 2026 12:09:10 +0200
Subject: [PATCH 44/53] Reduce change noise accross stacked PRs

Backport TODO comment
---
 runtimes/cmake/config-Fortran.cmake | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/runtimes/cmake/config-Fortran.cmake b/runtimes/cmake/config-Fortran.cmake
index a36003655d25a..5b566321fe75a 100644
--- a/runtimes/cmake/config-Fortran.cmake
+++ b/runtimes/cmake/config-Fortran.cmake
@@ -199,22 +199,15 @@ function (flang_module_target tgtname)
   endif ()
 
   target_compile_options(${tgtname} PRIVATE
-      # Let non-public modules find the public module files
-      "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
-
+    # Let non-public modules find the public module files
+    "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
+  )
+  if (CMAKE_Fortran_COMPILER_ID MATCHES "LLVM")
+    target_compile_options(${tgtname} PRIVATE
       # Flang bug workaround: Reformating of cooked token buffer causes
       # identifier to be split between lines
       "$<$<COMPILE_LANGUAGE:Fortran>:SHELL:-Xflang;SHELL:-fno-reformat>"
     )
-
-  # `flang --target=nvptx64` fails when not specifying `-march`, even when only
-  # emitting .mod files. Ensure that we pass `-march`.
-  if (LLVM_RUNTIMES_TARGET MATCHES "^nvptx")
-    foreach (_arch IN LISTS RUNTIMES_DEVICE_ARCHITECTURES)
-      target_compile_options(${tgtname} PRIVATE
-        "$<$<COMPILE_LANGUAGE:Fortran>:-march=${_arch}>"
-      )
-    endforeach()
   endif ()
 
   if (ARG_PUBLIC)

>From 14a30a14f61d4d29e0a4ec8856b7cdf5b9f78e8e Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 2 Apr 2026 12:09:48 +0200
Subject: [PATCH 45/53] Reduce change noise accross stacked PRs

Add feedback if libomp-mod is used even without Fortran support

Reduce change noise accross stacked PRs

Backport TODO comment

Reuse LIBOMP_FORTRAN_MODULES
---
 openmp/CMakeLists.txt                    | 17 ++++++++---------
 openmp/runtime/cmake/LibompExports.cmake |  2 +-
 runtimes/CMakeLists.txt                  |  1 +
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/openmp/CMakeLists.txt b/openmp/CMakeLists.txt
index a3eb7fda8a1b7..45234075113e7 100644
--- a/openmp/CMakeLists.txt
+++ b/openmp/CMakeLists.txt
@@ -70,12 +70,6 @@ set(OPENMP_TEST_CXX_COMPILER "${OPENMP_TEST_CXX_COMPILER_default}" CACHE STRING
 set(OPENMP_TEST_Fortran_COMPILER "${OPENMP_TEST_Fortran_COMPILER_default}" CACHE STRING
   "Fortran compiler to use for testing OpenMP runtime libraries.")
 
-# Set fortran test compiler if flang is found
-if (EXISTS "${OPENMP_TEST_Fortran_COMPILER}")
-  message("Using local flang build at ${OPENMP_TEST_Fortran_COMPILER}")
-else()
-  unset(OPENMP_TEST_Fortran_COMPILER)
-endif()
 
 # If not standalone, set CMAKE_CXX_STANDARD but don't set the global cache value,
 # only set it locally for OpenMP.
@@ -106,6 +100,9 @@ math(EXPR LIBOMP_VERSION_BUILD_MONTH_DAY "${LIBOMP_VERSION_BUILD}%10000")
 set(LIBOMP_BUILD_DATE "No_Timestamp")
 
 
+set(LIBOMP_FORTRAN_MODULES "${RUNTIMES_FLANG_MODULES_ENABLED}" CACHE BOOL
+  "Create Fortran module files? (requires fortran compiler)")
+
 # Set up testing infrastructure.
 include(OpenMPTesting)
 
@@ -138,11 +135,13 @@ else()
   get_clang_resource_dir(LIBOMP_HEADERS_INSTALL_PATH SUBDIR include)
 endif()
 
-if(RUNTIMES_FLANG_MODULES_ENABLED)
+if(LIBOMP_FORTRAN_MODULES)
   add_subdirectory(module)
 else()
-  message(STATUS "Building omp_lib.mod disabled by RUNTIMES_FLANG_MODULES_ENABLED='${RUNTIMES_FLANG_MODULES_ENABLED}'; libomp-mod does nothing")
-  add_custom_target(libomp-mod)
+  message(STATUS "Building omp_lib.mod disabled by LIBOMP_FORTRAN_MODULES='${LIBOMP_FORTRAN_MODULES}'; libomp-mod does nothing")
+  add_custom_target(libomp-mod
+    COMMAND ${CMAKE_COMMAND} -E echo "Building omp_lib.mod disabled by LIBOMP_FORTRAN_MODULES=${LIBOMP_FORTRAN_MODULES}"
+  )
 endif()
 
 # Use the current compiler target to determine the appropriate runtime to build.
diff --git a/openmp/runtime/cmake/LibompExports.cmake b/openmp/runtime/cmake/LibompExports.cmake
index 8944899df2631..805f128ebef2e 100644
--- a/openmp/runtime/cmake/LibompExports.cmake
+++ b/openmp/runtime/cmake/LibompExports.cmake
@@ -64,7 +64,7 @@ if(LIBOMP_OMPT_SUPPORT)
     COMMAND ${CMAKE_COMMAND} -E copy omp-tools.h ${LIBOMP_EXPORTS_CMN_DIR}
   )
 endif()
-if(RUNTIMES_FLANG_MODULES_ENABLED)
+if(LIBOMP_FORTRAN_MODULES)
   # We cannot attach a POST_BUILD command to libomp-mod, so instead attach it
   # to omp and ensure that libomp-mod is built before by adding a dependency
   add_custom_command(TARGET omp POST_BUILD
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 09762acb0ba8e..86573451ccd97 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -277,6 +277,7 @@ cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
 # hence must be included their those variables are defined.
 include(config-Fortran)
 
+
 option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
 option(LLVM_INCLUDE_DOCS "Generate build targets for the runtimes documentation." ON)
 option(LLVM_ENABLE_SPHINX "Use Sphinx to generate the runtimes documentation." OFF)

>From 749bb71315f914d28f6c4fc8d0167bee2514006e Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 9 Apr 2026 00:15:08 +0200
Subject: [PATCH 46/53] Split RUNTIMES_FLANG_MODULES_ENABLED into
 RUNTIMES_ENABLE_FORTRAN/RUNTIMES_ENABLE_FLANG_MODULES

---
 flang-rt/cmake/modules/AddFlangRT.cmake |  14 ++++
 runtimes/CMakeLists.txt                 |   4 +-
 runtimes/cmake/config-Fortran.cmake     | 104 ++++++++++++++----------
 3 files changed, 75 insertions(+), 47 deletions(-)

diff --git a/flang-rt/cmake/modules/AddFlangRT.cmake b/flang-rt/cmake/modules/AddFlangRT.cmake
index e46104ab1df58..efb545509c956 100644
--- a/flang-rt/cmake/modules/AddFlangRT.cmake
+++ b/flang-rt/cmake/modules/AddFlangRT.cmake
@@ -345,6 +345,20 @@ function (add_flangrt_library name)
     # directory. Otherwise it is part of testing and is not installed at all.
     # TODO: Consider multi-configuration builds (MSVC_IDE, "Ninja Multi-Config")
     if (ARG_INSTALL_WITH_TOOLCHAIN)
+      # FIXME: RUNTIMES_OUTPUT_RESOURCE_LIB_DIR is not a good location for
+      #        shared libraries because it is not a ld.so default search path.
+      #        Also, the machine where the executable is eventually executed may
+      #        not be one where the compiler is installed, so even RPATH/RUNPATH
+      #        will not help. The most appropriate location for shared libraries
+      #        is /usr/lib/<triple>/lib<name>.so, like e.g. libgcc_s.so.
+      #        Flang-RT also would require a library versioning scheme so
+      #        executables compiled with different versions of Flang either use
+      #        matching versions of Flang-RT, or use a newer backward-compatible
+      #        version. Currently, Flang-RT has no ABI backwards-compatibility
+      #        policy.
+      #        Currently, we just emit it into RUNTIMES_OUTPUT_RESOURCE_LIB_DIR
+      #        like the static library, which is already in the driver's and
+      #        linker's search path.
       set_target_properties(${tgtname}
         PROPERTIES
           ARCHIVE_OUTPUT_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_LIB_DIR}"
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 86573451ccd97..bb8be7b6e722a 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -270,9 +270,9 @@ cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_LIB_DIR)
 cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
 
 
-# Handle Fortran code. When a Fortran  toolchain is available and required by
+# Handle Fortran code. When a Fortran toolchain is available and required by
 # one or more of the runtimes, enables CMake's Fortran support and sets
-# RUNTIMES_FLANG_MODULES_ENABLED.
+# RUNTIMES_ENABLE_FORTRAN and RUNTIMES_ENABLE_FLANG_MODULES.
 # Makes use of RUNTIMES_OUTPUT_RESOURCE_DIR, RUNTIMES_INSTALL_RESOURCE_PATH,
 # hence must be included their those variables are defined.
 include(config-Fortran)
diff --git a/runtimes/cmake/config-Fortran.cmake b/runtimes/cmake/config-Fortran.cmake
index 5b566321fe75a..41c53a6bfc25c 100644
--- a/runtimes/cmake/config-Fortran.cmake
+++ b/runtimes/cmake/config-Fortran.cmake
@@ -1,9 +1,20 @@
 # Check whether the build environment supports building Fortran modules
 # flang-rt and openmp are the only runtimes that contain Fortran modules.
-#
-# Sets:
-#  * RUNTIMES_FLANG_MODULES_ENABLED Whether .mod files can be created
-#  * CMAKE_Fortran_*                CMake Fortran toolchain info for older versions of CMake
+
+
+# Whether building modules for Fortran is supported in the current build environment.
+# Also initializes RUNTIMES_ENABLE_FLANG_MODULES.
+# This is currently not intended to be a user-configuration but derived from CMAKE_Fortran_COMPILER.
+set(RUNTIMES_ENABLE_FORTRAN OFF)
+
+# List of targets that must be built by artifacts that compile using the Fortran compiler
+set(RUNTIMES_FORTRAN_BUILD_DEPS "")
+
+# Currently we hardcode which runtimes make use of Fortran
+set(request_fortran_support OFF)
+if ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES)
+  set(request_fortran_support ON)
+endif ()
 
 
 # Check whether the Fortran compiler already has access to builtin modules. Sets
@@ -53,10 +64,11 @@ function (check_fortran_builtins_available)
 endfunction ()
 
 
-set(FORTRAN_MODULE_DEPS "")
-if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES))
+# Check whether we can compile Fortran sources
+if (request_fortran_support)
+  # Workarounds for older versions of CMake not recognizing FLang. Hence, we
+  # cannot use CMAKE_Fortran_COMPILER_ID.
   cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
-
   if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
     # CMake 3.24 is the first version of CMake that directly recognizes Flang.
     # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
@@ -106,20 +118,19 @@ if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "open
     endif ()
   endif ()
 
-  include(CheckFortranSourceCompiles)
   include(CheckLanguage)
-
-  set(RUNTIMES_FLANG_MODULES_ENABLED_default OFF)
   check_language(Fortran)
   if (CMAKE_Fortran_COMPILER)
     enable_language(Fortran)
+    include(CheckFortranSourceCompiles)
 
     if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
       # In a bootstrapping build (or any runtimes-build that includes flang-rt),
       # the intrinsic modules are not built yet. Targets can depend on
       # flang-rt-mod to ensure that flang-rt's modules are built first.
-      set(FORTRAN_MODULE_DEPS flang-rt-mod)
-      set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+      list(APPEND RUNTIMES_FORTRAN_BUILD_DEPS flang-rt-mod)
+      set(RUNTIMES_ENABLE_FORTRAN ON)
+      message(STATUS "Fortran support enabled using just-built Flang-RT builtin modules")
     else ()
       # Check whether building modules works, avoid causing the entire build to
       # fail because of Fortran. The primary situation we want to support here
@@ -127,18 +138,26 @@ if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "open
       # non-bootstrapping build.
       check_fortran_builtins_available()
       if (HAVE_FORTRAN_INTRINSIC_MODS)
-        set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
-        message(STATUS "${LLVM_SUBPROJECT_TITLE}: Non-bootstrapping Fortran modules build (${CMAKE_Fortran_COMPILER_ID} located at ${CMAKE_Fortran_COMPILER})")
+        set(RUNTIMES_ENABLE_FORTRAN ON)
+        message(STATUS "Fortran support enabled using compiler's own modules")
       else ()
-        message(STATUS "Not compiling Flang modules: Not passing smoke check")
+        message(STATUS "Fortran support disabled: Not passing smoke check")
       endif ()
     endif ()
+  else ()
+    message(STATUS "Fortran support disabled: not enabled in CMake; Use CMAKE_Fortran_COMPILER_WORKS=yes if the issues is missing builtin modules")
   endif ()
+endif ()
 
-  option(RUNTIMES_FLANG_MODULES_ENABLED "Build Fortran modules" "${RUNTIMES_FLANG_MODULES_ENABLED_default}")
+
+# Check whether modules files are compatible with our version of Flang.
+set(RUNTIMES_ENABLE_FLANG_MODULES_default OFF)
+if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+  set(RUNTIMES_ENABLE_FLANG_MODULES_default ON)
 else ()
-  set(RUNTIMES_FLANG_MODULES_ENABLED NO)
+  set(RUNTIMES_ENABLE_FLANG_MODULES_default OFF)
 endif ()
+option(RUNTIMES_ENABLE_FLANG_MODULES "Make Fortran .mod files available to Flang; should only be enabled if compiling with a matching version of Flang" "${RUNTIMES_ENABLE_FLANG_MODULES_default}")
 
 
 # Determine the paths for Fortran .mod files.
@@ -146,18 +165,11 @@ endif ()
 # Sets:
 #  * RUNTIMES_OUTPUT_RESOURCE_MOD_DIR   Path for .mod files in build dir
 #  * RUNTIMES_INSTALL_RESOURCE_MOD_PATH Path for .mod files in install dir, relative to CMAKE_INSTALL_PREFIX
-if (RUNTIMES_FLANG_MODULES_ENABLED)
-  if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
-    # Flang expects its builtin modules in Clang's resource directory.
-    get_toolchain_module_subdir(toolchain_mod_subdir)
-    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
-    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
-  else ()
-    # For non-Flang compilers, avoid the risk of Flang accidentally picking them up.
-    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
-    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
-  endif ()
-  cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
+if (RUNTIMES_ENABLE_FLANG_MODULES)
+  # Flang expects its builtin modules in Clang's resource directory.
+  get_toolchain_module_subdir(toolchain_mod_subdir)
+  extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
+  extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
   cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
 
   # No way to find out which mod files are built by a target, so install the
@@ -166,10 +178,17 @@ if (RUNTIMES_FLANG_MODULES_ENABLED)
   # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
   set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
   cmake_path(NORMAL_PATH destination)
-    install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
-      DESTINATION "${destination}"
-    )
+  install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+    DESTINATION "${destination}"
+  )
+else ()
+  # If Flang modules are disabled (e.g. because the compiler is not Flang), avoid the risk of Flang accidentally picking them up.
+  extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${CMAKE_CURRENT_BINARY_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+
+  # We don't know how to install non-Flang modules
+  set(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "")
 endif ()
+cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
 
 
 # Set options to compile Fortran module files. Assumes the code above has run.
@@ -181,7 +200,7 @@ endif ()
 #     Modules files are to be used by other Fortran sources. If a library is
 #     compiled multiple times (e.g. static/shared, or msvcrt variants), only
 #     one of those can be public module files; non-public modules are still
-#     generated but to be forgotten deep inside the build directory to not
+#     generated but to be forgotten inside the build directory to not
 #     conflict with each other.
 #     Also, installs the module with the toolchain.
 # )
@@ -191,17 +210,14 @@ function (flang_module_target tgtname)
     "${options}"
     ""
     ""
-    ${ARGN})
-
-  if (NOT RUNTIMES_FLANG_MODULES_ENABLED)
-    message(WARNING "Cannot build module files for ${tgtname} when RUNTIMES_FLANG_MODULES_ENABLED is ${RUNTIMES_FLANG_MODULES_ENABLED}")
-    return ()
-  endif ()
+    ${ARGN}
+  )
 
+  # Let all modules find the public module files
   target_compile_options(${tgtname} PRIVATE
-    # Let non-public modules find the public module files
     "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
   )
+
   if (CMAKE_Fortran_COMPILER_ID MATCHES "LLVM")
     target_compile_options(${tgtname} PRIVATE
       # Flang bug workaround: Reformating of cooked token buffer causes
@@ -214,11 +230,9 @@ function (flang_module_target tgtname)
     set_target_properties(${tgtname}
       PROPERTIES
         Fortran_MODULE_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
-      )
+    )
   else ()
-    set_target_properties(${tgtname}
-      PROPERTIES
-        Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${tgtname}.mod"
-      )
+    # Keep non-public modules where CMake would put them normally;
+    # Modules of different target must not overwrite each other.
   endif ()
 endfunction ()

>From 4231f9dfeee37aae9de7bd4255edb89030f21b9c Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 9 Apr 2026 00:16:24 +0200
Subject: [PATCH 47/53] Split RUNTIMES_FLANG_MODULES_ENABLED into
 RUNTIMES_ENABLE_FORTRAN/RUNTIMES_ENABLE_FLANG_MODULES

---
 flang-rt/CMakeLists.txt                       |   3 +-
 .../cmake/modules/FlangRTIntrospection.cmake  |   1 +
 flang-rt/lib/CMakeLists.txt                   |   2 +-
 flang-rt/lib/runtime/CMakeLists.txt           |   2 +-
 openmp/CMakeLists.txt                         |   5 +-
 openmp/module/CMakeLists.txt                  |  12 +-
 openmp/runtime/test/lit.cfg                   |   3 +-
 runtimes/cmake/config-Fortran.cmake           | 104 ++++++++++--------
 8 files changed, 72 insertions(+), 60 deletions(-)

diff --git a/flang-rt/CMakeLists.txt b/flang-rt/CMakeLists.txt
index 01d800420a41e..ae135109885b5 100644
--- a/flang-rt/CMakeLists.txt
+++ b/flang-rt/CMakeLists.txt
@@ -122,6 +122,8 @@ else ()
   option(FLANG_RT_ENABLE_SHARED "Build Flang-RT as a shared library." OFF)
 endif ()
 
+option(FLANG_RT_FORTRAN_MODULES "Build Flang-RT modules" "${RUNTIMES_FLANG_MODULES_ENABLED}")
+
 
 # TODO: Support tests for the GPU target.
 set(FLANG_RT_INCLUDE_TESTS_default ${LLVM_INCLUDE_TESTS})
@@ -138,7 +140,6 @@ if (FLANG_RT_INCLUDE_TESTS AND NOT FLANG_RT_ENABLE_STATIC AND NOT FLANG_RT_ENABL
                   "Tests are disabled: check-flang-rt does nothing")
   set(FLANG_RT_INCLUDE_TESTS OFF)
 endif ()
-option(FLANG_RT_INCLUDE_TESTS "Generate build targets for the flang-rt unit and regression-tests." "${FLANG_RT_INCLUDE_TESTS_default}")
 
 
 set(FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT "" CACHE STRING "Compile Flang-RT with GPU support (CUDA)")
diff --git a/flang-rt/cmake/modules/FlangRTIntrospection.cmake b/flang-rt/cmake/modules/FlangRTIntrospection.cmake
index 6b48dd33806fa..04fff80549fff 100644
--- a/flang-rt/cmake/modules/FlangRTIntrospection.cmake
+++ b/flang-rt/cmake/modules/FlangRTIntrospection.cmake
@@ -12,6 +12,7 @@ include(CMakePushCheckState)
 #    a compiler introspection environment, see
 #    https://gitlab.kitware.com/cmake/cmake/-/issues/27419
 #    Additionally wrap it in a function namespace.
+#
 function (check_fortran_quadmath_support)
   cmake_push_check_state(RESET)
   set(CMAKE_REQUIRED_FLAGS "-ffree-form")
diff --git a/flang-rt/lib/CMakeLists.txt b/flang-rt/lib/CMakeLists.txt
index 8738ae7b9c4b6..58a7a24c19e0c 100644
--- a/flang-rt/lib/CMakeLists.txt
+++ b/flang-rt/lib/CMakeLists.txt
@@ -12,7 +12,7 @@ if (FLANG_RT_ENABLE_STATIC OR FLANG_RT_ENABLE_SHARED)
   if (FLANG_RT_INCLUDE_CUF)
     add_subdirectory(cuda)
   endif()
-else ()
+elseif (FLANG_RT_FORTRAN_MODULES)
   # Generate modules files only, skip the libraries
   add_subdirectory(runtime)
 endif ()
diff --git a/flang-rt/lib/runtime/CMakeLists.txt b/flang-rt/lib/runtime/CMakeLists.txt
index 80fccabaf563f..8485db72a29c7 100644
--- a/flang-rt/lib/runtime/CMakeLists.txt
+++ b/flang-rt/lib/runtime/CMakeLists.txt
@@ -24,12 +24,12 @@ set(module_sources
   __fortran_type_info.f90
   flang_debug.f90
   iso_fortran_env.f90
+  iso_fortran_env_impl.f90
   ieee_arithmetic.f90
   ieee_exceptions.f90
   ieee_features.f90
   iso_c_binding.f90
   iso_fortran_env.f90
-  iso_fortran_env_impl.f90
 
   __cuda_device.f90
   cooperative_groups.f90
diff --git a/openmp/CMakeLists.txt b/openmp/CMakeLists.txt
index 45234075113e7..c4a1181f80345 100644
--- a/openmp/CMakeLists.txt
+++ b/openmp/CMakeLists.txt
@@ -70,7 +70,6 @@ set(OPENMP_TEST_CXX_COMPILER "${OPENMP_TEST_CXX_COMPILER_default}" CACHE STRING
 set(OPENMP_TEST_Fortran_COMPILER "${OPENMP_TEST_Fortran_COMPILER_default}" CACHE STRING
   "Fortran compiler to use for testing OpenMP runtime libraries.")
 
-
 # If not standalone, set CMAKE_CXX_STANDARD but don't set the global cache value,
 # only set it locally for OpenMP.
 set(CMAKE_CXX_STANDARD 17)
@@ -100,8 +99,8 @@ math(EXPR LIBOMP_VERSION_BUILD_MONTH_DAY "${LIBOMP_VERSION_BUILD}%10000")
 set(LIBOMP_BUILD_DATE "No_Timestamp")
 
 
-set(LIBOMP_FORTRAN_MODULES "${RUNTIMES_FLANG_MODULES_ENABLED}" CACHE BOOL
-  "Create Fortran module files? (requires fortran compiler)")
+set(LIBOMP_FORTRAN_MODULES "${RUNTIMES_ENABLE_FORTRAN}" CACHE BOOL
+  "Create Fortran module files? (requires Fortran compiler)")
 
 # Set up testing infrastructure.
 include(OpenMPTesting)
diff --git a/openmp/module/CMakeLists.txt b/openmp/module/CMakeLists.txt
index 91a452dcc98c3..172b3cc1fd4b0 100644
--- a/openmp/module/CMakeLists.txt
+++ b/openmp/module/CMakeLists.txt
@@ -13,7 +13,7 @@ configure_file(omp_lib.h.var "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib
 
 # One compilation step creates both, omp_lib.mod and omp_lib_kinds.mod. Only
 # these files are used, the object file itself can be discarded.
-# FIXME: Adding it to libomp.so would allow implementing Fortran API in Fortran
+# TODO: Adding it to libomp ($<TARGET_OBJECTS:libomp-mod) would allow implementing Fortran API in Fortran
 add_library(libomp-mod OBJECT
   "{CMAKE_CURRENT_BINARY_DIR}/omp_lib.F90"
 )
@@ -27,15 +27,11 @@ if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
 endif ()
 
 flang_module_target(libomp-mod PUBLIC)
-if (FORTRAN_MODULE_DEPS)
-  add_dependencies(libomp-mod ${FORTRAN_MODULE_DEPS})
+if (RUNTIMES_FORTRAN_BUILD_DEPS)
+  add_dependencies(libomp-mod ${RUNTIMES_FORTRAN_BUILD_DEPS})
 endif ()
 
-set(destination "${LIBOMP_HEADERS_INSTALL_PATH}")
-if (LIBOMP_MODULES_INSTALL_PATH)
-  set(destination "${LIBOMP_MODULES_INSTALL_PATH}")
-endif ()
 install(FILES
   "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.h"
-  DESTINATION ${destination}
+  DESTINATION ${LIBOMP_HEADERS_INSTALL_PATH}
 )
diff --git a/openmp/runtime/test/lit.cfg b/openmp/runtime/test/lit.cfg
index b48405aed16ad..a899895a367a1 100644
--- a/openmp/runtime/test/lit.cfg
+++ b/openmp/runtime/test/lit.cfg
@@ -3,6 +3,7 @@
 
 import os
 import re
+import shlex
 import subprocess
 import lit.formats
 from lit.llvm.subst import ToolSubst
@@ -51,7 +52,7 @@ if config.test_fortran_compiler:
         ToolSubst(
             "%flang",
             command=config.test_fortran_compiler,
-            extra_args=config.test_fortran_flags.split(),
+            extra_args=shlex.split(config.test_fortran_flags),
             unresolved="fatal",
         ),
     ], [config.llvm_tools_dir])
diff --git a/runtimes/cmake/config-Fortran.cmake b/runtimes/cmake/config-Fortran.cmake
index 5b566321fe75a..41c53a6bfc25c 100644
--- a/runtimes/cmake/config-Fortran.cmake
+++ b/runtimes/cmake/config-Fortran.cmake
@@ -1,9 +1,20 @@
 # Check whether the build environment supports building Fortran modules
 # flang-rt and openmp are the only runtimes that contain Fortran modules.
-#
-# Sets:
-#  * RUNTIMES_FLANG_MODULES_ENABLED Whether .mod files can be created
-#  * CMAKE_Fortran_*                CMake Fortran toolchain info for older versions of CMake
+
+
+# Whether building modules for Fortran is supported in the current build environment.
+# Also initializes RUNTIMES_ENABLE_FLANG_MODULES.
+# This is currently not intended to be a user-configuration but derived from CMAKE_Fortran_COMPILER.
+set(RUNTIMES_ENABLE_FORTRAN OFF)
+
+# List of targets that must be built by artifacts that compile using the Fortran compiler
+set(RUNTIMES_FORTRAN_BUILD_DEPS "")
+
+# Currently we hardcode which runtimes make use of Fortran
+set(request_fortran_support OFF)
+if ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES)
+  set(request_fortran_support ON)
+endif ()
 
 
 # Check whether the Fortran compiler already has access to builtin modules. Sets
@@ -53,10 +64,11 @@ function (check_fortran_builtins_available)
 endfunction ()
 
 
-set(FORTRAN_MODULE_DEPS "")
-if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES))
+# Check whether we can compile Fortran sources
+if (request_fortran_support)
+  # Workarounds for older versions of CMake not recognizing FLang. Hence, we
+  # cannot use CMAKE_Fortran_COMPILER_ID.
   cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
-
   if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
     # CMake 3.24 is the first version of CMake that directly recognizes Flang.
     # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
@@ -106,20 +118,19 @@ if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "open
     endif ()
   endif ()
 
-  include(CheckFortranSourceCompiles)
   include(CheckLanguage)
-
-  set(RUNTIMES_FLANG_MODULES_ENABLED_default OFF)
   check_language(Fortran)
   if (CMAKE_Fortran_COMPILER)
     enable_language(Fortran)
+    include(CheckFortranSourceCompiles)
 
     if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
       # In a bootstrapping build (or any runtimes-build that includes flang-rt),
       # the intrinsic modules are not built yet. Targets can depend on
       # flang-rt-mod to ensure that flang-rt's modules are built first.
-      set(FORTRAN_MODULE_DEPS flang-rt-mod)
-      set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
+      list(APPEND RUNTIMES_FORTRAN_BUILD_DEPS flang-rt-mod)
+      set(RUNTIMES_ENABLE_FORTRAN ON)
+      message(STATUS "Fortran support enabled using just-built Flang-RT builtin modules")
     else ()
       # Check whether building modules works, avoid causing the entire build to
       # fail because of Fortran. The primary situation we want to support here
@@ -127,18 +138,26 @@ if (CMAKE_Fortran_COMPILER AND ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "open
       # non-bootstrapping build.
       check_fortran_builtins_available()
       if (HAVE_FORTRAN_INTRINSIC_MODS)
-        set(RUNTIMES_FLANG_MODULES_ENABLED_default ON)
-        message(STATUS "${LLVM_SUBPROJECT_TITLE}: Non-bootstrapping Fortran modules build (${CMAKE_Fortran_COMPILER_ID} located at ${CMAKE_Fortran_COMPILER})")
+        set(RUNTIMES_ENABLE_FORTRAN ON)
+        message(STATUS "Fortran support enabled using compiler's own modules")
       else ()
-        message(STATUS "Not compiling Flang modules: Not passing smoke check")
+        message(STATUS "Fortran support disabled: Not passing smoke check")
       endif ()
     endif ()
+  else ()
+    message(STATUS "Fortran support disabled: not enabled in CMake; Use CMAKE_Fortran_COMPILER_WORKS=yes if the issues is missing builtin modules")
   endif ()
+endif ()
 
-  option(RUNTIMES_FLANG_MODULES_ENABLED "Build Fortran modules" "${RUNTIMES_FLANG_MODULES_ENABLED_default}")
+
+# Check whether modules files are compatible with our version of Flang.
+set(RUNTIMES_ENABLE_FLANG_MODULES_default OFF)
+if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
+  set(RUNTIMES_ENABLE_FLANG_MODULES_default ON)
 else ()
-  set(RUNTIMES_FLANG_MODULES_ENABLED NO)
+  set(RUNTIMES_ENABLE_FLANG_MODULES_default OFF)
 endif ()
+option(RUNTIMES_ENABLE_FLANG_MODULES "Make Fortran .mod files available to Flang; should only be enabled if compiling with a matching version of Flang" "${RUNTIMES_ENABLE_FLANG_MODULES_default}")
 
 
 # Determine the paths for Fortran .mod files.
@@ -146,18 +165,11 @@ endif ()
 # Sets:
 #  * RUNTIMES_OUTPUT_RESOURCE_MOD_DIR   Path for .mod files in build dir
 #  * RUNTIMES_INSTALL_RESOURCE_MOD_PATH Path for .mod files in install dir, relative to CMAKE_INSTALL_PREFIX
-if (RUNTIMES_FLANG_MODULES_ENABLED)
-  if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang")
-    # Flang expects its builtin modules in Clang's resource directory.
-    get_toolchain_module_subdir(toolchain_mod_subdir)
-    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
-    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
-  else ()
-    # For non-Flang compilers, avoid the risk of Flang accidentally picking them up.
-    extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
-    extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
-  endif ()
-  cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
+if (RUNTIMES_ENABLE_FLANG_MODULES)
+  # Flang expects its builtin modules in Clang's resource directory.
+  get_toolchain_module_subdir(toolchain_mod_subdir)
+  extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${RUNTIMES_OUTPUT_RESOURCE_DIR}" "${toolchain_mod_subdir}")
+  extend_path(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "${RUNTIMES_INSTALL_RESOURCE_PATH}" "${toolchain_mod_subdir}")
   cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_MOD_PATH)
 
   # No way to find out which mod files are built by a target, so install the
@@ -166,10 +178,17 @@ if (RUNTIMES_FLANG_MODULES_ENABLED)
   # https://stackoverflow.com/questions/52712416/cmake-fortran-module-directory-to-be-used-with-add-library
   set(destination "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..")
   cmake_path(NORMAL_PATH destination)
-    install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
-      DESTINATION "${destination}"
-    )
+  install(DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
+    DESTINATION "${destination}"
+  )
+else ()
+  # If Flang modules are disabled (e.g. because the compiler is not Flang), avoid the risk of Flang accidentally picking them up.
+  extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${CMAKE_CURRENT_BINARY_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
+
+  # We don't know how to install non-Flang modules
+  set(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "")
 endif ()
+cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)
 
 
 # Set options to compile Fortran module files. Assumes the code above has run.
@@ -181,7 +200,7 @@ endif ()
 #     Modules files are to be used by other Fortran sources. If a library is
 #     compiled multiple times (e.g. static/shared, or msvcrt variants), only
 #     one of those can be public module files; non-public modules are still
-#     generated but to be forgotten deep inside the build directory to not
+#     generated but to be forgotten inside the build directory to not
 #     conflict with each other.
 #     Also, installs the module with the toolchain.
 # )
@@ -191,17 +210,14 @@ function (flang_module_target tgtname)
     "${options}"
     ""
     ""
-    ${ARGN})
-
-  if (NOT RUNTIMES_FLANG_MODULES_ENABLED)
-    message(WARNING "Cannot build module files for ${tgtname} when RUNTIMES_FLANG_MODULES_ENABLED is ${RUNTIMES_FLANG_MODULES_ENABLED}")
-    return ()
-  endif ()
+    ${ARGN}
+  )
 
+  # Let all modules find the public module files
   target_compile_options(${tgtname} PRIVATE
-    # Let non-public modules find the public module files
     "$<$<COMPILE_LANGUAGE:Fortran>:-fintrinsic-modules-path=${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}>"
   )
+
   if (CMAKE_Fortran_COMPILER_ID MATCHES "LLVM")
     target_compile_options(${tgtname} PRIVATE
       # Flang bug workaround: Reformating of cooked token buffer causes
@@ -214,11 +230,9 @@ function (flang_module_target tgtname)
     set_target_properties(${tgtname}
       PROPERTIES
         Fortran_MODULE_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
-      )
+    )
   else ()
-    set_target_properties(${tgtname}
-      PROPERTIES
-        Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${tgtname}.mod"
-      )
+    # Keep non-public modules where CMake would put them normally;
+    # Modules of different target must not overwrite each other.
   endif ()
 endfunction ()

>From b2ff0ba1df5bce2892f8291a1354f7989c82af9e Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 9 Apr 2026 00:25:18 +0200
Subject: [PATCH 48/53] Add missing get_toolchain_module_subdir

---
 cmake/Modules/GetToolchainDirs.cmake | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/cmake/Modules/GetToolchainDirs.cmake b/cmake/Modules/GetToolchainDirs.cmake
index c1f0f70b3e7cc..7568734e3f25d 100644
--- a/cmake/Modules/GetToolchainDirs.cmake
+++ b/cmake/Modules/GetToolchainDirs.cmake
@@ -49,6 +49,17 @@ function (get_toolchain_fortran_module_subdir outvar)
 endfunction ()
 
 
+# Corresponds to Flang's ToolChain::getDefaultIntrinsicModuleDir().
+function (get_toolchain_module_subdir outvar)
+  set(outval "finclude/flang")
+
+  get_toolchain_target_dirname(arch_dirname)
+  set(outval "${outval}/${arch_dirname}")
+
+  set(${outvar} "${outval}" PARENT_SCOPE)
+endfunction ()
+
+
 # Corresponds to Clang's ToolChain::getOSLibName(). Adapted from Compiler-RT.
 function (get_toolchain_os_dirname outvar)
   if (ANDROID)

>From 2f0b2ff6083d56a1e769d6ef32ed9c043ef59801 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 20 Apr 2026 17:40:30 +0200
Subject: [PATCH 49/53] Partial inlining of config-Fortran

---
 runtimes/CMakeLists.txt             | 39 +++++++++++++++++++++++++----
 runtimes/cmake/config-Fortran.cmake | 18 -------------
 2 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index bb8be7b6e722a..6eff86196112f 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -270,12 +270,41 @@ cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_LIB_DIR)
 cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
 
 
-# Handle Fortran code. When a Fortran toolchain is available and required by
-# one or more of the runtimes, enables CMake's Fortran support and sets
-# RUNTIMES_ENABLE_FORTRAN and RUNTIMES_ENABLE_FLANG_MODULES.
-# Makes use of RUNTIMES_OUTPUT_RESOURCE_DIR, RUNTIMES_INSTALL_RESOURCE_PATH,
+# Code for Fortran support.
+#
+# Currently, flang-rt and openmp are the only runtimes that contain Fortran
+# modules which we hardcode here. This code makes use of
+# RUNTIMES_OUTPUT_RESOURCE_DIR, RUNTIMES_INSTALL_RESOURCE_PATH,
 # hence must be included their those variables are defined.
-include(config-Fortran)
+# Sets the following public CMake variables:
+#
+# RUNTIMES_ENABLE_FORTRAN - Whether support for Fortran code is available and enabled.
+# This is currently not intended to be a user-configuration but derived from CMAKE_Fortran_COMPILER.
+# Can also be OFF when Fortran support is not needed or is insufficient, e.g.
+# if intrinsic modules are missing and cannot be compiled on-the-fly.
+#
+# RUNTIMES_FORTRAN_BUILD_DEPS - If RUNTIMES_ENABLE_FORTRAN is true, this is a
+# list of dependencies that must be built before any Fortran source can be
+# compiled. Contains the build targets for intrinsic modules, if necessary.
+# Otherweise, it is empty.
+#
+# RUNTIMES_ENABLE_FLANG_MODULES - Whether to build Flang modules and emit them into Flang's search path.
+# This is a CMake CACHE option defined in config-Fortran.cmake and default to
+# ON iff the Fortran compiler is detected for be a (compatible) version of Flang.
+# In the OFF setting, modules are still built, but not installed or emitted into a default path.
+#
+# RUNTIMES_OUTPUT_RESOURCE_MOD_DIR - Where to emit intrinsic module files in
+# the build directory. Most relevent when RUNTIMES_ENABLE_FLANG_MODULES is ON.
+#
+# RUNTIMES_INSTALL_RESOURCE_MOD_PATH - Where to install intrinsic module files
+# in the install prefix. Relative to CMAKE_INSTALL_PREFIX. Only used when
+# RUNTIMES_ENABLE_FLANG_MODULES is ON.
+#
+set(RUNTIMES_ENABLE_FORTRAN OFF)
+set(RUNTIMES_FORTRAN_BUILD_DEPS "")
+if ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES)
+  include(config-Fortran)
+endif ()
 
 
 option(LLVM_INCLUDE_TESTS "Generate build targets for the runtimes unit tests." ON)
diff --git a/runtimes/cmake/config-Fortran.cmake b/runtimes/cmake/config-Fortran.cmake
index 41c53a6bfc25c..0b640a65b6203 100644
--- a/runtimes/cmake/config-Fortran.cmake
+++ b/runtimes/cmake/config-Fortran.cmake
@@ -1,21 +1,3 @@
-# Check whether the build environment supports building Fortran modules
-# flang-rt and openmp are the only runtimes that contain Fortran modules.
-
-
-# Whether building modules for Fortran is supported in the current build environment.
-# Also initializes RUNTIMES_ENABLE_FLANG_MODULES.
-# This is currently not intended to be a user-configuration but derived from CMAKE_Fortran_COMPILER.
-set(RUNTIMES_ENABLE_FORTRAN OFF)
-
-# List of targets that must be built by artifacts that compile using the Fortran compiler
-set(RUNTIMES_FORTRAN_BUILD_DEPS "")
-
-# Currently we hardcode which runtimes make use of Fortran
-set(request_fortran_support OFF)
-if ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES)
-  set(request_fortran_support ON)
-endif ()
-
 
 # Check whether the Fortran compiler already has access to builtin modules. Sets
 # HAVE_FORTRAN_INTRINSIC_MODS when returning.

>From 323cc170fb330e55b79da9ef0e2c32c19f369e0c Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 20 Apr 2026 18:02:52 +0200
Subject: [PATCH 50/53] Assume no Fortran in other runtimes

Ensure non-empty dependency list
---
 runtimes/CMakeLists.txt             |  36 ++----
 runtimes/cmake/config-Fortran.cmake | 172 ++++++++++++++++------------
 2 files changed, 108 insertions(+), 100 deletions(-)

diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 6eff86196112f..75551ba0c651a 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -272,36 +272,14 @@ cmake_path(NORMAL_PATH RUNTIMES_INSTALL_RESOURCE_LIB_PATH)
 
 # Code for Fortran support.
 #
-# Currently, flang-rt and openmp are the only runtimes that contain Fortran
-# modules which we hardcode here. This code makes use of
-# RUNTIMES_OUTPUT_RESOURCE_DIR, RUNTIMES_INSTALL_RESOURCE_PATH,
-# hence must be included their those variables are defined.
-# Sets the following public CMake variables:
-#
-# RUNTIMES_ENABLE_FORTRAN - Whether support for Fortran code is available and enabled.
-# This is currently not intended to be a user-configuration but derived from CMAKE_Fortran_COMPILER.
-# Can also be OFF when Fortran support is not needed or is insufficient, e.g.
-# if intrinsic modules are missing and cannot be compiled on-the-fly.
-#
-# RUNTIMES_FORTRAN_BUILD_DEPS - If RUNTIMES_ENABLE_FORTRAN is true, this is a
-# list of dependencies that must be built before any Fortran source can be
-# compiled. Contains the build targets for intrinsic modules, if necessary.
-# Otherweise, it is empty.
-#
-# RUNTIMES_ENABLE_FLANG_MODULES - Whether to build Flang modules and emit them into Flang's search path.
-# This is a CMake CACHE option defined in config-Fortran.cmake and default to
-# ON iff the Fortran compiler is detected for be a (compatible) version of Flang.
-# In the OFF setting, modules are still built, but not installed or emitted into a default path.
+# Currently, only flang-rt and openmp contain Fortran sources. We assume that
+# none of the public CMake variables defined in config-Fortran are used unless
+# we enable one of these runtimes. Other runtimes would make used of undefined
+# variables.
 #
-# RUNTIMES_OUTPUT_RESOURCE_MOD_DIR - Where to emit intrinsic module files in
-# the build directory. Most relevent when RUNTIMES_ENABLE_FLANG_MODULES is ON.
-#
-# RUNTIMES_INSTALL_RESOURCE_MOD_PATH - Where to install intrinsic module files
-# in the install prefix. Relative to CMAKE_INSTALL_PREFIX. Only used when
-# RUNTIMES_ENABLE_FLANG_MODULES is ON.
-#
-set(RUNTIMES_ENABLE_FORTRAN OFF)
-set(RUNTIMES_FORTRAN_BUILD_DEPS "")
+# config-Fortran.cmake makes use of
+# RUNTIMES_OUTPUT_RESOURCE_DIR, RUNTIMES_INSTALL_RESOURCE_PATH,
+# hence must be included after those variables are defined.
 if ("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES OR "openmp" IN_LIST LLVM_ENABLE_RUNTIMES)
   include(config-Fortran)
 endif ()
diff --git a/runtimes/cmake/config-Fortran.cmake b/runtimes/cmake/config-Fortran.cmake
index 0b640a65b6203..160f7f3a98643 100644
--- a/runtimes/cmake/config-Fortran.cmake
+++ b/runtimes/cmake/config-Fortran.cmake
@@ -1,3 +1,29 @@
+# This file sets the following public CMake variables:
+#
+# RUNTIMES_ENABLE_FORTRAN - Whether support for Fortran code is available and
+# enabled. This is currently not intended to be a user-configuration but
+# derived from CMAKE_Fortran_COMPILER. Can also be OFF when Fortran support is
+# not needed or is insufficient, e.g. if intrinsic modules are missing and
+# cannot be compiled on-the-fly.
+#
+# RUNTIMES_FORTRAN_BUILD_DEPS - If RUNTIMES_ENABLE_FORTRAN is true, this is a
+# list of dependencies that must be built before any Fortran source can be
+# compiled. Contains the build targets for intrinsic modules, if necessary.
+# Otherweise, it is empty.
+#
+# RUNTIMES_ENABLE_FLANG_MODULES - Whether to build Flang modules and emit them
+# into Flang's search path. This is a CMake CACHE option defined in
+# config-Fortran.cmake and default to ON iff the Fortran compiler is detected
+# for be a (compatible) version of Flang. In the OFF setting, modules are still
+# built, but not installed or emitted into a default path.
+#
+# RUNTIMES_OUTPUT_RESOURCE_MOD_DIR - Where to emit intrinsic module files in
+# the build directory. Most relevant when RUNTIMES_ENABLE_FLANG_MODULES is ON.
+#
+# RUNTIMES_INSTALL_RESOURCE_MOD_PATH - Where to install intrinsic module files
+# in the install prefix. Relative to CMAKE_INSTALL_PREFIX. Only used when
+# RUNTIMES_ENABLE_FLANG_MODULES is ON.
+
 
 # Check whether the Fortran compiler already has access to builtin modules. Sets
 # HAVE_FORTRAN_INTRINSIC_MODS when returning.
@@ -46,89 +72,97 @@ function (check_fortran_builtins_available)
 endfunction ()
 
 
-# Check whether we can compile Fortran sources
-if (request_fortran_support)
-  # Workarounds for older versions of CMake not recognizing FLang. Hence, we
-  # cannot use CMAKE_Fortran_COMPILER_ID.
-  cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
-  if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
-    # CMake 3.24 is the first version of CMake that directly recognizes Flang.
-    # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
-    if (CMAKE_VERSION VERSION_LESS "3.24")
-      include(CMakeForceCompiler)
-      CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
+# Workarounds for older versions of CMake not recognizing FLang. Hence, we
+# cannot use CMAKE_Fortran_COMPILER_ID.
+cmake_path(GET CMAKE_Fortran_COMPILER STEM _Fortran_COMPILER_STEM)
+if (_Fortran_COMPILER_STEM STREQUAL "flang-new" OR _Fortran_COMPILER_STEM STREQUAL "flang")
+  # CMake 3.24 is the first version of CMake that directly recognizes Flang.
+  # LLVM's requirement is only CMake 3.20, teach CMake 3.20-3.23 how to use Flang, if used.
+  if (CMAKE_VERSION VERSION_LESS "3.24")
+    include(CMakeForceCompiler)
+    CMAKE_FORCE_Fortran_COMPILER("${CMAKE_Fortran_COMPILER}" "LLVMFlang")
 
-      set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
-      set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
+    set(CMAKE_Fortran_COMPILER_ID "LLVMFlang")
+    set(CMAKE_Fortran_COMPILER_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
 
-      set(CMAKE_Fortran_SUBMODULE_SEP "-")
-      set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
+    set(CMAKE_Fortran_SUBMODULE_SEP "-")
+    set(CMAKE_Fortran_SUBMODULE_EXT ".mod")
 
-      set(CMAKE_Fortran_PREPROCESS_SOURCE
-          "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
+    set(CMAKE_Fortran_PREPROCESS_SOURCE
+        "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
 
-      set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
-      set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
+    set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
+    set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
 
-      set(CMAKE_Fortran_MODDIR_FLAG "-J")
+    set(CMAKE_Fortran_MODDIR_FLAG "-J")
 
-      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
-      set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
-      set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
+    set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-cpp")
+    set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF "-nocpp")
+    set(CMAKE_Fortran_POSTPROCESS_FLAG "-ffixed-line-length-72")
 
-      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
-      set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
+    set(CMAKE_Fortran_LINKER_WRAPPER_FLAG "-Wl,")
+    set(CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP ",")
 
-      set(CMAKE_Fortran_VERBOSE_FLAG "-v")
+    set(CMAKE_Fortran_VERBOSE_FLAG "-v")
 
-      set(CMAKE_Fortran_LINK_MODE DRIVER)
-    endif ()
+    set(CMAKE_Fortran_LINK_MODE DRIVER)
+  endif ()
 
-    # Optimization flags are only passed after CMake 3.27.4
-    # https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
-    if (CMAKE_VERSION VERSION_LESS "3.27.4")
-      string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
-      string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
-      string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
-    endif ()
+  # Optimization flags are only passed after CMake 3.27.4
+  # https://gitlab.kitware.com/cmake/cmake/-/commit/1140087adea98bd8d8974e4c18979f4949b52c34
+  if (CMAKE_VERSION VERSION_LESS "3.27.4")
+    string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT " -O0 -g")
+    string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -O2 -g")
+    string(APPEND CMAKE_Fortran_FLAGS_RELEASE_INIT " -O3")
+  endif ()
 
-    # Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
-    # to nvptx amd amdgpu targets, passing the target triple is essential.
-    # https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
-    if (CMAKE_VERSION VERSION_LESS "3.28")
-      set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
-    endif ()
+  # Only CMake 3.28+ pass --target= to Flang. But for cross-compiling, including
+  # to nvptx amd amdgpu targets, passing the target triple is essential.
+  # https://gitlab.kitware.com/cmake/cmake/-/commit/e9af7b968756e72553296ecdcde6f36606a0babf
+  if (CMAKE_VERSION VERSION_LESS "3.28")
+    set(CMAKE_Fortran_COMPILE_OPTIONS_TARGET "--target=")
   endif ()
+endif ()
+
+
+set(RUNTIMES_ENABLE_FORTRAN OFF)
 
-  include(CheckLanguage)
-  check_language(Fortran)
-  if (CMAKE_Fortran_COMPILER)
-    enable_language(Fortran)
-    include(CheckFortranSourceCompiles)
-
-    if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
-      # In a bootstrapping build (or any runtimes-build that includes flang-rt),
-      # the intrinsic modules are not built yet. Targets can depend on
-      # flang-rt-mod to ensure that flang-rt's modules are built first.
-      list(APPEND RUNTIMES_FORTRAN_BUILD_DEPS flang-rt-mod)
+# Insert at least one element for
+#
+#    add_dependencies(target ${RUNTIMES_FORTRAN_BUILD_DEPS})
+#
+# to noy fail
+add_custom_target(fortran-dummy-dep)
+set(RUNTIMES_FORTRAN_BUILD_DEPS fortran-dummy-dep)
+
+include(CheckLanguage)
+check_language(Fortran)
+if (CMAKE_Fortran_COMPILER)
+  enable_language(Fortran)
+  include(CheckFortranSourceCompiles)
+
+  if (CMAKE_Fortran_COMPILER_ID STREQUAL "LLVMFlang" AND "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
+    # In a bootstrapping build (or any runtimes-build that includes flang-rt),
+    # the intrinsic modules are not built yet. Targets can depend on
+    # flang-rt-mod to ensure that flang-rt's modules are built first.
+    list(APPEND RUNTIMES_FORTRAN_BUILD_DEPS flang-rt-mod)
+    set(RUNTIMES_ENABLE_FORTRAN ON)
+    message(STATUS "Fortran support enabled using just-built Flang-RT builtin modules")
+  else ()
+    # Check whether building modules works, avoid causing the entire build to
+    # fail because of Fortran. The primary situation we want to support here
+    # is Flang, or its intrinsic modules were built separately in a
+    # non-bootstrapping build.
+    check_fortran_builtins_available()
+    if (HAVE_FORTRAN_INTRINSIC_MODS)
       set(RUNTIMES_ENABLE_FORTRAN ON)
-      message(STATUS "Fortran support enabled using just-built Flang-RT builtin modules")
+      message(STATUS "Fortran support enabled using compiler's own modules")
     else ()
-      # Check whether building modules works, avoid causing the entire build to
-      # fail because of Fortran. The primary situation we want to support here
-      # is Flang, or its intrinsic modules were built separately in a
-      # non-bootstrapping build.
-      check_fortran_builtins_available()
-      if (HAVE_FORTRAN_INTRINSIC_MODS)
-        set(RUNTIMES_ENABLE_FORTRAN ON)
-        message(STATUS "Fortran support enabled using compiler's own modules")
-      else ()
-        message(STATUS "Fortran support disabled: Not passing smoke check")
-      endif ()
+      message(STATUS "Fortran support disabled: Not passing smoke check")
     endif ()
-  else ()
-    message(STATUS "Fortran support disabled: not enabled in CMake; Use CMAKE_Fortran_COMPILER_WORKS=yes if the issues is missing builtin modules")
   endif ()
+else ()
+  message(STATUS "Fortran support disabled: not enabled in CMake; Use CMAKE_Fortran_COMPILER_WORKS=yes if the issues is missing builtin modules")
 endif ()
 
 
@@ -143,10 +177,6 @@ option(RUNTIMES_ENABLE_FLANG_MODULES "Make Fortran .mod files available to Flang
 
 
 # Determine the paths for Fortran .mod files.
-#
-# Sets:
-#  * RUNTIMES_OUTPUT_RESOURCE_MOD_DIR   Path for .mod files in build dir
-#  * RUNTIMES_INSTALL_RESOURCE_MOD_PATH Path for .mod files in install dir, relative to CMAKE_INSTALL_PREFIX
 if (RUNTIMES_ENABLE_FLANG_MODULES)
   # Flang expects its builtin modules in Clang's resource directory.
   get_toolchain_module_subdir(toolchain_mod_subdir)
@@ -167,7 +197,7 @@ else ()
   # If Flang modules are disabled (e.g. because the compiler is not Flang), avoid the risk of Flang accidentally picking them up.
   extend_path(RUNTIMES_OUTPUT_RESOURCE_MOD_DIR "${CMAKE_CURRENT_BINARY_DIR}" "finclude-${CMAKE_Fortran_COMPILER_ID}")
 
-  # We don't know how to install non-Flang modules
+  # We don't know how to install modules for other compilers. Do not install them at all.
   set(RUNTIMES_INSTALL_RESOURCE_MOD_PATH "")
 endif ()
 cmake_path(NORMAL_PATH RUNTIMES_OUTPUT_RESOURCE_MOD_DIR)

>From 632befc26c9abf2d138804cf9d099dec3f14d5bf Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Mon, 20 Apr 2026 19:26:36 +0200
Subject: [PATCH 51/53] Can assume non-empty RUNTIMES_FORTRAN_BUILD_DEPS

---
 openmp/module/CMakeLists.txt | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/openmp/module/CMakeLists.txt b/openmp/module/CMakeLists.txt
index 172b3cc1fd4b0..82f8d8b4384b7 100644
--- a/openmp/module/CMakeLists.txt
+++ b/openmp/module/CMakeLists.txt
@@ -27,9 +27,7 @@ if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
 endif ()
 
 flang_module_target(libomp-mod PUBLIC)
-if (RUNTIMES_FORTRAN_BUILD_DEPS)
-  add_dependencies(libomp-mod ${RUNTIMES_FORTRAN_BUILD_DEPS})
-endif ()
+add_dependencies(libomp-mod ${RUNTIMES_FORTRAN_BUILD_DEPS})
 
 install(FILES
   "${CMAKE_CURRENT_BINARY_DIR}/../runtime/src/omp_lib.h"

>From decaab30840f1228caaa8e2e29080dad732dc4ef Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Tue, 21 Apr 2026 17:37:49 +0200
Subject: [PATCH 52/53] Apply suggestions from code review

Co-authored-by: Matt Arsenault <arsenm2 at gmail.com>
---
 clang/lib/Driver/Driver.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 83740f922234f..dfc06baa3d495 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -6755,13 +6755,13 @@ 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 instrinsic modules
+  // 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(Twine(P)))
+      if (llvm::sys::fs::exists(P))
         return std::string(P);
     }
   }

>From bd9903bc63b099f78af8198d5af36b04047bfa75 Mon Sep 17 00:00:00 2001
From: Michael Kruse <llvm-project at meinersbur.de>
Date: Thu, 23 Apr 2026 20:06:06 +0200
Subject: [PATCH 53/53] Restore hiding module files deep in the build directory

Leaving up to CMake still clashed building the same source using
multiple targets.
---
 runtimes/cmake/config-Fortran.cmake | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/runtimes/cmake/config-Fortran.cmake b/runtimes/cmake/config-Fortran.cmake
index 247662cdbe1f5..795191d90830f 100644
--- a/runtimes/cmake/config-Fortran.cmake
+++ b/runtimes/cmake/config-Fortran.cmake
@@ -261,7 +261,15 @@ function (flang_module_target tgtname)
         Fortran_MODULE_DIRECTORY "${RUNTIMES_OUTPUT_RESOURCE_MOD_DIR}"
     )
   else ()
-    # Keep non-public modules where CMake would put them normally;
-    # Modules of different target must not overwrite each other.
+    # Modules of different targets must not overwrite each other.
+    # Ideally, we would use $<TARGET_PROPERTY:${tgtname},BINARY_DIR> but
+    # Fortran_MODULE_DIRECTORY does not support generator expressions.
+    # Not defining Fortran_MODULE_DIRECTORY at all would but it into
+    # ${CMAKE_CURRENT_BINARY_DIR} where modules with the same name but compiled
+    # by different targets would clash.
+    set_target_properties(${tgtname}
+      PROPERTIES
+        Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${tgtname}.dir/${CMAKE_CFG_INTDIR}"
+    )
   endif ()
 endfunction ()



More information about the libcxx-commits mailing list