|
root / base / usr / src / uts / common / sys / stdbit.h
stdbit.h C 347 lines 13.4 KB
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2024 Oxide Computer Company
 */

#ifndef _SYS_STDBIT_H
#define	_SYS_STDBIT_H

/*
 * This header implements all of the different aspects of the C23 stdbit.h
 * functionality. We attempt to make this header useful to all C versions other
 * than the type generic interfaces, for which we require the asked for version
 * of C to be at least C23. The functions that are present here are allowed to
 * be inline or not. To provide wider ranging compiler support we declare extern
 * versions of all of these symbols which are provided in both libc and the
 * kernel. This also avoids cases where a compiler builtin relies on external
 * runtime library support.
 *
 * In the future, we should provide inline versions with compilers that support
 * common builtins.
 */

#include <sys/feature_tests.h>
#include <sys/isa_defs.h>

/*
 * This header is required specifically to make the size_t, uintXX_t, and the
 * _least_ variants available. The generic values are allowed to leverage the
 * 'bool' type. In C23, bool became a keyword as opposed to a definition to
 * _Bool. We therefore include it so we can attempt to be consistent and
 * generally useful.
 */
#include <sys/int_types.h>
#include <sys/stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Declare our version.
 */
#define	__STDC_VERSION_STDBIT_H__	202311L

#if !defined(_SIZE_T) || __cplusplus >= 199711L
#define	_SIZE_T
#if defined(_LP64)
typedef unsigned long size_t;   /* size of something in bytes */
#else
typedef unsigned int size_t;    /* (historical version) */
#endif
#endif  /* _SIZE_T */

/*
 * Endian values and detection.
 */
#define	__STDC_ENDIAN_LITTLE__	1234
#define	__STDC_ENDIAN_BIG__	4321
#if defined(_LITTLE_ENDIAN)
#define	__STDC_ENDIAN_NATIVE__	__STDC_ENDIAN_LITTLE__
#elif defined(_BIG_ENDIAN)
#define	__STDC_ENDIAN_NATIVE__	__STDC_ENDIAN_BIG__
#else
#error	"Unknown byte order"
#endif	/* _LITTLE_ENDIAN */

/*
 * Count Leading Zeros
 */
extern unsigned int stdc_leading_zeros_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_leading_zeros_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_leading_zeros_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_leading_zeros_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * Count Leading Ones
 */
extern unsigned int stdc_leading_ones_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_leading_ones_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_leading_ones_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_leading_ones_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * Count Trailing Zeros
 */
extern unsigned int stdc_trailing_zeros_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_trailing_zeros_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_trailing_zeros_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_trailing_zeros_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * Count Trailing Ones
 */
extern unsigned int stdc_trailing_ones_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_trailing_ones_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_trailing_ones_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_trailing_ones_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * First Leading Zero
 */
extern unsigned int stdc_first_leading_zero_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_leading_zero_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_leading_zero_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_leading_zero_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * First Leading One
 */
extern unsigned int stdc_first_leading_one_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_leading_one_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_leading_one_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_leading_one_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * First Trailing Zero
 */
extern unsigned int stdc_first_trailing_zero_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_trailing_zero_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_trailing_zero_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_trailing_zero_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * First Trailing One
 */
extern unsigned int stdc_first_trailing_one_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_trailing_one_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_trailing_one_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_trailing_one_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * Count Zeros
 */
extern unsigned int stdc_count_zeros_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_count_zeros_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_count_zeros_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_count_zeros_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * Count Ones
 */
extern unsigned int stdc_count_ones_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_count_ones_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_count_ones_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_count_ones_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * Single-bit Check
 */
extern bool stdc_has_single_bit_uc(unsigned char) _C23_UNSEQ_ATTR;
extern bool stdc_has_single_bit_us(unsigned short) _C23_UNSEQ_ATTR;
extern bool stdc_has_single_bit_ui(unsigned int) _C23_UNSEQ_ATTR;
extern bool stdc_has_single_bit_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * Bit Width
 */
extern unsigned int stdc_bit_width_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned int stdc_bit_width_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_bit_width_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned int stdc_bit_width_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * Bit Floor
 */
extern unsigned char stdc_bit_floor_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned short stdc_bit_floor_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_bit_floor_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned long stdc_bit_floor_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * Bit Ceiling
 */
