diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 48170fa908fd6..1ba031d42741c 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -969,29 +969,41 @@ void tools::addFortranRuntimeLibs(const ToolChain &TC, llvm::opt::ArgStringList &CmdArgs) { if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { CmdArgs.push_back("Fortran_main.lib"); - CmdArgs.push_back("FortranRuntime.lib"); - CmdArgs.push_back("FortranDecimal.lib"); + CmdArgs.push_back("flang-rt.lib"); } else { CmdArgs.push_back("-lFortran_main"); - CmdArgs.push_back("-lFortranRuntime"); - CmdArgs.push_back("-lFortranDecimal"); + CmdArgs.push_back("-lflang-rt"); } } void tools::addFortranRuntimeLibraryPath(const ToolChain &TC, const llvm::opt::ArgList &Args, ArgStringList &CmdArgs) { - // Default to the /../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 /../lib, /../flang-rt/lib, and + // /../runtimes/runtimes-bins/flang-rt/lib directories. This + // works fine on the platforms that we have tested so far. We will probably + // have to re-fine this in the future. In particular, on some platforms, we + // may need to use lib64 instead of lib. + SmallString<256> BuildLibPath = + llvm::sys::path::parent_path(TC.getDriver().Dir); + SmallString<256> FlangRTLibPath = + llvm::sys::path::parent_path(TC.getDriver().Dir); + SmallString<256> RuntimesLibPath = llvm::sys::path::parent_path(TC.getDriver().Dir); - llvm::sys::path::append(DefaultLibPath, "lib"); - if (TC.getTriple().isKnownWindowsMSVCEnvironment()) - CmdArgs.push_back(Args.MakeArgString("-libpath:" + DefaultLibPath)); - else - CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath)); + // Search path for Fortran_main and Flang-rt libraries. + llvm::sys::path::append(BuildLibPath, "lib"); + llvm::sys::path::append(FlangRTLibPath, "flang-rt/lib"); + llvm::sys::path::append(RuntimesLibPath, + "runtimes/runtimes-bins/flang-rt/lib"); + if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { + CmdArgs.push_back(Args.MakeArgString("-libpath:" + BuildLibPath)); + CmdArgs.push_back(Args.MakeArgString("-libpath:" + FlangRTLibPath)); + CmdArgs.push_back(Args.MakeArgString("-libpath:" + RuntimesLibPath)); + } else { + CmdArgs.push_back(Args.MakeArgString("-L" + BuildLibPath)); + CmdArgs.push_back(Args.MakeArgString("-L" + FlangRTLibPath)); + CmdArgs.push_back(Args.MakeArgString("-L" + RuntimesLibPath)); + } } static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, diff --git a/flang-rt/CMakeLists.txt b/flang-rt/CMakeLists.txt new file mode 100644 index 0000000000000..053869b8769e2 --- /dev/null +++ b/flang-rt/CMakeLists.txt @@ -0,0 +1,148 @@ +# CMake build for the Flang runtime libraries +# The source for the flang runtime libraries (FortranDecimalRT, FortranRuntime) +# exist in the flang top-level directory. +# Flang-rt is only scaffolding and does not provide any additional source files. + +cmake_minimum_required(VERSION 3.20.0) + +#=============================================================================== +# Configure CMake +#=============================================================================== +set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake") +include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake + NO_POLICY_SCOPE) + +set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/flang-rt/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY + ${CMAKE_BINARY_DIR}/flang-rt/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY + ${CMAKE_BINARY_DIR}/flang-rt/lib) +set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_BINARY_DIR}/flang-rt) + +set(FLANG_RT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +set(FLANG_RT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") + +#=============================================================================== +# Setup Options and Defaults +#=============================================================================== +option(FLANG_RT_ENABLE_SHARED "Build flang-rt as a shared library." OFF) +option(FLANG_RT_ENABLE_STATIC "Build flang-rt as a static library." OFF) + +option(FLANG_RT_INCLUDE_TESTS + "Generate build targets for the Flang-rt unit tests." ${LLVM_INCLUDE_TESTS}) + +# MLIR_DIR must be passed on invocation of flang-rt because it is needed for the Flang package. +if(NOT DEFINED MLIR_DIR OR MLIR_DIR STREQUAL "") + message(FATAL_ERROR "MLIR_DIR must be set to the directory of the MLIRConfig cmake file in order to find the MLIR package.") +endif() +# Flang-rt requires a pre-built/installed version of flang that requires MLIR. +find_package(MLIR REQUIRED HINTS "${MLIR_DIR}") + +# FLANG_DIR must be passed on invocation of flang-rt. +if(NOT DEFINED FLANG_DIR OR FLANG_DIR STREQUAL "") + message(FATAL_ERROR "FLANG_DIR must be set to the directory of the FlangConfig cmake file in order to find the Flang package.") +endif() +# Flang-rt requires a pre-built/installed version of flang. +# Flang-rt uses flang/Common headers. +# Finding this package exposes FLANG_SOURCE_DIR, FLANG_BINARY_DIR, and FLANG_INCLUDE_DIRS to Flang-rt +find_package(Flang REQUIRED HINTS "${FLANG_DIR}") +# If the user specifies a relative path to LLVM_DIR, the calls to include +# LLVM modules fail. Append the absolute path to LLVM_DIR instead. +get_filename_component(FLANG_DIR_ABSOLUTE ${FLANG_DIR} REALPATH) +list(APPEND CMAKE_MODULE_PATH ${FLANG_DIR_ABSOLUTE}) + +set(LLVM_COMMON_CMAKE_UTILS "${FLANG_RT_SOURCE_DIR}/../cmake") +set(LLVM_CMAKE_UTILS "${LLVM_BUILD_MAIN_SOURCE_DIR}/cmake") +set(CLANG_CMAKE_UTILS "${FLANG_RT_SOURCE_DIR}/../clang/cmake") + +if (FLANG_RT_INCLUDE_TESTS) + # LLVM_DIR must be passed on invocation of flang-rt when tests are enabled. + if(NOT DEFINED LLVM_DIR OR LLVM_DIR STREQUAL "") + message(FATAL_ERROR "LLVM_DIR must be set to the directory of the LLVMConfig cmake file in order to find the LLVM package.") + endif() + # We need a pre-built/installed version of LLVM for gtest. + find_package(LLVM REQUIRED HINTS "${LLVM_DIR}") + # If the user specifies a relative path to LLVM_DIR, the calls to include + # LLVM modules fail. Append the absolute path to LLVM_DIR instead. + get_filename_component(LLVM_DIR_ABSOLUTE ${LLVM_DIR} REALPATH) + list(APPEND CMAKE_MODULE_PATH ${LLVM_DIR_ABSOLUTE}) + + add_compile_definitions(FLANG_RT_INCLUDE_TESTS=1) + + if (DEFINED FLANG_BINARY_DIR) + set(FLANG_BINARY_DIR ${FLANG_BINARY_DIR} CACHE PATH "Path to the Flang build directory" FORCE) + else() + message(FATAL_ERROR "FLANG_BINARY_DIR must be defined or passed by the user when building tests.") + endif() + set(FLANG_RT_TEST_COMPILER ${FLANG_BINARY_DIR}/bin/flang-new + CACHE PATH "Compiler to use for testing") + set(FLANG_RT_GTEST_AVAIL 1) +endif() + +# Add path for custom modules +list(INSERT CMAKE_MODULE_PATH 0 + "${FLANG_SOURCE_DIR}/cmake" + "${FLANG_SOURCE_DIR}/cmake/modules" + "${CLANG_CMAKE_UTILS}/modules" + "${LLVM_CMAKE_UTILS}/modules" +) + +include(AddClang) +include(AddFlang) +include(TestBigEndian) +test_big_endian(IS_BIGENDIAN) +if (IS_BIGENDIAN) + add_compile_definitions(FLANG_BIG_ENDIAN=1) +else () + add_compile_definitions(FLANG_LITTLE_ENDIAN=1) +endif () + +# Flang's include directories are needed for flang/Common. +include_directories(SYSTEM ${FLANG_INCLUDE_DIRS}) + +# LLVM's include directories are needed for gtest. +include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) + +#=============================================================================== +# Add Subdirectories +#=============================================================================== +set(FORTRAN_DECIMAL_SRC "${FLANG_SOURCE_DIR}/lib/Decimal") +set(FORTRAN_RUNTIME_SRC "${FLANG_SOURCE_DIR}/runtime") +set(FORTRAN_MAIN_SRC "${FLANG_SOURCE_DIR}/runtime/FortranMain") + +add_subdirectory(${FORTRAN_DECIMAL_SRC} FortranDecimalRT) +add_subdirectory(${FORTRAN_RUNTIME_SRC} FortranRuntime) +add_subdirectory(${FORTRAN_MAIN_SRC} FortranMain) + +if (FLANG_RT_INCLUDE_TESTS) + add_subdirectory(test) + if (FLANG_RT_GTEST_AVAIL) + add_subdirectory(unittests) + endif() +endif() + +#=============================================================================== +# Create Flang-rt wrapper library +#=============================================================================== +# Build as shared by default if no linkage type option set. +if (NOT FLANG_RT_ENABLE_SHARED AND NOT FLANG_RT_ENABLE_STATIC) + add_library(flang-rt SHARED $ + $) +endif() +if (FLANG_RT_ENABLE_SHARED) + add_library(flang-rt SHARED $ + $) +endif() +if (FLANG_RT_ENABLE_STATIC AND NOT FLANG_RT_ENABLE_SHARED) + add_library(flang-rt STATIC $ + $) +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 $ + $) +endif() diff --git a/flang-rt/docs/GettingStarted.md b/flang-rt/docs/GettingStarted.md new file mode 100644 index 0000000000000..ffc721aa9b4a4 --- /dev/null +++ b/flang-rt/docs/GettingStarted.md @@ -0,0 +1,156 @@ + + +# Flang-rt Runtime Library + +```eval_rst +.. contents:: + :local: +``` +## What is Flang-rt +Flang-rt is the runtime library project for Flang. The Flang driver requires +the Fortran_main and Flang-rt libraries at runtime in order to generate +user executables. Building this Flang-rt project will build both Fortran_main +and the Flang-rt library, which is comprised of the FortranRuntime and +FortranDecimalRT libraries. + +### Fortran_main +Fortran_main is left out of the Flang-rt library because it is required to +always be static unlike the link type of the Flang-rt library which can be +configured. Fortran_main implements the main entry point into Fortran's +`PROGRAM` in Flang by being the bridge between object files generated by Flang +and the C runtime that takes care of program set-up at system-level. For +every Fortran `PROGRAM`, Flang generates the `_QQmain` function. +Fortran_main implements the C `main` function that simply calls +`_QQmain`. + +### FortranDecimalRT +In order to decouple the common dependency between compiler and runtime, +[FortranDecimal's sources](../../flang/lib/Decimal/CMakeLists.txt) are built +separately for the compiler and the runtime. When the library is built for +Flang-rt, the name FortranDecimalRT is used to avoid naming conflicts and +confusion. + +### FortranRuntime +This is the core runtime library in Flang-rt. The sources for this library +currently still exist in the +[Flang source directory](../../flang/runtime/CMakeLists.txt). We hope to +migrate the sources to the Flang-rt directory in the future in order to further +decouple the runtime from the Flang compiler. + +## Building Flang-rt +Like other LLVM runtimes, Flang-rt can be built by targetting the +[runtimes LLVM target](../../runtimes/CMakelists.txt). It can also be built +when targetting the [llvm target](../../llvm/CMakeLists.txt) as an enabled +runtime. Flang-rt will implicitly be added as an enabled runtime when Flang +is an enabled project built by llvm. Flang-rt does not support standalone +builds. + +In the future, we may be interested in supporting in optionally building +Flang-rt when doing a Flang standalone build. + +### Building with the llvm target +Assuming you are building Flang-rt to use with Flang, see +[Flang's Getting Started guide](../../flang/docs/GettingStarted.md) for more +information. To build Flang-rt when building the Flang compiler, once you have +the llvm-project source ready, make a clean build directory. Let root be the +root directory that you cloned llvm-project into. +```bash +cd root +rm -rf build +mkdir build +cd build +``` +Now invoke the cmake configuration command for llvm that would build Flang with +Flang-rt. +```bash +cmake \ + -G Ninja \ + -DLLVM_ENABLE_RUNTIMES="compiler-rt;flang-rt" \ + -DCMAKE_CXX_STANDARD=17 \ + -DLLVM_INSTALL_UTILS=On \ + # New Flang-rt flags for enabled link types + -DFLANG_RT_ENABLE_STATIC=On \ + -DFLANG_RT_ENABLE_SHARED=On \ + # We need to enable GTest if we want to run Flang-rt's testsuites + -DLLVM_INSTALL_GTEST=On \ + -DFLANG_ENABLE_WERROR=On \ + -DLLVM_LIT_ARGS=-v \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_ENABLE_PROJECTS="clang;flang;lld;mlir;openmp" \ + ../llvm-project/llvm +``` +Flang requires other llvm projects (see LLVM_ENABLE_PROJECTS and the [Flang +Getting Started Guide](../../flang/docs/GettingStarted.md) for more specifics +on building Flang. + +By targetting the LLVM project, we are letting LLVM infrastructure handle +invoking the runtimes target that will build Flang-rt. This includes finding +the cmake packages for Clang, LLVM, Flang and MLIR that Flang-rt depends on. + +### Building with the runtimes target +If you already have a pre-built/installed version of LLVM, Flang, Clang and +MLIR, and would like to build Flang-rt without rebuilding the sources for these +other projects. You can simply target the runtimes project directly and passing +the paths to the directories of these files. If you built LLVM as we did above +with default build directories, your runtimes invocation should look something +like: +```bash +cd build +BUILDDIR=`pwd` + +cmake \ + -G Ninja \ + -DCMAKE_CXX_STANDARD=17 \ + # New Flang-rt flags for enabled link types + -DFLANG_RT_ENABLE_SHARED=On \ + -DFLANG_RT_ENABLE_STATIC=On \ + -DLLVM_LIT_ARGS=-v \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,$LD_LIBRARY_PATH" \ + -DLLVM_TARGETS_TO_BUILD=host \ + -DLLVM_EXTERNAL_LIT=$BUILD_DIR/bin/llvm-lit \ + # We need to specify the paths to the cmake packages of the dependencies + -DLLVM_DIR=$BUILD_DIR/lib/cmake/llvm \ + -DMLIR_DIR=$BUILD_DIR/lib/cmake/mlir \ + -DFLANG_DIR=$BUILD_DIR/lib/cmake/flang \ + -DLLVM_ENABLE_RUNTIMES="flang-rt" \ + ../llvm-project/runtimes/ +``` + +## Library locations +When building the llvm target with flang as an enabled project, the Flang-rt +library will be built to `$BUILDDIR/runtimes/runtimes-bins/flang-rt/lib`. When +building the runtimes target with flang-rt as an enabled runtime, the libraries +will be built to `$BUILDDIR/flang-rt/lib` by default. In either configuration, +the Fortran_main library will be built to `$BUILDDIR/lib` by default. + +## Using Flang-rt +The two build paths mentioned above get implicitly added as library paths at the +invocation of the driver. If Flang-rt is a shared library, you must make the +dynamic linker aware of where to look. One method to do so is to set the +environment variable `LD_LIBRARY_PATH` include the path to Flang-rt's directory. + +## Options +Flang-rt introduces 2 CMake options used to configure the library's link type: +``` +option(FLANG_RT_ENABLE_SHARED "Build flang-rt as a shared library." OFF) +option(FLANG_RT_ENABLE_STATIC "Build flang-rt as a static library." OFF) +``` +Both can be specified if you want to build both shared and static versions of +the Flang-rt runtime. If both are specified, the static library will be named +Flang-rt_static.a to avoid naming conflicts, as per the LLVM standard. + +## Usage Examples +```bash +# Example of using Flang with the shared Flang-rt runtime +# First we need to explicitly tell the dynamic linker where to find Flang-rt +# since it was built as shared. +$ $ export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$BUILDDIR/runtimes/runtimes-bins/flang-rt/lib" +$ flang-new -ffree-form hello.f95 -o hello +``` diff --git a/flang-rt/test/CMakeLists.txt b/flang-rt/test/CMakeLists.txt new file mode 100644 index 0000000000000..51cd6ddf864bc --- /dev/null +++ b/flang-rt/test/CMakeLists.txt @@ -0,0 +1,73 @@ +# Test runner infrastructure for Flang-rt. This configures the Flang-rt test +# trees for use by Lit, and delegates to LLVM's lit test handlers. + +llvm_canonicalize_cmake_booleans( + FLANG_STANDALONE_BUILD + LLVM_BUILD_EXAMPLES + LLVM_BYE_LINK_INTO_TOOLS + LLVM_ENABLE_PLUGINS +) + +set(FLANG_TOOLS_DIR ${FLANG_BINARY_DIR}/bin) + +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py + MAIN_CONFIG + ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py + PATHS + ${PATHS_FOR_PLUGINS} +) + +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py + MAIN_CONFIG + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py +) + +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/NonGtestUnit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/NonGtestUnit/lit.site.cfg.py + MAIN_CONFIG + ${CMAKE_CURRENT_SOURCE_DIR}/NonGtestUnit/lit.cfg.py +) + +set(FLANG_RT_TEST_PARAMS + flang_rt_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py) + +set(FLANG_RT_TEST_DEPENDS + LLVMSupport + flang-rt + Fortran_main +) +if (LLVM_ENABLE_PLUGINS AND NOT WIN32) + list(APPEND FLANG_RT_TEST_DEPENDS Bye) +endif() + +if (FLANG_RT_INCLUDE_TESTS) + if (FLANG_RT_GTEST_AVAIL) + list(APPEND FLANG_RT_TEST_DEPENDS FlangRTUnitTests) + endif() +endif() + +add_custom_target(flang-rt-test-depends DEPENDS ${FLANG_RT_TEST_DEPENDS}) + +add_lit_testsuite(check-flang-rt "Running the Flang-rt regression tests" + ${CMAKE_CURRENT_BINARY_DIR} + PARAMS ${FLANG_RT_TEST_PARAMS} + DEPENDS ${FLANG_RT_TEST_DEPENDS} +) +set_target_properties(check-flang-rt PROPERTIES FOLDER "Tests") + +add_lit_testsuites(FLANG_RT ${CMAKE_CURRENT_SOURCE_DIR} + PARAMS ${FLANG_RT_TEST_PARAMS} + DEPENDS ${FLANG_RT_TEST_DEPENDS}) + +# To modify the default target triple for flang-rt tests. +if (DEFINED FLANG_RT_TEST_TARGET_TRIPLE) + if (NOT DEFINED LLVM_TARGET_TRIPLE_ENV OR LLVM_TARGET_TRIPLE_ENV STREQUAL "") + message(FATAL_ERROR "LLVM_TARGET_TRIPLE_ENV must also be defined in order " + "to use FLANG_RT_TEST_TARGET_TRIPLE.") + endif() +endif() diff --git a/flang-rt/test/FortranRuntime/no-cpp-dep.c b/flang-rt/test/FortranRuntime/no-cpp-dep.c new file mode 100644 index 0000000000000..19c0260020b52 --- /dev/null +++ b/flang-rt/test/FortranRuntime/no-cpp-dep.c @@ -0,0 +1,38 @@ +/* +This test makes sure that flang's runtime does not depend on the C++ runtime +library. It tries to link this simple file against libFortranRuntime.a with +a C compiler. + +REQUIRES: c-compiler + +RUN: %cc -std=c99 %s -I%include %libruntime -lm -o /dev/null +*/ + +#include "flang/Runtime/entry-names.h" +#include + +/* +Manually add declarations for the runtime functions that we want to make sure +we're testing. We can't include any headers directly since they likely contain +C++ code that would explode here. +*/ +struct EnvironmentDefaultList; +struct Descriptor; + +double RTNAME(CpuTime)(); + +void RTNAME(ProgramStart)( + int, const char *[], const char *[], const struct EnvironmentDefaultList *); +int32_t RTNAME(ArgumentCount)(); +int32_t RTNAME(GetCommandArgument)(int32_t, const struct Descriptor *, + const struct Descriptor *, const struct Descriptor *); +int32_t RTNAME(GetEnvVariable)(); + +int main() { + double x = RTNAME(CpuTime)(); + RTNAME(ProgramStart)(0, 0, 0, 0); + int32_t c = RTNAME(ArgumentCount)(); + int32_t v = RTNAME(GetCommandArgument)(0, 0, 0, 0); + int32_t e = RTNAME(GetEnvVariable)("FOO", 0, 0); + return x + c + v + e; +} diff --git a/flang-rt/test/NonGtestUnit/lit.cfg.py b/flang-rt/test/NonGtestUnit/lit.cfg.py new file mode 100644 index 0000000000000..32be1d27c8f28 --- /dev/null +++ b/flang-rt/test/NonGtestUnit/lit.cfg.py @@ -0,0 +1,22 @@ +import os + +import lit.Test + +config.name = "flang-rt-OldUnit" + +config.suffixes = [".test"] + +config.test_source_root = os.path.join(config.flang_rt_obj_root, "unittests") +config.test_exec_root = config.test_source_root + +config.test_format = lit.formats.ExecutableTest() + +path = os.path.pathsep.join( + ( + config.flang_rt_lib_dir, + config.flang_bin_dir, + config.flang_libs_dir, + config.environment.get("LD_LIBRARY_PATH", ""), + ) +) +config.environment["LD_LIBRARY_PATH"] = path diff --git a/flang-rt/test/NonGtestUnit/lit.site.cfg.py.in b/flang-rt/test/NonGtestUnit/lit.site.cfg.py.in new file mode 100644 index 0000000000000..83d8e0e04adf9 --- /dev/null +++ b/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") diff --git a/flang-rt/test/Unit/lit.cfg.py b/flang-rt/test/Unit/lit.cfg.py new file mode 100644 index 0000000000000..079516fc86d7a --- /dev/null +++ b/flang-rt/test/Unit/lit.cfg.py @@ -0,0 +1,58 @@ +# -*- Python -*- + +# Configuration file for the 'lit' test runner. + +import os +import platform +import re +import subprocess +import sys + +import lit.formats +import lit.util + +from lit.llvm import llvm_config +from lit.llvm.subst import ToolSubst +from lit.llvm.subst import FindTool + +# name: The name of this test suite. +config.name = "flang-rt-Unit" + +# suffixes: A list of file extensions to treat as test files. +config.suffixes = [] + +# test_source_root: The root path where unit test binaries are located. +# test_exec_root: The root path where tests should be run. +config.test_source_root = os.path.join(config.flang_rt_obj_root, "unittests") +config.test_exec_root = config.test_source_root + +# testFormat: The test format to use to interpret tests. +config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, "Tests") + +# Tweak the PATH to include the flang bin and libs dirs. +path = os.path.pathsep.join( + ( + config.flang_bin_dir, + config.llvm_tools_dir, + config.environment["PATH"] + ) +) +config.environment["PATH"] = path + +path = os.path.pathsep.join( + ( + config.flang_rt_lib_dir, + config.flang_libs_dir, + config.flang_bin_dir, + config.environment.get("LD_LIBRARY_PATH", ""), + ) +) +config.environment["LD_LIBRARY_PATH"] = path + +# Propagate PYTHON_EXECUTABLE into the environment +# config.environment['PYTHON_EXECUTABLE'] = sys.executable + +# To modify the default target triple for flang-rt tests. +if config.flang_rt_test_triple: + config.target_triple = config.flang_rt_test_triple + config.environment[config.llvm_target_triple_env] = config.flang_rt_test_triple diff --git a/flang-rt/test/Unit/lit.site.cfg.py.in b/flang-rt/test/Unit/lit.site.cfg.py.in new file mode 100644 index 0000000000000..4bd4bc40473d8 --- /dev/null +++ b/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") diff --git a/flang-rt/test/lit.cfg.py b/flang-rt/test/lit.cfg.py new file mode 100644 index 0000000000000..97edd482c57c1 --- /dev/null +++ b/flang-rt/test/lit.cfg.py @@ -0,0 +1,173 @@ +# -*- Python -*- + +import os +import platform +import re +import subprocess +import sys + +import lit.formats +import lit.util + +from lit.llvm import llvm_config +from lit.llvm.subst import ToolSubst +from lit.llvm.subst import FindTool + +# Configuration file for the 'lit' test runner. + +# name: The name of this test suite. +config.name = "flang-rt" + +# testFormat: The test format to use to interpret tests. +# +# For now we require '&&' between commands, until they get globally killed and +# the test runner updated. +config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) + +# suffixes: A list of file extensions to treat as test files. +config.suffixes = [ + ".c", + ".cpp", + ".f", + ".F", + ".ff", + ".FOR", + ".for", + ".f77", + ".f90", + ".F90", + ".ff90", + ".f95", + ".F95", + ".ff95", + ".fpp", + ".FPP", + ".cuf", + ".CUF", + ".f18", + ".F18", + ".f03", + ".F03", + ".f08", + ".F08", + ".ll", + ".fir", + ".mlir", +] + +config.substitutions.append(("%PATH%", config.environment["PATH"])) +config.substitutions.append(("%pluginext", config.llvm_plugin_ext)) + +llvm_config.use_default_substitutions() + +# ask llvm-config about asserts +llvm_config.feature_config([("--assertion-mode", {"ON": "asserts"})]) + +# Targets +config.targets = frozenset(config.targets_to_build.split()) +for arch in config.targets_to_build.split(): + config.available_features.add(arch.lower() + "-registered-target") + +# To modify the default target triple for flang-rt tests. +if config.flang_rt_test_triple: + config.target_triple = config.flang_rt_test_triple + config.environment[config.llvm_target_triple_env] = config.flang_rt_test_triple + +# excludes: A list of directories to exclude from the testsuite. The 'Inputs' +# subdirectories contain auxiliary inputs for various tests in their parent +# directories. +config.excludes = ["Inputs", "CMakeLists.txt", "README.txt", "LICENSE.txt"] + +# Plugins (loadable modules) +if config.has_plugins: + config.available_features.add("plugins") + +if config.linked_bye_extension: + config.substitutions.append(("%loadbye", "")) +else: + config.substitutions.append( + ( + "%loadbye", + "-fpass-plugin={}/Bye{}".format( + config.llvm_shlib_dir, config.llvm_plugin_ext + ), + ) + ) + +# test_source_root: The root path where tests are located. +config.test_source_root = os.path.dirname(__file__) + +# test_exec_root: The root path where tests should be run. +config.test_exec_root = os.path.join(config.flang_rt_obj_root, "test") + +llvm_config.with_environment("PATH", config.flang_bin_dir, append_path=True) +llvm_config.with_environment("PATH", config.flang_rt_obj_root, append_path=True) +llvm_config.with_environment("PATH", config.flang_libs_dir, append_path=True) +llvm_config.with_environment("PATH", config.flang_rt_lib_dir, append_path=True) + +# For each occurrence of a flang tool name, replace it with the full path to +# the build directory holding that tool. +tools = [ + ToolSubst("%flang", command=FindTool("flang-new"), unresolved="fatal"), + ToolSubst( + "%flang_fc1", + command=FindTool("flang-new"), + extra_args=["-fc1"], + unresolved="fatal", + ), +] + +# Flang has several unimplemented features. TODO messages are used to mark +# and fail if these features are exercised. Some TODOs exit with a non-zero +# exit code, but others abort the execution in assert builds. +# To catch aborts, the `--crash` option for the `not` command has to be used. +tools.append(ToolSubst("%not_todo_cmd", command=FindTool("not"), unresolved="fatal")) +if "asserts" in config.available_features: + tools.append( + ToolSubst( + "%not_todo_abort_cmd", + command=FindTool("not"), + extra_args=["--crash"], + unresolved="fatal", + ) + ) +else: + tools.append( + ToolSubst("%not_todo_abort_cmd", command=FindTool("not"), unresolved="fatal") + ) + +# Define some variables to help us test that the flang runtime doesn't depend on +# the C++ runtime libraries. For this we need a C compiler. If for some reason +# we don't have one, we can just disable the test. +if config.cc: + libruntime_static = os.path.join(config.flang_rt_lib_dir, "libflang-rt.a") + libruntime_shared = os.path.join(config.flang_rt_lib_dir, "libflang-rt.so") + include = os.path.join(config.flang_src_dir, "include") + + if ( + os.path.isfile(libruntime_static) + and os.path.isdir(include) + ): + config.available_features.add("c-compiler") + tools.append(ToolSubst("%cc", command=config.cc, unresolved="fatal")) + tools.append(ToolSubst("%libruntime", command=libruntime_static, unresolved="fatal")) + tools.append(ToolSubst("%include", command=include, unresolved="fatal")) + + elif ( + os.path.isfile(libruntime_shared) + and os.path.isdir(include) + ): + config.available_features.add("c-compiler") + tools.append(ToolSubst("%cc", command=config.cc, unresolved="fatal")) + tools.append(ToolSubst("%libruntime", command=libruntime_shared, unresolved="fatal")) + tools.append(ToolSubst("%include", command=include, unresolved="fatal")) + + +# Add all the tools and their substitutions (if applicable). Use the search paths provided for +# finding the tools. +llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir) + +# Enable libpgmath testing +result = lit_config.params.get("LIBPGMATH") +if result: + config.environment["LIBPGMATH"] = True diff --git a/flang-rt/test/lit.site.cfg.py.in b/flang-rt/test/lit.site.cfg.py.in new file mode 100644 index 0000000000000..8a9873b1eabaf --- /dev/null +++ b/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") diff --git a/flang-rt/unittests/CMakeLists.txt b/flang-rt/unittests/CMakeLists.txt new file mode 100644 index 0000000000000..2b813c6e16dfa --- /dev/null +++ b/flang-rt/unittests/CMakeLists.txt @@ -0,0 +1,81 @@ +if (FLANG_EXPERIMENTAL_CUDA_RUNTIME) + # If Fortran runtime is built as CUDA library, the linking + # of targets that link FortranRuntime must be done + # with CUDA_RESOLVE_DEVICE_SYMBOLS. + # CUDA language must be enabled for CUDA_RESOLVE_DEVICE_SYMBOLS + # to take effect. + enable_language(CUDA) +endif() + +add_custom_target(FlangRTUnitTests) +set_target_properties(FlangRTUnitTests PROPERTIES FOLDER "Flang-rt Unit Tests") + +function(add_flang_rt_unittest_offload_properties target) + # Set CUDA_RESOLVE_DEVICE_SYMBOLS. + if (FLANG_EXPERIMENTAL_CUDA_RUNTIME) + set_target_properties(${target} + PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS ON + ) + endif() + # Enable OpenMP offload during linking. We may need to replace + # LINK_OPTIONS with COMPILE_OPTIONS when there are OpenMP offload + # unittests. + # + # FIXME: replace 'native' in --offload-arch option with the list + # of targets that Fortran Runtime was built for. + # Common code must be moved from flang/runtime/CMakeLists.txt. + # TODO: Revisit this because of Flang-rt. runtime is no longer an added subdirectory of flang. + if (NOT FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD STREQUAL "off") + set_target_properties(${target} + PROPERTIES LINK_OPTIONS + "-fopenmp;--offload-arch=native" + ) + endif() +endfunction() + +if(NOT TARGET llvm_gtest) + message(FATAL_ERROR "Target llvm_gtest not found.") +endif() + +function(add_flang_rt_unittest test_dirname) + add_unittest(FlangRTUnitTests ${test_dirname} ${ARGN}) + add_flang_rt_unittest_offload_properties(${test_dirname}) +endfunction() + +if (CXX_SUPPORTS_SUGGEST_OVERRIDE_FLAG) + add_compile_options("-Wno-suggest-override") +endif() + +function(add_flang_rt_nongtest_unittest test_name) + cmake_parse_arguments(ARG + "SLOW_TEST" + "" + "" + ${ARGN}) + + list(APPEND LLVM_COMPILE_FLAGS "-L${LLVM_BINARY_DIR}/lib") + if(ARG_SLOW_TEST) + set(suffix .slow) + else() + set(suffix .test) + endif() + + add_executable(${test_name}${suffix} ${test_name}.cpp) + + if (LLVM_LINK_LLVM_DYLIB AND NOT ARG_DISABLE_LLVM_LINK_LLVM_DYLIB) + set(llvm_libs LLVM) + else() + llvm_map_components_to_libnames(llvm_libs Support) + endif() + target_link_libraries(${test_name}${suffix} ${llvm_libs} ${ARG_UNPARSED_ARGUMENTS}) + + if(NOT ARG_SLOW_TEST) + add_dependencies(FlangRTUnitTests ${test_name}${suffix}) + endif() + + add_flang_rt_unittest_offload_properties(${test_name}${suffix}) +endfunction() + +add_subdirectory(FortranRuntime) +# TODO: We may want to find a better location for these tests that use the runtime +add_subdirectory(FortranEvaluate) diff --git a/flang-rt/unittests/FortranEvaluate/CMakeLists.txt b/flang-rt/unittests/FortranEvaluate/CMakeLists.txt new file mode 100644 index 0000000000000..211018f5559da --- /dev/null +++ b/flang-rt/unittests/FortranEvaluate/CMakeLists.txt @@ -0,0 +1,21 @@ +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +add_library(FlangRTFortranEvaluateTesting + testing.cpp +) +if (LLVM_LINK_LLVM_DYLIB) + set(llvm_libs LLVM) +else() + llvm_map_components_to_libnames(llvm_libs Support) +endif() +target_link_libraries(FlangRTFortranEvaluateTesting + ${llvm_libs}) + +add_flang_rt_nongtest_unittest(reshape + FlangRTFortranEvaluateTesting + flang-rt +) + +add_flang_rt_nongtest_unittest(ISO-Fortran-binding + FlangRTFortranEvaluateTesting + flang-rt +) diff --git a/flang/unittests/Evaluate/ISO-Fortran-binding.cpp b/flang-rt/unittests/FortranEvaluate/ISO-Fortran-binding.cpp similarity index 100% rename from flang/unittests/Evaluate/ISO-Fortran-binding.cpp rename to flang-rt/unittests/FortranEvaluate/ISO-Fortran-binding.cpp diff --git a/flang/unittests/Evaluate/reshape.cpp b/flang-rt/unittests/FortranEvaluate/reshape.cpp similarity index 100% rename from flang/unittests/Evaluate/reshape.cpp rename to flang-rt/unittests/FortranEvaluate/reshape.cpp diff --git a/flang-rt/unittests/FortranEvaluate/testing.cpp b/flang-rt/unittests/FortranEvaluate/testing.cpp new file mode 100644 index 0000000000000..cf0422f621c2f --- /dev/null +++ b/flang-rt/unittests/FortranEvaluate/testing.cpp @@ -0,0 +1,128 @@ +#include "testing.h" +#include +#include +#include + +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(got), + static_cast(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(x), rel, ys, + static_cast(y)); + return PrintFailureDetails; + } +} + +int Complete() { + if (failures == 0) { + if (passes == 1) { + fprintf(stdout, "single test PASSES\n"); + } else { + fprintf(stdout, "all %d tests PASS\n", passes); + } + passes = 0; + return EXIT_SUCCESS; + } else { + if (passes == 1) { + fprintf(stderr, "1 test passes, "); + } else { + fprintf(stderr, "%d tests pass, ", passes); + } + if (failures == 1) { + fprintf(stderr, "1 test FAILS\n"); + } else { + fprintf(stderr, "%d tests FAIL\n", failures); + } + passes = failures = 0; + return EXIT_FAILURE; + } +} +} // namespace testing diff --git a/flang-rt/unittests/FortranEvaluate/testing.h b/flang-rt/unittests/FortranEvaluate/testing.h new file mode 100644 index 0000000000000..e4c8dc93f9be0 --- /dev/null +++ b/flang-rt/unittests/FortranEvaluate/testing.h @@ -0,0 +1,37 @@ +#ifndef FORTRAN_EVALUATE_TESTING_H_ +#define FORTRAN_EVALUATE_TESTING_H_ + +#include +#include + +namespace testing { + +// Returns EXIT_SUCCESS or EXIT_FAILURE, so a test's main() should end +// with "return testing::Complete()". +int Complete(); + +// Pass/fail testing. These macros return a pointer to a printf-like +// function that can be optionally called to print more detail, e.g. +// COMPARE(x, ==, y)("z is 0x%llx", z); +// will also print z after the usual failure message if x != y. +#define TEST(predicate) \ + testing::Test(__FILE__, __LINE__, #predicate, (predicate)) +#define MATCH(want, got) testing::Match(__FILE__, __LINE__, (want), #got, (got)) +#define COMPARE(x, rel, y) \ + testing::Compare(__FILE__, __LINE__, #x, #rel, #y, (x), (y)) + +// Functions called by these macros; do not call directly. +using FailureDetailPrinter = void (*)(const char *, ...); +FailureDetailPrinter Test(const char *file, int line, const char *predicate, + bool pass); +FailureDetailPrinter Match(const char *file, int line, std::uint64_t want, + const char *gots, std::uint64_t got); +FailureDetailPrinter Match(const char *file, int line, const char *want, + const char *gots, const std::string &got); +FailureDetailPrinter Match(const char *file, int line, const std::string &want, + const char *gots, const std::string &got); +FailureDetailPrinter Compare(const char *file, int line, const char *xs, + const char *rel, const char *ys, std::uint64_t x, + std::uint64_t y); +} // namespace testing +#endif // FORTRAN_EVALUATE_TESTING_H_ diff --git a/flang/unittests/Runtime/Allocatable.cpp b/flang-rt/unittests/FortranRuntime/Allocatable.cpp similarity index 100% rename from flang/unittests/Runtime/Allocatable.cpp rename to flang-rt/unittests/FortranRuntime/Allocatable.cpp diff --git a/flang/unittests/Runtime/ArrayConstructor.cpp b/flang-rt/unittests/FortranRuntime/ArrayConstructor.cpp similarity index 100% rename from flang/unittests/Runtime/ArrayConstructor.cpp rename to flang-rt/unittests/FortranRuntime/ArrayConstructor.cpp diff --git a/flang/unittests/Runtime/BufferTest.cpp b/flang-rt/unittests/FortranRuntime/BufferTest.cpp similarity index 82% rename from flang/unittests/Runtime/BufferTest.cpp rename to flang-rt/unittests/FortranRuntime/BufferTest.cpp index 0632324b25d22..ce905b254a27e 100644 --- a/flang/unittests/Runtime/BufferTest.cpp +++ b/flang-rt/unittests/FortranRuntime/BufferTest.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "../../runtime/buffer.h" +#include "flang/../../runtime/buffer.h" #include "CrashHandlerFixture.h" #include "gtest/gtest.h" #include @@ -30,15 +30,16 @@ class Store : public FileFrame { 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(at), static_cast(minBytes), - static_cast(maxBytes), static_cast(expect_)); + static_cast(at), static_cast(minBytes), + static_cast(maxBytes), + static_cast(expect_)); } else if (at < 0 || at + minBytes > bytes_) { handler.SignalError("Read(%d,%d,%d) is out of bounds", - static_cast(at), static_cast(minBytes), - static_cast(maxBytes)); + static_cast(at), static_cast(minBytes), + static_cast(maxBytes)); } auto result{std::min(maxBytes, bytes_ - at)}; std::memcpy(to, &data_[at], result); @@ -46,14 +47,14 @@ class Store : public FileFrame { 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(at), static_cast(bytes), - static_cast(expect_)); + static_cast(at), static_cast(bytes), + static_cast(expect_)); } else if (at < 0 || at + bytes > bytes_) { handler.SignalError("Write(%d,%d) is out of bounds", static_cast(at), - static_cast(bytes)); + static_cast(bytes)); } std::memcpy(&data_[at], from, bytes); expect_ = at + bytes; @@ -70,8 +71,8 @@ class Store : public FileFrame { inline int ChunkSize(int j, int most) { // 31, 1, 29, 3, 27, ... j %= tinyBufferSize; - auto chunk{static_cast( - ((j % 2) ? j : (tinyBufferSize - 1 - j)) % tinyBufferSize)}; + auto chunk{static_cast(((j % 2) ? j : (tinyBufferSize - 1 - j)) % + tinyBufferSize)}; return std::min(chunk, most); } diff --git a/flang/unittests/Runtime/CMakeLists.txt b/flang-rt/unittests/FortranRuntime/CMakeLists.txt similarity index 84% rename from flang/unittests/Runtime/CMakeLists.txt rename to flang-rt/unittests/FortranRuntime/CMakeLists.txt index 23f02aa751246..3b03315794fcc 100644 --- a/flang/unittests/Runtime/CMakeLists.txt +++ b/flang-rt/unittests/FortranRuntime/CMakeLists.txt @@ -1,4 +1,4 @@ -add_flang_unittest(FlangRuntimeTests +add_flang_rt_unittest(FortranRuntimeTests Allocatable.cpp ArrayConstructor.cpp BufferTest.cpp @@ -29,7 +29,7 @@ add_flang_unittest(FlangRuntimeTests Transformational.cpp ) -target_link_libraries(FlangRuntimeTests +target_link_libraries(FortranRuntimeTests PRIVATE - FortranRuntime + flang-rt ) diff --git a/flang/unittests/Runtime/CharacterTest.cpp b/flang-rt/unittests/FortranRuntime/CharacterTest.cpp similarity index 100% rename from flang/unittests/Runtime/CharacterTest.cpp rename to flang-rt/unittests/FortranRuntime/CharacterTest.cpp diff --git a/flang/unittests/Runtime/CommandTest.cpp b/flang-rt/unittests/FortranRuntime/CommandTest.cpp similarity index 100% rename from flang/unittests/Runtime/CommandTest.cpp rename to flang-rt/unittests/FortranRuntime/CommandTest.cpp diff --git a/flang/unittests/Runtime/Complex.cpp b/flang-rt/unittests/FortranRuntime/Complex.cpp similarity index 100% rename from flang/unittests/Runtime/Complex.cpp rename to flang-rt/unittests/FortranRuntime/Complex.cpp diff --git a/flang/unittests/Runtime/CrashHandlerFixture.cpp b/flang-rt/unittests/FortranRuntime/CrashHandlerFixture.cpp similarity index 86% rename from flang/unittests/Runtime/CrashHandlerFixture.cpp rename to flang-rt/unittests/FortranRuntime/CrashHandlerFixture.cpp index 811603337e660..1ce8bf826cf27 100644 --- a/flang/unittests/Runtime/CrashHandlerFixture.cpp +++ b/flang-rt/unittests/FortranRuntime/CrashHandlerFixture.cpp @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// #include "CrashHandlerFixture.h" -#include "../../runtime/terminator.h" +#include "flang/../../runtime/terminator.h" #include #include // Replaces Fortran runtime's crash handler so we can verify the crash message -[[noreturn]] static void CatchCrash( - const char *sourceFile, int sourceLine, const char *message, va_list &ap) { +[[noreturn]] static void CatchCrash(const char *sourceFile, int sourceLine, + const char *message, va_list &ap) { char buffer[1000]; std::vsnprintf(buffer, sizeof buffer, message, ap); va_end(ap); diff --git a/flang/unittests/Runtime/CrashHandlerFixture.h b/flang-rt/unittests/FortranRuntime/CrashHandlerFixture.h similarity index 100% rename from flang/unittests/Runtime/CrashHandlerFixture.h rename to flang-rt/unittests/FortranRuntime/CrashHandlerFixture.h diff --git a/flang/unittests/Runtime/Derived.cpp b/flang-rt/unittests/FortranRuntime/Derived.cpp similarity index 100% rename from flang/unittests/Runtime/Derived.cpp rename to flang-rt/unittests/FortranRuntime/Derived.cpp diff --git a/flang/unittests/Runtime/ExternalIOTest.cpp b/flang-rt/unittests/FortranRuntime/ExternalIOTest.cpp similarity index 100% rename from flang/unittests/Runtime/ExternalIOTest.cpp rename to flang-rt/unittests/FortranRuntime/ExternalIOTest.cpp diff --git a/flang/unittests/Runtime/Format.cpp b/flang-rt/unittests/FortranRuntime/Format.cpp similarity index 100% rename from flang/unittests/Runtime/Format.cpp rename to flang-rt/unittests/FortranRuntime/Format.cpp diff --git a/flang/unittests/Runtime/Inquiry.cpp b/flang-rt/unittests/FortranRuntime/Inquiry.cpp similarity index 100% rename from flang/unittests/Runtime/Inquiry.cpp rename to flang-rt/unittests/FortranRuntime/Inquiry.cpp diff --git a/flang/unittests/Runtime/ListInputTest.cpp b/flang-rt/unittests/FortranRuntime/ListInputTest.cpp similarity index 83% rename from flang/unittests/Runtime/ListInputTest.cpp rename to flang-rt/unittests/FortranRuntime/ListInputTest.cpp index a4eba5283add6..c855ed93ee4b0 100644 --- a/flang/unittests/Runtime/ListInputTest.cpp +++ b/flang-rt/unittests/FortranRuntime/ListInputTest.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "CrashHandlerFixture.h" -#include "../../runtime/io-error.h" +#include "flang/../../runtime/io-error.h" #include "flang/Runtime/descriptor.h" #include "flang/Runtime/io-api.h" @@ -36,15 +36,15 @@ TEST(InputTest, TestListInputAlphabet) { // Use _two_ input buffers and _three_ output buffers. Note the `3*` in the // _inputBuffers_. SetCharacter(inputBuffers[j++], maxInputBufferLength, - "3*'abcdefghijklmnopqrstuvwxyzABC"); - SetCharacter( - inputBuffers[j++], maxInputBufferLength, "DEFGHIJKLMNOPQRSTUVWXYZ'"); + "3*'abcdefghijklmnopqrstuvwxyzABC"); + SetCharacter(inputBuffers[j++], maxInputBufferLength, + "DEFGHIJKLMNOPQRSTUVWXYZ'"); StaticDescriptor<1> staticDescriptor; Descriptor &whole{staticDescriptor.descriptor()}; SubscriptValue extent[]{numInputBuffers}; whole.Establish(TypeCode{CFI_type_char}, maxInputBufferLength, &inputBuffers, - 1, extent, CFI_attribute_pointer); + 1, extent, CFI_attribute_pointer); whole.Check(); auto *cookie{IONAME(BeginInternalArrayListInput)(whole)}; @@ -79,7 +79,7 @@ TEST(InputTest, TestListInputIntegerList) { Descriptor &whole{staticDescriptor.descriptor()}; SubscriptValue extent[]{numBuffers}; whole.Establish(TypeCode{CFI_type_char}, maxBufferLength, &buffer, 1, extent, - CFI_attribute_pointer); + CFI_attribute_pointer); whole.Check(); auto *cookie{IONAME(BeginInternalArrayListInput)(whole)}; @@ -88,10 +88,10 @@ TEST(InputTest, TestListInputIntegerList) { // Negative numbers will be overwritten by _expectedOutput_, and positive // numbers will not be as their indices are "Null values" of the Fortran 2018 // standard 13.10.3.2 in the format strings _buffer_ - std::int64_t actualOutput[listInputLength]{ - -1, -2, -3, -4, 5, -6, 7, -8, 9, 10}; - const std::int64_t expectedOutput[listInputLength]{ - 1, 2, 3, 3, 5, 6, 7, 8, 9, 10}; + std::int64_t actualOutput[listInputLength]{-1, -2, -3, -4, 5, + -6, 7, -8, 9, 10}; + const std::int64_t expectedOutput[listInputLength]{1, 2, 3, 3, 5, + 6, 7, 8, 9, 10}; for (j = 0; j < listInputLength; ++j) { IONAME(InputInteger)(cookie, actualOutput[j]); } @@ -116,7 +116,7 @@ TEST(InputTest, TestListInputInvalidFormatWithSingleSuccess) { Descriptor &whole{staticDescriptor.descriptor()}; SubscriptValue extent[]{numBuffers}; whole.Establish(TypeCode{CFI_type_char}, formatBuffer.size(), - formatBuffer.data(), 1, extent, CFI_attribute_pointer); + formatBuffer.data(), 1, extent, CFI_attribute_pointer); whole.Check(); auto *cookie{IONAME(BeginInternalArrayListInput)(whole)}; @@ -127,7 +127,7 @@ TEST(InputTest, TestListInputInvalidFormatWithSingleSuccess) { // Perform failing InputInteger ASSERT_DEATH(IONAME(InputInteger)(cookie, dummy), - "Bad character 'g' in INTEGER input field"); + "Bad character 'g' in INTEGER input field"); } // Same test as _TestListInputInvalidFormatWithSingleSuccess_, however no @@ -140,7 +140,7 @@ TEST(InputTest, TestListInputInvalidFormat) { Descriptor &whole{staticDescriptor.descriptor()}; SubscriptValue extent[]{numBuffers}; whole.Establish(TypeCode{CFI_type_char}, formatBuffer.size(), - formatBuffer.data(), 1, extent, CFI_attribute_pointer); + formatBuffer.data(), 1, extent, CFI_attribute_pointer); whole.Check(); auto *cookie{IONAME(BeginInternalArrayListInput)(whole)}; @@ -148,7 +148,7 @@ TEST(InputTest, TestListInputInvalidFormat) { // Perform failing InputInteger ASSERT_DEATH(IONAME(InputInteger)(cookie, dummy), - "Bad character 'g' in INTEGER input field"); + "Bad character 'g' in INTEGER input field"); } using ParamTy = std::tuple>; @@ -163,7 +163,7 @@ TEST_P(SimpleListInputTest, TestListInput) { Descriptor &whole{staticDescriptor.descriptor()}; SubscriptValue extent[]{numBuffers}; whole.Establish(TypeCode{CFI_type_char}, formatBuffer.size(), - formatBuffer.data(), 1, extent, CFI_attribute_pointer); + formatBuffer.data(), 1, extent, CFI_attribute_pointer); whole.Check(); auto *cookie{IONAME(BeginInternalArrayListInput)(whole)}; @@ -185,9 +185,10 @@ TEST_P(SimpleListInputTest, TestListInput) { } } -INSTANTIATE_TEST_SUITE_P(SimpleListInputTestInstantiation, SimpleListInputTest, +INSTANTIATE_TEST_SUITE_P( + SimpleListInputTestInstantiation, SimpleListInputTest, testing::Values(std::make_tuple("", std::vector{}), - std::make_tuple("0", std::vector{}), - std::make_tuple("1", std::vector{1}), - std::make_tuple("1, 2", std::vector{1, 2}), - std::make_tuple("3*2", std::vector{2, 2, 2}))); + std::make_tuple("0", std::vector{}), + std::make_tuple("1", std::vector{1}), + std::make_tuple("1, 2", std::vector{1, 2}), + std::make_tuple("3*2", std::vector{2, 2, 2}))); diff --git a/flang/unittests/Runtime/LogicalFormatTest.cpp b/flang-rt/unittests/FortranRuntime/LogicalFormatTest.cpp similarity index 100% rename from flang/unittests/Runtime/LogicalFormatTest.cpp rename to flang-rt/unittests/FortranRuntime/LogicalFormatTest.cpp diff --git a/flang/unittests/Runtime/Matmul.cpp b/flang-rt/unittests/FortranRuntime/Matmul.cpp similarity index 100% rename from flang/unittests/Runtime/Matmul.cpp rename to flang-rt/unittests/FortranRuntime/Matmul.cpp diff --git a/flang/unittests/Runtime/MatmulTranspose.cpp b/flang-rt/unittests/FortranRuntime/MatmulTranspose.cpp similarity index 100% rename from flang/unittests/Runtime/MatmulTranspose.cpp rename to flang-rt/unittests/FortranRuntime/MatmulTranspose.cpp diff --git a/flang/unittests/Runtime/MiscIntrinsic.cpp b/flang-rt/unittests/FortranRuntime/MiscIntrinsic.cpp similarity index 100% rename from flang/unittests/Runtime/MiscIntrinsic.cpp rename to flang-rt/unittests/FortranRuntime/MiscIntrinsic.cpp diff --git a/flang/unittests/Runtime/Namelist.cpp b/flang-rt/unittests/FortranRuntime/Namelist.cpp similarity index 73% rename from flang/unittests/Runtime/Namelist.cpp rename to flang-rt/unittests/FortranRuntime/Namelist.cpp index 5911d67f0d5fc..2e3c5c2919297 100644 --- a/flang/unittests/Runtime/Namelist.cpp +++ b/flang-rt/unittests/FortranRuntime/Namelist.cpp @@ -6,11 +6,11 @@ // //===----------------------------------------------------------------------===// -#include "../../runtime/namelist.h" +#include "flang/../../runtime/namelist.h" #include "CrashHandlerFixture.h" -#include "tools.h" #include "flang/Runtime/descriptor.h" #include "flang/Runtime/io-api.h" +#include "tools.h" #include #include #include @@ -27,7 +27,7 @@ struct NamelistTests : CrashHandlerFixture {}; static void ClearDescriptorStorage(const Descriptor &descriptor) { std::memset(descriptor.raw().base_addr, 0, - descriptor.Elements() * descriptor.ElementBytes()); + descriptor.Elements() * descriptor.ElementBytes()); } TEST(NamelistTests, BasicSanity) { @@ -38,17 +38,20 @@ TEST(NamelistTests, BasicSanity) { Descriptor &internalDesc{statDescs[0].descriptor()}; SubscriptValue extent[]{numLines}; internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/lineLength, - &buffer, 1, extent, CFI_attribute_pointer); + &buffer, 1, extent, CFI_attribute_pointer); // Set up data arrays std::vector ints; for (int j{0}; j < 20; ++j) { ints.push_back(j % 2 == 0 ? (1 << j) : -(1 << j)); } - std::vector reals{0.0, -0.0, std::numeric_limits::infinity(), - -std::numeric_limits::infinity(), - std::numeric_limits::quiet_NaN(), - std::numeric_limits::max(), std::numeric_limits::lowest(), - std::numeric_limits::epsilon()}; + std::vector reals{0.0, + -0.0, + std::numeric_limits::infinity(), + -std::numeric_limits::infinity(), + std::numeric_limits::quiet_NaN(), + std::numeric_limits::max(), + std::numeric_limits::lowest(), + std::numeric_limits::epsilon()}; std::vector logicals; logicals.push_back(false); logicals.push_back(true); @@ -76,12 +79,14 @@ TEST(NamelistTests, BasicSanity) { // Create a NAMELIST group static constexpr int items{5}; const NamelistGroup::Item itemArray[items]{{"ints", *intDesc}, - {"reals", *realDesc}, {"logicals", *logicalDesc}, - {"complexes", *complexDesc}, {"characters", *characterDesc}}; + {"reals", *realDesc}, + {"logicals", *logicalDesc}, + {"complexes", *complexDesc}, + {"characters", *characterDesc}}; const NamelistGroup group{"group1", items, itemArray}; // Do an internal NAMELIST write and check results - auto outCookie1{IONAME(BeginInternalArrayListOutput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + auto outCookie1{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(SetDelim)(outCookie1, "APOSTROPHE", 10)); ASSERT_TRUE(IONAME(OutputNamelist)(outCookie1, group)); auto outStatus1{IONAME(EndIoStatement)(outCookie1)}; @@ -109,14 +114,14 @@ TEST(NamelistTests, BasicSanity) { ClearDescriptorStorage(*logicalDesc); ClearDescriptorStorage(*complexDesc); ClearDescriptorStorage(*characterDesc); - auto inCookie{IONAME(BeginInternalArrayListInput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group)); auto inStatus{IONAME(EndIoStatement)(inCookie)}; ASSERT_EQ(inStatus, 0) << "Failed namelist input sanity, status " << static_cast(inStatus); - auto outCookie2{IONAME(BeginInternalArrayListOutput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + auto outCookie2{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(SetDelim)(outCookie2, "APOSTROPHE", 10)); ASSERT_TRUE(IONAME(OutputNamelist)(outCookie2, group)); auto outStatus2{IONAME(EndIoStatement)(outCookie2)}; @@ -139,18 +144,19 @@ TEST(NamelistTests, Subscripts) { StaticDescriptor<1, true> statDesc; Descriptor &internalDesc{statDesc.descriptor()}; internalDesc.Establish(TypeCode{CFI_type_char}, - /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer); - auto inCookie{IONAME(BeginInternalArrayListInput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, + CFI_attribute_pointer); + auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group)); auto inStatus{IONAME(EndIoStatement)(inCookie)}; ASSERT_EQ(inStatus, 0) << "Failed namelist input subscripts, status " << static_cast(inStatus); char out[40]; internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out, - out, 0, nullptr, CFI_attribute_pointer); - auto outCookie{IONAME(BeginInternalArrayListOutput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + out, 0, nullptr, CFI_attribute_pointer); + auto outCookie{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group)); auto outStatus{IONAME(EndIoStatement)(outCookie)}; ASSERT_EQ(outStatus, 0) @@ -177,8 +183,8 @@ TEST(NamelistTests, ShortArrayInput) { Descriptor &internalDesc{statDesc.descriptor()}; SubscriptValue shape{2}; internalDesc.Establish(1, 12, t1, 1, &shape, CFI_attribute_pointer); - auto inCookie{IONAME(BeginInternalArrayListInput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group)); auto inStatus{IONAME(EndIoStatement)(inCookie)}; ASSERT_EQ(inStatus, 0) << "Failed namelist input subscripts, status " @@ -198,17 +204,18 @@ TEST(NamelistTests, ScalarSubstring) { StaticDescriptor<1, true> statDesc; Descriptor &internalDesc{statDesc.descriptor()}; internalDesc.Establish(TypeCode{CFI_type_char}, - /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer); - auto inCookie{IONAME(BeginInternalArrayListInput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, + CFI_attribute_pointer); + auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group)); ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk) << "namelist scalar substring input"; char out[32]; internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out, - out, 0, nullptr, CFI_attribute_pointer); - auto outCookie{IONAME(BeginInternalArrayListOutput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + out, 0, nullptr, CFI_attribute_pointer); + auto outCookie{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(SetDelim)(outCookie, "apostrophe", 10)); ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group)); ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output"; @@ -218,26 +225,27 @@ TEST(NamelistTests, ScalarSubstring) { } TEST(NamelistTests, ArraySubstring) { - OwningPtr scDesc{ - MakeArray(std::vector{2}, - std::vector{"abcdefgh", "ijklmnop"}, 8)}; + OwningPtr scDesc{MakeArray( + std::vector{2}, std::vector{"abcdefgh", "ijklmnop"}, + 8)}; const NamelistGroup::Item items[]{{"a", *scDesc}}; const NamelistGroup group{"justa", 1, items}; static char t1[]{"&justa A(:)(2:+5)='BCDE' 'JKLM'/"}; StaticDescriptor<1, true> statDesc; Descriptor &internalDesc{statDesc.descriptor()}; internalDesc.Establish(TypeCode{CFI_type_char}, - /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer); - auto inCookie{IONAME(BeginInternalArrayListInput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, + CFI_attribute_pointer); + auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group)); ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk) << "namelist scalar substring input"; char out[40]; internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out, - out, 0, nullptr, CFI_attribute_pointer); - auto outCookie{IONAME(BeginInternalArrayListOutput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + out, 0, nullptr, CFI_attribute_pointer); + auto outCookie{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(SetDelim)(outCookie, "apostrophe", 10)); ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group)); ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output"; @@ -256,17 +264,18 @@ TEST(NamelistTests, Skip) { StaticDescriptor<1, true> statDesc; Descriptor &internalDesc{statDesc.descriptor()}; internalDesc.Establish(TypeCode{CFI_type_char}, - /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer); - auto inCookie{IONAME(BeginInternalArrayListInput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, + CFI_attribute_pointer); + auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group)); ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk) << "namelist input with skipping"; char out[20]; internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out, - out, 0, nullptr, CFI_attribute_pointer); - auto outCookie{IONAME(BeginInternalArrayListOutput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + out, 0, nullptr, CFI_attribute_pointer); + auto outCookie{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group)); ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output"; std::string got{out, sizeof out}; @@ -285,18 +294,19 @@ TEST(NamelistTests, Comma) { StaticDescriptor<1, true> statDesc; Descriptor &internalDesc{statDesc.descriptor()}; internalDesc.Establish(TypeCode{CFI_type_char}, - /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, CFI_attribute_pointer); - auto inCookie{IONAME(BeginInternalArrayListInput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + /*elementBytes=*/std::strlen(t1), t1, 0, nullptr, + CFI_attribute_pointer); + auto inCookie{IONAME(BeginInternalArrayListInput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(SetDecimal)(inCookie, "COMMA", 5)); ASSERT_TRUE(IONAME(InputNamelist)(inCookie, group)); ASSERT_EQ(IONAME(EndIoStatement)(inCookie), IostatOk) << "namelist input with skipping"; char out[30]; internalDesc.Establish(TypeCode{CFI_type_char}, /*elementBytes=*/sizeof out, - out, 0, nullptr, CFI_attribute_pointer); - auto outCookie{IONAME(BeginInternalArrayListOutput)( - internalDesc, nullptr, 0, __FILE__, __LINE__)}; + out, 0, nullptr, CFI_attribute_pointer); + auto outCookie{IONAME(BeginInternalArrayListOutput)(internalDesc, nullptr, 0, + __FILE__, __LINE__)}; ASSERT_TRUE(IONAME(SetDecimal)(outCookie, "COMMA", 5)); ASSERT_TRUE(IONAME(OutputNamelist)(outCookie, group)); ASSERT_EQ(IONAME(EndIoStatement)(outCookie), IostatOk) << "namelist output"; diff --git a/flang/unittests/Runtime/Numeric.cpp b/flang-rt/unittests/FortranRuntime/Numeric.cpp similarity index 100% rename from flang/unittests/Runtime/Numeric.cpp rename to flang-rt/unittests/FortranRuntime/Numeric.cpp diff --git a/flang/unittests/Runtime/NumericalFormatTest.cpp b/flang-rt/unittests/FortranRuntime/NumericalFormatTest.cpp similarity index 100% rename from flang/unittests/Runtime/NumericalFormatTest.cpp rename to flang-rt/unittests/FortranRuntime/NumericalFormatTest.cpp diff --git a/flang/unittests/Runtime/Pointer.cpp b/flang-rt/unittests/FortranRuntime/Pointer.cpp similarity index 100% rename from flang/unittests/Runtime/Pointer.cpp rename to flang-rt/unittests/FortranRuntime/Pointer.cpp diff --git a/flang/unittests/Runtime/Ragged.cpp b/flang-rt/unittests/FortranRuntime/Ragged.cpp similarity index 100% rename from flang/unittests/Runtime/Ragged.cpp rename to flang-rt/unittests/FortranRuntime/Ragged.cpp diff --git a/flang/unittests/Runtime/Random.cpp b/flang-rt/unittests/FortranRuntime/Random.cpp similarity index 100% rename from flang/unittests/Runtime/Random.cpp rename to flang-rt/unittests/FortranRuntime/Random.cpp diff --git a/flang/unittests/Runtime/Reduction.cpp b/flang-rt/unittests/FortranRuntime/Reduction.cpp similarity index 100% rename from flang/unittests/Runtime/Reduction.cpp rename to flang-rt/unittests/FortranRuntime/Reduction.cpp diff --git a/flang/unittests/Runtime/RuntimeCrashTest.cpp b/flang-rt/unittests/FortranRuntime/RuntimeCrashTest.cpp similarity index 66% rename from flang/unittests/Runtime/RuntimeCrashTest.cpp rename to flang-rt/unittests/FortranRuntime/RuntimeCrashTest.cpp index 34a8ff6d37113..580ffe69f2448 100644 --- a/flang/unittests/Runtime/RuntimeCrashTest.cpp +++ b/flang-rt/unittests/FortranRuntime/RuntimeCrashTest.cpp @@ -11,10 +11,10 @@ // //===----------------------------------------------------------------------===// #include "CrashHandlerFixture.h" -#include "tools.h" -#include "../../runtime/terminator.h" +#include "flang/../../runtime/terminator.h" #include "flang/Runtime/io-api.h" #include "flang/Runtime/transformational.h" +#include "tools.h" #include using namespace Fortran::runtime; @@ -26,7 +26,7 @@ using Fortran::common::TypeCategory; //------------------------------------------------------------------------------ struct TestTerminator : CrashHandlerFixture {}; -#define TEST_CRASH_HANDLER_MESSAGE \ +#define TEST_CRASH_HANDLER_MESSAGE \ "Intentionally crashing runtime for unit test" TEST(TestTerminator, CrashTest) { @@ -39,13 +39,13 @@ TEST(TestTerminator, CrashTest) { TEST(TestTerminator, CheckFailedLocationTest) { static Fortran::runtime::Terminator t; ASSERT_DEATH(t.CheckFailed("predicate", "someFileName", 789), - "RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(789\\)"); + "RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(789\\)"); } TEST(TestTerminator, CheckFailedTest) { static Fortran::runtime::Terminator t; ASSERT_DEATH(t.CheckFailed("predicate"), - "RUNTIME_CHECK\\(predicate\\) failed at \\(null\\)\\(0\\)"); + "RUNTIME_CHECK\\(predicate\\) failed at \\(null\\)\\(0\\)"); } //------------------------------------------------------------------------------ @@ -57,9 +57,10 @@ TEST(TestIOCrash, FormatDescriptorWriteMismatchTest) { static constexpr int bufferSize{4}; static char buffer[bufferSize]; static const char *format{"(A4)"}; - auto *cookie{IONAME(BeginInternalFormattedOutput)( - buffer, bufferSize, format, std::strlen(format))}; - ASSERT_DEATH(IONAME(OutputLogical)(cookie, true), + auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format, + std::strlen(format))}; + ASSERT_DEATH( + IONAME(OutputLogical)(cookie, true), "Data edit descriptor 'A' may not be used with a LOGICAL data item"); } @@ -67,10 +68,10 @@ TEST(TestIOCrash, InvalidFormatCharacterTest) { static constexpr int bufferSize{1}; static char buffer[bufferSize]; static const char *format{"(C1)"}; - auto *cookie{IONAME(BeginInternalFormattedOutput)( - buffer, bufferSize, format, std::strlen(format))}; + auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format, + std::strlen(format))}; ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xfeedface), - "Unknown 'C' edit descriptor in FORMAT"); + "Unknown 'C' edit descriptor in FORMAT"); } //------------------------------------------------------------------------------ @@ -83,80 +84,80 @@ TEST(TestIOCrash, OverwriteBufferAsciiTest) { static constexpr int bufferSize{4}; static char buffer[bufferSize]; static const char *format{"(A4)"}; - auto *cookie{IONAME(BeginInternalFormattedOutput)( - buffer, bufferSize, format, std::strlen(format))}; + auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format, + std::strlen(format))}; IONAME(OutputAscii)(cookie, "four", bufferSize); ASSERT_DEATH(IONAME(OutputAscii)(cookie, "Too many characters!", 20), - "Internal write overran available records"); + "Internal write overran available records"); } TEST(TestIOCrash, OverwriteBufferCharacterTest) { static constexpr int bufferSize{1}; static char buffer[bufferSize]; static const char *format{"(A1)"}; - auto *cookie{IONAME(BeginInternalFormattedOutput)( - buffer, bufferSize, format, std::strlen(format))}; + auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format, + std::strlen(format))}; IONAME(OutputCharacter)(cookie, "a", 1); ASSERT_DEATH(IONAME(OutputCharacter)(cookie, "a", 1), - "Internal write overran available records"); + "Internal write overran available records"); } TEST(TestIOCrash, OverwriteBufferLogicalTest) { static constexpr int bufferSize{1}; static char buffer[bufferSize]; static const char *format{"(L1)"}; - auto *cookie{IONAME(BeginInternalFormattedOutput)( - buffer, bufferSize, format, std::strlen(format))}; + auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format, + std::strlen(format))}; IONAME(OutputLogical)(cookie, true); ASSERT_DEATH(IONAME(OutputLogical)(cookie, true), - "Internal write overran available records"); + "Internal write overran available records"); } TEST(TestIOCrash, OverwriteBufferRealTest) { static constexpr int bufferSize{1}; static char buffer[bufferSize]; static const char *format{"(F1)"}; - auto *cookie{IONAME(BeginInternalFormattedOutput)( - buffer, bufferSize, format, std::strlen(format))}; + auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format, + std::strlen(format))}; IONAME(OutputReal32)(cookie, 1.); EXPECT_DEATH(IONAME(OutputReal32)(cookie, 1.), - "Internal write overran available records"); + "Internal write overran available records"); std::memset(buffer, '\0', bufferSize); - cookie = IONAME(BeginInternalFormattedOutput)( - buffer, bufferSize, format, std::strlen(format)); + cookie = IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format, + std::strlen(format)); IONAME(OutputReal64)(cookie, 1.); EXPECT_DEATH(IONAME(OutputReal64)(cookie, 1.), - "Internal write overran available records"); + "Internal write overran available records"); } TEST(TestIOCrash, OverwriteBufferComplexTest) { static constexpr int bufferSize{8}; static char buffer[bufferSize]; static const char *format{"(Z1,Z1)"}; - auto *cookie{IONAME(BeginInternalFormattedOutput)( - buffer, bufferSize, format, std::strlen(format))}; + auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format, + std::strlen(format))}; IONAME(OutputComplex32)(cookie, 1., 1.); EXPECT_DEATH(IONAME(OutputComplex32)(cookie, 1., 1.), - "Internal write overran available records"); + "Internal write overran available records"); std::memset(buffer, '\0', bufferSize); - cookie = IONAME(BeginInternalFormattedOutput)( - buffer, bufferSize, format, std::strlen(format)); + cookie = IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format, + std::strlen(format)); IONAME(OutputComplex64)(cookie, 1., 1.); EXPECT_DEATH(IONAME(OutputComplex64)(cookie, 1., 1.), - "Internal write overran available records"); + "Internal write overran available records"); } TEST(TestIOCrash, OverwriteBufferIntegerTest) { static constexpr int bufferSize{1}; static char buffer[bufferSize]; static const char *format{"(I1)"}; - auto *cookie{IONAME(BeginInternalFormattedOutput)( - buffer, bufferSize, format, std::strlen(format))}; + auto *cookie{IONAME(BeginInternalFormattedOutput)(buffer, bufferSize, format, + std::strlen(format))}; IONAME(OutputInteger64)(cookie, 0xdeadbeef); ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xdeadbeef), - "Internal write overran available records"); + "Internal write overran available records"); } //------------------------------------------------------------------------------ @@ -168,13 +169,15 @@ TEST(TestIntrinsicCrash, ConformityErrors) { // ARRAY(2,3) and MASK(2,4) should trigger a runtime error. auto array{MakeArray( std::vector{2, 3}, std::vector{1, 2, 3, 4, 5, 6})}; - auto mask{MakeArray(std::vector{2, 4}, - std::vector{ - false, true, true, false, false, true, true, true})}; + auto mask{MakeArray( + std::vector{2, 4}, + std::vector{false, true, true, false, false, true, true, + true})}; StaticDescriptor<1, true> statDesc; Descriptor &result{statDesc.descriptor()}; - ASSERT_DEATH(RTNAME(Pack)(result, *array, *mask, nullptr, __FILE__, __LINE__), + ASSERT_DEATH( + RTNAME(Pack)(result, *array, *mask, nullptr, __FILE__, __LINE__), "Incompatible array arguments to PACK: dimension 2 of ARRAY= has extent " "3 but MASK= has extent 4"); } diff --git a/flang/unittests/Runtime/Stop.cpp b/flang-rt/unittests/FortranRuntime/Stop.cpp similarity index 54% rename from flang/unittests/Runtime/Stop.cpp rename to flang-rt/unittests/FortranRuntime/Stop.cpp index b13602eaee5ea..1c5611dd39683 100644 --- a/flang/unittests/Runtime/Stop.cpp +++ b/flang-rt/unittests/FortranRuntime/Stop.cpp @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "flang/Runtime/stop.h" #include "CrashHandlerFixture.h" -#include "../../runtime/environment.h" +#include "flang/../../runtime/environment.h" #include #include @@ -21,67 +21,69 @@ struct TestProgramEnd : CrashHandlerFixture {}; TEST(TestProgramEnd, StopTest) { EXPECT_EXIT(RTNAME(StopStatement)(), testing::ExitedWithCode(EXIT_SUCCESS), - "Fortran STOP"); + "Fortran STOP"); } TEST(TestProgramEnd, StopTestNoStopMessage) { putenv(const_cast("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("NO_STOP_MESSAGE=1")); - Fortran::runtime::executionEnvironment.Configure( - 0, nullptr, nullptr, nullptr); + Fortran::runtime::executionEnvironment.Configure(0, nullptr, nullptr, + nullptr); static const char *message{"bye bye"}; EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message), - /*isErrorStop=*/false, /*quiet=*/false), - testing::ExitedWithCode(EXIT_SUCCESS), "bye bye"); + /*isErrorStop=*/false, /*quiet=*/false), + testing::ExitedWithCode(EXIT_SUCCESS), "bye bye"); EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message), - /*isErrorStop=*/false, /*quiet=*/true), - testing::ExitedWithCode(EXIT_SUCCESS), ""); + /*isErrorStop=*/false, /*quiet=*/true), + testing::ExitedWithCode(EXIT_SUCCESS), ""); EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message), - /*isErrorStop=*/true, /*quiet=*/false), - testing::ExitedWithCode(EXIT_FAILURE), "Fortran ERROR STOP: bye bye"); + /*isErrorStop=*/true, /*quiet=*/false), + testing::ExitedWithCode(EXIT_FAILURE), + "Fortran ERROR STOP: bye bye"); EXPECT_EXIT(RTNAME(StopStatementText)(message, std::strlen(message), - /*isErrorStop=*/true, /*quiet=*/true), - testing::ExitedWithCode(EXIT_FAILURE), ""); + /*isErrorStop=*/true, /*quiet=*/true), + testing::ExitedWithCode(EXIT_FAILURE), ""); } TEST(TestProgramEnd, FailImageTest) { - EXPECT_EXIT( - RTNAME(FailImageStatement)(), testing::ExitedWithCode(EXIT_FAILURE), ""); + EXPECT_EXIT(RTNAME(FailImageStatement)(), + testing::ExitedWithCode(EXIT_FAILURE), ""); } TEST(TestProgramEnd, ExitTest) { EXPECT_EXIT(RTNAME(Exit)(), testing::ExitedWithCode(EXIT_SUCCESS), ""); - EXPECT_EXIT( - RTNAME(Exit)(EXIT_FAILURE), testing::ExitedWithCode(EXIT_FAILURE), ""); + EXPECT_EXIT(RTNAME(Exit)(EXIT_FAILURE), testing::ExitedWithCode(EXIT_FAILURE), + ""); } TEST(TestProgramEnd, AbortTest) { EXPECT_DEATH(RTNAME(Abort)(), ""); } @@ -91,8 +93,8 @@ TEST(TestProgramEnd, CrashTest) { static const std::string fileName{"file name"}; static const std::string headMessage{"fatal Fortran runtime error\\("}; static const std::string tailMessage{":343\\): "}; - static const std::string fullMessage{ - headMessage + fileName + tailMessage + crashMessage}; + static const std::string fullMessage{headMessage + fileName + tailMessage + + crashMessage}; EXPECT_DEATH( RTNAME(ReportFatalUserError)(crashMessage.c_str(), fileName.c_str(), 343), fullMessage.c_str()); diff --git a/flang/unittests/Runtime/TemporaryStack.cpp b/flang-rt/unittests/FortranRuntime/TemporaryStack.cpp similarity index 100% rename from flang/unittests/Runtime/TemporaryStack.cpp rename to flang-rt/unittests/FortranRuntime/TemporaryStack.cpp diff --git a/flang/unittests/Runtime/Time.cpp b/flang-rt/unittests/FortranRuntime/Time.cpp similarity index 100% rename from flang/unittests/Runtime/Time.cpp rename to flang-rt/unittests/FortranRuntime/Time.cpp diff --git a/flang/unittests/Runtime/Transformational.cpp b/flang-rt/unittests/FortranRuntime/Transformational.cpp similarity index 100% rename from flang/unittests/Runtime/Transformational.cpp rename to flang-rt/unittests/FortranRuntime/Transformational.cpp diff --git a/flang/unittests/Runtime/tools.h b/flang-rt/unittests/FortranRuntime/tools.h similarity index 100% rename from flang/unittests/Runtime/tools.h rename to flang-rt/unittests/FortranRuntime/tools.h diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt index ac30da89995ed..893d5a4750813 100644 --- a/flang/CMakeLists.txt +++ b/flang/CMakeLists.txt @@ -188,7 +188,7 @@ if (FLANG_STANDALONE_BUILD) if (FLANG_GTEST_AVAIL) add_custom_target(check-all DEPENDS check-flang FlangUnitTests) else() - add_custom_target(check-all DEPENDS check-flang ) + add_custom_target(check-all DEPENDS check-flang) endif() if (LLVM_BUILD_DOCS) add_custom_target(doxygen ALL) @@ -421,6 +421,11 @@ if (FLANG_INCLUDE_TESTS) add_compile_definitions(FLANG_INCLUDE_TESTS=1) endif() +# Add Flang subdirectories. +# NOTE: The runtime subdirectory is no longer added here. +# Sources for the runtime are added in Flang-rt. +# TODO: Move the runtime sources to the flang-rt top level directory. + add_subdirectory(include) add_subdirectory(lib) add_subdirectory(cmake/modules) @@ -430,7 +435,6 @@ option(FLANG_BUILD_TOOLS if (FLANG_BUILD_TOOLS) add_subdirectory(tools) endif() -add_subdirectory(runtime) if (LLVM_INCLUDE_EXAMPLES) add_subdirectory(examples) diff --git a/flang/cmake/modules/AddFlang.cmake b/flang/cmake/modules/AddFlang.cmake index 41ce8738e7bf2..a072f372bcff8 100644 --- a/flang/cmake/modules/AddFlang.cmake +++ b/flang/cmake/modules/AddFlang.cmake @@ -17,7 +17,7 @@ macro(add_flang_subdirectory name) endmacro() function(add_flang_library name) - set(options SHARED STATIC INSTALL_WITH_TOOLCHAIN) + set(options SHARED STATIC INSTALL_WITH_TOOLCHAIN PIC) set(multiValueArgs ADDITIONAL_HEADERS CLANG_LIBS) cmake_parse_arguments(ARG "${options}" @@ -65,6 +65,9 @@ function(add_flang_library name) endif() llvm_add_library(${name} ${LIBTYPE} ${ARG_UNPARSED_ARGUMENTS} ${srcs}) + if (ARG_PIC) + set_target_properties(${name} PROPERTIES POSITION_INDEPENDENT_CODE ON) + endif() clang_target_link_libraries(${name} PRIVATE ${ARG_CLANG_LIBS}) diff --git a/flang/cmake/modules/FlangConfig.cmake.in b/flang/cmake/modules/FlangConfig.cmake.in index ac4b77bd8514a..359a1dbac617e 100644 --- a/flang/cmake/modules/FlangConfig.cmake.in +++ b/flang/cmake/modules/FlangConfig.cmake.in @@ -9,6 +9,8 @@ find_package(LLVM ${LLVM_VERSION} EXACT REQUIRED CONFIG set(FLANG_EXPORTED_TARGETS "@FLANG_EXPORTS@") set(FLANG_CMAKE_DIR "@FLANG_CONFIG_CMAKE_DIR@") set(FLANG_INCLUDE_DIRS "@FLANG_CONFIG_INCLUDE_DIRS@") +set(FLANG_SOURCE_DIR "@FLANG_SOURCE_DIR@") +set(FLANG_BINARY_DIR "@FLANG_BINARY_DIR@") # Provide all our library targets to users. @FLANG_CONFIG_INCLUDE_EXPORTS@ diff --git a/flang/lib/Decimal/CMakeLists.txt b/flang/lib/Decimal/CMakeLists.txt index 3116ff68ea262..211c19693de81 100644 --- a/flang/lib/Decimal/CMakeLists.txt +++ b/flang/lib/Decimal/CMakeLists.txt @@ -49,7 +49,19 @@ endif() # avoid an unwanted dependency on libstdc++.so. add_definitions(-U_GLIBCXX_ASSERTIONS) -add_flang_library(FortranDecimal INSTALL_WITH_TOOLCHAIN - binary-to-decimal.cpp - decimal-to-binary.cpp -) +# Build FortranDecimal when the build target is Flang or LLVM. +if (CMAKE_SOURCE_DIR STREQUAL FLANG_SOURCE_DIR OR CMAKE_SOURCE_DIR STREQUAL LLVM_MAIN_SRC_DIR) + add_flang_library(FortranDecimal + binary-to-decimal.cpp + decimal-to-binary.cpp + ) +# Build FortranDecimalRT for FlangRT when the build target is Runtimes. +# Standalone builds of FlangRT is not supported. +elseif (CMAKE_SOURCE_DIR STREQUAL Runtimes_SOURCE_DIR) + add_flang_library(FortranDecimalRT STATIC INSTALL_WITH_TOOLCHAIN PIC + binary-to-decimal.cpp + decimal-to-binary.cpp + ) +else() + message(FATAL_ERROR "CMAKE_SOURCE_DIR of target points to neither Flang or Flang-rt, no library added for FortranDecimal.") +endif() diff --git a/flang/runtime/CMakeLists.txt b/flang/runtime/CMakeLists.txt index e7d416749219e..51f1e16be778b 100644 --- a/flang/runtime/CMakeLists.txt +++ b/flang/runtime/CMakeLists.txt @@ -6,10 +6,14 @@ # #===------------------------------------------------------------------------===# +# TODO: Maybe this file should still be added by flang/CMakeLists.txt and +# when FLANG_STANDALONE_BUILD=On and a new variable FLANG_BUILD_RUNTIME=On +# we should invoke an ExternalProject_Add(flang-rt ...) from here? + if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) cmake_minimum_required(VERSION 3.20.0) - project(FlangRuntime C CXX) + project(FortranRuntime C CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) @@ -82,8 +86,6 @@ append(${NO_LTO_FLAGS} CMAKE_CXX_FLAGS) add_definitions(-U_GLIBCXX_ASSERTIONS) add_definitions(-U_LIBCPP_ENABLE_ASSERTIONS) -add_subdirectory(FortranMain) - set(sources ISO_Fortran_binding.cpp allocatable.cpp @@ -268,10 +270,13 @@ if (NOT FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD STREQUAL "off") endif() endif() -add_flang_library(FortranRuntime +add_compile_options(-fPIC) + +add_flang_library(FortranRuntime STATIC ${sources} LINK_LIBS - FortranDecimal + FortranDecimalRT INSTALL_WITH_TOOLCHAIN + PIC ) diff --git a/flang/runtime/sum.cpp b/flang/runtime/sum.cpp index c3c1482963846..6ca6620c16cde 100644 --- a/flang/runtime/sum.cpp +++ b/flang/runtime/sum.cpp @@ -138,10 +138,15 @@ CppTypeFor RTNAME(SumReal10)(const Descriptor &x, } #endif #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 +#if HAS_FLOAT128 +using AccumType = __float128; +#else // if LDBL_MANT_DIG == 113 +using AccumType = long double; +#endif CppTypeFor RTNAME(SumReal16)(const Descriptor &x, const char *source, int line, int dim, const Descriptor *mask) { return GetTotalReduction( - x, source, line, dim, mask, RealSumAccumulator{x}, "SUM"); + x, source, line, dim, mask, RealSumAccumulator{x}, "SUM"); } #endif diff --git a/flang/test/CMakeLists.txt b/flang/test/CMakeLists.txt index 7d96a72e5f36d..e93d594490b64 100644 --- a/flang/test/CMakeLists.txt +++ b/flang/test/CMakeLists.txt @@ -61,9 +61,6 @@ set(FLANG_TEST_DEPENDS llvm-objdump llvm-readobj split-file - FortranRuntime - Fortran_main - FortranDecimal ) if (LLVM_ENABLE_PLUGINS AND NOT WIN32) list(APPEND FLANG_TEST_DEPENDS Bye) diff --git a/flang/test/Driver/linker-flags.f90 b/flang/test/Driver/linker-flags.f90 index 09b8a224df138..2fbf3c4bf3450 100644 --- a/flang/test/Driver/linker-flags.f90 +++ b/flang/test/Driver/linker-flags.f90 @@ -24,21 +24,18 @@ ! GNU-LABEL: "{{.*}}ld{{(\.exe)?}}" ! GNU-SAME: "[[object_file]]" ! GNU-SAME: -lFortran_main -! GNU-SAME: -lFortranRuntime -! GNU-SAME: -lFortranDecimal +! GNU-SAME: -lflang-rt ! GNU-SAME: -lm ! DARWIN-LABEL: "{{.*}}ld{{(\.exe)?}}" ! DARWIN-SAME: "[[object_file]]" ! DARWIN-SAME: -lFortran_main -! DARWIN-SAME: -lFortranRuntime -! DARWIN-SAME: -lFortranDecimal +! DARWIN-SAME: -lflang-rt ! MINGW-LABEL: "{{.*}}ld{{(\.exe)?}}" ! MINGW-SAME: "[[object_file]]" ! MINGW-SAME: -lFortran_main -! MINGW-SAME: -lFortranRuntime -! MINGW-SAME: -lFortranDecimal +! MINGW-SAME: -lflang-rt ! NOTE: This also matches lld-link (when CLANG_DEFAULT_LINKER=lld) and ! any .exe suffix that is added when resolving to the full path of @@ -46,7 +43,6 @@ ! when the executable is not found or on non-Windows platforms. ! MSVC-LABEL: link ! MSVC-SAME: Fortran_main.lib -! MSVC-SAME: FortranRuntime.lib -! MSVC-SAME: FortranDecimal.lib +! MSVC-SAME: flang-rt.lib ! MSVC-SAME: /subsystem:console ! MSVC-SAME: "[[object_file]]" diff --git a/flang/test/lit.cfg.py b/flang/test/lit.cfg.py index dda8ed456c986..89a2353047c30 100644 --- a/flang/test/lit.cfg.py +++ b/flang/test/lit.cfg.py @@ -153,19 +153,16 @@ # the C++ runtime libraries. For this we need a C compiler. If for some reason # we don't have one, we can just disable the test. if config.cc: - libruntime = os.path.join(config.flang_lib_dir, "libFortranRuntime.a") - libdecimal = os.path.join(config.flang_lib_dir, "libFortranDecimal.a") + libruntime = os.path.join(config.flang_lib_dir, "libflang-rt.a") include = os.path.join(config.flang_src_dir, "include") if ( os.path.isfile(libruntime) - and os.path.isfile(libdecimal) and os.path.isdir(include) ): config.available_features.add("c-compiler") tools.append(ToolSubst("%cc", command=config.cc, unresolved="fatal")) tools.append(ToolSubst("%libruntime", command=libruntime, unresolved="fatal")) - tools.append(ToolSubst("%libdecimal", command=libdecimal, unresolved="fatal")) tools.append(ToolSubst("%include", command=include, unresolved="fatal")) # Add all the tools and their substitutions (if applicable). Use the search paths provided for diff --git a/flang/tools/flang-driver/CMakeLists.txt b/flang/tools/flang-driver/CMakeLists.txt index 3ce8b407450d2..9f33cdfe3fa90 100644 --- a/flang/tools/flang-driver/CMakeLists.txt +++ b/flang/tools/flang-driver/CMakeLists.txt @@ -14,14 +14,6 @@ set( LLVM_LINK_COMPONENTS add_flang_tool(flang-new driver.cpp fc1_main.cpp - - DEPENDS - # These libraries are used in the linker invocation generated by the driver - # (i.e. when constructing the linker job). Without them the driver would be - # unable to generate executables. - FortranRuntime - FortranDecimal - Fortran_main ) target_link_libraries(flang-new diff --git a/flang/unittests/CMakeLists.txt b/flang/unittests/CMakeLists.txt index 72d37ebeb853c..ab12fd8e7f5da 100644 --- a/flang/unittests/CMakeLists.txt +++ b/flang/unittests/CMakeLists.txt @@ -24,11 +24,15 @@ function(add_flang_unittest_offload_properties target) # FIXME: replace 'native' in --offload-arch option with the list # of targets that Fortran Runtime was built for. # Common code must be moved from flang/runtime/CMakeLists.txt. + # TODO: Revisit this because of Flang-rt. runtime is no longer an added subdirectory of flang. So we temporarily duplicated the option definition to here. This is not a permanent solution. + set(FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD "off" CACHE STRING + "Compile Fortran runtime as OpenMP target offload sources (experimental). Valid options are 'off', 'host_device', 'nohost'") + if (NOT FLANG_EXPERIMENTAL_OMP_OFFLOAD_BUILD STREQUAL "off") set_target_properties(${target} - PROPERTIES LINK_OPTIONS - "-fopenmp;--offload-arch=native" - ) + PROPERTIES LINK_OPTIONS + "-fopenmp;--offload-arch=native" + ) endif() endfunction() @@ -74,5 +78,4 @@ add_subdirectory(Optimizer) add_subdirectory(Common) add_subdirectory(Decimal) add_subdirectory(Evaluate) -add_subdirectory(Runtime) add_subdirectory(Frontend) diff --git a/flang/unittests/Evaluate/CMakeLists.txt b/flang/unittests/Evaluate/CMakeLists.txt index 4658d8d3345b5..f9551dac713a3 100644 --- a/flang/unittests/Evaluate/CMakeLists.txt +++ b/flang/unittests/Evaluate/CMakeLists.txt @@ -45,7 +45,6 @@ add_flang_nongtest_unittest(intrinsics FortranDecimal FortranSemantics FortranParser - FortranRuntime ) add_flang_nongtest_unittest(logical @@ -68,20 +67,6 @@ add_flang_nongtest_unittest(real ) llvm_update_compile_flags(real.test) -add_flang_nongtest_unittest(reshape - FortranEvaluateTesting - FortranSemantics - FortranEvaluate - FortranRuntime -) - -add_flang_nongtest_unittest(ISO-Fortran-binding - FortranEvaluateTesting - FortranEvaluate - FortranSemantics - FortranRuntime -) - add_flang_nongtest_unittest(folding FortranCommon FortranEvaluateTesting diff --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt index 9c165d998e2e1..34b45d0e77822 100644 --- a/flang/unittests/Optimizer/CMakeLists.txt +++ b/flang/unittests/Optimizer/CMakeLists.txt @@ -19,16 +19,6 @@ add_flang_unittest(FlangOptimizerTests Builder/DoLoopHelperTest.cpp Builder/FIRBuilderTest.cpp Builder/HLFIRToolsTest.cpp - Builder/Runtime/AllocatableTest.cpp - Builder/Runtime/AssignTest.cpp - Builder/Runtime/CommandTest.cpp - Builder/Runtime/CharacterTest.cpp - Builder/Runtime/DerivedTest.cpp - Builder/Runtime/NumericTest.cpp - Builder/Runtime/RaggedTest.cpp - Builder/Runtime/ReductionTest.cpp - Builder/Runtime/StopTest.cpp - Builder/Runtime/TransformationalTest.cpp FIRContextTest.cpp FIRTypesTest.cpp FortranVariableTest.cpp diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp index 53e146bb8600b..2eae92906db95 100644 --- a/lld/COFF/MinGW.cpp +++ b/lld/COFF/MinGW.cpp @@ -50,8 +50,7 @@ AutoExporter::AutoExporter( "libc++", "libc++abi", "libFortran_main", - "libFortranRuntime", - "libFortranDecimal", + "libflang-rt", "libunwind", "libmsvcrt", "libucrtbase", diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index 5985256498dcb..7b49ec161c3f3 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -149,7 +149,10 @@ endif() # As we migrate runtimes to using the bootstrapping build, the set of default runtimes # should grow as we remove those runtimes from LLVM_ENABLE_PROJECTS above. set(LLVM_DEFAULT_RUNTIMES "libcxx;libcxxabi;libunwind") -set(LLVM_SUPPORTED_RUNTIMES "libc;libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp;llvm-libgcc") +if ("flang" IN_LIST LLVM_ENABLE_PROJECTS) + set(LLVM_DEFAULT_RUNTIMES "libcxx;libcxxabi;libunwind;flang-rt") +endif() +set(LLVM_SUPPORTED_RUNTIMES "libc;libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp;llvm-libgcc;flang-rt") set(LLVM_ENABLE_RUNTIMES "" CACHE STRING "Semicolon-separated list of runtimes to build, or \"all\" (${LLVM_DEFAULT_RUNTIMES}). Supported runtimes are ${LLVM_SUPPORTED_RUNTIMES}.") if(LLVM_ENABLE_RUNTIMES STREQUAL "all") @@ -171,6 +174,11 @@ if ("libc" IN_LIST LLVM_ENABLE_RUNTIMES) endif() endif() +if ("flang" IN_LIST LLVM_ENABLE_PROJECTS AND NOT "flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES) + message(STATUS "Enabling Flang-rt to be built with the Flang project.") + list(APPEND LLVM_ENABLE_RUNTIMES "flang-rt") +endif() + # LLVM_ENABLE_PROJECTS_USED is `ON` if the user has ever used the # `LLVM_ENABLE_PROJECTS` CMake cache variable. This exists for # several reasons: diff --git a/llvm/projects/CMakeLists.txt b/llvm/projects/CMakeLists.txt index 08f2fa522420b..2f66cd1a4c44b 100644 --- a/llvm/projects/CMakeLists.txt +++ b/llvm/projects/CMakeLists.txt @@ -6,6 +6,7 @@ foreach(entry ${entries}) if(IS_DIRECTORY ${entry} AND EXISTS ${entry}/CMakeLists.txt) if((NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/compiler-rt) AND (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/dragonegg) AND + (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/flang-rt) AND (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/libcxx) AND (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/libcxxabi) AND (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/libunwind) AND @@ -37,6 +38,8 @@ if(${LLVM_BUILD_RUNTIME}) if(NOT LLVM_BUILD_EXTERNAL_COMPILER_RT) add_llvm_external_project(compiler-rt) endif() + + add_llvm_external_project(flang-rt) endif() add_llvm_external_project(dragonegg) diff --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt index 7ec6480773c8f..dc568373e48f0 100644 --- a/llvm/runtimes/CMakeLists.txt +++ b/llvm/runtimes/CMakeLists.txt @@ -401,17 +401,24 @@ if(runtimes) endforeach() endif() endif() + set(EXTRA_CMAKE_ARGS "") + if("flang-rt" IN_LIST LLVM_ENABLE_RUNTIMES) + list(APPEND EXTRA_CMAKE_ARGS "-DLLVM_DIR=${LLVM_BINARY_DIR}/lib/cmake/llvm") + list(APPEND EXTRA_CMAKE_ARGS "-DFLANG_DIR=${LLVM_BINARY_DIR}/lib/cmake/flang") + list(APPEND EXTRA_CMAKE_ARGS "-DCLANG_DIR=${LLVM_BINARY_DIR}/lib/cmake/clang") + list(APPEND EXTRA_CMAKE_ARGS "-DMLIR_DIR=${LLVM_BINARY_DIR}/lib/cmake/mlir") + endif() if(NOT LLVM_RUNTIME_TARGETS) runtime_default_target( DEPENDS ${builtins_dep} ${extra_deps} - CMAKE_ARGS ${libc_cmake_args} + CMAKE_ARGS ${libc_cmake_args} ${EXTRA_CMAKE_ARGS} PREFIXES ${prefixes}) set(test_targets check-runtimes) else() if("default" IN_LIST LLVM_RUNTIME_TARGETS) runtime_default_target( DEPENDS ${builtins_dep} ${extra_deps} - CMAKE_ARGS ${libc_cmake_args} + CMAKE_ARGS ${libc_cmake_args} ${EXTRA_CMAKE_ARGS} PREFIXES ${prefixes}) list(REMOVE_ITEM LLVM_RUNTIME_TARGETS "default") else() @@ -451,7 +458,7 @@ if(runtimes) runtime_register_target(${name} DEPENDS ${builtins_dep_name} ${libc_tools} - CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=${name} ${libc_cmake_args} + CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=${name} ${libc_cmake_args} ${EXTRA_CMAKE_ARGS} EXTRA_ARGS TARGET_TRIPLE ${name}) add_dependencies(runtimes runtimes-${name}) @@ -481,6 +488,7 @@ if(runtimes) CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=${name} -DLLVM_RUNTIMES_PREFIX=${name}/ -DLLVM_RUNTIMES_LIBDIR_SUBDIR=${multilib} + ${EXTRA_CMAKE_ARGS} BASE_NAME ${name} EXTRA_ARGS TARGET_TRIPLE ${name}) diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt index 010ec879e44a3..c26a5f725d59f 100644 --- a/runtimes/CMakeLists.txt +++ b/runtimes/CMakeLists.txt @@ -19,7 +19,7 @@ list(INSERT CMAKE_MODULE_PATH 0 # We order libraries to mirror roughly how they are layered, except that compiler-rt can depend # on libc++, so we put it after. -set(LLVM_DEFAULT_RUNTIMES "libc;libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp") +set(LLVM_DEFAULT_RUNTIMES "libc;libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp;flang-rt") set(LLVM_SUPPORTED_RUNTIMES "${LLVM_DEFAULT_RUNTIMES};llvm-libgcc") set(LLVM_ENABLE_RUNTIMES "" CACHE STRING "Semicolon-separated list of runtimes to build, or \"all\" (${LLVM_DEFAULT_RUNTIMES}). Supported runtimes are ${LLVM_SUPPORTED_RUNTIMES}.")