xref: /netbsd-src/external/bsd/jemalloc/dist/test/unit/bit_util.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
1a0698ed9Schristos #include "test/jemalloc_test.h"
2a0698ed9Schristos 
3a0698ed9Schristos #include "jemalloc/internal/bit_util.h"
4a0698ed9Schristos 
5a0698ed9Schristos #define TEST_POW2_CEIL(t, suf, pri) do {				\
6a0698ed9Schristos 	unsigned i, pow2;						\
7a0698ed9Schristos 	t x;								\
8a0698ed9Schristos 									\
9*7bdf38e5Schristos 	expect_##suf##_eq(pow2_ceil_##suf(0), 0, "Unexpected result");	\
10a0698ed9Schristos 									\
11a0698ed9Schristos 	for (i = 0; i < sizeof(t) * 8; i++) {				\
12*7bdf38e5Schristos 		expect_##suf##_eq(pow2_ceil_##suf(((t)1) << i), ((t)1)	\
13a0698ed9Schristos 		    << i, "Unexpected result");				\
14a0698ed9Schristos 	}								\
15a0698ed9Schristos 									\
16a0698ed9Schristos 	for (i = 2; i < sizeof(t) * 8; i++) {				\
17*7bdf38e5Schristos 		expect_##suf##_eq(pow2_ceil_##suf((((t)1) << i) - 1),	\
18a0698ed9Schristos 		    ((t)1) << i, "Unexpected result");			\
19a0698ed9Schristos 	}								\
20a0698ed9Schristos 									\
21a0698ed9Schristos 	for (i = 0; i < sizeof(t) * 8 - 1; i++) {			\
22*7bdf38e5Schristos 		expect_##suf##_eq(pow2_ceil_##suf((((t)1) << i) + 1),	\
23a0698ed9Schristos 		    ((t)1) << (i+1), "Unexpected result");		\
24a0698ed9Schristos 	}								\
25a0698ed9Schristos 									\
26a0698ed9Schristos 	for (pow2 = 1; pow2 < 25; pow2++) {				\
27a0698ed9Schristos 		for (x = (((t)1) << (pow2-1)) + 1; x <= ((t)1) << pow2;	\
28a0698ed9Schristos 		    x++) {						\
29*7bdf38e5Schristos 			expect_##suf##_eq(pow2_ceil_##suf(x),		\
30a0698ed9Schristos 			    ((t)1) << pow2,				\
31a0698ed9Schristos 			    "Unexpected result, x=%"pri, x);		\
32a0698ed9Schristos 		}							\
33a0698ed9Schristos 	}								\
34a0698ed9Schristos } while (0)
35a0698ed9Schristos 
36a0698ed9Schristos TEST_BEGIN(test_pow2_ceil_u64) {
37a0698ed9Schristos 	TEST_POW2_CEIL(uint64_t, u64, FMTu64);
38a0698ed9Schristos }
39a0698ed9Schristos TEST_END
40a0698ed9Schristos 
41a0698ed9Schristos TEST_BEGIN(test_pow2_ceil_u32) {
42a0698ed9Schristos 	TEST_POW2_CEIL(uint32_t, u32, FMTu32);
43a0698ed9Schristos }
44a0698ed9Schristos TEST_END
45a0698ed9Schristos 
46a0698ed9Schristos TEST_BEGIN(test_pow2_ceil_zu) {
47a0698ed9Schristos 	TEST_POW2_CEIL(size_t, zu, "zu");
48a0698ed9Schristos }
49a0698ed9Schristos TEST_END
50a0698ed9Schristos 
51*7bdf38e5Schristos void
52*7bdf38e5Schristos expect_lg_ceil_range(size_t input, unsigned answer) {
53*7bdf38e5Schristos 	if (input == 1) {
54*7bdf38e5Schristos 		expect_u_eq(0, answer, "Got %u as lg_ceil of 1", answer);
55*7bdf38e5Schristos 		return;
56*7bdf38e5Schristos 	}
57*7bdf38e5Schristos 	expect_zu_le(input, (ZU(1) << answer),
58*7bdf38e5Schristos 	    "Got %u as lg_ceil of %zu", answer, input);
59*7bdf38e5Schristos 	expect_zu_gt(input, (ZU(1) << (answer - 1)),
60*7bdf38e5Schristos 	    "Got %u as lg_ceil of %zu", answer, input);
61*7bdf38e5Schristos }
62*7bdf38e5Schristos 
63*7bdf38e5Schristos void
64*7bdf38e5Schristos expect_lg_floor_range(size_t input, unsigned answer) {
65*7bdf38e5Schristos 	if (input == 1) {
66*7bdf38e5Schristos 		expect_u_eq(0, answer, "Got %u as lg_floor of 1", answer);
67*7bdf38e5Schristos 		return;
68*7bdf38e5Schristos 	}
69*7bdf38e5Schristos 	expect_zu_ge(input, (ZU(1) << answer),
70*7bdf38e5Schristos 	    "Got %u as lg_floor of %zu", answer, input);
71*7bdf38e5Schristos 	expect_zu_lt(input, (ZU(1) << (answer + 1)),
72*7bdf38e5Schristos 	    "Got %u as lg_floor of %zu", answer, input);
73*7bdf38e5Schristos }
74*7bdf38e5Schristos 
75*7bdf38e5Schristos TEST_BEGIN(test_lg_ceil_floor) {
76*7bdf38e5Schristos 	for (size_t i = 1; i < 10 * 1000 * 1000; i++) {
77*7bdf38e5Schristos 		expect_lg_ceil_range(i, lg_ceil(i));
78*7bdf38e5Schristos 		expect_lg_ceil_range(i, LG_CEIL(i));
79*7bdf38e5Schristos 		expect_lg_floor_range(i, lg_floor(i));
80*7bdf38e5Schristos 		expect_lg_floor_range(i, LG_FLOOR(i));
81*7bdf38e5Schristos 	}
82*7bdf38e5Schristos 	for (int i = 10; i < 8 * (1 << LG_SIZEOF_PTR) - 5; i++) {
83*7bdf38e5Schristos 		for (size_t j = 0; j < (1 << 4); j++) {
84*7bdf38e5Schristos 			size_t num1 = ((size_t)1 << i)
85*7bdf38e5Schristos 			    - j * ((size_t)1 << (i - 4));
86*7bdf38e5Schristos 			size_t num2 = ((size_t)1 << i)
87*7bdf38e5Schristos 			    + j * ((size_t)1 << (i - 4));
88*7bdf38e5Schristos 			expect_zu_ne(num1, 0, "Invalid lg argument");
89*7bdf38e5Schristos 			expect_zu_ne(num2, 0, "Invalid lg argument");
90*7bdf38e5Schristos 			expect_lg_ceil_range(num1, lg_ceil(num1));
91*7bdf38e5Schristos 			expect_lg_ceil_range(num1, LG_CEIL(num1));
92*7bdf38e5Schristos 			expect_lg_ceil_range(num2, lg_ceil(num2));
93*7bdf38e5Schristos 			expect_lg_ceil_range(num2, LG_CEIL(num2));
94*7bdf38e5Schristos 
95*7bdf38e5Schristos 			expect_lg_floor_range(num1, lg_floor(num1));
96*7bdf38e5Schristos 			expect_lg_floor_range(num1, LG_FLOOR(num1));
97*7bdf38e5Schristos 			expect_lg_floor_range(num2, lg_floor(num2));
98*7bdf38e5Schristos 			expect_lg_floor_range(num2, LG_FLOOR(num2));
99*7bdf38e5Schristos 		}
100*7bdf38e5Schristos 	}
101*7bdf38e5Schristos }
102*7bdf38e5Schristos TEST_END
103*7bdf38e5Schristos 
104*7bdf38e5Schristos #define TEST_FFS(t, suf, test_suf, pri) do {				\
105*7bdf38e5Schristos 	for (unsigned i = 0; i < sizeof(t) * 8; i++) {			\
106*7bdf38e5Schristos 		for (unsigned j = 0; j <= i; j++) {			\
107*7bdf38e5Schristos 			for (unsigned k = 0; k <= j; k++) {		\
108*7bdf38e5Schristos 				t x = (t)1 << i;			\
109*7bdf38e5Schristos 				x |= (t)1 << j;				\
110*7bdf38e5Schristos 				x |= (t)1 << k;				\
111*7bdf38e5Schristos 				expect_##test_suf##_eq(ffs_##suf(x), k,	\
112*7bdf38e5Schristos 				    "Unexpected result, x=%"pri, x);	\
113*7bdf38e5Schristos 			}						\
114*7bdf38e5Schristos 		}							\
115*7bdf38e5Schristos 	}								\
116*7bdf38e5Schristos } while(0)
117*7bdf38e5Schristos 
118*7bdf38e5Schristos TEST_BEGIN(test_ffs_u) {
119*7bdf38e5Schristos 	TEST_FFS(unsigned, u, u,"u");
120*7bdf38e5Schristos }
121*7bdf38e5Schristos TEST_END
122*7bdf38e5Schristos 
123*7bdf38e5Schristos TEST_BEGIN(test_ffs_lu) {
124*7bdf38e5Schristos 	TEST_FFS(unsigned long, lu, lu, "lu");
125*7bdf38e5Schristos }
126*7bdf38e5Schristos TEST_END
127*7bdf38e5Schristos 
128*7bdf38e5Schristos TEST_BEGIN(test_ffs_llu) {
129*7bdf38e5Schristos 	TEST_FFS(unsigned long long, llu, qd, "llu");
130*7bdf38e5Schristos }
131*7bdf38e5Schristos TEST_END
132*7bdf38e5Schristos 
133*7bdf38e5Schristos TEST_BEGIN(test_ffs_u32) {
134*7bdf38e5Schristos 	TEST_FFS(uint32_t, u32, u32, FMTu32);
135*7bdf38e5Schristos }
136*7bdf38e5Schristos TEST_END
137*7bdf38e5Schristos 
138*7bdf38e5Schristos TEST_BEGIN(test_ffs_u64) {
139*7bdf38e5Schristos 	TEST_FFS(uint64_t, u64, u64, FMTu64);
140*7bdf38e5Schristos }
141*7bdf38e5Schristos TEST_END
142*7bdf38e5Schristos 
143*7bdf38e5Schristos TEST_BEGIN(test_ffs_zu) {
144*7bdf38e5Schristos 	TEST_FFS(size_t, zu, zu, "zu");
145*7bdf38e5Schristos }
146*7bdf38e5Schristos TEST_END
147*7bdf38e5Schristos 
148*7bdf38e5Schristos #define TEST_FLS(t, suf, test_suf, pri) do {				\
149*7bdf38e5Schristos 	for (unsigned i = 0; i < sizeof(t) * 8; i++) {			\
150*7bdf38e5Schristos 		for (unsigned j = 0; j <= i; j++) {			\
151*7bdf38e5Schristos 			for (unsigned k = 0; k <= j; k++) {		\
152*7bdf38e5Schristos 				t x = (t)1 << i;			\
153*7bdf38e5Schristos 				x |= (t)1 << j;				\
154*7bdf38e5Schristos 				x |= (t)1 << k;				\
155*7bdf38e5Schristos 				expect_##test_suf##_eq(fls_##suf(x), i,	\
156*7bdf38e5Schristos 				    "Unexpected result, x=%"pri, x);	\
157*7bdf38e5Schristos 			}						\
158*7bdf38e5Schristos 		}							\
159*7bdf38e5Schristos 	}								\
160*7bdf38e5Schristos } while(0)
161*7bdf38e5Schristos 
162*7bdf38e5Schristos TEST_BEGIN(test_fls_u) {
163*7bdf38e5Schristos 	TEST_FLS(unsigned, u, u,"u");
164*7bdf38e5Schristos }
165*7bdf38e5Schristos TEST_END
166*7bdf38e5Schristos 
167*7bdf38e5Schristos TEST_BEGIN(test_fls_lu) {
168*7bdf38e5Schristos 	TEST_FLS(unsigned long, lu, lu, "lu");
169*7bdf38e5Schristos }
170*7bdf38e5Schristos TEST_END
171*7bdf38e5Schristos 
172*7bdf38e5Schristos TEST_BEGIN(test_fls_llu) {
173*7bdf38e5Schristos 	TEST_FLS(unsigned long long, llu, qd, "llu");
174*7bdf38e5Schristos }
175*7bdf38e5Schristos TEST_END
176*7bdf38e5Schristos 
177*7bdf38e5Schristos TEST_BEGIN(test_fls_u32) {
178*7bdf38e5Schristos 	TEST_FLS(uint32_t, u32, u32, FMTu32);
179*7bdf38e5Schristos }
180*7bdf38e5Schristos TEST_END
181*7bdf38e5Schristos 
182*7bdf38e5Schristos TEST_BEGIN(test_fls_u64) {
183*7bdf38e5Schristos 	TEST_FLS(uint64_t, u64, u64, FMTu64);
184*7bdf38e5Schristos }
185*7bdf38e5Schristos TEST_END
186*7bdf38e5Schristos 
187*7bdf38e5Schristos TEST_BEGIN(test_fls_zu) {
188*7bdf38e5Schristos 	TEST_FLS(size_t, zu, zu, "zu");
189*7bdf38e5Schristos }
190*7bdf38e5Schristos TEST_END
191*7bdf38e5Schristos 
192*7bdf38e5Schristos TEST_BEGIN(test_fls_u_slow) {
193*7bdf38e5Schristos 	TEST_FLS(unsigned, u_slow, u,"u");
194*7bdf38e5Schristos }
195*7bdf38e5Schristos TEST_END
196*7bdf38e5Schristos 
197*7bdf38e5Schristos TEST_BEGIN(test_fls_lu_slow) {
198*7bdf38e5Schristos 	TEST_FLS(unsigned long, lu_slow, lu, "lu");
199*7bdf38e5Schristos }
200*7bdf38e5Schristos TEST_END
201*7bdf38e5Schristos 
202*7bdf38e5Schristos TEST_BEGIN(test_fls_llu_slow) {
203*7bdf38e5Schristos 	TEST_FLS(unsigned long long, llu_slow, qd, "llu");
204*7bdf38e5Schristos }
205*7bdf38e5Schristos TEST_END
206*7bdf38e5Schristos 
207*7bdf38e5Schristos static unsigned
208*7bdf38e5Schristos popcount_byte(unsigned byte) {
209*7bdf38e5Schristos 	int count = 0;
210*7bdf38e5Schristos 	for (int i = 0; i < 8; i++) {
211*7bdf38e5Schristos 		if ((byte & (1 << i)) != 0) {
212*7bdf38e5Schristos 			count++;
213*7bdf38e5Schristos 		}
214*7bdf38e5Schristos 	}
215*7bdf38e5Schristos 	return count;
216*7bdf38e5Schristos }
217*7bdf38e5Schristos 
218*7bdf38e5Schristos static uint64_t
219*7bdf38e5Schristos expand_byte_to_mask(unsigned byte) {
220*7bdf38e5Schristos 	uint64_t result = 0;
221*7bdf38e5Schristos 	for (int i = 0; i < 8; i++) {
222*7bdf38e5Schristos 		if ((byte & (1 << i)) != 0) {
223*7bdf38e5Schristos 			result |= ((uint64_t)0xFF << (i * 8));
224*7bdf38e5Schristos 		}
225*7bdf38e5Schristos 	}
226*7bdf38e5Schristos 	return result;
227*7bdf38e5Schristos }
228*7bdf38e5Schristos 
229*7bdf38e5Schristos #define TEST_POPCOUNT(t, suf, pri_hex) do {				\
230*7bdf38e5Schristos 	t bmul = (t)0x0101010101010101ULL;				\
231*7bdf38e5Schristos 	for (unsigned i = 0; i < (1 << sizeof(t)); i++) {		\
232*7bdf38e5Schristos 		for (unsigned j = 0; j < 256; j++) {			\
233*7bdf38e5Schristos 			/*						\
234*7bdf38e5Schristos 			 * Replicate the byte j into various		\
235*7bdf38e5Schristos 			 * bytes of the integer (as indicated by the	\
236*7bdf38e5Schristos 			 * mask in i), and ensure that the popcount of	\
237*7bdf38e5Schristos 			 * the result is popcount(i) * popcount(j)	\
238*7bdf38e5Schristos 			 */						\
239*7bdf38e5Schristos 			t mask = (t)expand_byte_to_mask(i);		\
240*7bdf38e5Schristos 			t x = (bmul * j) & mask;			\
241*7bdf38e5Schristos 			expect_u_eq(					\
242*7bdf38e5Schristos 			    popcount_byte(i) * popcount_byte(j),	\
243*7bdf38e5Schristos 			    popcount_##suf(x),				\
244*7bdf38e5Schristos 			    "Unexpected result, x=0x%"pri_hex, x);	\
245*7bdf38e5Schristos 		}							\
246*7bdf38e5Schristos 	}								\
247*7bdf38e5Schristos } while (0)
248*7bdf38e5Schristos 
249*7bdf38e5Schristos TEST_BEGIN(test_popcount_u) {
250*7bdf38e5Schristos 	TEST_POPCOUNT(unsigned, u, "x");
251*7bdf38e5Schristos }
252*7bdf38e5Schristos TEST_END
253*7bdf38e5Schristos 
254*7bdf38e5Schristos TEST_BEGIN(test_popcount_u_slow) {
255*7bdf38e5Schristos 	TEST_POPCOUNT(unsigned, u_slow, "x");
256*7bdf38e5Schristos }
257*7bdf38e5Schristos TEST_END
258*7bdf38e5Schristos 
259*7bdf38e5Schristos TEST_BEGIN(test_popcount_lu) {
260*7bdf38e5Schristos 	TEST_POPCOUNT(unsigned long, lu, "lx");
261*7bdf38e5Schristos }
262*7bdf38e5Schristos TEST_END
263*7bdf38e5Schristos 
264*7bdf38e5Schristos TEST_BEGIN(test_popcount_lu_slow) {
265*7bdf38e5Schristos 	TEST_POPCOUNT(unsigned long, lu_slow, "lx");
266*7bdf38e5Schristos }
267*7bdf38e5Schristos TEST_END
268*7bdf38e5Schristos 
269*7bdf38e5Schristos TEST_BEGIN(test_popcount_llu) {
270*7bdf38e5Schristos 	TEST_POPCOUNT(unsigned long long, llu, "llx");
271*7bdf38e5Schristos }
272*7bdf38e5Schristos TEST_END
273*7bdf38e5Schristos 
274*7bdf38e5Schristos TEST_BEGIN(test_popcount_llu_slow) {
275*7bdf38e5Schristos 	TEST_POPCOUNT(unsigned long long, llu_slow, "llx");
276*7bdf38e5Schristos }
277*7bdf38e5Schristos TEST_END
278*7bdf38e5Schristos 
279a0698ed9Schristos int
280a0698ed9Schristos main(void) {
281*7bdf38e5Schristos 	return test_no_reentrancy(
282a0698ed9Schristos 	    test_pow2_ceil_u64,
283a0698ed9Schristos 	    test_pow2_ceil_u32,
284*7bdf38e5Schristos 	    test_pow2_ceil_zu,
285*7bdf38e5Schristos 	    test_lg_ceil_floor,
286*7bdf38e5Schristos 	    test_ffs_u,
287*7bdf38e5Schristos 	    test_ffs_lu,
288*7bdf38e5Schristos 	    test_ffs_llu,
289*7bdf38e5Schristos 	    test_ffs_u32,
290*7bdf38e5Schristos 	    test_ffs_u64,
291*7bdf38e5Schristos 	    test_ffs_zu,
292*7bdf38e5Schristos 	    test_fls_u,
293*7bdf38e5Schristos 	    test_fls_lu,
294*7bdf38e5Schristos 	    test_fls_llu,
295*7bdf38e5Schristos 	    test_fls_u32,
296*7bdf38e5Schristos 	    test_fls_u64,
297*7bdf38e5Schristos 	    test_fls_zu,
298*7bdf38e5Schristos 	    test_fls_u_slow,
299*7bdf38e5Schristos 	    test_fls_lu_slow,
300*7bdf38e5Schristos 	    test_fls_llu_slow,
301*7bdf38e5Schristos 	    test_popcount_u,
302*7bdf38e5Schristos 	    test_popcount_u_slow,
303*7bdf38e5Schristos 	    test_popcount_lu,
304*7bdf38e5Schristos 	    test_popcount_lu_slow,
305*7bdf38e5Schristos 	    test_popcount_llu,
306*7bdf38e5Schristos 	    test_popcount_llu_slow);
307a0698ed9Schristos }
308