Skip to content

Commit 0f5fb12

Browse files
committed
Add unit tests for bit manipulation instructions
1 parent c208114 commit 0f5fb12

File tree

7 files changed

+349
-8
lines changed

7 files changed

+349
-8
lines changed

src/westmere/bits.h

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <stdbool.h>
1313
#include <stdint.h>
14+
#include <immintrin.h>
1415

1516
static inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
1617
#if has_builtin(__builtin_uaddll_overflow)

tests/CMakeLists.txt

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
find_package(cmocka REQUIRED)
2-
cmocka_add_tests(zone-tests types.c include.c ip4.c time.c base32.c svcb.c syntax.c eui.c)
2+
if(HAVE_WESTMERE)
3+
set(sources ${sources} westmere/bits.c)
4+
set_source_files_properties(westmere/bits.c PROPERTIES COMPILE_FLAGS "-march=westmere")
5+
endif()
6+
if(HAVE_HASWELL)
7+
set(sources ${sources} haswell/bits.c)
8+
set_source_files_properties(haswell/bits.c PROPERTIES COMPILE_FLAGS "-march=haswell")
9+
endif()
10+
11+
cmocka_add_tests(zone-tests types.c include.c ip4.c time.c base32.c svcb.c syntax.c eui.c bits.c)
312

413
target_link_libraries(zone-tests PRIVATE zone)
5-
target_sources(zone-tests PRIVATE tools.c)
14+
target_sources(zone-tests PRIVATE tools.c fallback/bits.c ${sources})
615
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
716
target_compile_options(zone-tests PRIVATE -Wno-missing-prototypes -Wno-deprecated-declarations)
817
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU")

tests/bits.c

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* bits.c -- test bit manipulation instructions
3+
*
4+
* Copyright (c) 2024, NLnet Labs. All rights reserved.
5+
*
6+
* SPDX-License-Identifier: BSD-3-Clause
7+
*
8+
*/
9+
#include <assert.h>
10+
#include <stdarg.h>
11+
#include <setjmp.h>
12+
#include <stdint.h>
13+
#include <stddef.h>
14+
#include <string.h>
15+
#include <cmocka.h>
16+
17+
#include "config.h"
18+
#include "attributes.h"
19+
#include "isadetection.h"
20+
21+
#if _MSC_VER
22+
# define strcasecmp(s1, s2) _stricmp(s1, s2)
23+
# define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
24+
#else
25+
#include <strings.h>
26+
#endif
27+
28+
struct kernel {
29+
const char *name;
30+
uint32_t instruction_set;
31+
void (*test_trailing_zeroes)(void **state);
32+
void (*test_leading_zeroes)(void **state);
33+
void (*test_prefix_xor)(void **state);
34+
void (*test_add_overflow)(void **state);
35+
};
36+
37+
#if HAVE_HASWELL
38+
extern void test_haswell_trailing_zeroes(void **);
39+
extern void test_haswell_leading_zeroes(void **);
40+
extern void test_haswell_prefix_xor(void **);
41+
extern void test_haswell_add_overflow(void **);
42+
#endif
43+
44+
#if HAVE_WESTMERE
45+
extern void test_westmere_trailing_zeroes(void **);
46+
extern void test_westmere_leading_zeroes(void **);
47+
extern void test_westmere_prefix_xor(void **);
48+
extern void test_westmere_add_overflow(void **);
49+
#endif
50+
51+
extern void test_fallback_trailing_zeroes(void **);
52+
extern void test_fallback_leading_zeroes(void **);
53+
54+
static const struct kernel kernels[] = {
55+
#if HAVE_HASWELL
56+
{ "haswell", AVX2, &test_haswell_trailing_zeroes,
57+
&test_haswell_leading_zeroes,
58+
&test_haswell_prefix_xor,
59+
&test_haswell_add_overflow },
60+
#endif
61+
#if HAVE_WESTMERE
62+
{ "westmere", SSE42, &test_westmere_trailing_zeroes,
63+
&test_westmere_leading_zeroes,
64+
&test_westmere_prefix_xor,
65+
&test_westmere_add_overflow },
66+
#endif
67+
{ "fallback", DEFAULT, &test_fallback_trailing_zeroes,
68+
&test_fallback_leading_zeroes,
69+
0, 0 }
70+
};
71+
72+
static inline const struct kernel *
73+
select_kernel(void)
74+
{
75+
const char *preferred;
76+
const uint32_t supported = detect_supported_architectures();
77+
const size_t length = sizeof(kernels)/sizeof(kernels[0]);
78+
size_t count = 0;
79+
80+
if ((preferred = getenv("ZONE_KERNEL"))) {
81+
for (; count < length; count++)
82+
if (strcasecmp(preferred, kernels[count].name) == 0)
83+
break;
84+
if (count == length)
85+
count = 0;
86+
}
87+
88+
for (; count < length; count++)
89+
if ((kernels[count].instruction_set & supported) == (kernels[count].instruction_set))
90+
return &kernels[count];
91+
92+
return &kernels[length - 1];
93+
}
94+
95+
/*!cmocka */
96+
void test_trailing_zeroes(void **state)
97+
{
98+
const struct kernel *kernel = select_kernel();
99+
assert(kernel);
100+
kernel->test_trailing_zeroes(state);
101+
}
102+
103+
/*!cmocka */
104+
void test_leading_zeroes(void **state)
105+
{
106+
const struct kernel *kernel = select_kernel();
107+
assert(kernel);
108+
kernel->test_leading_zeroes(state);
109+
}
110+
111+
/*!cmocka */
112+
void test_prefix_xor(void **state)
113+
{
114+
const struct kernel *kernel = select_kernel();
115+
assert(kernel);
116+
if (kernel->test_prefix_xor)
117+
kernel->test_prefix_xor(state);
118+
else
119+
assert_true(1);
120+
}
121+
122+
/*!cmocka */
123+
void test_add_overflow(void **state)
124+
{
125+
const struct kernel *kernel = select_kernel();
126+
assert(kernel);
127+
if (kernel->test_add_overflow)
128+
kernel->test_add_overflow(state);
129+
else
130+
assert_true(1);
131+
}

