This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG6403287eff71: [Flang] [FlangRT] Introduce FlangRT project as 
solution to Flang's runtime LLVM… (authored by pscoro, committed by 
madanial).

Changed prior to commit:
  https://reviews.llvm.org/D154869?vs=557468&id=557508#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D154869/new/

https://reviews.llvm.org/D154869

Files:
  clang/lib/Driver/ToolChains/CommonArgs.cpp
  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
  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/Evaluate/ISO-Fortran-binding.cpp
  flang/unittests/Evaluate/reshape.cpp
  flang/unittests/Optimizer/CMakeLists.txt
  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
  lld/COFF/MinGW.cpp
  llvm/CMakeLists.txt
  llvm/projects/CMakeLists.txt
  llvm/runtimes/CMakeLists.txt
  runtimes/CMakeLists.txt

Index: runtimes/CMakeLists.txt
===================================================================
--- runtimes/CMakeLists.txt
+++ runtimes/CMakeLists.txt
@@ -19,7 +19,7 @@
 
 # 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}.")
Index: llvm/runtimes/CMakeLists.txt
===================================================================
--- llvm/runtimes/CMakeLists.txt
+++ llvm/runtimes/CMakeLists.txt
@@ -401,17 +401,24 @@
       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 @@
 
       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 @@
           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})
 
Index: llvm/projects/CMakeLists.txt
===================================================================
--- llvm/projects/CMakeLists.txt
+++ llvm/projects/CMakeLists.txt
@@ -6,6 +6,7 @@
   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(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)
Index: llvm/CMakeLists.txt
===================================================================
--- llvm/CMakeLists.txt
+++ llvm/CMakeLists.txt
@@ -149,7 +149,10 @@
 # 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 @@
   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:
Index: lld/COFF/MinGW.cpp
===================================================================
--- lld/COFF/MinGW.cpp
+++ lld/COFF/MinGW.cpp
@@ -50,8 +50,7 @@
       "libc++",
       "libc++abi",
       "libFortran_main",
-      "libFortranRuntime",
-      "libFortranDecimal",
+      "libflang-rt",
       "libunwind",
       "libmsvcrt",
       "libucrtbase",
Index: flang/unittests/Optimizer/CMakeLists.txt
===================================================================
--- flang/unittests/Optimizer/CMakeLists.txt
+++ flang/unittests/Optimizer/CMakeLists.txt
@@ -19,16 +19,6 @@
   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
Index: flang/unittests/Evaluate/CMakeLists.txt
===================================================================
--- flang/unittests/Evaluate/CMakeLists.txt
+++ flang/unittests/Evaluate/CMakeLists.txt
@@ -45,7 +45,6 @@
   FortranDecimal
   FortranSemantics
   FortranParser
-  FortranRuntime
 )
 
 add_flang_nongtest_unittest(logical
@@ -68,20 +67,6 @@
 )
 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
Index: flang/tools/flang-driver/CMakeLists.txt
===================================================================
--- flang/tools/flang-driver/CMakeLists.txt
+++ flang/tools/flang-driver/CMakeLists.txt
@@ -14,14 +14,6 @@
 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
Index: flang/test/Driver/linker-flags.f90
===================================================================
--- flang/test/Driver/linker-flags.f90
+++ 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]]"
Index: flang/test/CMakeLists.txt
===================================================================
--- flang/test/CMakeLists.txt
+++ flang/test/CMakeLists.txt
@@ -61,9 +61,6 @@
   llvm-objdump
   llvm-readobj
   split-file
-  FortranRuntime
-  Fortran_main
-  FortranDecimal
 )
 if (LLVM_ENABLE_PLUGINS AND NOT WIN32)
   list(APPEND FLANG_TEST_DEPENDS Bye)
Index: flang/runtime/sum.cpp
===================================================================
--- flang/runtime/sum.cpp
+++ flang/runtime/sum.cpp
@@ -138,10 +138,15 @@
 }
 #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
 
Index: flang/runtime/CMakeLists.txt
===================================================================
--- flang/runtime/CMakeLists.txt
+++ 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 @@
 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 @@
   endif()
 endif()
 
-add_flang_library(FortranRuntime
+add_compile_options(-fPIC)
+
+add_flang_library(FortranRuntime STATIC
   ${sources}
   LINK_LIBS
-  FortranDecimal
+  FortranDecimalRT
 
   INSTALL_WITH_TOOLCHAIN
+  PIC
 )
Index: flang/lib/Decimal/CMakeLists.txt
===================================================================
--- flang/lib/Decimal/CMakeLists.txt
+++ flang/lib/Decimal/CMakeLists.txt
@@ -49,7 +49,19 @@
 # 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()
Index: flang/cmake/modules/FlangConfig.cmake.in
===================================================================
--- flang/cmake/modules/FlangConfig.cmake.in
+++ flang/cmake/modules/FlangConfig.cmake.in
@@ -9,6 +9,8 @@
 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@
Index: flang/cmake/modules/AddFlang.cmake
===================================================================
--- flang/cmake/modules/AddFlang.cmake
+++ flang/cmake/modules/AddFlang.cmake
@@ -17,7 +17,7 @@
 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 @@
   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})
 
