[clang] 6403287 - [Flang] [FlangRT] Introduce FlangRT project as solution to Flang's runtime LLVM integration

Mark Danial via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 30 09:54:37 PDT 2023


Author: Paul Scoropan
Date: 2023-09-30T12:35:33-04:00
New Revision: 6403287eff71a3d6f6c862346d6ed3f0f000eb70

URL: https://github.com/llvm/llvm-project/commit/6403287eff71a3d6f6c862346d6ed3f0f000eb70
DIFF: https://github.com/llvm/llvm-project/commit/6403287eff71a3d6f6c862346d6ed3f0f000eb70.diff

LOG: [Flang] [FlangRT] Introduce FlangRT project as solution to Flang's runtime LLVM integration

See discourse thread https://discourse.llvm.org/t/rfc-support-cmake-option-to-control-link-type-built-for-flang-runtime-libraries/71602/18 for full details.

Flang-rt is the new library target for the flang runtime libraries. It builds the Flang-rt library (which contains the sources of FortranRuntime and FortranDecimal) and the Fortran_main library. See documentation in this patch for detailed description (flang-rt/docs/GettingStarted.md).

This patch aims to:
- integrate Flang's runtime into existing llvm infrasturcture so that Flang's runtime can be built similarly to other runtimes via the runtimes target or via the llvm target as an enabled runtime
- decouple the FortranDecimal library sources that were used by both compiler and runtime so that different build configurations can be applied for compiler vs runtime
- add support for running flang-rt testsuites, which were created by migrating relevant tests from `flang/test` and `flang/unittest` to `flang-rt/test` and `flang-rt/unittest`, using a new `check-flang-rt` target.
- provide documentation on how to build and use the new FlangRT runtime

Reviewed By: DanielCChen

Differential Revision: https://reviews.llvm.org/D154869

Added: 
    flang-rt/CMakeLists.txt
    flang-rt/docs/GettingStarted.md
    flang-rt/test/CMakeLists.txt
    flang-rt/test/FortranRuntime/no-cpp-dep.c
    flang-rt/test/NonGtestUnit/lit.cfg.py
    flang-rt/test/NonGtestUnit/lit.site.cfg.py.in
    flang-rt/test/Unit/lit.cfg.py
    flang-rt/test/Unit/lit.site.cfg.py.in
    flang-rt/test/lit.cfg.py
    flang-rt/test/lit.site.cfg.py.in
    flang-rt/unittests/CMakeLists.txt
    flang-rt/unittests/FortranEvaluate/CMakeLists.txt
    flang-rt/unittests/FortranEvaluate/ISO-Fortran-binding.cpp
    flang-rt/unittests/FortranEvaluate/reshape.cpp
    flang-rt/unittests/FortranEvaluate/testing.cpp
    flang-rt/unittests/FortranEvaluate/testing.h
    flang-rt/unittests/FortranRuntime/Allocatable.cpp
    flang-rt/unittests/FortranRuntime/ArrayConstructor.cpp
    flang-rt/unittests/FortranRuntime/BufferTest.cpp
    flang-rt/unittests/FortranRuntime/CMakeLists.txt
    flang-rt/unittests/FortranRuntime/CharacterTest.cpp
    flang-rt/unittests/FortranRuntime/CommandTest.cpp
    flang-rt/unittests/FortranRuntime/Complex.cpp
    flang-rt/unittests/FortranRuntime/CrashHandlerFixture.cpp
    flang-rt/unittests/FortranRuntime/CrashHandlerFixture.h
    flang-rt/unittests/FortranRuntime/Derived.cpp
    flang-rt/unittests/FortranRuntime/ExternalIOTest.cpp
    flang-rt/unittests/FortranRuntime/Format.cpp
    flang-rt/unittests/FortranRuntime/Inquiry.cpp
    flang-rt/unittests/FortranRuntime/ListInputTest.cpp
    flang-rt/unittests/FortranRuntime/LogicalFormatTest.cpp
    flang-rt/unittests/FortranRuntime/Matmul.cpp
    flang-rt/unittests/FortranRuntime/MatmulTranspose.cpp
    flang-rt/unittests/FortranRuntime/MiscIntrinsic.cpp
    flang-rt/unittests/FortranRuntime/Namelist.cpp
    flang-rt/unittests/FortranRuntime/Numeric.cpp
    flang-rt/unittests/FortranRuntime/NumericalFormatTest.cpp
    flang-rt/unittests/FortranRuntime/Pointer.cpp
    flang-rt/unittests/FortranRuntime/Ragged.cpp
    flang-rt/unittests/FortranRuntime/Random.cpp
    flang-rt/unittests/FortranRuntime/Reduction.cpp
    flang-rt/unittests/FortranRuntime/RuntimeCrashTest.cpp
    flang-rt/unittests/FortranRuntime/Stop.cpp
    flang-rt/unittests/FortranRuntime/TemporaryStack.cpp
    flang-rt/unittests/FortranRuntime/Time.cpp
    flang-rt/unittests/FortranRuntime/Transformational.cpp
    flang-rt/unittests/FortranRuntime/tools.h

Modified: 
    clang/lib/Driver/ToolChains/CommonArgs.cpp
    flang/CMakeLists.txt
    flang/cmake/modules/AddFlang.cmake
    flang/cmake/modules/FlangConfig.cmake.in
    flang/lib/Decimal/CMakeLists.txt
    flang/runtime/CMakeLists.txt
    flang/runtime/sum.cpp
    flang/test/CMakeLists.txt
    flang/test/Driver/linker-flags.f90
    flang/test/lit.cfg.py
    flang/tools/flang-driver/CMakeLists.txt
    flang/unittests/CMakeLists.txt
    flang/unittests/Evaluate/CMakeLists.txt
    flang/unittests/Optimizer/CMakeLists.txt
    lld/COFF/MinGW.cpp
    llvm/CMakeLists.txt
    llvm/projects/CMakeLists.txt
    llvm/runtimes/CMakeLists.txt
    runtimes/CMakeLists.txt

Removed: 
    flang/unittests/Evaluate/ISO-Fortran-binding.cpp
    flang/unittests/Evaluate/reshape.cpp
    flang/unittests/Runtime/Allocatable.cpp
    flang/unittests/Runtime/ArrayConstructor.cpp
    flang/unittests/Runtime/BufferTest.cpp
    flang/unittests/Runtime/CMakeLists.txt
    flang/unittests/Runtime/CharacterTest.cpp
    flang/unittests/Runtime/CommandTest.cpp
    flang/unittests/Runtime/Complex.cpp
    flang/unittests/Runtime/CrashHandlerFixture.cpp
    flang/unittests/Runtime/CrashHandlerFixture.h
    flang/unittests/Runtime/Derived.cpp
    flang/unittests/Runtime/ExternalIOTest.cpp
    flang/unittests/Runtime/Format.cpp
    flang/unittests/Runtime/Inquiry.cpp
    flang/unittests/Runtime/ListInputTest.cpp
    flang/unittests/Runtime/LogicalFormatTest.cpp
    flang/unittests/Runtime/Matmul.cpp
    flang/unittests/Runtime/MatmulTranspose.cpp
    flang/unittests/Runtime/MiscIntrinsic.cpp
    flang/unittests/Runtime/Namelist.cpp
    flang/unittests/Runtime/Numeric.cpp
    flang/unittests/Runtime/NumericalFormatTest.cpp
    flang/unittests/Runtime/Pointer.cpp
    flang/unittests/Runtime/Ragged.cpp
    flang/unittests/Runtime/Random.cpp
    flang/unittests/Runtime/Reduction.cpp
    flang/unittests/Runtime/RuntimeCrashTest.cpp
    flang/unittests/Runtime/Stop.cpp
    flang/unittests/Runtime/TemporaryStack.cpp
    flang/unittests/Runtime/Time.cpp
    flang/unittests/Runtime/Transformational.cpp
    flang/unittests/Runtime/tools.h


################################################################################
diff  --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 48170fa908fd62f..1ba031d42741cc4 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -969,29 +969,41 @@ void tools::addFortranRuntimeLibs(const ToolChain &TC,
                                   llvm::opt::ArgStringList &CmdArgs) {
   if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
     CmdArgs.push_back("Fortran_main.lib");
-    CmdArgs.push_back("FortranRuntime.lib");
-    CmdArgs.push_back("FortranDecimal.lib");
+    CmdArgs.push_back("flang-rt.lib");
   } else {
     CmdArgs.push_back("-lFortran_main");
-    CmdArgs.push_back("-lFortranRuntime");
-    CmdArgs.push_back("-lFortranDecimal");
+    CmdArgs.push_back("-lflang-rt");
   }
 }
 
 void tools::addFortranRuntimeLibraryPath(const ToolChain &TC,
                                          const llvm::opt::ArgList &Args,
                                          ArgStringList &CmdArgs) {
-  // Default to the <driver-path>/../lib directory. This works fine on the
-  // platforms that we have tested so far. We will probably have to re-fine
-  // this in the future. In particular, on some platforms, we may need to use
-  // lib64 instead of lib.
-  SmallString<256> DefaultLibPath =
+  // Default to the <driver-path>/../lib, <driver-path>/../flang-rt/lib, and
+  // <driver-path>/../runtimes/runtimes-bins/flang-rt/lib directories. This
+  // works fine on the platforms that we have tested so far. We will probably
+  // have to re-fine this in the future. In particular, on some platforms, we
+  // may need to use lib64 instead of lib.
+  SmallString<256> BuildLibPath =
+      llvm::sys::path::parent_path(TC.getDriver().Dir);
+  SmallString<256> FlangRTLibPath =
+      llvm::sys::path::parent_path(TC.getDriver().Dir);
+  SmallString<256> RuntimesLibPath =
       llvm::sys::path::parent_path(TC.getDriver().Dir);
-  llvm::sys::path::append(DefaultLibPath, "lib");
-  if (TC.getTriple().isKnownWindowsMSVCEnvironment())
-    CmdArgs.push_back(Args.MakeArgString("-libpath:" + DefaultLibPath));
-  else
-    CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath));
+  // Search path for Fortran_main and Flang-rt libraries.
+  llvm::sys::path::append(BuildLibPath, "lib");
+  llvm::sys::path::append(FlangRTLibPath, "flang-rt/lib");
+  llvm::sys::path::append(RuntimesLibPath,
+                          "runtimes/runtimes-bins/flang-rt/lib");
+  if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
+    CmdArgs.push_back(Args.MakeArgString("-libpath:" + BuildLibPath));
+    CmdArgs.push_back(Args.MakeArgString("-libpath:" + FlangRTLibPath));
+    CmdArgs.push_back(Args.MakeArgString("-libpath:" + RuntimesLibPath));
+  } else {
+    CmdArgs.push_back(Args.MakeArgString("-L" + BuildLibPath));
+    CmdArgs.push_back(Args.MakeArgString("-L" + FlangRTLibPath));
+    CmdArgs.push_back(Args.MakeArgString("-L" + RuntimesLibPath));
+  }
 }
 
 static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,

