a729db99b10e364d64c2f7e40624d1b1cf4b5219
[lttng-modules.git] / lib / bitfield.h
1 /* SPDX-License-Identifier: MIT
2 *
3 * BabelTrace
4 *
5 * Bitfields read/write functions.
6 *
7 * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 */
9
10 #ifndef _BABELTRACE_BITFIELD_H
11 #define _BABELTRACE_BITFIELD_H
12
13 #include <lttng-endian.h>
14
15 #ifndef CHAR_BIT
16 #define CHAR_BIT 8
17 #endif
18
19 /* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
20 #define _bt_piecewise_rshift(_v, _shift) \
21 ({ \
22 typeof(_v) ___v = (_v); \
23 typeof(_shift) ___shift = (_shift); \
24 unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \
25 unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \
26 \
27 for (; sb; sb--) \
28 ___v >>= sizeof(___v) * CHAR_BIT - 1; \
29 ___v >>= final; \
30 })
31
32 #define _bt_piecewise_lshift(_v, _shift) \
33 ({ \
34 typeof(_v) ___v = (_v); \
35 typeof(_shift) ___shift = (_shift); \
36 unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \
37 unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \
38 \
39 for (; sb; sb--) \
40 ___v <<= sizeof(___v) * CHAR_BIT - 1; \
41 ___v <<= final; \
42 })
43
44 #define _bt_is_signed_type(type) (((type)(-1)) < 0)
45
46 #define _bt_unsigned_cast(type, v) \
47 ({ \
48 (sizeof(v) < sizeof(type)) ? \
49 ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \
50 (type) (v); \
51 })
52
53 /*
54 * bt_bitfield_write - write integer to a bitfield in native endianness
55 *
56 * Save integer to the bitfield, which starts at the "start" bit, has "len"
57 * bits.
58 * The inside of a bitfield is from high bits to low bits.
59 * Uses native endianness.
60 * For unsigned "v", pad MSB with 0 if bitfield is larger than v.
61 * For signed "v", sign-extend v if bitfield is larger than v.
62 *
63 * On little endian, bytes are placed from the less significant to the most
64 * significant. Also, consecutive bitfields are placed from lower bits to higher
65 * bits.
66 *
67 * On big endian, bytes are places from most significant to less significant.
68 * Also, consecutive bitfields are placed from higher to lower bits.
69 */
70
71 #define _bt_bitfield_write_le(_ptr, type, _start, _length, _v) \
72 do { \
73 typeof(_v) __v = (_v); \
74 type *__ptr = (void *) (_ptr); \
75 unsigned long __start = (_start), __length = (_length); \
76 type mask, cmask; \
77 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
78 unsigned long start_unit, end_unit, this_unit; \
79 unsigned long end, cshift; /* cshift is "complement shift" */ \
80 \
81 if (!__length) \
82 break; \
83 \
84 end = __start + __length; \
85 start_unit = __start / ts; \
86 end_unit = (end + (ts - 1)) / ts; \
87 \
88 /* Trim v high bits */ \
89 if (__length < sizeof(__v) * CHAR_BIT) \
90 __v &= ~((~(typeof(__v)) 0) << __length); \
91 \
92 /* We can now append v with a simple "or", shift it piece-wise */ \
93 this_unit = start_unit; \
94 if (start_unit == end_unit - 1) { \
95 mask = ~((~(type) 0) << (__start % ts)); \
96 if (end % ts) \
97 mask |= (~(type) 0) << (end % ts); \
98 cmask = (type) __v << (__start % ts); \
99 cmask &= ~mask; \
100 __ptr[this_unit] &= mask; \
101 __ptr[this_unit] |= cmask; \
102 break; \
103 } \
104 if (__start % ts) { \
105 cshift = __start % ts; \
106 mask = ~((~(type) 0) << cshift); \
107 cmask = (type) __v << cshift; \
108 cmask &= ~mask; \
109 __ptr[this_unit] &= mask; \
110 __ptr[this_unit] |= cmask; \
111 __v = _bt_piecewise_rshift(__v, ts - cshift); \
112 __start += ts - cshift; \
113 this_unit++; \
114 } \
115 for (; this_unit < end_unit - 1; this_unit++) { \
116 __ptr[this_unit] = (type) __v; \
117 __v = _bt_piecewise_rshift(__v, ts); \
118 __start += ts; \
119 } \
120 if (end % ts) { \
121 mask = (~(type) 0) << (end % ts); \
122 cmask = (type) __v; \
123 cmask &= ~mask; \
124 __ptr[this_unit] &= mask; \
125 __ptr[this_unit] |= cmask; \
126 } else \
127 __ptr[this_unit] = (type) __v; \
128 } while (0)
129
130 #define _bt_bitfield_write_be(_ptr, type, _start, _length, _v) \
131 do { \
132 typeof(_v) __v = (_v); \
133 type *__ptr = (void *) (_ptr); \
134 unsigned long __start = (_start), __length = (_length); \
135 type mask, cmask; \
136 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
137 unsigned long start_unit, end_unit, this_unit; \
138 unsigned long end, cshift; /* cshift is "complement shift" */ \
139 \
140 if (!__length) \
141 break; \
142 \
143 end = __start + __length; \
144 start_unit = __start / ts; \
145 end_unit = (end + (ts - 1)) / ts; \
146 \
147 /* Trim v high bits */ \
148 if (__length < sizeof(__v) * CHAR_BIT) \
149 __v &= ~((~(typeof(__v)) 0) << __length); \
150 \
151 /* We can now append v with a simple "or", shift it piece-wise */ \
152 this_unit = end_unit - 1; \
153 if (start_unit == end_unit - 1) { \
154 mask = ~((~(type) 0) << ((ts - (end % ts)) % ts)); \
155 if (__start % ts) \
156 mask |= (~((type) 0)) << (ts - (__start % ts)); \
157 cmask = (type) __v << ((ts - (end % ts)) % ts); \
158 cmask &= ~mask; \
159 __ptr[this_unit] &= mask; \
160 __ptr[this_unit] |= cmask; \
161 break; \
162 } \
163 if (end % ts) { \
164 cshift = end % ts; \
165 mask = ~((~(type) 0) << (ts - cshift)); \
166 cmask = (type) __v << (ts - cshift); \
167 cmask &= ~mask; \
168 __ptr[this_unit] &= mask; \
169 __ptr[this_unit] |= cmask; \
170 __v = _bt_piecewise_rshift(__v, cshift); \
171 end -= cshift; \
172 this_unit--; \
173 } \
174 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
175 __ptr[this_unit] = (type) __v; \
176 __v = _bt_piecewise_rshift(__v, ts); \
177 end -= ts; \
178 } \
179 if (__start % ts) { \
180 mask = (~(type) 0) << (ts - (__start % ts)); \
181 cmask = (type) __v; \
182 cmask &= ~mask; \
183 __ptr[this_unit] &= mask; \
184 __ptr[this_unit] |= cmask; \
185 } else \
186 __ptr[this_unit] = (type) __v; \
187 } while (0)
188
189 /*
190 * bt_bitfield_write - write integer to a bitfield in native endianness
191 * bt_bitfield_write_le - write integer to a bitfield in little endian
192 * bt_bitfield_write_be - write integer to a bitfield in big endian
193 */
194
195 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
196
197 #define bt_bitfield_write(ptr, type, _start, _length, _v) \
198 _bt_bitfield_write_le(ptr, type, _start, _length, _v)
199
200 #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \
201 _bt_bitfield_write_le(ptr, type, _start, _length, _v)
202
203 #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \
204 _bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v)
205
206 #elif (__BYTE_ORDER == __BIG_ENDIAN)
207
208 #define bt_bitfield_write(ptr, type, _start, _length, _v) \
209 _bt_bitfield_write_be(ptr, type, _start, _length, _v)
210
211 #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \
212 _bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v)
213
214 #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \
215 _bt_bitfield_write_be(ptr, type, _start, _length, _v)
216
217 #else /* (BYTE_ORDER == PDP_ENDIAN) */
218
219 #error "Byte order not supported"
220
221 #endif
222
223 #define _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
224 do { \
225 typeof(*(_vptr)) *__vptr = (_vptr); \
226 typeof(*__vptr) __v; \
227 type *__ptr = (void *) (_ptr); \
228 unsigned long __start = (_start), __length = (_length); \
229 type mask, cmask; \
230 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
231 unsigned long start_unit, end_unit, this_unit; \
232 unsigned long end, cshift; /* cshift is "complement shift" */ \
233 \
234 if (!__length) { \
235 *__vptr = 0; \
236 break; \
237 } \
238 \
239 end = __start + __length; \
240 start_unit = __start / ts; \
241 end_unit = (end + (ts - 1)) / ts; \
242 \
243 this_unit = end_unit - 1; \
244 if (_bt_is_signed_type(typeof(__v)) \
245 && (__ptr[this_unit] & ((type) 1 << ((end % ts ? : ts) - 1)))) \
246 __v = ~(typeof(__v)) 0; \
247 else \
248 __v = 0; \
249 if (start_unit == end_unit - 1) { \
250 cmask = __ptr[this_unit]; \
251 cmask >>= (__start % ts); \
252 if ((end - __start) % ts) { \
253 mask = ~((~(type) 0) << (end - __start)); \
254 cmask &= mask; \
255 } \
256 __v = _bt_piecewise_lshift(__v, end - __start); \
257 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
258 *__vptr = __v; \
259 break; \
260 } \
261 if (end % ts) { \
262 cshift = end % ts; \
263 mask = ~((~(type) 0) << cshift); \
264 cmask = __ptr[this_unit]; \
265 cmask &= mask; \
266 __v = _bt_piecewise_lshift(__v, cshift); \
267 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
268 end -= cshift; \
269 this_unit--; \
270 } \
271 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
272 __v = _bt_piecewise_lshift(__v, ts); \
273 __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\
274 end -= ts; \
275 } \
276 if (__start % ts) { \
277 mask = ~((~(type) 0) << (ts - (__start % ts))); \
278 cmask = __ptr[this_unit]; \
279 cmask >>= (__start % ts); \
280 cmask &= mask; \
281 __v = _bt_piecewise_lshift(__v, ts - (__start % ts)); \
282 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
283 } else { \
284 __v = _bt_piecewise_lshift(__v, ts); \
285 __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\
286 } \
287 *__vptr = __v; \
288 } while (0)
289
290 #define _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
291 do { \
292 typeof(*(_vptr)) *__vptr = (_vptr); \
293 typeof(*__vptr) __v; \
294 type *__ptr = (void *) (_ptr); \
295 unsigned long __start = (_start), __length = (_length); \
296 type mask, cmask; \
297 unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \
298 unsigned long start_unit, end_unit, this_unit; \
299 unsigned long end, cshift; /* cshift is "complement shift" */ \
300 \
301 if (!__length) { \
302 *__vptr = 0; \
303 break; \
304 } \
305 \
306 end = __start + __length; \
307 start_unit = __start / ts; \
308 end_unit = (end + (ts - 1)) / ts; \
309 \
310 this_unit = start_unit; \
311 if (_bt_is_signed_type(typeof(__v)) \
312 && (__ptr[this_unit] & ((type) 1 << (ts - (__start % ts) - 1)))) \
313 __v = ~(typeof(__v)) 0; \
314 else \
315 __v = 0; \
316 if (start_unit == end_unit - 1) { \
317 cmask = __ptr[this_unit]; \
318 cmask >>= (ts - (end % ts)) % ts; \
319 if ((end - __start) % ts) { \
320 mask = ~((~(type) 0) << (end - __start)); \
321 cmask &= mask; \
322 } \
323 __v = _bt_piecewise_lshift(__v, end - __start); \
324 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
325 *__vptr = __v; \
326 break; \
327 } \
328 if (__start % ts) { \
329 cshift = __start % ts; \
330 mask = ~((~(type) 0) << (ts - cshift)); \
331 cmask = __ptr[this_unit]; \
332 cmask &= mask; \
333 __v = _bt_piecewise_lshift(__v, ts - cshift); \
334 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
335 __start += ts - cshift; \
336 this_unit++; \
337 } \
338 for (; this_unit < end_unit - 1; this_unit++) { \
339 __v = _bt_piecewise_lshift(__v, ts); \
340 __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\
341 __start += ts; \
342 } \
343 if (end % ts) { \
344 mask = ~((~(type) 0) << (end % ts)); \
345 cmask = __ptr[this_unit]; \
346 cmask >>= ts - (end % ts); \
347 cmask &= mask; \
348 __v = _bt_piecewise_lshift(__v, end % ts); \
349 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
350 } else { \
351 __v = _bt_piecewise_lshift(__v, ts); \
352 __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\
353 } \
354 *__vptr = __v; \
355 } while (0)
356
357 /*
358 * bt_bitfield_read - read integer from a bitfield in native endianness
359 * bt_bitfield_read_le - read integer from a bitfield in little endian
360 * bt_bitfield_read_be - read integer from a bitfield in big endian
361 */
362
363 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
364
365 #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \
366 _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
367
368 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
369 _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
370
371 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
372 _bt_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr)
373
374 #elif (__BYTE_ORDER == __BIG_ENDIAN)
375
376 #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \
377 _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
378
379 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
380 _bt_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr)
381
382 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
383 _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
384
385 #else /* (__BYTE_ORDER == __PDP_ENDIAN) */
386
387 #error "Byte order not supported"
388
389 #endif
390
391 #endif /* _BABELTRACE_BITFIELD_H */
This page took 0.036653 seconds and 3 git commands to generate.