1 /* SPDX-License-Identifier: MIT
5 * Bitfields read/write functions.
7 * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
10 #ifndef _BABELTRACE_BITFIELD_H
11 #define _BABELTRACE_BITFIELD_H
13 #include <lttng-endian.h>
19 /* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
20 #define _bt_piecewise_rshift(_v, _shift) \
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); \
28 ___v >>= sizeof(___v) * CHAR_BIT - 1; \
32 #define _bt_piecewise_lshift(_v, _shift) \
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); \
40 ___v <<= sizeof(___v) * CHAR_BIT - 1; \
44 #define _bt_is_signed_type(type) (((type)(-1)) < 0)
46 #define _bt_unsigned_cast(type, v) \
48 (sizeof(v) < sizeof(type)) ? \
49 ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \
54 * bt_bitfield_write - write integer to a bitfield in native endianness
56 * Save integer to the bitfield, which starts at the "start" bit, has "len"
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.
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
67 * On big endian, bytes are places from most significant to less significant.
68 * Also, consecutive bitfields are placed from higher to lower bits.
71 #define _bt_bitfield_write_le(_ptr, type, _start, _length, _v) \
73 typeof(_v) __v = (_v); \
74 type *__ptr = (void *) (_ptr); \
75 unsigned long __start = (_start), __length = (_length); \
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" */ \
84 end = __start + __length; \
85 start_unit = __start / ts; \
86 end_unit = (end + (ts - 1)) / ts; \
88 /* Trim v high bits */ \
89 if (__length < sizeof(__v) * CHAR_BIT) \
90 __v &= ~((~(typeof(__v)) 0) << __length); \
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)); \
97 mask |= (~(type) 0) << (end % ts); \
98 cmask = (type) __v << (__start % ts); \
100 __ptr[this_unit] &= mask; \
101 __ptr[this_unit] |= cmask; \
104 if (__start % ts) { \
105 cshift = __start % ts; \
106 mask = ~((~(type) 0) << cshift); \
107 cmask = (type) __v << cshift; \
109 __ptr[this_unit] &= mask; \
110 __ptr[this_unit] |= cmask; \
111 __v = _bt_piecewise_rshift(__v, ts - cshift); \
112 __start += ts - cshift; \
115 for (; this_unit < end_unit - 1; this_unit++) { \
116 __ptr[this_unit] = (type) __v; \
117 __v = _bt_piecewise_rshift(__v, ts); \
121 mask = (~(type) 0) << (end % ts); \
122 cmask = (type) __v; \
124 __ptr[this_unit] &= mask; \
125 __ptr[this_unit] |= cmask; \
127 __ptr[this_unit] = (type) __v; \
130 #define _bt_bitfield_write_be(_ptr, type, _start, _length, _v) \
132 typeof(_v) __v = (_v); \
133 type *__ptr = (void *) (_ptr); \
134 unsigned long __start = (_start), __length = (_length); \
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" */ \
143 end = __start + __length; \
144 start_unit = __start / ts; \
145 end_unit = (end + (ts - 1)) / ts; \
147 /* Trim v high bits */ \
148 if (__length < sizeof(__v) * CHAR_BIT) \
149 __v &= ~((~(typeof(__v)) 0) << __length); \
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)); \
156 mask |= (~((type) 0)) << (ts - (__start % ts)); \
157 cmask = (type) __v << ((ts - (end % ts)) % ts); \
159 __ptr[this_unit] &= mask; \
160 __ptr[this_unit] |= cmask; \
165 mask = ~((~(type) 0) << (ts - cshift)); \
166 cmask = (type) __v << (ts - cshift); \
168 __ptr[this_unit] &= mask; \
169 __ptr[this_unit] |= cmask; \
170 __v = _bt_piecewise_rshift(__v, cshift); \
174 for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
175 __ptr[this_unit] = (type) __v; \
176 __v = _bt_piecewise_rshift(__v, ts); \
179 if (__start % ts) { \
180 mask = (~(type) 0) << (ts - (__start % ts)); \
181 cmask = (type) __v; \
183 __ptr[this_unit] &= mask; \
184 __ptr[this_unit] |= cmask; \
186 __ptr[this_unit] = (type) __v; \
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
195 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
197 #define bt_bitfield_write(ptr, type, _start, _length, _v) \
198 _bt_bitfield_write_le(ptr, type, _start, _length, _v)
200 #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \
201 _bt_bitfield_write_le(ptr, type, _start, _length, _v)
203 #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \
204 _bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v)
206 #elif (__BYTE_ORDER == __BIG_ENDIAN)
208 #define bt_bitfield_write(ptr, type, _start, _length, _v) \
209 _bt_bitfield_write_be(ptr, type, _start, _length, _v)
211 #define bt_bitfield_write_le(ptr, type, _start, _length, _v) \
212 _bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v)
214 #define bt_bitfield_write_be(ptr, type, _start, _length, _v) \
215 _bt_bitfield_write_be(ptr, type, _start, _length, _v)
217 #else /* (BYTE_ORDER == PDP_ENDIAN) */
219 #error "Byte order not supported"
223 #define _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
225 typeof(*(_vptr)) *__vptr = (_vptr); \
226 typeof(*__vptr) __v; \
227 type *__ptr = (void *) (_ptr); \
228 unsigned long __start = (_start), __length = (_length); \
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" */ \
239 end = __start + __length; \
240 start_unit = __start / ts; \
241 end_unit = (end + (ts - 1)) / ts; \
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; \
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)); \
256 __v = _bt_piecewise_lshift(__v, end - __start); \
257 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
263 mask = ~((~(type) 0) << cshift); \
264 cmask = __ptr[this_unit]; \
266 __v = _bt_piecewise_lshift(__v, cshift); \
267 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
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]);\
276 if (__start % ts) { \
277 mask = ~((~(type) 0) << (ts - (__start % ts))); \
278 cmask = __ptr[this_unit]; \
279 cmask >>= (__start % ts); \
281 __v = _bt_piecewise_lshift(__v, ts - (__start % ts)); \
282 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
284 __v = _bt_piecewise_lshift(__v, ts); \
285 __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\
290 #define _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
292 typeof(*(_vptr)) *__vptr = (_vptr); \
293 typeof(*__vptr) __v; \
294 type *__ptr = (void *) (_ptr); \
295 unsigned long __start = (_start), __length = (_length); \
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" */ \
306 end = __start + __length; \
307 start_unit = __start / ts; \
308 end_unit = (end + (ts - 1)) / ts; \
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; \
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)); \
323 __v = _bt_piecewise_lshift(__v, end - __start); \
324 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
328 if (__start % ts) { \
329 cshift = __start % ts; \
330 mask = ~((~(type) 0) << (ts - cshift)); \
331 cmask = __ptr[this_unit]; \
333 __v = _bt_piecewise_lshift(__v, ts - cshift); \
334 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
335 __start += ts - cshift; \
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]);\
344 mask = ~((~(type) 0) << (end % ts)); \
345 cmask = __ptr[this_unit]; \
346 cmask >>= ts - (end % ts); \
348 __v = _bt_piecewise_lshift(__v, end % ts); \
349 __v |= _bt_unsigned_cast(typeof(__v), cmask); \
351 __v = _bt_piecewise_lshift(__v, ts); \
352 __v |= _bt_unsigned_cast(typeof(__v), __ptr[this_unit]);\
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
363 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
365 #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \
366 _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
368 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
369 _bt_bitfield_read_le(_ptr, type, _start, _length, _vptr)
371 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
372 _bt_bitfield_read_be(_ptr, unsigned char, _start, _length, _vptr)
374 #elif (__BYTE_ORDER == __BIG_ENDIAN)
376 #define bt_bitfield_read(_ptr, type, _start, _length, _vptr) \
377 _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
379 #define bt_bitfield_read_le(_ptr, type, _start, _length, _vptr) \
380 _bt_bitfield_read_le(_ptr, unsigned char, _start, _length, _vptr)
382 #define bt_bitfield_read_be(_ptr, type, _start, _length, _vptr) \
383 _bt_bitfield_read_be(_ptr, type, _start, _length, _vptr)
385 #else /* (__BYTE_ORDER == __PDP_ENDIAN) */
387 #error "Byte order not supported"
391 #endif /* _BABELTRACE_BITFIELD_H */
This page took 0.046509 seconds and 5 git commands to generate.