diff  --git a/flang-rt/CMakeLists.txt b/flang-rt/CMakeLists.txt
new file mode 100644
index 000000000000000..053869b8769e216
--- /dev/null
+++ b/flang-rt/CMakeLists.txt
@@ -0,0 +1,148 @@
+# CMake build for the Flang runtime libraries
+# The source for the flang runtime libraries (FortranDecimalRT, FortranRuntime)
+# exist in the flang top-level directory.
+# Flang-rt is only scaffolding and does not provide any additional source files.
+
+cmake_minimum_required(VERSION 3.20.0)
+
+#===============================================================================
+# Configure CMake
+#===============================================================================
+set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")
+include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake
+  NO_POLICY_SCOPE)
+
+set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/flang-rt/bin)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
+  ${CMAKE_BINARY_DIR}/flang-rt/lib)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
+  ${CMAKE_BINARY_DIR}/flang-rt/lib)
+set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_BINARY_DIR}/flang-rt)
+
+set(FLANG_RT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+set(FLANG_RT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+
+#===============================================================================
+# Setup Options and Defaults
+#===============================================================================
+option(FLANG_RT_ENABLE_SHARED "Build flang-rt as a shared library." OFF)
+option(FLANG_RT_ENABLE_STATIC "Build flang-rt as a static library." OFF)
+
+option(FLANG_RT_INCLUDE_TESTS
+    "Generate build targets for the Flang-rt unit tests." ${LLVM_INCLUDE_TESTS})
+
+# MLIR_DIR must be passed on invocation of flang-rt because it is needed for the Flang package.
+if(NOT DEFINED MLIR_DIR OR MLIR_DIR STREQUAL "")
+  message(FATAL_ERROR "MLIR_DIR must be set to the directory of the MLIRConfig cmake file in order to find the MLIR package.")
+endif()
+# Flang-rt requires a pre-built/installed version of flang that requires MLIR.
+find_package(MLIR REQUIRED HINTS "${MLIR_DIR}")
+
+# FLANG_DIR must be passed on invocation of flang-rt.
+if(NOT DEFINED FLANG_DIR OR FLANG_DIR STREQUAL "")
+  message(FATAL_ERROR "FLANG_DIR must be set to the directory of the FlangConfig cmake file in order to find the Flang package.")
+endif()
+# Flang-rt requires a pre-built/installed version of flang.
+# Flang-rt uses flang/Common headers.
+# Finding this package exposes FLANG_SOURCE_DIR, FLANG_BINARY_DIR, and FLANG_INCLUDE_DIRS to Flang-rt
+find_package(Flang REQUIRED HINTS "${FLANG_DIR}")
+# If the user specifies a relative path to LLVM_DIR, the calls to include
+# LLVM modules fail. Append the absolute path to LLVM_DIR instead.
+get_filename_component(FLANG_DIR_ABSOLUTE ${FLANG_DIR} REALPATH)
+list(APPEND CMAKE_MODULE_PATH ${FLANG_DIR_ABSOLUTE})
+
+set(LLVM_COMMON_CMAKE_UTILS "${FLANG_RT_SOURCE_DIR}/../cmake")
+set(LLVM_CMAKE_UTILS "${LLVM_BUILD_MAIN_SOURCE_DIR}/cmake")
+set(CLANG_CMAKE_UTILS "${FLANG_RT_SOURCE_DIR}/../clang/cmake")
+
+if (FLANG_RT_INCLUDE_TESTS)
+  # LLVM_DIR must be passed on invocation of flang-rt when tests are enabled.
+  if(NOT DEFINED LLVM_DIR OR LLVM_DIR STREQUAL "")
+    message(FATAL_ERROR "LLVM_DIR must be set to the directory of the LLVMConfig cmake file in order to find the LLVM package.")
+  endif()
+  # We need a pre-built/installed version of LLVM for gtest.
+  find_package(LLVM REQUIRED HINTS "${LLVM_DIR}")
+  # If the user specifies a relative path to LLVM_DIR, the calls to include
+  # LLVM modules fail. Append the absolute path to LLVM_DIR instead.
+  get_filename_component(LLVM_DIR_ABSOLUTE ${LLVM_DIR} REALPATH)
+  list(APPEND CMAKE_MODULE_PATH ${LLVM_DIR_ABSOLUTE})
+
+  add_compile_definitions(FLANG_RT_INCLUDE_TESTS=1)
+
+  if (DEFINED FLANG_BINARY_DIR)
+    set(FLANG_BINARY_DIR ${FLANG_BINARY_DIR} CACHE PATH "Path to the Flang build directory" FORCE)
+  else()
+    message(FATAL_ERROR "FLANG_BINARY_DIR must be defined or passed by the user when building tests.")
+  endif()
+  set(FLANG_RT_TEST_COMPILER ${FLANG_BINARY_DIR}/bin/flang-new
+      CACHE PATH "Compiler to use for testing")
+  set(FLANG_RT_GTEST_AVAIL 1)
+endif()
+
+# Add path for custom modules
+list(INSERT CMAKE_MODULE_PATH 0
+  "${FLANG_SOURCE_DIR}/cmake"
+  "${FLANG_SOURCE_DIR}/cmake/modules"
+  "${CLANG_CMAKE_UTILS}/modules"
+  "${LLVM_CMAKE_UTILS}/modules"
+)
+
+include(AddClang)
+include(AddFlang)
+include(TestBigEndian)
+test_big_endian(IS_BIGENDIAN)
+if (IS_BIGENDIAN)
+  add_compile_definitions(FLANG_BIG_ENDIAN=1)
+else ()
+  add_compile_definitions(FLANG_LITTLE_ENDIAN=1)
+endif ()
+
+# Flang's include directories are needed for flang/Common.
+include_directories(SYSTEM ${FLANG_INCLUDE_DIRS})
+
+# LLVM's include directories are needed for gtest.
+include_directories(SYSTEM ${LLVM_INCLUDE_DIRS})
+
+#===============================================================================
+# Add Subdirectories
+#===============================================================================
+set(FORTRAN_DECIMAL_SRC "${FLANG_SOURCE_DIR}/lib/Decimal")
+set(FORTRAN_RUNTIME_SRC "${FLANG_SOURCE_DIR}/runtime")
+set(FORTRAN_MAIN_SRC "${FLANG_SOURCE_DIR}/runtime/FortranMain")
+
+add_subdirectory(${FORTRAN_DECIMAL_SRC} FortranDecimalRT)
+add_subdirectory(${FORTRAN_RUNTIME_SRC} FortranRuntime)
+add_subdirectory(${FORTRAN_MAIN_SRC} FortranMain)
+
+if (FLANG_RT_INCLUDE_TESTS)
+  add_subdirectory(test)
+  if (FLANG_RT_GTEST_AVAIL)
+    add_subdirectory(unittests)
+  endif()
+endif()
+
+#===============================================================================
+# Create Flang-rt wrapper library
+#===============================================================================
+# Build as shared by default if no linkage type option set.
+if (NOT FLANG_RT_ENABLE_SHARED AND NOT FLANG_RT_ENABLE_STATIC)
+  add_library(flang-rt SHARED $<TARGET_OBJECTS:obj.FortranDecimalRT>
+                              $<TARGET_OBJECTS:obj.FortranRuntime>)
+endif()
+if (FLANG_RT_ENABLE_SHARED)
+  add_library(flang-rt SHARED $<TARGET_OBJECTS:obj.FortranDecimalRT>
+                              $<TARGET_OBJECTS:obj.FortranRuntime>)
+endif()
+if (FLANG_RT_ENABLE_STATIC AND NOT FLANG_RT_ENABLE_SHARED)
+  add_library(flang-rt STATIC $<TARGET_OBJECTS:obj.FortranDecimalRT>
+                              $<TARGET_OBJECTS:obj.FortranRuntime>)
+endif()
+# When building both static and shared, we need to append _static to the name
+# to avoid naming conflicts.
+if (FLANG_RT_ENABLE_STATIC AND FLANG_RT_ENABLE_SHARED)
+  add_library(flang-rt_static STATIC $<TARGET_OBJECTS:obj.FortranDecimalRT>
+                                     $<TARGET_OBJECTS:obj.FortranRuntime>)
+endif()

diff  --git a/flang-rt/docs/GettingStarted.md b/flang-rt/docs/GettingStarted.md
new file mode 100644
index 000000000000000..ffc721aa9b4a4c3
--- /dev/null
+++ b/flang-rt/docs/GettingStarted.md
@@ -0,0 +1,156 @@
+<!--===- docs/GettingStarted.md 
+  
+   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
+  
+-->
+
+# Flang-rt Runtime Library
+
+```eval_rst
+.. contents::
+   :local:
+```
+## What is Flang-rt
+Flang-rt is the runtime library project for Flang. The Flang driver requires
+the Fortran_main and Flang-rt libraries at runtime in order to generate
+user executables. Building this Flang-rt project will build both Fortran_main
+and the Flang-rt library, which is comprised of the FortranRuntime and
+FortranDecimalRT libraries.
+
+### Fortran_main
+Fortran_main is left out of the Flang-rt library because it is required to
+always be static unlike the link type of the Flang-rt library which can be
+configured. Fortran_main implements the main entry point into Fortran's
+`PROGRAM` in Flang by being the bridge between object files generated by Flang 
+and the C runtime that takes care of program set-up at system-level. For
+every Fortran `PROGRAM`, Flang generates the `_QQmain` function.
+Fortran_main implements the C `main` function that simply calls
+`_QQmain`.
+
+### FortranDecimalRT
+In order to decouple the common dependency between compiler and runtime,
+[FortranDecimal's sources](../../flang/lib/Decimal/CMakeLists.txt) are built
+separately for the compiler and the runtime. When the library is built for
+Flang-rt, the name FortranDecimalRT is used to avoid naming conflicts and
+confusion.
+
+### FortranRuntime
+This is the core runtime library in Flang-rt. The sources for this library
+currently still exist in the
+[Flang source directory](../../flang/runtime/CMakeLists.txt). We hope to
+migrate the sources to the Flang-rt directory in the future in order to further
+decouple the runtime from the Flang compiler.
+
+## Building Flang-rt
+Like other LLVM runtimes, Flang-rt can be built by targetting the
+[runtimes LLVM target](../../runtimes/CMakelists.txt). It can also be built
+when targetting the [llvm target](../../llvm/CMakeLists.txt) as an enabled
+runtime. Flang-rt will implicitly be added as an enabled runtime when Flang
+is an enabled project built by llvm. Flang-rt does not support standalone
+builds.
+
+In the future, we may be interested in supporting in optionally building
+Flang-rt when doing a Flang standalone build.
+
+### Building with the llvm target
+Assuming you are building Flang-rt to use with Flang, see
+[Flang's Getting Started guide](../../flang/docs/GettingStarted.md) for more
+information. To build Flang-rt when building the Flang compiler, once you have
+the llvm-project source ready, make a clean build directory. Let root be the
+root directory that you cloned llvm-project into.
+```bash
+cd root
+rm -rf build
+mkdir build
+cd build
+```
+Now invoke the cmake configuration command for llvm that would build Flang with
+Flang-rt.
+```bash
+cmake \
+  -G Ninja \
+  -DLLVM_ENABLE_RUNTIMES="compiler-rt;flang-rt" \
+  -DCMAKE_CXX_STANDARD=17 \
+  -DLLVM_INSTALL_UTILS=On \
+  # New Flang-rt flags for enabled link types
+  -DFLANG_RT_ENABLE_STATIC=On \
+  -DFLANG_RT_ENABLE_SHARED=On \
+  # We need to enable GTest if we want to run Flang-rt's testsuites
+  -DLLVM_INSTALL_GTEST=On \
+  -DFLANG_ENABLE_WERROR=On \
+  -DLLVM_LIT_ARGS=-v \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DLLVM_ENABLE_PROJECTS="clang;flang;lld;mlir;openmp" \
+  ../llvm-project/llvm
+```
+Flang requires other llvm projects (see LLVM_ENABLE_PROJECTS and the [Flang
+Getting Started Guide](../../flang/docs/GettingStarted.md) for more specifics
+on building Flang.
+
+By targetting the LLVM project, we are letting LLVM infrastructure handle
+invoking the runtimes target that will build Flang-rt. This includes finding
+the cmake packages for Clang, LLVM, Flang and MLIR that Flang-rt depends on.
+
+### Building with the runtimes target
+If you already have a pre-built/installed version of LLVM, Flang, Clang and
+MLIR, and would like to build Flang-rt without rebuilding the sources for these
+other projects. You can simply target the runtimes project directly and passing
+the paths to the directories of these files. If you built LLVM as we did above
+with default build directories, your runtimes invocation should look something
+like:
+```bash
+cd build
+BUILDDIR=`pwd`
+
+cmake \
+  -G Ninja \
+  -DCMAKE_CXX_STANDARD=17 \
+  # New Flang-rt flags for enabled link types
+  -DFLANG_RT_ENABLE_SHARED=On \
+  -DFLANG_RT_ENABLE_STATIC=On \
+  -DLLVM_LIT_ARGS=-v \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,$LD_LIBRARY_PATH" \
+  -DLLVM_TARGETS_TO_BUILD=host \
+  -DLLVM_EXTERNAL_LIT=$BUILD_DIR/bin/llvm-lit \
+  # We need to specify the paths to the cmake packages of the dependencies
+  -DLLVM_DIR=$BUILD_DIR/lib/cmake/llvm \
+  -DMLIR_DIR=$BUILD_DIR/lib/cmake/mlir \
+  -DFLANG_DIR=$BUILD_DIR/lib/cmake/flang \
+  -DLLVM_ENABLE_RUNTIMES="flang-rt" \
+  ../llvm-project/runtimes/
+```
+
+## Library locations
+When building the llvm target with flang as an enabled project, the Flang-rt
+library will be built to `$BUILDDIR/runtimes/runtimes-bins/flang-rt/lib`. When
+building the runtimes target with flang-rt as an enabled runtime, the libraries
+will be built to `$BUILDDIR/flang-rt/lib` by default. In either configuration,
+the Fortran_main library will be built to `$BUILDDIR/lib` by default.
+
+## Using Flang-rt
+The two build paths mentioned above get implicitly added as library paths at the
+invocation of the driver. If Flang-rt is a shared library, you must make the
+dynamic linker aware of where to look. One method to do so is to set the
+environment variable `LD_LIBRARY_PATH` include the path to Flang-rt's directory.
+
+## Options
+Flang-rt introduces 2 CMake options used to configure the library's link type:
+```
+option(FLANG_RT_ENABLE_SHARED "Build flang-rt as a shared library." OFF)
+option(FLANG_RT_ENABLE_STATIC "Build flang-rt as a static library." OFF)
+```
+Both can be specified if you want to build both shared and static versions of
+the Flang-rt runtime. If both are specified, the static library will be named
+Flang-rt_static.a to avoid naming conflicts, as per the LLVM standard.
+
+## Usage Examples
+```bash
+# Example of using Flang with the shared Flang-rt runtime
+# First we need to explicitly tell the dynamic linker where to find Flang-rt
+# since it was built as shared.
+$ $ export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$BUILDDIR/runtimes/runtimes-bins/flang-rt/lib"
+$ flang-new -ffree-form hello.f95 -o hello
+```

diff  --git a/flang-rt/test/CMakeLists.txt b/flang-rt/test/CMakeLists.txt
new file mode 100644
index 000000000000000..51cd6ddf864bc8a
--- /dev/null
+++ b/flang-rt/test/CMakeLists.txt
@@ -0,0 +1,73 @@
+# Test runner infrastructure for Flang-rt. This configures the Flang-rt test
+# trees for use by Lit, and delegates to LLVM's lit test handlers.
+
+llvm_canonicalize_cmake_booleans(
+  FLANG_STANDALONE_BUILD
+  LLVM_BUILD_EXAMPLES
+  LLVM_BYE_LINK_INTO_TOOLS
+  LLVM_ENABLE_PLUGINS
+)
+
+set(FLANG_TOOLS_DIR ${FLANG_BINARY_DIR}/bin)
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py
+  MAIN_CONFIG
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py
+  PATHS
+  ${PATHS_FOR_PLUGINS}
+)
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
+  ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py
+  MAIN_CONFIG
+  ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py
+)
+
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/NonGtestUnit/lit.site.cfg.py.in
+  ${CMAKE_CURRENT_BINARY_DIR}/NonGtestUnit/lit.site.cfg.py
+  MAIN_CONFIG
+  ${CMAKE_CURRENT_SOURCE_DIR}/NonGtestUnit/lit.cfg.py
+)
+
+set(FLANG_RT_TEST_PARAMS
+  flang_rt_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py)
+
+set(FLANG_RT_TEST_DEPENDS
+  LLVMSupport
+  flang-rt
+  Fortran_main
+)
+if (LLVM_ENABLE_PLUGINS AND NOT WIN32)
+  list(APPEND FLANG_RT_TEST_DEPENDS Bye)
+endif()
+
+if (FLANG_RT_INCLUDE_TESTS)
+  if (FLANG_RT_GTEST_AVAIL)
+    list(APPEND FLANG_RT_TEST_DEPENDS FlangRTUnitTests)
+  endif()
+endif()
+
+add_custom_target(flang-rt-test-depends DEPENDS ${FLANG_RT_TEST_DEPENDS})
+
+add_lit_testsuite(check-flang-rt "Running the Flang-rt regression tests"
+  ${CMAKE_CURRENT_BINARY_DIR}
+  PARAMS ${FLANG_RT_TEST_PARAMS}
+  DEPENDS ${FLANG_RT_TEST_DEPENDS}
+)
+set_target_properties(check-flang-rt PROPERTIES FOLDER "Tests")
+
+add_lit_testsuites(FLANG_RT ${CMAKE_CURRENT_SOURCE_DIR}
+  PARAMS ${FLANG_RT_TEST_PARAMS}
+  DEPENDS ${FLANG_RT_TEST_DEPENDS})
+
+# To modify the default target triple for flang-rt tests.
+if (DEFINED FLANG_RT_TEST_TARGET_TRIPLE)
+  if (NOT DEFINED LLVM_TARGET_TRIPLE_ENV OR LLVM_TARGET_TRIPLE_ENV STREQUAL "")
+    message(FATAL_ERROR "LLVM_TARGET_TRIPLE_ENV must also be defined in order "
+                        "to use FLANG_RT_TEST_TARGET_TRIPLE.")
+  endif()
+endif()

diff  --git a/flang-rt/test/FortranRuntime/no-cpp-dep.c b/flang-rt/test/FortranRuntime/no-cpp-dep.c
new file mode 100644
index 000000000000000..19c0260020b528b
--- /dev/null
+++ b/flang-rt/test/FortranRuntime/no-cpp-dep.c
@@ -0,0 +1,38 @@
+/*
+This test makes sure that flang's runtime does not depend on the C++ runtime
+library. It tries to link this simple file against libFortranRuntime.a with
+a C compiler.
+
+REQUIRES: c-compiler
+
+RUN: %cc -std=c99 %s -I%include %libruntime -lm -o /dev/null
+*/
+
+#include "flang/Runtime/entry-names.h"
+#include <stdint.h>
+
+/*
+Manually add declarations for the runtime functions that we want to make sure
+we're testing. We can't include any headers directly since they likely contain
+C++ code that would explode here.
+*/
+struct EnvironmentDefaultList;
+struct Descriptor;
+
+double RTNAME(CpuTime)();
+
+void RTNAME(ProgramStart)(
+    int, const char *[], const char *[], const struct EnvironmentDefaultList *);
+int32_t RTNAME(ArgumentCount)();
+int32_t RTNAME(GetCommandArgument)(int32_t, const struct Descriptor *,
+    const struct Descriptor *, const struct Descriptor *);
+int32_t RTNAME(GetEnvVariable)();
+
+int main() {
+  double x = RTNAME(CpuTime)();
+  RTNAME(ProgramStart)(0, 0, 0, 0);
+  int32_t c = RTNAME(ArgumentCount)();
+  int32_t v = RTNAME(GetCommandArgument)(0, 0, 0, 0);
+  int32_t e = RTNAME(GetEnvVariable)("FOO", 0, 0);
+  return x + c + v + e;
+}

diff  --git a/flang-rt/test/NonGtestUnit/lit.cfg.py b/flang-rt/test/NonGtestUnit/lit.cfg.py
new file mode 100644
index 000000000000000..32be1d27c8f28c3
--- /dev/null
+++ b/flang-rt/test/NonGtestUnit/lit.cfg.py
@@ -0,0 +1,22 @@
+import os
+
+import lit.Test
+
+config.name = "flang-rt-OldUnit"
+
+config.suffixes = [".test"]
+
+config.test_source_root = os.path.join(config.flang_rt_obj_root, "unittests")
+config.test_exec_root = config.test_source_root
+
+config.test_format = lit.formats.ExecutableTest()
+
+path = os.path.pathsep.join(
+    (
+        config.flang_rt_lib_dir,
+        config.flang_bin_dir,
+        config.flang_libs_dir,
+        config.environment.get("LD_LIBRARY_PATH", ""),
+    )
+)
+config.environment["LD_LIBRARY_PATH"] = path

diff  --git a/flang-rt/test/NonGtestUnit/lit.site.cfg.py.in b/flang-rt/test/NonGtestUnit/lit.site.cfg.py.in
new file mode 100644
index 000000000000000..83d8e0e04adf91b
--- /dev/null
+++ b/flang-rt/test/NonGtestUnit/lit.site.cfg.py.in
@@ -0,0 +1,23 @@
+ at LIT_SITE_CFG_IN_HEADER@
+
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_tools_dir = lit_config.substitute("@LLVM_TOOLS_DIR@")
+config.llvm_libs_dir = lit_config.substitute("@LLVM_LIBS_DIR@")
+config.llvm_build_mode = lit_config.substitute("@LLVM_BUILD_MODE@")
+config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
+config.flang_src_dir = "@FLANG_SOURCE_DIR@"
+config.flang_bin_dir = "@FLANG_BINARY_DIR@/bin"
+config.flang_libs_dir = "@FLANG_BINARY_DIR@/lib"
+config.flang_rt_obj_root = "@FLANG_RT_BINARY_DIR@"
+config.flang_tools_dir = lit_config.substitute("@FLANG_TOOLS_DIR@")
+config.flang_llvm_tools_dir = "@CMAKE_BINARY_DIR@/bin"
+config.flang_rt_src_dir = "@FLANG_RT_SOURCE_DIR@"
+config.flang_rt_lib_dir = "@FLANG_RT_BINARY_DIR@/lib"
+config.flang_rt_test_compiler = "@FLANG_RT_TEST_COMPILER@"
+config.flang_rt_test_triple = "@FLANG_RT_TEST_TARGET_TRIPLE@"
+config.target_triple = "@LLVM_TARGET_TRIPLE@"
+config.python_executable = "@Python3_EXECUTABLE@"
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@FLANG_RT_SOURCE_DIR@/test/NonGtestUnit/lit.cfg.py")

diff  --git a/flang-rt/test/Unit/lit.cfg.py b/flang-rt/test/Unit/lit.cfg.py
new file mode 100644
index 000000000000000..079516fc86d7aee
--- /dev/null
+++ b/flang-rt/test/Unit/lit.cfg.py
@@ -0,0 +1,58 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+import os
+import platform
+import re
+import subprocess
+import sys
+
+import lit.formats
+import lit.util
+
+from lit.llvm import llvm_config
+from lit.llvm.subst import ToolSubst
+from lit.llvm.subst import FindTool
+
+# name: The name of this test suite.
+config.name = "flang-rt-Unit"
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = []
+
+# test_source_root: The root path where unit test binaries are located.
+# test_exec_root: The root path where tests should be run.
+config.test_source_root = os.path.join(config.flang_rt_obj_root, "unittests")
+config.test_exec_root = config.test_source_root
+
+# testFormat: The test format to use to interpret tests.
+config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, "Tests")
+
+# Tweak the PATH to include the flang bin and libs dirs.
+path = os.path.pathsep.join(
+    (
+        config.flang_bin_dir,
+        config.llvm_tools_dir,
+        config.environment["PATH"]
+    )
+)
+config.environment["PATH"] = path
+
+path = os.path.pathsep.join(
+    (
+        config.flang_rt_lib_dir,
+        config.flang_libs_dir,
+        config.flang_bin_dir,
+        config.environment.get("LD_LIBRARY_PATH", ""),
+    )
+)
+config.environment["LD_LIBRARY_PATH"] = path
+
+# Propagate PYTHON_EXECUTABLE into the environment
+# config.environment['PYTHON_EXECUTABLE'] = sys.executable
+
+# To modify the default target triple for flang-rt tests.
+if config.flang_rt_test_triple:
+    config.target_triple = config.flang_rt_test_triple
+    config.environment[config.llvm_target_triple_env] = config.flang_rt_test_triple

diff  --git a/flang-rt/test/Unit/lit.site.cfg.py.in b/flang-rt/test/Unit/lit.site.cfg.py.in
new file mode 100644
index 000000000000000..4bd4bc40473d87d
--- /dev/null
+++ b/flang-rt/test/Unit/lit.site.cfg.py.in
@@ -0,0 +1,22 @@
+ at LIT_SITE_CFG_IN_HEADER@
+
+config.llvm_src_root = "@LLVM_SOURCE_DIR@"
+config.llvm_obj_root = "@LLVM_BINARY_DIR@"
+config.llvm_target_triple_env = "@LLVM_TARGET_TRIPLE_ENV@"
+config.llvm_tools_dir = lit_config.substitute("@LLVM_TOOLS_DIR@")
+config.llvm_build_mode = lit_config.substitute("@LLVM_BUILD_MODE@")
+config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
+config.flang_bin_dir = "@FLANG_BINARY_DIR@/bin"
+config.flang_src_dir = "@FLANG_SOURCE_DIR@"
+config.flang_libs_dir = "@FLANG_BINARY_DIR@/lib"
+config.flang_rt_obj_root = "@FLANG_RT_BINARY_DIR@"
+config.flang_rt_src_dir = "@FLANG_RT_SOURCE_DIR@"
+config.flang_rt_lib_dir = "@FLANG_RT_BINARY_DIR@/lib"
+config.flang_rt_test_compiler = "@FLANG_RT_TEST_COMPILER@"
+config.flang_rt_test_triple = "@FLANG_RT_TEST_TARGET_TRIPLE@"
+config.flang_tools_dir = lit_config.substitute("@FLANG_TOOLS_DIR@")
+config.target_triple = "@LLVM_TARGET_TRIPLE@"
+config.python_executable = "@Python3_EXECUTABLE@"
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@FLANG_RT_SOURCE_DIR@/test/Unit/lit.cfg.py")

diff  --git a/flang-rt/test/lit.cfg.py b/flang-rt/test/lit.cfg.py
new file mode 100644
index 000000000000000..97edd482c57c142
--- /dev/null
+++ b/flang-rt/test/lit.cfg.py
@@ -0,0 +1,173 @@
+# -*- Python -*-
+
+import os
+import platform
+import re
+import subprocess
+import sys
+
+import lit.formats
+import lit.util
+
+from lit.llvm import llvm_config
+from lit.llvm.subst import ToolSubst
+from lit.llvm.subst import FindTool
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = "flang-rt"
+
+# testFormat: The test format to use to interpret tests.
+#
+# For now we require '&&' between commands, until they get globally killed and
+# the test runner updated.
+config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = [
+    ".c",
+    ".cpp",
+    ".f",
+    ".F",
+    ".ff",
+    ".FOR",
+    ".for",
+    ".f77",
+    ".f90",
+    ".F90",
+    ".ff90",
+    ".f95",
+    ".F95",
+    ".ff95",
+    ".fpp",
+    ".FPP",
+    ".cuf",
+    ".CUF",
+    ".f18",
+    ".F18",
+    ".f03",
+    ".F03",
+    ".f08",
+    ".F08",
+    ".ll",
+    ".fir",
+    ".mlir",
+]
+
+config.substitutions.append(("%PATH%", config.environment["PATH"]))
+config.substitutions.append(("%pluginext", config.llvm_plugin_ext))
+
+llvm_config.use_default_substitutions()
+
+# ask llvm-config about asserts
+llvm_config.feature_config([("--assertion-mode", {"ON": "asserts"})])
+
+# Targets
+config.targets = frozenset(config.targets_to_build.split())
+for arch in config.targets_to_build.split():
+    config.available_features.add(arch.lower() + "-registered-target")
+
+# To modify the default target triple for flang-rt tests.
+if config.flang_rt_test_triple:
+    config.target_triple = config.flang_rt_test_triple
+    config.environment[config.llvm_target_triple_env] = config.flang_rt_test_triple
+
+# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
+# subdirectories contain auxiliary inputs for various tests in their parent
+# directories.
+config.excludes = ["Inputs", "CMakeLists.txt", "README.txt", "LICENSE.txt"]
+
+# Plugins (loadable modules)
+if config.has_plugins:
+    config.available_features.add("plugins")
+
+if config.linked_bye_extension:
+    config.substitutions.append(("%loadbye", ""))
+else:
+    config.substitutions.append(
+        (
+            "%loadbye",
+            "-fpass-plugin={}/Bye{}".format(
+                config.llvm_shlib_dir, config.llvm_plugin_ext
+            ),
+        )
+    )
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# test_exec_root: The root path where tests should be run.
+config.test_exec_root = os.path.join(config.flang_rt_obj_root, "test")
+
+llvm_config.with_environment("PATH", config.flang_bin_dir, append_path=True)
+llvm_config.with_environment("PATH", config.flang_rt_obj_root, append_path=True)
+llvm_config.with_environment("PATH", config.flang_libs_dir, append_path=True)
+llvm_config.with_environment("PATH", config.flang_rt_lib_dir, append_path=True)
+
+# For each occurrence of a flang tool name, replace it with the full path to
+# the build directory holding that tool.
+tools = [
+    ToolSubst("%flang", command=FindTool("flang-new"), unresolved="fatal"),
+    ToolSubst(
+        "%flang_fc1",
+        command=FindTool("flang-new"),
+        extra_args=["-fc1"],
+        unresolved="fatal",
+    ),
+]
+
+# Flang has several unimplemented features. TODO messages are used to mark
+# and fail if these features are exercised. Some TODOs exit with a non-zero
+# exit code, but others abort the execution in assert builds.
+# To catch aborts, the `--crash` option for the `not` command has to be used.
+tools.append(ToolSubst("%not_todo_cmd", command=FindTool("not"), unresolved="fatal"))
+if "asserts" in config.available_features:
+    tools.append(
+        ToolSubst(
+            "%not_todo_abort_cmd",
+            command=FindTool("not"),
+            extra_args=["--crash"],
+            unresolved="fatal",
+        )
+    )
+else:
+    tools.append(
+        ToolSubst("%not_todo_abort_cmd", command=FindTool("not"), unresolved="fatal")
+    )
+
+# Define some variables to help us test that the flang runtime doesn't depend on
+# the C++ runtime libraries. For this we need a C compiler. If for some reason
+# we don't have one, we can just disable the test.
+if config.cc:
+    libruntime_static = os.path.join(config.flang_rt_lib_dir, "libflang-rt.a")
+    libruntime_shared = os.path.join(config.flang_rt_lib_dir, "libflang-rt.so")
+    include = os.path.join(config.flang_src_dir, "include")
+
+    if (
+        os.path.isfile(libruntime_static)
+        and os.path.isdir(include)
+    ):
+        config.available_features.add("c-compiler")
+        tools.append(ToolSubst("%cc", command=config.cc, unresolved="fatal"))
+        tools.append(ToolSubst("%libruntime", command=libruntime_static, unresolved="fatal"))
+        tools.append(ToolSubst("%include", command=include, unresolved="fatal"))
+
+    elif (
+        os.path.isfile(libruntime_shared)
+        and os.path.isdir(include)
+    ):
+        config.available_features.add("c-compiler")
+        tools.append(ToolSubst("%cc", command=config.cc, unresolved="fatal"))
+        tools.append(ToolSubst("%libruntime", command=libruntime_shared, unresolved="fatal"))
+        tools.append(ToolSubst("%include", command=include, unresolved="fatal"))
+
+
+# Add all the tools and their substitutions (if applicable). Use the search paths provided for
+# finding the tools.
+llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir)
+
+# Enable libpgmath testing
+result = lit_config.params.get("LIBPGMATH")
+if result:
+    config.environment["LIBPGMATH"] = True