Index: flang/CMakeLists.txt
===================================================================
--- flang/CMakeLists.txt
+++ flang/CMakeLists.txt
@@ -188,7 +188,7 @@
   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 @@
   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 @@
 if (FLANG_BUILD_TOOLS)
   add_subdirectory(tools)
 endif()
-add_subdirectory(runtime)
 
 if (LLVM_INCLUDE_EXAMPLES)
   add_subdirectory(examples)
Index: flang-rt/unittests/FortranRuntime/Stop.cpp
===================================================================
--- flang-rt/unittests/FortranRuntime/Stop.cpp
+++ 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 @@
 
 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 @@
   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());
Index: flang-rt/unittests/FortranRuntime/RuntimeCrashTest.cpp
===================================================================
--- flang-rt/unittests/FortranRuntime/RuntimeCrashTest.cpp
+++ 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 @@
 //------------------------------------------------------------------------------
 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, 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 @@
   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 @@
   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 @@
   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 @@
   // 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");
 }
Index: flang-rt/unittests/FortranRuntime/Namelist.cpp
===================================================================
--- flang-rt/unittests/FortranRuntime/Namelist.cpp
+++ 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 @@
 
 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 @@
   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 @@
   // 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 @@
   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 @@
   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 @@
   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 @@
   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, 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 @@
   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 @@
   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";
Index: flang-rt/unittests/FortranRuntime/ListInputTest.cpp
===================================================================
--- flang-rt/unittests/FortranRuntime/ListInputTest.cpp
+++ 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 @@
   // 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 @@
   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 @@
   // 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 @@
   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 @@
 
   // 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 @@
   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 @@
 
   // 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 @@
   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 @@
   }
 }
 
-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})));
Index: flang-rt/unittests/FortranRuntime/CrashHandlerFixture.cpp
===================================================================
--- flang-rt/unittests/FortranRuntime/CrashHandlerFixture.cpp
+++ 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);
Index: flang-rt/unittests/FortranRuntime/CMakeLists.txt
===================================================================
--- flang-rt/unittests/FortranRuntime/CMakeLists.txt
+++ 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 @@
   Transformational.cpp
 )
 
-target_link_libraries(FlangRuntimeTests
+target_link_libraries(FortranRuntimeTests
   PRIVATE
-  FortranRuntime
+  flang-rt
 )
Index: flang-rt/unittests/FortranRuntime/BufferTest.cpp
===================================================================
--- flang-rt/unittests/FortranRuntime/BufferTest.cpp
+++ 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 @@
   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 @@
     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 @@
 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);
 }
 
Index: flang-rt/unittests/FortranEvaluate/testing.h
===================================================================
--- /dev/null
+++ 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_
Index: flang-rt/unittests/FortranEvaluate/testing.cpp
===================================================================
--- /dev/null
+++ 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
Index: flang-rt/unittests/FortranEvaluate/CMakeLists.txt
===================================================================
--- /dev/null
+++ 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
+)
Index: flang/unittests/CMakeLists.txt
===================================================================
--- flang/unittests/CMakeLists.txt
+++ flang/unittests/CMakeLists.txt
@@ -24,11 +24,15 @@
   # 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(Common)
 add_subdirectory(Decimal)
 add_subdirectory(Evaluate)
-add_subdirectory(Runtime)
 add_subdirectory(Frontend)
Index: flang-rt/unittests/CMakeLists.txt
===================================================================
--- flang-rt/unittests/CMakeLists.txt
+++ flang-rt/unittests/CMakeLists.txt
@@ -7,10 +7,10 @@
   enable_language(CUDA)
 endif()
 
-add_custom_target(FlangUnitTests)
-set_target_properties(FlangUnitTests PROPERTIES FOLDER "Flang Unit Tests")
+add_custom_target(FlangRTUnitTests)
+set_target_properties(FlangRTUnitTests PROPERTIES FOLDER "Flang-rt Unit Tests")
 
-function(add_flang_unittest_offload_properties target)
+function(add_flang_rt_unittest_offload_properties target)
   # Set CUDA_RESOLVE_DEVICE_SYMBOLS.
   if (FLANG_EXPERIMENTAL_CUDA_RUNTIME)
     set_target_properties(${target}
@@ -24,30 +24,36 @@
   # 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"
-      )
+        PROPERTIES LINK_OPTIONS
+        "-fopenmp;--offload-arch=native"
+    )
   endif()
 endfunction()
 
-function(add_flang_unittest test_dirname)
-  add_unittest(FlangUnitTests ${test_dirname} ${ARGN})
-  add_flang_unittest_offload_properties(${test_dirname})
+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_nongtest_unittest test_name)
+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()
@@ -64,15 +70,12 @@
   target_link_libraries(${test_name}${suffix} ${llvm_libs} ${ARG_UNPARSED_ARGUMENTS})
 
   if(NOT ARG_SLOW_TEST)