extern unsigned char stdc_bit_ceil_uc(unsigned char) _C23_UNSEQ_ATTR;
extern unsigned short stdc_bit_ceil_us(unsigned short) _C23_UNSEQ_ATTR;
extern unsigned int stdc_bit_ceil_ui(unsigned int) _C23_UNSEQ_ATTR;
extern unsigned long stdc_bit_ceil_ul(unsigned long) _C23_UNSEQ_ATTR;

/*
 * long long variants of functions. This check is just for some non-C23
 * environments out of courtesy.
 */
#if defined(_LONGLONG_TYPE)
extern unsigned int stdc_leading_zeros_ull(unsigned long long) _C23_UNSEQ_ATTR;
extern unsigned int stdc_leading_ones_ull(unsigned long long) _C23_UNSEQ_ATTR;
extern unsigned int stdc_trailing_zeros_ull(unsigned long long) _C23_UNSEQ_ATTR;
extern unsigned int stdc_trailing_ones_ull(unsigned long long) _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_leading_zero_ull(unsigned long long)
    _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_leading_one_ull(unsigned long long)
    _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_trailing_zero_ull(unsigned long long)
    _C23_UNSEQ_ATTR;
extern unsigned int stdc_first_trailing_one_ull(unsigned long long)
    _C23_UNSEQ_ATTR;
extern unsigned int stdc_count_zeros_ull(unsigned long long) _C23_UNSEQ_ATTR;
extern unsigned int stdc_count_ones_ull(unsigned long long) _C23_UNSEQ_ATTR;
extern bool stdc_has_single_bit_ull(unsigned long long) _C23_UNSEQ_ATTR;
extern unsigned int stdc_bit_width_ull(unsigned long long) _C23_UNSEQ_ATTR;
extern unsigned long long stdc_bit_floor_ull(unsigned long long)
    _C23_UNSEQ_ATTR;
extern unsigned long long stdc_bit_ceil_ull(unsigned long long) _C23_UNSEQ_ATTR;
#endif	/* _LONGLONG_TYPE */

/*
 * Type Generic functions. The standard requires that these be a generic return
 * type that operates on the following types of values:
 *
 *  - Standard unsigned integer types (excluding bool) i.e. 'unsigned int'.
 *  - Extended unsigned integer types i.e. 'uint128_t' which is not something
 *    currently supported and up to the platform.
 *  - Bit-precise integers that match standard or extended integers. This means
 *    that _BitInt(32) is accepted, but a value that basically doesn't match a
 *    uint8_t, uint16_t, uint32_t, or uint64_t like _BitInt(48) is not valid.
 *
 * There currently is no way to match ranges of _BitInt in the _Generic macro so
 * we end up focusing on the size of the type that was passed. _Generic matches
 * on the type of the first expression, so rather than just the base type of the
 * value, we instead use a suggestion to transform it into a fixed-length array.
 * This works for signed and unsigned integers, implicitly doing a cast to the
 * unsigned value for signed integers. Similarly, this incidentally works for
 * signed and unsigned _BitInt() values that are able to be translated into
 * standard sizes.  We always use the ull versions for 64-bit values as that is
 * always 64-bit regardless if we're in an ILP32 or LP64 environment.
 *
 * _Generic was introduced in C11. As we currently don't have any _Generic
 * statements that aren't valid in C11, we reduce our guard for these to C11 as
 * there isn't really a good way to test for the presence of the _Generic
 * construct otherwise. If we end up having to modify these to use more explicit
 * types, we'll have to have per-standard versions of these macros.
 */
#if defined(_STDC_C11)
/* CSTYLED */
#define	stdc_leading_zeros(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
    char(*)[1]:	stdc_leading_zeros_uc(val),	\
    char(*)[2]:	stdc_leading_zeros_us(val),	\
    char(*)[4]:	stdc_leading_zeros_ui(val),	\
    char(*)[8]:	stdc_leading_zeros_ull(val))

/* CSTYLED */
#define	stdc_leading_ones(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
    char(*)[1]:	stdc_leading_ones_uc(val),	\
    char(*)[2]:	stdc_leading_ones_us(val),	\
    char(*)[4]:	stdc_leading_ones_ui(val),	\
    char(*)[8]:	stdc_leading_ones_ull(val))