diff  --git a/flang-rt/test/lit.site.cfg.py.in b/flang-rt/test/lit.site.cfg.py.in
new file mode 100644
index 000000000000000..8a9873b1eabaf37
--- /dev/null
+++ b/flang-rt/test/lit.site.cfg.py.in
@@ -0,0 +1,31 @@
+ at LIT_SITE_CFG_IN_HEADER@
+
+import sys
+
+config.llvm_tools_dir = lit_config.substitute("@LLVM_TOOLS_DIR@")
+config.llvm_shlib_dir = lit_config.substitute(path(r"@SHLIBDIR@"))
+config.llvm_plugin_ext = "@LLVM_PLUGIN_EXT@"
+config.target_triple = "@LLVM_TARGET_TRIPLE@"
+config.llvm_target_triple_env = "@LLVM_TARGET_TRIPLE_ENV@"
+config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
+config.errc_messages = "@LLVM_LIT_ERRC_MESSAGES@"
+config.flang_src_dir = "@FLANG_SOURCE_DIR@"
+config.flang_bin_dir = "@FLANG_BINARY_DIR@/bin"
+config.flang_libs_dir = "@FLANG_BINARY_DIR@/lib"
+config.flang_tools_dir = lit_config.substitute("@FLANG_TOOLS_DIR@")
+config.flang_llvm_tools_dir = "@CMAKE_BINARY_DIR@/bin"
+config.flang_rt_obj_root = "@FLANG_RT_BINARY_DIR@"
+config.flang_rt_src_dir = "@FLANG_RT_SOURCE_DIR@"
+config.flang_rt_lib_dir = "@FLANG_RT_BINARY_DIR@/lib"
+config.flang_rt_test_triple = "@FLANG_RT_TEST_TARGET_TRIPLE@"
+config.python_executable = "@PYTHON_EXECUTABLE@"
+config.has_plugins = @LLVM_ENABLE_PLUGINS@
+config.linked_bye_extension = @LLVM_BYE_LINK_INTO_TOOLS@
+config.cc = "@CMAKE_C_COMPILER@"
+config.targets_to_build = "@TARGETS_TO_BUILD@"
+
+import lit.llvm
+lit.llvm.initialize(lit_config, config)
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@FLANG_RT_SOURCE_DIR@/test/lit.cfg.py")

