Skip to content

Commit c801cb4

Browse files
committed
[OpenMP] Add libomp unit test infrastructure
1 parent b9301c2 commit c801cb4

File tree

8 files changed

+331
-2
lines changed

8 files changed

+331
-2
lines changed

openmp/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ endif()
469469

470470
add_subdirectory(src)
471471
add_subdirectory(test)
472+
add_subdirectory(unittests)
472473

473474
# make these variables available for tools:
474475
set(LIBOMP_LIBRARY_DIR ${LIBOMP_LIBRARY_DIR} PARENT_SCOPE)

openmp/runtime/src/CMakeLists.txt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,26 @@ if(NOT WIN32)
174174
endif()
175175

176176
# Add the OpenMP library
177+
178+
# First, create an OBJECT library with all the runtime sources.
179+
# This allows both the main library and unit tests to link against the same compiled objects.
180+
add_library(omp_objects OBJECT ${LIBOMP_SOURCE_FILES})
181+
set_property(TARGET omp_objects PROPERTY FOLDER "OpenMP/Libraries")
182+
set_property(TARGET omp_objects PROPERTY POSITION_INDEPENDENT_CODE ON)
183+
# Export the omp_objects target so unittests can use it
184+
set(LIBOMP_OBJECTS_TARGET omp_objects PARENT_SCOPE)
185+
177186
libomp_get_ldflags(LIBOMP_CONFIGURED_LDFLAGS)
178187

