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