diff  --git a/flang-rt/unittests/CMakeLists.txt b/flang-rt/unittests/CMakeLists.txt
new file mode 100644
index 000000000000000..2b813c6e16dfaa1
--- /dev/null
+++ b/flang-rt/unittests/CMakeLists.txt
@@ -0,0 +1,81 @@
+if (FLANG_EXPERIMENTAL_CUDA_RUNTIME)
+  # If Fortran runtime is built as CUDA library, the linking
+  # of targets that link FortranRuntime must be done
+  # with CUDA_RESOLVE_DEVICE_SYMBOLS.
+  # CUDA language must be enabled for CUDA_RESOLVE_DEVICE_SYMBOLS
+  # to take effect.
+  enable_language(CUDA)
+endif()
+
+add_custom_target(FlangRTUnitTests)
+set_target_properties(FlangRTUnitTests PROPERTIES FOLDER "Flang-rt Unit Tests")
+
+function(add_flang_rt_unittest_offload_properties target)
+  # Set CUDA_RESOLVE_DEVICE_SYMBOLS.
+  if (FLANG_EXPERIMENTAL_CUDA_RUNTIME)
+    set_target_properties(${target}
+      PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS ON
+      )
+  endif()
+  # Enable OpenMP offload during linking. We may need to replace
+  # LINK_OPTIONS with COMPILE_OPTIONS when there are OpenMP offload
+  # unittests.
+  #
+  # FIXME: replace 'native' in --offload-arch option with the list
+  #        of targets that Fortran Runtime was built for.
+  #        Common code must be moved from flang/runtime/CMakeLists.txt.
+  # TODO: Revisit this because of Flang-rt. runtime is no longer an added subdirectory of flang.
+  if (NOT FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD STREQUAL "off")
+    set_target_properties(${target}
+        PROPERTIES LINK_OPTIONS
+        "-fopenmp;--offload-arch=native"
+    )
+  endif()
+endfunction()
+
+if(NOT TARGET llvm_gtest)
+  message(FATAL_ERROR "Target llvm_gtest not found.")
+endif()
+
+function(add_flang_rt_unittest test_dirname)
+  add_unittest(FlangRTUnitTests ${test_dirname} ${ARGN})
+  add_flang_rt_unittest_offload_properties(${test_dirname})
+endfunction()
+
+if (CXX_SUPPORTS_SUGGEST_OVERRIDE_FLAG)
+  add_compile_options("-Wno-suggest-override")
+endif()
+
+function(add_flang_rt_nongtest_unittest test_name)
+  cmake_parse_arguments(ARG
+    "SLOW_TEST"
+    ""
+    ""
+    ${ARGN})
+
+  list(APPEND LLVM_COMPILE_FLAGS "-L${LLVM_BINARY_DIR}/lib")
+  if(ARG_SLOW_TEST)
+      set(suffix .slow)
+  else()
+      set(suffix .test)
+  endif()
+
+  add_executable(${test_name}${suffix} ${test_name}.cpp)
+
+  if (LLVM_LINK_LLVM_DYLIB AND NOT ARG_DISABLE_LLVM_LINK_LLVM_DYLIB)
+    set(llvm_libs LLVM)
+  else()
+    llvm_map_components_to_libnames(llvm_libs Support)
+  endif()
+  target_link_libraries(${test_name}${suffix} ${llvm_libs} ${ARG_UNPARSED_ARGUMENTS})
+
+  if(NOT ARG_SLOW_TEST)
+    add_dependencies(FlangRTUnitTests ${test_name}${suffix})
+  endif()
+
+  add_flang_rt_unittest_offload_properties(${test_name}${suffix})
+endfunction()
+
+add_subdirectory(FortranRuntime)
+# TODO: We may want to find a better location for these tests that use the runtime
+add_subdirectory(FortranEvaluate)

diff  --git a/flang-rt/unittests/FortranEvaluate/CMakeLists.txt b/flang-rt/unittests/FortranEvaluate/CMakeLists.txt
new file mode 100644
index 000000000000000..211018f5559da9b
--- /dev/null
+++ b/flang-rt/unittests/FortranEvaluate/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+add_library(FlangRTFortranEvaluateTesting
+  testing.cpp
+)
+if (LLVM_LINK_LLVM_DYLIB)
+  set(llvm_libs LLVM)
+else()
+  llvm_map_components_to_libnames(llvm_libs Support)
+endif()
+target_link_libraries(FlangRTFortranEvaluateTesting
+    ${llvm_libs})
+
+add_flang_rt_nongtest_unittest(reshape
+  FlangRTFortranEvaluateTesting
+  flang-rt
+)
+
+add_flang_rt_nongtest_unittest(ISO-Fortran-binding
+  FlangRTFortranEvaluateTesting
+  flang-rt
+)

diff  --git a/flang/unittests/Evaluate/ISO-Fortran-binding.cpp b/flang-rt/unittests/FortranEvaluate/ISO-Fortran-binding.cpp
similarity index 100%
rename from flang/unittests/Evaluate/ISO-Fortran-binding.cpp
rename to flang-rt/unittests/FortranEvaluate/ISO-Fortran-binding.cpp

diff  --git a/flang/unittests/Evaluate/reshape.cpp b/flang-rt/unittests/FortranEvaluate/reshape.cpp
similarity index 100%
rename from flang/unittests/Evaluate/reshape.cpp
rename to flang-rt/unittests/FortranEvaluate/reshape.cpp

diff  --git a/flang-rt/unittests/FortranEvaluate/testing.cpp b/flang-rt/unittests/FortranEvaluate/testing.cpp
new file mode 100644
index 000000000000000..cf0422f621c2fe5
--- /dev/null
+++ b/flang-rt/unittests/FortranEvaluate/testing.cpp
@@ -0,0 +1,128 @@
+#include "testing.h"
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+namespace testing {
+
+namespace {
+int passes{0};
+int failures{0};
+} // namespace
+
+static void BitBucket(const char *, ...) {}
+
+static void PrintFailureDetails(const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  fputs("\t", stderr);
+  vfprintf(stderr, format, ap);
+  va_end(ap);
+  fputc('\n', stderr);
+}
+
+FailureDetailPrinter Test(const char *file, int line, const char *predicate,
+                          bool pass) {
+  if (pass) {
+    ++passes;
+    return BitBucket;
+  } else {
+    ++failures;
+    fprintf(stderr, "%s:%d: FAIL: %s\n", file, line, predicate);
+    return PrintFailureDetails;
+  }
+}
+
+FailureDetailPrinter Match(const char *file, int line, std::uint64_t want,
+                           const char *gots, std::uint64_t got) {
+  if (want == got) {
+    ++passes;
+    return BitBucket;
+  } else {
+    ++failures;
+    fprintf(stderr, "%s:%d: FAIL: %s == 0x%jx, not 0x%jx\n", file, line, gots,
+            static_cast<std::uintmax_t>(got),
+            static_cast<std::uintmax_t>(want));
+    return PrintFailureDetails;
+  }
+}
+
+FailureDetailPrinter Match(const char *file, int line, const char *want,
+                           const char *gots, const std::string &got) {
+  if (want == got) {
+    ++passes;
+    return BitBucket;
+  } else {
+    ++failures;
+    fprintf(stderr, "%s:%d: FAIL: %s == \"%s\", not \"%s\"\n", file, line, gots,
+            got.data(), want);
+    return PrintFailureDetails;
+  }
+}
+
+FailureDetailPrinter Match(const char *file, int line, const std::string &want,
+                           const char *gots, const std::string &got) {
+  return Match(file, line, want.data(), gots, got);
+}
+
+FailureDetailPrinter Compare(const char *file, int line, const char *xs,
+                             const char *rel, const char *ys, std::uint64_t x,
+                             std::uint64_t y) {
+  while (*rel == ' ') {
+    ++rel;
+  }
+  bool pass{false};
+  if (*rel == '<') {
+    if (rel[1] == '=') {
+      pass = x <= y;
+    } else {
+      pass = x < y;
+    }
+  } else if (*rel == '>') {
+    if (rel[1] == '=') {
+      pass = x >= y;
+    } else {
+      pass = x > y;
+    }
+  } else if (*rel == '=') {
+    pass = x == y;
+  } else if (*rel == '!') {
+    pass = x != y;
+  }
+  if (pass) {
+    ++passes;
+    return BitBucket;
+  } else {
+    ++failures;
+    fprintf(stderr, "%s:%d: FAIL: %s[0x%jx] %s %s[0x%jx]\n", file, line, xs,
+            static_cast<std::uintmax_t>(x), rel, ys,
+            static_cast<std::uintmax_t>(y));
+    return PrintFailureDetails;
+  }
+}
+
+int Complete() {
+  if (failures == 0) {
+    if (passes == 1) {
+      fprintf(stdout, "single test PASSES\n");
+    } else {
+      fprintf(stdout, "all %d tests PASS\n", passes);
+    }
+    passes = 0;
+    return EXIT_SUCCESS;
+  } else {
+    if (passes == 1) {
+      fprintf(stderr, "1 test passes, ");
+    } else {
+      fprintf(stderr, "%d tests pass, ", passes);
+    }
+    if (failures == 1) {
+      fprintf(stderr, "1 test FAILS\n");
+    } else {
+      fprintf(stderr, "%d tests FAIL\n", failures);
+    }
+    passes = failures = 0;
+    return EXIT_FAILURE;
+  }
+}
+} // namespace testing