179188
libomp_get_libflags(LIBOMP_CONFIGURED_LIBFLAGS)
180189
# Build libomp library. Add LLVMSupport dependency if building in-tree with libomptarget profiling enabled.
181190
if(OPENMP_STANDALONE_BUILD OR (NOT OPENMP_ENABLE_LIBOMP_PROFILING))
182-
add_library(omp ${LIBOMP_LIBRARY_KIND} ${LIBOMP_SOURCE_FILES})
191+
add_library(omp ${LIBOMP_LIBRARY_KIND} $<TARGET_OBJECTS:omp_objects>)
183192
set_property(TARGET omp PROPERTY FOLDER "OpenMP/Libraries")
184193
# Linking command will include libraries in LIBOMP_CONFIGURED_LIBFLAGS
185194
target_link_libraries(omp ${LIBOMP_CONFIGURED_LIBFLAGS} ${LIBOMP_DL_LIBS})
186195
else()
187-
add_llvm_library(omp ${LIBOMP_LIBRARY_KIND} ${LIBOMP_SOURCE_FILES} PARTIAL_SOURCES_INTENDED
196+
add_llvm_library(omp ${LIBOMP_LIBRARY_KIND} $<TARGET_OBJECTS:omp_objects> PARTIAL_SOURCES_INTENDED
188197
LINK_LIBS ${LIBOMP_CONFIGURED_LIBFLAGS} ${LIBOMP_DL_LIBS}
189198
LINK_COMPONENTS Support
190199
BUILDTREE_ONLY
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
add_custom_target(OpenMPUnitTests)
2+
set_target_properties(OpenMPUnitTests PROPERTIES FOLDER "OpenMP/Tests")
3+
4+
if (NOT TARGET llvm_gtest)
5+
message(WARNING "OpenMP unittests disabled due to GTest being unavailable; "
6+
"Try LLVM_INSTALL_GTEST=ON for the LLVM build")
7+
return ()
8+
endif ()
9+
10+
function(add_openmp_unittest test_dirname)
11+
add_unittest(OpenMPUnitTests ${test_dirname} ${ARGN})
12+
13+
# Link against the object library created in runtime/src
14+
target_link_libraries(${test_dirname} PRIVATE
15+
$<TARGET_OBJECTS:omp_objects>
16+
)
17+
18+
target_include_directories(${test_dirname} PRIVATE
19+
${LIBOMP_INCLUDE_DIR}
20+
${LIBOMP_SRC_DIR}
21+
)
22+
endfunction()
23+
24+
configure_lit_site_cfg(
25+
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
26+
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py
27+
MAIN_CONFIG
28+
${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py
29+
)
30+
31+
add_openmp_testsuite(
32+
check-libomp-unit
33+
"Running libomp unit tests"
34+
${CMAKE_CURRENT_BINARY_DIR}
35+
EXCLUDE_FROM_CHECK_ALL
36+
DEPENDS OpenMPUnitTests omp
37+
)
38+
39+
add_subdirectory(src)

openmp/runtime/unittests/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# libomp Unit Tests
2+
3+
Usage:
4+
```
5+
cd <your-llvm-build-directory>/runtimes/runtimes-bins
6+
ninja check-libomp-unit
7+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# -*- Python -*-
2+
3+
# Configuration file for the 'lit' test runner.
4+
5+
import os
6+
import subprocess
7+
8+
import lit.formats
9+
10+
# name: The name of this test suite.
11+
config.name = "OpenMP-Unit"
12+
13+
# suffixes: A list of file extensions to treat as test files.
14+
config.suffixes = []
15+
16+
# test_source_root: The root path where tests are located.
17+
# test_exec_root: The root path where tests should be run.
18+
config.test_exec_root = config.openmp_unittests_dir
19+
config.test_source_root = config.test_exec_root
20+
21+
# testFormat: The test format to use to interpret tests.
22+
config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, ".unittests")
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@AUTO_GEN_COMMENT@
2+
3+
config.library_dir = "@LIBOMP_LIBRARY_DIR@"
4+
config.openmp_unittests_dir = "@CMAKE_CURRENT_BINARY_DIR@"
5+
config.llvm_build_mode = lit_config.substitute("@LLVM_BUILD_MODE@")
6+
7+
# Let the main config do the real work.
8+
lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg.py")
9+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
add_openmp_unittest(libomp.unittests
2+
TestKmpStr.cpp
3+
)
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
//===- TestKmpStr.cpp - Tests for kmp_str utilities ----------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "kmp_str.h"
10+
#include "gtest/gtest.h"
11+
#include <cstring>
12+
13+
namespace {
14+
15+
// Test basic string buffer initialization
16+
TEST(KmpStrTest, BufferInit) {
17+
kmp_str_buf_t buffer;
18+
__kmp_str_buf_init(&buffer);
19+
20+
EXPECT_NE(buffer.str, nullptr);
21+
EXPECT_GT(buffer.size, 0u);
22+
EXPECT_EQ(buffer.used, 0);
23+
EXPECT_EQ(buffer.str[0], '\0');
24+
}
25+
26+
// Test string buffer clear
27+
TEST(KmpStrTest, BufferClear) {
28+
kmp_str_buf_t buffer;
29+
__kmp_str_buf_init(&buffer);
30+
__kmp_str_buf_print(&buffer, "test string");
31+
32+
EXPECT_GT(buffer.used, 0);
33+
34+
__kmp_str_buf_clear(&buffer);
35+
EXPECT_EQ(buffer.used, 0);
36+
EXPECT_EQ(buffer.str[0], '\0');
37+
38+
__kmp_str_buf_free(&buffer);
39+
}
40+
41+
// Test string buffer print
42+
TEST(KmpStrTest, BufferPrint) {
43+
kmp_str_buf_t buffer;
44+
__kmp_str_buf_init(&buffer);
45+
46+
__kmp_str_buf_print(&buffer, "Hello, %s!", "World");
47+
48+
EXPECT_STREQ(buffer.str, "Hello, World!");
49+
EXPECT_EQ(buffer.used, 13);
50+
51+
__kmp_str_buf_free(&buffer);
52+
}
53+
54+
// Test string buffer concatenation
55+
TEST(KmpStrTest, BufferCat) {
56+
kmp_str_buf_t buffer;
57+
__kmp_str_buf_init(&buffer);
58+
59+
__kmp_str_buf_cat(&buffer, "Hello", 5);
60+
__kmp_str_buf_cat(&buffer, " ", 1);
61+
__kmp_str_buf_cat(&buffer, "World", 5);
62+
63+
EXPECT_STREQ(buffer.str, "Hello World");
64+
65+
__kmp_str_buf_free(&buffer);
66+
}
67+
68+
// Test string buffer reservation
69+
TEST(KmpStrTest, BufferReserve) {
70+
kmp_str_buf_t buffer;
71+
__kmp_str_buf_init(&buffer);
72+
73+
size_t large_size = 2048;
74+
__kmp_str_buf_reserve(&buffer, large_size);
75+
76+
EXPECT_GE(buffer.size, large_size);
77+
78+
__kmp_str_buf_free(&buffer);
79+
}
80+
81+
// Test basic string to int conversion
82+
TEST(KmpStrTest, BasicStrToInt) {
83+
EXPECT_EQ(__kmp_basic_str_to_int("0"), 0);
84+
EXPECT_EQ(__kmp_basic_str_to_int("1"), 1);
85+
EXPECT_EQ(__kmp_basic_str_to_int("42"), 42);
86+
EXPECT_EQ(__kmp_basic_str_to_int("123"), 123);
87+
}
88+
89+
// Test string match
90+
TEST(KmpStrTest, StrMatch) {
91+
const char *data = "Hello World";
92+
93+
// Test exact match (len == 0)
94+
EXPECT_TRUE(__kmp_str_match("Hello World", 0, data));
95+
EXPECT_FALSE(__kmp_str_match("Hello", 0, data)); // Not exact (data is longer)
96+
97+
// Test prefix match (len < 0)
98+
EXPECT_TRUE(
99+
__kmp_str_match("Hello", -1, data)); // "Hello" is prefix of "Hello World"
100+
EXPECT_FALSE(__kmp_str_match("World", -1, data)); // "World" is not a prefix
101+
102+
// Test minimum length match (len > 0)
103+
EXPECT_TRUE(__kmp_str_match("Hello", 5, data)); // At least 5 chars match
104+
EXPECT_TRUE(__kmp_str_match("Hello", 3, data)); // At least 3 chars match
105+
EXPECT_FALSE(__kmp_str_match("World", 5, data)); // First chars don't match
106+
}
107+
108+
// Test string contains
109+
TEST(KmpStrTest, StrContains) {
110+
const char *data = "Hello World";
111+
112+
EXPECT_TRUE(__kmp_str_contains("Hello", 5, data));
113+
EXPECT_TRUE(__kmp_str_contains("World", 5, data));
114+
EXPECT_TRUE(__kmp_str_contains("lo Wo", 5, data));
115+
EXPECT_FALSE(__kmp_str_contains("Goodbye", 7, data));
116+
}
117+
118+
// Test string match for true/false values
119+
TEST(KmpStrTest, MatchBool) {
120+
// Test true values
121+
EXPECT_TRUE(__kmp_str_match_true("true"));
122+
EXPECT_TRUE(__kmp_str_match_true("TRUE"));
123+
EXPECT_TRUE(__kmp_str_match_true("on"));
124+
EXPECT_TRUE(__kmp_str_match_true("ON"));
125+
EXPECT_TRUE(__kmp_str_match_true("1"));
126+
EXPECT_TRUE(__kmp_str_match_true("yes"));
127+
EXPECT_TRUE(__kmp_str_match_true("YES"));
128+
129+
// Test false values
130+
EXPECT_TRUE(__kmp_str_match_false("false"));
131+
EXPECT_TRUE(__kmp_str_match_false("FALSE"));
132+
EXPECT_TRUE(__kmp_str_match_false("off"));
133+
EXPECT_TRUE(__kmp_str_match_false("OFF"));
134+
EXPECT_TRUE(__kmp_str_match_false("0"));
135+
EXPECT_TRUE(__kmp_str_match_false("no"));
136+
EXPECT_TRUE(__kmp_str_match_false("NO"));
137+
}
138+
139+
// Test string replace
140+
TEST(KmpStrTest, StrReplace) {
141+
char str[] = "Hello World";
142+
__kmp_str_replace(str, ' ', '_');
143+
EXPECT_STREQ(str, "Hello_World");
144+
145+
__kmp_str_replace(str, 'o', '0');
146+
EXPECT_STREQ(str, "Hell0_W0rld");
147+
}
148+
149+
// Test string split
150+
TEST(KmpStrTest, StrSplit) {
151+
char str[] = "key=value";
152+
char *head = nullptr;
153+
char *tail = nullptr;
154+
155+
__kmp_str_split(str, '=', &head, &tail);
156+
157+
EXPECT_STREQ(head, "key");
158+
EXPECT_STREQ(tail, "value");
159+
}
160+
161+
// Test file name parsing
162+
TEST(KmpStrTest, FileNameInit) {
163+
const char *path = "/path/to/file.txt";
164+
kmp_str_fname_t fname;
165+
__kmp_str_fname_init(&fname, path);
166+
167+
EXPECT_NE(fname.path, nullptr);
168+
EXPECT_STREQ(fname.path, path);
169+
EXPECT_NE(fname.base, nullptr);
170+
EXPECT_STREQ(fname.base, "file.txt");
171+
172+
__kmp_str_fname_free(&fname);
173+
}
174+
175+
// Test string format
176+
TEST(KmpStrTest, StrFormat) {
177+
char *result = __kmp_str_format("Number: %d, String: %s", 42, "test");
178+
179+
EXPECT_NE(result, nullptr);
180+
EXPECT_STREQ(result, "Number: 42, String: test");
181+
182+
__kmp_str_free(&result);
183+
EXPECT_EQ(result, nullptr);
184+
}
185+
186+
// Test string buffer concatenate buffers
187+
TEST(KmpStrTest, BufferCatBuf) {
188+
kmp_str_buf_t buf1, buf2;
189+
__kmp_str_buf_init(&buf1);
190+
__kmp_str_buf_init(&buf2);
191+
192+
__kmp_str_buf_print(&buf1, "Hello");
193+
__kmp_str_buf_print(&buf2, " World");
194+
195+
__kmp_str_buf_catbuf(&buf1, &buf2);
196+
197+
EXPECT_STREQ(buf1.str, "Hello World");
198+
199+
__kmp_str_buf_free(&buf1);
200+
__kmp_str_buf_free(&buf2);
201+
}
202+
203+
// Test size string parsing
204+
TEST(KmpStrTest, StrToSize) {
205+
size_t result;
206+
const char *error = nullptr;
207+
208+
__kmp_str_to_size("100", &result, 1, &error);
209+
EXPECT_EQ(error, nullptr);
210+
EXPECT_EQ(result, 100u);
211+
212+
__kmp_str_to_size("1K", &result, 1024, &error);
213+
EXPECT_EQ(error, nullptr);
214+
EXPECT_EQ(result, 1024u);
215+
216+
__kmp_str_to_size("2M", &result, 1024, &error);
217+
EXPECT_EQ(error, nullptr);
218+
EXPECT_EQ(result, 2u * 1024u * 1024u);
219+
}
220+
221+
// Test uint string parsing
222+
TEST(KmpStrTest, StrToUint) {
223+
kmp_uint64 result;
224+
const char *error = nullptr;
225+
226+
__kmp_str_to_uint("0", &result, &error);
227+
EXPECT_EQ(error, nullptr);
228+
EXPECT_EQ(result, 0u);
229+
230+
__kmp_str_to_uint("42", &result, &error);
231+
EXPECT_EQ(error, nullptr);
232+
EXPECT_EQ(result, 42u);
233+
234+
__kmp_str_to_uint("1234567890", &result, &error);
235+
EXPECT_EQ(error, nullptr);
236+
EXPECT_EQ(result, 1234567890u);
237+
}
238+
239+
} // namespace

0 commit comments

Comments
 (0)