/* CSTYLED */
#define	stdc_trailing_zeros(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
    char(*)[1]:	stdc_trailing_zeros_uc(val),	\
    char(*)[2]:	stdc_trailing_zeros_us(val),	\
    char(*)[4]:	stdc_trailing_zeros_ui(val),	\
    char(*)[8]:	stdc_trailing_zeros_ull(val))

/* CSTYLED */
#define	stdc_trailing_ones(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
    char(*)[1]:	stdc_trailing_ones_uc(val),	\
    char(*)[2]:	stdc_trailing_ones_us(val),	\
    char(*)[4]:	stdc_trailing_ones_ui(val),	\
    char(*)[8]:	stdc_trailing_ones_ull(val))

/* CSTYLED */
#define	stdc_first_leading_zero(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
    char(*)[1]:	stdc_first_leading_zero_uc(val),	\
    char(*)[2]:	stdc_first_leading_zero_us(val),	\
    char(*)[4]:	stdc_first_leading_zero_ui(val),	\
    char(*)[8]:	stdc_first_leading_zero_ull(val))

/* CSTYLED */
#define	stdc_first_leading_one(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
    char(*)[1]:	stdc_first_leading_one_uc(val),	\
    char(*)[2]:	stdc_first_leading_one_us(val),	\
    char(*)[4]:	stdc_first_leading_one_ui(val),	\
    char(*)[8]:	stdc_first_leading_one_ull(val))

/* CSTYLED */
#define	stdc_first_trailing_zero(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
    char(*)[1]:	stdc_first_trailing_zero_uc(val),	\
    char(*)[2]:	stdc_first_trailing_zero_us(val),	\
    char(*)[4]:	stdc_first_trailing_zero_ui(val),	\
    char(*)[8]:	stdc_first_trailing_zero_ull(val))

/* CSTYLED */
#define	stdc_first_trailing_one(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
    char(*)[1]:	stdc_first_trailing_one_uc(val),	\
    char(*)[2]:	stdc_first_trailing_one_us(val),	\
    char(*)[4]:	stdc_first_trailing_one_ui(val),	\
    char(*)[8]:	stdc_first_trailing_one_ull(val))

/* CSTYLED */
#define	stdc_count_zeros(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
    char(*)[1]:	stdc_count_zeros_uc(val),	\
    char(*)[2]:	stdc_count_zeros_us(val),	\
    char(*)[4]:	stdc_count_zeros_ui(val),	\
    char(*)[8]:	stdc_count_zeros_ull(val))

/* CSTYLED */
#define	stdc_count_ones(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
    char(*)[1]:	stdc_count_ones_uc(val),	\
    char(*)[2]:	stdc_count_ones_us(val),	\
    char(*)[4]:	stdc_count_ones_ui(val),	\
    char(*)[8]:	stdc_count_ones_ull(val))

/* CSTYLED */
#define	stdc_has_single_bit(val)	_Generic((char(*)[sizeof (val)]){ 0 }, \
    char(*)[1]:	stdc_has_single_bit_uc(val),	\
    char(*)[2]:	stdc_has_single_bit_us(val),	\
    char(*)[4]:	stdc_has_single_bit_ui(val),	\
    char(*)[8]:	stdc_has_single_bit_ull(val))

/* CSTYLED */
#define	stdc_bit_width(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
    char(*)[1]:	stdc_bit_width_uc(val),	\
    char(*)[2]:	stdc_bit_width_us(val),	\
    char(*)[4]:	stdc_bit_width_ui(val),	\
    char(*)[8]:	stdc_bit_width_ull(val))

/* CSTYLED */
#define	stdc_bit_floor(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
    char(*)[1]:	stdc_bit_floor_uc(val),	\
    char(*)[2]:	stdc_bit_floor_us(val),	\
    char(*)[4]:	stdc_bit_floor_ui(val),	\
    char(*)[8]:	stdc_bit_floor_ull(val))

/* CSTYLED */
#define	stdc_bit_ceil(val)	_Generic((char(*)[sizeof (val)]){ 0 },	\
    char(*)[1]:	stdc_bit_ceil_uc(val),	\
    char(*)[2]:	stdc_bit_ceil_us(val),	\
    char(*)[4]:	stdc_bit_ceil_ui(val),	\
    char(*)[8]:	stdc_bit_ceil_ull(val))
#endif	/* STDC_C11 */

#ifdef __cplusplus
}
#endif

#endif /* _SYS_STDBIT_H */