diff  --git a/flang-rt/unittests/FortranEvaluate/testing.h b/flang-rt/unittests/FortranEvaluate/testing.h
new file mode 100644
index 000000000000000..e4c8dc93f9be0c8
--- /dev/null
+++ b/flang-rt/unittests/FortranEvaluate/testing.h
@@ -0,0 +1,37 @@
+#ifndef FORTRAN_EVALUATE_TESTING_H_
+#define FORTRAN_EVALUATE_TESTING_H_
+
+#include <cinttypes>
+#include <string>
+
+namespace testing {
+
+// Returns EXIT_SUCCESS or EXIT_FAILURE, so a test's main() should end
+// with "return testing::Complete()".
+int Complete();
+
+// Pass/fail testing.  These macros return a pointer to a printf-like
+// function that can be optionally called to print more detail, e.g.
+//   COMPARE(x, ==, y)("z is 0x%llx", z);
+// will also print z after the usual failure message if x != y.
+#define TEST(predicate)                                                        \
+  testing::Test(__FILE__, __LINE__, #predicate, (predicate))
+#define MATCH(want, got) testing::Match(__FILE__, __LINE__, (want), #got, (got))
+#define COMPARE(x, rel, y)                                                     \
+  testing::Compare(__FILE__, __LINE__, #x, #rel, #y, (x), (y))
+
+// Functions called by these macros; do not call directly.
+using FailureDetailPrinter = void (*)(const char *, ...);
+FailureDetailPrinter Test(const char *file, int line, const char *predicate,
+                          bool pass);
+FailureDetailPrinter Match(const char *file, int line, std::uint64_t want,
+                           const char *gots, std::uint64_t got);
+FailureDetailPrinter Match(const char *file, int line, const char *want,
+                           const char *gots, const std::string &got);
+FailureDetailPrinter Match(const char *file, int line, const std::string &want,
+                           const char *gots, const std::string &got);
+FailureDetailPrinter Compare(const char *file, int line, const char *xs,
+                             const char *rel, const char *ys, std::uint64_t x,
+                             std::uint64_t y);
+} // namespace testing
+#endif // FORTRAN_EVALUATE_TESTING_H_

diff  --git a/flang/unittests/Runtime/Allocatable.cpp b/flang-rt/unittests/FortranRuntime/Allocatable.cpp
similarity index 100%
rename from flang/unittests/Runtime/Allocatable.cpp
rename to flang-rt/unittests/FortranRuntime/Allocatable.cpp

diff  --git a/flang/unittests/Runtime/ArrayConstructor.cpp b/flang-rt/unittests/FortranRuntime/ArrayConstructor.cpp
similarity index 100%
rename from flang/unittests/Runtime/ArrayConstructor.cpp
rename to flang-rt/unittests/FortranRuntime/ArrayConstructor.cpp

diff  --git a/flang/unittests/Runtime/BufferTest.cpp b/flang-rt/unittests/FortranRuntime/BufferTest.cpp
similarity index 82%
rename from flang/unittests/Runtime/BufferTest.cpp
rename to flang-rt/unittests/FortranRuntime/BufferTest.cpp
index 0632324b25d22ea..ce905b254a27e80 100644
--- a/flang/unittests/Runtime/BufferTest.cpp
+++ b/flang-rt/unittests/FortranRuntime/BufferTest.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "../../runtime/buffer.h"
+#include "flang/../../runtime/buffer.h"
 #include "CrashHandlerFixture.h"
 #include "gtest/gtest.h"
 #include <algorithm>
@@ -30,15 +30,16 @@ class Store : public FileFrame<Store, tinyBufferSize> {
   void set_expect(FileOffset to) { expect_ = to; }
 
   std::size_t Read(FileOffset at, char *to, std::size_t minBytes,
-      std::size_t maxBytes, IoErrorHandler &handler) {
+                   std::size_t maxBytes, IoErrorHandler &handler) {
     if (enforceSequence_ && at != expect_) {
       handler.SignalError("Read(%d,%d,%d) not at expected %d",
-          static_cast<int>(at), static_cast<int>(minBytes),
-          static_cast<int>(maxBytes), static_cast<int>(expect_));
+                          static_cast<int>(at), static_cast<int>(minBytes),
+                          static_cast<int>(maxBytes),
+                          static_cast<int>(expect_));
     } else if (at < 0 || at + minBytes > bytes_) {
       handler.SignalError("Read(%d,%d,%d) is out of bounds",
-          static_cast<int>(at), static_cast<int>(minBytes),
-          static_cast<int>(maxBytes));
+                          static_cast<int>(at), static_cast<int>(minBytes),
+                          static_cast<int>(maxBytes));
     }
     auto result{std::min<std::size_t>(maxBytes, bytes_ - at)};
     std::memcpy(to, &data_[at], result);
@@ -46,14 +47,14 @@ class Store : public FileFrame<Store, tinyBufferSize> {
     return result;
   }
   std::size_t Write(FileOffset at, const char *from, std::size_t bytes,
-      IoErrorHandler &handler) {
+                    IoErrorHandler &handler) {
     if (enforceSequence_ && at != expect_) {
       handler.SignalError("Write(%d,%d) not at expected %d",
-          static_cast<int>(at), static_cast<int>(bytes),
-          static_cast<int>(expect_));
+                          static_cast<int>(at), static_cast<int>(bytes),
+                          static_cast<int>(expect_));
     } else if (at < 0 || at + bytes > bytes_) {
       handler.SignalError("Write(%d,%d) is out of bounds", static_cast<int>(at),
-          static_cast<int>(bytes));
+                          static_cast<int>(bytes));
     }
     std::memcpy(&data_[at], from, bytes);
     expect_ = at + bytes;
@@ -70,8 +71,8 @@ class Store : public FileFrame<Store, tinyBufferSize> {
 inline int ChunkSize(int j, int most) {
   // 31, 1, 29, 3, 27, ...
   j %= tinyBufferSize;
-  auto chunk{static_cast<int>(
-      ((j % 2) ? j : (tinyBufferSize - 1 - j)) % tinyBufferSize)};
+  auto chunk{static_cast<int>(((j % 2) ? j : (tinyBufferSize - 1 - j)) %
+                              tinyBufferSize)};
   return std::min(chunk, most);
 }
 

diff  --git a/flang/unittests/Runtime/CMakeLists.txt b/flang-rt/unittests/FortranRuntime/CMakeLists.txt
similarity index 84%
rename from flang/unittests/Runtime/CMakeLists.txt
rename to flang-rt/unittests/FortranRuntime/CMakeLists.txt
index 23f02aa751246b0..3b03315794fcc27 100644
--- a/flang/unittests/Runtime/CMakeLists.txt
+++ b/flang-rt/unittests/FortranRuntime/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_flang_unittest(FlangRuntimeTests
+add_flang_rt_unittest(FortranRuntimeTests
   Allocatable.cpp
   ArrayConstructor.cpp
   BufferTest.cpp
@@ -29,7 +29,7 @@ add_flang_unittest(FlangRuntimeTests
   Transformational.cpp
 )
 
-target_link_libraries(FlangRuntimeTests
+target_link_libraries(FortranRuntimeTests
   PRIVATE
-  FortranRuntime
+  flang-rt
 )

diff  --git a/flang/unittests/Runtime/CharacterTest.cpp b/flang-rt/unittests/FortranRuntime/CharacterTest.cpp
similarity index 100%
rename from flang/unittests/Runtime/CharacterTest.cpp
rename to flang-rt/unittests/FortranRuntime/CharacterTest.cpp

diff  --git a/flang/unittests/Runtime/CommandTest.cpp b/flang-rt/unittests/FortranRuntime/CommandTest.cpp
similarity index 100%
rename from flang/unittests/Runtime/CommandTest.cpp
rename to flang-rt/unittests/FortranRuntime/CommandTest.cpp

diff  --git a/flang/unittests/Runtime/Complex.cpp b/flang-rt/unittests/FortranRuntime/Complex.cpp
similarity index 100%
rename from flang/unittests/Runtime/Complex.cpp
rename to flang-rt/unittests/FortranRuntime/Complex.cpp

diff  --git a/flang/unittests/Runtime/CrashHandlerFixture.cpp b/flang-rt/unittests/FortranRuntime/CrashHandlerFixture.cpp
similarity index 86%
rename from flang/unittests/Runtime/CrashHandlerFixture.cpp
rename to flang-rt/unittests/FortranRuntime/CrashHandlerFixture.cpp
index 811603337e6608c..1ce8bf826cf27ff 100644
--- a/flang/unittests/Runtime/CrashHandlerFixture.cpp
+++ b/flang-rt/unittests/FortranRuntime/CrashHandlerFixture.cpp
@@ -6,13 +6,13 @@
 //
 //===----------------------------------------------------------------------===//
 #include "CrashHandlerFixture.h"
-#include "../../runtime/terminator.h"
+#include "flang/../../runtime/terminator.h"
 #include <cstdarg>
 #include <cstdlib>
 
 // Replaces Fortran runtime's crash handler so we can verify the crash message
-[[noreturn]] static void CatchCrash(
-    const char *sourceFile, int sourceLine, const char *message, va_list &ap) {
+[[noreturn]] static void CatchCrash(const char *sourceFile, int sourceLine,
+                                    const char *message, va_list &ap) {
   char buffer[1000];
   std::vsnprintf(buffer, sizeof buffer, message, ap);
   va_end(ap);

diff  --git a/flang/unittests/Runtime/CrashHandlerFixture.h b/flang-rt/unittests/FortranRuntime/CrashHandlerFixture.h
similarity index 100%
rename from flang/unittests/Runtime/CrashHandlerFixture.h
rename to flang-rt/unittests/FortranRuntime/CrashHandlerFixture.h

diff  --git a/flang/unittests/Runtime/Derived.cpp b/flang-rt/unittests/FortranRuntime/Derived.cpp
similarity index 100%
rename from flang/unittests/Runtime/Derived.cpp
rename to flang-rt/unittests/FortranRuntime/Derived.cpp

diff  --git a/flang/unittests/Runtime/ExternalIOTest.cpp b/flang-rt/unittests/FortranRuntime/ExternalIOTest.cpp
similarity index 100%
rename from flang/unittests/Runtime/ExternalIOTest.cpp
rename to flang-rt/unittests/FortranRuntime/ExternalIOTest.cpp

diff  --git a/flang/unittests/Runtime/Format.cpp b/flang-rt/unittests/FortranRuntime/Format.cpp
similarity index 100%
rename from flang/unittests/Runtime/Format.cpp
rename to flang-rt/unittests/FortranRuntime/Format.cpp

diff  --git a/flang/unittests/Runtime/Inquiry.cpp b/flang-rt/unittests/FortranRuntime/Inquiry.cpp
similarity index 100%
rename from flang/unittests/Runtime/Inquiry.cpp
rename to flang-rt/unittests/FortranRuntime/Inquiry.cpp

diff  --git a/flang/unittests/Runtime/ListInputTest.cpp b/flang-rt/unittests/FortranRuntime/ListInputTest.cpp
similarity index 83%
rename from flang/unittests/Runtime/ListInputTest.cpp
rename to flang-rt/unittests/FortranRuntime/ListInputTest.cpp
index a4eba5283add68e..c855ed93ee4b01b 100644
--- a/flang/unittests/Runtime/ListInputTest.cpp
+++ b/flang-rt/unittests/FortranRuntime/ListInputTest.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CrashHandlerFixture.h"
-#include "../../runtime/io-error.h"
+#include "flang/../../runtime/io-error.h"
 #include "flang/Runtime/descriptor.h"
 #include "flang/Runtime/io-api.h"
 
@@ -36,15 +36,15 @@ TEST(InputTest, TestListInputAlphabet) {
   // Use _two_ input buffers and _three_ output buffers. Note the `3*` in the
   // _inputBuffers_.
   SetCharacter(inputBuffers[j++], maxInputBufferLength,
-      "3*'abcdefghijklmnopqrstuvwxyzABC");
-  SetCharacter(
-      inputBuffers[j++], maxInputBufferLength, "DEFGHIJKLMNOPQRSTUVWXYZ'");
+               "3*'abcdefghijklmnopqrstuvwxyzABC");
+  SetCharacter(inputBuffers[j++], maxInputBufferLength,
+               "DEFGHIJKLMNOPQRSTUVWXYZ'");
 
   StaticDescriptor<1> staticDescriptor;
   Descriptor &whole{staticDescriptor.descriptor()};
   SubscriptValue extent[]{numInputBuffers};
   whole.Establish(TypeCode{CFI_type_char}, maxInputBufferLength, &inputBuffers,
-      1, extent, CFI_attribute_pointer);
+                  1, extent, CFI_attribute_pointer);
   whole.Check();
   auto *cookie{IONAME(BeginInternalArrayListInput)(whole)};
 
@@ -79,7 +79,7 @@ TEST(InputTest, TestListInputIntegerList) {
   Descriptor &whole{staticDescriptor.descriptor()};
   SubscriptValue extent[]{numBuffers};
   whole.Establish(TypeCode{CFI_type_char}, maxBufferLength, &buffer, 1, extent,
-      CFI_attribute_pointer);
+                  CFI_attribute_pointer);
   whole.Check();
   auto *cookie{IONAME(BeginInternalArrayListInput)(whole)};
 
@@ -88,10 +88,10 @@ TEST(InputTest, TestListInputIntegerList) {
   // Negative numbers will be overwritten by _expectedOutput_, and positive
   // numbers will not be as their indices are "Null values" of the Fortran 2018
   // standard 13.10.3.2 in the format strings _buffer_
-  std::int64_t actualOutput[listInputLength]{
-      -1, -2, -3, -4, 5, -6, 7, -8, 9, 10};
-  const std::int64_t expectedOutput[listInputLength]{
-      1, 2, 3, 3, 5, 6, 7, 8, 9, 10};
+  std::int64_t actualOutput[listInputLength]{-1, -2, -3, -4, 5,
+                                             -6, 7,  -8, 9,  10};
+  const std::int64_t expectedOutput[listInputLength]{1, 2, 3, 3, 5,
+                                                     6, 7, 8, 9, 10};
   for (j = 0; j < listInputLength; ++j) {
     IONAME(InputInteger)(cookie, actualOutput[j]);
   }
@@ -116,7 +116,7 @@ TEST(InputTest, TestListInputInvalidFormatWithSingleSuccess) {
   Descriptor &whole{staticDescriptor.descriptor()};
   SubscriptValue extent[]{numBuffers};
   whole.Establish(TypeCode{CFI_type_char}, formatBuffer.size(),
-      formatBuffer.data(), 1, extent, CFI_attribute_pointer);
+                  formatBuffer.data(), 1, extent, CFI_attribute_pointer);
   whole.Check();
 
   auto *cookie{IONAME(BeginInternalArrayListInput)(whole)};
@@ -127,7 +127,7 @@ TEST(InputTest, TestListInputInvalidFormatWithSingleSuccess) {
 
   // Perform failing InputInteger
   ASSERT_DEATH(IONAME(InputInteger)(cookie, dummy),
-      "Bad character 'g' in INTEGER input field");
+               "Bad character 'g' in INTEGER input field");
 }
 
 // Same test as _TestListInputInvalidFormatWithSingleSuccess_, however no
@@ -140,7 +140,7 @@ TEST(InputTest, TestListInputInvalidFormat) {
   Descriptor &whole{staticDescriptor.descriptor()};
   SubscriptValue extent[]{numBuffers};
   whole.Establish(TypeCode{CFI_type_char}, formatBuffer.size(),
-      formatBuffer.data(), 1, extent, CFI_attribute_pointer);
+                  formatBuffer.data(), 1, extent, CFI_attribute_pointer);
   whole.Check();
 
   auto *cookie{IONAME(BeginInternalArrayListInput)(whole)};
@@ -148,7 +148,7 @@ TEST(InputTest, TestListInputInvalidFormat) {
 
   // Perform failing InputInteger
   ASSERT_DEATH(IONAME(InputInteger)(cookie, dummy),
-      "Bad character 'g' in INTEGER input field");
+               "Bad character 'g' in INTEGER input field");
 }
 
 using ParamTy = std::tuple<std::string, std::vector<int>>;
@@ -163,7 +163,7 @@ TEST_P(SimpleListInputTest, TestListInput) {
   Descriptor &whole{staticDescriptor.descriptor()};
   SubscriptValue extent[]{numBuffers};
   whole.Establish(TypeCode{CFI_type_char}, formatBuffer.size(),
-      formatBuffer.data(), 1, extent, CFI_attribute_pointer);
+                  formatBuffer.data(), 1, extent, CFI_attribute_pointer);
   whole.Check();
   auto *cookie{IONAME(BeginInternalArrayListInput)(whole)};
 
@@ -185,9 +185,10 @@ TEST_P(SimpleListInputTest, TestListInput) {
   }
 }
 
-INSTANTIATE_TEST_SUITE_P(SimpleListInputTestInstantiation, SimpleListInputTest,
+INSTANTIATE_TEST_SUITE_P(
+    SimpleListInputTestInstantiation, SimpleListInputTest,
     testing::Values(std::make_tuple("", std::vector<int>{}),
-        std::make_tuple("0", std::vector<int>{}),
-        std::make_tuple("1", std::vector<int>{1}),
-        std::make_tuple("1, 2", std::vector<int>{1, 2}),
-        std::make_tuple("3*2", std::vector<int>{2, 2, 2})));
+                    std::make_tuple("0", std::vector<int>{}),
+                    std::make_tuple("1", std::vector<int>{1}),
+                    std::make_tuple("1, 2", std::vector<int>{1, 2}),
+                    std::make_tuple("3*2", std::vector<int>{2, 2, 2})));

diff  --git a/flang/unittests/Runtime/LogicalFormatTest.cpp b/flang-rt/unittests/FortranRuntime/LogicalFormatTest.cpp
similarity index 100%
rename from flang/unittests/Runtime/LogicalFormatTest.cpp
rename to flang-rt/unittests/FortranRuntime/LogicalFormatTest.cpp

diff  --git a/flang/unittests/Runtime/Matmul.cpp b/flang-rt/unittests/FortranRuntime/Matmul.cpp
similarity index 100%
rename from flang/unittests/Runtime/Matmul.cpp
rename to flang-rt/unittests/FortranRuntime/Matmul.cpp

diff  --git a/flang/unittests/Runtime/MatmulTranspose.cpp b/flang-rt/unittests/FortranRuntime/MatmulTranspose.cpp
similarity index 100%
rename from flang/unittests/Runtime/MatmulTranspose.cpp
rename to flang-rt/unittests/FortranRuntime/MatmulTranspose.cpp

diff  --git a/flang/unittests/Runtime/MiscIntrinsic.cpp b/flang-rt/unittests/FortranRuntime/MiscIntrinsic.cpp
similarity index 100%
rename from flang/unittests/Runtime/MiscIntrinsic.cpp
rename to flang-rt/unittests/FortranRuntime/MiscIntrinsic.cpp

diff  --git a/flang/unittests/Runtime/Namelist.cpp b/flang-rt/unittests/FortranRuntime/Namelist.cpp
similarity index 73%
rename from flang/unittests/Runtime/Namelist.cpp
rename to flang-rt/unittests/FortranRuntime/Namelist.cpp
index 5911d67f0d5fc44..2e3c5c2919297f1 100644
--- a/flang/unittests/Runtime/Namelist.cpp
+++ b/flang-rt/unittests/FortranRuntime/Namelist.cpp
@@ -6,11 +6,11 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "../../runtime/namelist.h"
+#include "flang/../../runtime/namelist.h"
 #include "CrashHandlerFixture.h"
-#include "tools.h"
 #include "flang/Runtime/descriptor.h"
 #include "flang/Runtime/io-api.h"
+#include "tools.h"
 #include <algorithm>
 #include <cinttypes>
 #include <complex>
@@ -27,7 +27,7 @@ struct NamelistTests : CrashHandlerFixture {};
 
 static void ClearDescriptorStorage(const Descriptor &descriptor) {
   std::memset(descriptor.raw().base_addr, 0,
-      descriptor.Elements() * descriptor.ElementBytes());
+              descriptor.Elements() * descriptor.ElementBytes());
 }
 
 TEST(NamelistTests, BasicSanity) {
@@ -38,17 +38,20 @@ TEST(NamelistTests, BasicSanity) {
   Descriptor &internalDesc{statDescs[0].descriptor()};
   SubscriptValue extent[]{numLines};
   internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/lineLength,
-      &buffer, 1, extent, CFI_attribute_pointer);
+                         &buffer, 1, extent, CFI_attribute_pointer);
   // Set up data arrays
   std::vector<int> ints;
   for (int j{0}; j < 20; ++j) {
     ints.push_back(j % 2 == 0 ? (1 << j) : -(1 << j));
   }
-  std::vector<double> reals{0.0, -0.0, std::numeric_limits<double>::infinity(),
-      -std::numeric_limits<double>::infinity(),
-      std::numeric_limits<double>::quiet_NaN(),
-      std::numeric_limits<double>::max(), std::numeric_limits<double>::lowest(),
-      std::numeric_limits<double>::epsilon()};
+  std::vector<double> reals{0.0,
+                            -0.0,
+                            std::numeric_limits<double>::infinity(),
+                            -std::numeric_limits<double>::infinity(),
+                            std::numeric_limits<double>::quiet_NaN(),
+                            std::numeric_limits<double>::max(),
+                            std::numeric_limits<double>::lowest(),
+                            std::numeric_limits<double>::epsilon()};
   std::vector<std::uint8_t> logicals;
   logicals.push_back(false);
   logicals.push_back(true);
@@ -76,12 +79,14 @@ TEST(NamelistTests, BasicSanity) {
   // Create a NAMELIST group
   static constexpr int items{5};
   const NamelistGroup::Item itemArray[items]{{"ints", *intDesc},
-      {"reals", *realDesc}, {"logicals", *logicalDesc},
-      {"complexes", *complexDesc}, {"characters", *characterDesc}};
+                                             {"reals", *realDesc},
+                                             {"logicals", *logicalDesc},
+                                             {"complexes", *complexDesc},
+                                             {"characters", *characterDesc}};
   const NamelistGroup group{"group1", items, itemArray};
   // Do an internal NAMELIST write and check results
-  auto outCookie1{IONAME(BeginInternalArrayListOutput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+  auto outCookie1{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0,
+                                                       __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(SetDelim)(outCookie1, "APOSTROPHE", 10));
   ASSERT_TRUE(IONAME(OutputNamelist)(outCookie1, group));
   auto outStatus1{IONAME(EndIoStatement)(outCookie1)};
@@ -109,14 +114,14 @@ TEST(NamelistTests, BasicSanity) {
   ClearDescriptorStorage(*logicalDesc);
   ClearDescriptorStorage(*complexDesc);
   ClearDescriptorStorage(*characterDesc);
-  auto inCookie{IONAME(BeginInternalArrayListInput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+  auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0,
+                                                    __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));
   auto inStatus{IONAME(EndIoStatement)(inCookie)};
   ASSERT_EQ(inStatus, 0) << "Failed namelist input sanity, status "
                          << static_cast<int>(inStatus);
-  auto outCookie2{IONAME(BeginInternalArrayListOutput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+  auto outCookie2{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0,
+                                                       __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(SetDelim)(outCookie2, "APOSTROPHE", 10));
   ASSERT_TRUE(IONAME(OutputNamelist)(outCookie2, group));
   auto outStatus2{IONAME(EndIoStatement)(outCookie2)};
@@ -139,18 +144,19 @@ TEST(NamelistTests, Subscripts) {
   StaticDescriptor<1, true> statDesc;
   Descriptor &internalDesc{statDesc.descriptor()};
   internalDesc.Establish(TypeCode{CFI_type_char},
-      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);
-  auto inCookie{IONAME(BeginInternalArrayListInput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+                         /*elementBytes=*/std::strlen(t1), t1, 0, nullptr,
+                         CFI_attribute_pointer);
+  auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0,
+                                                    __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));
   auto inStatus{IONAME(EndIoStatement)(inCookie)};
   ASSERT_EQ(inStatus, 0) << "Failed namelist input subscripts, status "
                          << static_cast<int>(inStatus);
   char out[40];
   internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,
-      out, 0, nullptr, CFI_attribute_pointer);
-  auto outCookie{IONAME(BeginInternalArrayListOutput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+                         out, 0, nullptr, CFI_attribute_pointer);
+  auto outCookie{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0,
+                                                      __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));
   auto outStatus{IONAME(EndIoStatement)(outCookie)};
   ASSERT_EQ(outStatus, 0)
@@ -177,8 +183,8 @@ TEST(NamelistTests, ShortArrayInput) {
   Descriptor &internalDesc{statDesc.descriptor()};
   SubscriptValue shape{2};
   internalDesc.Establish(1, 12, t1, 1, &shape, CFI_attribute_pointer);
-  auto inCookie{IONAME(BeginInternalArrayListInput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+  auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0,
+                                                    __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));
   auto inStatus{IONAME(EndIoStatement)(inCookie)};
   ASSERT_EQ(inStatus, 0) << "Failed namelist input subscripts, status "
@@ -198,17 +204,18 @@ TEST(NamelistTests, ScalarSubstring) {
   StaticDescriptor<1, true> statDesc;
   Descriptor &internalDesc{statDesc.descriptor()};
   internalDesc.Establish(TypeCode{CFI_type_char},
-      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);
-  auto inCookie{IONAME(BeginInternalArrayListInput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+                         /*elementBytes=*/std::strlen(t1), t1, 0, nullptr,
+                         CFI_attribute_pointer);
+  auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0,
+                                                    __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));
   ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)
       << "namelist scalar substring input";
   char out[32];
   internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,
-      out, 0, nullptr, CFI_attribute_pointer);
-  auto outCookie{IONAME(BeginInternalArrayListOutput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+                         out, 0, nullptr, CFI_attribute_pointer);
+  auto outCookie{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0,
+                                                      __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(SetDelim)(outCookie, "apostrophe", 10));
   ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));
   ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";
@@ -218,26 +225,27 @@ TEST(NamelistTests, ScalarSubstring) {
 }
 
 TEST(NamelistTests, ArraySubstring) {
-  OwningPtr<Descriptor> scDesc{
-      MakeArray<TypeCategory::Character, 1>(std::vector<int>{2},
-          std::vector<std::string>{"abcdefgh", "ijklmnop"}, 8)};
+  OwningPtr<Descriptor> scDesc{MakeArray<TypeCategory::Character, 1>(
+      std::vector<int>{2}, std::vector<std::string>{"abcdefgh", "ijklmnop"},
+      8)};
   const NamelistGroup::Item items[]{{"a", *scDesc}};
   const NamelistGroup group{"justa", 1, items};
   static char t1[]{"&justa A(:)(2:+5)='BCDE' 'JKLM'/"};
   StaticDescriptor<1, true> statDesc;
   Descriptor &internalDesc{statDesc.descriptor()};
   internalDesc.Establish(TypeCode{CFI_type_char},
-      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);
-  auto inCookie{IONAME(BeginInternalArrayListInput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+                         /*elementBytes=*/std::strlen(t1), t1, 0, nullptr,
+                         CFI_attribute_pointer);
+  auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0,
+                                                    __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));
   ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)
       << "namelist scalar substring input";
   char out[40];
   internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,
-      out, 0, nullptr, CFI_attribute_pointer);
-  auto outCookie{IONAME(BeginInternalArrayListOutput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+                         out, 0, nullptr, CFI_attribute_pointer);
+  auto outCookie{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0,
+                                                      __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(SetDelim)(outCookie, "apostrophe", 10));
   ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));
   ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";
@@ -256,17 +264,18 @@ TEST(NamelistTests, Skip) {
   StaticDescriptor<1, true> statDesc;
   Descriptor &internalDesc{statDesc.descriptor()};
   internalDesc.Establish(TypeCode{CFI_type_char},
-      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);
-  auto inCookie{IONAME(BeginInternalArrayListInput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+                         /*elementBytes=*/std::strlen(t1), t1, 0, nullptr,
+                         CFI_attribute_pointer);
+  auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0,
+                                                    __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));
   ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)
       << "namelist input with skipping";
   char out[20];
   internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,