tests/fallback/bits.c

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* bits.c -- test bit manipulation instructions
3+
*
4+
* Copyright (c) 2024, NLnet Labs. All rights reserved.
5+
*
6+
* SPDX-License-Identifier: BSD-3-Clause
7+
*
8+
*/
9+
#include <stdarg.h>
10+
#include <setjmp.h>
11+
#include <string.h>
12+
#include <stdint.h>
13+
#include <stdio.h>
14+
#include <cmocka.h>
15+
16+
#include "attributes.h"
17+
#include "fallback/bits.h"
18+
19+
void test_fallback_trailing_zeroes(void **state)
20+
{
21+
(void)state;
22+
fprintf(stderr, "test_fallback_trailing_zeroes\n");
23+
for (uint64_t shift = 0; shift < 63; shift++) {
24+
uint64_t bit = 1llu << shift;
25+
uint64_t tz = trailing_zeroes(bit);
26+
assert_int_equal(tz, shift);
27+
}
28+
}
29+
30+
void test_fallback_leading_zeroes(void **state)
31+
{
32+
(void)state;
33+
fprintf(stderr, "test_fallback_leading_zeroes\n");
34+
for (uint64_t shift = 0; shift << 63; shift++) {
35+
const uint64_t bit = 1llu << shift;
36+
uint64_t lz = leading_zeroes(bit);
37+
assert_int_equal(lz, 63 - shift);
38+
}
39+
}