-    add_dependencies(FlangUnitTests ${test_name}${suffix})
+    add_dependencies(FlangRTUnitTests ${test_name}${suffix})
   endif()
 
-  add_flang_unittest_offload_properties(${test_name}${suffix})
+  add_flang_rt_unittest_offload_properties(${test_name}${suffix})
 endfunction()
 
-add_subdirectory(Optimizer)
-add_subdirectory(Common)
-add_subdirectory(Decimal)
-add_subdirectory(Evaluate)
-add_subdirectory(Runtime)
-add_subdirectory(Frontend)
+add_subdirectory(FortranRuntime)
+# TODO: We may want to find a better location for these tests that use the runtime
+add_subdirectory(FortranEvaluate)
Index: flang-rt/test/lit.site.cfg.py.in
===================================================================
--- /dev/null
+++ flang-rt/test/lit.site.cfg.py.in
@@ -0,0 +1,31 @@
+@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")
Index: flang/test/lit.cfg.py
===================================================================
--- flang/test/lit.cfg.py
+++ 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
Index: flang-rt/test/lit.cfg.py
===================================================================
--- flang-rt/test/lit.cfg.py
+++ flang-rt/test/lit.cfg.py
@@ -16,7 +16,7 @@
 # Configuration file for the 'lit' test runner.
 
 # name: The name of this test suite.
-config.name = "Flang"
+config.name = "flang-rt"
 
 # testFormat: The test format to use to interpret tests.
 #
@@ -56,7 +56,6 @@
 ]
 
 config.substitutions.append(("%PATH%", config.environment["PATH"]))
-config.substitutions.append(("%llvmshlibdir", config.llvm_shlib_dir))
 config.substitutions.append(("%pluginext", config.llvm_plugin_ext))
 
 llvm_config.use_default_substitutions()
@@ -69,20 +68,16 @@
 for arch in config.targets_to_build.split():
     config.available_features.add(arch.lower() + "-registered-target")
 
-# To modify the default target triple for flang tests.
-if config.flang_test_triple:
-    config.target_triple = config.flang_test_triple
-    config.environment[config.llvm_target_triple_env] = config.flang_test_triple
+# 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"]
 
-# If the flang examples are built, add examples to the config
-if config.flang_examples:
-    config.available_features.add("examples")
-
 # Plugins (loadable modules)
 if config.has_plugins:
     config.available_features.add("plugins")
@@ -103,20 +98,12 @@
 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_obj_root, "test")
-
-# Tweak the PATH to include the tools dir.
-llvm_config.with_environment("PATH", config.flang_tools_dir, append_path=True)
-llvm_config.with_environment("PATH", config.llvm_tools_dir, append_path=True)
+config.test_exec_root = os.path.join(config.flang_rt_obj_root, "test")
 
-if config.flang_standalone_build:
-    # For builds with FIR, set path for tco and enable related tests
-    if config.flang_llvm_tools_dir != "":
-        config.available_features.add("fir")
-        if config.llvm_tools_dir != config.flang_llvm_tools_dir:
-            llvm_config.with_environment(
-                "PATH", config.flang_llvm_tools_dir, append_path=True
-            )
+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.
@@ -153,29 +140,32 @@
 # 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_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)
-        and os.path.isfile(libdecimal)
+        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, unresolved="fatal"))
-        tools.append(ToolSubst("%libdecimal", command=libdecimal, 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.
-if config.flang_standalone_build:
-    llvm_config.add_tool_substitutions(
-        tools, [config.flang_llvm_tools_dir, config.llvm_tools_dir]
-    )
-else:
-    llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir)
+llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir)
 
 # Enable libpgmath testing
 result = lit_config.params.get("LIBPGMATH")
Index: flang-rt/test/Unit/lit.site.cfg.py.in
===================================================================
--- /dev/null
+++ flang-rt/test/Unit/lit.site.cfg.py.in
@@ -0,0 +1,22 @@
+@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")
Index: flang-rt/test/Unit/lit.cfg.py
===================================================================
--- /dev/null
+++ 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
Index: flang-rt/test/NonGtestUnit/lit.site.cfg.py.in
===================================================================
--- /dev/null
+++ flang-rt/test/NonGtestUnit/lit.site.cfg.py.in
@@ -0,0 +1,23 @@
+@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")
Index: flang-rt/test/NonGtestUnit/lit.cfg.py
===================================================================
--- /dev/null
+++ 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
Index: flang-rt/test/FortranRuntime/no-cpp-dep.c
===================================================================
--- /dev/null
+++ 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;
+}
Index: flang-rt/test/CMakeLists.txt
===================================================================
--- /dev/null
+++ 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()
Index: flang-rt/docs/GettingStarted.md
===================================================================
--- /dev/null
+++ 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
+```
Index: flang-rt/CMakeLists.txt
===================================================================
--- /dev/null
+++ 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()
Index: clang/lib/Driver/ToolChains/CommonArgs.cpp
===================================================================
--- clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -969,29 +969,41 @@
                                   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,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to