From a30a6421fb103586fa9e25f81a0f248a1f8449f3 Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Fri, 14 Nov 2025 07:54:28 -0600 Subject: [PATCH 01/11] [OpenMP] Add libomp unit test infrastructure --- openmp/runtime/CMakeLists.txt | 1 + openmp/runtime/src/CMakeLists.txt | 13 +- openmp/runtime/unittests/CMakeLists.txt | 39 ++++ openmp/runtime/unittests/README.md | 7 + openmp/runtime/unittests/lit.cfg.py | 22 ++ openmp/runtime/unittests/lit.site.cfg.py.in | 9 + openmp/runtime/unittests/src/CMakeLists.txt | 3 + openmp/runtime/unittests/src/TestKmpStr.cpp | 239 ++++++++++++++++++++ 8 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 openmp/runtime/unittests/CMakeLists.txt create mode 100644 openmp/runtime/unittests/README.md create mode 100644 openmp/runtime/unittests/lit.cfg.py create mode 100644 openmp/runtime/unittests/lit.site.cfg.py.in create mode 100644 openmp/runtime/unittests/src/CMakeLists.txt create mode 100644 openmp/runtime/unittests/src/TestKmpStr.cpp diff --git a/openmp/runtime/CMakeLists.txt b/openmp/runtime/CMakeLists.txt index 93948b941f0dc..33276b7d97d3a 100644 --- a/openmp/runtime/CMakeLists.txt +++ b/openmp/runtime/CMakeLists.txt @@ -446,6 +446,7 @@ endif() add_subdirectory(src) add_subdirectory(test) +add_subdirectory(unittests) # make these variables available for tools: set(LIBOMP_LIBRARY_DIR ${LIBOMP_LIBRARY_DIR} PARENT_SCOPE) diff --git a/openmp/runtime/src/CMakeLists.txt b/openmp/runtime/src/CMakeLists.txt index 0c0804776a774..7440f1fd05f9c 100644 --- a/openmp/runtime/src/CMakeLists.txt +++ b/openmp/runtime/src/CMakeLists.txt @@ -174,17 +174,26 @@ if(NOT WIN32) endif() # Add the OpenMP library + +# First, create an OBJECT library with all the runtime sources. +# This allows both the main library and unit tests to link against the same compiled objects. +add_library(omp_objects OBJECT ${LIBOMP_SOURCE_FILES}) +set_property(TARGET omp_objects PROPERTY FOLDER "OpenMP/Libraries") +set_property(TARGET omp_objects PROPERTY POSITION_INDEPENDENT_CODE ON) +# Export the omp_objects target so unittests can use it +set(LIBOMP_OBJECTS_TARGET omp_objects PARENT_SCOPE) + libomp_get_ldflags(LIBOMP_CONFIGURED_LDFLAGS) libomp_get_libflags(LIBOMP_CONFIGURED_LIBFLAGS) # Build libomp library. Add LLVMSupport dependency if building in-tree with libomptarget profiling enabled. if(OPENMP_STANDALONE_BUILD OR (NOT OPENMP_ENABLE_LIBOMP_PROFILING)) - add_library(omp ${LIBOMP_LIBRARY_KIND} ${LIBOMP_SOURCE_FILES}) + add_library(omp ${LIBOMP_LIBRARY_KIND} $) set_property(TARGET omp PROPERTY FOLDER "OpenMP/Libraries") # Linking command will include libraries in LIBOMP_CONFIGURED_LIBFLAGS target_link_libraries(omp ${LIBOMP_CONFIGURED_LIBFLAGS} ${LIBOMP_DL_LIBS}) else() - add_llvm_library(omp ${LIBOMP_LIBRARY_KIND} ${LIBOMP_SOURCE_FILES} PARTIAL_SOURCES_INTENDED + add_llvm_library(omp ${LIBOMP_LIBRARY_KIND} $ PARTIAL_SOURCES_INTENDED LINK_LIBS ${LIBOMP_CONFIGURED_LIBFLAGS} ${LIBOMP_DL_LIBS} LINK_COMPONENTS Support BUILDTREE_ONLY diff --git a/openmp/runtime/unittests/CMakeLists.txt b/openmp/runtime/unittests/CMakeLists.txt new file mode 100644 index 0000000000000..14ddbfc827cbb --- /dev/null +++ b/openmp/runtime/unittests/CMakeLists.txt @@ -0,0 +1,39 @@ +add_custom_target(OpenMPUnitTests) +set_target_properties(OpenMPUnitTests PROPERTIES FOLDER "OpenMP/Tests") + +if (NOT TARGET llvm_gtest) + message(WARNING "OpenMP unittests disabled due to GTest being unavailable; " + "Try LLVM_INSTALL_GTEST=ON for the LLVM build") + return () +endif () + +function(add_openmp_unittest test_dirname) + add_unittest(OpenMPUnitTests ${test_dirname} ${ARGN}) + + # Link against the object library created in runtime/src + target_link_libraries(${test_dirname} PRIVATE + $ + ) + + target_include_directories(${test_dirname} PRIVATE + ${LIBOMP_INCLUDE_DIR} + ${LIBOMP_SRC_DIR} + ) +endfunction() + +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 +) + +add_openmp_testsuite( + check-libomp-unit + "Running libomp unit tests" + ${CMAKE_CURRENT_BINARY_DIR} + EXCLUDE_FROM_CHECK_ALL + DEPENDS OpenMPUnitTests omp +) + +add_subdirectory(src) diff --git a/openmp/runtime/unittests/README.md b/openmp/runtime/unittests/README.md new file mode 100644 index 0000000000000..ad7dd9d716ceb --- /dev/null +++ b/openmp/runtime/unittests/README.md @@ -0,0 +1,7 @@ +# libomp Unit Tests + +Usage: +``` +cd /runtimes/runtimes-bins +ninja check-libomp-unit +``` \ No newline at end of file diff --git a/openmp/runtime/unittests/lit.cfg.py b/openmp/runtime/unittests/lit.cfg.py new file mode 100644 index 0000000000000..552ea8ef9854d --- /dev/null +++ b/openmp/runtime/unittests/lit.cfg.py @@ -0,0 +1,22 @@ +# -*- Python -*- + +# Configuration file for the 'lit' test runner. + +import os +import subprocess + +import lit.formats + +# name: The name of this test suite. +config.name = "OpenMP-Unit" + +# suffixes: A list of file extensions to treat as test files. +config.suffixes = [] + +# test_source_root: The root path where tests are located. +# test_exec_root: The root path where tests should be run. +config.test_exec_root = config.openmp_unittests_dir +config.test_source_root = config.test_exec_root + +# testFormat: The test format to use to interpret tests. +config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, ".unittests") diff --git a/openmp/runtime/unittests/lit.site.cfg.py.in b/openmp/runtime/unittests/lit.site.cfg.py.in new file mode 100644 index 0000000000000..878c95f1d8e29 --- /dev/null +++ b/openmp/runtime/unittests/lit.site.cfg.py.in @@ -0,0 +1,9 @@ +@AUTO_GEN_COMMENT@ + +config.library_dir = "@LIBOMP_LIBRARY_DIR@" +config.openmp_unittests_dir = "@CMAKE_CURRENT_BINARY_DIR@" +config.llvm_build_mode = lit_config.substitute("@LLVM_BUILD_MODE@") + +# Let the main config do the real work. +lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg.py") + diff --git a/openmp/runtime/unittests/src/CMakeLists.txt b/openmp/runtime/unittests/src/CMakeLists.txt new file mode 100644 index 0000000000000..455fbf0b92fc5 --- /dev/null +++ b/openmp/runtime/unittests/src/CMakeLists.txt @@ -0,0 +1,3 @@ +add_openmp_unittest(libomp.unittests + TestKmpStr.cpp +) diff --git a/openmp/runtime/unittests/src/TestKmpStr.cpp b/openmp/runtime/unittests/src/TestKmpStr.cpp new file mode 100644 index 0000000000000..a22a729da9272 --- /dev/null +++ b/openmp/runtime/unittests/src/TestKmpStr.cpp @@ -0,0 +1,239 @@ +//===- TestKmpStr.cpp - Tests for kmp_str utilities ----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "kmp_str.h" +#include "gtest/gtest.h" +#include + +namespace { + +// Test basic string buffer initialization +TEST(KmpStrTest, BufferInit) { + kmp_str_buf_t buffer; + __kmp_str_buf_init(&buffer); + + EXPECT_NE(buffer.str, nullptr); + EXPECT_GT(buffer.size, 0u); + EXPECT_EQ(buffer.used, 0); + EXPECT_EQ(buffer.str[0], '\0'); +} + +// Test string buffer clear +TEST(KmpStrTest, BufferClear) { + kmp_str_buf_t buffer; + __kmp_str_buf_init(&buffer); + __kmp_str_buf_print(&buffer, "test string"); + + EXPECT_GT(buffer.used, 0); + + __kmp_str_buf_clear(&buffer); + EXPECT_EQ(buffer.used, 0); + EXPECT_EQ(buffer.str[0], '\0'); + + __kmp_str_buf_free(&buffer); +} + +// Test string buffer print +TEST(KmpStrTest, BufferPrint) { + kmp_str_buf_t buffer; + __kmp_str_buf_init(&buffer); + + __kmp_str_buf_print(&buffer, "Hello, %s!", "World"); + + EXPECT_STREQ(buffer.str, "Hello, World!"); + EXPECT_EQ(buffer.used, 13); + + __kmp_str_buf_free(&buffer); +} + +// Test string buffer concatenation +TEST(KmpStrTest, BufferCat) { + kmp_str_buf_t buffer; + __kmp_str_buf_init(&buffer); + + __kmp_str_buf_cat(&buffer, "Hello", 5); + __kmp_str_buf_cat(&buffer, " ", 1); + __kmp_str_buf_cat(&buffer, "World", 5); + + EXPECT_STREQ(buffer.str, "Hello World"); + + __kmp_str_buf_free(&buffer); +} + +// Test string buffer reservation +TEST(KmpStrTest, BufferReserve) { + kmp_str_buf_t buffer; + __kmp_str_buf_init(&buffer); + + size_t large_size = 2048; + __kmp_str_buf_reserve(&buffer, large_size); + + EXPECT_GE(buffer.size, large_size); + + __kmp_str_buf_free(&buffer); +} + +// Test basic string to int conversion +TEST(KmpStrTest, BasicStrToInt) { + EXPECT_EQ(__kmp_basic_str_to_int("0"), 0); + EXPECT_EQ(__kmp_basic_str_to_int("1"), 1); + EXPECT_EQ(__kmp_basic_str_to_int("42"), 42); + EXPECT_EQ(__kmp_basic_str_to_int("123"), 123); +} + +// Test string match +TEST(KmpStrTest, StrMatch) { + const char *data = "Hello World"; + + // Test exact match (len == 0) + EXPECT_TRUE(__kmp_str_match("Hello World", 0, data)); + EXPECT_FALSE(__kmp_str_match("Hello", 0, data)); // Not exact (data is longer) + + // Test prefix match (len < 0) + EXPECT_TRUE( + __kmp_str_match("Hello", -1, data)); // "Hello" is prefix of "Hello World" + EXPECT_FALSE(__kmp_str_match("World", -1, data)); // "World" is not a prefix + + // Test minimum length match (len > 0) + EXPECT_TRUE(__kmp_str_match("Hello", 5, data)); // At least 5 chars match + EXPECT_TRUE(__kmp_str_match("Hello", 3, data)); // At least 3 chars match + EXPECT_FALSE(__kmp_str_match("World", 5, data)); // First chars don't match +} + +// Test string contains +TEST(KmpStrTest, StrContains) { + const char *data = "Hello World"; + + EXPECT_TRUE(__kmp_str_contains("Hello", 5, data)); + EXPECT_TRUE(__kmp_str_contains("World", 5, data)); + EXPECT_TRUE(__kmp_str_contains("lo Wo", 5, data)); + EXPECT_FALSE(__kmp_str_contains("Goodbye", 7, data)); +} + +// Test string match for true/false values +TEST(KmpStrTest, MatchBool) { + // Test true values + EXPECT_TRUE(__kmp_str_match_true("true")); + EXPECT_TRUE(__kmp_str_match_true("TRUE")); + EXPECT_TRUE(__kmp_str_match_true("on")); + EXPECT_TRUE(__kmp_str_match_true("ON")); + EXPECT_TRUE(__kmp_str_match_true("1")); + EXPECT_TRUE(__kmp_str_match_true("yes")); + EXPECT_TRUE(__kmp_str_match_true("YES")); + + // Test false values + EXPECT_TRUE(__kmp_str_match_false("false")); + EXPECT_TRUE(__kmp_str_match_false("FALSE")); + EXPECT_TRUE(__kmp_str_match_false("off")); + EXPECT_TRUE(__kmp_str_match_false("OFF")); + EXPECT_TRUE(__kmp_str_match_false("0")); + EXPECT_TRUE(__kmp_str_match_false("no")); + EXPECT_TRUE(__kmp_str_match_false("NO")); +} + +// Test string replace +TEST(KmpStrTest, StrReplace) { + char str[] = "Hello World"; + __kmp_str_replace(str, ' ', '_'); + EXPECT_STREQ(str, "Hello_World"); + + __kmp_str_replace(str, 'o', '0'); + EXPECT_STREQ(str, "Hell0_W0rld"); +} + +// Test string split +TEST(KmpStrTest, StrSplit) { + char str[] = "key=value"; + char *head = nullptr; + char *tail = nullptr; + + __kmp_str_split(str, '=', &head, &tail); + + EXPECT_STREQ(head, "key"); + EXPECT_STREQ(tail, "value"); +} + +// Test file name parsing +TEST(KmpStrTest, FileNameInit) { + const char *path = "/path/to/file.txt"; + kmp_str_fname_t fname; + __kmp_str_fname_init(&fname, path); + + EXPECT_NE(fname.path, nullptr); + EXPECT_STREQ(fname.path, path); + EXPECT_NE(fname.base, nullptr); + EXPECT_STREQ(fname.base, "file.txt"); + + __kmp_str_fname_free(&fname); +} + +// Test string format +TEST(KmpStrTest, StrFormat) { + char *result = __kmp_str_format("Number: %d, String: %s", 42, "test"); + + EXPECT_NE(result, nullptr); + EXPECT_STREQ(result, "Number: 42, String: test"); + + __kmp_str_free(&result); + EXPECT_EQ(result, nullptr); +} + +// Test string buffer concatenate buffers +TEST(KmpStrTest, BufferCatBuf) { + kmp_str_buf_t buf1, buf2; + __kmp_str_buf_init(&buf1); + __kmp_str_buf_init(&buf2); + + __kmp_str_buf_print(&buf1, "Hello"); + __kmp_str_buf_print(&buf2, " World"); + + __kmp_str_buf_catbuf(&buf1, &buf2); + + EXPECT_STREQ(buf1.str, "Hello World"); + + __kmp_str_buf_free(&buf1); + __kmp_str_buf_free(&buf2); +} + +// Test size string parsing +TEST(KmpStrTest, StrToSize) { + size_t result; + const char *error = nullptr; + + __kmp_str_to_size("100", &result, 1, &error); + EXPECT_EQ(error, nullptr); + EXPECT_EQ(result, 100u); + + __kmp_str_to_size("1K", &result, 1024, &error); + EXPECT_EQ(error, nullptr); + EXPECT_EQ(result, 1024u); + + __kmp_str_to_size("2M", &result, 1024, &error); + EXPECT_EQ(error, nullptr); + EXPECT_EQ(result, 2u * 1024u * 1024u); +} + +// Test uint string parsing +TEST(KmpStrTest, StrToUint) { + kmp_uint64 result; + const char *error = nullptr; + + __kmp_str_to_uint("0", &result, &error); + EXPECT_EQ(error, nullptr); + EXPECT_EQ(result, 0u); + + __kmp_str_to_uint("42", &result, &error); + EXPECT_EQ(error, nullptr); + EXPECT_EQ(result, 42u); + + __kmp_str_to_uint("1234567890", &result, &error); + EXPECT_EQ(error, nullptr); + EXPECT_EQ(result, 1234567890u); +} + +} // namespace From 4d12f2482d4cc58ffd100f2e3484cde7321ceaa9 Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Mon, 17 Nov 2025 04:25:01 -0600 Subject: [PATCH 02/11] dynamic linking for unit tests --- openmp/runtime/src/CMakeLists.txt | 35 ++++++++++++++++++++++--- openmp/runtime/unittests/CMakeLists.txt | 17 +++++++----- openmp/runtime/unittests/README.md | 4 ++- 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/openmp/runtime/src/CMakeLists.txt b/openmp/runtime/src/CMakeLists.txt index 7440f1fd05f9c..7ee648f54de05 100644 --- a/openmp/runtime/src/CMakeLists.txt +++ b/openmp/runtime/src/CMakeLists.txt @@ -176,17 +176,19 @@ endif() # Add the OpenMP library # First, create an OBJECT library with all the runtime sources. -# This allows both the main library and unit tests to link against the same compiled objects. +# This allows both the main library and unit tests to link against the same +# compiled objects. add_library(omp_objects OBJECT ${LIBOMP_SOURCE_FILES}) set_property(TARGET omp_objects PROPERTY FOLDER "OpenMP/Libraries") set_property(TARGET omp_objects PROPERTY POSITION_INDEPENDENT_CODE ON) -# Export the omp_objects target so unittests can use it +# Export the omp_objects target so unit tests can use it set(LIBOMP_OBJECTS_TARGET omp_objects PARENT_SCOPE) libomp_get_ldflags(LIBOMP_CONFIGURED_LDFLAGS) - libomp_get_libflags(LIBOMP_CONFIGURED_LIBFLAGS) -# Build libomp library. Add LLVMSupport dependency if building in-tree with libomptarget profiling enabled. + +# Build libomp library. Add LLVMSupport dependency if building in-tree with +# libomptarget profiling enabled. if(OPENMP_STANDALONE_BUILD OR (NOT OPENMP_ENABLE_LIBOMP_PROFILING)) add_library(omp ${LIBOMP_LIBRARY_KIND} $) set_property(TARGET omp PROPERTY FOLDER "OpenMP/Libraries") @@ -209,6 +211,31 @@ if(${LIBOMP_USE_HWLOC}) ) endif() +# Build a testing version of libomp that exports all symbols for unit tests. +# This library uses the same compiled objects as libomp, but with all symbols +# exported to allow testing internal functions. +if(NOT WIN32 AND NOT STUBS_LIBRARY) + set(LIBOMP_TEST_LDFLAGS ${LIBOMP_CONFIGURED_LDFLAGS}) + # Replace the libomp exports with the test exports exporting all symbols. + if(LIBOMP_HAVE_VERSION_SCRIPT_FLAG) + string(REPLACE "${LIBOMP_SRC_DIR}/exports_so.txt" + "${LIBOMP_SRC_DIR}/exports_test_so.txt" + LIBOMP_TEST_LDFLAGS "${LIBOMP_TEST_LDFLAGS}") + endif() + + # Create the testing library from the same objects as libomp. + add_library(omp_testing SHARED $) + set_property(TARGET omp_testing PROPERTY FOLDER "OpenMP/Libraries") + target_link_libraries(omp_testing ${LIBOMP_CONFIGURED_LIBFLAGS} ${LIBOMP_DL_LIBS}) + set_target_properties(omp_testing PROPERTIES + PREFIX "" SUFFIX "" OUTPUT_NAME "libomp_testing${LIBOMP_LIBRARY_SUFFIX}" + LINK_FLAGS "${LIBOMP_TEST_LDFLAGS}" + LINKER_LANGUAGE ${LIBOMP_LINKER_LANGUAGE} + EXCLUDE_FROM_ALL TRUE # Don't build by default, only when tests need it + ) + add_dependencies(omp_testing libomp-needed-headers) +endif() + if(OPENMP_MSVC_NAME_SCHEME) if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG") set(LIBOMP_PDB_NAME ${LIBOMP_DEFAULT_LIB_NAME}${MSVC_TOOLS_VERSION}d.${LIBOMP_ARCH}) diff --git a/openmp/runtime/unittests/CMakeLists.txt b/openmp/runtime/unittests/CMakeLists.txt index 14ddbfc827cbb..e44fda78fb804 100644 --- a/openmp/runtime/unittests/CMakeLists.txt +++ b/openmp/runtime/unittests/CMakeLists.txt @@ -1,19 +1,22 @@ add_custom_target(OpenMPUnitTests) set_target_properties(OpenMPUnitTests PROPERTIES FOLDER "OpenMP/Tests") -if (NOT TARGET llvm_gtest) +if(NOT TARGET llvm_gtest) message(WARNING "OpenMP unittests disabled due to GTest being unavailable; " "Try LLVM_INSTALL_GTEST=ON for the LLVM build") - return () -endif () + return() +endif() +if(NOT TARGET omp_testing) + message(WARNING "OpenMP unittests disabled due to omp_testing library being unavailable") + return() +endif() function(add_openmp_unittest test_dirname) add_unittest(OpenMPUnitTests ${test_dirname} ${ARGN}) - # Link against the object library created in runtime/src - target_link_libraries(${test_dirname} PRIVATE - $ - ) + # Link against the testing library which exports all symbols. + target_link_libraries(${test_dirname} PRIVATE omp_testing) + add_dependencies(${test_dirname} omp_testing) target_include_directories(${test_dirname} PRIVATE ${LIBOMP_INCLUDE_DIR} diff --git a/openmp/runtime/unittests/README.md b/openmp/runtime/unittests/README.md index ad7dd9d716ceb..974f877654776 100644 --- a/openmp/runtime/unittests/README.md +++ b/openmp/runtime/unittests/README.md @@ -4,4 +4,6 @@ Usage: ``` cd /runtimes/runtimes-bins ninja check-libomp-unit -``` \ No newline at end of file +``` + +Note: unit tests are currently not supported on Windows From c63c254f2d65e7a9a7b2e5c09f40033d96a64b68 Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Tue, 18 Nov 2025 09:04:23 -0600 Subject: [PATCH 03/11] fix omp_objects dependency --- openmp/runtime/src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/openmp/runtime/src/CMakeLists.txt b/openmp/runtime/src/CMakeLists.txt index 7ee648f54de05..638f6c2ca61bd 100644 --- a/openmp/runtime/src/CMakeLists.txt +++ b/openmp/runtime/src/CMakeLists.txt @@ -332,6 +332,7 @@ set(LIBOMPTARGET_OPENMP_HOST_RTL_FOLDER "${LIBOMP_LIBRARY_DIR}" CACHE STRING # objects depend on : .inc files add_custom_target(libomp-needed-headers DEPENDS kmp_i18n_id.inc kmp_i18n_default.inc) set_target_properties(libomp-needed-headers PROPERTIES FOLDER "OpenMP/Sourcegenning") +add_dependencies(omp_objects libomp-needed-headers) add_dependencies(omp libomp-needed-headers) # Windows specific build rules From 4cd6cbe3d3bea05d7d0c50572188af6ce91e7fb0 Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Tue, 18 Nov 2025 14:09:49 -0600 Subject: [PATCH 04/11] rename add_openmp_unittest argument --- openmp/runtime/unittests/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openmp/runtime/unittests/CMakeLists.txt b/openmp/runtime/unittests/CMakeLists.txt index e44fda78fb804..b161846708d70 100644 --- a/openmp/runtime/unittests/CMakeLists.txt +++ b/openmp/runtime/unittests/CMakeLists.txt @@ -11,14 +11,14 @@ if(NOT TARGET omp_testing) return() endif() -function(add_openmp_unittest test_dirname) - add_unittest(OpenMPUnitTests ${test_dirname} ${ARGN}) +function(add_openmp_unittest test_filename) + add_unittest(OpenMPUnitTests ${test_filename} ${ARGN}) # Link against the testing library which exports all symbols. - target_link_libraries(${test_dirname} PRIVATE omp_testing) - add_dependencies(${test_dirname} omp_testing) + target_link_libraries(${test_filename} PRIVATE omp_testing) + add_dependencies(${test_filename} omp_testing) - target_include_directories(${test_dirname} PRIVATE + target_include_directories(${test_filename} PRIVATE ${LIBOMP_INCLUDE_DIR} ${LIBOMP_SRC_DIR} ) From 16ad02ee78df600de7841eadae56fa4ca185cb8f Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Wed, 3 Dec 2025 15:15:20 -0600 Subject: [PATCH 05/11] implement feedback --- openmp/runtime/src/CMakeLists.txt | 44 +++--------- .../{unittests => test/Unit}/lit.cfg.py | 2 +- openmp/runtime/test/Unit/lit.site.cfg.py.in | 8 +++ openmp/runtime/unittests/CMakeLists.txt | 70 ++++++++++++++----- .../runtime/unittests/String/CMakeLists.txt | 3 + .../unittests/{src => String}/TestKmpStr.cpp | 0 openmp/runtime/unittests/lit.site.cfg.py.in | 9 --- openmp/runtime/unittests/src/CMakeLists.txt | 3 - 8 files changed, 72 insertions(+), 67 deletions(-) rename openmp/runtime/{unittests => test/Unit}/lit.cfg.py (97%) create mode 100644 openmp/runtime/test/Unit/lit.site.cfg.py.in create mode 100644 openmp/runtime/unittests/String/CMakeLists.txt rename openmp/runtime/unittests/{src => String}/TestKmpStr.cpp (100%) delete mode 100644 openmp/runtime/unittests/lit.site.cfg.py.in delete mode 100644 openmp/runtime/unittests/src/CMakeLists.txt diff --git a/openmp/runtime/src/CMakeLists.txt b/openmp/runtime/src/CMakeLists.txt index 638f6c2ca61bd..10065f2f21fc5 100644 --- a/openmp/runtime/src/CMakeLists.txt +++ b/openmp/runtime/src/CMakeLists.txt @@ -176,13 +176,11 @@ endif() # Add the OpenMP library # First, create an OBJECT library with all the runtime sources. -# This allows both the main library and unit tests to link against the same -# compiled objects. -add_library(omp_objects OBJECT ${LIBOMP_SOURCE_FILES}) -set_property(TARGET omp_objects PROPERTY FOLDER "OpenMP/Libraries") -set_property(TARGET omp_objects PROPERTY POSITION_INDEPENDENT_CODE ON) -# Export the omp_objects target so unit tests can use it -set(LIBOMP_OBJECTS_TARGET omp_objects PARENT_SCOPE) +# This allows the unittests later to access internal symbols which don't export +# in libomp. +add_library(obj.omp OBJECT ${LIBOMP_SOURCE_FILES}) +set_property(TARGET obj.omp PROPERTY FOLDER "OpenMP/Libraries") +set_property(TARGET obj.omp PROPERTY POSITION_INDEPENDENT_CODE ON) libomp_get_ldflags(LIBOMP_CONFIGURED_LDFLAGS) libomp_get_libflags(LIBOMP_CONFIGURED_LIBFLAGS) @@ -190,12 +188,12 @@ libomp_get_libflags(LIBOMP_CONFIGURED_LIBFLAGS) # Build libomp library. Add LLVMSupport dependency if building in-tree with # libomptarget profiling enabled. if(OPENMP_STANDALONE_BUILD OR (NOT OPENMP_ENABLE_LIBOMP_PROFILING)) - add_library(omp ${LIBOMP_LIBRARY_KIND} $) + add_library(omp ${LIBOMP_LIBRARY_KIND} $) set_property(TARGET omp PROPERTY FOLDER "OpenMP/Libraries") # Linking command will include libraries in LIBOMP_CONFIGURED_LIBFLAGS target_link_libraries(omp ${LIBOMP_CONFIGURED_LIBFLAGS} ${LIBOMP_DL_LIBS}) else() - add_llvm_library(omp ${LIBOMP_LIBRARY_KIND} $ PARTIAL_SOURCES_INTENDED + add_llvm_library(omp ${LIBOMP_LIBRARY_KIND} $ PARTIAL_SOURCES_INTENDED LINK_LIBS ${LIBOMP_CONFIGURED_LIBFLAGS} ${LIBOMP_DL_LIBS} LINK_COMPONENTS Support BUILDTREE_ONLY @@ -211,31 +209,6 @@ if(${LIBOMP_USE_HWLOC}) ) endif() -# Build a testing version of libomp that exports all symbols for unit tests. -# This library uses the same compiled objects as libomp, but with all symbols -# exported to allow testing internal functions. -if(NOT WIN32 AND NOT STUBS_LIBRARY) - set(LIBOMP_TEST_LDFLAGS ${LIBOMP_CONFIGURED_LDFLAGS}) - # Replace the libomp exports with the test exports exporting all symbols. - if(LIBOMP_HAVE_VERSION_SCRIPT_FLAG) - string(REPLACE "${LIBOMP_SRC_DIR}/exports_so.txt" - "${LIBOMP_SRC_DIR}/exports_test_so.txt" - LIBOMP_TEST_LDFLAGS "${LIBOMP_TEST_LDFLAGS}") - endif() - - # Create the testing library from the same objects as libomp. - add_library(omp_testing SHARED $) - set_property(TARGET omp_testing PROPERTY FOLDER "OpenMP/Libraries") - target_link_libraries(omp_testing ${LIBOMP_CONFIGURED_LIBFLAGS} ${LIBOMP_DL_LIBS}) - set_target_properties(omp_testing PROPERTIES - PREFIX "" SUFFIX "" OUTPUT_NAME "libomp_testing${LIBOMP_LIBRARY_SUFFIX}" - LINK_FLAGS "${LIBOMP_TEST_LDFLAGS}" - LINKER_LANGUAGE ${LIBOMP_LINKER_LANGUAGE} - EXCLUDE_FROM_ALL TRUE # Don't build by default, only when tests need it - ) - add_dependencies(omp_testing libomp-needed-headers) -endif() - if(OPENMP_MSVC_NAME_SCHEME) if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG") set(LIBOMP_PDB_NAME ${LIBOMP_DEFAULT_LIB_NAME}${MSVC_TOOLS_VERSION}d.${LIBOMP_ARCH}) @@ -332,8 +305,7 @@ set(LIBOMPTARGET_OPENMP_HOST_RTL_FOLDER "${LIBOMP_LIBRARY_DIR}" CACHE STRING # objects depend on : .inc files add_custom_target(libomp-needed-headers DEPENDS kmp_i18n_id.inc kmp_i18n_default.inc) set_target_properties(libomp-needed-headers PROPERTIES FOLDER "OpenMP/Sourcegenning") -add_dependencies(omp_objects libomp-needed-headers) -add_dependencies(omp libomp-needed-headers) +add_dependencies(obj.omp libomp-needed-headers) # Windows specific build rules if(WIN32) diff --git a/openmp/runtime/unittests/lit.cfg.py b/openmp/runtime/test/Unit/lit.cfg.py similarity index 97% rename from openmp/runtime/unittests/lit.cfg.py rename to openmp/runtime/test/Unit/lit.cfg.py index 552ea8ef9854d..01bd3d961bf00 100644 --- a/openmp/runtime/unittests/lit.cfg.py +++ b/openmp/runtime/test/Unit/lit.cfg.py @@ -19,4 +19,4 @@ config.test_source_root = config.test_exec_root # testFormat: The test format to use to interpret tests. -config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, ".unittests") +config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, "Tests") diff --git a/openmp/runtime/test/Unit/lit.site.cfg.py.in b/openmp/runtime/test/Unit/lit.site.cfg.py.in new file mode 100644 index 0000000000000..dd5c075b5f112 --- /dev/null +++ b/openmp/runtime/test/Unit/lit.site.cfg.py.in @@ -0,0 +1,8 @@ +@AUTO_GEN_COMMENT@ + +config.openmp_unittests_dir = "@CMAKE_CURRENT_BINARY_DIR@/../unittests" +config.llvm_build_mode = lit_config.substitute("@LLVM_BUILD_MODE@") + +# Let the main config do the real work. +lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/../test/Unit/lit.cfg.py") + diff --git a/openmp/runtime/unittests/CMakeLists.txt b/openmp/runtime/unittests/CMakeLists.txt index b161846708d70..3c56512bcf120 100644 --- a/openmp/runtime/unittests/CMakeLists.txt +++ b/openmp/runtime/unittests/CMakeLists.txt @@ -1,34 +1,68 @@ add_custom_target(OpenMPUnitTests) set_target_properties(OpenMPUnitTests PROPERTIES FOLDER "OpenMP/Tests") -if(NOT TARGET llvm_gtest) - message(WARNING "OpenMP unittests disabled due to GTest being unavailable; " - "Try LLVM_INSTALL_GTEST=ON for the LLVM build") +if(WIN32 OR STUBS_LIBRARY) + message(WARNING "OpenMP unittests disabled due to stub library or Windows") return() endif() -if(NOT TARGET omp_testing) - message(WARNING "OpenMP unittests disabled due to omp_testing library being unavailable") - return() + +# Build a testing version of libomp that exports all symbols for unit tests. +# This library uses the same compiled objects as libomp, but with all symbols +# exported to allow testing internal functions. + +libomp_get_ldflags(LIBOMP_TEST_LDFLAGS) +libomp_get_libflags(LIBOMP_TEST_LIBFLAGS) +# Replace the libomp exports with the test exports exporting all symbols. +if(LIBOMP_HAVE_VERSION_SCRIPT_FLAG) + string(REPLACE "${LIBOMP_SRC_DIR}/exports_so.txt" + "${LIBOMP_SRC_DIR}/exports_test_so.txt" + LIBOMP_TEST_LDFLAGS "${LIBOMP_TEST_LDFLAGS}") +endif() +# Duplicate setting of LIBOMP_LINKER_LANGUAGE to match libomp. +if(NOT ${LIBOMP_USE_STDCPPLIB}) + set(LIBOMP_LINKER_LANGUAGE C) + set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES) +else() + set(LIBOMP_LINKER_LANGUAGE CXX) endif() -function(add_openmp_unittest test_filename) - add_unittest(OpenMPUnitTests ${test_filename} ${ARGN}) +# Create the testing library from the same objects as libomp. +add_library(omp_testing SHARED $) +set_property(TARGET omp_testing PROPERTY FOLDER "OpenMP/Libraries") +target_link_libraries(omp_testing PUBLIC default_gtest) +target_link_libraries(omp_testing PUBLIC ${LIBOMP_TEST_LIBFLAGS} ${LIBOMP_DL_LIBS}) +set_target_properties(omp_testing PROPERTIES + PREFIX "" SUFFIX "" OUTPUT_NAME "libomp_testing${LIBOMP_LIBRARY_SUFFIX}" + LINK_FLAGS "${LIBOMP_TEST_LDFLAGS}" + LINKER_LANGUAGE ${LIBOMP_LINKER_LANGUAGE} + EXCLUDE_FROM_ALL TRUE # Don't build by default, only when tests need it +) +target_include_directories(omp_testing PUBLIC + ${LIBOMP_INCLUDE_DIR} + ${LIBOMP_SRC_DIR} +) + +# Make the targets default_gtest and default_gtest_main available. +build_gtest() + +function(add_openmp_unittest test_name) + add_unittest(OpenMPUnitTests ${test_name} ${ARGN}) # Link against the testing library which exports all symbols. - target_link_libraries(${test_filename} PRIVATE omp_testing) - add_dependencies(${test_filename} omp_testing) + target_link_libraries(${test_name} PRIVATE omp_testing) - target_include_directories(${test_filename} PRIVATE - ${LIBOMP_INCLUDE_DIR} - ${LIBOMP_SRC_DIR} - ) + if(TARGET default_gtest) + target_link_libraries(${test_name} PRIVATE default_gtest_main default_gtest) + else () + target_link_libraries(${test_name} PRIVATE llvm_gtest_main llvm_gtest) + endif () endfunction() configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in + ${CMAKE_CURRENT_SOURCE_DIR}/../test/Unit/lit.site.cfg.py.in ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py MAIN_CONFIG - ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py + ${CMAKE_CURRENT_SOURCE_DIR}/../test/Unit/lit.cfg.py ) add_openmp_testsuite( @@ -36,7 +70,7 @@ add_openmp_testsuite( "Running libomp unit tests" ${CMAKE_CURRENT_BINARY_DIR} EXCLUDE_FROM_CHECK_ALL - DEPENDS OpenMPUnitTests omp + DEPENDS OpenMPUnitTests ) -add_subdirectory(src) +add_subdirectory(String) diff --git a/openmp/runtime/unittests/String/CMakeLists.txt b/openmp/runtime/unittests/String/CMakeLists.txt new file mode 100644 index 0000000000000..be072c76a10a6 --- /dev/null +++ b/openmp/runtime/unittests/String/CMakeLists.txt @@ -0,0 +1,3 @@ +add_openmp_unittest(StringTests + TestKmpStr.cpp +) diff --git a/openmp/runtime/unittests/src/TestKmpStr.cpp b/openmp/runtime/unittests/String/TestKmpStr.cpp similarity index 100% rename from openmp/runtime/unittests/src/TestKmpStr.cpp rename to openmp/runtime/unittests/String/TestKmpStr.cpp diff --git a/openmp/runtime/unittests/lit.site.cfg.py.in b/openmp/runtime/unittests/lit.site.cfg.py.in deleted file mode 100644 index 878c95f1d8e29..0000000000000 --- a/openmp/runtime/unittests/lit.site.cfg.py.in +++ /dev/null @@ -1,9 +0,0 @@ -@AUTO_GEN_COMMENT@ - -config.library_dir = "@LIBOMP_LIBRARY_DIR@" -config.openmp_unittests_dir = "@CMAKE_CURRENT_BINARY_DIR@" -config.llvm_build_mode = lit_config.substitute("@LLVM_BUILD_MODE@") - -# Let the main config do the real work. -lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg.py") - diff --git a/openmp/runtime/unittests/src/CMakeLists.txt b/openmp/runtime/unittests/src/CMakeLists.txt deleted file mode 100644 index 455fbf0b92fc5..0000000000000 --- a/openmp/runtime/unittests/src/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_openmp_unittest(libomp.unittests - TestKmpStr.cpp -) From b12ff59f5c8a9c432adce1aa13ff38b6ce60b44b Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Tue, 16 Dec 2025 09:17:09 -0600 Subject: [PATCH 06/11] implement feedback --- openmp/cmake/modules/LibompHandleFlags.cmake | 7 ++++++- openmp/runtime/CMakeLists.txt | 13 +++++++++++++ openmp/runtime/src/CMakeLists.txt | 13 ------------- openmp/runtime/test/lit.cfg | 3 +++ openmp/runtime/unittests/CMakeLists.txt | 15 +-------------- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/openmp/cmake/modules/LibompHandleFlags.cmake b/openmp/cmake/modules/LibompHandleFlags.cmake index c36a88fb862ae..77ccb3ecaff34 100644 --- a/openmp/cmake/modules/LibompHandleFlags.cmake +++ b/openmp/cmake/modules/LibompHandleFlags.cmake @@ -97,6 +97,7 @@ endfunction() # Linker flags function(libomp_get_ldflags ldflags) + cmake_parse_arguments(ARG "FOR_UNITTESTS" "" "" ${ARGN}) set(ldflags_local) libomp_append(ldflags_local "${CMAKE_LINK_DEF_FILE_FLAG}${CMAKE_CURRENT_BINARY_DIR}/${LIBOMP_LIB_NAME}.def" IF_DEFINED CMAKE_LINK_DEF_FILE_FLAG) @@ -105,7 +106,11 @@ function(libomp_get_ldflags ldflags) libomp_append(ldflags_local "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}${LIBOMP_VERSION_MAJOR}.${LIBOMP_VERSION_MINOR}" IF_DEFINED CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG) libomp_append(ldflags_local -Wl,--as-needed LIBOMP_HAVE_AS_NEEDED_FLAG) - libomp_append(ldflags_local "-Wl,--version-script=${LIBOMP_SRC_DIR}/exports_so.txt" LIBOMP_HAVE_VERSION_SCRIPT_FLAG) + if(ARG_FOR_UNITTESTS) + libomp_append(ldflags_local "-Wl,--version-script=${LIBOMP_SRC_DIR}/exports_test_so.txt" LIBOMP_HAVE_VERSION_SCRIPT_FLAG) + else() + libomp_append(ldflags_local "-Wl,--version-script=${LIBOMP_SRC_DIR}/exports_so.txt" LIBOMP_HAVE_VERSION_SCRIPT_FLAG) + endif() libomp_append(ldflags_local -static-libgcc LIBOMP_HAVE_STATIC_LIBGCC_FLAG) libomp_append(ldflags_local -Wl,-z,noexecstack LIBOMP_HAVE_Z_NOEXECSTACK_FLAG) libomp_append(ldflags_local -no-intel-extensions LIBOMP_HAVE_NO_INTEL_EXTENSIONS_FLAG) diff --git a/openmp/runtime/CMakeLists.txt b/openmp/runtime/CMakeLists.txt index 33276b7d97d3a..016f8ae10e648 100644 --- a/openmp/runtime/CMakeLists.txt +++ b/openmp/runtime/CMakeLists.txt @@ -118,6 +118,19 @@ if(NOT DEFINED CMAKE_MACOSX_RPATH) set(CMAKE_MACOSX_RPATH TRUE) endif() +# Remove any cmake-automatic linking of the standard C++ library. +# We neither need (nor want) the standard C++ library dependency even though we compile c++ files. +if(NOT ${LIBOMP_USE_STDCPPLIB}) + set(LIBOMP_LINKER_LANGUAGE C) + set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES) +else() + set(LIBOMP_LINKER_LANGUAGE CXX) +endif() + +if(UNIX) + set(LIBOMP_DL_LIBS ${CMAKE_DL_LIBS}) +endif() + # User specified flags. These are appended to the configured flags. set(LIBOMP_CXXFLAGS "" CACHE STRING "Appended user specified C++ compiler flags.") diff --git a/openmp/runtime/src/CMakeLists.txt b/openmp/runtime/src/CMakeLists.txt index 10065f2f21fc5..53f83c006b04f 100644 --- a/openmp/runtime/src/CMakeLists.txt +++ b/openmp/runtime/src/CMakeLists.txt @@ -153,19 +153,6 @@ libomp_get_asmflags(LIBOMP_CONFIGURED_ASMFLAGS) set_source_files_properties(${LIBOMP_CXXFILES} PROPERTIES COMPILE_FLAGS "${LIBOMP_CONFIGURED_CXXFLAGS}") set_source_files_properties(${LIBOMP_ASMFILES} ${LIBOMP_GNUASMFILES} PROPERTIES COMPILE_FLAGS "${LIBOMP_CONFIGURED_ASMFLAGS}") -# Remove any cmake-automatic linking of the standard C++ library. -# We neither need (nor want) the standard C++ library dependency even though we compile c++ files. -if(NOT ${LIBOMP_USE_STDCPPLIB}) - set(LIBOMP_LINKER_LANGUAGE C) - set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES) -else() - set(LIBOMP_LINKER_LANGUAGE CXX) -endif() - -if(UNIX) - set(LIBOMP_DL_LIBS ${CMAKE_DL_LIBS}) -endif() - # Disable libstdc++ assertions, even in an LLVM_ENABLE_ASSERTIONS build, to # avoid an unwanted dependency on libstdc++.so. add_compile_definitions(_GLIBCXX_NO_ASSERTIONS) diff --git a/openmp/runtime/test/lit.cfg b/openmp/runtime/test/lit.cfg index 72da1ba1411f8..f35794f09f641 100644 --- a/openmp/runtime/test/lit.cfg +++ b/openmp/runtime/test/lit.cfg @@ -41,6 +41,9 @@ config.name = 'libomp' # suffixes: A list of file extensions to treat as test files. config.suffixes = ['.c', '.cpp'] +# Exclude Unit tests - they are run separately via check-libomp-unit +config.excludes = ['Unit'] + if config.test_fortran_compiler: lit_config.note("OpenMP Fortran tests enabled") config.suffixes += ['.f90', '.F90'] diff --git a/openmp/runtime/unittests/CMakeLists.txt b/openmp/runtime/unittests/CMakeLists.txt index 3c56512bcf120..10ffef9e566c8 100644 --- a/openmp/runtime/unittests/CMakeLists.txt +++ b/openmp/runtime/unittests/CMakeLists.txt @@ -10,21 +10,8 @@ endif() # This library uses the same compiled objects as libomp, but with all symbols # exported to allow testing internal functions. -libomp_get_ldflags(LIBOMP_TEST_LDFLAGS) +libomp_get_ldflags(LIBOMP_TEST_LDFLAGS FOR_UNITTESTS) libomp_get_libflags(LIBOMP_TEST_LIBFLAGS) -# Replace the libomp exports with the test exports exporting all symbols. -if(LIBOMP_HAVE_VERSION_SCRIPT_FLAG) - string(REPLACE "${LIBOMP_SRC_DIR}/exports_so.txt" - "${LIBOMP_SRC_DIR}/exports_test_so.txt" - LIBOMP_TEST_LDFLAGS "${LIBOMP_TEST_LDFLAGS}") -endif() -# Duplicate setting of LIBOMP_LINKER_LANGUAGE to match libomp. -if(NOT ${LIBOMP_USE_STDCPPLIB}) - set(LIBOMP_LINKER_LANGUAGE C) - set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES) -else() - set(LIBOMP_LINKER_LANGUAGE CXX) -endif() # Create the testing library from the same objects as libomp. add_library(omp_testing SHARED $) From 197b195b30fc90a7dcd783e67023815680eb330b Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Wed, 17 Dec 2025 08:53:27 +0100 Subject: [PATCH 07/11] Update openmp/runtime/CMakeLists.txt Co-authored-by: Shilei Tian --- openmp/runtime/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmp/runtime/CMakeLists.txt b/openmp/runtime/CMakeLists.txt index 016f8ae10e648..b12d1ea0ee90d 100644 --- a/openmp/runtime/CMakeLists.txt +++ b/openmp/runtime/CMakeLists.txt @@ -119,7 +119,7 @@ if(NOT DEFINED CMAKE_MACOSX_RPATH) endif() # Remove any cmake-automatic linking of the standard C++ library. -# We neither need (nor want) the standard C++ library dependency even though we compile c++ files. +# We neither need (nor want) the standard C++ library dependency even though we compile C++ files. if(NOT ${LIBOMP_USE_STDCPPLIB}) set(LIBOMP_LINKER_LANGUAGE C) set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES) From 5eb66f4961dbba68a24bb9326eb1605e6e3531c1 Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Wed, 17 Dec 2025 07:30:22 -0600 Subject: [PATCH 08/11] enhance TestKmpStr.cpp --- .../runtime/unittests/String/TestKmpStr.cpp | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/openmp/runtime/unittests/String/TestKmpStr.cpp b/openmp/runtime/unittests/String/TestKmpStr.cpp index a22a729da9272..87497b93c7538 100644 --- a/openmp/runtime/unittests/String/TestKmpStr.cpp +++ b/openmp/runtime/unittests/String/TestKmpStr.cpp @@ -86,6 +86,31 @@ TEST(KmpStrTest, BasicStrToInt) { EXPECT_EQ(__kmp_basic_str_to_int("123"), 123); } +// Test basic string to int conversion with invalid inputs +TEST(KmpStrTest, BasicStrToIntInvalid) { + // Empty string returns 0 + EXPECT_EQ(__kmp_basic_str_to_int(""), 0); + + // Strings starting with non-digits return 0 + EXPECT_EQ(__kmp_basic_str_to_int("abc"), 0); + EXPECT_EQ(__kmp_basic_str_to_int("hello"), 0); + EXPECT_EQ(__kmp_basic_str_to_int("xyz123"), 0); + + // Special characters return 0 + EXPECT_EQ(__kmp_basic_str_to_int("!@#"), 0); + EXPECT_EQ(__kmp_basic_str_to_int("+42"), 0); + EXPECT_EQ(__kmp_basic_str_to_int("-42"), 0); + + // Leading whitespace causes early stop (returns 0) + EXPECT_EQ(__kmp_basic_str_to_int(" 42"), 0); + EXPECT_EQ(__kmp_basic_str_to_int("\t42"), 0); + + // Mixed content: parses digits until first non-digit + EXPECT_EQ(__kmp_basic_str_to_int("123abc"), 123); + EXPECT_EQ(__kmp_basic_str_to_int("42 "), 42); + EXPECT_EQ(__kmp_basic_str_to_int("7.5"), 7); +} + // Test string match TEST(KmpStrTest, StrMatch) { const char *data = "Hello World"; @@ -134,6 +159,73 @@ TEST(KmpStrTest, MatchBool) { EXPECT_TRUE(__kmp_str_match_false("0")); EXPECT_TRUE(__kmp_str_match_false("no")); EXPECT_TRUE(__kmp_str_match_false("NO")); + + // Note: Trailing characters after a valid prefix still match due to + // minimum-length prefix matching (e.g., "true" uses len=1, "yes" uses len=1) + EXPECT_TRUE(__kmp_str_match_true("true ")); + EXPECT_TRUE(__kmp_str_match_false("false ")); + EXPECT_TRUE(__kmp_str_match_true("truex")); + EXPECT_TRUE(__kmp_str_match_false("falsex")); + + // Partial prefixes also match due to minimum-length matching + EXPECT_TRUE(__kmp_str_match_true("t")); + EXPECT_TRUE(__kmp_str_match_true("tru")); + EXPECT_TRUE(__kmp_str_match_false("f")); + EXPECT_TRUE(__kmp_str_match_false("fals")); + EXPECT_TRUE(__kmp_str_match_true("y")); + EXPECT_TRUE(__kmp_str_match_true("yess")); + EXPECT_TRUE(__kmp_str_match_false("n")); + EXPECT_TRUE(__kmp_str_match_false("noo")); + + // "on" and "off" require at least 2 characters + EXPECT_TRUE(__kmp_str_match_true("on")); + EXPECT_TRUE(__kmp_str_match_false("of")); + EXPECT_TRUE(__kmp_str_match_false("off")); + + // "enabled" and "disabled" require exact match (len=0) + EXPECT_TRUE(__kmp_str_match_true("enabled")); + EXPECT_TRUE(__kmp_str_match_false("disabled")); +} + +// Test string match for invalid bool values +TEST(KmpStrTest, MatchBoolInvalid) { + // Empty string is neither true nor false + EXPECT_FALSE(__kmp_str_match_true("")); + EXPECT_FALSE(__kmp_str_match_false("")); + + // Random strings are neither true nor false + EXPECT_FALSE(__kmp_str_match_true("hello")); + EXPECT_FALSE(__kmp_str_match_false("hello")); + EXPECT_FALSE(__kmp_str_match_true("abc")); + EXPECT_FALSE(__kmp_str_match_false("abc")); + + // Numbers other than 0/1 are neither true nor false + EXPECT_FALSE(__kmp_str_match_true("2")); + EXPECT_FALSE(__kmp_str_match_false("2")); + EXPECT_FALSE(__kmp_str_match_true("42")); + EXPECT_FALSE(__kmp_str_match_false("42")); + EXPECT_FALSE(__kmp_str_match_true("-1")); + EXPECT_FALSE(__kmp_str_match_false("-1")); + + // Leading whitespace prevents matching + EXPECT_FALSE(__kmp_str_match_true(" true")); + EXPECT_FALSE(__kmp_str_match_false(" false")); + + // "on" and "off" require at least 2 characters + EXPECT_FALSE(__kmp_str_match_true("o")); + EXPECT_FALSE(__kmp_str_match_false("o")); + + // "enabled" and "disabled" require exact match (len=0) + EXPECT_FALSE(__kmp_str_match_true("enable")); + EXPECT_FALSE(__kmp_str_match_false("disable")); + + // True values don't match as false and vice versa + EXPECT_FALSE(__kmp_str_match_false("true")); + EXPECT_FALSE(__kmp_str_match_false("1")); + EXPECT_FALSE(__kmp_str_match_false("yes")); + EXPECT_FALSE(__kmp_str_match_true("false")); + EXPECT_FALSE(__kmp_str_match_true("0")); + EXPECT_FALSE(__kmp_str_match_true("no")); } // Test string replace From 03ddc0ce946e17efa9a3be124beba8226838d37f Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Wed, 17 Dec 2025 10:25:33 -0600 Subject: [PATCH 09/11] implement feedback --- openmp/runtime/CMakeLists.txt | 2 +- openmp/runtime/unittests/CMakeLists.txt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/openmp/runtime/CMakeLists.txt b/openmp/runtime/CMakeLists.txt index b12d1ea0ee90d..9332ca30128d8 100644 --- a/openmp/runtime/CMakeLists.txt +++ b/openmp/runtime/CMakeLists.txt @@ -120,7 +120,7 @@ endif() # Remove any cmake-automatic linking of the standard C++ library. # We neither need (nor want) the standard C++ library dependency even though we compile C++ files. -if(NOT ${LIBOMP_USE_STDCPPLIB}) +if(NOT LIBOMP_USE_STDCPPLIB) set(LIBOMP_LINKER_LANGUAGE C) set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES) else() diff --git a/openmp/runtime/unittests/CMakeLists.txt b/openmp/runtime/unittests/CMakeLists.txt index 10ffef9e566c8..400f411551e7b 100644 --- a/openmp/runtime/unittests/CMakeLists.txt +++ b/openmp/runtime/unittests/CMakeLists.txt @@ -19,7 +19,9 @@ set_property(TARGET omp_testing PROPERTY FOLDER "OpenMP/Libraries") target_link_libraries(omp_testing PUBLIC default_gtest) target_link_libraries(omp_testing PUBLIC ${LIBOMP_TEST_LIBFLAGS} ${LIBOMP_DL_LIBS}) set_target_properties(omp_testing PROPERTIES - PREFIX "" SUFFIX "" OUTPUT_NAME "libomp_testing${LIBOMP_LIBRARY_SUFFIX}" + PREFIX "" + SUFFIX "" + OUTPUT_NAME "libomp_testing${LIBOMP_LIBRARY_SUFFIX}" LINK_FLAGS "${LIBOMP_TEST_LDFLAGS}" LINKER_LANGUAGE ${LIBOMP_LINKER_LANGUAGE} EXCLUDE_FROM_ALL TRUE # Don't build by default, only when tests need it From 62b7be579d957c86eaf4ad412077fbf7179e67bf Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Fri, 19 Dec 2025 03:03:55 -0600 Subject: [PATCH 10/11] fix standalone build --- openmp/runtime/unittests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmp/runtime/unittests/CMakeLists.txt b/openmp/runtime/unittests/CMakeLists.txt index 400f411551e7b..f8ef61e2254f1 100644 --- a/openmp/runtime/unittests/CMakeLists.txt +++ b/openmp/runtime/unittests/CMakeLists.txt @@ -32,7 +32,7 @@ target_include_directories(omp_testing PUBLIC ) # Make the targets default_gtest and default_gtest_main available. -build_gtest() +add_subdirectory("${LLVM_THIRD_PARTY_DIR}/unittest" "${CMAKE_BINARY_DIR}/third-party/runtimes_gtest") function(add_openmp_unittest test_name) add_unittest(OpenMPUnitTests ${test_name} ${ARGN}) From c08593a2c5a06785306989f01239844619f86280 Mon Sep 17 00:00:00 2001 From: Robert Imschweiler Date: Wed, 7 Jan 2026 08:42:35 -0600 Subject: [PATCH 11/11] improve gtest dependency handling --- openmp/runtime/unittests/CMakeLists.txt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/openmp/runtime/unittests/CMakeLists.txt b/openmp/runtime/unittests/CMakeLists.txt index f8ef61e2254f1..e1f0840933483 100644 --- a/openmp/runtime/unittests/CMakeLists.txt +++ b/openmp/runtime/unittests/CMakeLists.txt @@ -6,6 +6,22 @@ if(WIN32 OR STUBS_LIBRARY) return() endif() +# Make the targets default_gtest and default_gtest_main available. +if (OPENMP_STANDALONE_BUILD) + set(LLVM_RUNTIMES_BUILD 1) + if (EXISTS "${LLVM_THIRD_PARTY_DIR}/unittest/googletest/include/gtest/gtest.h") + add_subdirectory("${LLVM_THIRD_PARTY_DIR}/unittest" "${CMAKE_BINARY_DIR}/third-party/runtimes_gtest") + else() + message(WARNING "OpenMP unit tests will be skipped as LLVM third-party unittest directory is not available at: ${LLVM_THIRD_PARTY_DIR}/unittest") + return() + endif() +elseif ("openmp" IN_LIST LLVM_ENABLE_PROJECTS) + # llvm_gtest should already exist +else () + # LLVM_ENABLE_RUNTIMES build + build_gtest() +endif () + # Build a testing version of libomp that exports all symbols for unit tests. # This library uses the same compiled objects as libomp, but with all symbols # exported to allow testing internal functions. @@ -31,9 +47,6 @@ target_include_directories(omp_testing PUBLIC ${LIBOMP_SRC_DIR} ) -# Make the targets default_gtest and default_gtest_main available. -add_subdirectory("${LLVM_THIRD_PARTY_DIR}/unittest" "${CMAKE_BINARY_DIR}/third-party/runtimes_gtest") - function(add_openmp_unittest test_name) add_unittest(OpenMPUnitTests ${test_name} ${ARGN})