-      out, 0, nullptr, CFI_attribute_pointer);
-  auto outCookie{IONAME(BeginInternalArrayListOutput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+                         out, 0, nullptr, CFI_attribute_pointer);
+  auto outCookie{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0,
+                                                      __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));
   ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";
   std::string got{out, sizeof out};
@@ -285,18 +294,19 @@ TEST(NamelistTests, Comma) {
   StaticDescriptor<1, true> statDesc;
   Descriptor &internalDesc{statDesc.descriptor()};
   internalDesc.Establish(TypeCode{CFI_type_char},
-      /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer);
-  auto inCookie{IONAME(BeginInternalArrayListInput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+                         /*elementBytes=*/std::strlen(t1), t1, 0, nullptr,
+                         CFI_attribute_pointer);
+  auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0,
+                                                    __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(SetDecimal)(inCookie, "COMMA", 5));
   ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group));
   ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk)
       << "namelist input with skipping";
   char out[30];
   internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out,
-      out, 0, nullptr, CFI_attribute_pointer);
-  auto outCookie{IONAME(BeginInternalArrayListOutput)(
-      internalDesc, nullptr, 0, __FILE__, __LINE__)};
+                         out, 0, nullptr, CFI_attribute_pointer);
+  auto outCookie{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0,
+                                                      __FILE__, __LINE__)};
   ASSERT_TRUE(IONAME(SetDecimal)(outCookie, "COMMA", 5));
   ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group));
   ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output";

diff  --git a/flang/unittests/Runtime/Numeric.cpp b/flang-rt/unittests/FortranRuntime/Numeric.cpp
similarity index 100%
rename from flang/unittests/Runtime/Numeric.cpp
rename to flang-rt/unittests/FortranRuntime/Numeric.cpp

diff  --git a/flang/unittests/Runtime/NumericalFormatTest.cpp b/flang-rt/unittests/FortranRuntime/NumericalFormatTest.cpp
similarity index 100%
rename from flang/unittests/Runtime/NumericalFormatTest.cpp
rename to flang-rt/unittests/FortranRuntime/NumericalFormatTest.cpp

diff  --git a/flang/unittests/Runtime/Pointer.cpp b/flang-rt/unittests/FortranRuntime/Pointer.cpp
similarity index 100%
rename from flang/unittests/Runtime/Pointer.cpp
rename to flang-rt/unittests/FortranRuntime/Pointer.cpp

diff  --git a/flang/unittests/Runtime/Ragged.cpp b/flang-rt/unittests/FortranRuntime/Ragged.cpp
similarity index 100%
rename from flang/unittests/Runtime/Ragged.cpp
rename to flang-rt/unittests/FortranRuntime/Ragged.cpp

diff  --git a/flang/unittests/Runtime/Random.cpp b/flang-rt/unittests/FortranRuntime/Random.cpp
similarity index 100%
rename from flang/unittests/Runtime/Random.cpp
rename to flang-rt/unittests/FortranRuntime/Random.cpp

diff  --git a/flang/unittests/Runtime/Reduction.cpp b/flang-rt/unittests/FortranRuntime/Reduction.cpp
similarity index 100%
rename from flang/unittests/Runtime/Reduction.cpp
rename to flang-rt/unittests/FortranRuntime/Reduction.cpp

diff  --git a/flang/unittests/Runtime/RuntimeCrashTest.cpp b/flang-rt/unittests/FortranRuntime/RuntimeCrashTest.cpp
similarity index 66%
rename from flang/unittests/Runtime/RuntimeCrashTest.cpp
rename to flang-rt/unittests/FortranRuntime/RuntimeCrashTest.cpp
index 34a8ff6d371131f..580ffe69f244801 100644
--- a/flang/unittests/Runtime/RuntimeCrashTest.cpp
+++ b/flang-rt/unittests/FortranRuntime/RuntimeCrashTest.cpp
@@ -11,10 +11,10 @@
 //
 //===----------------------------------------------------------------------===//
 #include "CrashHandlerFixture.h"
-#include "tools.h"
-#include "../../runtime/terminator.h"
+#include "flang/../../runtime/terminator.h"
 #include "flang/Runtime/io-api.h"
 #include "flang/Runtime/transformational.h"
+#include "tools.h"
 #include <gtest/gtest.h>
 
 using namespace Fortran::runtime;
@@ -26,7 +26,7 @@ using Fortran::common::TypeCategory;
 //------------------------------------------------------------------------------
 struct TestTerminator : CrashHandlerFixture {};
 
-#define TEST_CRASH_HANDLER_MESSAGE \
+#define TEST_CRASH_HANDLER_MESSAGE                                             \
   "Intentionally crashing runtime for unit test"
 
 TEST(TestTerminator, CrashTest) {
@@ -39,13 +39,13 @@ TEST(TestTerminator, CrashTest) {
 TEST(TestTerminator, CheckFailedLocationTest) {
   static Fortran::runtime::Terminator t;
   ASSERT_DEATH(t.CheckFailed("predicate", "someFileName", 789),
-      "RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(789\\)");
+               "RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(789\\)");
 }
 
 TEST(TestTerminator, CheckFailedTest) {
   static Fortran::runtime::Terminator t;
   ASSERT_DEATH(t.CheckFailed("predicate"),
-      "RUNTIME_CHECK\\(predicate\\) failed at \\(null\\)\\(0\\)");
+               "RUNTIME_CHECK\\(predicate\\) failed at \\(null\\)\\(0\\)");
 }
 
 //------------------------------------------------------------------------------
@@ -57,9 +57,10 @@ TEST(TestIOCrash, FormatDescriptorWriteMismatchTest) {
   static constexpr int bufferSize{4};
   static char buffer[bufferSize];
   static const char *format{"(A4)"};
-  auto *cookie{IONAME(BeginInternalFormattedOutput)(
-      buffer, bufferSize, format, std::strlen(format))};
-  ASSERT_DEATH(IONAME(OutputLogical)(cookie, true),
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format,
+                                                    std::strlen(format))};
+  ASSERT_DEATH(
+      IONAME(OutputLogical)(cookie, true),
       "Data edit descriptor 'A' may not be used with a LOGICAL data item");
 }
 
@@ -67,10 +68,10 @@ TEST(TestIOCrash, InvalidFormatCharacterTest) {
   static constexpr int bufferSize{1};
   static char buffer[bufferSize];
   static const char *format{"(C1)"};
-  auto *cookie{IONAME(BeginInternalFormattedOutput)(
-      buffer, bufferSize, format, std::strlen(format))};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format,
+                                                    std::strlen(format))};
   ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xfeedface),
-      "Unknown 'C' edit descriptor in FORMAT");
+               "Unknown 'C' edit descriptor in FORMAT");
 }
 
 //------------------------------------------------------------------------------
@@ -83,80 +84,80 @@ TEST(TestIOCrash, OverwriteBufferAsciiTest) {
   static constexpr int bufferSize{4};
   static char buffer[bufferSize];
   static const char *format{"(A4)"};
-  auto *cookie{IONAME(BeginInternalFormattedOutput)(
-      buffer, bufferSize, format, std::strlen(format))};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format,
+                                                    std::strlen(format))};
   IONAME(OutputAscii)(cookie, "four", bufferSize);
   ASSERT_DEATH(IONAME(OutputAscii)(cookie, "Too many characters!", 20),
-      "Internal write overran available records");
+               "Internal write overran available records");
 }
 
 TEST(TestIOCrash, OverwriteBufferCharacterTest) {
   static constexpr int bufferSize{1};
   static char buffer[bufferSize];
   static const char *format{"(A1)"};
-  auto *cookie{IONAME(BeginInternalFormattedOutput)(
-      buffer, bufferSize, format, std::strlen(format))};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format,
+                                                    std::strlen(format))};
   IONAME(OutputCharacter)(cookie, "a", 1);
   ASSERT_DEATH(IONAME(OutputCharacter)(cookie, "a", 1),
-      "Internal write overran available records");
+               "Internal write overran available records");
 }
 
 TEST(TestIOCrash, OverwriteBufferLogicalTest) {
   static constexpr int bufferSize{1};
   static char buffer[bufferSize];
   static const char *format{"(L1)"};
-  auto *cookie{IONAME(BeginInternalFormattedOutput)(
-      buffer, bufferSize, format, std::strlen(format))};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format,
+                                                    std::strlen(format))};
   IONAME(OutputLogical)(cookie, true);
   ASSERT_DEATH(IONAME(OutputLogical)(cookie, true),
-      "Internal write overran available records");
+               "Internal write overran available records");
 }
 
 TEST(TestIOCrash, OverwriteBufferRealTest) {
   static constexpr int bufferSize{1};
   static char buffer[bufferSize];
   static const char *format{"(F1)"};
-  auto *cookie{IONAME(BeginInternalFormattedOutput)(
-      buffer, bufferSize, format, std::strlen(format))};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format,
+                                                    std::strlen(format))};
   IONAME(OutputReal32)(cookie, 1.);
   EXPECT_DEATH(IONAME(OutputReal32)(cookie, 1.),
-      "Internal write overran available records");
+               "Internal write overran available records");
 
   std::memset(buffer, '\0', bufferSize);
-  cookie = IONAME(BeginInternalFormattedOutput)(
-      buffer, bufferSize, format, std::strlen(format));
+  cookie = IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format,
+                                                std::strlen(format));
   IONAME(OutputReal64)(cookie, 1.);
   EXPECT_DEATH(IONAME(OutputReal64)(cookie, 1.),
-      "Internal write overran available records");
+               "Internal write overran available records");
 }
 
 TEST(TestIOCrash, OverwriteBufferComplexTest) {
   static constexpr int bufferSize{8};
   static char buffer[bufferSize];
   static const char *format{"(Z1,Z1)"};
-  auto *cookie{IONAME(BeginInternalFormattedOutput)(
-      buffer, bufferSize, format, std::strlen(format))};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format,
+                                                    std::strlen(format))};
   IONAME(OutputComplex32)(cookie, 1., 1.);
   EXPECT_DEATH(IONAME(OutputComplex32)(cookie, 1., 1.),
-      "Internal write overran available records");
+               "Internal write overran available records");
 
   std::memset(buffer, '\0', bufferSize);
-  cookie = IONAME(BeginInternalFormattedOutput)(
-      buffer, bufferSize, format, std::strlen(format));
+  cookie = IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format,
+                                                std::strlen(format));
   IONAME(OutputComplex64)(cookie, 1., 1.);
   EXPECT_DEATH(IONAME(OutputComplex64)(cookie, 1., 1.),
-      "Internal write overran available records");
+               "Internal write overran available records");
 }
 
 TEST(TestIOCrash, OverwriteBufferIntegerTest) {
   static constexpr int bufferSize{1};
   static char buffer[bufferSize];
   static const char *format{"(I1)"};
-  auto *cookie{IONAME(BeginInternalFormattedOutput)(
-      buffer, bufferSize, format, std::strlen(format))};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format,
+                                                    std::strlen(format))};
   IONAME(OutputInteger64)(cookie, 0xdeadbeef);
   ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xdeadbeef),
-      "Internal write overran available records");
+               "Internal write overran available records");
 }
 
 //------------------------------------------------------------------------------
@@ -168,13 +169,15 @@ TEST(TestIntrinsicCrash, ConformityErrors) {
   // ARRAY(2,3) and MASK(2,4) should trigger a runtime error.
   auto array{MakeArray<TypeCategory::Integer, 4>(
       std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})};
