xref: /illumos-gate/usr/src/uts/common/sys/stdbit.h (revision 2e07277863d69344215bd0c72e171d0c854dbe56)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2024 Oxide Computer Company
14  */
15 
16 #ifndef _SYS_STDBIT_H
17 #define	_SYS_STDBIT_H
18 
19 /*
20  * This header implements all of the different aspects of the C23 stdbit.h
21  * functionality. We attempt to make this header useful to all C versions other
22  * than the type generic interfaces, for which we require the asked for version
23  * of C to be at least C23. The functions that are present here are allowed to
24  * be inline or not. To provide wider ranging compiler support we declare extern
25  * versions of all of these symbols which are provided in both libc and the
26  * kernel. This also avoids cases where a compiler builtin relies on external
27  * runtime library support.
28  *
29  * In the future, we should provide inline versions with compilers that support
30  * common builtins.
31  */
32 
33 #include <sys/feature_tests.h>
34 #include <sys/isa_defs.h>
35 
36 /*
37  * This header is required specifically to make the size_t, uintXX_t, and the
38  * _least_ variants available. The generic values are allowed to leverage the
39  * 'bool' type. In C23, bool became a keyword as opposed to a definition to
40  * _Bool. We therefore include it so we can attempt to be consistent and
41  * generally useful.
42  */
43 #include <sys/int_types.h>
44 #include <sys/stdbool.h>
45 
46 #ifdef __cplusplus
47 extern "C" {
48 #endif
49 
50 /*
51  * Declare our version.
52  */
53 #define	__STDC_VERSION_STDBIT_H__	202311L
54 
55 #if !defined(_SIZE_T) || __cplusplus >= 199711L
56 #define	_SIZE_T
57 #if defined(_LP64) || defined(_I32LPx)
58 typedef unsigned long size_t;   /* size of something in bytes */
59 #else
60 typedef unsigned int size_t;    /* (historical version) */
61 #endif
62 #endif  /* _SIZE_T */
63 
64 /*
65  * Endian values and detection.
66  */
67 #define	__STDC_ENDIAN_LITTLE__	1234
68 #define	__STDC_ENDIAN_BIG__	4321
69 #if defined(_LITTLE_ENDIAN)
70 #define	__STDC_ENDIAN_NATIVE__	__STDC_ENDIAN_LITTLE__
71 #elif defined(_BIG_ENDIAN)
72 #define	__STDC_ENDIAN_NATIVE__	__STDC_ENDIAN_BIG__
73 #else
74 #error	"Unknown byte order"
75 #endif	/* _LITTLE_ENDIAN */
76 
77 /*
78  * Count Leading Zeros
79  */
80 extern unsigned int stdc_leading_zeros_uc(unsigned char) _C23_UNSEQ_ATTR;
81 extern unsigned int stdc_leading_zeros_us(unsigned short) _C23_UNSEQ_ATTR;
82 extern unsigned int stdc_leading_zeros_ui(unsigned int) _C23_UNSEQ_ATTR;
83 extern unsigned int stdc_leading_zeros_ul(unsigned long) _C23_UNSEQ_ATTR;
84 
85 /*
86  * Count Leading Ones
87  */
88 extern unsigned int stdc_leading_ones_uc(unsigned char) _C23_UNSEQ_ATTR;
89 extern unsigned int stdc_leading_ones_us(unsigned short) _C23_UNSEQ_ATTR;
90 extern unsigned int stdc_leading_ones_ui(unsigned int) _C23_UNSEQ_ATTR;
91 extern unsigned int stdc_leading_ones_ul(unsigned long) _C23_UNSEQ_ATTR;
92 
93 /*
94  * Count Trailing Zeros
95  */
96 extern unsigned int stdc_trailing_zeros_uc(unsigned char) _C23_UNSEQ_ATTR;
97 extern unsigned int stdc_trailing_zeros_us(unsigned short) _C23_UNSEQ_ATTR;
98 extern unsigned int stdc_trailing_zeros_ui(unsigned int) _C23_UNSEQ_ATTR;
99 extern unsigned int stdc_trailing_zeros_ul(unsigned long) _C23_UNSEQ_ATTR;
100 
101 /*
102  * Count Trailing Ones
103  */
104 extern unsigned int stdc_trailing_ones_uc(unsigned char) _C23_UNSEQ_ATTR;
105 extern unsigned int stdc_trailing_ones_us(unsigned short) _C23_UNSEQ_ATTR;
106 extern unsigned int stdc_trailing_ones_ui(unsigned int) _C23_UNSEQ_ATTR;
107 extern unsigned int stdc_trailing_ones_ul(unsigned long) _C23_UNSEQ_ATTR;
108 
109 /*
110  * First Leading Zero
111  */
112 extern unsigned int stdc_first_leading_zero_uc(unsigned char) _C23_UNSEQ_ATTR;
113 extern unsigned int stdc_first_leading_zero_us(unsigned short) _C23_UNSEQ_ATTR;
114 extern unsigned int stdc_first_leading_zero_ui(unsigned int) _C23_UNSEQ_ATTR;
115 extern unsigned int stdc_first_leading_zero_ul(unsigned long) _C23_UNSEQ_ATTR;
116 
117 /*
118  * First Leading One
119  */
120 extern unsigned int stdc_first_leading_one_uc(unsigned char) _C23_UNSEQ_ATTR;
121 extern unsigned int stdc_first_leading_one_us(unsigned short) _C23_UNSEQ_ATTR;
122 extern unsigned int stdc_first_leading_one_ui(unsigned int) _C23_UNSEQ_ATTR;
123 extern unsigned int stdc_first_leading_one_ul(unsigned long) _C23_UNSEQ_ATTR;
124 
125 /*
126  * First Trailing Zero
127  */
128 extern unsigned int stdc_first_trailing_zero_uc(unsigned char) _C23_UNSEQ_ATTR;
129 extern unsigned int stdc_first_trailing_zero_us(unsigned short) _C23_UNSEQ_ATTR;
130 extern unsigned int stdc_first_trailing_zero_ui(unsigned int) _C23_UNSEQ_ATTR;
131 extern unsigned int stdc_first_trailing_zero_ul(unsigned long) _C23_UNSEQ_ATTR;
132 
133 /*
134  * First Trailing One
135  */
136 extern unsigned int stdc_first_trailing_one_uc(unsigned char) _C23_UNSEQ_ATTR;
137 extern unsigned int stdc_first_trailing_one_us(unsigned short) _C23_UNSEQ_ATTR;
138 extern unsigned int stdc_first_trailing_one_ui(unsigned int) _C23_UNSEQ_ATTR;
139 extern unsigned int stdc_first_trailing_one_ul(unsigned long) _C23_UNSEQ_ATTR;
140 
141 /*
142  * Count Zeros
143  */
144 extern unsigned int stdc_count_zeros_uc(unsigned char) _C23_UNSEQ_ATTR;
145 extern unsigned int stdc_count_zeros_us(unsigned short) _C23_UNSEQ_ATTR;
146 extern unsigned int stdc_count_zeros_ui(unsigned int) _C23_UNSEQ_ATTR;
147 extern unsigned int stdc_count_zeros_ul(unsigned long) _C23_UNSEQ_ATTR;
148 
149 /*
150  * Count Ones
151  */
152 extern unsigned int stdc_count_ones_uc(unsigned char) _C23_UNSEQ_ATTR;
153 extern unsigned int stdc_count_ones_us(unsigned short) _C23_UNSEQ_ATTR;
154 extern unsigned int stdc_count_ones_ui(unsigned int) _C23_UNSEQ_ATTR;
155 extern unsigned int stdc_count_ones_ul(unsigned long) _C23_UNSEQ_ATTR;
156 
157 /*
158  * Single-bit Check
159  */
160 extern bool stdc_has_single_bit_uc(unsigned char) _C23_UNSEQ_ATTR;
161 extern bool stdc_has_single_bit_us(unsigned short) _C23_UNSEQ_ATTR;
162 extern bool stdc_has_single_bit_ui(unsigned int) _C23_UNSEQ_ATTR;
163 extern bool stdc_has_single_bit_ul(unsigned long) _C23_UNSEQ_ATTR;
164 
165 /*
166  * Bit Width
167  */
168 extern unsigned int stdc_bit_width_uc(unsigned char) _C23_UNSEQ_ATTR;
169 extern unsigned int stdc_bit_width_us(unsigned short) _C23_UNSEQ_ATTR;
170 extern unsigned int stdc_bit_width_ui(unsigned int) _C23_UNSEQ_ATTR;
171 extern unsigned int stdc_bit_width_ul(unsigned long) _C23_UNSEQ_ATTR;
172 
173 /*
174  * Bit Floor
175  */
176 extern unsigned char stdc_bit_floor_uc(unsigned char) _C23_UNSEQ_ATTR;
177 extern unsigned short stdc_bit_floor_us(unsigned short) _C23_UNSEQ_ATTR;
178 extern unsigned int stdc_bit_floor_ui(unsigned int) _C23_UNSEQ_ATTR;
179 extern unsigned long stdc_bit_floor_ul(unsigned long) _C23_UNSEQ_ATTR;
180 
181 /*
182  * Bit Ceiling
183  */
184 extern unsigned char stdc_bit_ceil_uc(unsigned char) _C23_UNSEQ_ATTR;
185 extern unsigned short stdc_bit_ceil_us(unsigned short) _C23_UNSEQ_ATTR;
186 extern unsigned int stdc_bit_ceil_ui(unsigned int) _C23_UNSEQ_ATTR;
187 extern unsigned long stdc_bit_ceil_ul(unsigned long) _C23_UNSEQ_ATTR;
188 
189 /*
190  * long long variants of functions. This check is just for some non-C23
191  * environments out of courtesy.
192  */
193 #if defined(_LONGLONG_TYPE)
194 extern unsigned int stdc_leading_zeros_ull(unsigned long long) _C23_UNSEQ_ATTR;
195 extern unsigned int stdc_leading_ones_ull(unsigned long long) _C23_UNSEQ_ATTR;
196 extern unsigned int stdc_trailing_zeros_ull(unsigned long long) _C23_UNSEQ_ATTR;
197 extern unsigned int stdc_trailing_ones_ull(unsigned long long) _C23_UNSEQ_ATTR;
198 extern unsigned int stdc_first_leading_zero_ull(unsigned long long)
199     _C23_UNSEQ_ATTR;
200 extern unsigned int stdc_first_leading_one_ull(unsigned long long)
201     _C23_UNSEQ_ATTR;
202 extern unsigned int stdc_first_trailing_zero_ull(unsigned long long)
203     _C23_UNSEQ_ATTR;
204 extern unsigned int stdc_first_trailing_one_ull(unsigned long long)
205     _C23_UNSEQ_ATTR;
206 extern unsigned int stdc_count_zeros_ull(unsigned long long) _C23_UNSEQ_ATTR;
207 extern unsigned int stdc_count_ones_ull(unsigned long long) _C23_UNSEQ_ATTR;
208 extern bool stdc_has_single_bit_ull(unsigned long long) _C23_UNSEQ_ATTR;
209 extern unsigned int stdc_bit_width_ull(unsigned long long) _C23_UNSEQ_ATTR;
210 extern unsigned long long stdc_bit_floor_ull(unsigned long long)
211     _C23_UNSEQ_ATTR;
212 extern unsigned long long stdc_bit_ceil_ull(unsigned long long) _C23_UNSEQ_ATTR;
213 #endif	/* _LONGLONG_TYPE */
214 
215 /*
216  * Type Generic functions. The standard requires that these be a generic return
217  * type that operates on the following types of values:
218  *
219  *  - Standard unsigned integer types (excluding bool) i.e. 'unsigned int'.
220  *  - Extended unsigned integer types i.e. 'uint128_t' which is not something
221  *    currently supported and up to the platform.
222  *  - Bit-precise integers that match standard or extended integers. This means
223  *    that _BitInt(32) is accepted, but a value that basically doesn't match a
224  *    uint8_t, uint16_t, uint32_t, or uint64_t like _BitInt(48) is not valid.
225  *
226  * There currently is no way to match ranges of _BitInt in the _Generic macro so
227  * we end up focusing on the size of the type that was passed. _Generic matches
228  * on the type of the first expression, so rather than just the base type of the
229  * value, we instead use a suggestion to transform it into a fixed-length array.
230  * This works for signed and unsigned integers, implicitly doing a cast to the
231  * unsigned value for signed integers. Similarly, this incidentally works for
232  * signed and unsigned _BitInt() values that are able to be translated into
233  * standard sizes.  We always use the ull versions for 64-bit values as that is
234  * always 64-bit regardless if we're in an ILP32 or LP64 environment.
235  */
236 #if defined(_STDC_C23)
237 /* CSTYLED */
238 #define	stdc_leading_zeros(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
239     char(*)[1]:	stdc_leading_zeros_uc(val),	\
240     char(*)[2]:	stdc_leading_zeros_us(val),	\
241     char(*)[4]:	stdc_leading_zeros_ui(val),	\
242     char(*)[8]:	stdc_leading_zeros_ull(val))
243 
244 /* CSTYLED */
245 #define	stdc_leading_ones(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
246     char(*)[1]:	stdc_leading_ones_uc(val),	\
247     char(*)[2]:	stdc_leading_ones_us(val),	\
248     char(*)[4]:	stdc_leading_ones_ui(val),	\
249     char(*)[8]:	stdc_leading_ones_ull(val))
250 
251 /* CSTYLED */
252 #define	stdc_trailing_zeros(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
253     char(*)[1]:	stdc_trailing_zeros_uc(val),	\
254     char(*)[2]:	stdc_trailing_zeros_us(val),	\
255     char(*)[4]:	stdc_trailing_zeros_ui(val),	\
256     char(*)[8]:	stdc_trailing_zeros_ull(val))
257 
258 /* CSTYLED */
259 #define	stdc_trailing_ones(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
260     char(*)[1]:	stdc_trailing_ones_uc(val),	\
261     char(*)[2]:	stdc_trailing_ones_us(val),	\
262     char(*)[4]:	stdc_trailing_ones_ui(val),	\
263     char(*)[8]:	stdc_trailing_ones_ull(val))
264 
265 /* CSTYLED */
266 #define	stdc_first_leading_zero(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
267     char(*)[1]:	stdc_first_leading_zero_uc(val),	\
268     char(*)[2]:	stdc_first_leading_zero_us(val),	\
269     char(*)[4]:	stdc_first_leading_zero_ui(val),	\
270     char(*)[8]:	stdc_first_leading_zero_ull(val))
271 
272 /* CSTYLED */
273 #define	stdc_first_leading_one(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
274     char(*)[1]:	stdc_first_leading_one_uc(val),	\
275     char(*)[2]:	stdc_first_leading_one_us(val),	\
276     char(*)[4]:	stdc_first_leading_one_ui(val),	\
277     char(*)[8]:	stdc_first_leading_one_ull(val))
278 
279 /* CSTYLED */
280 #define	stdc_first_trailing_zero(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
281     char(*)[1]:	stdc_first_trailing_zero_uc(val),	\
282     char(*)[2]:	stdc_first_trailing_zero_us(val),	\
283     char(*)[4]:	stdc_first_trailing_zero_ui(val),	\
284     char(*)[8]:	stdc_first_trailing_zero_ull(val))
285 
286 /* CSTYLED */
287 #define	stdc_first_trailing_one(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
288     char(*)[1]:	stdc_first_trailing_one_uc(val),	\
289     char(*)[2]:	stdc_first_trailing_one_us(val),	\
290     char(*)[4]:	stdc_first_trailing_one_ui(val),	\
291     char(*)[8]:	stdc_first_trailing_one_ull(val))
292 
293 /* CSTYLED */
294 #define	stdc_count_zeros(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
295     char(*)[1]:	stdc_count_zeros_uc(val),	\
296     char(*)[2]:	stdc_count_zeros_us(val),	\
297     char(*)[4]:	stdc_count_zeros_ui(val),	\
298     char(*)[8]:	stdc_count_zeros_ull(val))
299 
300 /* CSTYLED */
301 #define	stdc_count_ones(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
302     char(*)[1]:	stdc_count_ones_uc(val),	\
303     char(*)[2]:	stdc_count_ones_us(val),	\
304     char(*)[4]:	stdc_count_ones_ui(val),	\
305     char(*)[8]:	stdc_count_ones_ull(val))
306 
307 /* CSTYLED */
308 #define	stdc_has_single_bit(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
309     char(*)[1]:	stdc_has_single_bit_uc(val),	\
310     char(*)[2]:	stdc_has_single_bit_us(val),	\
311     char(*)[4]:	stdc_has_single_bit_ui(val),	\
312     char(*)[8]:	stdc_has_single_bit_ull(val))
313 
314 /* CSTYLED */
315 #define	stdc_bit_width(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
316     char(*)[1]:	stdc_bit_width_uc(val),	\
317     char(*)[2]:	stdc_bit_width_us(val),	\
318     char(*)[4]:	stdc_bit_width_ui(val),	\
319     char(*)[8]:	stdc_bit_width_ull(val))
320 
321 /* CSTYLED */
322 #define	stdc_bit_floor(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
323     char(*)[1]:	stdc_bit_floor_uc(val),	\
324     char(*)[2]:	stdc_bit_floor_us(val),	\
325     char(*)[4]:	stdc_bit_floor_ui(val),	\
326     char(*)[8]:	stdc_bit_floor_ull(val))
327 
328 /* CSTYLED */
329 #define	stdc_bit_ceil(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
330     char(*)[1]:	stdc_bit_ceil_uc(val),	\
331     char(*)[2]:	stdc_bit_ceil_us(val),	\
332     char(*)[4]:	stdc_bit_ceil_ui(val),	\
333     char(*)[8]:	stdc_bit_ceil_ull(val))
334 #endif	/* STDC_C23 */
335 
336 #ifdef __cplusplus
337 }
338 #endif
339 
340 #endif /* _SYS_STDBIT_H */
341