tests/haswell/bits.c

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* bits-haswell.c -- test Haswell specific bit manipulation instructions
3+
*
4+
* Copyright (c) 2024, NLnet Labs. All rights reserved.
5+
*
6+
* SPDX-License-Identifier: BSD-3-Clause
7+
*
8+
*/
9+
#include <stdarg.h>
10+
#include <setjmp.h>
11+
#include <string.h>
12+
#include <stdio.h>
13+
#include <cmocka.h>
14+
15+
#include "attributes.h"
16+
#include "haswell/bits.h"
17+
18+
void test_haswell_trailing_zeroes(void **state)
19+
{
20+
(void)state;
21+
fprintf(stderr, "test_haswell_trailing_zeroes\n");
22+
for (uint64_t shift = 0; shift < 63; shift++) {
23+
uint64_t bit = 1llu << shift;
24+
uint64_t tz = trailing_zeroes(bit);
25+
assert_int_equal(tz, shift);
26+
}
27+
}
28+
29+
void test_haswell_leading_zeroes(void **state)
30+
{
31+
(void)state;
32+
fprintf(stderr, "test_haswell_leading_zeroes\n");
33+
for (uint64_t shift = 0; shift << 63; shift++) {
34+
const uint64_t bit = 1llu << shift;
35+
uint64_t lz = leading_zeroes(bit);
36+
assert_int_equal(lz, 63 - shift);
37+
}
38+
}
39+
40+
void test_haswell_prefix_xor(void **state)
41+
{
42+
(void)state;
43+
fprintf(stderr, "test_haswell_prefix_xor\n");
44+
// "0001 0001 0000 0101 0000 0110 0000 0000"
45+
uint64_t mask =
46+
(1llu << 28) | (1llu << 24) |
47+
(1llu << 18) | (1llu << 16) |
48+
(1llu << 10) | (1llu << 9);
49+
// "0000 1111 0000 0011 0000 0010 0000 0000"
50+
uint64_t prefix_mask =
51+
(1llu << 27) | (1llu << 26) | (1llu << 25) | (1llu << 24) |
52+
(1llu << 17) | (1llu << 16) |
53+
(1llu << 9);
54+
55+
assert_int_equal(prefix_xor(mask), prefix_mask);
56+
}
57+
58+
void test_haswell_add_overflow(void **state)
59+
{
60+
(void)state;
61+
fprintf(stderr, "test_haswell_add_overflow\n");
62+
uint64_t all_ones = UINT64_MAX;
63+
uint64_t result = 0;
64+
uint64_t overflow = add_overflow(all_ones, 2llu, &result);
65+
assert_int_equal(result, 1llu);
66+
assert_true(overflow);
67+
overflow = add_overflow(all_ones, 1llu, &result);
68+
assert_int_equal(result, 0llu);
69+
assert_true(overflow);
70+
overflow = add_overflow(all_ones, 0llu, &result);
71+
assert_int_equal(result, all_ones);
72+
assert_false(overflow);
73+
}

tests/tools.c

+21-6
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,21 @@
1414
#include <process.h>
1515
#include <sys/types.h>
1616
#include <sys/stat.h>
17+
18+
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
19+
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
20+
#endif
1721
#else
1822
#include <unistd.h>
1923
#include <sys/stat.h>
2024
#endif
2125

26+
#include "diagnostic.h"
27+
2228
static bool is_dir(const char *dir)
2329
{
2430
struct stat sb;
25-
if (stat(dir, &sb) == 0 && S_ISDIR(sb.st_mode))// & S_IFMT) == S_IFDIR)
31+
if (stat(dir, &sb) == 0 && S_ISDIR(sb.st_mode))
2632
return true;
2733
return false;
2834
}
@@ -31,8 +37,11 @@ static const char *get_tmpdir(const char *dir)
3137
{
3238
const char *tmpdir = NULL;
3339

34-
#if _WIN32
40+
#if _MSC_VER
41+
diagnostic_push()
42+
msvc_diagnostic_ignored(4996)
3543
tmpdir = getenv("TMP");
44+
diagnostic_pop()
3645
#else
3746
tmpdir = getenv("TMPDIR");
3847
#endif
@@ -57,18 +66,24 @@ char *get_tempnam(const char *dir, const char *pfx)
5766
return NULL;
5867

5968
static unsigned int count = 0;
69+
unsigned int pid;
70+
71+
diagnostic_push()
72+
msvc_diagnostic_ignored(4996)
73+
pid = (unsigned int)getpid();
74+
diagnostic_pop()
6075

61-
srand(getpid() + count++);
76+
srand(pid + count++);
6277

6378
for (unsigned int i = 0; i < 1000; i++) {
6479
char tmp[16];
6580
int rnd = rand();
6681
int len = snprintf(tmp, sizeof(tmp), "%s/%s.%d", tmpdir, pfx, rnd);
67-
assert(len != -1);
68-
char *tmpfile = malloc(len + 1);
82+
assert(len >= 0);
83+
char *tmpfile = malloc((unsigned int)len + 1);
6984
if (!tmpfile)
7085
return NULL;
71-
(void)snprintf(tmpfile, len + 1, "%s/%s.%d", tmpdir, pfx, rnd);
86+
(void)snprintf(tmpfile, (unsigned int)len + 1, "%s/%s.%d", tmpdir, pfx, rnd);
7287
struct stat sb;
7388
if (stat(tmpfile, &sb) == -1)
7489
return tmpfile;

0 commit comments

Comments
 (0)