-  auto mask{MakeArray<TypeCategory::Logical, 1>(std::vector<int>{2, 4},
-      std::vector<std::uint8_t>{
-          false, true, true, false, false, true, true, true})};
+  auto mask{MakeArray<TypeCategory::Logical, 1>(
+      std::vector<int>{2, 4},
+      std::vector<std::uint8_t>{false, true, true, false, false, true, true,
+                                true})};
   StaticDescriptor<1, true> statDesc;
   Descriptor &result{statDesc.descriptor()};
 
-  ASSERT_DEATH(RTNAME(Pack)(result, *array, *mask, nullptr, __FILE__, __LINE__),
+  ASSERT_DEATH(
+      RTNAME(Pack)(result, *array, *mask, nullptr, __FILE__, __LINE__),
       "Incompatible array arguments to PACK: dimension 2 of ARRAY= has extent "
       "3 but MASK= has extent 4");
 }

diff  --git a/flang/unittests/Runtime/Stop.cpp b/flang-rt/unittests/FortranRuntime/Stop.cpp
similarity index 54%
rename from flang/unittests/Runtime/Stop.cpp
rename to flang-rt/unittests/FortranRuntime/Stop.cpp
index b13602eaee5ea6b..1c5611dd396833c 100644
--- a/flang/unittests/Runtime/Stop.cpp
+++ b/flang-rt/unittests/FortranRuntime/Stop.cpp
@@ -11,7 +11,7 @@
 //===----------------------------------------------------------------------===//
 #include "flang/Runtime/stop.h"
 #include "CrashHandlerFixture.h"
-#include "../../runtime/environment.h"
+#include "flang/../../runtime/environment.h"
 #include <cstdlib>
 #include <gtest/gtest.h>
 
@@ -21,67 +21,69 @@ struct TestProgramEnd : CrashHandlerFixture {};
 
 TEST(TestProgramEnd, StopTest) {
   EXPECT_EXIT(RTNAME(StopStatement)(), testing::ExitedWithCode(EXIT_SUCCESS),
-      "Fortran STOP");
+              "Fortran STOP");
 }
 
 TEST(TestProgramEnd, StopTestNoStopMessage) {
   putenv(const_cast<char *>("NO_STOP_MESSAGE=1"));
-  Fortran::runtime::executionEnvironment.Configure(
-      0, nullptr, nullptr, nullptr);
-  EXPECT_EXIT(
-      RTNAME(StopStatement)(), testing::ExitedWithCode(EXIT_SUCCESS), "");
+  Fortran::runtime::executionEnvironment.Configure(0, nullptr, nullptr,
+                                                   nullptr);
+  EXPECT_EXIT(RTNAME(StopStatement)(), testing::ExitedWithCode(EXIT_SUCCESS),
+              "");
 }
 
 TEST(TestProgramEnd, StopMessageTest) {
   static const char *message{"bye bye"};
   EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message),
-                  /*isErrorStop=*/false, /*quiet=*/false),
-      testing::ExitedWithCode(EXIT_SUCCESS), "Fortran STOP: bye bye");
+                                        /*isErrorStop=*/false, /*quiet=*/false),
+              testing::ExitedWithCode(EXIT_SUCCESS), "Fortran STOP: bye bye");
 
   EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message),
-                  /*isErrorStop=*/false, /*quiet=*/true),
-      testing::ExitedWithCode(EXIT_SUCCESS), "");
+                                        /*isErrorStop=*/false, /*quiet=*/true),
+              testing::ExitedWithCode(EXIT_SUCCESS), "");
 
   EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message),
-                  /*isErrorStop=*/true, /*quiet=*/false),
-      testing::ExitedWithCode(EXIT_FAILURE), "Fortran ERROR STOP: bye bye");
+                                        /*isErrorStop=*/true, /*quiet=*/false),
+              testing::ExitedWithCode(EXIT_FAILURE),
+              "Fortran ERROR STOP: bye bye");
 
   EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message),
-                  /*isErrorStop=*/true, /*quiet=*/true),
-      testing::ExitedWithCode(EXIT_FAILURE), "");
+                                        /*isErrorStop=*/true, /*quiet=*/true),
+              testing::ExitedWithCode(EXIT_FAILURE), "");
 }
 
 TEST(TestProgramEnd, NoStopMessageTest) {
   putenv(const_cast<char *>("NO_STOP_MESSAGE=1"));
-  Fortran::runtime::executionEnvironment.Configure(
-      0, nullptr, nullptr, nullptr);
+  Fortran::runtime::executionEnvironment.Configure(0, nullptr, nullptr,
+                                                   nullptr);
   static const char *message{"bye bye"};
   EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message),
-                  /*isErrorStop=*/false, /*quiet=*/false),
-      testing::ExitedWithCode(EXIT_SUCCESS), "bye bye");
+                                        /*isErrorStop=*/false, /*quiet=*/false),
+              testing::ExitedWithCode(EXIT_SUCCESS), "bye bye");
 
   EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message),
-                  /*isErrorStop=*/false, /*quiet=*/true),
-      testing::ExitedWithCode(EXIT_SUCCESS), "");
+                                        /*isErrorStop=*/false, /*quiet=*/true),
+              testing::ExitedWithCode(EXIT_SUCCESS), "");
 
   EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message),
-                  /*isErrorStop=*/true, /*quiet=*/false),
-      testing::ExitedWithCode(EXIT_FAILURE), "Fortran ERROR STOP: bye bye");
+                                        /*isErrorStop=*/true, /*quiet=*/false),
+              testing::ExitedWithCode(EXIT_FAILURE),
+              "Fortran ERROR STOP: bye bye");
 
   EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message),
-                  /*isErrorStop=*/true, /*quiet=*/true),
-      testing::ExitedWithCode(EXIT_FAILURE), "");
+                                        /*isErrorStop=*/true, /*quiet=*/true),
+              testing::ExitedWithCode(EXIT_FAILURE), "");
 }
 
 TEST(TestProgramEnd, FailImageTest) {
-  EXPECT_EXIT(
-      RTNAME(FailImageStatement)(), testing::ExitedWithCode(EXIT_FAILURE), "");
+  EXPECT_EXIT(RTNAME(FailImageStatement)(),
+              testing::ExitedWithCode(EXIT_FAILURE), "");
 }
 
 TEST(TestProgramEnd, ExitTest) {
   EXPECT_EXIT(RTNAME(Exit)(), testing::ExitedWithCode(EXIT_SUCCESS), "");
-  EXPECT_EXIT(
-      RTNAME(Exit)(EXIT_FAILURE), testing::ExitedWithCode(EXIT_FAILURE), "");
+  EXPECT_EXIT(RTNAME(Exit)(EXIT_FAILURE), testing::ExitedWithCode(EXIT_FAILURE),
+              "");
 }
 
 TEST(TestProgramEnd, AbortTest) { EXPECT_DEATH(RTNAME(Abort)(), ""); }
@@ -91,8 +93,8 @@ TEST(TestProgramEnd, CrashTest) {
   static const std::string fileName{"file name"};
   static const std::string headMessage{"fatal Fortran runtime error\\("};
   static const std::string tailMessage{":343\\): "};
-  static const std::string fullMessage{
-      headMessage + fileName + tailMessage + crashMessage};
+  static const std::string fullMessage{headMessage + fileName + tailMessage +
+                                       crashMessage};
   EXPECT_DEATH(
       RTNAME(ReportFatalUserError)(crashMessage.c_str(), fileName.c_str(), 343),
       fullMessage.c_str());

diff  --git a/flang/unittests/Runtime/TemporaryStack.cpp b/flang-rt/unittests/FortranRuntime/TemporaryStack.cpp
similarity index 100%
rename from flang/unittests/Runtime/TemporaryStack.cpp
rename to flang-rt/unittests/FortranRuntime/TemporaryStack.cpp

diff  --git a/flang/unittests/Runtime/Time.cpp b/flang-rt/unittests/FortranRuntime/Time.cpp
similarity index 100%
rename from flang/unittests/Runtime/Time.cpp
rename to flang-rt/unittests/FortranRuntime/Time.cpp

diff  --git a/flang/unittests/Runtime/Transformational.cpp b/flang-rt/unittests/FortranRuntime/Transformational.cpp
similarity index 100%
rename from flang/unittests/Runtime/Transformational.cpp
rename to flang-rt/unittests/FortranRuntime/Transformational.cpp

diff  --git a/flang/unittests/Runtime/tools.h b/flang-rt/unittests/FortranRuntime/tools.h
similarity index 100%
rename from flang/unittests/Runtime/tools.h
rename to flang-rt/unittests/FortranRuntime/tools.h

diff  --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt
index ac30da89995ed31..893d5a4750813dc 100644
--- a/flang/CMakeLists.txt
+++ b/flang/CMakeLists.txt
@@ -188,7 +188,7 @@ if (FLANG_STANDALONE_BUILD)
   if (FLANG_GTEST_AVAIL)
     add_custom_target(check-all DEPENDS check-flang FlangUnitTests)
   else()
-    add_custom_target(check-all DEPENDS check-flang )
+    add_custom_target(check-all DEPENDS check-flang)
   endif()
   if (LLVM_BUILD_DOCS)
     add_custom_target(doxygen ALL)
@@ -421,6 +421,11 @@ if (FLANG_INCLUDE_TESTS)
   add_compile_definitions(FLANG_INCLUDE_TESTS=1)
 endif()
 
+# Add Flang subdirectories.
+# NOTE: The runtime subdirectory is no longer added here.
+# Sources for the runtime are added in Flang-rt.
+# TODO: Move the runtime sources to the flang-rt top level directory.
+
 add_subdirectory(include)
 add_subdirectory(lib)
 add_subdirectory(cmake/modules)
@@ -430,7 +435,6 @@ option(FLANG_BUILD_TOOLS
 if (FLANG_BUILD_TOOLS)
   add_subdirectory(tools)
 endif()
-add_subdirectory(runtime)
 
 if (LLVM_INCLUDE_EXAMPLES)
   add_subdirectory(examples)

diff  --git a/flang/cmake/modules/AddFlang.cmake b/flang/cmake/modules/AddFlang.cmake
index 41ce8738e7bf277..a072f372bcff85f 100644
--- a/flang/cmake/modules/AddFlang.cmake
+++ b/flang/cmake/modules/AddFlang.cmake
@@ -17,7 +17,7 @@ macro(add_flang_subdirectory name)
 endmacro()
 
 function(add_flang_library name)
-  set(options SHARED STATIC INSTALL_WITH_TOOLCHAIN)
+  set(options SHARED STATIC INSTALL_WITH_TOOLCHAIN PIC)
   set(multiValueArgs ADDITIONAL_HEADERS CLANG_LIBS)
   cmake_parse_arguments(ARG
     "${options}"
@@ -65,6 +65,9 @@ function(add_flang_library name)
   endif()
 
   llvm_add_library(${name} ${LIBTYPE} ${ARG_UNPARSED_ARGUMENTS} ${srcs})
+  if (ARG_PIC)
+    set_target_properties(${name} PROPERTIES POSITION_INDEPENDENT_CODE ON)
+  endif()
 
   clang_target_link_libraries(${name} PRIVATE ${ARG_CLANG_LIBS})
 

diff  --git a/flang/cmake/modules/FlangConfig.cmake.in b/flang/cmake/modules/FlangConfig.cmake.in
index ac4b77bd8514a7a..359a1dbac617e4e 100644
--- a/flang/cmake/modules/FlangConfig.cmake.in
+++ b/flang/cmake/modules/FlangConfig.cmake.in
@@ -9,6 +9,8 @@ find_package(LLVM ${LLVM_VERSION} EXACT REQUIRED CONFIG
 set(FLANG_EXPORTED_TARGETS "@FLANG_EXPORTS@")
 set(FLANG_CMAKE_DIR "@FLANG_CONFIG_CMAKE_DIR@")
 set(FLANG_INCLUDE_DIRS "@FLANG_CONFIG_INCLUDE_DIRS@")
+set(FLANG_SOURCE_DIR "@FLANG_SOURCE_DIR@")
+set(FLANG_BINARY_DIR "@FLANG_BINARY_DIR@")
 
 # Provide all our library targets to users.
 @FLANG_CONFIG_INCLUDE_EXPORTS@

diff  --git a/flang/lib/Decimal/CMakeLists.txt b/flang/lib/Decimal/CMakeLists.txt
index 3116ff68ea2627e..211c19693de810c 100644
--- a/flang/lib/Decimal/CMakeLists.txt
+++ b/flang/lib/Decimal/CMakeLists.txt
@@ -49,7 +49,19 @@ endif()
 # avoid an unwanted dependency on libstdc++.so.
 add_definitions(-U_GLIBCXX_ASSERTIONS)
 
-add_flang_library(FortranDecimal INSTALL_WITH_TOOLCHAIN
-  binary-to-decimal.cpp
-  decimal-to-binary.cpp
-)
+# Build FortranDecimal when the build target is Flang or LLVM.
+if (CMAKE_SOURCE_DIR STREQUAL FLANG_SOURCE_DIR OR CMAKE_SOURCE_DIR STREQUAL LLVM_MAIN_SRC_DIR)
+  add_flang_library(FortranDecimal
+    binary-to-decimal.cpp
+    decimal-to-binary.cpp
+  )
+# Build FortranDecimalRT for FlangRT when the build target is Runtimes.
+# Standalone builds of FlangRT is not supported.
+elseif (CMAKE_SOURCE_DIR STREQUAL Runtimes_SOURCE_DIR)
+  add_flang_library(FortranDecimalRT STATIC INSTALL_WITH_TOOLCHAIN PIC
+    binary-to-decimal.cpp
+    decimal-to-binary.cpp
+  )
+else()
+  message(FATAL_ERROR "CMAKE_SOURCE_DIR of target points to neither Flang or Flang-rt, no library added for FortranDecimal.")
+endif()

diff  --git a/flang/runtime/CMakeLists.txt b/flang/runtime/CMakeLists.txt
index e7d416749219ef6..51f1e16be778b89 100644
--- a/flang/runtime/CMakeLists.txt
+++ b/flang/runtime/CMakeLists.txt
@@ -6,10 +6,14 @@
 #
 #===------------------------------------------------------------------------===#
 
+# TODO: Maybe this file should still be added by flang/CMakeLists.txt and
+# when FLANG_STANDALONE_BUILD=On and a new variable FLANG_BUILD_RUNTIME=On
+# we should invoke an ExternalProject_Add(flang-rt ...) from here?
+
 if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
   cmake_minimum_required(VERSION 3.20.0)
 
-  project(FlangRuntime C CXX)
+  project(FortranRuntime C CXX)
 
   set(CMAKE_CXX_STANDARD 17)
   set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
@@ -82,8 +86,6 @@ append(${NO_LTO_FLAGS} CMAKE_CXX_FLAGS)
 add_definitions(-U_GLIBCXX_ASSERTIONS)
 add_definitions(-U_LIBCPP_ENABLE_ASSERTIONS)
 
-add_subdirectory(FortranMain)
-
 set(sources
   ISO_Fortran_binding.cpp
   allocatable.cpp
@@ -268,10 +270,13 @@ if (NOT FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD STREQUAL "off")
   endif()
 endif()
 
-add_flang_library(FortranRuntime
+add_compile_options(-fPIC)
+
+add_flang_library(FortranRuntime STATIC
   ${sources}
   LINK_LIBS
-  FortranDecimal
+  FortranDecimalRT
 
   INSTALL_WITH_TOOLCHAIN
+  PIC
 )

diff  --git a/flang/runtime/sum.cpp b/flang/runtime/sum.cpp
index c3c148296384622..6ca6620c16cde07 100644
--- a/flang/runtime/sum.cpp
+++ b/flang/runtime/sum.cpp
@@ -138,10 +138,15 @@ CppTypeFor<TypeCategory::Real, 10> RTNAME(SumReal10)(const Descriptor &x,
 }
 #endif
 #if LDBL_MANT_DIG == 113 || HAS_FLOAT128
+#if HAS_FLOAT128
+using AccumType = __float128;
+#else // if LDBL_MANT_DIG == 113
+using AccumType = long double;
+#endif
 CppTypeFor<TypeCategory::Real, 16> RTNAME(SumReal16)(const Descriptor &x,
     const char *source, int line, int dim, const Descriptor *mask) {
   return GetTotalReduction<TypeCategory::Real, 16>(
-      x, source, line, dim, mask, RealSumAccumulator<long double>{x}, "SUM");
+      x, source, line, dim, mask, RealSumAccumulator<AccumType>{x}, "SUM");
 }
 #endif
 

diff  --git a/flang/test/CMakeLists.txt b/flang/test/CMakeLists.txt
index 7d96a72e5f36d6d..e93d594490b649b 100644
--- a/flang/test/CMakeLists.txt
+++ b/flang/test/CMakeLists.txt
@@ -61,9 +61,6 @@ set(FLANG_TEST_DEPENDS
   llvm-objdump
   llvm-readobj
   split-file
-  FortranRuntime
-  Fortran_main
-  FortranDecimal
 )
 if (LLVM_ENABLE_PLUGINS AND NOT WIN32)
   list(APPEND FLANG_TEST_DEPENDS Bye)

diff  --git a/flang/test/Driver/linker-flags.f90 b/flang/test/Driver/linker-flags.f90
index 09b8a224df13828..2fbf3c4bf3450a8 100644
--- a/flang/test/Driver/linker-flags.f90
+++ b/flang/test/Driver/linker-flags.f90
@@ -24,21 +24,18 @@
 ! GNU-LABEL:  "{{.*}}ld{{(\.exe)?}}"
 ! GNU-SAME: "[[object_file]]"
 ! GNU-SAME: -lFortran_main
-! GNU-SAME: -lFortranRuntime
-! GNU-SAME: -lFortranDecimal
+! GNU-SAME: -lflang-rt
 ! GNU-SAME: -lm
 
 ! DARWIN-LABEL:  "{{.*}}ld{{(\.exe)?}}"
 ! DARWIN-SAME: "[[object_file]]"
 ! DARWIN-SAME: -lFortran_main
-! DARWIN-SAME: -lFortranRuntime
-! DARWIN-SAME: -lFortranDecimal
+! DARWIN-SAME: -lflang-rt
 
 ! MINGW-LABEL:  "{{.*}}ld{{(\.exe)?}}"
 ! MINGW-SAME: "[[object_file]]"
 ! MINGW-SAME: -lFortran_main
-! MINGW-SAME: -lFortranRuntime
-! MINGW-SAME: -lFortranDecimal
+! MINGW-SAME: -lflang-rt
 
 ! NOTE: This also matches lld-link (when CLANG_DEFAULT_LINKER=lld) and
 !       any .exe suffix that is added when resolving to the full path of
@@ -46,7 +43,6 @@
 !       when the executable is not found or on non-Windows platforms.
 ! MSVC-LABEL: link
 ! MSVC-SAME: Fortran_main.lib
-! MSVC-SAME: FortranRuntime.lib
-! MSVC-SAME: FortranDecimal.lib
+! MSVC-SAME: flang-rt.lib
 ! MSVC-SAME: /subsystem:console
 ! MSVC-SAME: "[[object_file]]"

diff  --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py
index dda8ed456c986a5..89a2353047c305a 100644
--- a/flang/test/lit.cfg.py
+++ b/flang/test/lit.cfg.py
@@ -153,19 +153,16 @@
 # the C++ runtime libraries. For this we need a C compiler. If for some reason
 # we don't have one, we can just disable the test.
 if config.cc:
-    libruntime = os.path.join(config.flang_lib_dir, "libFortranRuntime.a")
-    libdecimal = os.path.join(config.flang_lib_dir, "libFortranDecimal.a")
+    libruntime = os.path.join(config.flang_lib_dir, "libflang-rt.a")
     include = os.path.join(config.flang_src_dir, "include")
 
     if (
         os.path.isfile(libruntime)
-        and os.path.isfile(libdecimal)
         and os.path.isdir(include)
     ):
         config.available_features.add("c-compiler")
         tools.append(ToolSubst("%cc", command=config.cc, unresolved="fatal"))
         tools.append(ToolSubst("%libruntime", command=libruntime, unresolved="fatal"))
-        tools.append(ToolSubst("%libdecimal", command=libdecimal, unresolved="fatal"))
         tools.append(ToolSubst("%include", command=include, unresolved="fatal"))
 
 # Add all the tools and their substitutions (if applicable). Use the search paths provided for

diff  --git a/flang/tools/flang-driver/CMakeLists.txt b/flang/tools/flang-driver/CMakeLists.txt
index 3ce8b407450d245..9f33cdfe3fa90f7 100644
--- a/flang/tools/flang-driver/CMakeLists.txt
+++ b/flang/tools/flang-driver/CMakeLists.txt
@@ -14,14 +14,6 @@ set( LLVM_LINK_COMPONENTS
 add_flang_tool(flang-new
   driver.cpp
   fc1_main.cpp
-
-  DEPENDS
-  # These libraries are used in the linker invocation generated by the driver
-  # (i.e. when constructing the linker job). Without them the driver would be
-  # unable to generate executables.
-  FortranRuntime
-  FortranDecimal
-  Fortran_main
 )
 
 target_link_libraries(flang-new

diff  --git a/flang/unittests/CMakeLists.txt b/flang/unittests/CMakeLists.txt
index 72d37ebeb853c5b..ab12fd8e7f5daad 100644
--- a/flang/unittests/CMakeLists.txt
+++ b/flang/unittests/CMakeLists.txt
@@ -24,11 +24,15 @@ function(add_flang_unittest_offload_properties target)
   # FIXME: replace 'native' in --offload-arch option with the list
   #        of targets that Fortran Runtime was built for.
   #        Common code must be moved from flang/runtime/CMakeLists.txt.
+  # TODO: Revisit this because of Flang-rt. runtime is no longer an added subdirectory of flang. So we temporarily duplicated the option definition to here. This is not a permanent solution.
+  set(FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD "off" CACHE STRING
+    "Compile Fortran runtime as OpenMP target offload sources (experimental). Valid options are 'off', 'host_device', 'nohost'")
+
   if (NOT FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD STREQUAL "off")
     set_target_properties(${target}
-      PROPERTIES LINK_OPTIONS
-      "-fopenmp;--offload-arch=native"
-      )
+        PROPERTIES LINK_OPTIONS
+        "-fopenmp;--offload-arch=native"
+    )
   endif()
 endfunction()
 
@@ -74,5 +78,4 @@ add_subdirectory(Optimizer)
 add_subdirectory(Common)
 add_subdirectory(Decimal)
 add_subdirectory(Evaluate)
-add_subdirectory(Runtime)
 add_subdirectory(Frontend)

diff  --git a/flang/unittests/Evaluate/CMakeLists.txt b/flang/unittests/Evaluate/CMakeLists.txt
index 4658d8d3345b5d6..f9551dac713a348 100644
--- a/flang/unittests/Evaluate/CMakeLists.txt
+++ b/flang/unittests/Evaluate/CMakeLists.txt
@@ -45,7 +45,6 @@ add_flang_nongtest_unittest(intrinsics
   FortranDecimal
   FortranSemantics
   FortranParser
-  FortranRuntime
 )
 
 add_flang_nongtest_unittest(logical
@@ -68,20 +67,6 @@ add_flang_nongtest_unittest(real
 )
 llvm_update_compile_flags(real.test)
 
-add_flang_nongtest_unittest(reshape
-  FortranEvaluateTesting
-  FortranSemantics
-  FortranEvaluate
-  FortranRuntime
-)
-
-add_flang_nongtest_unittest(ISO-Fortran-binding
-  FortranEvaluateTesting
-  FortranEvaluate
-  FortranSemantics
-  FortranRuntime
-)
-
 add_flang_nongtest_unittest(folding
   FortranCommon
   FortranEvaluateTesting

diff  --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt
index 9c165d998e2e11a..34b45d0e77822cd 100644
--- a/flang/unittests/Optimizer/CMakeLists.txt
+++ b/flang/unittests/Optimizer/CMakeLists.txt
@@ -19,16 +19,6 @@ add_flang_unittest(FlangOptimizerTests
   Builder/DoLoopHelperTest.cpp
   Builder/FIRBuilderTest.cpp
   Builder/HLFIRToolsTest.cpp
-  Builder/Runtime/AllocatableTest.cpp
-  Builder/Runtime/AssignTest.cpp
-  Builder/Runtime/CommandTest.cpp
-  Builder/Runtime/CharacterTest.cpp
-  Builder/Runtime/DerivedTest.cpp
-  Builder/Runtime/NumericTest.cpp
-  Builder/Runtime/RaggedTest.cpp
-  Builder/Runtime/ReductionTest.cpp
-  Builder/Runtime/StopTest.cpp
-  Builder/Runtime/TransformationalTest.cpp
   FIRContextTest.cpp
   FIRTypesTest.cpp
   FortranVariableTest.cpp

diff  --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp
index 53e146bb8600b8f..2eae92906db95b5 100644
--- a/lld/COFF/MinGW.cpp
+++ b/lld/COFF/MinGW.cpp
@@ -50,8 +50,7 @@ AutoExporter::AutoExporter(
       "libc++",
       "libc++abi",
       "libFortran_main",
-      "libFortranRuntime",
-      "libFortranDecimal",
+      "libflang-rt",
       "libunwind",
       "libmsvcrt",
       "libucrtbase",

diff  --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 5985256498dcbb2..7b49ec161c3f3bf 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -149,7 +149,10 @@ endif()
 # As we migrate runtimes to using the bootstrapping build, the set of default runtimes
 # should grow as we remove those runtimes from LLVM_ENABLE_PROJECTS above.
 set(LLVM_DEFAULT_RUNTIMES "libcxx;libcxxabi;libunwind")
-set(LLVM_SUPPORTED_RUNTIMES "libc;libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp;llvm-libgcc")
+if ("flang" IN_LIST LLVM_ENABLE_PROJECTS)
+  set(LLVM_DEFAULT_RUNTIMES "libcxx;libcxxabi;libunwind;flang-rt")
+endif()
+set(LLVM_SUPPORTED_RUNTIMES "libc;libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp;llvm-libgcc;flang-rt")
 set(LLVM_ENABLE_RUNTIMES "" CACHE STRING
   "Semicolon-separated list of runtimes to build, or \"all\" (${LLVM_DEFAULT_RUNTIMES}). Supported runtimes are ${LLVM_SUPPORTED_RUNTIMES}.")
 if(LLVM_ENABLE_RUNTIMES STREQUAL "all")
@@ -171,6 +174,11 @@ if ("libc" IN_LIST LLVM_ENABLE_RUNTIMES)
   endif()
 endif()
 
+if ("flang" IN_LIST LLVM_ENABLE_PROJECTS AND NOT "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
+  message(STATUS "Enabling Flang-rt to be built with the Flang project.")
+  list(APPEND LLVM_ENABLE_RUNTIMES "flang-rt")
+endif()
+
 # LLVM_ENABLE_PROJECTS_USED is `ON` if the user has ever used the
 # `LLVM_ENABLE_PROJECTS` CMake cache variable.  This exists for
 # several reasons:

diff  --git a/llvm/projects/CMakeLists.txt b/llvm/projects/CMakeLists.txt
index 08f2fa522420b0e..2f66cd1a4c44b48 100644
--- a/llvm/projects/CMakeLists.txt
+++ b/llvm/projects/CMakeLists.txt
@@ -6,6 +6,7 @@ foreach(entry ${entries})
   if(IS_DIRECTORY ${entry} AND EXISTS ${entry}/CMakeLists.txt)
     if((NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/compiler-rt) AND
        (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/dragonegg) AND
+       (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/flang-rt) AND
        (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/libcxx) AND
        (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/libcxxabi) AND
        (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/libunwind) AND
@@ -37,6 +38,8 @@ if(${LLVM_BUILD_RUNTIME})
   if(NOT LLVM_BUILD_EXTERNAL_COMPILER_RT)
     add_llvm_external_project(compiler-rt)
   endif()
+
+  add_llvm_external_project(flang-rt)
 endif()
 
 add_llvm_external_project(dragonegg)

diff  --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt
index 7ec6480773c8f05..dc568373e48f0ed 100644
--- a/llvm/runtimes/CMakeLists.txt
+++ b/llvm/runtimes/CMakeLists.txt
@@ -401,17 +401,24 @@ if(runtimes)
       endforeach()
     endif()
   endif()
+  set(EXTRA_CMAKE_ARGS "")
+  if("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES)
+    list(APPEND EXTRA_CMAKE_ARGS "-DLLVM_DIR=${LLVM_BINARY_DIR}/lib/cmake/llvm")
+    list(APPEND EXTRA_CMAKE_ARGS "-DFLANG_DIR=${LLVM_BINARY_DIR}/lib/cmake/flang")
+    list(APPEND EXTRA_CMAKE_ARGS "-DCLANG_DIR=${LLVM_BINARY_DIR}/lib/cmake/clang")
+    list(APPEND EXTRA_CMAKE_ARGS "-DMLIR_DIR=${LLVM_BINARY_DIR}/lib/cmake/mlir")
+  endif()
   if(NOT LLVM_RUNTIME_TARGETS)
     runtime_default_target(
       DEPENDS ${builtins_dep} ${extra_deps}
-      CMAKE_ARGS ${libc_cmake_args}
+      CMAKE_ARGS ${libc_cmake_args} ${EXTRA_CMAKE_ARGS}
       PREFIXES ${prefixes})
     set(test_targets check-runtimes)
   else()
     if("default" IN_LIST LLVM_RUNTIME_TARGETS)
       runtime_default_target(
         DEPENDS ${builtins_dep} ${extra_deps}
-        CMAKE_ARGS ${libc_cmake_args}
+        CMAKE_ARGS ${libc_cmake_args} ${EXTRA_CMAKE_ARGS}
         PREFIXES ${prefixes})
       list(REMOVE_ITEM LLVM_RUNTIME_TARGETS "default")
     else()
@@ -451,7 +458,7 @@ if(runtimes)
 
       runtime_register_target(${name}
         DEPENDS ${builtins_dep_name} ${libc_tools}
-        CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=${name} ${libc_cmake_args}
+        CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=${name} ${libc_cmake_args} ${EXTRA_CMAKE_ARGS}
         EXTRA_ARGS TARGET_TRIPLE ${name})
 
       add_dependencies(runtimes runtimes-${name})
@@ -481,6 +488,7 @@ if(runtimes)
           CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=${name}
                      -DLLVM_RUNTIMES_PREFIX=${name}/
                      -DLLVM_RUNTIMES_LIBDIR_SUBDIR=${multilib}
+                     ${EXTRA_CMAKE_ARGS}
           BASE_NAME ${name}
           EXTRA_ARGS TARGET_TRIPLE ${name})
 

diff  --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 010ec879e44a322..c26a5f725d59f50 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -19,7 +19,7 @@ list(INSERT CMAKE_MODULE_PATH 0
 
 # We order libraries to mirror roughly how they are layered, except that compiler-rt can depend
 # on libc++, so we put it after.
-set(LLVM_DEFAULT_RUNTIMES "libc;libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp")
+set(LLVM_DEFAULT_RUNTIMES "libc;libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp;flang-rt")
 set(LLVM_SUPPORTED_RUNTIMES "${LLVM_DEFAULT_RUNTIMES};llvm-libgcc")
 set(LLVM_ENABLE_RUNTIMES "" CACHE STRING
   "Semicolon-separated list of runtimes to build, or \"all\" (${LLVM_DEFAULT_RUNTIMES}). Supported runtimes are ${LLVM_SUPPORTED_RUNTIMES}.")


        


More information about the cfe-commits mailing list